diff --git a/AutomatedTesting/AssetProcessorGamePlatformConfig.setreg b/AutomatedTesting/AssetProcessorGamePlatformConfig.setreg deleted file mode 100644 index c9876cb1f9..0000000000 --- a/AutomatedTesting/AssetProcessorGamePlatformConfig.setreg +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Amazon": { - "AssetProcessor": { - "Settings": { - "RC cgf": { - "ignore": true - }, - "RC fbx": { - "ignore": true - } - } - } - } -} diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py index 625c9772bd..5cfc57fd5f 100755 --- a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py +++ b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C18977329 # Test Case Title : Add cloth simulation to a Mesh -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/18977329 # fmt: off class Tests: diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py index 9b3135cd2b..c21df8ea4c 100755 --- a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py +++ b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C18977330 # Test Case Title : Add cloth simulation to an Actor -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/18977330 # fmt: off class Tests: diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798177_WhiteBox_AddComponentToEntity.py b/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798177_WhiteBox_AddComponentToEntity.py index dabc04575f..86a27e588e 100755 --- a/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798177_WhiteBox_AddComponentToEntity.py +++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798177_WhiteBox_AddComponentToEntity.py @@ -12,7 +12,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C28798177 # Test Case Title : White Box Tool Component can be added to an Entity -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/28798177 # fmt:off diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798205_WhiteBox_SetInvisible.py b/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798205_WhiteBox_SetInvisible.py index 18a5c3164e..7a2a08a8ce 100755 --- a/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798205_WhiteBox_SetInvisible.py +++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/C28798205_WhiteBox_SetInvisible.py @@ -12,7 +12,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C28798205 # Test Case Title : From the White Box Component Card the White Box Mesh can be set to be invisible in Game View -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/28798205 # fmt:off diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/C29279329_WhiteBox_SetDefaultShape.py b/AutomatedTesting/Gem/PythonTests/WhiteBox/C29279329_WhiteBox_SetDefaultShape.py index e892285dde..635c804914 100755 --- a/AutomatedTesting/Gem/PythonTests/WhiteBox/C29279329_WhiteBox_SetDefaultShape.py +++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/C29279329_WhiteBox_SetDefaultShape.py @@ -12,7 +12,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C29279329 # Test Case Title : White Box mesh shape can be changed with the Default Shape dropdown on the Component -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/29279329 # fmt:off diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py index f84e367d1d..0b75760e05 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py @@ -18,7 +18,7 @@ import pytest import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) -EDITOR_TIMEOUT = 120 +EDITOR_TIMEOUT = 300 TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts") diff --git a/AutomatedTesting/Gem/PythonTests/physics/C14976308_ScriptCanvas_SetKinematicTargetTransform.py b/AutomatedTesting/Gem/PythonTests/physics/C14976308_ScriptCanvas_SetKinematicTargetTransform.py index c76c5cab80..8400364626 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/C14976308_ScriptCanvas_SetKinematicTargetTransform.py +++ b/AutomatedTesting/Gem/PythonTests/physics/C14976308_ScriptCanvas_SetKinematicTargetTransform.py @@ -68,7 +68,7 @@ def C14976308_ScriptCanvas_SetKinematicTargetTransform(): the script deactivates Signal, Sphere's transform will update to that of Transform_Target. NOTE: There is a known bug (LY-107723) which causes the rotation to update to a value that is not sufficiently close to the expected result when using Set Kinematic Target which will cause the test to fail: - https://jira.agscollab.com/browse/LY-107723 + LY-107723 Test Steps: 1) Open level and enter game mode diff --git a/AutomatedTesting/Gem/PythonTests/physics/C3510644_Collider_CollisionGroups.py b/AutomatedTesting/Gem/PythonTests/physics/C3510644_Collider_CollisionGroups.py index 4ae10288bd..e714da9de7 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/C3510644_Collider_CollisionGroups.py +++ b/AutomatedTesting/Gem/PythonTests/physics/C3510644_Collider_CollisionGroups.py @@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # Test case ID : C3510644 # Test Case Title : Check that the collision layer and collision group of the terrain can be changed # and the collision behavior of the terrain changes accordingly -# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/3510644 # fmt: off diff --git a/AutomatedTesting/Gem/PythonTests/physics/C6321601_Force_HighValuesDirectionAxes.py b/AutomatedTesting/Gem/PythonTests/physics/C6321601_Force_HighValuesDirectionAxes.py index 4b0b036970..08083a7868 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/C6321601_Force_HighValuesDirectionAxes.py +++ b/AutomatedTesting/Gem/PythonTests/physics/C6321601_Force_HighValuesDirectionAxes.py @@ -239,7 +239,7 @@ def C6321601_Force_HighValuesDirectionAxes(): force_notification_handler.add_callback("OnCalculateNetForce", on_calc_net_force) # Wait for 3 secs, because there is a known bug identified and filed in - # JIRA https://jira.agscollab.com/browse/LY-107677 + # JIRA LY-107677 # The error "[Error] Huge object being added to a COctreeNode, name: 'MeshComponentRenderNode', objBox:" # will show (if occured) in about 3 sec into the game mode. helper.wait_for_condition(has_physx_error, 3.0) diff --git a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_InDevelopment.py b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_InDevelopment.py index 8f098941ea..8986c1024a 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_InDevelopment.py +++ b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_InDevelopment.py @@ -50,7 +50,7 @@ class TestAutomation(TestAutomationBase): unexpected_lines = ["Assert"] self._run_test(request, workspace, editor, test_module, expected_lines, unexpected_lines) - # BUG: https://jira.agscollab.com/browse/LY-107723") + # BUG: LY-107723") def test_C14976308_ScriptCanvas_SetKinematicTargetTransform(self, request, workspace, editor): from . import C14976308_ScriptCanvas_SetKinematicTargetTransform as test_module diff --git a/AutomatedTesting/Gem/PythonTests/physics/UtilTest_Physmaterial_Editor.py b/AutomatedTesting/Gem/PythonTests/physics/UtilTest_Physmaterial_Editor.py index 5f24f41083..b6d7c610e3 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/UtilTest_Physmaterial_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/physics/UtilTest_Physmaterial_Editor.py @@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ''' This unittest might have to be refactored once changes to Physmaterial_Editor.py are made. These changes will occur after the but, reverence below is resloved. -Bug: https://jira.agscollab.com/browse/LY-107392 +Bug: LY-107392 ''' class Tests: opening_bad_file = ("Bad file could not be opened", "Bad file was opened") diff --git a/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_CreateScriptEventFile.py b/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_CreateScriptEventFile.py index dcbbf47f0c..b844f9e4af 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_CreateScriptEventFile.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_CreateScriptEventFile.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569013 Test Case Title: Script Event file can be created -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569013 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_NewScriptEvent.py b/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_NewScriptEvent.py index 1f801d4eeb..e4fec76fe2 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_NewScriptEvent.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/AssetEditor_NewScriptEvent.py @@ -12,7 +12,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92568942 Test Case Title: Clicking the "+" button and selecting "New Script Event" opens the Asset Editor with a new Script Event asset -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92568942 """ from PySide2 import QtWidgets diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleEntities.py b/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleEntities.py index a26cb4f923..0947b0bb51 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleEntities.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleEntities.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92568856 Test Case Title: Multiple Entities can be targeted in the Debugger tool -URLs of the test case: https://testrail.agscollab.com/index.php?/tests/view/92568856 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleGraphs.py b/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleGraphs.py index 4aa5c822a7..8d2c39f288 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleGraphs.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Debugging_TargetMultipleGraphs.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569137 Test Case Title: Multiple Graphs can be targeted in the Debugger tool -URLs of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569137 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Docking_Pane.py b/AutomatedTesting/Gem/PythonTests/scripting/Docking_Pane.py index 4fa1e1257f..537b4d817a 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/Docking_Pane.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Docking_Pane.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: C1702824 Test Case Title: Docking -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/1702824 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/EditMenu_UndoRedo.py b/AutomatedTesting/Gem/PythonTests/scripting/EditMenu_UndoRedo.py index a87d9e9be9..38ceb8335b 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/EditMenu_UndoRedo.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/EditMenu_UndoRedo.py @@ -11,10 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569049 Test Case Title: Edit > Undo undoes the last action -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569049 Test case ID: T92569051 Test Case Title: Edit > Redo redoes the last undone action -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569051 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Entity_AddScriptCanvasComponent.py b/AutomatedTesting/Gem/PythonTests/scripting/Entity_AddScriptCanvasComponent.py index fd8e9b1173..47bbb955ec 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Entity_AddScriptCanvasComponent.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Entity_AddScriptCanvasComponent.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92562978 Test Case Title: Script Canvas Component can be added to an entity -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92562978 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/FileMenu_New_Open.py b/AutomatedTesting/Gem/PythonTests/scripting/FileMenu_New_Open.py index f72ac8ea01..3206590a8d 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/FileMenu_New_Open.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/FileMenu_New_Open.py @@ -11,10 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569037 Test Case Title: File > New Script creates a new script -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569037 Test case ID: T92569039 Test Case Title: File > Open opens the Open... dialog -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569039 """ import os diff --git a/AutomatedTesting/Gem/PythonTests/scripting/GraphClose_SavePrompt.py b/AutomatedTesting/Gem/PythonTests/scripting/GraphClose_SavePrompt.py index ce610b159b..ec8f0c8fb6 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/GraphClose_SavePrompt.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/GraphClose_SavePrompt.py @@ -11,11 +11,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92563070 Test Case Title: Graphs can be closed by clicking X on the Graph name tab -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92563070 Test case ID: T92563068 Test Case Title: Save Prompt: User is prompted to save a graph on close after creating a new graph -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92563068 """ import os diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Graph_ZoomInZoomOut.py b/AutomatedTesting/Gem/PythonTests/scripting/Graph_ZoomInZoomOut.py index a93b6e61d1..d2765bfdf7 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Graph_ZoomInZoomOut.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Graph_ZoomInZoomOut.py @@ -11,10 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569079 Test Case Title: View > Zoom In zooms the graph in -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569079 Test case ID: T92569081 Test Case Title: View > Zoom In zooms the graph out -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569081 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ImportPathHelper.py b/AutomatedTesting/Gem/PythonTests/scripting/ImportPathHelper.py index a45024cebf..23e5f87030 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/ImportPathHelper.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ImportPathHelper.py @@ -9,9 +9,9 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ + def init(): import os import sys sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared') sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../EditorPythonTestTools/editor_python_test_tools') - \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/scripting/NodeCategory_ExpandOnClick.py b/AutomatedTesting/Gem/PythonTests/scripting/NodeCategory_ExpandOnClick.py new file mode 100644 index 0000000000..141cdbea8d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/NodeCategory_ExpandOnClick.py @@ -0,0 +1,128 @@ +""" +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. + +Test case ID: T92562988 +Test Case Title: Left-click/double click expands and collapses node categories +""" + + +# fmt: off +class Tests(): + pane_open = ("Script Canvas pane successfully opened", "Script Canvas pane failed to open") + click_expand = ("Category expanded on left click", "Category failed to expand on left click") + click_collapse = ("Category collapsed on left click", "Category failed to collapse on left click") + dClick_expand = ("Category expanded on double click", "Category failed to expand on double click") + dClick_collapse = ("Category collapsed on double click", "Category failed to collapse on double click") +# fmt: on + + +def NodeCategory_ExpandOnClick(): + """ + Summary: + Verifying the expand/collapse functionality on node categories + + Expected Behavior: + The node category should expand when double clicked or when the drop down indicator is + left-clicked. Once expanded, it should be collapsed via the same actions. + + Test Steps: + 1) Open Script Canvas pane + 2) Get the SC window objects + 3) Ensure all categories are collapsed for a clean state + 4) Left-Click on a node category arrow to expand it + 5) Verify it expanded + 6) Left-Click on a node category arrow to collapse it + 7) Verify it collapsed + 8) Double-Click on a node category to expand it + 9) Verify it expanded + 10) Double-Click on a node category to collapse it + 11) Verify it collapsed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + from utils import Report + from PySide2 import QtCore, QtWidgets, QtTest + from PySide2.QtTest import QTest + import pyside_utils + import azlmbr.legacy.general as general + + def left_click_arrow(item_view, index): + original_state = item_view.isExpanded(index) + rect_center_y = item_view.visualRect(index).center().y() + rect_left_x = item_view.visualRect(index).left() + for i in range(5): # this range can be increased for safe side + QtTest.QTest.mouseClick( + item_view.viewport(), + QtCore.Qt.LeftButton, + QtCore.Qt.NoModifier, + QtCore.QPoint(rect_left_x - i, rect_center_y), + ) + if item_view.isExpanded(index) != original_state: + break + + def double_click(item_view, index): + item_index_center = item_view.visualRect(index).center() + # Left click on the item before trying to double click, will otherwise fail to expand + # as first click would highlight and second click would be a 'single click' + pyside_utils.item_view_index_mouse_click(item_view, index) + QTest.mouseDClick(item_view.viewport(), QtCore.Qt.LeftButton, QtCore.Qt.NoModifier, item_index_center) + + # 1) Open Script Canvas pane + general.open_pane("Script Canvas") + Report.critical_result(Tests.pane_open, general.is_pane_visible("Script Canvas")) + + # 2) Get the SC window objects + editor_window = pyside_utils.get_editor_main_window() + sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas") + if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None: + action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction}) + action.trigger() + node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette") + nodeTree = node_palette.findChild(QtWidgets.QTreeView, "treeView") + ai_index = pyside_utils.find_child_by_pattern(nodeTree, "AI") + + # 3) Ensure all categories are collapsed for a clean state + nodeTree.collapseAll() + + # 4) Left-Click on a node category arrow to expand it + left_click_arrow(nodeTree, ai_index) + + # 5) Verify it expanded + Report.result(Tests.click_expand, nodeTree.isExpanded(ai_index)) + + # 6) Left-Click on a node category arrow to collapse it + left_click_arrow(nodeTree, ai_index) + + # 7) Verify it collapsed + Report.result(Tests.click_collapse, not nodeTree.isExpanded(ai_index)) + + # 8) Double-Click on a node category to expand it + double_click(nodeTree, ai_index) + + # 9) Verify it expanded + Report.result(Tests.dClick_expand, nodeTree.isExpanded(ai_index)) + + # 10) Double-Click on a node category to collapse it + double_click(nodeTree, ai_index) + + # 11) Verify it collapsed + Report.result(Tests.dClick_collapse, not nodeTree.isExpanded(ai_index)) + + +if __name__ == "__main__": + import ImportPathHelper as imports + imports.init() + from utils import Report + Report.start_test(NodeCategory_ExpandOnClick) diff --git a/AutomatedTesting/Gem/PythonTests/scripting/NodeInspector_RenameVariable.py b/AutomatedTesting/Gem/PythonTests/scripting/NodeInspector_RenameVariable.py index 33d3f4137a..550969e32a 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/NodeInspector_RenameVariable.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/NodeInspector_RenameVariable.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92568982 Test Case Title: Renaming variables in the Node Inspector -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92568982 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_ClearSelection.py b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_ClearSelection.py index de30e46767..979bcff02e 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_ClearSelection.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_ClearSelection.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92562993 Test Case Title: Clicking the X button on the Search Box clears the currently entered string -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92562993 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SearchText_Deletion.py b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SearchText_Deletion.py new file mode 100644 index 0000000000..0739a8e637 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SearchText_Deletion.py @@ -0,0 +1,91 @@ +""" +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. +""" + + +# fmt: off +class Tests(): + set_search_string = ("Search string is set", "Search string is not set") + search_string_deleted = ("Search string deleted as expected", "Search string not deleted") +# fmt: on + + +def NodePalette_SearchText_Deletion(): + """ + Summary: + We enter some string in the Node Palette Search box, select that text and delete it. + + Expected Behavior: + After RightClick->Delete the text in the Searchbox should be deleted. + + Test Steps: + 1) Open Script Canvas window (Tools > Script Canvas) + 2) Get the SC window object + 3) Open Node Manager if not opened already + 4) Set some string in the Search box + 5) Verify if the test string is set + 6) Delete search string using right click and verify if it is cleared + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + + from PySide2 import QtWidgets, QtTest, QtCore + + from utils import TestHelper as helper + + import azlmbr.legacy.general as general + + import pyside_utils + + TEST_STRING = "TestString" + + # 1) Open Script Canvas window (Tools > Script Canvas) + general.idle_enable(True) + general.open_pane("Script Canvas") + helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 3.0) + + # 2) Get the SC window object + editor_window = pyside_utils.get_editor_main_window() + sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas") + + # 3) Open Node Manager if not opened already + if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None: + action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction}) + action.trigger() + node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette") + search_frame = node_palette.findChild(QtWidgets.QFrame, "searchFrame") + + # 4) Set some string in the Search box + search_box = search_frame.findChild(QtWidgets.QLineEdit, "searchFilter") + search_box.setText(TEST_STRING) + + # 5) Verify if the test string is set + result = helper.wait_for_condition(lambda: search_box.text() == TEST_STRING, 1.0) + Report.result(Tests.set_search_string, result) + + # 6) Delete search string using right click and verify if it is cleared + QtTest.QTest.keyClick(search_box, QtCore.Qt.Key_A, QtCore.Qt.ControlModifier) + pyside_utils.trigger_context_menu_entry(search_box, "Delete") + result = helper.wait_for_condition(lambda: search_box.text() == "", 2.0) + Report.result(Tests.search_string_deleted, result) + + +if __name__ == "__main__": + import ImportPathHelper as imports + + imports.init() + from utils import Report + + Report.start_test(NodePalette_SearchText_Deletion) diff --git a/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SelectNode.py b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SelectNode.py index 2ab76071a6..374dc4e1a0 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SelectNode.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/NodePalette_SelectNode.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92568940 Test Case Title: Categories and Nodes can be selected -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92568940 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/OnEntityActivatedDeactivated_PrintMessage.py b/AutomatedTesting/Gem/PythonTests/scripting/OnEntityActivatedDeactivated_PrintMessage.py index 51b63c4268..00893d6acb 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/OnEntityActivatedDeactivated_PrintMessage.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/OnEntityActivatedDeactivated_PrintMessage.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92569253 // T92569254 Test Case Title: On Entity Activated // On Entity Deactivated -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92569253 // https://testrail.agscollab.com/index.php?/tests/view/92569254 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Opening_Closing_Pane.py b/AutomatedTesting/Gem/PythonTests/scripting/Opening_Closing_Pane.py index 666f052240..48c40eb05e 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/Opening_Closing_Pane.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Opening_Closing_Pane.py @@ -10,8 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: C1702834 // C1702823 Test Case Title: Opening pane // Closing pane -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/1702834 and - https://testrail.agscollab.com/index.php?/cases/view/1702823 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Pane_RetainOnSCRestart.py b/AutomatedTesting/Gem/PythonTests/scripting/Pane_RetainOnSCRestart.py index fa5e9e6068..adf9b5f35a 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Pane_RetainOnSCRestart.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Pane_RetainOnSCRestart.py @@ -10,8 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: C1702821 // C1702832 Test Case Title: Retain visibility, size and location upon Script Canvas restart -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/1702821 and - https://testrail.agscollab.com/index.php?/cases/view/1702832 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Resizing_Pane.py b/AutomatedTesting/Gem/PythonTests/scripting/Resizing_Pane.py index 180f577953..bbae3afefd 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/Resizing_Pane.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Resizing_Pane.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: C1702829 Test Case Title: Resizing pane -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/1702829 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_ChangingAssets.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_ChangingAssets.py index 38d60ad871..bb4de4a6c9 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_ChangingAssets.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_ChangingAssets.py @@ -11,7 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92562986 Test Case Title: Changing the assigned Script Canvas Asset on an entity properly updates level functionality -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92562986 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoComponents.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoComponents.py index 896bee96e5..6187ac81ba 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoComponents.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoComponents.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92563190 Test Case Title: A single Entity with two Script Canvas components works properly -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92563190 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoEntities.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoEntities.py index 401e6c0271..9453c31488 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoEntities.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptCanvas_TwoEntities.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92563191 Test Case Title: Two Entities can use the same Graph asset successfully at RunTime -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92563191 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveAcrossMultiple.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveAcrossMultiple.py index d671229cdf..a2913d3468 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveAcrossMultiple.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveAcrossMultiple.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92567321 Test Case Title: Script Events: Can send and receive a script event across multiple entities successfully -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92567321 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveSuccessfully.py index b5e26d14ae..388e2bb7c0 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_SendReceiveSuccessfully.py @@ -10,7 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92567320 Test Case Title: Script Events: Can send and receive a script event successfully -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92567320 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py index 152dea93cd..dda75f0a0c 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py @@ -192,6 +192,17 @@ class TestAutomation(TestAutomationBase): from . import ScriptEvents_ReturnSetType_Successfully as test_module self._run_test(request, workspace, editor, test_module) + def test_NodeCategory_ExpandOnClick(self, request, workspace, editor, launcher_platform): + from . import NodeCategory_ExpandOnClick as test_module + self._run_test(request, workspace, editor, test_module) + + def test_NodePalette_SearchText_Deletion(self, request, workspace, editor, launcher_platform): + from . import NodePalette_SearchText_Deletion as test_module + self._run_test(request, workspace, editor, test_module) + + def test_VariableManager_UnpinVariableType_Works(self, request, workspace, editor, launcher_platform): + from . import VariableManager_UnpinVariableType_Works as test_module + self._run_test(request, workspace, editor, test_module) # NOTE: We had to use hydra_test_utils.py, as TestAutomationBase run_test method # fails because of pyside_utils import @@ -261,4 +272,4 @@ class TestScriptCanvasTests(object): expected_lines, auto_test_mode=False, timeout=60, - ) \ No newline at end of file + ) diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Toggle_ScriptCanvasTools.py b/AutomatedTesting/Gem/PythonTests/scripting/Toggle_ScriptCanvasTools.py index 4024e28277..42cc42de0d 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Toggle_ScriptCanvasTools.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Toggle_ScriptCanvasTools.py @@ -13,11 +13,6 @@ Test Case Title: Tools > Node Palette toggles the Node Palette Tools > Node Inspector toggles the Node Inspector Tools > Bookmarks toggles the Bookmarks Tools > Variable Manager toggles the Variable Manager - -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/92569165 - https://testrail.agscollab.com/index.php?/cases/view/92569167 - https://testrail.agscollab.com/index.php?/cases/view/92569168 - https://testrail.agscollab.com/index.php?/cases/view/92569170 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/UnDockedPane_CloseSCWindow.py b/AutomatedTesting/Gem/PythonTests/scripting/UnDockedPane_CloseSCWindow.py index 875f28ec95..da33a8ab80 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/UnDockedPane_CloseSCWindow.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/UnDockedPane_CloseSCWindow.py @@ -10,8 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: C1702825 // C1702831 Test Case Title: Undocking // Closing script canvas with the pane floating -URLs of the test case: https://testrail.agscollab.com/index.php?/cases/view/1702825 & - https://testrail.agscollab.com/index.php?/cases/view/1702831 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_CreateDeleteVars.py b/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_CreateDeleteVars.py index 6facc324d4..8b5c78fa87 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_CreateDeleteVars.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_CreateDeleteVars.py @@ -10,10 +10,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Test case ID: T92564789 Test Case Title: Each Variable type can be created -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92564789 Test case ID: T92568873 Test Case Title: Each Variable type can be deleted -URL of the test case: https://testrail.agscollab.com/index.php?/tests/view/92568873 """ diff --git a/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_UnpinVariableType_Works.py b/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_UnpinVariableType_Works.py new file mode 100644 index 0000000000..7076f60385 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/VariableManager_UnpinVariableType_Works.py @@ -0,0 +1,121 @@ +""" +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. +""" + + +# fmt: off +class Tests(): + variable_manager_opened = ("VariableManager is opened successfully", "Failed to open VariableManager") + variable_pinned = ("Variable is pinned", "Variable is not pinned, But it should be unpinned") + variable_unpinned = ("Variable is unpinned", "Variable is not unpinned, But it should be pinned") + variable_unpinned_after_reopen = ("Variable is unpinned after reopening create variable menu", "Variable is not unpinned after reopening create variable menu") +# fmt: on + + +def VariableManager_UnpinVariableType_Works(): + """ + Summary: + Unpin variable types in create variable menu. + Expected Behavior: + The variable unpinned in create variable menu remains unpinned after reopening create variable menu. + Test Steps: + 1) Open Script Canvas window (Tools > Script Canvas) + 2) Get the SC window object + 3) Open Variable Manager in Script Canvas window + 4) Create new graph + 5) Click on the Create Variable button in the Variable Manager + 6) Unpin Boolean by clicking the "Pin" icon on its left side + 7) Close and Reopen Create Variable menu and make sure Boolean is unpinned after reopening Create Variable menu + 8) Restore default layout and close SC window + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ + + from PySide2 import QtWidgets + import azlmbr.legacy.general as general + + import pyside_utils + from utils import TestHelper as helper + from utils import Report + from PySide2.QtCore import Qt + + GENERAL_WAIT = 1.0 # seconds + + def find_pane(window, pane_name): + return window.findChild(QtWidgets.QDockWidget, pane_name) + + def click_menu_option(window, option_text): + action = pyside_utils.find_child_by_pattern(window, {"text": option_text, "type": QtWidgets.QAction}) + action.trigger() + + # 1) Open Script Canvas window (Tools > Script Canvas) + general.idle_enable(True) + general.open_pane("Script Canvas") + helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 6.0) + + # 2) Get the SC window object + editor_window = pyside_utils.get_editor_main_window() + sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas") + sc_main = sc.findChild(QtWidgets.QMainWindow) + + # 3) Open Variable Manager in Script Canvas window + pane = find_pane(sc, "VariableManager") + if not pane.isVisible(): + click_menu_option(sc, "Variable Manager") + pane = find_pane(sc, "VariableManager") + Report.result(Tests.variable_manager_opened, pane.isVisible()) + + # 4) Create new graph + create_new_graph = pyside_utils.find_child_by_pattern( + sc_main, {"objectName": "action_New_Script", "type": QtWidgets.QAction} + ) + create_new_graph.trigger() + + # 5) Click on the Create Variable button in the Variable Manager + variable_manager = sc_main.findChild(QtWidgets.QDockWidget, "VariableManager") + button = variable_manager.findChild(QtWidgets.QPushButton, "addButton") + button.click() + + # 6) Unpin Boolean by clicking the "Pin" icon on its left side + table_view = variable_manager.findChild(QtWidgets.QTableView, "variablePalette") + model_index = pyside_utils.find_child_by_pattern(table_view, "Boolean") + # Make sure Boolean is pinned + is_boolean = model_index.siblingAtColumn(0) + result = helper.wait_for_condition(lambda: is_boolean.data(Qt.DecorationRole) is not None, GENERAL_WAIT) + Report.result(Tests.variable_pinned, result) + # Unpin Boolean and make sure Boolean is unpinned. + pyside_utils.item_view_index_mouse_click(table_view, is_boolean) + result = helper.wait_for_condition(lambda: is_boolean.data(Qt.DecorationRole) is None, GENERAL_WAIT) + Report.result(Tests.variable_unpinned, result) + + # 7) Close and Reopen Create Variable menu and make sure Boolean is unpinned after reopening Create Variable menu + button.click() + button.click() + model_index = pyside_utils.find_child_by_pattern(table_view, "Boolean") + result = helper.wait_for_condition( + lambda: model_index.siblingAtColumn(0).data(Qt.DecorationRole) is None, GENERAL_WAIT + ) + Report.result(Tests.variable_unpinned_after_reopen, result) + + # 8) Restore default layout and close SC window + click_menu_option(sc, "Restore Default Layout") + general.close_pane("Script Canvas") + + +if __name__ == "__main__": + import ImportPathHelper as imports + + imports.init() + + from utils import Report + + Report.start_test(VariableManager_UnpinVariableType_Works) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae8a7a05f8..2ee08a8d16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,13 +25,37 @@ include(cmake/LySet.cmake) include(cmake/Version.cmake) include(cmake/OutputDirectory.cmake) +# Set the engine_path and engine_json +set(o3de_engine_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_engine_json ${o3de_engine_path}/engine.json) + if(NOT PROJECT_NAME) project(O3DE LANGUAGES C CXX VERSION ${LY_VERSION_STRING} ) + + # o3de manifest + include(cmake/o3de_manifest.cmake) +endif() + +################################################################################ +# Resolve this engines name and restricted path +################################################################################ +o3de_engine_name(${o3de_engine_json} o3de_engine_name) +o3de_restricted_path(${o3de_engine_json} o3de_engine_restricted_path) +message(STATUS "O3DE Engine Name: ${o3de_engine_name}") +message(STATUS "O3DE Engine Path: ${o3de_engine_path}") +if(o3de_engine_restricted_path) + message(STATUS "O3DE Engine Restricted Path: ${o3de_engine_restricted_path}") endif() +# add the engines cmake folder to the CMAKE_MODULE_PATH +list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") + +################################################################################ +# Initialize +################################################################################ include(cmake/GeneralSettings.cmake) include(cmake/FileUtil.cmake) include(cmake/PAL.cmake) @@ -60,20 +84,19 @@ include(cmake/Projects.cmake) if(NOT INSTALLED_ENGINE) # Add the rest of the targets add_subdirectory(Code) - add_subdirectory(Gems) else() ly_find_o3de_packages() endif() +# Add external subdirectories listed in the manifest +list(APPEND LY_EXTERNAL_SUBDIRS ${o3de_engine_external_subdirectories}) + 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() +# Add any engine restricted platforms as external subdirs +o3de_add_engine_restricted_platform_external_subdirs() if(NOT INSTALLED_ENGINE) add_subdirectory(scripts) diff --git a/Code/CryEngine/CryCommon/CREBaseCloud.h b/Code/CryEngine/CryCommon/CREBaseCloud.h deleted file mode 100644 index b7a95d88d4..0000000000 --- a/Code/CryEngine/CryCommon/CREBaseCloud.h +++ /dev/null @@ -1,158 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef __CREBASECLOUD_H__ -#define __CREBASECLOUD_H__ - -//================================================================================ - -class SCloudParticle -{ -public: - inline SCloudParticle(); - inline SCloudParticle(const Vec3& vPos, float fRadius, const ColorF& baseColor, float fTransparency = 0); - inline SCloudParticle(const Vec3& vPos, float fRadiusX, float fRadiusY, float fRotMin, float fRotMax, Vec2 vUV[]); - inline ~SCloudParticle(); - - float GetRadiusX() const { return m_fSize[0]; } - float GetRadiusY() const { return m_fSize[1]; } - float GetTransparency() const { return m_fTransparency; } - const Vec3& GetPosition() const { return m_vPosition; } - const ColorF& GetBaseColor() const { return m_vBaseColor; } - uint32 GetNumLitColors() const { return m_vLitColors.size(); } - inline const ColorF GetLitColor(unsigned int index) const; - float GetSquareSortDistance() const { return m_fSquareSortDistance; } - - //! Sets the radius of the particle. - void SetRadiusX(float rad) { m_fSize[0] = rad; } - void SetRadiusY(float rad) { m_fSize[1] = rad; } - void SetTransparency(float trans) { m_fTransparency = trans; } - void SetPosition(const Vec3& pos) { m_vPosition = pos; } - void SetBaseColor(const ColorF& col) { m_vBaseColor = col; } - void AddLitColor(const ColorF& col) { m_vLitColors.push_back(col); } - void ClearLitColors() { m_vLitColors.clear(); } - void SetSquareSortDistance(float fSquareDistance) { m_fSquareSortDistance = fSquareDistance; } - - bool operator<(const SCloudParticle& p) const - { - return (m_fSquareSortDistance < p.m_fSquareSortDistance); - } - - bool operator>(const SCloudParticle& p) const - { - return (m_fSquareSortDistance > p.m_fSquareSortDistance); - } - -protected: - float m_fTransparency; - Vec3 m_vPosition; - float m_fSize[2]; - float m_fRotMin; - float m_fRotMax; - ColorF m_vBaseColor; - TArray m_vLitColors; - Vec3 m_vEye; - - // for sorting particles during shading - float m_fSquareSortDistance; -public: - Vec2 m_vUV[2]; -}; - -inline SCloudParticle::SCloudParticle() -{ - m_fSize[0] = 0; - m_fTransparency = 0; - m_vPosition = Vec3(0, 0, 0); - m_vBaseColor = Col_Black; - m_vEye = Vec3(0, 0, 0); - m_fSquareSortDistance = 0; - - m_vLitColors.clear(); -} - -inline SCloudParticle::SCloudParticle(const Vec3& pos, float fRadius, const ColorF& baseColor, float fTransparency) -{ - m_fSize[0] = fRadius; - m_fSize[1] = fRadius; - m_fTransparency = fTransparency; - m_vPosition = pos; - m_vBaseColor = baseColor; - m_vUV[0] = Vec2(0, 0); - m_vUV[1] = Vec2(1, 1); - - m_fRotMin = 0; - m_fRotMax = 0; - m_vEye = Vec3(0, 0, 0); - m_fSquareSortDistance = 0; - - m_vLitColors.clear(); -} - -inline SCloudParticle::SCloudParticle(const Vec3& vPos, float fRadiusX, float fRadiusY, float fRotMin, float fRotMax, Vec2 vUV[2]) -{ - m_fSize[0] = fRadiusX; - m_fSize[1] = fRadiusY; - m_vPosition = vPos; - m_vBaseColor = Col_White; - m_vUV[0] = vUV[0]; - m_vUV[1] = vUV[1]; - m_fRotMin = fRotMin; - m_fRotMax = fRotMax; - - m_fTransparency = 1.0f; - m_vEye = Vec3(0, 0, 0); - m_fSquareSortDistance = 0; - - m_vLitColors.clear(); -} - -inline SCloudParticle::~SCloudParticle() -{ - m_vLitColors.clear(); -} - -inline const ColorF SCloudParticle::GetLitColor(unsigned int index) const -{ - if (index <= m_vLitColors.size()) - { - return m_vLitColors[index]; - } - else - { - return Col_Black; - } -} - -//=========================================================================== -class CREBaseCloud - : public CRendElementBase -{ - friend class CRECloud; - -public: - CREBaseCloud() - : CRendElementBase() - { - mfSetType(eDATA_Cloud); - mfUpdateFlags(FCEF_TRANSFORM); - } - virtual void SetParticles(SCloudParticle* pParticles, int nNumParticles) = 0; - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } -}; - -#endif // __CREBASECLOUD_H__ diff --git a/Code/CryEngine/CryCommon/CREFogVolume.h b/Code/CryEngine/CryCommon/CREFogVolume.h deleted file mode 100644 index 83a024d15e..0000000000 --- a/Code/CryEngine/CryCommon/CREFogVolume.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -#ifndef _CREFOGVOLUME_ -#define _CREFOGVOLUME_ - -#pragma once - -#include "VertexFormats.h" - - -struct IFogVolumeRenderNode; - - -class CREFogVolume - : public CRendElementBase -{ -public: - CREFogVolume(); - - virtual ~CREFogVolume(); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - - Vec3 m_center; - uint32 m_viewerInsideVolume : 1; - uint32 m_affectsThisAreaOnly : 1; - uint32 m_stencilRef : 8; - uint32 m_volumeType : 1; - uint32 m_reserved : 21; - AABB m_localAABB; - Matrix34 m_matWSInv; - float m_globalDensity; - float m_densityOffset; - float m_nearCutoff; - Vec2 m_softEdgesLerp; - ColorF m_fogColor; // color already combined with fHDRDynamic - Vec3 m_heightFallOffDirScaled; - Vec3 m_heightFallOffBasePoint; - Vec3 m_eyePosInWS; - Vec3 m_eyePosInOS; - Vec3 m_rampParams; - Vec3 m_windOffset; - float m_noiseScale; - Vec3 m_noiseFreq; - float m_noiseOffset; - float m_noiseElapsedTime; - Vec3 m_scale; -}; - - -#endif // #ifndef _CREFOGVOLUME_ diff --git a/Code/CryEngine/CryCommon/CREGameEffect.h b/Code/CryEngine/CryCommon/CREGameEffect.h deleted file mode 100644 index 17e68813ed..0000000000 --- a/Code/CryEngine/CryCommon/CREGameEffect.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -#ifndef _CREGameEffect_ -#define _CREGameEffect_ - -#pragma once - -//================================================================================================== -// Name: IREGameEffect -// Desc: Interface for game effect render elements, designed to be instantiated in game code, and -// called from the CREGameEffect within the engine. This then allows render elements -// to be created in game code as well as in the engine. -// Author: James Chilvers -//================================================================================================== -struct IREGameEffect -{ - virtual ~IREGameEffect(){} - - virtual void mfPrepare(bool bCheckOverflow) = 0; - virtual bool mfDraw(CShader* ef, SShaderPass* sfm, CRenderObject* renderObj) = 0; -};//------------------------------------------------------------------------------------------------ - -//================================================================================================== -// Name: CREGameEffect -// Desc: Render element that uses the IREGameEffect interface for its functionality -// Author: James Chilvers -//================================================================================================== -class CREGameEffect - : public CRendElementBase -{ -public: - - CREGameEffect(); - ~CREGameEffect(); - - // CRendElementBase interface - void mfPrepare(bool bCheckOverflow); - bool mfDraw(CShader* ef, SShaderPass* sfm); - - // CREGameEffect interface - inline void SetPrivateImplementation(IREGameEffect* pImpl) { m_pImpl = pImpl; } - inline IREGameEffect* GetPrivateImplementation() const { return m_pImpl; } - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } -private: - - IREGameEffect* m_pImpl; // Implementation of of render element -};//------------------------------------------------------------------------------------------------ - -#endif // #ifndef _CREGameEffect_ diff --git a/Code/CryEngine/CryCommon/CREGeomCache.h b/Code/CryEngine/CryCommon/CREGeomCache.h deleted file mode 100644 index 6911b8486e..0000000000 --- a/Code/CryEngine/CryCommon/CREGeomCache.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Backend part of geometry cache rendering - -#ifndef CRYINCLUDE_CRYCOMMON_CREGEOMCACHE_H -#define CRYINCLUDE_CRYCOMMON_CREGEOMCACHE_H -#pragma once - -#if defined(USE_GEOM_CACHES) - -#include -#include - -class CREGeomCache - : public CRendElementBase -{ -public: - struct SMeshInstance - { - AABB m_aabb; - Matrix34 m_matrix; - Matrix34 m_prevMatrix; - }; - - struct SMeshRenderData - { - DynArray m_instances; - _smart_ptr m_pRenderMesh; - }; - - struct UpdateList - { - CryCriticalSection m_mutex; - AZStd::vector> m_geoms; - }; - -public: - CREGeomCache(); - ~CREGeomCache(); - - bool Update(const int flags, const bool bTesselation); - static void UpdateModified(); - - // CRendElementBase interface - virtual bool mfUpdate(int Flags, bool bTessellation); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - // CREGeomCache interface - virtual void InitializeRenderElement(const uint numMeshes, _smart_ptr* pMeshes, uint16 materialId); - virtual void SetupMotionBlur(CRenderObject* pRenderObject, const SRenderingPassInfo& passInfo); - - virtual volatile int* SetAsyncUpdateState(int& threadId); - virtual DynArray* GetMeshFillDataPtr(); - virtual DynArray* GetRenderDataPtr(); - virtual void DisplayFilledBuffer(const int threadId); - - - AZ::Vertex::Format GetVertexFormat() const override; - bool GetGeometryInfo(SGeometryInfo &streams) override; - -private: - uint16 m_materialId; - volatile bool m_bUpdateFrame[2]; - volatile int m_transformUpdateState[2]; - - // We use a double buffered m_meshFillData array for input from the main thread. When data - // was successfully sent from the main thread it gets copied to m_meshRenderData - // This simplifies the cases where frame data is missing, e.g. meshFillData is not updated for a frame - // Note that meshFillData really needs to be double buffered because the copy occurs in render thread - // so the next main thread could already be touching the data again - // - // Note: m_meshRenderData is directly accessed for ray intersections via GetRenderDataPtr. - // This is safe, because it's only used in editor. - DynArray m_meshFillData[2]; - DynArray m_meshRenderData; - - static StaticInstance sm_updateList[2]; // double buffered update lists - - AZ::Vertex::Format m_geomCacheVertexFormat; -}; - -#endif -#endif // CRYINCLUDE_CRYCOMMON_CREGEOMCACHE_H diff --git a/Code/CryEngine/CryCommon/CREImposter.h b/Code/CryEngine/CryCommon/CREImposter.h deleted file mode 100644 index 1150212b7d..0000000000 --- a/Code/CryEngine/CryCommon/CREImposter.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include -#include "Cry_Camera.h" - -//================================================================================ - -struct SDynTexture2; -struct SDynTexture; -class IDynTexture; -class CameraViewParameters; - -struct IImposterRenderElement -{ - virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0; - virtual void mfPrepare(bool bCheckOverflow) = 0; - virtual bool mfDraw(CShader* ef, SShaderPass* sl) = 0; - virtual const SMinMaxBox& mfGetWorldSpaceBounds() = 0; - - virtual bool IsSplit() = 0; - virtual bool IsScreenImposter() = 0; - - virtual float GetRadiusX() = 0; - virtual float GetRadiusY() = 0; - virtual Vec3* GetQuadCorners() = 0; - virtual Vec3 GetNearPoint() = 0; - virtual Vec3 GetFarPoint() = 0; - virtual float GetErrorToleranceCosAngle() = 0; - virtual uint32 GetState() = 0; - virtual int GetAlphaRef() = 0; - virtual ColorF GetColorHelper() = 0; - virtual Vec3 GetLastSunDirection() = 0; - virtual uint8 GetLastBestEdge() = 0; - virtual float GetNear() = 0; - virtual float GetFar() = 0; - virtual float GetTransparency() = 0; - virtual Vec3 GetPosition(); - virtual int GetLogResolutionX() = 0; - virtual int GetLogResolutionY() = 0; - virtual CameraViewParameters& GetLastViewParameters() = 0; - virtual IDynTexture* GetTexture() = 0; - virtual IDynTexture* GetScreenTexture() = 0; - virtual IDynTexture* GetFrontTexture() = 0; - virtual IDynTexture* GetDepthTexture() = 0; - virtual const SMinMaxBox& GetWorldSpaceBounds() = 0; - - virtual void SetBBox(const Vec3& min, const Vec3& max) = 0; - virtual void SetScreenImposterState(bool state) = 0; - virtual void SetState(uint32 state) = 0; - virtual void SetAlphaRef(uint32 ref) = 0; - virtual void SetPosition(Vec3 pos) = 0; - virtual void SetFrameResetValue(int frameResetValue) = 0; - virtual void SetTexture(IDynTexture* texture) = 0; - virtual void SetScreenTexture(IDynTexture* texture) = 0; - virtual void SetFrontTexture(IDynTexture* texture) = 0; - virtual void SetDepthTexture(IDynTexture* texture) = 0; -}; - -class CREImposter - : public CRendElementBase -{ - friend class CRECloud; - static IDynTexture* m_pScreenTexture; - - CameraViewParameters m_LastViewParameters; - bool m_bScreenImposter; - bool m_bSplit; - float m_fRadiusX; - float m_fRadiusY; - Vec3 m_vQuadCorners[4]; // in world space, relative to m_vPos, in clockwise order, can be rotated - Vec3 m_vNearPoint; - Vec3 m_vFarPoint; - int m_nLogResolutionX; - int m_nLogResolutionY; - IDynTexture* m_pTexture; - IDynTexture* m_pFrontTexture; - IDynTexture* m_pTextureDepth; - float m_fErrorToleranceCosAngle; // cosine of m_fErrorToleranceAngle used to check if IsImposterValid - SMinMaxBox m_WorldSpaceBV; - uint32 m_State; - int m_AlphaRef; - float m_fCurTransparency; - ColorF m_ColorHelper; - Vec3 m_vPos; - Vec3 m_vLastSunDir; - uint8 m_nLastBestEdge; // 0..11 this edge is favored to not jitter between different edges - float m_fNear; - float m_fFar; - - bool IsImposterValid(const CameraViewParameters& viewParameters, float fRadiusX, float fRadiusY, float fCamRadiusX, float fCamRadiusY, - const int iRequiredLogResX, const int iRequiredLogResY, const uint32 dwBestEdge); - - bool Display(bool bDisplayFrontOfSplit); - -public: - int m_nFrameReset; - int m_FrameUpdate; - float m_fTimeUpdate; - - static int m_MemUpdated; - static int m_MemPostponed; - static int m_PrevMemUpdated; - static int m_PrevMemPostponed; - - CREImposter() - : CRendElementBase() - , m_pTexture(NULL) - , m_pFrontTexture(NULL) - , m_pTextureDepth(NULL) - , m_bSplit(false) - , m_fRadiusX(0) - , m_fRadiusY(0) - , m_fErrorToleranceCosAngle(cos(DEG2RAD(0.25f))) - , m_bScreenImposter(false) - , m_State(GS_DEPTHWRITE) - , m_AlphaRef(-1) - , m_fCurTransparency(1.0f) - , m_FrameUpdate(0) - , m_nFrameReset(0) - , m_fTimeUpdate(0) - , m_vLastSunDir(0, 0, 0) - , m_nLogResolutionX(0) - , m_nLogResolutionY(0) - , m_nLastBestEdge(0) - { - mfSetType(eDATA_Imposter); - mfUpdateFlags(FCEF_TRANSFORM); - m_ColorHelper = Col_White; - } - virtual ~CREImposter() - { - ReleaseResources(); - } - - bool UpdateImposter(); - void ReleaseResources(); - - bool PrepareForUpdate(); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sl); - const SMinMaxBox& mfGetWorldSpaceBounds() { return m_WorldSpaceBV; } - - virtual bool IsSplit() { return m_bSplit; } - virtual bool IsScreenImposter() { return m_bScreenImposter; } - - virtual float GetRadiusX() { return m_fRadiusX; } - virtual float GetRadiusY() { return m_fRadiusY; } - virtual Vec3* GetQuadCorners() { return &m_vQuadCorners[0]; } - virtual Vec3 GetNearPoint() { return m_vNearPoint; } - virtual Vec3 GetFarPoint() { return m_vFarPoint; } - virtual float GetErrorToleranceCosAngle() { return m_fErrorToleranceCosAngle; } - virtual uint32 GetState() { return m_State; } - virtual int GetAlphaRef() { return m_AlphaRef; } - virtual ColorF GetColorHelper() { return m_ColorHelper; } - virtual Vec3 GetLastSunDirection() { return m_vLastSunDir; } - virtual uint8 GetLastBestEdge() { return m_nLastBestEdge; } - virtual float GetNear() { return m_fNear; } - virtual float GetFar() { return m_fFar; } - virtual float GetTransparency() { return m_fCurTransparency; } - virtual Vec3 GetPosition(); - virtual int GetLogResolutionX() { return m_nLogResolutionX; } - virtual int GetLogResolutionY() { return m_nLogResolutionY; } - virtual CameraViewParameters& GetLastViewParameters() { return m_LastViewParameters; } - virtual IDynTexture** GetTexture() { return &m_pTexture; } - virtual IDynTexture** GetScreenTexture() { return &m_pScreenTexture; } - virtual IDynTexture** GetFrontTexture() { return &m_pFrontTexture; } - virtual IDynTexture** GetDepthTexture() { return &m_pTextureDepth; } - virtual const SMinMaxBox& GetWorldSpaceBounds() { return m_WorldSpaceBV; } - virtual int GetFrameReset() { return m_nFrameReset; } - virtual void SetBBox(const Vec3& min, const Vec3& max) { m_WorldSpaceBV.SetMin(min); m_WorldSpaceBV.SetMax(max); } - virtual void SetScreenImposterState(bool state) { m_bScreenImposter = state; } - virtual void SetState(uint32 state) { m_State = state; } - virtual void SetAlphaRef(uint32 ref) { m_AlphaRef = ref; } - virtual void SetPosition(Vec3 pos) { m_vPos = pos; } - virtual void SetFrameResetValue(int frameResetValue) { m_nFrameReset = frameResetValue; } -}; diff --git a/Code/CryEngine/CryCommon/CREMesh.h b/Code/CryEngine/CryCommon/CREMesh.h deleted file mode 100644 index 40df816808..0000000000 --- a/Code/CryEngine/CryCommon/CREMesh.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef __CREMESH_H__ -#define __CREMESH_H__ - -class CREMesh - : public CRendElementBase -{ -public: - - struct CRenderChunk* m_pChunk; - class CRenderMesh* m_pRenderMesh; - - // Copy of Chunk to avoid indirections - int32 m_nFirstIndexId; - int32 m_nNumIndices; - - uint32 m_nFirstVertId; - uint32 m_nNumVerts; - -protected: - CREMesh() - { - mfSetType(eDATA_Mesh); - mfUpdateFlags(FCEF_TRANSFORM); - - m_pChunk = NULL; - m_pRenderMesh = NULL; - m_nFirstIndexId = -1; - m_nNumIndices = -1; - m_nFirstVertId = 0; - m_nNumVerts = 0; - } - - virtual ~CREMesh() - { - } - - // Ideally should be declared and left unimplemented to prevent slicing at compile time - // but this would prevent auto code gen in renderer later on. - // To track potential slicing, uncomment the following (and their equivalent in CREMeshImpl) - //CREMesh(CREMesh&); - //CREMesh& operator=(CREMesh& rhs); -}; - -#endif // __CREMESH_H__ diff --git a/Code/CryEngine/CryCommon/CREOcclusionQuery.h b/Code/CryEngine/CryCommon/CREOcclusionQuery.h deleted file mode 100644 index 9350a74104..0000000000 --- a/Code/CryEngine/CryCommon/CREOcclusionQuery.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef __CREOCCLUSIONQUERY_H__ -#define __CREOCCLUSIONQUERY_H__ - -#define SUPP_HMAP_OCCL -#define SUPP_HWOBJ_OCCL - -//============================================================= - -class CRenderMesh; - -class CREOcclusionQuery - : public CRendElementBase -{ - friend class CRender3D; - bool m_bSucceeded; -public: - - int m_nVisSamples; - int m_nCheckFrame; - int m_nDrawFrame; - Vec3 m_vBoxMin; - Vec3 m_vBoxMax; - - UINT_PTR m_nOcclusionID; // this will carry a pointer LPDIRECT3DQUERY9, so it needs to be 64-bit on Windows 64 - - CRenderMesh* m_pRMBox; - static uint32 m_nQueriesPerFrameCounter; - static uint32 m_nReadResultNowCounter; - static uint32 m_nReadResultTryCounter; - - CREOcclusionQuery() - { - m_nOcclusionID = 0; - - m_nVisSamples = 800 * 600; - m_nCheckFrame = 0; - m_nDrawFrame = 0; - m_vBoxMin = Vec3(0, 0, 0); - m_vBoxMax = Vec3(0, 0, 0); - m_pRMBox = NULL; - - mfSetType(eDATA_OcclusionQuery); - mfUpdateFlags(FCEF_TRANSFORM); - } - - bool RT_ReadResult_Try(uint32 nDefaultNumSamples); - - ILINE bool HasSucceeded() const { return m_bSucceeded; } - - virtual ~CREOcclusionQuery(); - - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - virtual void mfReset(); - virtual bool mfReadResult_Try(uint32 nDefaultNumSamples = 1); - virtual bool mfReadResult_Now(); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } -}; - -struct OcclusionTestClient -{ - OcclusionTestClient() - : nLastOccludedMainFrameID(0) - , nLastVisibleMainFrameID(0) - { -#ifdef SUPP_HMAP_OCCL - vLastVisPoint.Set(0, 0, 0); - nTerrainOccLastFrame = 0; -#endif -#ifdef SUPP_HWOBJ_OCCL - bOccluded = true; - pREOcclusionQuery = 0; -#endif - //nInstantTestRequested=0; - } -#ifdef SUPP_HWOBJ_OCCL - ~OcclusionTestClient() - { - if (pREOcclusionQuery) - { - pREOcclusionQuery->Release(false); - } - } -#endif - uint32 nLastVisibleMainFrameID, nLastOccludedMainFrameID; - uint32 nLastShadowCastMainFrameID, nLastNoShadowCastMainFrameID; -#ifdef SUPP_HMAP_OCCL - Vec3 vLastVisPoint; - int nTerrainOccLastFrame; -#endif -#ifdef SUPP_HWOBJ_OCCL - CREOcclusionQuery* pREOcclusionQuery; - uint8 bOccluded; -#endif - //uint8 nInstantTestRequested; -}; - - -#endif // CRYINCLUDE_CRYCOMMON_CREOCCLUSIONQUERY_H diff --git a/Code/CryEngine/CryCommon/CREPostProcess.h b/Code/CryEngine/CryCommon/CREPostProcess.h deleted file mode 100644 index 4803ae2166..0000000000 --- a/Code/CryEngine/CryCommon/CREPostProcess.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_CREPOSTPROCESS_H -#define CRYINCLUDE_CRYCOMMON_CREPOSTPROCESS_H -#pragma once - - -class CREPostProcess - : public CRendElementBase -{ - friend class CD3D9Renderer; - -public: - - CREPostProcess(); - virtual ~CREPostProcess(); - - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - // Use for setting numeric values, vec4 (colors, position, vectors, wtv), strings - virtual int mfSetParameter(const char* pszParam, float fValue, bool bForceValue = false) const; - virtual int mfSetParameterVec4(const char* pszParam, const Vec4& pValue, bool bForceValue = false) const; - virtual int mfSetParameterString(const char* pszParam, const char* pszArg) const; - - virtual void mfGetParameter(const char* pszParam, float& fValue) const; - virtual void mfGetParameterVec4(const char* pszParam, Vec4& pValue) const; - virtual void mfGetParameterString(const char* pszParam, const char*& pszArg) const; - - virtual int32 mfGetPostEffectID(const char* pPostEffectName) const; - - // Reset all post processing effects - virtual void Reset(bool bOnSpecChange = false); - virtual void mfReset() - { - Reset(); - } - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } -}; - -#endif // CRYINCLUDE_CRYCOMMON_CREPOSTPROCESS_H diff --git a/Code/CryEngine/CryCommon/CREPrismObject.h b/Code/CryEngine/CryCommon/CREPrismObject.h deleted file mode 100644 index 4ec290f1b9..0000000000 --- a/Code/CryEngine/CryCommon/CREPrismObject.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -#ifndef _CREPRISMOBJECT_ -#define _CREPRISMOBJECT_ - -#pragma once - -#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE) - -class CREPrismObject - : public CRendElementBase -{ -public: - CREPrismObject(); - - virtual ~CREPrismObject() {} - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - - Vec3 m_center; -}; - -#endif // EXCLUDE_DOCUMENTATION_PURPOSE - -#endif // _CREPRISMOBJECT_ diff --git a/Code/CryEngine/CryCommon/CRESky.h b/Code/CryEngine/CryCommon/CRESky.h deleted file mode 100644 index 3dfc7d184f..0000000000 --- a/Code/CryEngine/CryCommon/CRESky.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef __CRESKY_H__ -#define __CRESKY_H__ - -//============================================================= - -#include "VertexFormats.h" -#include - -struct SSkyLightRenderParams; - -class CRESky - : public CRendElementBase -{ - friend class CRender3D; - -public: - - float m_fTerrainWaterLevel; - float m_fSkyBoxStretching; - float m_fAlpha; - int m_nSphereListId; - -public: - CRESky(); - virtual ~CRESky(); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - - AZ::Vertex::Format GetVertexFormat() const override; - bool GetGeometryInfo(SGeometryInfo& streams) override; - -private: - AZ::Vertex::Format m_skyVertexFormat; -}; - -class CREHDRSky - : public CRendElementBase -{ -public: - CREHDRSky(); - virtual ~CREHDRSky(); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - - void GenerateSkyDomeTextures(int32 width, int32 height); - - virtual AZ::Vertex::Format GetVertexFormat() const override; - virtual bool GetGeometryInfo(SGeometryInfo& streams) override; - -public: - const SSkyLightRenderParams* m_pRenderParams; - int m_moonTexId; - class CTexture* m_pSkyDomeTextureMie; - class CTexture* m_pSkyDomeTextureRayleigh; - - static void SetCommonMoonParams(CShader* ef, bool bUseMoon = false); - -private: - void Init(); - -private: - int m_skyDomeTextureLastTimeStamp; - int m_frameReset; - class CStars* m_pStars; - AZ::Vertex::Format m_hdrSkyVertexFormat; -}; - - -#endif // __CRESKY_H__ diff --git a/Code/CryEngine/CryCommon/CREVolumeObject.h b/Code/CryEngine/CryCommon/CREVolumeObject.h deleted file mode 100644 index 2137053a8e..0000000000 --- a/Code/CryEngine/CryCommon/CREVolumeObject.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -#ifndef _CREVOLUMEOBJECT_ -#define _CREVOLUMEOBJECT_ - -#pragma once - -#include "VertexFormats.h" - - -struct IVolumeObjectRenderNode; - -struct IVolumeTexture -{ -public: - virtual ~IVolumeTexture() {} - virtual void Release() = 0; - virtual bool Create(unsigned int width, unsigned int height, unsigned int depth, unsigned char* pData) = 0; - virtual bool Update(unsigned int width, unsigned int height, unsigned int depth, const unsigned char* pData) = 0; - virtual int GetTexID() const = 0; - virtual uint32 GetWidth() const = 0; - virtual uint32 GetHeight() const = 0; - virtual uint32 GetDepth() const = 0; - virtual ITexture* GetTexture() const = 0; -}; - -class CREVolumeObject - : public CRendElementBase -{ -public: - CREVolumeObject(); - - virtual ~CREVolumeObject(); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - - virtual IVolumeTexture* CreateVolumeTexture() const; - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - - Vec3 m_center; - Matrix34 m_matInv; - Vec3 m_eyePosInWS; - Vec3 m_eyePosInOS; - Plane_tpl m_volumeTraceStartPlane; - AABB m_renderBoundsOS; - bool m_viewerInsideVolume; - bool m_nearPlaneIntersectsVolume; - float m_alpha; - float m_scale; - - IVolumeTexture* m_pDensVol; - IVolumeTexture* m_pShadVol; - _smart_ptr m_pHullMesh; -}; - -#endif // #ifndef _CREVOLUMEOBJECT_ diff --git a/Code/CryEngine/CryCommon/CREWaterOcean.h b/Code/CryEngine/CryCommon/CREWaterOcean.h deleted file mode 100644 index e8ca310d41..0000000000 --- a/Code/CryEngine/CryCommon/CREWaterOcean.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef _CREWATEROCEAN_ -#define _CREWATEROCEAN_ - -class CWater; - -class CREWaterOcean - : public CRendElementBase -{ -public: - CREWaterOcean(); - virtual ~CREWaterOcean(); - - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - virtual void mfGetPlane(Plane_tpl& pl); - - virtual void Create(uint32 nVerticesCount, SVF_P3F_C4B_T2F* pVertices, uint32 nIndicesCount, const void* pIndices, uint32 nIndexSizeof); - void ReleaseOcean(); - - virtual Vec3 GetPositionAt(float x, float y) const; - virtual Vec4* GetDisplaceGrid() const; - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } -private: - - uint32 m_nVerticesCount; - uint32 m_nIndicesCount; - uint32 m_nIndexSizeof; - - void* m_pVertDecl; - void* m_pVertices; - void* m_pIndices; - -private: - - void UpdateFFT(); - void FrameUpdate(); -}; - - -#endif diff --git a/Code/CryEngine/CryCommon/CREWaterVolume.h b/Code/CryEngine/CryCommon/CREWaterVolume.h deleted file mode 100644 index 89102e3097..0000000000 --- a/Code/CryEngine/CryCommon/CREWaterVolume.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -#ifndef _CREWATERVOLUME_ -#define _CREWATERVOLUME_ - -#pragma once - - -#include "VertexFormats.h" - -class CREWaterVolume - : public CRendElementBase -{ -public: - CREWaterVolume(); - - virtual ~CREWaterVolume(); - virtual void mfPrepare(bool bCheckOverflow); - virtual bool mfDraw(CShader* ef, SShaderPass* sfm); - virtual void mfGetPlane(Plane_tpl& pl); - virtual void mfCenter(Vec3& vCenter, CRenderObject* pObj); - - virtual void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(this, sizeof(*this)); - } - -public: - struct SParams - { - SParams() - : m_pVertices(0) - , m_pIndices(0) - , m_numVertices(0) - , m_numIndices(0) - , m_center(0, 0, 0) - , m_WSBBox(Vec3(-1, -1, -1), Vec3(1, 1, 1)) - , m_fogPlane(Vec3(0, 0, 1), 0) - , m_fogDensity(0.1f) - , m_fogColor(0.2f, 0.5f, 0.7f) - , m_fogColorAffectedBySun(true) - , m_fogShadowing(0.5f) - , m_caustics(true) - , m_causticIntensity(1.0f) - , m_causticTiling(1.0f) - , m_causticHeight(0.9f) - , m_viewerInsideVolume(false) - , m_viewerCloseToWaterPlane(false) - , m_viewerCloseToWaterVolume(false) - { - } - - const SVF_P3F_C4B_T2F* m_pVertices; - const uint16* m_pIndices; - - size_t m_numVertices; - size_t m_numIndices; - - Vec3 m_center; - AABB m_WSBBox; - - Plane_tpl m_fogPlane; - float m_fogDensity; - Vec3 m_fogColor; - bool m_fogColorAffectedBySun; - float m_fogShadowing; - - bool m_caustics; - float m_causticIntensity; - float m_causticTiling; - float m_causticHeight; - - bool m_viewerInsideVolume; - bool m_viewerCloseToWaterPlane; - bool m_viewerCloseToWaterVolume; - }; - - struct SOceanParams - { - SOceanParams() - : m_fogColor(0.2f, 0.5f, 0.7f) - , m_fogColorShallow(0.2f, 0.5f, 0.7f) - , m_fogDensity(0.2f) - { - } - - Vec3 m_fogColor; - Vec3 m_fogColorShallow; - float m_fogDensity; - }; - -public: - const SParams* m_pParams; - const SOceanParams* m_pOceanParams; - bool m_drawWaterSurface; - bool m_drawFastPath; -}; - - -#endif // #ifndef _CREWATERVOLUME_ diff --git a/Code/CryEngine/CryCommon/CryAssert_Mac.h b/Code/CryEngine/CryCommon/CryAssert_Mac.h index 8cf49e1a5d..9502605fea 100644 --- a/Code/CryEngine/CryCommon/CryAssert_Mac.h +++ b/Code/CryEngine/CryCommon/CryAssert_Mac.h @@ -45,43 +45,6 @@ void CryAssertTrace(const char* szFormat, ...) } } } -/* -bool CryAssert(const char* szCondition, const char* szFile,unsigned int line, bool *pIgnore) -{ - if (!gEnv) return false; - - gEnv->pSystem->OnAssert(szCondition, gs_szMessage, szFile, line); - - if (!gEnv->bNoAssertDialog && !gEnv->bIgnoreAllAsserts) - { - EDialogAction action = MacOSXHandleAssert(szCondition, szFile, line, gs_szMessage, gEnv->pRenderer != NULL); - - switch (action) { - case eDAStop: - raise(SIGABRT); - exit(-1); - case eDABreak: - return true; - case eDAIgnoreAll: - gEnv->bIgnoreAllAsserts = true; - break; - case eDAIgnore: - *pIgnore = true; - break; - case eDAReportAsBug: - if ( gEnv && gEnv->pSystem) - { - gEnv->pSystem->ReportBug("Assert: %s - %s", szCondition,gs_szMessage); - } - - case eDAContinue: - default: - break; - } - } - - return false; -}*/ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, bool* pIgnore) { diff --git a/Code/CryEngine/CryCommon/CryMemoryManager.h b/Code/CryEngine/CryCommon/CryMemoryManager.h index 4547ae70bc..b3f8ba7c8e 100644 --- a/Code/CryEngine/CryCommon/CryMemoryManager.h +++ b/Code/CryEngine/CryCommon/CryMemoryManager.h @@ -116,7 +116,6 @@ namespace CryMemory struct ICustomMemoryHeap; class IGeneralMemoryHeap; class IPageMappingHeap; -class IDefragAllocator; class IMemoryAddressRange; // Description: @@ -180,8 +179,6 @@ struct IMemoryManager virtual IMemoryAddressRange* ReserveAddressRange(size_t capacity, const char* sName) = 0; virtual IPageMappingHeap* CreatePageMappingHeap(size_t addressSpace, const char* sName) = 0; - - virtual IDefragAllocator* CreateDefragAllocator() = 0; }; // Global function implemented in CryMemoryManager_impl.h diff --git a/Code/CryEngine/CryCommon/Cry_Camera.h b/Code/CryEngine/CryCommon/Cry_Camera.h index 56a764d897..d0eb318e94 100644 --- a/Code/CryEngine/CryCommon/Cry_Camera.h +++ b/Code/CryEngine/CryCommon/Cry_Camera.h @@ -620,24 +620,24 @@ public: bool IsPointVisible(const Vec3& p) const; //sphere-frustum test - bool IsSphereVisible_F(const Sphere& s) const; - uint8 IsSphereVisible_FH(const Sphere& s) const; //this is going to be the exact version of sphere-culling + bool IsSphereVisible_F(const ::Sphere& s) const; + uint8 IsSphereVisible_FH(const ::Sphere& s) const; //this is going to be the exact version of sphere-culling // AABB-frustum test // Fast - bool IsAABBVisible_F(const AABB& aabb) const; - uint8 IsAABBVisible_FH(const AABB& aabb, bool* pAllInside) const; - uint8 IsAABBVisible_FH(const AABB& aabb) const; + bool IsAABBVisible_F(const ::AABB& aabb) const; + uint8 IsAABBVisible_FH(const ::AABB& aabb, bool* pAllInside) const; + uint8 IsAABBVisible_FH(const ::AABB& aabb) const; // Exact - bool IsAABBVisible_E(const AABB& aabb) const; - uint8 IsAABBVisible_EH(const AABB& aabb, bool* pAllInside) const; - uint8 IsAABBVisible_EH(const AABB& aabb) const; + bool IsAABBVisible_E(const ::AABB& aabb) const; + uint8 IsAABBVisible_EH(const ::AABB& aabb, bool* pAllInside) const; + uint8 IsAABBVisible_EH(const ::AABB& aabb) const; // Multi-camera - bool IsAABBVisible_EHM(const AABB& aabb, bool* pAllInside) const; - bool IsAABBVisible_EM(const AABB& aabb) const; - bool IsAABBVisible_FM(const AABB& aabb) const; + bool IsAABBVisible_EHM(const ::AABB& aabb, bool* pAllInside) const; + bool IsAABBVisible_EM(const ::AABB& aabb) const; + bool IsAABBVisible_FM(const ::AABB& aabb) const; //OBB-frustum test bool IsOBBVisible_F(const Vec3& wpos, const OBB& obb) const; @@ -1386,7 +1386,7 @@ inline bool CCamera::IsPointVisible(const Vec3& p) const // return values // CULL_EXCLUSION = sphere outside of frustum (very fast rejection-test) // CULL_INTERSECT = sphere and frustum intersects or sphere in completely inside frustum -inline bool CCamera::IsSphereVisible_F(const Sphere& s) const +inline bool CCamera::IsSphereVisible_F(const ::Sphere& s) const { if ((m_fp[0] | s.center) > s.radius) { @@ -1427,7 +1427,7 @@ inline bool CCamera::IsSphereVisible_F(const Sphere& s) const // CULL_EXCLUSION = sphere outside of frustum (very fast rejection-test) // CULL_INTERSECT = sphere intersects the borders of the frustum, further checks necessary // CULL_INCLUSION = sphere is complete inside the frustum, no further checks necessary -inline uint8 CCamera::IsSphereVisible_FH(const Sphere& s) const +inline uint8 CCamera::IsSphereVisible_FH(const ::Sphere& s) const { f32 nc, rc, lc, tc, bc, cc; if ((nc = m_fp[0] | s.center) > s.radius) diff --git a/Code/CryEngine/CryCommon/Cry_Geo.h b/Code/CryEngine/CryCommon/Cry_Geo.h index ebe27a469a..359896157c 100644 --- a/Code/CryEngine/CryCommon/Cry_Geo.h +++ b/Code/CryEngine/CryCommon/Cry_Geo.h @@ -794,7 +794,7 @@ struct HWVSphere radius = r; } - ILINE HWVSphere(const Sphere& sp) + ILINE HWVSphere(const ::Sphere& sp) { center = HWVLoadVecUnaligned(&sp.center); radius = SIMDFLoadFloat(sp.radius); diff --git a/Code/CryEngine/CryCommon/Cry_GeoDistance.h b/Code/CryEngine/CryCommon/Cry_GeoDistance.h index 47794c7671..2329038dc4 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoDistance.h +++ b/Code/CryEngine/CryCommon/Cry_GeoDistance.h @@ -1179,7 +1179,7 @@ namespace Distance { // float result = Distance::Point_TriangleSq( pos, triangle ); //---------------------------------------------------------------------------------- template - ILINE F Sphere_TriangleSq(const Sphere& s, const Triangle_tpl& t) + ILINE F Sphere_TriangleSq(const ::Sphere& s, const Triangle_tpl& t) { F sqdistance = Distance::Point_TriangleSq(s.center, t) - (s.radius * s.radius); if (sqdistance < 0) @@ -1190,7 +1190,7 @@ namespace Distance { } template - ILINE F Sphere_TriangleSq(const Sphere& s, const Triangle_tpl& t, Vec3_tpl& output) + ILINE F Sphere_TriangleSq(const ::Sphere& s, const Triangle_tpl& t, Vec3_tpl& output) { F sqdistance = Distance::Point_TriangleSq(s.center, t, output) - (s.radius * s.radius); if (sqdistance < 0) diff --git a/Code/CryEngine/CryCommon/Cry_GeoIntersect.h b/Code/CryEngine/CryCommon/Cry_GeoIntersect.h index 89f6d8ebaf..f0be567ce2 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoIntersect.h +++ b/Code/CryEngine/CryCommon/Cry_GeoIntersect.h @@ -792,7 +792,7 @@ namespace Intersect { //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Line_Sphere(const Line& line, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Line_Sphere(const Line& line, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 end = line.pointonline + line.direction; @@ -830,7 +830,7 @@ namespace Intersect { //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Ray_Sphere(const Ray& ray, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Ray_Sphere(const Ray& ray, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 end = ray.origin + ray.direction; float a = ray.direction | ray.direction; @@ -863,7 +863,7 @@ namespace Intersect { return intersection; } - inline bool Ray_SphereFirst(const Ray& ray, const Sphere& s, Vec3& intPoint) + inline bool Ray_SphereFirst(const Ray& ray, const ::Sphere& s, Vec3& intPoint) { Vec3 p2; unsigned char res = Ray_Sphere(ray, s, intPoint, p2); @@ -886,7 +886,7 @@ namespace Intersect { //--- 0x02 = one intersection, lineseg has just an EXIT point but no ENTRY point (ls.start is inside the sphere) -- //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Lineseg_Sphere(const Lineseg& ls, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Lineseg_Sphere(const Lineseg& ls, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 dir = (ls.end - ls.start); @@ -931,7 +931,7 @@ namespace Intersect { } - inline bool Lineseg_SphereFirst(const Lineseg& lineseg, const Sphere& s, Vec3& intPoint) + inline bool Lineseg_SphereFirst(const Lineseg& lineseg, const ::Sphere& s, Vec3& intPoint) { Vec3 p2; uint8 res = Lineseg_Sphere(lineseg, s, intPoint, p2); diff --git a/Code/CryEngine/CryCommon/Cry_GeoOverlap.h b/Code/CryEngine/CryCommon/Cry_GeoOverlap.h index ab560b7518..14af81258a 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoOverlap.h +++ b/Code/CryEngine/CryCommon/Cry_GeoOverlap.h @@ -103,7 +103,7 @@ namespace Overlap { // Checks if a point is inside a sphere. // Example: // bool result=Overlap::Point_Sphere( point, sphere ); - ILINE bool Point_Sphere(const Vec3& p, const Sphere& s) + ILINE bool Point_Sphere(const Vec3& p, const ::Sphere& s) { Vec3 distc = p - s.center; f32 sqrad = s.radius * s.radius; @@ -407,7 +407,7 @@ namespace Overlap { //! check if a Lineseg and a Sphere overlap - inline bool Lineseg_Sphere(const Lineseg& ls, const Sphere& s) + inline bool Lineseg_Sphere(const Lineseg& ls, const ::Sphere& s) { float radius2 = s.radius * s.radius; @@ -729,7 +729,7 @@ namespace Overlap { * 0 = no overlap * 1 = overlap *----------------------------------------------------------------------------------*/ - ILINE bool Sphere_AABB(const Sphere& s, const AABB& aabb) + ILINE bool Sphere_AABB(const ::Sphere& s, const AABB& aabb) { Vec3 center(s.center); @@ -746,7 +746,7 @@ namespace Overlap { } // As Sphere_AABB but ignores z parts - ILINE bool Sphere_AABB2D(const Sphere& s, const AABB& aabb) + ILINE bool Sphere_AABB2D(const ::Sphere& s, const AABB& aabb) { Vec3 center(s.center); @@ -776,7 +776,7 @@ namespace Overlap { * 0x01 = Sphere and AABB overlap * 0x02 = Sphere in inside AABB */ - ILINE char Sphere_AABB_Inside(const Sphere& s, const AABB& aabb) + ILINE char Sphere_AABB_Inside(const ::Sphere& s, const AABB& aabb) { if (Sphere_AABB(s, aabb)) { @@ -819,7 +819,7 @@ namespace Overlap { //--- 0 = no overlap --------------------------- //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- - inline bool Sphere_OBB(const Sphere& s, const OBB& obb) + inline bool Sphere_OBB(const ::Sphere& s, const OBB& obb) { //first we transform the sphere-center into the AABB-space of the OBB Vec3 SphereInOBBSpace = s.center * obb.m33; @@ -861,7 +861,7 @@ namespace Overlap { //--- 0 = no overlap --------------------------- //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- - inline bool Sphere_Sphere(const Sphere& s1, const Sphere& s2) + inline bool Sphere_Sphere(const ::Sphere& s1, const ::Sphere& s2) { Vec3 distc = s1.center - s2.center; f32 sqrad = (s1.radius + s2.radius) * (s1.radius + s2.radius); @@ -884,7 +884,7 @@ namespace Overlap { //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- template - ILINE bool Sphere_Triangle(const Sphere& s, const Triangle_tpl& t) + ILINE bool Sphere_Triangle(const ::Sphere& s, const Triangle_tpl& t) { //create a "bouding sphere" around triangle for fast rejection test Vec3_tpl middle = (t.v0 + t.v1 + t.v2) * (1 / 3.0f); @@ -899,7 +899,7 @@ namespace Overlap { SqRad0 = (F)fsel(SqRad0 - SqRad2, SqRad0, SqRad2); //first simple rejection-test... - if (Sphere_Sphere(s, Sphere(middle, sqrt_tpl(SqRad0))) == 0) + if (Sphere_Sphere(s, ::Sphere(middle, sqrt_tpl(SqRad0))) == 0) { return 0; //overlap not possible } diff --git a/Code/CryEngine/CryCommon/ICryMiniGUI.h b/Code/CryEngine/CryCommon/ICryMiniGUI.h deleted file mode 100644 index 95db2e6518..0000000000 --- a/Code/CryEngine/CryCommon/ICryMiniGUI.h +++ /dev/null @@ -1,286 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Mini GUI subsystem - - -#ifndef CRYINCLUDE_CRYCOMMON_ICRYMINIGUI_H -#define CRYINCLUDE_CRYCOMMON_ICRYMINIGUI_H -#pragma once - - -#include -#include -#include - -namespace minigui -{ - struct IMiniCtrl; - - // Rectangle class - struct Rect - { - float left; - float top; - float right; - float bottom; - - Rect() - : left(0) - , top(0) - , right(0) - , bottom(0) {} - Rect(float l, float t, float r, float b) - : left(l) - , top(t) - , right(r) - , bottom(b) {} - Rect(const Rect& rc) { left = rc.left; top = rc.top; right = rc.right; bottom = rc.bottom; } - bool IsPointInside(float x, float y) const { return x >= left && x <= right && y >= top && y <= bottom; } - float Width() const { return right - left; } - float Height() const { return bottom - top; } - }; - - typedef void(* ClickCallback)(void* data, bool onOff); - typedef void(* RenderCallback)(float x, float y); - - enum EMiniCtrlStatus - { - eCtrl_Hidden = BIT(0), // Control is hidden. - eCtrl_Highlight = BIT(1), // Control is highlight (probably mouse over). - eCtrl_Focus = BIT(2), // Control have focus (from keyboard). - eCtrl_Checked = BIT(3), // Control have checked mark. - eCtrl_NoBorder = BIT(4), // Control have no border. - eCtrl_CheckButton = BIT(5), // Button control behave as a check button. - eCtrl_TextAlignCentre = BIT(6), // Draw text aligned centre - eCtrl_AutoResize = BIT(7), // Auto resize depending on text length - eCtrl_Moveable = BIT(8), // Dynamically reposition ctrl - eCtrl_CloseButton = BIT(9), // Control has close button - }; - enum EMiniCtrlEvent - { - eCtrlEvent_LButtonDown = BIT(0), - eCtrlEvent_LButtonUp = BIT(1), - eCtrlEvent_LButtonPressed = BIT(2), - eCtrlEvent_MouseOver = BIT(3), - eCtrlEvent_MouseOff = BIT(4), - eCtrlEvent_DPadLeft = BIT(5), - eCtrlEvent_DPadRight = BIT(6), - eCtrlEvent_DPadUp = BIT(7), - eCtrlEvent_DPadDown = BIT(8), - }; - - // Types of the supported controls - enum EMiniCtrlType - { - eCtrlType_Unknown = 0, - eCtrlType_Button, - eCtrlType_Menu, - eCtrlType_InfoBox, - eCtrlType_Table, - }; - - struct SMetrics - { - float fTextSize; - float fTitleSize; - - // Colors. - ColorB clrFrameBorder; - ColorB clrFrameBorderHighlight; - ColorB clrFrameBorderOutOfFocus; - ColorB clrChecked; - ColorB clrBackground; - ColorB clrBackgroundHighlight; - ColorB clrBackgroundSelected; - ColorB clrTitle; - ColorB clrText; - ColorB clrTextSelected; - - uint8 outOfFocusAlpha; - }; - - enum ECommand - { - eCommand_ButtonPress, - eCommand_ButtonChecked, - eCommand_ButtonUnchecked, - }; - // Command sent from the control. - struct SCommand - { - ECommand command; - IMiniCtrl* pCtrl; - int nCtrlID; - }; - - ////////////////////////////////////////////////////////////////////////// - // Event listener interface for the MiniGUI - ////////////////////////////////////////////////////////////////////////// - struct IMiniGUIEventListener - { - // - virtual ~IMiniGUIEventListener(){} - virtual void OnCommand(SCommand& cmd) = 0; - // - }; - - // Interface to the GUI - struct IMiniGUI - : public ICryUnknown - { - public: - CRYINTERFACE_DECLARE(IMiniGUI, 0xea09d34268814f2a, 0xaf1034e04b076011); - - // - virtual void Init() = 0; - virtual void Done() = 0; - virtual void Draw() = 0; - virtual void Reset() = 0; - - virtual void SaveState() = 0; - virtual void RestoreState() = 0; - - virtual void SetEnabled(bool status) = 0; - virtual void SetInFocus(bool status) = 0; - virtual bool InFocus() = 0; - - virtual void SetEventListener(IMiniGUIEventListener* pListener) = 0; - - virtual SMetrics& Metrics() = 0; - - // Makes a new control - virtual IMiniCtrl* CreateCtrl(IMiniCtrl* pParentCtrl, int nCtrlID, EMiniCtrlType type, int nCtrlFlags, const Rect& rc, const char* title) = 0; - - // Remove all controls. - virtual void RemoveAllCtrl() = 0; - - virtual void OnCommand(SCommand& cmd) = 0; - - virtual IMiniCtrl* GetCtrlFromPoint(float x, float y) const = 0; - - virtual void SetMovingCtrl(IMiniCtrl* pCtrl) = 0; - // - }; - - DECLARE_SMART_POINTERS(IMiniGUI); - - struct IMiniCtrl - : public _reference_target_t - { - // - virtual void Reset() = 0; - - virtual void SaveState() = 0; - virtual void RestoreState() = 0; - - // For system call only. - virtual void SetGUI(IMiniGUI* pGUI) = 0; - virtual IMiniGUI* GetGUI() const = 0; - - virtual EMiniCtrlType GetType() const = 0; - - virtual int GetId() const = 0; - virtual void SetId(int id) = 0; - - virtual const char* GetTitle() const = 0; - virtual void SetTitle(const char* title) = 0; - - virtual Rect GetRect() const = 0; - virtual void SetRect(const Rect& rc) = 0; - - virtual void SetFlag(uint32 flag) = 0; - virtual void ClearFlag(uint32 flag) = 0; - virtual bool CheckFlag(uint32 flag) const = 0; - - // Sub Controls handling. - virtual void AddSubCtrl(IMiniCtrl* pCtrl) = 0; - virtual void RemoveSubCtrl(IMiniCtrl* pCtrl) = 0; - virtual void RemoveAllSubCtrl() = 0; - virtual int GetSubCtrlCount() const = 0; - virtual IMiniCtrl* GetSubCtrl(int nIndex) const = 0; - virtual IMiniCtrl* GetParent() const = 0; - - // Check if point is inside any of the sub controls. - virtual IMiniCtrl* GetCtrlFromPoint(float x, float y) = 0; - - virtual void OnPaint(class CDrawContext& dc) = 0; - - virtual void SetVisible(bool state) = 0; - - // Events from GUI - virtual void OnEvent([[maybe_unused]] float x, [[maybe_unused]] float y, EMiniCtrlEvent) {}; - - ////////////////////////////////////////////////////////////////////////// - // When set, this control will be enabling/disabling specified cvar - // when button not checked fOffValue will be set on cvar, when checked fOnValue will be set. - virtual bool SetControlCVar(const char* sCVarName, float fOffValue, float fOnValue) = 0; - - virtual bool SetClickCallback(ClickCallback callback, void* pCallbackData) = 0; - - virtual bool SetRenderCallback(RenderCallback callback) = 0; - - virtual bool SetConnectedCtrl(IMiniCtrl* pConnectedCtrl) = 0; - - //resize text box based what text is present - virtual void AutoResize() = 0; - - //Create close 'X' button for control - virtual void CreateCloseButton() = 0; - - //Move control - virtual void Move(float x, float y) = 0; - // - }; - typedef _smart_ptr IMiniCtrlPtr; - - class IMiniGuiCommon - { - public: - // - virtual ~IMiniGuiCommon(){} - virtual bool IsHidden() = 0; - virtual void Hide(bool stat) = 0; - // - }; - - class IMiniTable - : public IMiniGuiCommon - { - public: - // - virtual int AddColumn(const char* name) = 0; - virtual void RemoveColumns() = 0; - virtual int AddData(int columnIndex, ColorB col, const char* format, ...) = 0; - virtual void ClearTable() = 0; - // - }; - - class IMiniInfoBox - : public IMiniGuiCommon - { - public: - // - virtual void SetTextIndent(float x) = 0; - virtual void SetTextSize(float sz) = 0; - virtual void ClearEntries() = 0; - virtual void AddEntry(const char* str, ColorB col, float textSize) = 0; - // - }; -} - - -#define MINIGUI_BEGIN namespace minigui { -#define MINIGUI_END } - -#endif // CRYINCLUDE_CRYCOMMON_ICRYMINIGUI_H diff --git a/Code/CryEngine/CryCommon/IDeferredCollisionEvent.h b/Code/CryEngine/CryCommon/IDeferredCollisionEvent.h deleted file mode 100644 index 2dee198d0a..0000000000 --- a/Code/CryEngine/CryCommon/IDeferredCollisionEvent.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IDEFERREDCOLLISIONEVENT_H -#define CRYINCLUDE_CRYCOMMON_IDEFERREDCOLLISIONEVENT_H -#pragma once - - -#include - -struct EventPhys; - -// Base class for all deferred physics events -// Basically this class works like a future, -// Start() start the computation(some in the main thread, major part in a task/job) -// Result() will sync the task operation and return the result -struct IDeferredPhysicsEvent - : public IThreadTask -{ - // enum list of all types of deferred events - enum DeferredEventType - { - PhysCallBack_OnCollision - }; - - IDeferredPhysicsEvent(){} - // - virtual ~IDeferredPhysicsEvent(){} - - // == "future" like interface == // - - // start the execution of the event - virtual void Start() = 0; - - // sync the event and do all necessary post-processing, then return the result - virtual int Result(EventPhys* pOrigEvent = 0) = 0; - - // just wait for the event to finish - virtual void Sync() = 0; - - // check if the async computation part has finished - virtual bool HasFinished() = 0; - - // Get the concrete Type of this deferred event - virtual DeferredEventType GetType() const = 0; - - // returns a ptr to the original physics event - virtual EventPhys* PhysicsEvent() = 0; - // -}; - - -// Manager class for deferred physics events -struct IDeferredPhysicsEventManager -{ - // type of create function used to create needed deferred events in the HandleEvent function - typedef IDeferredPhysicsEvent*(* CreateEventFunc)(const EventPhys* pEvent); - - IDeferredPhysicsEventManager(){} - // - virtual ~IDeferredPhysicsEventManager(){} - - // dispatch an deferred event to the task thread - virtual void DispatchDeferredEvent(IDeferredPhysicsEvent* pEvent) = 0; - - // Encapsulates common logic for deferred events, should be called from the physics callbacks - // handles the cvar management as well as deferred event creating - virtual int HandleEvent(const EventPhys* pEvent, IDeferredPhysicsEventManager::CreateEventFunc, IDeferredPhysicsEvent::DeferredEventType) = 0; - - // Register and Unregister Deferred events in the manager to allow - virtual void RegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent) = 0; - virtual void UnRegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent) = 0; - - // Delete all Deferred Events in flight, use only when also clearing the physics event queue - // or else this call results in dangling points, mostly used for save/load - virtual void ClearDeferredEvents() = 0; - - virtual void Update() = 0; - - virtual IDeferredPhysicsEvent* GetLastCollisionEventForEntity(IPhysicalEntity* pPhysEnt) = 0; - // -}; - - -#endif // CRYINCLUDE_CRYCOMMON_IDEFERREDCOLLISIONEVENT_H diff --git a/Code/CryEngine/CryCommon/IDefragAllocator.h b/Code/CryEngine/CryCommon/IDefragAllocator.h deleted file mode 100644 index a415b3af67..0000000000 --- a/Code/CryEngine/CryCommon/IDefragAllocator.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IDEFRAGALLOCATOR_H -#define CRYINCLUDE_CRYCOMMON_IDEFRAGALLOCATOR_H -#pragma once - - -struct IDefragAllocatorStats -{ - size_t nCapacity; - size_t nInUseSize; - uint32 nInUseBlocks; - uint32 nFreeBlocks; - uint32 nPinnedBlocks; - uint32 nMovingBlocks; - uint32 nLargestFreeBlockSize; - uint32 nSmallestFreeBlockSize; - uint32 nMeanFreeBlockSize; - uint32 nCancelledMoveCount; -}; - -struct IDefragAllocatorCopyNotification -{ - IDefragAllocatorCopyNotification() - : bDstIsValid(false) - , bSrcIsUnneeded(false) - , bCancel(false) - { - } - - bool bDstIsValid; - bool bSrcIsUnneeded; - - // Flag to indicate that the copy can't be initiated after all - currently only cancelling before a relocate - // is begun is supported, and the destination region must be stable - bool bCancel; -}; - -class IDefragAllocatorPolicy -{ -public: - enum - { - InvalidUserMoveId = 0xffffffff - }; - -public: - // - virtual uint32 BeginCopy(void* pContext, UINT_PTR dstOffset, UINT_PTR srcOffset, UINT_PTR size, IDefragAllocatorCopyNotification* pNotification) = 0; - virtual void Relocate(uint32 userMoveId, void* pContext, UINT_PTR newOffset, UINT_PTR oldOffset, UINT_PTR size) = 0; - virtual void CancelCopy(uint32 userMoveId, void* pContext, bool bSync) = 0; - - // Perform the copy and relocate immediately - will only be called when UnAppendSegment is - virtual void SyncCopy(void* pContext, UINT_PTR dstOffset, UINT_PTR srcOffset, UINT_PTR size) = 0; - // - -protected: - virtual ~IDefragAllocatorPolicy() {} -}; - -class IDefragAllocator -{ -public: - typedef uint32 Hdl; - enum - { - InvalidHdl = 0, - }; - - struct AllocatePinnedResult - { - Hdl hdl; - UINT_PTR offs; - UINT_PTR usableSize; - }; - - enum EBlockSearchKind - { - eBSK_BestFit, - eBSK_FirstFit - }; - - struct Policy - { - Policy() - : pDefragPolicy(NULL) - , maxAllocs(0) - , maxSegments(1) - , blockSearchKind(eBSK_BestFit) - { - } - - IDefragAllocatorPolicy* pDefragPolicy; - size_t maxAllocs; - size_t maxSegments; - EBlockSearchKind blockSearchKind; - }; - -public: - // - virtual void Release(bool bDiscard = false) = 0; - - virtual void Init(UINT_PTR capacity, UINT_PTR alignment, const Policy& policy = Policy()) = 0; - - virtual bool AppendSegment(UINT_PTR capacity) = 0; - virtual void UnAppendSegment() = 0; - - virtual Hdl Allocate(size_t sz, const char* source, void* pContext = NULL) = 0; - virtual Hdl AllocateAligned(size_t sz, size_t alignment, const char* source, void* pContext = NULL) = 0; - virtual AllocatePinnedResult AllocatePinned(size_t sz, const char* source, void* pContext = NULL) = 0; - virtual bool Free(Hdl hdl) = 0; - - virtual void ChangeContext(Hdl hdl, void* pNewContext) = 0; - - virtual size_t GetAllocated() const = 0; - virtual IDefragAllocatorStats GetStats() = 0; - - virtual void DisplayMemoryUsage(const char* title, unsigned int allocatorDisplayOffset = 0) = 0; - - virtual size_t DefragmentTick(size_t maxMoves, size_t maxAmount, bool bForce = false) = 0; - - virtual UINT_PTR UsableSize(Hdl hdl) = 0; - - // Pin the chunk until the next defrag tick, when it will be automatically unpinned - virtual UINT_PTR WeakPin(Hdl hdl) = 0; - - // Pin the chunk until Unpin is called - virtual UINT_PTR Pin(Hdl hdl) = 0; - - virtual void Unpin(Hdl hdl) = 0; - - virtual const char* GetSourceOf(Hdl hdl) = 0; - // - -#ifndef _RELEASE - virtual void DumpState(const char* filename) = 0; - virtual void RestoreState(const char* filename) = 0; -#endif - -protected: - virtual ~IDefragAllocator() {} -}; - -#endif // CRYINCLUDE_CRYCOMMON_IDEFRAGALLOCATOR_H diff --git a/Code/CryEngine/CryCommon/IFileChangeMonitor.h b/Code/CryEngine/CryCommon/IFileChangeMonitor.h deleted file mode 100644 index 4ad46852ed..0000000000 --- a/Code/CryEngine/CryCommon/IFileChangeMonitor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IFILECHANGEMONITOR_H -#define CRYINCLUDE_CRYCOMMON_IFILECHANGEMONITOR_H -#pragma once - -struct IFileChangeListener -{ - enum EChangeType - { - //! error or unknown change type - eChangeType_Unknown, - //! the file was created - eChangeType_Created, - //! the file was deleted - eChangeType_Deleted, - //! the file was modified (size changed,write) - eChangeType_Modified, - //! this is the old name of a renamed file - eChangeType_RenamedOldName, - //! this is the new name of a renamed file - eChangeType_RenamedNewName - }; - - virtual ~IFileChangeListener() = default; - - virtual void OnFileChange(const char* sFilename, EChangeType eType) = 0; -}; - -struct IFileChangeMonitor -{ - virtual ~IFileChangeMonitor() = default; - - // - // Register the path of a file or directory to monitor - // Path is relative to game directory, e.g. "Libs/WoundSystem/" or "Libs/WoundSystem/HitLocations.xml" - virtual bool RegisterListener(IFileChangeListener* pListener, const char* sMonitorItem) = 0; - // This function can be used to monitor files of specific type, e.g. - // RegisterListener(pListener, "Animations", "caf") - virtual bool RegisterListener(IFileChangeListener* pListener, const char* sFolder, const char* sExtension) = 0; - virtual bool UnregisterListener(IFileChangeListener* pListener) = 0; - // -}; - -#endif // CRYINCLUDE_CRYCOMMON_IFILECHANGEMONITOR_H diff --git a/Code/CryEngine/CryCommon/IFont.h b/Code/CryEngine/CryCommon/IFont.h index c8634fa854..2706c350a3 100644 --- a/Code/CryEngine/CryCommon/IFont.h +++ b/Code/CryEngine/CryCommon/IFont.h @@ -33,8 +33,6 @@ struct ICryFont; struct IFFont; struct FontFamily; -struct IRenderer; - struct SVF_P2F_C4B_T2F_F4B; extern "C" @@ -100,9 +98,6 @@ struct ICryFont //! \param glyphSizeY Height (in pixels) of the characters to be rendered at in the font texture. virtual void AddCharsToFontTextures(FontFamilyPtr pFontFamily, const char* pChars, int glyphSizeX = defaultGlyphSizeX, int glyphSizeY = defaultGlyphSizeY) = 0; - // Summary: - // Globally sets common font render properties based on the initialized renderer - virtual void SetRendererProperties(IRenderer* pRenderer) = 0; // Summary: // Puts the objects used in this module into the sizer interface virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0; diff --git a/Code/CryEngine/CryCommon/IMemory.h b/Code/CryEngine/CryCommon/IMemory.h index 4a96bae2c0..a3b1dc1c2c 100644 --- a/Code/CryEngine/CryCommon/IMemory.h +++ b/Code/CryEngine/CryCommon/IMemory.h @@ -16,7 +16,6 @@ #pragma once #include -#include // <> required for Interfuscator #include // <> required for Interfuscator #include diff --git a/Code/CryEngine/CryCommon/IOverloadSceneManager.h b/Code/CryEngine/CryCommon/IOverloadSceneManager.h deleted file mode 100644 index 9d391c5701..0000000000 --- a/Code/CryEngine/CryCommon/IOverloadSceneManager.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : IOverloadSceneManager interface declaration. - - -#ifndef CRYINCLUDE_CRYCOMMON_IOVERLOADSCENEMANAGER_H -#define CRYINCLUDE_CRYCOMMON_IOVERLOADSCENEMANAGER_H -#pragma once - -//================================================================================================== -// Name: COverloadSceneManager -// Desc: Manages overload values (eg CPU,GPU etc) -// 1.0="everything is ok" 0.0="very bad frame rate" -// various systems can use this information and control what is currently in the scene -// Author: James Chilvers -//================================================================================================== -struct IOverloadSceneManager -{ -public: - // - virtual ~IOverloadSceneManager() {} - - virtual void Reset() = 0; - virtual void Update() = 0; - - // Override auto-calculated scale to reach targetfps. - // frameScale is clamped to internal min/max values, - // dt is the length of time in seconds to transition - virtual void OverrideScale(float frameScale, float dt) = 0; - - // Go back to auto-calculated scale from an overridden scale - virtual void ResetScale(float dt) = 0; - // -};//------------------------------------------------------------------------------------------------ - -#endif // CRYINCLUDE_CRYCOMMON_IOVERLOADSCENEMANAGER_H diff --git a/Code/CryEngine/CryCommon/IPathfinder.h b/Code/CryEngine/CryCommon/IPathfinder.h index 3e50bb09cb..97e5f7b4f1 100644 --- a/Code/CryEngine/CryCommon/IPathfinder.h +++ b/Code/CryEngine/CryCommon/IPathfinder.h @@ -109,7 +109,7 @@ struct NavigationBlocker , costMultMod(0) , radialDecay(false) {AZ_Assert(false, "Should never get called"); } - Sphere sphere; + ::Sphere sphere; bool radialDecay; bool directional; diff --git a/Code/CryEngine/CryCommon/IPerfHud.h b/Code/CryEngine/CryCommon/IPerfHud.h deleted file mode 100644 index 33104435dc..0000000000 --- a/Code/CryEngine/CryCommon/IPerfHud.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Performance HUD - - -#ifndef CRYINCLUDE_CRYCOMMON_IPERFHUD_H -#define CRYINCLUDE_CRYCOMMON_IPERFHUD_H -#pragma once - - -#include -#include -#include -#include - -struct ICryPerfHUDWidget - : public _reference_target_t -{ - // - enum EWidgetID - { - eWidget_Warnings = 0, - eWidget_RenderStats, - eWidget_StreamingStats, - eWidget_RenderBatchStats, - eWidget_FpsBuckets, - eWidget_Particles, - eWidget_PakFile, - eWidget_Num, //number of widgets - }; - - ICryPerfHUDWidget(int id = -1) - : m_id(id) - {} - - // - virtual ~ICryPerfHUDWidget() {} - - virtual void Reset() = 0; - virtual void Update() = 0; - virtual bool ShouldUpdate() = 0; - virtual void LoadBudgets(XmlNodeRef perfXML) = 0; - virtual void SaveStats(XmlNodeRef statsXML) = 0; - virtual void Enable(int mode) = 0; - virtual void Disable() = 0; - // - - int m_id; -}; - -// Base Interface for all engine module extensions -struct ICryPerfHUD - : public ICryUnknown -{ - CRYINTERFACE_DECLARE(ICryPerfHUD, 0x268d142e043d464c, 0xa0776580f81b988a); - - struct PerfBucket - { - ILINE PerfBucket(float _target) - { - target = _target; - timeAtTarget = 0.f; - } - - float target; - float timeAtTarget; - }; - - enum EHudState - { - eHudOff = 0, - eHudInFocus, - eHudOutOfFocus, - eHudNumStates, - }; - - // - // Called once to initialize HUD. - virtual void Init() = 0; - virtual void Done() = 0; - virtual void Draw() = 0; - virtual void LoadBudgets() = 0; - virtual void SaveStats(const char* filename = NULL) = 0; - virtual void ResetWidgets() = 0; - virtual void SetState(EHudState state) = 0; - virtual void Reset() = 0; - virtual void Destroy() = 0; - - // Retrieve name of the extension module. - virtual void Show(bool bRestoreState) = 0; - - virtual void AddWidget(ICryPerfHUDWidget* pWidget) = 0; - virtual void RemoveWidget(ICryPerfHUDWidget* pWidget) = 0; - - virtual minigui::IMiniCtrl* CreateMenu(const char* name, minigui::IMiniCtrl* pParent = NULL) = 0; - virtual bool CreateCVarMenuItem(minigui::IMiniCtrl* pMenu, const char* name, const char* controlVar, float controlVarOn, float controlVarOff) = 0; - virtual bool CreateCallbackMenuItem(minigui::IMiniCtrl* pMenu, const char* name, minigui::ClickCallback clickCallback, void* pCallbackData) = 0; - virtual minigui::IMiniInfoBox* CreateInfoMenuItem(minigui::IMiniCtrl* pMenu, const char* name, minigui::RenderCallback renderCallback, const minigui::Rect& rect, bool onAtStart = false) = 0; - virtual minigui::IMiniTable* CreateTableMenuItem(minigui::IMiniCtrl* pMenu, const char* name) = 0; - - virtual minigui::IMiniCtrl* GetMenu(const char* name) = 0; - - virtual void EnableWidget(ICryPerfHUDWidget::EWidgetID id, int mode) = 0; - virtual void DisableWidget(ICryPerfHUDWidget::EWidgetID id) = 0; - - //Warnings - Widget Specific interface - virtual void AddWarning(float duration, const char* fmt, va_list argList) = 0; - virtual bool WarningsWindowEnabled() const = 0; - - //FPS - Widget Specific interface - virtual const std::vector* GetFpsBuckets(float& totalTime) const = 0; - // -}; - -DECLARE_SMART_POINTERS(ICryPerfHUD); - -void CryPerfHUDWarning(float duration, const char*, ...) PRINTF_PARAMS(2, 3); -inline void CryPerfHUDWarning(float duration, const char* format, ...) -{ - if (gEnv && gEnv->pSystem) - { - ICryPerfHUD* pPerfHud = gEnv->pSystem->GetPerfHUD(); - - if (pPerfHud) - { - va_list args; - va_start(args, format); - pPerfHud->AddWarning(duration, format, args); - va_end(args); - } - } -} - -#endif // CRYINCLUDE_CRYCOMMON_IPERFHUD_H diff --git a/Code/CryEngine/CryCommon/IRenderer.h b/Code/CryEngine/CryCommon/IRenderer.h index 71c2500d80..94f8772e71 100644 --- a/Code/CryEngine/CryCommon/IRenderer.h +++ b/Code/CryEngine/CryCommon/IRenderer.h @@ -1472,7 +1472,6 @@ struct IRenderer ///////////////////////////////////////////////////////////////////////////////// // Shaders/Shaders management ///////////////////////////////////////////////////////////////////////////////// - virtual void EF_SetShaderMissCallback(ShaderCacheMissCallback callback) = 0; virtual const char* EF_GetShaderMissLogPath() = 0; ///////////////////////////////////////////////////////////////////////////////// @@ -1533,10 +1532,6 @@ struct IRenderer virtual int EF_LoadLightmap (const char* name) = 0; virtual bool EF_RenderEnvironmentCubeHDR (int size, Vec3& Pos, TArray& vecData) = 0; - // Summary: - // Creates new RE (RenderElement) of type (edt). - virtual IRenderElement* EF_CreateRE (EDataType edt) = 0; - // Summary: // Starts using of the shaders (return first index for allow recursions). virtual void EF_StartEf (const SRenderingPassInfo& passInfo) = 0; @@ -2385,26 +2380,6 @@ private: virtual void EF_QueryImpl(ERenderQueryTypes eQuery, void* pInOut0, uint32 nInOutSize0, void* pInOut1, uint32 nInOutSize1) = 0; }; -// util class to change wireframe mode -class CScopedWireFrameMode -{ -public: - CScopedWireFrameMode(IRenderer* pRenderer, int nMode) - : m_pRenderer(pRenderer) - , m_nMode(nMode) - { - (void) m_nMode; // removes not used warning - pRenderer->PushWireframeMode(nMode); - } - ~CScopedWireFrameMode() - { - m_pRenderer->PopWireframeMode(); - } -private: - IRenderer* m_pRenderer; - int m_nMode; -}; - struct SShaderCacheStatistics { size_t m_nTotalLevelShaderCacheMisses; diff --git a/Code/CryEngine/CryCommon/IShader.h b/Code/CryEngine/CryCommon/IShader.h index 7fcbdefebb..a87144a8c2 100644 --- a/Code/CryEngine/CryCommon/IShader.h +++ b/Code/CryEngine/CryCommon/IShader.h @@ -3413,6 +3413,6 @@ struct SShaderGraphBlock typedef std::vector FXShaderGraphBlocks; typedef FXShaderGraphBlocks::iterator FXShaderGraphBlocksItor; -#include "RendElement.h" +#include #endif // CRYINCLUDE_CRYCOMMON_ISHADER_H diff --git a/Code/CryEngine/CryCommon/ISystem.h b/Code/CryEngine/CryCommon/ISystem.h index 96d9a6ad10..93de0008b0 100644 --- a/Code/CryEngine/CryCommon/ISystem.h +++ b/Code/CryEngine/CryCommon/ISystem.h @@ -89,7 +89,6 @@ struct IResourceManager; struct ITextModeConsole; struct IAVI_Reader; class CPNoise3; -struct IFileChangeMonitor; struct IVisualLog; struct ILocalizationManager; struct ICryFactoryRegistry; @@ -99,7 +98,6 @@ struct IZLibDecompressor; struct ILZ4Decompressor; class IZStdDecompressor; struct IOutputPrintSink; -struct IOverloadSceneManager; struct IThreadManager; struct IServiceNetwork; struct IRemoteCommandManager; @@ -130,7 +128,6 @@ struct CLoadingTimeProfiler; class ICmdLine; struct INotificationNetwork; -struct ICryPerfHUD; class ILyShine; namespace JobManager { @@ -641,14 +638,12 @@ struct SSystemInitParams bool bDedicatedServer; // When running a dedicated server. bool bExecuteCommandLine; // can be switched of to suppress the feature or do it later during the initialization. bool bSkipFont; // Don't load CryFont.dll - bool bSkipRenderer; // Don't load Renderer bool bSkipConsole; // Don't create console bool bSkipNetwork; // Don't create Network bool bSkipWebsocketServer; // Don't create the WebSocket server bool bMinimal; // Don't load banks bool bTesting; // CryUnit bool bNoRandom; //use fixed generator init/seed - bool bShaderCacheGen; // When running in shadercache gen mode bool bUnattendedMode; // When running as part of a build on build-machines: Prevent popping up of any dialog bool bSkipMovie; // Don't load movie bool bSkipAnimation; // Don't load animation @@ -699,7 +694,6 @@ struct SSystemInitParams bExecuteCommandLine = true; bExecuteCommandLine = true; bSkipFont = false; - bSkipRenderer = false; bSkipConsole = false; bSkipNetwork = false; #if defined(WIN32) || defined(WIN64) @@ -712,7 +706,6 @@ struct SSystemInitParams bMinimal = false; bTesting = false; bNoRandom = false; - bShaderCacheGen = false; bUnattendedMode = false; bSkipMovie = false; bSkipAnimation = false; @@ -792,7 +785,6 @@ struct SSystemGlobalEnvironment { AZ::IO::IArchive* pCryPak; AZ::IO::FileIOBase* pFileIO; - IFileChangeMonitor* pFileChangeMonitor; IProfileLogSystem* pProfileLogSystem; IOpticsManager* pOpticsManager; ITimer* pTimer; @@ -806,7 +798,6 @@ struct SSystemGlobalEnvironment IRenderer* pRenderer; IMaterialEffects* pMaterialEffects; ISoftCodeMgr* pSoftCodeMgr; - IOverloadSceneManager* pOverloadSceneManager; IServiceNetwork* pServiceNetwork; IRemoteCommandManager* pRemoteCommandManager; ILyShine* pLyShine; @@ -1127,14 +1118,6 @@ struct ISystem // Gets number of CPUs virtual int GetLogicalCPUCount() = 0; - // Summary: - // Return the rendering driver name. GL or Metal - virtual const char* GetRenderingDriverName() const = 0; - - // Summary: - // Dumps the memory usage statistics to the logging default MB. (can be KB) - virtual void DumpMemoryUsageStatistics(bool bUseKB = false) = 0; - // Summary: // Quits the application. virtual void Quit() = 0; @@ -1145,9 +1128,6 @@ struct ISystem // Returns true if the application is in the shutdown phase. virtual bool IsQuitting() const = 0; // Summary: - // Returns true if the application was initialized to generate the shader cache. - virtual bool IsShaderCacheGenMode() const = 0; - // Summary: // Tells the system in which way we are using the serialization system. virtual void SerializingFile(int mode) = 0; virtual int IsSerializingFile() const = 0; @@ -1195,7 +1175,6 @@ struct ISystem virtual IZLibDecompressor* GetIZLibDecompressor() = 0; virtual ILZ4Decompressor* GetLZ4Decompressor() = 0; virtual IZStdDecompressor* GetZStdDecompressor() = 0; - virtual ICryPerfHUD* GetPerfHUD() = 0; virtual INotificationNetwork* GetINotificationNetwork() = 0; virtual IViewSystem* GetIViewSystem() = 0; virtual ILevelSystem* GetILevelSystem() = 0; @@ -1217,16 +1196,10 @@ struct ISystem virtual IProfilingSystem* GetIProfilingSystem() = 0; virtual ISystemEventDispatcher* GetISystemEventDispatcher() = 0; virtual IVisualLog* GetIVisualLog() = 0; - virtual IFileChangeMonitor* GetIFileChangeMonitor() = 0; - virtual WIN_HWND GetHWND() = 0; - - virtual IRenderer* GetIRenderer() = 0; virtual ITimer* GetITimer() = 0; virtual IThreadManager* GetIThreadManager() = 0; - //irtual IThreadManager* GetIThreadManager() = 0; - virtual void SetLoadingProgressListener(ILoadingProgressListener* pListener) = 0; virtual ISystem::ILoadingProgressListener* GetLoadingProgressListener() const = 0; @@ -1234,7 +1207,6 @@ struct ISystem // Game is created after System init, so has to be set explicitly. virtual void SetIMaterialEffects(IMaterialEffects* pMaterialEffects) = 0; virtual void SetIOpticsManager(IOpticsManager* pOpticsManager) = 0; - virtual void SetIFileChangeMonitor(IFileChangeMonitor* pFileChangeMonitor) = 0; virtual void SetIVisualLog(IVisualLog* pVisualLog) = 0; //virtual const char *GetGamePath()=0; @@ -1377,10 +1349,6 @@ struct ISystem // Non-0 if the state was indeed changed, 0 if already in that state. virtual int SetThreadState(ESubsystem subsys, bool bActive) = 0; - // Summary: - // Creates and returns a usable object implementing ICrySizer interface. - virtual ICrySizer* CreateSizer() = 0; - // Summary: // Query if system is now paused. // Pause flag is set when calling system update with pause mode. @@ -1491,11 +1459,6 @@ struct ISystem // returns zeroes if no updates happened yet virtual void GetUpdateStats(SSystemUpdateStats& stats) = 0; - // Description: - // Useful to investigate memory fragmentation. - // Every time you call this from the console: #System.DumpMemoryCoverage() - // it adds a line to "MemoryCoverage.bmp" (generated the first time, there is a max line count). - virtual void DumpMemoryCoverage() = 0; virtual ESystemGlobalState GetSystemGlobalState(void) = 0; virtual void SetSystemGlobalState(ESystemGlobalState systemGlobalState) = 0; diff --git a/Code/CryEngine/CryCommon/LoadScreenComponent.cpp b/Code/CryEngine/CryCommon/LoadScreenComponent.cpp deleted file mode 100644 index 3059e8a1fc..0000000000 --- a/Code/CryEngine/CryCommon/LoadScreenComponent.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include -#include -#include - -#include "LoadScreenComponent.h" -#include - -#if AZ_LOADSCREENCOMPONENT_ENABLED - -namespace -{ - // Due to issues with DLLs sometimes there can be different values of gEnv in different DLLs. - // So we use this preferred method of getting the global environment - SSystemGlobalEnvironment* GetGlobalEnv() - { - if (!GetISystem()) - { - return nullptr; - } - - return GetISystem()->GetGlobalEnvironment(); - } - - static const char* const s_gameFixedFpsCvarName = "game_load_screen_sequence_fixed_fps"; - static const char* const s_gameMaxFpsCvarName = "game_load_screen_max_fps"; - static const char* const s_gameMinimumLoadTimeCvarName = "game_load_screen_minimum_time"; - - static const char* const s_levelFixedFpsCvarName = "level_load_screen_sequence_fixed_fps"; - static const char* const s_levelMaxFpsCvarName = "level_load_screen_max_fps"; - static const char* const s_levelMinimumLoadTimeCvarName = "level_load_screen_minimum_time"; -} - -void LoadScreenComponent::Reflect(AZ::ReflectContext* context) -{ - AZ::SerializeContext* serializeContext = azrtti_cast(context); - - if (serializeContext) - { - serializeContext->Class() - ->Version(1) - ; - - AZ::EditContext* editContext = serializeContext->GetEditContext(); - if (editContext) - { - editContext->Class( - "Load screen manager", "Allows management of a load screen") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "Game") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) - ; - } - } -} - -void LoadScreenComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) -{ - provided.push_back(AZ_CRC("LoadScreenService", 0x901b031c)); -} - -void LoadScreenComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) -{ - incompatible.push_back(AZ_CRC("LoadScreenService", 0x901b031c)); -} - -void LoadScreenComponent::Reset() -{ - m_loadScreenState = LoadScreenState::None; - - m_fixedDeltaTimeInSeconds = -1.0f; - m_maxDeltaTimeInSeconds = -1.0f; - m_previousCallTimeForUpdateAndRender = CTimeValue(); - m_processingLoadScreen.store(false); - - // Reset CVars so they're not carried over to other levels - SSystemGlobalEnvironment* pGEnv = GetGlobalEnv(); - if (pGEnv && pGEnv->pConsole) - { - if (ICVar* var = pGEnv->pConsole->GetCVar(s_levelFixedFpsCvarName)) - { - var->Set(""); - } - if (ICVar* var = pGEnv->pConsole->GetCVar(s_levelMaxFpsCvarName)) - { - var->Set(""); - } - if (ICVar* var = pGEnv->pConsole->GetCVar(s_levelMinimumLoadTimeCvarName)) - { - var->Set(""); - } - } -} - -void LoadScreenComponent::LoadConfigSettings(const char* fixedFpsVarName, const char* maxFpsVarName, const char* minimumLoadTimeVarName) -{ - m_fixedDeltaTimeInSeconds = -1.0f; - m_maxDeltaTimeInSeconds = -1.0f; - m_minimumLoadTimeInSeconds = 0.0f; - - SSystemGlobalEnvironment* pGEnv = GetGlobalEnv(); - if (pGEnv && pGEnv->pConsole) - { - ICVar* fixedFpsVar = pGEnv->pConsole->GetCVar(fixedFpsVarName); - if (fixedFpsVar && fixedFpsVar->GetFVal() > 0.0f) - { - m_fixedDeltaTimeInSeconds = (1.0f / fixedFpsVar->GetFVal()); - } - - ICVar* maxFpsVar = pGEnv->pConsole->GetCVar(maxFpsVarName); - if (maxFpsVar && maxFpsVar->GetFVal() > 0.0f) - { - m_maxDeltaTimeInSeconds = (1.0f / maxFpsVar->GetFVal()); - } - - if (ICVar* minimumLoadTimeVar = pGEnv->pConsole->GetCVar(minimumLoadTimeVarName)) - { - // Never allow values below 0 seconds - m_minimumLoadTimeInSeconds = AZStd::max(minimumLoadTimeVar->GetFVal(), 0.0f); - } - } -} - -void LoadScreenComponent::Init() -{ - Reset(); -} - -void LoadScreenComponent::Activate() -{ - CrySystemEventBus::Handler::BusConnect(); - LoadScreenBus::Handler::BusConnect(GetEntityId()); -} - -void LoadScreenComponent::Deactivate() -{ - CrySystemEventBus::Handler::BusDisconnect(); - LoadScreenBus::Handler::BusDisconnect(GetEntityId()); -} - -void LoadScreenComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams&) -{ - SSystemGlobalEnvironment* pGEnv = system.GetGlobalEnvironment(); - - // Can't use macros here because we have to use our pointer. - if (pGEnv && pGEnv->pConsole) - { - pGEnv->pConsole->Register("ly_EnableLoadingThread", &m_loadingThreadEnabled, 0, VF_NULL, - "EXPERIMENTAL. Enable fully threaded loading where the LoadingScreen is drawn on a thread that isn't loading data."); - } - - if (pGEnv && !pGEnv->IsEditor()) - { - // If not running from the editor, then run GameStart - GameStart(); - } -} - -void LoadScreenComponent::OnCrySystemShutdown(ISystem&) -{ -} - -void LoadScreenComponent::UpdateAndRender() -{ - SSystemGlobalEnvironment* pGEnv = GetGlobalEnv(); - - if (m_loadScreenState == LoadScreenState::Showing && pGEnv && pGEnv->pTimer) - { - AZ_Assert(GetCurrentThreadId() == pGEnv->mMainThreadId, "UpdateAndRender should only be called from the main thread"); - - // Throttling. - if (!m_previousCallTimeForUpdateAndRender.GetValue()) - { - // This is the first call to UpdateAndRender(). - m_previousCallTimeForUpdateAndRender = pGEnv->pTimer->GetAsyncTime(); - } - - const CTimeValue callTimeForUpdateAndRender = pGEnv->pTimer->GetAsyncTime(); - const float deltaTimeInSeconds = fabs((callTimeForUpdateAndRender - m_previousCallTimeForUpdateAndRender).GetSeconds()); - - // Early-out: We DON'T need to execute UpdateAndRender() at a higher frequency than 30 FPS. - const bool shouldThrottle = m_maxDeltaTimeInSeconds > 0.0f && deltaTimeInSeconds < m_maxDeltaTimeInSeconds; - - if (!shouldThrottle) - { - bool expectedValue = false; - if (m_processingLoadScreen.compare_exchange_strong(expectedValue, true)) - { - m_previousCallTimeForUpdateAndRender = callTimeForUpdateAndRender; - - const float updateDeltaTime = (m_fixedDeltaTimeInSeconds == -1.0f) ? deltaTimeInSeconds : m_fixedDeltaTimeInSeconds; - - EBUS_EVENT(LoadScreenUpdateNotificationBus, UpdateAndRender, updateDeltaTime); - - // Some platforms (iOS, OSX) require system events to be pumped in order to update the screen - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty); - - m_processingLoadScreen.store(false); - } - } - } -} - -void LoadScreenComponent::GameStart() -{ - if (m_loadScreenState == LoadScreenState::None) - { - LoadConfigSettings(s_gameFixedFpsCvarName, s_gameMaxFpsCvarName, s_gameMinimumLoadTimeCvarName); - - const bool usingLoadingThread = IsLoadingThreadEnabled(); - - AZ::EBusLogicalResult> anyHandled(false); - EBUS_EVENT_RESULT(anyHandled, LoadScreenNotificationBus, NotifyGameLoadStart, usingLoadingThread); - - if (anyHandled.value) - { - if (usingLoadingThread) - { - m_loadScreenState = LoadScreenState::ShowingMultiThreaded; - - GetGlobalEnv()->pRenderer->StartLoadtimePlayback(this); - } - else - { - m_loadScreenState = LoadScreenState::Showing; - - // Kick-start the first frame. - UpdateAndRender(); - } - - if (ITimer* timer = GetGlobalEnv()->pTimer) - { - m_lastStartTime = timer->GetAsyncTime(); - } - } - } -} - -void LoadScreenComponent::LevelStart() -{ - if (m_loadScreenState == LoadScreenState::None) - { - LoadConfigSettings(s_levelFixedFpsCvarName, s_levelMaxFpsCvarName, s_levelMinimumLoadTimeCvarName); - - const bool usingLoadingThread = IsLoadingThreadEnabled(); - - AZ::EBusLogicalResult> anyHandled(false); - EBUS_EVENT_RESULT(anyHandled, LoadScreenNotificationBus, NotifyLevelLoadStart, usingLoadingThread); - - if (anyHandled.value) - { - if (usingLoadingThread) - { - m_loadScreenState = LoadScreenState::ShowingMultiThreaded; - - GetGlobalEnv()->pRenderer->StartLoadtimePlayback(this); - } - else - { - m_loadScreenState = LoadScreenState::Showing; - - // Kick-start the first frame. - UpdateAndRender(); - } - - if (ITimer* timer = GetGlobalEnv()->pTimer) - { - m_lastStartTime = timer->GetAsyncTime(); - } - } - } -} - -void LoadScreenComponent::Pause() -{ - if (m_loadScreenState == LoadScreenState::Showing) - { - m_loadScreenState = LoadScreenState::Paused; - } - else if (m_loadScreenState == LoadScreenState::ShowingMultiThreaded) - { - m_loadScreenState = LoadScreenState::PausedMultithreaded; - } -} - -void LoadScreenComponent::Resume() -{ - if (m_loadScreenState == LoadScreenState::Paused) - { - m_loadScreenState = LoadScreenState::Showing; - } - else if (m_loadScreenState == LoadScreenState::PausedMultithreaded) - { - m_loadScreenState = LoadScreenState::ShowingMultiThreaded; - } -} - -void LoadScreenComponent::Stop() -{ - // If we were actually in a load screen, check if we need to wait longer. - if (m_loadScreenState != LoadScreenState::None && m_minimumLoadTimeInSeconds > 0.0f) - { - if (ITimer* timer = GetGlobalEnv()->pTimer) - { - CTimeValue currentTime = timer->GetAsyncTime(); - float timeSinceStart = currentTime.GetDifferenceInSeconds(m_lastStartTime); - - while (timeSinceStart < m_minimumLoadTimeInSeconds) - { - // Simple loop that makes sure the loading screens update but also doesn't consume the whole core. - - if (m_loadScreenState == LoadScreenState::Showing) - { - EBUS_EVENT(LoadScreenBus, UpdateAndRender); - } - - CrySleep(0); - - currentTime = timer->GetAsyncTime(); - timeSinceStart = currentTime.GetDifferenceInSeconds(m_lastStartTime); - } - } - } - - if (m_loadScreenState == LoadScreenState::ShowingMultiThreaded) - { - // This will block until the other thread completes. - GetGlobalEnv()->pRenderer->StopLoadtimePlayback(); - } - - if (m_loadScreenState != LoadScreenState::None) - { - EBUS_EVENT(LoadScreenNotificationBus, NotifyLoadEnd); - } - - Reset(); - - m_loadScreenState = LoadScreenState::None; -} - -bool LoadScreenComponent::IsPlaying() -{ - return m_loadScreenState != LoadScreenState::None; -} - -void LoadScreenComponent::LoadtimeUpdate(float deltaTime) -{ - if (m_loadScreenState == LoadScreenState::ShowingMultiThreaded) - { - EBUS_EVENT(LoadScreenUpdateNotificationBus, LoadThreadUpdate, deltaTime); - } -} - -void LoadScreenComponent::LoadtimeRender() -{ - if (m_loadScreenState == LoadScreenState::ShowingMultiThreaded) - { - EBUS_EVENT(LoadScreenUpdateNotificationBus, LoadThreadRender); - } -} - -#endif // if AZ_LOADSCREENCOMPONENT_ENABLED diff --git a/Code/CryEngine/CryCommon/LoadScreenComponent.h b/Code/CryEngine/CryCommon/LoadScreenComponent.h deleted file mode 100644 index 71ed6287f1..0000000000 --- a/Code/CryEngine/CryCommon/LoadScreenComponent.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ -#pragma once - -#include -#include -#include - -#include -#include -#include - -#if AZ_LOADSCREENCOMPONENT_ENABLED - -/* -* This component is responsible for managing the load screen. -*/ -class LoadScreenComponent - : public AZ::Component - , public CrySystemEventBus::Handler - , public LoadScreenBus::Handler - , public ILoadtimeCallback -{ -public: - AZ_COMPONENT(LoadScreenComponent, "{97CDBD6C-C621-4427-87C8-10E1B8F947FF}"); - - LoadScreenComponent() = default; - ~LoadScreenComponent() = default; - - ////////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Init() override; - void Activate() override; - void Deactivate() override; - ////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // CrySystemEvents - void OnCrySystemInitialized(ISystem&, const SSystemInitParams& params) override; - void OnCrySystemShutdown(ISystem&) override; - //////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // LoadScreenBus interface implementation - void UpdateAndRender() override; - void GameStart() override; - void LevelStart() override; - void Pause() override; - void Resume() override; - void Stop() override; - bool IsPlaying() override; - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // ILoadtimeCallback interface implementation - void LoadtimeUpdate(float deltaTime) override; - void LoadtimeRender() override; - ////////////////////////////////////////////////////////////////////////// - - inline bool IsLoadingThreadEnabled() const - { - return m_loadingThreadEnabled != 0; - } - -protected: - static void Reflect(AZ::ReflectContext* context); - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - -private: - void Reset(); - void LoadConfigSettings(const char* fixedFpsVarName, const char* maxFpsVarName, const char* minimumLoadTimeVarName); - - ////////////////////////////////////////////////////////////////////////// - enum class LoadScreenState - { - None, - Showing, - ShowingMultiThreaded, - Paused, - PausedMultithreaded, - }; - LoadScreenState m_loadScreenState{ LoadScreenState::None }; - - float m_fixedDeltaTimeInSeconds{ -1.0f }; - float m_maxDeltaTimeInSeconds{ -1.0f }; - float m_minimumLoadTimeInSeconds{ 0.0f }; - - CTimeValue m_lastStartTime; - CTimeValue m_previousCallTimeForUpdateAndRender; - AZStd::atomic_bool m_processingLoadScreen{ false }; - - int32_t m_loadingThreadEnabled{ 0 }; - ////////////////////////////////////////////////////////////////////////// -}; - -#endif // if AZ_LOADSCREENCOMPONENT_ENABLED diff --git a/Code/CryEngine/CryCommon/Mocks/IMemoryManagerMock.h b/Code/CryEngine/CryCommon/Mocks/IMemoryManagerMock.h index 3f458d7f52..63df006e14 100644 --- a/Code/CryEngine/CryCommon/Mocks/IMemoryManagerMock.h +++ b/Code/CryEngine/CryCommon/Mocks/IMemoryManagerMock.h @@ -40,6 +40,4 @@ public: IMemoryAddressRange* (size_t capacity, const char* sName)); MOCK_METHOD2(CreatePageMappingHeap, IPageMappingHeap* (size_t addressSpace, const char* sName)); - MOCK_METHOD0(CreateDefragAllocator, - IDefragAllocator*()); }; diff --git a/Code/CryEngine/CryCommon/Mocks/IRendererMock.h b/Code/CryEngine/CryCommon/Mocks/IRendererMock.h index 757c586261..7b0b7b76a2 100644 --- a/Code/CryEngine/CryCommon/Mocks/IRendererMock.h +++ b/Code/CryEngine/CryCommon/Mocks/IRendererMock.h @@ -286,8 +286,6 @@ public: CRenderObject * (SShaderItem & si, CRenderObject * obj, const SRenderingPassInfo& passInfo, int numPts, int ninds, SVF_P3F_C4B_T2F * &verts, SPipTangents * &tangs, uint16 * &inds, int nAW, const SRendItemSorter& rendItemSorter)); MOCK_METHOD0(ForceUpdateGlobalShaderParameters, void()); - MOCK_METHOD1(EF_SetShaderMissCallback, - void(ShaderCacheMissCallback callback)); MOCK_METHOD0(EF_GetShaderMissLogPath, const char*()); MOCK_METHOD1(EF_GetShaderNames, @@ -334,8 +332,6 @@ public: int(const char* name)); MOCK_METHOD3(EF_RenderEnvironmentCubeHDR, bool(int size, Vec3 & Pos, TArray&vecData)); - MOCK_METHOD1(EF_CreateRE, - IRenderElement * (EDataType edt)); MOCK_METHOD1(EF_StartEf, void(const SRenderingPassInfo& passInfo)); MOCK_METHOD3(EF_GetObjData, diff --git a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h index 4d2e80a2f3..9e5182ebcf 100644 --- a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h +++ b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h @@ -49,18 +49,12 @@ public: int()); MOCK_METHOD0(GetLogicalCPUCount, int()); - MOCK_CONST_METHOD0(GetRenderingDriverName, - const char*()); - MOCK_METHOD1(DumpMemoryUsageStatistics, - void(bool)); MOCK_METHOD0(Quit, void()); MOCK_METHOD1(Relaunch, void(bool bRelaunch)); MOCK_CONST_METHOD0(IsQuitting, bool()); - MOCK_CONST_METHOD0(IsShaderCacheGenMode, - bool()); MOCK_METHOD1(SerializingFile, void(int mode)); MOCK_CONST_METHOD0(IsSerializingFile, @@ -90,8 +84,6 @@ public: ILZ4Decompressor * ()); MOCK_METHOD0(GetZStdDecompressor, IZStdDecompressor * ()); - MOCK_METHOD0(GetPerfHUD, - ICryPerfHUD * ()); MOCK_METHOD0(GetINotificationNetwork, INotificationNetwork * ()); MOCK_METHOD0(GetIViewSystem, @@ -132,12 +124,6 @@ public: ISystemEventDispatcher * ()); MOCK_METHOD0(GetIVisualLog, IVisualLog * ()); - MOCK_METHOD0(GetIFileChangeMonitor, - IFileChangeMonitor * ()); - MOCK_METHOD0(GetHWND, - WIN_HWND()); - MOCK_METHOD0(GetIRenderer, - IRenderer * ()); MOCK_METHOD0(GetITimer, ITimer * ()); MOCK_METHOD0(GetIThreadManager, @@ -150,8 +136,6 @@ public: void(IMaterialEffects * pMaterialEffects)); MOCK_METHOD1(SetIOpticsManager, void(IOpticsManager * pOpticsManager)); - MOCK_METHOD1(SetIFileChangeMonitor, - void(IFileChangeMonitor * pFileChangeMonitor)); MOCK_METHOD1(SetIVisualLog, void(IVisualLog * pVisualLog)); MOCK_METHOD2(DebugStats, @@ -229,8 +213,6 @@ public: void(bool detectResolution)); MOCK_METHOD2(SetThreadState, int(ESubsystem subsys, bool bActive)); - MOCK_METHOD0(CreateSizer, - ICrySizer * ()); MOCK_CONST_METHOD0(IsPaused, bool()); MOCK_METHOD0(GetLocalizationManager, @@ -275,8 +257,6 @@ public: void(bool)); MOCK_METHOD1(GetUpdateStats, void(SSystemUpdateStats & stats)); - MOCK_METHOD0(DumpMemoryCoverage, - void()); MOCK_METHOD0(GetSystemGlobalState, ESystemGlobalState(void)); MOCK_METHOD1(SetSystemGlobalState, diff --git a/Code/CryEngine/CryCommon/ProjectDefines.h b/Code/CryEngine/CryCommon/ProjectDefines.h index 9308412c15..f82861d6e0 100644 --- a/Code/CryEngine/CryCommon/ProjectDefines.h +++ b/Code/CryEngine/CryCommon/ProjectDefines.h @@ -162,10 +162,6 @@ typedef uint32 vtx_idx; #endif #endif -#if defined(ENABLE_PROFILING_CODE) - #define USE_PERFHUD -#endif - #if defined(ENABLE_PROFILING_CODE) #define ENABLE_ART_RT_TIME_ESTIMATE #endif diff --git a/Code/CryEngine/CryCommon/RendElement.h b/Code/CryEngine/CryCommon/RendElement.h deleted file mode 100644 index 41bcf2bf67..0000000000 --- a/Code/CryEngine/CryCommon/RendElement.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_RENDELEMENT_H -#define CRYINCLUDE_CRYCOMMON_RENDELEMENT_H -#pragma once - - -//============================================================= - -#include "VertexFormats.h" - -class CRendElementBase; -struct CRenderChunk; -struct PrimitiveGroup; -class CShader; -struct SShaderTechnique; -class CParserBin; -struct SParserFrame; - -namespace AZ -{ - namespace Vertex - { - class Format; - } -} - -enum EDataType -{ - eDATA_Unknown = 0, - eDATA_Sky, - eDATA_Beam, - eDATA_ClientPoly, - eDATA_Flare, - eDATA_Terrain, - eDATA_SkyZone, - eDATA_Mesh, - eDATA_Imposter, - eDATA_LensOptics, - eDATA_FarTreeSprites_Deprecated, - eDATA_OcclusionQuery, - eDATA_Particle, - eDATA_GPUParticle, - eDATA_PostProcess, - eDATA_HDRProcess, - eDATA_Cloud, - eDATA_HDRSky, - eDATA_FogVolume, - eDATA_WaterVolume, - eDATA_WaterOcean, - eDATA_VolumeObject, - eDATA_PrismObject, // normally this would be #if !defined(EXCLUDE_DOCUMENTATION_PURPOSE) but we keep it to get consistent numbers for serialization - eDATA_DeferredShading, - eDATA_GameEffect, - eDATA_BreakableGlass, - eDATA_GeomCache, - eDATA_Gem, -}; - -#include - -//======================================================= - -#define FCEF_TRANSFORM 1 -#define FCEF_DIRTY 2 -#define FCEF_NODEL 4 -#define FCEF_DELETED 8 - -#define FCEF_MODIF_TC 0x10 -#define FCEF_MODIF_VERT 0x20 -#define FCEF_MODIF_COL 0x40 -#define FCEF_MODIF_MASK 0xf0 - -#define FCEF_UPDATEALWAYS 0x100 -#define FCEF_ALLOC_CUST_FLOAT_DATA 0x200 -#define FCEF_MERGABLE 0x400 - -#define FCEF_SKINNED 0x800 -#define FCEF_PRE_DRAW_DONE 0x1000 - -#define FGP_NOCALC 1 -#define FGP_SRC 2 -#define FGP_REAL 4 -#define FGP_WAIT 8 - -#define FGP_STAGE_SHIFT 0x10 - -#define MAX_CUSTOM_TEX_BINDS_NUM 2 - -struct SGeometryInfo; -class CRendElement; - -struct IRenderElementDelegate -{ - virtual void mfPrepare(bool bCheckOverflow) = 0; - virtual bool mfDraw(CShader* shader, SShaderPass* pass) = 0; - virtual bool mfSetSampler([[maybe_unused]] int customId, [[maybe_unused]] int nTUnit, [[maybe_unused]] int nTState, [[maybe_unused]] int nTexMaterialSlot, [[maybe_unused]] int nSUnit) { return true; }; -}; - -struct IRenderElement -{ - virtual int mfGetMatId() = 0; - virtual uint16 mfGetFlags() = 0; - virtual void mfSetFlags(uint16 fl) = 0; - virtual void mfUpdateFlags(uint16 fl) = 0; - virtual void mfClearFlags(uint16 fl) = 0; - virtual void mfPrepare(bool bCheckOverflow) = 0; - virtual void mfCenter(Vec3& centr, CRenderObject* pObj) = 0; - virtual void mfGetBBox(Vec3& vMins, Vec3& vMaxs) = 0; - virtual void mfReset() = 0; - virtual void mfGetPlane(Plane_tpl& pl) = 0; - virtual void mfExport(struct SShaderSerializeContext& SC) = 0; - virtual void mfImport(struct SShaderSerializeContext& SC, uint32& offset) = 0; - virtual void mfPrecache(const SShaderItem& SH) = 0; - virtual bool mfIsHWSkinned() = 0; - virtual bool mfCheckUpdate(int Flags, uint16 nFrame, bool bTessellation = false) = 0; - virtual bool mfUpdate(int Flags, bool bTessellation = false) = 0; - virtual bool mfCompile(CParserBin& Parser, SParserFrame& Frame) = 0; - virtual bool mfDraw(CShader* ef, SShaderPass* sfm) = 0; - virtual bool mfPreDraw(SShaderPass* sl) = 0; - virtual bool mfSetSampler(int customId, int nTUnit, int nTState, int nTexMaterialSlot, int nSUnit) = 0; - virtual void mfSetDelegate(IRenderElementDelegate* pDelegate) = 0; - virtual IRenderElementDelegate* mfGetDelegate() = 0; - virtual CRenderChunk* mfGetMatInfo() = 0; - virtual TRenderChunkArray* mfGetMatInfoList() = 0; - virtual void* mfGetPointer(ESrcPointer ePT, int* Stride, EParamType Type, ESrcPointer Dst, int Flags) = 0; - virtual AZ::Vertex::Format GetVertexFormat() const = 0; - virtual void* GetCustomData() const = 0; - virtual int GetCustomTexBind(int i) const = 0; - virtual CRendElementBase* mfCopyConstruct() = 0; - virtual EDataType mfGetType() = 0; - virtual int Size() = 0; - virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0; - -}; - -class CRendElement -{ -public: - static CRendElement m_RootGlobal; - static CRendElement m_RootRelease[]; - CRendElement* m_NextGlobal; - CRendElement* m_PrevGlobal; - - EDataType m_Type; - -protected: - virtual void UnlinkGlobal() - { - if (!m_NextGlobal || !m_PrevGlobal) - { - return; - } - m_NextGlobal->m_PrevGlobal = m_PrevGlobal; - m_PrevGlobal->m_NextGlobal = m_NextGlobal; - m_NextGlobal = m_PrevGlobal = NULL; - } - - virtual void LinkGlobal(CRendElement* Before) - { - if (m_NextGlobal || m_PrevGlobal) - { - return; - } - m_NextGlobal = Before->m_NextGlobal; - Before->m_NextGlobal->m_PrevGlobal = this; - Before->m_NextGlobal = this; - m_PrevGlobal = Before; - } - -public: - CRendElement(); - virtual ~CRendElement(); - virtual void Release(bool bForce = false); - virtual const char* mfTypeString(); - virtual void mfSetType(EDataType t) { m_Type = t; } - virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {} - virtual int Size() { return 0; } - - static void ShutDown(); - static void Tick(); - static void Cleanup(); -}; - -class CRendElementBase - : public CRendElement - , public IRenderElement -{ -public: - uint16 m_Flags; - uint16 m_nFrameUpdated; - -public: - void* m_CustomData; - int m_CustomTexBind[MAX_CUSTOM_TEX_BINDS_NUM]; - - struct SGeometryStreamInfo - { - const void* pStream; - int nOffset; - int nStride; - }; - struct SGeometryInfo - { - uint32 bonesRemapGUID; // Input paremeter to fetch correct skinning stream. - - int primitiveType; //!< \see eRenderPrimitiveType - AZ::Vertex::Format vertexFormat; - uint32 streamMask; - - int32 nFirstIndex; - int32 nNumIndices; - uint32 nFirstVertex; - uint32 nNumVertices; - - uint32 nMaxVertexStreams; - - SGeometryStreamInfo indexStream; - SGeometryStreamInfo vertexStream[VSF_NUM]; - - void* pTessellationAdjacencyBuffer; - void* pSkinningExtraBonesBuffer; - }; - -public: - CRendElementBase(); - virtual ~CRendElementBase(); - - - virtual void mfPrepare(bool bCheckOverflow) override - { - if (m_delegate) - { - m_delegate->mfPrepare(bCheckOverflow); - } - } - bool mfDraw(CShader* ef, SShaderPass* sfm) override { return m_delegate ? m_delegate->mfDraw(ef, sfm) : true; } - bool mfSetSampler(int customId, int nTUnit, int nTState, int nTexMaterialSlot, int nSUnit) override { return m_delegate ? m_delegate->mfSetSampler(customId, nTUnit, nTState, nTexMaterialSlot, nSUnit) : false; } - void mfSetDelegate(IRenderElementDelegate* pDelegate) override { m_delegate = pDelegate; } - IRenderElementDelegate* mfGetDelegate() { return m_delegate; } - - EDataType mfGetType() override { return m_Type; }; - - CRenderChunk* mfGetMatInfo() override { return nullptr; } - TRenderChunkArray* mfGetMatInfoList() override { return nullptr; } - int mfGetMatId() override { return -1; } - void mfReset() override {}; - CRendElementBase* mfCopyConstruct() override; - void mfCenter(Vec3& centr, CRenderObject* pObj) override; - - bool mfCompile([[maybe_unused]] CParserBin& Parser, [[maybe_unused]] SParserFrame& Frame) override { return false; } - bool mfPreDraw([[maybe_unused]] SShaderPass* sl) override { return true; } - bool mfUpdate([[maybe_unused]] int Flags, [[maybe_unused]] bool bTessellation = false) override { return true; } - void mfPrecache([[maybe_unused]] const SShaderItem& SH) override {} - void mfExport([[maybe_unused]] struct SShaderSerializeContext& SC) override { CryFatalError("mfExport has not been implemented for this render element type"); } - void mfImport([[maybe_unused]] struct SShaderSerializeContext& SC, [[maybe_unused]] uint32& offset) override { CryFatalError("mfImport has not been implemented for this render element type"); } - void mfGetPlane(Plane_tpl& pl) override; - void* mfGetPointer([[maybe_unused]] ESrcPointer ePT, [[maybe_unused]] int* Stride, [[maybe_unused]] EParamType Type, [[maybe_unused]] ESrcPointer Dst, [[maybe_unused]] int Flags) override { return nullptr; } - - uint16 mfGetFlags() override { return m_Flags; } - void mfSetFlags(uint16 fl) override { m_Flags = fl; } - void mfUpdateFlags(uint16 fl) override { m_Flags |= fl; } - void mfClearFlags(uint16 fl) override { m_Flags &= ~fl; } - bool mfCheckUpdate(int Flags, uint16 nFrame, bool bTessellation = false) override - { - if (nFrame != m_nFrameUpdated || (m_Flags & (FCEF_DIRTY | FCEF_SKINNED | FCEF_UPDATEALWAYS))) - { - m_nFrameUpdated = nFrame; - return mfUpdate(Flags, bTessellation); - } - return true; - } - void mfGetBBox(Vec3& vMins, Vec3& vMaxs) override - { - vMins.Set(0, 0, 0); - vMaxs.Set(0, 0, 0); - } - bool mfIsHWSkinned() override { return false; } - int Size() override { return 0; } - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const override {} - AZ::Vertex::Format GetVertexFormat() const override { return AZ::Vertex::Format(eVF_Unknown); }; - virtual bool GetGeometryInfo([[maybe_unused]] SGeometryInfo& streams) { return false; } - void Draw([[maybe_unused]] CRenderObject* pObj, [[maybe_unused]] const struct SGraphicsPiplinePassContext& ctx) {}; - void* GetCustomData() const { return m_CustomData; } - int GetCustomTexBind(int index) const { return m_CustomTexBind[index]; } - -protected: - IRenderElementDelegate * m_delegate = nullptr; -}; - -#include "CREMesh.h" -#include "CRESky.h" -#include "CREOcclusionQuery.h" -#include "CREImposter.h" -#include "CREBaseCloud.h" -#include "CREPostProcess.h" -#include "CREFogVolume.h" -#include "CREWaterVolume.h" -#include "CREWaterOcean.h" -#include "CREVolumeObject.h" -#include "CREGameEffect.h" -#include "CREGeomCache.h" - -#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE) -#include "CREPrismObject.h" -#endif // EXCLUDE_DOCUMENTATION_PURPOSE - -//========================================================== - -#endif // CRYINCLUDE_CRYCOMMON_RENDELEMENT_H diff --git a/Code/CryEngine/CryCommon/TypeLibrary.h b/Code/CryEngine/CryCommon/TypeLibrary.h deleted file mode 100644 index 03d608a24e..0000000000 --- a/Code/CryEngine/CryCommon/TypeLibrary.h +++ /dev/null @@ -1,512 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_TYPELIBRARY_H -#define CRYINCLUDE_CRYCOMMON_TYPELIBRARY_H -#pragma once - -#include // <> required for Interfuscator - -#include -#include - -#ifdef SOFTCODE_ENABLED - -// Internal: Used by SC types to auto-remove themselves from their TypeRegistrar on destruction. -struct InstanceTracker -{ - InstanceTracker() - : m_pRegistrar() - {} - - ~InstanceTracker() - { - if (m_pRegistrar) - { - m_pRegistrar->RemoveInstance(this); - } - } - - void SetRegistrar(ITypeRegistrar* pRegistrar) - { - m_pRegistrar = pRegistrar; - } - - ITypeRegistrar* m_pRegistrar; // Valid if created by a registrar, otherwise NULL -}; - -#endif - - -#ifdef SOFTCODE_ENABLED - -// Include this for SEH support - #include - -/* - Used to declare the interface as having an associated TypeLibrary. - Usage: - struct IMyInterface - { - DECLARE_TYPELIB(IMyInterface); -*/ - #define DECLARE_TYPELIB(IName) \ - static void VisitMembers(IExchanger & ex) {} \ - typedef CTypeLibrary TLibrary - -/* - Exposes a class to a TypeLibrary for registration. - Usage: - class MyThing : public IThing - { - DECLARE_TYPE(MyThing, IThing); - ... -*/ - #define DECLARE_TYPE(TName, TSuperType) \ -public: \ - void VisitMembers(IExchanger & ex) { TSuperType::VisitMembers(ex); VisitMember<__START_MEMBERS>(ex); } \ -private: \ - friend class TypeRegistrar; \ - static const size_t __START_MEMBERS = __COUNTER__ + 1; \ - template \ - void VisitMember(IExchanger & exchanger) {} \ - InstanceTracker __instanceTracker - - #ifdef SOFTCODE - #define _EXPORT_TYPE_LIB(Interface) \ - extern "C" ITypeLibrary * GetTypeLibrary() { return CTypeLibrary::Instance(); } - #else - #define _EXPORT_TYPE_LIB(Interface) - #endif - -// Internal: Outputs the specialized method template for the member at index - #define _SOFT_MEMBER_VISITOR(member, index) \ - template <> \ - void VisitMember(IExchanger & ex) { ex.Visit(#member, member); VisitMember(ex); } - -/* - Used to expose a class member to SoftCoding (to allow run-time member exchange) - If SoftCode is disabled this does nothing and simple emits the member. - For array types, use SOFT_ARRAY() instead or use AZStd::array which allows assignment. - Usage: std::vector SOFT(m_myStrings); -*/ - #define SOFT(member) \ - member; \ - _SOFT_MEMBER_VISITOR(member, __COUNTER__) - -/* - Used to expose a primitive array type to SoftCoding. - Declare it directly after the member. - NOTE: It's cleaner to convert the member to AZStd::array as - this avoid having to use this special case while preserving semantics. - Usage: - ColorB m_colors[20]; - SOFT_ARRAY(m_colors); -*/ - #define SOFT_ARRAY(arrayMember) _SOFT_MEMBER_VISITOR(arrayMember, __COUNTER__) - -// Internal: Executes given lambda in an SEH try block. -template -void SoftCodeTry(TLambda& lambda) -{ - __try - { - lambda(); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } -} - -// Internal: Used by TypeRegistry. Use SOFTCODE_RETRY() for user code. - #define SOFTCODE_TRY(exp) SoftCodeTry([&](){ exp; }) - #define SOFTCODE_TRY_BLOCK SoftCodeTry([&]() { - #define SOFTCODE_TRY_END }); - -/* - Internal: Attempt a given lambda functor. In the even on an exception execution will pause - to allow the user to provide a replacement implementation for the failing instance. - Usage: See SOFTCODE_RETRY & SOFTCODE_RETRY_BLOCK below. -*/ -template -void SoftCodeRetry(TPtr& pointer, TLambda& lambda) -{ - bool complete = false; - while (pointer && !complete) - { - __try - { - lambda(); - complete = true; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - if (gEnv->pSoftCodeMgr) - { - pointer = reinterpret_cast(gEnv->pSoftCodeMgr->WaitForUpdate(pointer)); - } - } - } - ; -} - -/* - Attempts to call an expression based the given pointer. - If a Structured Exception is raised the thread will wait for a replacement of - the pointer to be provided via the SoftCodeMgr. This will repeat until no exception is raised. - - Usage: SOFTCODE_RETRY(pThing, (pThing->Update(frameTime))); // Same as pThing->Update(frameTime); -*/ - #define SOFTCODE_RETRY(pointer, exp) SoftCodeRetry(pointer, [&](){ exp; }) - -/* - Attempts to call an expression based the given pointer. - If a Structured Exception is raised the thread will wait for a replacement of - the pointer to be provided via the SoftCodeMgr. This will repeat until no exception is raised. - - Usage: - SOFTCODE_RETRY_BLOCK(pThing) - { - pSomething = pThing->GetSomething(); - } - SOFTCODE_RETRY_END -*/ - #define SOFTCODE_RETRY_BLOCK(pointer) SoftCodeRetry(pointer, [&]() { - #define SOFTCODE_RETRY_END }); - -#else // !SOFTCODE_ENABLED ... - -// IMPORTANT: Docs for these macros are found above. - - #define DECLARE_TYPELIB(IName) \ - typedef CTypeLibrary TLibrary - - #define DECLARE_TYPE(TName, TSuperType) \ -private: \ - friend class TypeRegistrar; - - #define _EXPORT_TYPE_LIB(Interface) - - #define SOFT(member) member - #define SOFT_ARRAY(arrayMember) - - #define SOFTCODE_TRY(exp) (exp) - #define SOFTCODE_TRY_BLOCK { - #define SOFTCODE_TRY_END }; - - #define SOFTCODE_RETRY(pointer, exp) (exp) - #define SOFTCODE_RETRY_BLOCK(pointer) { - #define SOFTCODE_RETRY_END }; - -#endif // !SOFTCODE_ENABLED - -/* - Implements registration for a type to a TypeLibrary. - Usage: - // MyThing.cpp - DECLARE_TYPE(MyThing); -*/ -#define IMPLEMENT_TYPE(TName) \ - static TypeRegistrar s_register##TName(#TName) - -/* - Provides the singleton for the TypeLibrary implementation. - Also exports the accessors function for SoftCode builds. - Usage: - // ThingLibrary.cpp - IMPLEMENT_TYPELIB(IThing, "Things") -*/ -#define IMPLEMENT_TYPELIB(Interface, Name) \ - _EXPORT_TYPE_LIB(Interface) \ - template <> \ - CTypeLibrary* CTypeLibrary::Instance() \ - { \ - static CTypeLibrary s_instance(Name); \ - return &s_instance; \ - } - -/* - Internal: Used to register a type with a TypeLibrary. - Also provides instance construction (factory) access. - For SC builds it also provides copying and instance tracking. -*/ -template -class TypeRegistrar - : public ITypeRegistrar -{ -public: - TypeRegistrar(const char* name) - : m_name(name) - { - typedef typename T::TLibrary TLib; - TLib::Instance()->RegisterType(this); - } - - virtual const char* GetName() const { return m_name; } - - virtual void* CreateInstance() - { - T* pInstance = NULL; - - SOFTCODE_TRY_BLOCK - { - pInstance = ConstructInstance(); - } - SOFTCODE_TRY_END - - if (pInstance) - { - RegisterInstance(pInstance); - } - - return pInstance; - } - -#ifdef SOFTCODE_ENABLED - virtual size_t InstanceCount() const - { - return m_instances.size(); - } - - virtual void RemoveInstance(InstanceTracker* pTracker) - { - T* pInstance = GetInstanceFromTracker(pTracker); - TInstanceVec::iterator iter(std::find(m_instances.begin(), m_instances.end(), pInstance)); - std::swap(*iter, m_instances.back()); - m_instances.pop_back(); - } - - virtual bool ExchangeInstances(IExchanger& exchanger) - { - if (exchanger.IsLoading()) - { - const size_t instanceCount = exchanger.InstanceCount(); - - // Ensure we have the correct number of instances - if (m_instances.size() != instanceCount) - { - // TODO: Destroy any existing instances - for (size_t i = 0; i < instanceCount; ++i) - { - if (!CreateInstance()) - { - return false; - } - } - } - } - - bool complete = false; - SOFTCODE_TRY_BLOCK - { - for (std::vector::iterator iter(m_instances.begin()); iter != m_instances.end(); ++iter) - { - T* pInstance = *iter; - if (exchanger.BeginInstance(pInstance)) - { - // Exchanges the members of pInstance as defined in T - // Should also exchange members of parent types - pInstance->VisitMembers(exchanger); - } - } - complete = true; - } - SOFTCODE_TRY_END - - return complete; - } - - virtual bool DestroyInstances() - { - bool complete = false; - SOFTCODE_TRY_BLOCK - { - while (!m_instances.empty()) - { - delete m_instances.back(); - // NOTE: No need to pop_back() as already done by the InstanceTracker via RemoveInstance() - } - complete = true; - } - SOFTCODE_TRY_END - - return complete; - } - - - virtual bool HasInstance(void* pInstance) const - { - return std::find(m_instances.begin(), m_instances.end(), pInstance) != m_instances.end(); - } -#endif - -private: - void RegisterInstance(T* pInstance) - { -#ifdef SOFTCODE_ENABLED - pInstance->__instanceTracker.SetRegistrar(this); - m_instances.push_back(pInstance); -#endif - } - -#ifdef SOFTCODE_ENABLED - // Util: Avoids having to redundantly store the instance address in the tracker - T* GetInstanceFromTracker(InstanceTracker* pTracker) - { - ptrdiff_t trackerOffset = reinterpret_cast(&((static_cast(0))->__instanceTracker)); - return reinterpret_cast(reinterpret_cast(pTracker) - trackerOffset); - } -#endif - - // Needed to avoid C2712 due to lack of stack unwind within SEH try blocks - T* ConstructInstance() - { - return new T(); - } - -private: - const char* m_name; // Name of the type - -#ifdef SOFTCODE_ENABLED - typedef std::vector TInstanceVec; - TInstanceVec m_instances; // Tracks the active instances (SC only) -#endif -}; - -/* - Provides factory creation support for a set of types that - derive from a single interface T. Users need to provide a - specialization of the static CTypeLibrary* Instance() member - in a cpp file to provide the singleton instance. -*/ -template -class CTypeLibrary - #ifdef SOFTCODE_ENABLED - : public ITypeLibrary - #endif -{ -public: - CTypeLibrary(const char* name) - : m_name(name) -#ifdef SOFTCODE_ENABLED - , m_pOverrideLib() - , m_overrideActive() - , m_registered() -#endif - { - } - - // Implemented in the export cpp - static CTypeLibrary* Instance(); - - void RegisterType(ITypeRegistrar* pType) - { - m_typeMap[pType->GetName()] = pType; - } - - // The global identifier for this library module - /*virtual*/ const char* GetName() { return m_name; } - -#ifdef SOFTCODE_ENABLED - virtual void* CreateInstanceVoid(const char* typeName) - { - return CreateInstance(typeName); - } -#endif - - // Generic creation function - T* CreateInstance(const char* typeName) - { -#ifdef SOFTCODE_ENABLED - RegisterWithSoftCode(); - - // If override is enabled, use it - if (m_pOverrideLib) - { - return reinterpret_cast(m_pOverrideLib->CreateInstanceVoid(typeName)); - } -#endif - - TTypeMap::const_iterator typeIter(m_typeMap.find(typeName)); - if (typeIter != m_typeMap.end()) - { - ITypeRegistrar* pRegistrar = typeIter->second; - return reinterpret_cast(pRegistrar->CreateInstance()); - } - - return NULL; - } - -#ifdef SOFTCODE_ENABLED - // Indicates CreateInstance requests should be forwarded to the specified lib - virtual void SetOverride(ITypeLibrary* pOverrideLib) - { - m_pOverrideLib = pOverrideLib; - } - - virtual size_t GetTypes(ITypeRegistrar** ppTypes, size_t& count) const - { - size_t returnedCount = 0; - - if (ppTypes && count >= m_typeMap.size()) - { - for (TTypeMap::const_iterator iter(m_typeMap.begin()); iter != m_typeMap.end(); ++iter) - { - *ppTypes = iter->second; - ++ppTypes; - ++returnedCount; - } - } - - count = m_typeMap.size(); - return returnedCount; - } - - // Inform the Mgr of this Library and allow it to set an override - inline void RegisterWithSoftCode() - { - // Only register built-in types, SC types are handled directly by - // the SoftCodeMgr, so there's no need to auto-register. -#ifndef SOFTCODE - if (!m_registered) - { - if (ISoftCodeMgr* pSoftCodeMgr = gEnv->pSoftCodeMgr) - { - pSoftCodeMgr->RegisterLibrary(this); - } - - m_registered = true; - } -#endif - } -#endif - -private: - typedef AZStd::basic_string, AZ::AZStdAlloc> TypeString; - typedef AZStd::map, AZ::AZStdAlloc> TTypeMap; - TTypeMap m_typeMap; - - // The name for this TypeLibrary used during SC registration - const char* m_name; - -#ifdef SOFTCODE_ENABLED - // Used to patch in a new TypeLib at run-time - ITypeLibrary* m_pOverrideLib; - // True when the owning object system enables the override - bool m_overrideActive; - // True when registration with SoftCodeMgr has been attempted - bool m_registered; -#endif -}; - -#endif // CRYINCLUDE_CRYCOMMON_TYPELIBRARY_H diff --git a/Code/CryEngine/CryCommon/crycommon_files.cmake b/Code/CryEngine/CryCommon/crycommon_files.cmake index 7d169c2643..3b63dab649 100644 --- a/Code/CryEngine/CryCommon/crycommon_files.cmake +++ b/Code/CryEngine/CryCommon/crycommon_files.cmake @@ -20,13 +20,9 @@ set(FILES ICmdLine.h IColorGradingController.h IConsole.h - ICryMiniGUI.h - IDeferredCollisionEvent.h - IDefragAllocator.h IEngineModule.h IEntityRenderState.h IEntityRenderState_info.cpp - IFileChangeMonitor.h IFlares.h IFont.h IFunctorBase.h @@ -51,8 +47,6 @@ set(FILES IMiniLog.h IMovieSystem.h INotificationNetwork.h - IOverloadSceneManager.h - IPerfHud.h IPhysics.h IPhysicsDebugRenderer.h IPostEffectGroup.h @@ -109,7 +103,6 @@ set(FILES FunctorBaseMember.h stridedptr.h Options.h - CREGeomCache.h SerializationTypes.h CryEndian.h CryRandomInternal.h @@ -205,7 +198,6 @@ set(FILES TimeValue_info.h TypeInfo_decl.h TypeInfo_impl.h - TypeLibrary.h UnalignedBlit.h UnicodeBinding.h UnicodeEncoding.h @@ -222,18 +214,6 @@ set(FILES PakLoadDataUtils.cpp PakLoadDataUtils.h TPool.h - CREBaseCloud.h - CREFogVolume.h - CREGameEffect.h - CREImposter.h - CREMesh.h - CREOcclusionQuery.h - CREPostProcess.h - CRESky.h - CREVolumeObject.h - CREWaterOcean.h - CREWaterVolume.h - RendElement.h Cry_Matrix33.h Cry_Matrix34.h Cry_Matrix44.h @@ -280,8 +260,6 @@ set(FILES Linux_Win32Wrapper.h LinuxSpecific.h LoadScreenBus.h - LoadScreenComponent.cpp - LoadScreenComponent.h MacSpecific.h platform.h platform_impl.cpp @@ -478,7 +456,6 @@ set(FILES Terrain/Bus/TerrainRendererBus.h Terrain/Bus/HeightmapDataBus.h Terrain/Bus/TerrainProviderBus.h - CREPrismObject.h StaticInstance.h Pak/CryPakUtils.h ) diff --git a/Code/CryEngine/CrySystem/AutoDetectSpec.cpp b/Code/CryEngine/CrySystem/AutoDetectSpec.cpp index dd7739bb79..31eee85d90 100644 --- a/Code/CryEngine/CrySystem/AutoDetectSpec.cpp +++ b/Code/CryEngine/CrySystem/AutoDetectSpec.cpp @@ -711,31 +711,6 @@ static Win32SysInspect::DXFeatureLevel GetFeatureLevel(D3D_FEATURE_LEVEL feature } } - -static int GetDXGIAdapterOverride() -{ -#if defined(WIN32) || defined(WIN64) - ICVar* pCVar = gEnv->pConsole ? gEnv->pConsole->GetCVar("r_overrideDXGIAdapter") : 0; - return pCVar ? pCVar->GetIVal() : -1; -#else - return -1; -#endif -} - - -static void LogDeviceInfo(unsigned int adapterIdx, const DXGI_ADAPTER_DESC1& ad, Win32SysInspect::DXFeatureLevel fl, bool displaysConnected) -{ - const bool suitableDevice = fl >= Win32SysInspect::DXFL_11_0 && displaysConnected; - - CryLogAlways("- %s (vendor = 0x%.4x, device = 0x%.4x)", CryStringUtils::WStrToUTF8(ad.Description).c_str(), ad.VendorId, ad.DeviceId); - CryLogAlways(" - Adapter index: %d", adapterIdx); - CryLogAlways(" - Dedicated video memory: %d MB", ad.DedicatedVideoMemory >> 20); - CryLogAlways(" - Feature level: %s", GetFeatureLevelAsString(fl)); - CryLogAlways(" - Displays connected: %s", displaysConnected ? "yes" : "no"); - CryLogAlways(" - Suitable rendering device: %s", suitableDevice ? "yes" : "no"); -} - - static bool FindGPU(DXGI_ADAPTER_DESC1& adapterDesc, Win32SysInspect::DXFeatureLevel& featureLevel) { memset(&adapterDesc, 0, sizeof(adapterDesc)); @@ -757,15 +732,7 @@ static bool FindGPU(DXGI_ADAPTER_DESC1& adapterDesc, Win32SysInspect::DXFeatureL if (pD3D11CD) { - const int r_overrideDXGIAdapter = GetDXGIAdapterOverride(); - const bool logDeviceInfo = !gEnv->pRenderer && r_overrideDXGIAdapter < 0; - - if (logDeviceInfo) - { - CryLogAlways("Logging video adapters:"); - } - - unsigned int nAdapter = r_overrideDXGIAdapter >= 0 ? r_overrideDXGIAdapter : 0; + unsigned int nAdapter = 0; IDXGIAdapter1* pAdapter = 0; while (pFactory->EnumAdapters1(nAdapter, &pAdapter) != DXGI_ERROR_NOT_FOUND) { @@ -786,29 +753,16 @@ static bool FindGPU(DXGI_ADAPTER_DESC1& adapterDesc, Win32SysInspect::DXFeatureL const Win32SysInspect::DXFeatureLevel fl = GetFeatureLevel(deviceFeatureLevel); - if (logDeviceInfo) - { - LogDeviceInfo(nAdapter, ad, fl, displaysConnected); - } - if (featureLevel < fl && displaysConnected) { adapterDesc = ad; featureLevel = fl; } - else if (r_overrideDXGIAdapter >= 0) - { - CryLogAlways("No display connected to DXGI adapter override %d. Adapter cannot be used for rendering.", r_overrideDXGIAdapter); - } } SAFE_RELEASE(pDevice); SAFE_RELEASE(pAdapter); } - if (r_overrideDXGIAdapter >= 0) - { - break; - } ++nAdapter; } } diff --git a/Code/CryEngine/CrySystem/CrySizerImpl.cpp b/Code/CryEngine/CrySystem/CrySizerImpl.cpp deleted file mode 100644 index bd26b05b9e..0000000000 --- a/Code/CryEngine/CrySystem/CrySizerImpl.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include -#include -#include "CrySizerImpl.h" - -CrySizerImpl::CrySizerImpl() - : m_pResourceCollector(0) -{ - m_nFlags = 0; - m_nTotalSize = 0; - // to avoid reallocations during walk through the memory tree, reserve the space for the names - clear(); -} - -CrySizerImpl::~CrySizerImpl() -{ -} - -void CrySizerImpl::Push (const char* szComponentName) -{ - m_stackNames.push_back (getNameIndex(getCurrentName(), szComponentName)); - // if the depth is too deep, something is wrong, perhaps an infinite loop - assert (m_stackNames.size() < 128); -} - -void CrySizerImpl::PushSubcomponent (const char* szSubcomponentName) -{ - Push (szSubcomponentName); -} - - -void CrySizerImpl::Pop () -{ - if (!m_stackNames.empty()) - { - m_stackNames.pop_back(); - } - else - { - assert (0); - } -} - -// returns the index of the current name on the top of the name stack -size_t CrySizerImpl::getCurrentName() const -{ - assert(!m_stackNames.empty()); - return m_stackNames.empty() ? 0 : m_stackNames.back(); -} - - - -// searches for the name in the name array; adds the name if it's not there and returns the index -size_t CrySizerImpl::getNameIndex(size_t nParent, const char* szComponentName) -{ - NameArray::const_iterator it = m_arrNames.begin(), itEnd = it + m_arrNames.size(); - for (; it != itEnd; ++it) - { -#if defined(LINUX) - if (!strcasecmp(it->strName.c_str(), szComponentName) && it->nParent == nParent) -#else - if (!strcmp(it->strName.c_str(), szComponentName) && it->nParent == nParent) -#endif - { - return (size_t)(it - m_arrNames.begin());//it-m_arrNames.begin(); - } - } - - size_t nNewName = m_arrNames.size(); - m_arrNames.resize(nNewName + 1); - - m_arrNames[nNewName].assign(szComponentName, nParent); - - m_arrNames[nParent].arrChildren.push_back(nParent); - - return nNewName; -} - -static NullResCollector s_nullCollector; - -IResourceCollector* CrySizerImpl::GetResourceCollector() -{ - return m_pResourceCollector != 0 ? m_pResourceCollector : &s_nullCollector; -} - -void CrySizerImpl::Reset() -{ - clear(); - - m_nTotalSize = 0; - - //m_arrNames.resize(0); - //m_arrNames.push_back("TOTAL"); // the default name, with index 0 - //m_LastObject.clear(); - ////m_nFlags; - //m_nTotalSize=0; - //if (m_pResourceCollector) - //{ - // m_pResourceCollector->Reset(); - //} - //m_setObjects->clear(); - //m_stackNames.resize(0); - //m_stackNames.push_back(0); -} - - -// adds an object identified by the unique pointer (it needs not be -// the actual object position in the memory, though it would be nice, -// but it must be unique throughout the system and unchanging for this object) -// RETURNS: true if the object has actually been added (for the first time) -// and calculated -bool CrySizerImpl::AddObject (const void* pIdentifier, size_t sizeBytes, int nCount) -{ - if (!pIdentifier || !sizeBytes) - { - return false; // we don't add the NULL objects - } - Object NewObject(pIdentifier, sizeBytes, getCurrentName()); - - // check if the last object was the same - if (NewObject == m_LastObject) - { - assert (m_LastObject.nSize == sizeBytes); - return false; - } - - ObjectSet& rSet = m_setObjects[getHash(pIdentifier)]; - ObjectSet::iterator it = rSet.find (NewObject); - if (it == rSet.end()) - { - // there's no such object in the map, add it - rSet.insert (NewObject); - ComponentName& CompName = m_arrNames[getCurrentName()]; - CompName.numObjects += nCount; - CompName.sizeObjects += sizeBytes; - - m_nTotalSize += sizeBytes; - return true; - } - else - { - Object* pObj = const_cast(&(*it)); - - // if we do an heap check, don't accept the same object twice - if (sizeBytes != pObj->nSize) - { - // if the following assert fails: - // assert (0); - // .. it means we have one object that's added two times with different sizes; that's screws up the whole idea - // we assume there are two different objects that are for some reason assigned the same id - pObj->nSize += sizeBytes; // anyway it's an invalid situation - ComponentName& CompName = m_arrNames[getCurrentName()]; - CompName.sizeObjects += sizeBytes; - return true; // yes we added the object, though there were an error condition - } - - return false; - } -} - -size_t CrySizerImpl::GetObjectCount() -{ - size_t count = m_stackNames.size(); - for (int i = 0; i < g_nHashSize; i++) - { - count += m_setObjects[i].size(); - } - return count; -} - - -// finalizes data collection, should be called after all objects have been added -void CrySizerImpl::End() -{ - // clean up the totals of each name - int i; - for (i = 0; i < m_arrNames.size(); ++i) - { - assert (i == 0 || ((int)m_arrNames[i].nParent < i && m_arrNames[i].nParent >= 0)); - m_arrNames[i].sizeObjectsTotal = m_arrNames[i].sizeObjects; - } - - // add the component's size to the total size of the parent. - // for every component, all their children are put after them in the name array - // we don't include the root because it doesn't belong to any other parent (nowhere further to add) - for (i = m_arrNames.size() - 1; i > 0; --i) - { - // the parent's total size is increased by the _total_ size (already calculated) of this object - m_arrNames[m_arrNames[i].nParent].sizeObjectsTotal += m_arrNames[i].sizeObjectsTotal; - } -} - - -void CrySizerImpl::clear() -{ - for (unsigned i = 0; i < g_nHashSize; ++i) - { - m_setObjects[i].clear(); - } - - m_arrNames.clear(); - m_arrNames.push_back("TOTAL"); // the default name, with index 0 - m_stackNames.clear(); - m_stackNames.push_back(0); - m_LastObject.pId = NULL; - - if (m_pResourceCollector) - { - m_pResourceCollector->Reset(); - } -} - -// hash function for an address; returns value 0..1<> 4) & (g_nHashSize-1); - - // pseudorandomizing transform - ldiv_t Qrem = (ldiv_t)ldiv(((uint32)(UINT_PTR)pId >> 2), 127773); - Qrem.rem = 16807 * Qrem.rem - 2836 * Qrem.quot; - if (Qrem.rem < 0) - { - Qrem.rem += 2147483647; // 0x7FFFFFFF - } - return ((unsigned)Qrem.rem) & (g_nHashSize - 1); -} -unsigned CrySizerImpl::GetDepthLevel(unsigned nCurrent) -{ - uint32 nDepth = 0; - nCurrent = m_arrNames[nCurrent].nParent; - while (nCurrent != 0) - { - nDepth++; - nCurrent = m_arrNames[nCurrent].nParent; - } - return nDepth; -} - diff --git a/Code/CryEngine/CrySystem/CrySizerImpl.h b/Code/CryEngine/CrySystem/CrySizerImpl.h deleted file mode 100644 index f43ee25297..0000000000 --- a/Code/CryEngine/CrySystem/CrySizerImpl.h +++ /dev/null @@ -1,184 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Implementation of the ICrySizer interface, which is used to -// calculate the memory usage by the subsystems and components, to help -// the artists keep the memory budged low. - - -#ifndef CRYINCLUDE_CRYSYSTEM_CRYSIZERIMPL_H -#define CRYINCLUDE_CRYSYSTEM_CRYSIZERIMPL_H -#pragma once - - - -// prerequisities - -////////////////////////////////////////////////////////////////////////// -// implementation of interface ICrySizer -// ICrySizer is passed to all subsystems and has a lot of helper functions that -// are compiled in the appropriate subsystems. CrySizerImpl is created in CrySystem -// and is passed to all the other subsystems -class CrySizerImpl - : public ICrySizer -{ -public: - CrySizerImpl(); - ~CrySizerImpl(); - - virtual void Release() { delete this; } - virtual size_t GetTotalSize() { return m_nTotalSize; }; - virtual size_t GetObjectCount(); - - void Reset(); - - // adds an object identified by the unique pointer (it needs not be - // the actual object position in the memory, though it would be nice, - // but it must be unique throughout the system and unchanging for this object) - // RETURNS: true if the object has actually been added (for the first time) - // and calculated - virtual bool AddObject (const void* pIdentifier, size_t nSizeBytes, int nCount = 1); - - virtual IResourceCollector* GetResourceCollector(); - - // finalizes data collection, should be called after all objects have been added - void End(); - - void clear(); - - // Arguments: - // pColl - can be 0 - void SetResourceCollector(IResourceCollector* pColl) { m_pResourceCollector = pColl; } - -protected: - - IResourceCollector* m_pResourceCollector; // - - // these functions must operate on the component name stack - // they are to be only accessible from within class CrySizerComponentNameHelper - // which should be used through macro SIZER_COMPONENT_NAME - virtual void Push (const char* szComponentName); - virtual void PushSubcomponent (const char* szSubcomponentName); - virtual void Pop (); - - // searches for the name in the name array; adds the name if it's not there and returns the index - size_t getNameIndex (size_t nParent, const char* szComponentName); - - // returns the index of the current name on the top of the name stack - size_t getCurrentName() const; - -protected: - friend class CrySizerStatsBuilder; - - // the stack of subsystem names; the indices in the name array are kept, not the names themselves - typedef DynArray NameStack; - NameStack m_stackNames; - - // the array of names; each name ever pushed on the stack is present here - struct ComponentName - { - ComponentName (){} - ComponentName (const char* szName, size_t parent = 0) - : strName (szName) - , nParent (parent) - , numObjects(0) - , sizeObjects (0) - , sizeObjectsTotal (0) - { - } - - void assign (const char* szName, size_t parent = 0) - { - strName = szName; - nParent = parent; - numObjects = 0; - sizeObjects = 0; - sizeObjectsTotal = 0; - arrChildren.clear(); - } - - // the component name, not including the parents' names - string strName; - // the index of the parent, 0 being the root - size_t nParent; - // the number of objects within this component - size_t numObjects; - // the size of the objects belonging to this component, in bytes - size_t sizeObjects; - // the total size of all objects; gets filled by the end() method of the CrySizerImpl - size_t sizeObjectsTotal; - // the children components - DynArray arrChildren; - }; - typedef DynArray NameArray; - NameArray m_arrNames; - - - - // the set of objects and their sizes: the key is the object address/id, - // the value is the size of the object and its name (the index of the name actually) - struct Object - { - const void* pId; // unique pointer identifying the object in memory - size_t nSize; // the size of the object in bytes - size_t nName; // the index of the name in the name array - - Object () - {clear(); } - - Object (const void* id, size_t size = 0, size_t name = 0) - : pId(id) - , nSize(size) - , nName(name) {} - - // the objects are sorted by their Id - bool operator < (const Object& right) const {return (UINT_PTR)pId < (UINT_PTR)right.pId; } - bool operator < (const void* right) const {return (UINT_PTR)pId < (UINT_PTR)right; } - //friend bool operator < (const void* left, const Object& right); - - bool operator == (const Object& right) const {return pId == right.pId; } - - void clear() - { - pId = NULL; - nSize = 0; - nName = 0; - } - }; - typedef std::set ObjectSet; - // 2^g_nHashPower == the number of subsets comprising the hash - - enum - { - g_nHashPower = 12 - }; - - // hash size (number of subsets) - enum - { - g_nHashSize = 1 << g_nHashPower - }; - // hash function for an address; returns value 0..1< 0x10000000 ? 0 : nMinSubcomponentBytes) -{ -} - - -// creates the map of names from old (in the sizer Impl) to new (in the Stats) -void CrySizerStatsBuilder::processNames() -{ - size_t numCompNames = m_pSizer->m_arrNames.size(); - m_pStats->m_arrComponents.reserve (numCompNames); - m_pStats->m_arrComponents.clear(); - - m_mapNames.resize (numCompNames, (size_t)-1); - - // add all root objects - addNameSubtree(0, 0); -} - - -////////////////////////////////////////////////////////////////////////// -// given the name in the old system, adds the subtree of names to the -// name map and components. In case all the subtree is empty, returns false and -// adds nothing -size_t CrySizerStatsBuilder::addNameSubtree (unsigned nDepth, size_t nName) -{ - assert ((int)nName < m_pSizer->m_arrNames.size()); - - CrySizerImpl::ComponentName& rCompName = m_pSizer->m_arrNames[nName]; - size_t sizeObjectsTotal = rCompName.sizeObjectsTotal; - - if (sizeObjectsTotal <= m_nMinSubcomponentBytes) - { - return sizeObjectsTotal; // the subtree didn't pass - } - // the index of the component in the stats object (sorted by the depth-first traverse order) - size_t nNewName = m_pStats->m_arrComponents.size(); - m_pStats->m_arrComponents.resize (nNewName + 1); - - Component& rNewComp = m_pStats->m_arrComponents[nNewName]; - rNewComp.strName = rCompName.strName; - rNewComp.nDepth = nDepth; - rNewComp.numObjects = rCompName.numObjects; - rNewComp.sizeBytes = rCompName.sizeObjects; - rNewComp.sizeBytesTotal = sizeObjectsTotal; - m_mapNames[nName] = nNewName; - - // find the immediate children and sort them by their total size - typedef std::map UintUintMap; - UintUintMap mapSizeName; // total size -> child index (name in old indexation) - - for (int i = nName + 1; i < m_pSizer->m_arrNames.size(); ++i) - { - CrySizerImpl::ComponentName& rChild = m_pSizer->m_arrNames[i]; - if (rChild.nParent == nName && rChild.sizeObjectsTotal > m_nMinSubcomponentBytes) - { - mapSizeName.insert (UintUintMap::value_type(rChild.sizeObjectsTotal, i)); - } - } - - // add the sorted components - /* - for (unsigned i = nName + 1; i < m_pSizer->m_arrNames.size(); ++i) - if (m_pSizer->m_arrNames[i].nParent == nName) - addNameSubtree(nDepth+1,i); - */ - - for (UintUintMap::reverse_iterator it = mapSizeName.rbegin(); it != mapSizeName.rend(); ++it) - { - addNameSubtree(nDepth + 1, it->second); - } - - return sizeObjectsTotal; -} - - -////////////////////////////////////////////////////////////////////////// -// creates the statistics out of the given CrySizerImpl into the given CrySizerStats -// Maps the old to new names according to the depth-walk tree rule -void CrySizerStatsBuilder::build (CrySizerStats* pStats) -{ - m_pStats = pStats; - - m_mapNames.clear(); - - processNames(); - - m_pSizer->clear(); - pStats->refresh(); - pStats->m_nAgeFrames = 0; -} - - -////////////////////////////////////////////////////////////////////////// -// constructs the statistics based on the given cry sizer -CrySizerStats::CrySizerStats (CrySizerImpl* pCrySizer) -{ - CrySizerStatsBuilder builder (pCrySizer); - builder.build(this); -} - -CrySizerStats::CrySizerStats () - : m_nStartRow(0) -{ -} - -void CrySizerStats::updateKeys() -{ - const unsigned int statSize = size(); - //assume 10 pixels for font - unsigned int height = gEnv->pRenderer->GetHeight() / 12; - if (CryGetAsyncKeyState(VK_UP)) - { - if (m_nStartRow > 0) - { - --m_nStartRow; - } - } - if (CryGetAsyncKeyState(VK_DOWN)) - { - if (statSize > height + m_nStartRow) - { - ++m_nStartRow; - } - } - if (CryGetAsyncKeyState(VK_RIGHT) & 1) - { - //assume 10 pixels for font - if (statSize > height) - { - m_nStartRow = statSize - height; - } - } - if (CryGetAsyncKeyState(VK_LEFT) & 1) - { - m_nStartRow = 0; - } -} - -// if there is already such name in the map, then just returns the index -// of the compoentn in the component array; otherwise adds an entry to themap -// and to the component array nad returns its index -CrySizerStatsBuilder::Component& CrySizerStatsBuilder::mapName (unsigned nName) -{ - assert (m_mapNames[nName] != -1); - return m_pStats->m_arrComponents[m_mapNames[nName]]; - /* - IdToIdMap::iterator it = m_mapNames.find (nName); - if (it == m_mapNames.end()) - { - unsigned nNewName = m_arrComponents.size(); - m_mapNames.insert (IdToIdMap::value_type(nName, nNewName)); - m_arrComponents.resize(nNewName + 1); - m_arrComponents[nNewName].strName.swap(m_pSizer->m_arrNames[nName]); - return m_arrComponents.back(); - } - else - { - assert (it->second < m_arrComponents.size()); - return m_arrComponents[it->second]; - } - */ -} - -// refreshes the statistics built after the component array is built -void CrySizerStats::refresh() -{ - m_nMaxNameLength = 0; - for (size_t i = 0; i < m_arrComponents.size(); ++i) - { - size_t nLength = m_arrComponents[i].strName.length() + m_arrComponents[i].nDepth; - if (nLength > m_nMaxNameLength) - { - m_nMaxNameLength = nLength; - } - } -} - - -bool CrySizerStats::Component::GenericOrder::operator () (const Component& left, const Component& right) const -{ - return left.strName < right.strName; -} - - -CrySizerStatsRenderer::CrySizerStatsRenderer (ISystem* pSystem, CrySizerStats* pStats, unsigned nMaxSubcomponentDepth, int nMinSubcomponentBytes) - : m_pStats(pStats) - , m_pRenderer(pSystem->GetIRenderer()) - , m_pLog (pSystem->GetILog()) - , m_pTextModeConsole(pSystem->GetITextModeConsole()) - , m_nMinSubcomponentBytes (nMinSubcomponentBytes < 0 || nMinSubcomponentBytes > 0x10000000 ? 0x8000 : nMinSubcomponentBytes) - , m_nMaxSubcomponentDepth (nMaxSubcomponentDepth) -{ -} - - -static void DrawStatsText(float x, float y, float fScale, float color[4], const char* format, ...) -{ - va_list args; - va_start(args, format); - SDrawTextInfo ti; - ti.xscale = fScale; - ti.yscale = fScale; - ti.color[0] = color[0]; - ti.color[1] = color[1]; - ti.color[2] = color[2]; - ti.color[3] = color[3]; - ti.flags = eDrawText_2D | eDrawText_FixedSize | eDrawText_Monospace; - gEnv->pRenderer->DrawTextQueued(Vec3(x, y, 0.5f), ti, format, args); - va_end(args); -} - -void CrySizerStatsRenderer::render(bool bRefreshMark) -{ - if (!m_pStats->size()) - { - return; - } - - int x, y, dx, dy; - m_pRenderer->GetViewport(&x, &y, &dx, &dy); - - // left coordinate of the text - unsigned nNameWidth = (unsigned)(m_pStats->getMaxNameLength() + 1); - if (nNameWidth < 25) - { - nNameWidth = 25; - } - float fCharScaleX = 1.2f; - float fLeft = 0; - float fTop = 8; - float fVStep = 9; - -#ifdef _DEBUG - const char* szCountStr1 = "count"; - const char* szCountStr2 = "_____"; -#else // _DEBUG - const char* szCountStr1 = "", * szCountStr2 = ""; -#endif // _DEBUG - - float fTextColor[4] = {0.9f, 0.85f, 1, 0.85f}; - DrawStatsText(fLeft, fTop, fCharScaleX, fTextColor, - "%-*s total partial %s", nNameWidth, bRefreshMark ? "Memory usage (refresh*)" : "Memory usage (refresh )", szCountStr1); - DrawStatsText(fLeft, fTop + fVStep * 0.25f, fCharScaleX, fTextColor, - "%*s _____ _______ %s", nNameWidth, "", szCountStr2); - - unsigned nSubgroupDepth = 1; - - // different colors used to paint the statistics subgroups - // a new statistic subgroup starts with a new subtree of depth <= specified - float fGray = 0;//0.45f; - float fLightGray = 0.5f;//0.8f; - float fColors[] = - { - fLightGray, fLightGray, fGray, 1, - 1, 1, 1, 1, - fGray, 1, 1, 1, - 1, fGray, 1, 1, - 1, 1, fGray, 1, - fGray, fLightGray, 1, 1, - fGray, 1, fGray, 1, - 1, fGray, fGray, 1 - }; - float* pColor = fColors; - - unsigned statSize = m_pStats->size(); - unsigned startRow = m_pStats->row(); - unsigned i = 0; - for (; i < startRow; ++i) - { - const Component& rComp = (*m_pStats)[i]; - if (rComp.nDepth <= nSubgroupDepth) - { - //switch the color - pColor += 4; - if (pColor >= fColors + sizeof(fColors) / sizeof(fColors[0])) - { - pColor = fColors; - } - - fTop += fVStep * (0.333333f + (nSubgroupDepth - rComp.nDepth) * 0.15f); - } - } - - for (unsigned r = startRow; i < statSize; ++i) - { - const Component& rComp = (*m_pStats)[i]; - if (rComp.nDepth <= nSubgroupDepth) - { - //switch the color - pColor += 4; - if (pColor >= fColors + sizeof(fColors) / sizeof(fColors[0])) - { - pColor = fColors; - } - - fTop += fVStep * (0.333333f + (nSubgroupDepth - rComp.nDepth) * 0.15f); - } - - if (rComp.sizeBytesTotal <= m_nMinSubcomponentBytes || rComp.nDepth > m_nMaxSubcomponentDepth) - { - continue; - } - - fTop += fVStep; - - char szDepth[32] = " .............................."; - if (rComp.nDepth < sizeof(szDepth)) - { - szDepth[rComp.nDepth] = '\0'; - } - - char szSize[32]; - if (rComp.sizeBytes > 0) - { - if (rComp.sizeBytesTotal > rComp.sizeBytes) - { - azsprintf(szSize, "%7.3f %7.3f", rComp.getTotalSizeMBytes(), rComp.getSizeMBytes()); - } - else - { - azsprintf(szSize, " %7.3f", rComp.getSizeMBytes()); - } - } - else - { - assert (rComp.sizeBytesTotal > 0); - azsprintf(szSize, "%7.3f ", rComp.getTotalSizeMBytes()); - } - char szCount[16]; -#ifdef _DEBUG - if (rComp.numObjects) - { - azsprintf(szCount, "%zd" PRIu64 "", rComp.numObjects); - } - else -#endif - szCount[0] = '\0'; - - DrawStatsText(fLeft, fTop, fCharScaleX, pColor, - "%s%-*s:%s%s", szDepth, nNameWidth - rComp.nDepth, rComp.strName.c_str(), szSize, szCount); - - if (m_pTextModeConsole) - { - string text; - text.Format("%s%-*s:%s%s", szDepth, nNameWidth - rComp.nDepth, rComp.strName.c_str(), szSize, szCount); - m_pTextModeConsole->PutText(0, r++, text.c_str()); - } - } - - float fLTGrayColor[4] = {fLightGray, fLightGray, fLightGray, 1.0f}; - fTop += 0.25f * fVStep; - DrawStatsText(fLeft, fTop, fCharScaleX, fLTGrayColor, - "%-*s %s", nNameWidth, "___________________________", "________________"); - fTop += fVStep; - - const char* szOverheadNames[CrySizerStats::g_numTimers] = - { - ".Collection", - ".Transformation", - ".Cleanup" - }; - bool bOverheadsHeaderPrinted = false; - for (i = 0; i < CrySizerStats::g_numTimers; ++i) - { - float fTime = m_pStats->getTime(i); - if (fTime < 20) - { - continue; - } - // print the header - if (!bOverheadsHeaderPrinted) - { - DrawStatsText(fLeft, fTop, fCharScaleX, fTextColor, - "%-*s", nNameWidth, "Overheads"); - fTop += fVStep; - bOverheadsHeaderPrinted = true; - } - - DrawStatsText(fLeft, fTop, fCharScaleX, fTextColor, - "%-*s:%7.1f ms", nNameWidth, szOverheadNames[i], fTime); - fTop += fVStep; - } -} - -void CrySizerStatsRenderer::dump(bool bUseKB) -{ - if (!m_pStats->size()) - { - return; - } - - unsigned nNameWidth = (unsigned)(m_pStats->getMaxNameLength() + 1); - - // left coordinate of the text - m_pLog->LogToFile ("Memory Statistics: %s", bUseKB ? "KB" : "MB"); - m_pLog->LogToFile("%-*s TOTAL partial count", nNameWidth, ""); - - // different colors used to paint the statistics subgroups - // a new statistic subgroup starts with a new subtree of depth <= specified - - for (unsigned i = 0; i < m_pStats->size(); ++i) - { - const Component& rComp = (*m_pStats)[i]; - - if (rComp.sizeBytesTotal <= m_nMinSubcomponentBytes || rComp.nDepth > m_nMaxSubcomponentDepth) - { - continue; - } - - char szDepth[32] = " .............................."; - if (rComp.nDepth < sizeof(szDepth)) - { - szDepth[rComp.nDepth] = '\0'; - } - - char szSize[32]; - if (rComp.sizeBytes > 0) - { - if (rComp.sizeBytesTotal > rComp.sizeBytes) - { - azsprintf(szSize, bUseKB ? "%7.2f %7.2f" : "%7.3f %7.3f", bUseKB ? rComp.getTotalSizeKBytes() : rComp.getTotalSizeMBytes(), bUseKB ? rComp.getSizeKBytes() : rComp.getSizeMBytes()); - } - else - { - azsprintf(szSize, bUseKB ? " %7.2f" : " %7.3f", bUseKB ? rComp.getSizeKBytes() : rComp.getSizeMBytes()); - } - } - else - { - assert (rComp.sizeBytesTotal > 0); - azsprintf(szSize, bUseKB ? "%7.2f " : "%7.3f ", bUseKB ? rComp.getTotalSizeKBytes() : rComp.getTotalSizeMBytes()); - } - char szCount[16]; - - if (rComp.numObjects) - { - azsprintf(szCount, "%8u", (unsigned int)rComp.numObjects); - } - else - { - szCount[0] = '\0'; - } - - m_pLog->LogToFile ("%s%-*s:%s%s", szDepth, nNameWidth - rComp.nDepth, rComp.strName.c_str(), szSize, szCount); - } -} - - -void CrySizerStats::startTimer(unsigned nTimer, ITimer* pTimer) -{ - assert (nTimer < g_numTimers); - m_fTime[nTimer] = pTimer->GetAsyncCurTime(); -} - -void CrySizerStats::stopTimer(unsigned nTimer, ITimer* pTimer) -{ - assert (nTimer < g_numTimers); - m_fTime[nTimer] = 1000 * (pTimer->GetAsyncCurTime() - m_fTime[nTimer]); -} diff --git a/Code/CryEngine/CrySystem/CrySizerStats.h b/Code/CryEngine/CrySystem/CrySizerStats.h deleted file mode 100644 index fc8c43a7c2..0000000000 --- a/Code/CryEngine/CrySystem/CrySizerStats.h +++ /dev/null @@ -1,207 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Declaration of the CrySizerStats class, which is used to -// calculate the memory usage by the subsystems and components, to help -// the artists keep the memory budged low. - -#ifndef CRYINCLUDE_CRYSYSTEM_CRYSIZERSTATS_H -#define CRYINCLUDE_CRYSYSTEM_CRYSIZERSTATS_H -#pragma once - - -class CrySizerImpl; - -////////////////////////////////////////////////////////////////////////// -// This class holds only the necessary statistics data, which can be carried -// over a few frames without significant impact on memory usage -// CrySizerImpl is an implementation of ICrySizer, which is used to collect -// those data; it must be destructed immediately after constructing the Stats -// object to avoid excessive memory usage. -class CrySizerStats -{ -public: - // constructs the statistics based on the given cry sizer - CrySizerStats (CrySizerImpl* pCrySizer); - - CrySizerStats (); - - // this structure describes one component of the memory size statistics - struct Component - { - Component() {clear(); } - Component (const string& name, unsigned size = 0, unsigned num = 0) - : strName(name) - , sizeBytes(size) - , numObjects(num) - , nDepth(0) {} - void clear() - { - strName = ""; - sizeBytes = 0; - numObjects = 0; - nDepth = 0; - } - - // the name of the component, as it appeared in the push() call - string strName; - // the total size, in bytes, of objects in the component - size_t sizeBytes; - // the total size including the subcomponents - size_t sizeBytesTotal; - // the number of objects allocated - size_t numObjects; - unsigned nDepth; - - float getSizeKBytes() const {return sizeBytes / float(1 << 10); } - - float getTotalSizeKBytes () const {return sizeBytesTotal / float(1 << 10); } - - float getSizeMBytes() const {return sizeBytes / float(1 << 20); } - - float getTotalSizeMBytes () const {return sizeBytesTotal / float(1 << 20); } - - struct NameOrder - { - bool operator () (const Component& left, const Component& right) const {return left.strName < right.strName; } - }; - - struct SizeOrder - { - bool operator () (const Component& left, const Component& right) const {return left.sizeBytes < right.sizeBytes; } - }; - - struct GenericOrder - { - bool operator () (const Component& left, const Component& right) const; - }; - }; - - // returns the number of different subsystems/components used - unsigned numComponents() const {return (unsigned)m_arrComponents.size(); } - // returns the name of the i-th component - const Component& getComponent(unsigned nComponent) const {return m_arrComponents[nComponent]; } - - unsigned size() const {return numComponents(); } - const Component& operator [] (unsigned i) const {return getComponent(i); } - const Component& operator [] (signed i) const {return getComponent(i); } - - unsigned row() const {return m_nStartRow; } - void updateKeys(); - - size_t getMaxNameLength() const {return m_nMaxNameLength; } - enum - { - g_numTimers = 3 - }; - - void startTimer(unsigned nTimer, ITimer* pTimer); - void stopTimer(unsigned nTimer, ITimer* pTimer); - float getTime(unsigned nTimer) const {assert (nTimer < g_numTimers); return m_fTime[nTimer]; } - int getAgeFrames() const {return m_nAgeFrames; } - void incAgeFrames() {++m_nAgeFrames; } -protected: - // refreshes the statistics built after the component array is built - void refresh(); -protected: - // the names of the components - typedef std::vector ComponentArray; - ComponentArray m_arrComponents; - - // the maximum length of the component name, in characters - size_t m_nMaxNameLength; - - // the timer that counts the time spent on statistics gathering - float m_fTime[g_numTimers]; - - // the age of the statistics, in frames - int m_nAgeFrames; - - //current row offset inc/dec by cursor keys - unsigned m_nStartRow; - - friend class CrySizerStatsBuilder; -}; - - -////////////////////////////////////////////////////////////////////////// -// this is the constructor for the CrySizerStats -class CrySizerStatsBuilder -{ -public: - CrySizerStatsBuilder (CrySizerImpl* pSizer, int nMinSubcomponentBytes = 0); - - void build (CrySizerStats* pStats); - -protected: - typedef CrySizerStats::Component Component; - // if there is already such name in the map, then just returns the index - // of the compoentn in the component array; otherwise adds an entry to themap - // and to the component array nad returns its index - Component& mapName (unsigned nName); - - // creates the map of names from old to new, and initializes the components themselves - void processNames(); - - // given the name in the old system, adds the subtree of names to the - // name map and components. In case all the subtree is empty, returns 0 and - // adds nothing. Otherwise, returns the total size of objects belonging to the - // subtree - size_t addNameSubtree (unsigned nDepth, size_t nName); - -protected: - CrySizerStats* m_pStats; - CrySizerImpl* m_pSizer; - - // this is the mapping from the old names into the new componentn indices - typedef std::vector IdToIdMap; - // from old to new - IdToIdMap m_mapNames; - - // this is the threshold: if the total number of bytes in the subcomponent - // is less than this, the subcomponent isn't shown - unsigned m_nMinSubcomponentBytes; -}; - - - -////////////////////////////////////////////////////////////////////////// -// Renders the given usage stats; gets created upon every rendering -class CrySizerStatsRenderer -{ -public: - // constructor - CrySizerStatsRenderer (ISystem* pSystem, CrySizerStats* pStats, unsigned nMaxDepth = 2, int nMinSubcomponentBytes = -1); - void render(bool bRefreshMark = false); - // dumps it to log. uses MB as default - void dump (bool bUseKB = false); - -protected: // ------------------------------------------------- - - typedef CrySizerStats::Component Component; - - IRenderer* m_pRenderer; // - ILog* m_pLog; // - CrySizerStats* m_pStats; // - - ITextModeConsole* m_pTextModeConsole; - - // this is the threshold: if the total number of bytes in the subcomponent - // is less than this, the subcomponent isn't shown - unsigned m_nMinSubcomponentBytes; - - // the max depth of the branch to output - unsigned m_nMaxSubcomponentDepth; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_CRYSIZERSTATS_H diff --git a/Code/CryEngine/CrySystem/DebugCallStack.cpp b/Code/CryEngine/CrySystem/DebugCallStack.cpp index da3876a422..f33e793db6 100644 --- a/Code/CryEngine/CrySystem/DebugCallStack.cpp +++ b/Code/CryEngine/CrySystem/DebugCallStack.cpp @@ -287,18 +287,6 @@ int DebugCallStack::handleException(EXCEPTION_POINTERS* exception_pointer) gEnv->szDebugStatus[SSystemGlobalEnvironment::MAX_DEBUG_STRING_LENGTH - 1] = '\0'; WriteLineToLog("Debug Status: %s", gEnv->szDebugStatus); } - - if (gEnv->pRenderer) - { - ID3DDebugMessage* pMsg = 0; - gEnv->pRenderer->EF_Query(EFQ_GetLastD3DDebugMessage, pMsg); - if (pMsg) - { - const char* pStr = pMsg->GetMessage(); - WriteLineToLog("Last D3D debug message: %s", pStr ? pStr : "#unknown#"); - SAFE_RELEASE(pMsg); - } - } } firstTime = false; @@ -832,17 +820,6 @@ int DebugCallStack::SubmitBug(EXCEPTION_POINTERS* exception_pointer) assert(!hwndException); - // If in full screen minimize render window - { - ICVar* pFullscreen = (gEnv && gEnv->pConsole) ? gEnv->pConsole->GetCVar("r_Fullscreen") : 0; - if (pFullscreen && pFullscreen->GetIVal() != 0 && gEnv->pRenderer && gEnv->pRenderer->GetHWND()) - { - ::ShowWindow((HWND)gEnv->pRenderer->GetHWND(), SW_MINIMIZE); - } - } - - //hwndException = CreateDialog( gDLLHandle,MAKEINTRESOURCE(IDD_EXCEPTION),NULL,NULL ); - RemoveOldFiles(); AZ::Debug::Trace::PrintCallstack("", 2); diff --git a/Code/CryEngine/CrySystem/DefragAllocator.cpp b/Code/CryEngine/CrySystem/DefragAllocator.cpp deleted file mode 100644 index 8858724be1..0000000000 --- a/Code/CryEngine/CrySystem/DefragAllocator.cpp +++ /dev/null @@ -1,1976 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "DefragAllocator.h" -#include "IRenderAuxGeom.h" - -CDefragAllocatorWalker::CDefragAllocatorWalker(CDefragAllocator& alloc) -{ - m_pAlloc = &alloc; - m_pAlloc->m_lock.Lock(); - - m_nChunkIdx = CDefragAllocator::AddrStartSentinal; -} - -CDefragAllocatorWalker::~CDefragAllocatorWalker() -{ - m_pAlloc->m_lock.Unlock(); -} - -const SDefragAllocChunk* CDefragAllocatorWalker::Next() -{ - m_nChunkIdx = m_pAlloc->m_chunks[m_nChunkIdx].addrNextIdx; - if (m_nChunkIdx == CDefragAllocator::AddrEndSentinal) - { - return NULL; - } - return &m_pAlloc->m_chunks[m_nChunkIdx]; -} - -CDefragAllocator::CDefragAllocator() - : m_isThreadSafe(false) - , m_chunksAreFixed(false) - , m_capacity(0) - , m_available(0) - , m_numAllocs(0) - , m_minAlignment(1) - , m_logMinAlignment(0) - , m_nCancelledMoves(0) -{ -} - -CDefragAllocator::~CDefragAllocator() -{ -} - -void CDefragAllocator::Release(bool bDiscard) -{ - if (!bDiscard) - { - if (m_policy.pDefragPolicy) - { - Defrag_CompletePendingMoves(); - } - - for (PendingMoveVec::iterator it = m_pendingMoves.begin(), itEnd = m_pendingMoves.end(); it != itEnd; ++it) - { - CDBA_ASSERT(it->dstChunkIdx == InvalidChunkIdx); - } - } - - delete this; -} - -void CDefragAllocator::Init(UINT_PTR capacity, UINT_PTR minAlignment, const Policy& policy) -{ - CDBA_ASSERT((capacity & (minAlignment - 1)) == 0); - CDBA_ASSERT((minAlignment & (minAlignment - 1)) == 0); - CDBA_ASSERT(!policy.pDefragPolicy || policy.maxAllocs > 0); - CDBA_ASSERT((capacity / minAlignment) < (1 << SDefragAllocChunkAttr::SizeWidth)); - - uint32 logMinAlignment = (uint32)IntegerLog2(minAlignment); - - capacity >>= logMinAlignment; - - CDBA_ASSERT(capacity <= (uint32) - 1); - - m_isThreadSafe = policy.pDefragPolicy != NULL; - - m_capacity = (uint32)capacity; - m_available = (uint32)capacity; - m_numAllocs = 0; - - m_minAlignment = (uint32)minAlignment; - m_logMinAlignment = logMinAlignment; - - m_chunks.clear(); - m_unusedChunks.clear(); - - m_policy = policy; - if (policy.pDefragPolicy) - { - m_pendingMoves.resize(MaxPendingMoves); - } - - m_chunks.reserve(NumBuckets + 3); - - // Create sentinal chunk for by-address list - { - SDefragAllocChunk addrStartSentinal = {0}; - addrStartSentinal.addrNextIdx = 1; - addrStartSentinal.addrPrevIdx = 1; - addrStartSentinal.attr.SetBusy(true); - addrStartSentinal.ptr = 0; - m_chunks.push_back(addrStartSentinal); - - SDefragAllocChunk addrEndSentinal = {0}; - addrEndSentinal.addrNextIdx = 0; - addrEndSentinal.addrPrevIdx = 0; - addrEndSentinal.attr.SetBusy(true); - addrEndSentinal.ptr = m_capacity; - m_chunks.push_back(addrEndSentinal); - } - - SDefragAllocSegment seg; - seg.address = 0; - seg.capacity = (uint32)capacity; - seg.headSentinalChunkIdx = AddrStartSentinal; - - // Create sentinal chunks for the bucket lists - for (size_t bucketIdx = 0; bucketIdx < NumBuckets; ++bucketIdx) - { - Index chunkIdx = bucketIdx + 2; - - SDefragAllocChunk chunk = {0}; - chunk.attr.SetBusy(true); - chunk.freeNextIdx = chunkIdx; - chunk.freePrevIdx = chunkIdx; - - m_freeBuckets[bucketIdx] = chunkIdx; - m_chunks.push_back(chunk); - } - - Index totalChunkIdx = AllocateChunk(); - SDefragAllocChunk& totalChunk = m_chunks[totalChunkIdx]; - totalChunk.attr.SetSize((unsigned int)capacity); - totalChunk.attr.SetPinCount(0); - totalChunk.attr.SetMoving(0); - LinkAddrChunk(totalChunkIdx, 0); - LinkFreeChunk(totalChunkIdx); - - if (policy.maxAllocs > 0) - { - size_t curChunksSize = m_chunks.size(); - m_chunks.resize(policy.maxAllocs); - for (Index i = (Index)curChunksSize, c = (Index)m_chunks.size(); i < c; ++i) - { - m_unusedChunks.push_back(i); - } - } - - m_chunksAreFixed = policy.pDefragPolicy != NULL; - - m_segments.reserve(policy.maxSegments); - m_segments.push_back(seg); -} - -#ifndef _RELEASE -void CDefragAllocator::DumpState(const char* filename) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - FILE* fp = nullptr; - azfopen(&fp, filename, "wb"); - if (fp) - { - uint32 magic = 0xdef7a6e7; - fwrite(&magic, sizeof(magic), 1, fp); - - fwrite(&m_capacity, sizeof(m_capacity), 1, fp); - fwrite(&m_available, sizeof(m_available), 1, fp); - fwrite(&m_numAllocs, sizeof(m_numAllocs), 1, fp); - fwrite(&m_minAlignment, sizeof(m_minAlignment), 1, fp); - fwrite(&m_logMinAlignment, sizeof(m_logMinAlignment), 1, fp); - fwrite(&m_freeBuckets[0], sizeof(m_freeBuckets), 1, fp); - - uint32 numChunks = (uint32)m_chunks.size(); - fwrite(&numChunks, sizeof(numChunks), 1, fp); - fwrite(&m_chunks[0], sizeof(m_chunks[0]), numChunks, fp); - uint32 numUnused = (uint32)m_unusedChunks.size(); - fwrite(&numUnused, sizeof(numUnused), 1, fp); - fwrite(&m_unusedChunks[0], sizeof(m_unusedChunks[0]), numUnused, fp); - uint32 numPending = (uint32)m_pendingMoves.size(); - fwrite(&numPending, sizeof(numPending), 1, fp); - fwrite(&m_pendingMoves[0], sizeof(m_pendingMoves[0]), numPending, fp); - uint32 numSegs = (uint32)m_segments.size(); - fwrite(&numSegs, sizeof(numSegs), 1, fp); - fwrite(&m_segments[0], sizeof(m_segments[0]), numSegs, fp); - - fclose(fp); - } -} - -void CDefragAllocator::RestoreState(const char* filename) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - FILE* fp = nullptr; - azfopen(&fp, filename, "rb"); - if (fp) - { - uint32 magic; - fread(&magic, sizeof(magic), 1, fp); - - bool bSwap = magic == 0xe7a6f7de; - - fread(&m_capacity, sizeof(m_capacity), 1, fp); - SwapEndian(m_capacity, bSwap); - - fread(&m_available, sizeof(m_available), 1, fp); - SwapEndian(m_available, bSwap); - - fread(&m_numAllocs, sizeof(m_numAllocs), 1, fp); - SwapEndian(m_numAllocs, bSwap); - - fread(&m_minAlignment, sizeof(m_minAlignment), 1, fp); - SwapEndian(m_minAlignment, bSwap); - - fread(&m_logMinAlignment, sizeof(m_logMinAlignment), 1, fp); - SwapEndian(m_logMinAlignment, bSwap); - - fread(&m_freeBuckets[0], sizeof(m_freeBuckets), 1, fp); - SwapEndian(&m_freeBuckets[0], NumBuckets, bSwap); - - uint32 numChunks; - fread(&numChunks, sizeof(numChunks), 1, fp); - SwapEndian(numChunks, bSwap); - - m_chunks.resize(numChunks); - fread(&m_chunks[0], sizeof(m_chunks[0]), numChunks, fp); - if (bSwap) - { - for (size_t ci = 0, cc = m_chunks.size(); ci != cc; ++ci) - { - m_chunks[ci].SwapEndian(); - } - } - - uint32 numUnused; - fread(&numUnused, sizeof(numUnused), 1, fp); - SwapEndian(numUnused, bSwap); - - m_unusedChunks.resize(numUnused); - fread(&m_unusedChunks[0], sizeof(m_unusedChunks[0]), numUnused, fp); - SwapEndian(&m_unusedChunks[0], m_unusedChunks.size(), bSwap); - - uint32 numPending; - fread(&numPending, sizeof(numPending), 1, fp); - SwapEndian(numPending, bSwap); - - m_pendingMoves.resize(numPending); - fread(&m_pendingMoves[0], sizeof(m_pendingMoves[0]), numPending, fp); - if (bSwap) - { - for (size_t pi = 0, pc = m_pendingMoves.size(); pi != pc; ++pi) - { - m_pendingMoves[pi].SwapEndian(); - } - } - - uint32 numSegs; - fread(&numSegs, sizeof(numSegs), 1, fp); - SwapEndian(numSegs, bSwap); - - m_segments.resize(numSegs); - fread(&m_segments[0], sizeof(m_segments[0]), numSegs, fp); - if (bSwap) - { - for (size_t si = 0, sc = m_segments.size(); si != sc; ++si) - { - m_segments[si].SwapEndian(); - } - } - - fclose(fp); - - RebuildFreeLists(); - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); - ValidateFreeLists(); -#endif - } -} -#endif - -bool CDefragAllocator::AppendSegment(UINT_PTR capacity) -{ - CDBA_ASSERT((capacity & (m_minAlignment - 1)) == 0); - - bool bSuccessful = false; - - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - capacity >>= m_logMinAlignment; - - // Create a sentinal chunk for the head of the new segment. - Index headSentinalIdx = AllocateChunk(); - if (headSentinalIdx != InvalidChunkIdx) - { - // And a free block. - Index freeBlockIdx = AllocateChunk(); - if (freeBlockIdx != InvalidChunkIdx) - { - SDefragAllocChunk& headSentinalChunk = m_chunks[headSentinalIdx]; - SDefragAllocChunk& freeChunk = m_chunks[freeBlockIdx]; - SDefragAllocChunk& addrEndSentinal = m_chunks[AddrEndSentinal]; - - uint32 allocCapacity = m_capacity; - - headSentinalChunk.ptr = allocCapacity; -#ifndef _RELEASE - headSentinalChunk.source = "Segment Sentinal"; -#endif - headSentinalChunk.attr.SetBusy(true); - headSentinalChunk.attr.SetMoving(false); - headSentinalChunk.attr.SetPinCount(1); - headSentinalChunk.attr.SetSize(0); - - freeChunk.ptr = allocCapacity; - freeChunk.attr.SetBusy(false); - freeChunk.attr.SetMoving(false); - freeChunk.attr.SetPinCount(0); - freeChunk.attr.SetSize((unsigned int)capacity); - - LinkAddrChunk(headSentinalIdx, addrEndSentinal.addrPrevIdx); - LinkAddrChunk(freeBlockIdx, headSentinalIdx); - LinkFreeChunk(freeBlockIdx); - addrEndSentinal.ptr = allocCapacity + (uint32)capacity; - - SDefragAllocSegment seg; - seg.address = allocCapacity; - seg.capacity = (uint32)capacity; - seg.headSentinalChunkIdx = headSentinalIdx; - m_segments.push_back(seg); - - m_capacity = allocCapacity + (uint32)capacity; - m_available += (uint32)capacity; - bSuccessful = true; - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); -#endif - } - else - { - ReleaseChunk(headSentinalIdx); - } - } - - return bSuccessful; -} - -void CDefragAllocator::UnAppendSegment() -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - // Can't remove the last segment! - CDBA_ASSERT(m_segments.size() > 1); - - [[maybe_unused]] bool bHasMoves = Defrag_CompletePendingMoves(); - - // All outstanding moves should be completed. - CDBA_ASSERT(!bHasMoves); - - // Move all live chunks from this segment into another. - SyncMoveSegment((uint32)m_segments.size() - 1); - - SDefragAllocSegment& segment = m_segments.back(); - SDefragAllocChunk& headSentinalChunk = m_chunks[segment.headSentinalChunkIdx]; - - // Assert that the segment is empty, and release all chunks within it. - uint32 endAddress = m_capacity; - Index chunkIdx = headSentinalChunk.addrNextIdx; - - UnlinkAddrChunk(segment.headSentinalChunkIdx); - ReleaseChunk(segment.headSentinalChunkIdx); - - SDefragAllocChunk* pChunk = &m_chunks[chunkIdx]; - - while (pChunk->ptr != endAddress) - { - CDBA_ASSERT(!pChunk->attr.IsBusy()); - - Index nextChunkIdx = pChunk->addrNextIdx; - - UnlinkFreeChunk(chunkIdx); - UnlinkAddrChunk(chunkIdx); - ReleaseChunk(chunkIdx); - - chunkIdx = nextChunkIdx; - pChunk = &m_chunks[chunkIdx]; - } - - // chunkIdx/pChunk should be the end of memory sentinal. - CDBA_ASSERT(chunkIdx == AddrEndSentinal && pChunk->attr.IsBusy() && !pChunk->attr.GetSize()); - - pChunk->ptr -= segment.capacity; - - m_capacity -= segment.capacity; - m_available -= segment.capacity; - m_segments.pop_back(); -} - -IDefragAllocator::Hdl CDefragAllocator::Allocate(size_t sz, const char* source, void* pContext) -{ - CDBA_ASSERT((IntegerLog2(NextPower2(Align(sz, m_minAlignment))) - m_logMinAlignment) < (1u << SDefragAllocChunkAttr::SizeWidth)); - - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - return Allocate_Locked(sz, m_minAlignment, source, pContext); -} - -IDefragAllocator::Hdl CDefragAllocator::AllocateAligned(size_t sz, size_t alignment, const char* source, void* pContext) -{ - alignment = max((size_t)m_minAlignment, alignment); - - // Just to check the alignment can be stored - CDBA_ASSERT((IntegerLog2(alignment) - m_logMinAlignment) < (1u << SDefragAllocChunk::AlignBitCount)); - CDBA_ASSERT((IntegerLog2(NextPower2(Align(sz, alignment))) - m_logMinAlignment) < (1u << SDefragAllocChunkAttr::SizeWidth)); - - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - return Allocate_Locked(sz, alignment, source, pContext); -} - -IDefragAllocator::AllocatePinnedResult CDefragAllocator::AllocatePinned(size_t sz, const char* source, void* pContext /* = NULL */) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - AllocatePinnedResult apr = {0}; - apr.hdl = Allocate_Locked(sz, m_minAlignment, source, pContext); - if (apr.hdl != InvalidHdl) - { - apr.offs = Pin(apr.hdl); - apr.usableSize = CDefragAllocator::UsableSize(apr.hdl); - } - - return apr; -} - -bool CDefragAllocator::Free(Hdl hdl) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - if (hdl != InvalidHdl) - { - // Assume that the allocator now has exclusive ownership of hdl - that is, - // that the caller won't be modifying it externally. - - Index hdlIdx = ChunkIdxFromHdl(hdl); - CDBA_ASSERT(hdlIdx < m_chunks.size()); - - SDefragAllocChunk* chunk = &m_chunks[hdlIdx]; - CDBA_ASSERT(chunk->attr.IsBusy()); - - // Moving state can only be acquired by defrag and released by CancelMove, both own lock as well as Free. - if (chunk->attr.IsMoving()) - { - CancelMove_Locked(hdlIdx, false); - CDBA_ASSERT(!chunk->attr.IsMoving()); - } - - MarkAsFree(*chunk); - MergeFreeBlock(hdlIdx); - - return true; - } - - return false; -} - -void CDefragAllocator::ChangeContext(Hdl hdl, void* pNewContext) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - CDBA_ASSERT(hdl != InvalidHdl); - - Index hdlIdx = ChunkIdxFromHdl(hdl); - SDefragAllocChunk& chunk = m_chunks[hdlIdx]; - CDBA_ASSERT(chunk.attr.IsBusy()); - chunk.pContext = pNewContext; -} - -IDefragAllocatorStats CDefragAllocator::GetStats() -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - - IDefragAllocatorStats stats = {0}; - - stats.nCapacity = static_cast(m_capacity) << m_logMinAlignment; - stats.nInUseSize = static_cast(m_capacity - m_available) << m_logMinAlignment; - stats.nInUseBlocks = m_numAllocs; - - uint32 numFreeBlocks = 0; - uint32 numPinnedBlocks = 0; - uint32 numMovingBlocks = 0; - uint32 maxFreeBlockSize = 0; - uint32 minFreeBlockSize = (uint32) - 1; - - SDefragAllocChunk* pChunks = &m_chunks[0]; - for (Index idx = pChunks[AddrStartSentinal].addrNextIdx; idx != AddrEndSentinal; idx = pChunks[idx].addrNextIdx) - { - SDefragAllocChunk& c = pChunks[idx]; - SDefragAllocChunkAttr ca = c.attr; - - if (ca.IsBusy()) - { - if (ca.IsPinned()) - { - ++numPinnedBlocks; - } - if (ca.IsMoving()) - { - ++numMovingBlocks; - } - } - else - { - maxFreeBlockSize = max(maxFreeBlockSize, ca.GetSize()); - minFreeBlockSize = min(minFreeBlockSize, ca.GetSize()); - ++numFreeBlocks; - } - } - - stats.nFreeBlocks = numFreeBlocks; - stats.nPinnedBlocks = numPinnedBlocks - numMovingBlocks - (int)(m_segments.size() - 1); // Each moving block pins a block for the destination - stats.nMovingBlocks = numMovingBlocks; - stats.nLargestFreeBlockSize = maxFreeBlockSize << m_logMinAlignment; - stats.nSmallestFreeBlockSize = minFreeBlockSize << m_logMinAlignment; - stats.nMeanFreeBlockSize = (numFreeBlocks > 0) - ? ((m_available << m_logMinAlignment) / numFreeBlocks) - : 0; - stats.nCancelledMoveCount = (uint32)m_nCancelledMoves; - - return stats; -} - -size_t CDefragAllocator::DefragmentTick(size_t maxMoves, size_t maxAmount, bool bForce) -{ - if (m_isThreadSafe) - { - if (bForce) - { - m_lock.Lock(); - } - else if (!m_lock.TryLock()) - { - return 0; - } - } - - Defrag_CompletePendingMoves(); - - maxMoves = min(maxMoves, (size_t)MaxPendingMoves); - maxMoves = min(maxMoves, m_unusedChunks.size()); // Assume that each move requires a split - maxAmount >>= m_logMinAlignment; - - PendingMove* moves[MaxPendingMoves]; - size_t numMoves = 0; - size_t curAmount = 0; - -#ifdef CDBA_MORE_DEBUG - Defrag_ValidateFreeBlockIteration(); -#endif - - if (maxMoves > 0) - { - numMoves = Defrag_FindMovesBwd(moves + numMoves, maxMoves - numMoves, curAmount, maxAmount); - if (numMoves < maxMoves) - { - numMoves += Defrag_FindMovesFwd(moves + numMoves, maxMoves - numMoves, curAmount, maxAmount); - } - -#ifdef CDBA_DEBUG - for (size_t moveIdx = 0; moveIdx < numMoves; ++moveIdx) - { - PendingMove& pm = *moves[moveIdx]; - - SDefragAllocChunk& srcChunk = m_chunks[pm.srcChunkIdx]; - SDefragAllocChunk& dstChunk = m_chunks[pm.dstChunkIdx]; - SDefragAllocChunkAttr srcChunkAttr = srcChunk.attr; - SDefragAllocChunkAttr dstChunkAttr = dstChunk.attr; - - CDBA_ASSERT(srcChunkAttr.IsMoving()); - CDBA_ASSERT(dstChunkAttr.IsPinned()); - CDBA_ASSERT(dstChunkAttr.IsBusy()); - CDBA_ASSERT(dstChunkAttr.GetSize() == srcChunkAttr.GetSize()); - } -#endif - } - - if (m_isThreadSafe) - { - m_lock.Unlock(); - } - - return curAmount; -} - -CDefragAllocator::Index CDefragAllocator::AllocateChunk() -{ - Index result = InvalidChunkIdx; - - if (!m_unusedChunks.empty()) - { - result = m_unusedChunks.back(); - m_unusedChunks.pop_back(); - } - else if (!m_chunksAreFixed) - { - m_chunks.push_back(SDefragAllocChunk()); - result = (Index) (m_chunks.size() - 1); - CDBA_ASSERT(result == (m_chunks.size() - 1)); - } - - IF_LIKELY (result != InvalidChunkIdx) - { - SDefragAllocChunk& chunk = m_chunks[result]; - chunk.attr.SetBusy(false); - chunk.attr.SetPinCount(0); - chunk.attr.SetMoving(false); - chunk.pContext = NULL; -#ifndef _RELEASE - chunk.source = ""; -#endif - } - - return result; -} - -void CDefragAllocator::DisplayMemoryUsage([[maybe_unused]] const char* title, [[maybe_unused]] unsigned int allocatorDisplayOffset) -{ -#if !defined(_RELEASE) || defined(PERFORMANCE_BUILD) // We want this vis in Performance builds - if (IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom()) - { - int width = gEnv->pRenderer->GetWidth(); - int height = gEnv->pRenderer->GetHeight(); - - // The height of the bar is 40 pixels, but DrawTriangles is in screen UV coords - const float c_barHeight = 40.0f / height; - - unsigned int currentSize = 0; - unsigned int chunkCount = m_chunks.size(); - AZStd::vector chunkVerts; - chunkVerts.reserve(chunkCount * 4); - AZStd::vector chunkIndices; - chunkIndices.reserve(chunkCount * 6); - AZStd::vector chunkColors; - chunkColors.reserve(chunkCount * 4); - - // Chunks use banded colors to show delineations between adjacent allocations - const ColorB usedColor[2] = { ColorB(255, 0, 0), ColorB(200, 0, 0) }; - const ColorB freeColor[2] = { ColorB(0, 255, 0), ColorB(0, 200, 0) }; - - uint32 i = 0; - float minBarY = 1.0f - allocatorDisplayOffset * c_barHeight; - float maxBarY = 1.0f - (allocatorDisplayOffset + 1) * c_barHeight; - for (size_t idx = m_chunks[0].addrNextIdx; idx != 0; idx = m_chunks[idx].addrNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - unsigned int chunkSize = chunk.attr.GetSize(); - if (chunkSize != 0) - { - // Start and end x locations in screen UV coords - float startX = static_cast(currentSize) / m_capacity; - float endX = static_cast(currentSize + chunkSize) / m_capacity; - - // Ensure a valid size is at least one pixel wide - endX = AZStd::max(endX, startX + 1.0f / width); - - chunkVerts.push_back(Vec3(startX, minBarY, 0.0f)); - chunkVerts.push_back(Vec3(endX, minBarY, 0.0f)); - chunkVerts.push_back(Vec3(endX, maxBarY, 0.0f)); - chunkVerts.push_back(Vec3(startX, maxBarY, 0.0f)); - - chunkIndices.push_back(i * 4 + 0); - chunkIndices.push_back(i * 4 + 1); - chunkIndices.push_back(i * 4 + 2); - chunkIndices.push_back(i * 4 + 0); - chunkIndices.push_back(i * 4 + 2); - chunkIndices.push_back(i * 4 + 3); - - if (chunk.attr.IsPinned()) - { - chunkColors.push_back(usedColor[i & 1]); - chunkColors.push_back(usedColor[i & 1]); - chunkColors.push_back(usedColor[i & 1]); - chunkColors.push_back(usedColor[i & 1]); - } - else - { - chunkColors.push_back(freeColor[i & 1]); - chunkColors.push_back(freeColor[i & 1]); - chunkColors.push_back(freeColor[i & 1]); - chunkColors.push_back(freeColor[i & 1]); - } - - currentSize += chunkSize; - i++; - } - } - - SAuxGeomRenderFlags savedFlags = pAuxGeom->GetRenderFlags(); - SAuxGeomRenderFlags tempFlags; - tempFlags.SetMode2D3DFlag(e_Mode2D); - pAuxGeom->SetRenderFlags(tempFlags); - pAuxGeom->DrawTriangles(chunkVerts.data(), chunkVerts.size(), chunkIndices.data(), chunkIndices.size(), chunkColors.data()); - pAuxGeom->SetRenderFlags(savedFlags); - - // Draw other stats about the system - const float statisticsWidth = 384.0f; - float statsXOffset = allocatorDisplayOffset * statisticsWidth; - IDefragAllocatorStats stats = GetStats(); - ColorF statsTextColor(1.0f, 1.0f, 0.5f, 1.0f); - pAuxGeom->Draw2dLabel(10 + statsXOffset, 85, 1.7f, statsTextColor, false, title); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 110, 1.5f, statsTextColor, false, "Capacity (MB): %.2f", stats.nCapacity / 1024.0f / 1024.0f); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 130, 1.5f, statsTextColor, false, "In Use (MB): %.2f", stats.nInUseSize / 1024.0f / 1024.0f); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 150, 1.5f, statsTextColor, false, "In Use Blocks: %u", stats.nInUseBlocks); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 170, 1.5f, statsTextColor, false, "Free Blocks: %u", stats.nFreeBlocks); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 190, 1.5f, statsTextColor, false, "Largest Free Block (B): %u", stats.nLargestFreeBlockSize); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 210, 1.5f, statsTextColor, false, "Smallest Free Block (B): %u", stats.nSmallestFreeBlockSize); - pAuxGeom->Draw2dLabel(20 + statsXOffset, 230, 1.5f, statsTextColor, false, "Mean Free Block (B): %u", stats.nMeanFreeBlockSize); - } -#endif -} - -void CDefragAllocator::ReleaseChunk(Index idx) -{ - m_unusedChunks.push_back(idx); -} - -void CDefragAllocator::LinkFreeChunk(Index idx) -{ - SDefragAllocChunk* pChunks = &m_chunks[0]; - SDefragAllocChunk& chunk = pChunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - - int bucket = BucketForSize(chunk.attr.GetSize()); - - Index rootIdx = m_freeBuckets[bucket]; - Index beforeIdx; - - // Search for the position in the list to insert the new block, maintaining address order - for (beforeIdx = pChunks[rootIdx].freeNextIdx; beforeIdx != rootIdx; beforeIdx = pChunks[beforeIdx].freeNextIdx) - { - if (pChunks[beforeIdx].ptr > chunk.ptr) - { - break; - } - } - - Index afterIdx = pChunks[beforeIdx].freePrevIdx; - SDefragAllocChunk& after = pChunks[afterIdx]; - - chunk.freeNextIdx = after.freeNextIdx; - chunk.freePrevIdx = afterIdx; - pChunks[after.freeNextIdx].freePrevIdx = idx; - after.freeNextIdx = idx; -} - -IDefragAllocator::Hdl CDefragAllocator::Allocate_Locked(size_t sz, size_t alignment, [[maybe_unused]] const char* source, void* pContext) -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - CDBA_ASSERT(sz <= (BIT64(NumBuckets))); -#else - CDBA_ASSERT(sz <= (BIT(NumBuckets))); -#endif - - sz = Align(sz, alignment) >> m_logMinAlignment; - alignment >>= m_logMinAlignment; - - if (sz > m_available) - { - return InvalidHdl; - } - - Index bestChunkIdx = InvalidChunkIdx; - switch (m_policy.blockSearchKind) - { - case eBSK_BestFit: - bestChunkIdx = BestFit_FindFreeBlockFor(sz, alignment, 0, ~(uint32)0, true); - break; - case eBSK_FirstFit: - bestChunkIdx = FirstFit_FindFreeBlockFor(sz, alignment, 0, ~(uint32)0, true); - break; - default: - __debugbreak(); - break; - } - - if (bestChunkIdx != InvalidChunkIdx) - { - SplitResult sr = SplitFreeBlock(bestChunkIdx, sz, alignment, true); - - IF_LIKELY (sr.bSuccessful) - { - SDefragAllocChunk& bestChunk = m_chunks[bestChunkIdx]; - CDBA_ASSERT(bestChunk.attr.GetSize() == sz); - - MarkAsInUse(bestChunk); - bestChunk.pContext = pContext; -#ifndef _RELEASE - bestChunk.source = source; -#endif - bestChunk.attr.SetPinCount(0); - bestChunk.attr.SetMoving(false); - - return ChunkHdlFromIdx(bestChunkIdx); - } - } - - return InvalidHdl; -} - -CDefragAllocator::SplitResult CDefragAllocator::SplitFreeBlock(Index fbId, size_t sz, size_t alignment, bool allocateInLowHalf) -{ - CDefragAllocator::SplitResult res; - res.bSuccessful = false; - res.nLeftSplitChunkIdx = InvalidChunkIdx; - res.nRightSplitChunkIdx = InvalidChunkIdx; - - SDefragAllocChunk* allocChunk = &m_chunks[fbId]; - - CDBA_ASSERT(!allocChunk->attr.IsBusy()); - CDBA_ASSERT(sz <= allocChunk->attr.GetSize()); - - if ((allocChunk->ptr & (alignment - 1)) != 0 || allocChunk->attr.GetSize() != sz) - { - // Determine the sizes of the new chunks - UINT_PTR baseAddress = allocChunk->ptr; - UINT_PTR endAddress = allocChunk->ptr + allocChunk->attr.GetSize(); - UINT_PTR allocAddress = allocateInLowHalf - ? Align(baseAddress, alignment) - : ((endAddress - sz) & ~(alignment - 1)); - UINT_PTR allocEndAddress = allocAddress + sz; - - // Allocate split chunks - Index nLeftSplitChunkIdx = InvalidChunkIdx; - if (baseAddress != allocAddress) - { - nLeftSplitChunkIdx = AllocateChunk(); - if (nLeftSplitChunkIdx == InvalidChunkIdx) - { - return res; - } - } - - Index nRightSplitChunkIdx = InvalidChunkIdx; - if (allocEndAddress != endAddress) - { - nRightSplitChunkIdx = AllocateChunk(); - if (nRightSplitChunkIdx == InvalidChunkIdx) - { - if (nLeftSplitChunkIdx != InvalidChunkIdx) - { - ReleaseChunk(nLeftSplitChunkIdx); - } - return res; - } - } - - // Split - UnlinkFreeChunk(fbId); - - allocChunk = &m_chunks[fbId]; - - if (nLeftSplitChunkIdx != InvalidChunkIdx) - { - SDefragAllocChunk& splitChunk = m_chunks[nLeftSplitChunkIdx]; - - splitChunk.ptr = baseAddress; - splitChunk.attr.SetSize((int)(allocAddress - baseAddress)); - LinkAddrChunk(nLeftSplitChunkIdx, allocChunk->addrPrevIdx); - } - - if (nRightSplitChunkIdx != InvalidChunkIdx) - { - SDefragAllocChunk& splitChunk = m_chunks[nRightSplitChunkIdx]; - - splitChunk.ptr = allocEndAddress; - splitChunk.attr.SetSize((int)(endAddress - allocEndAddress)); - LinkAddrChunk(nRightSplitChunkIdx, fbId); - } - - allocChunk->ptr = allocAddress; - allocChunk->attr.SetSize((int)(allocEndAddress - allocAddress)); - allocChunk->logAlign = IntegerLog2(alignment); - - if (nLeftSplitChunkIdx != InvalidChunkIdx) - { - LinkFreeChunk(nLeftSplitChunkIdx); - } - if (nRightSplitChunkIdx != InvalidChunkIdx) - { - LinkFreeChunk(nRightSplitChunkIdx); - } - - res.bSuccessful = true; - res.nLeftSplitChunkIdx = nLeftSplitChunkIdx; - res.nRightSplitChunkIdx = nRightSplitChunkIdx; - } - else - { - // Perfect fit. - UnlinkFreeChunk(fbId); - - res.bSuccessful = true; - } - -#ifdef CDBA_MORE_DEBUG - ValidateFreeLists(); -#endif - - return res; -} - -CDefragAllocator::Index CDefragAllocator::MergeFreeBlock(Index fbId) -{ - SDefragAllocChunk* pChunks = &m_chunks[0]; - - SDefragAllocChunk* chunk = &pChunks[fbId]; - - CDBA_ASSERT(m_available <= m_capacity); - CDBA_ASSERT(!chunk->attr.IsBusy()); - - LinkFreeChunk(fbId); - - Index prevChunkIdx = chunk->addrPrevIdx; - SDefragAllocChunk& prevChunk = pChunks[prevChunkIdx]; - if (!prevChunk.attr.IsBusy()) - { - // Merge with previous chunk - - UnlinkFreeChunk(fbId); - UnlinkFreeChunk(prevChunkIdx); - - prevChunk.attr.AddSize(chunk->attr.GetSize()); - prevChunk.addrNextIdx = chunk->addrNextIdx; - pChunks[chunk->addrNextIdx].addrPrevIdx = prevChunkIdx; - - CDBA_ASSERT(pChunks[prevChunk.addrPrevIdx].ptr + pChunks[prevChunk.addrPrevIdx].attr.GetSize() == prevChunk.ptr); - CDBA_ASSERT(prevChunk.ptr + prevChunk.attr.GetSize() == pChunks[prevChunk.addrNextIdx].ptr); - CDBA_ASSERT(pChunks[prevChunk.addrPrevIdx].addrNextIdx == prevChunkIdx); - CDBA_ASSERT(pChunks[prevChunk.addrNextIdx].addrPrevIdx == prevChunkIdx); - - LinkFreeChunk(prevChunkIdx); - ReleaseChunk(fbId); - - // Pretend the released chunk is the previous one, so the next merge can happen - - fbId = prevChunkIdx; - chunk = &prevChunk; - } - - Index nextChunkIdx = chunk->addrNextIdx; - SDefragAllocChunk& nextChunk = pChunks[nextChunkIdx]; - if (!nextChunk.attr.IsBusy()) - { - // Merge with next chunk - - UnlinkFreeChunk(fbId); - UnlinkFreeChunk(nextChunkIdx); - - chunk->attr.AddSize(nextChunk.attr.GetSize()); - chunk->addrNextIdx = nextChunk.addrNextIdx; - pChunks[chunk->addrNextIdx].addrPrevIdx = fbId; - - CDBA_ASSERT(pChunks[chunk->addrPrevIdx].ptr + pChunks[chunk->addrPrevIdx].attr.GetSize() == chunk->ptr); - CDBA_ASSERT(chunk->ptr + chunk->attr.GetSize() == pChunks[chunk->addrNextIdx].ptr); - CDBA_ASSERT(pChunks[chunk->addrPrevIdx].addrNextIdx == fbId); - CDBA_ASSERT(pChunks[chunk->addrNextIdx].addrPrevIdx == fbId); - - LinkFreeChunk(fbId); - ReleaseChunk(nextChunkIdx); - } - - return fbId; -} - -#ifdef CDBA_MORE_DEBUG -void CDefragAllocator::Defrag_ValidateFreeBlockIteration() -{ - Index freeLists[NumBuckets]; - size_t numFreeLists = 0; - - { - PrepareMergePopPrev(freeLists); - UINT_PTR addr = (UINT_PTR)-1; - - if (numFreeLists) - { - do - { - size_t list = MergePeekPrevChunk(freeLists); - Index chk = freeLists[list]; - UINT_PTR chkAddr = m_chunks[chk].ptr; - CDBA_ASSERT(chkAddr < addr); - addr = chkAddr; - MergePopPrevChunk(freeLists, list); - } while (numFreeLists > 0); - } - } - { - PrepareMergePopNext(freeLists); - UINT_PTR addr = 0; - - if (numFreeLists) - { - do - { - size_t list = MergePeekNextChunk(freeLists); - Index chk = freeLists[list]; - UINT_PTR chkAddr = m_chunks[chk].ptr; - CDBA_ASSERT(chkAddr > addr); - addr = chkAddr; - MergePopNextChunk(freeLists, list); - } while (numFreeLists > 0); - } - } -} -#endif - -CDefragAllocator::Index CDefragAllocator::BestFit_FindFreeBlockForSegment(size_t sz, size_t alignment, uint32 seg) -{ - SDefragAllocSegment& segment = m_segments[seg]; - return BestFit_FindFreeBlockFor(sz, alignment, segment.address, segment.address + segment.capacity, true); -} - -CDefragAllocator::Index CDefragAllocator::BestFit_FindFreeBlockFor(size_t sz, size_t alignment, [[maybe_unused]] UINT_PTR addressMin, UINT_PTR addressMax, bool allocateInLowHalf) -{ - Index bestChunkIdx = InvalidChunkIdx; - UINT_PTR bestWastage = (UINT_PTR)-1; - - for (int bucket = BucketForSize(sz); (bestChunkIdx == InvalidChunkIdx) && (bucket < NumBuckets); ++bucket) - { - size_t rootIdx = m_freeBuckets[bucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freeNextIdx; idx != rootIdx; idx = m_chunks[idx].freeNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max(1U, chunk.attr.GetSize()) >= (1U << bucket)); - - if (chunk.ptr < addressMax) - { - UINT_PTR chunkStart = chunk.ptr; - UINT_PTR chunkSize = chunk.attr.GetSize(); - UINT_PTR chunkEnd = chunkStart + chunkSize; - UINT_PTR allocStart = allocateInLowHalf - ? Align(chunkStart, alignment) - : ((chunkEnd - sz) & ~(alignment - 1)); - UINT_PTR allocEnd = allocStart + sz; - - if (chunkStart <= allocStart && allocEnd <= chunkEnd) - { - if (allocStart == chunkStart && chunkSize == sz) - { - bestChunkIdx = idx; - bestWastage = 0; - - break; - } - - UINT_PTR wastage = (allocStart - chunkStart) + (chunkEnd - allocEnd); - if (wastage < bestWastage) - { - bestChunkIdx = idx; - bestWastage = wastage; - } - } - } - else - { - break; - } - } - } - - return bestChunkIdx; -} - -CDefragAllocator::Index CDefragAllocator::FirstFit_FindFreeBlockFor(size_t sz, size_t alignment, [[maybe_unused]] UINT_PTR addressMin, UINT_PTR addressMax, bool allocateInLowHalf) -{ - for (int bucket = BucketForSize(sz); bucket < NumBuckets; ++bucket) - { - size_t rootIdx = m_freeBuckets[bucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - for (size_t idx = root.freeNextIdx; idx != rootIdx; idx = m_chunks[idx].freeNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max(1U, chunk.attr.GetSize()) >= (1U << bucket)); - if (chunk.ptr < addressMax) - { - UINT_PTR chunkStart = chunk.ptr; - UINT_PTR chunkSize = chunk.attr.GetSize(); - UINT_PTR chunkEnd = chunkStart + chunkSize; - UINT_PTR allocStart = allocateInLowHalf - ? Align(chunkStart, alignment) - : ((chunkEnd - sz) & ~(alignment - 1)); - UINT_PTR allocEnd = allocStart + sz; - if (chunkStart <= allocStart && allocEnd <= chunkEnd) - { - return idx; - } - } - else - { - break; - } - } - } - return InvalidChunkIdx; -} -size_t CDefragAllocator::Defrag_FindMovesBwd(PendingMove** pMoves, size_t maxMoves, size_t& curAmount, size_t maxAmount) -{ - Index freeLists[NumBuckets]; - - size_t numMoves = 0; - bool bIsLast = true; - - PrepareMergePopPrev(freeLists); - - int nSegmentIdx = (int)m_segments.size() - 1; - - // Try and copy a block from the back to the front - do - { - size_t freeChunkList = MergePeekPrevChunk(freeLists); - if (freeChunkList == (size_t)-1) - { - break; - } - - assert(freeChunkList < sizeof(freeLists) / sizeof(freeLists[0])); - Index freeChunkIdx = freeLists[freeChunkList]; - MergePopPrevChunk(freeLists, freeChunkList); - - // Keep track of the last free block in each segment, by watching free blocks - // crossing segment boundaries. - if (nSegmentIdx >= 0) - { - if (m_chunks[freeChunkIdx].ptr < m_segments[nSegmentIdx].address) - { - bIsLast = true; - --nSegmentIdx; - } - } - - // Don't move free block->next blocks if they're at the end of a segment - they're defragged enough. - // TODO - could allow this (and self moves below) if defragging stalls in a bad state - if (!bIsLast) - { - for (Index candidateIdx = m_chunks[freeChunkIdx].addrNextIdx; freeChunkIdx != InvalidChunkIdx && numMoves < maxMoves && curAmount < maxAmount; ) - { - SDefragAllocChunk& freeChunk = m_chunks[freeChunkIdx]; - SDefragAllocChunk& candidateChunk = m_chunks[candidateIdx]; - SDefragAllocChunkAttr candidateChunkAttr = candidateChunk.attr; - - CDBA_ASSERT(!freeChunk.attr.IsBusy()); - - if (IsMoveableCandidate(candidateChunkAttr, 0xffffffff)) - { -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - size_t candidateChunkAlign = BIT64(candidateChunk.logAlign); -#else - size_t candidateChunkAlign = BIT(candidateChunk.logAlign); -#endif - - // Try and reallocate this chunk. For the time being, assume that it's going to remain in a valid moveable state. - Index dstChunkIdx = Defrag_Bwd_FindFreeBlockFor(candidateChunkAttr.GetSize(), candidateChunkAlign, freeChunk.ptr);// + freeChunk.attr.GetSize()); - - if (dstChunkIdx != InvalidChunkIdx) - { - PendingMove* pPM = AllocPendingMove(); - IF_UNLIKELY (!pPM) - { - return numMoves; - } - - // Found a possible move, so try and mark the chunk as moveable - as long as it's still a valid candidate. - if (TryMarkAsMoving(candidateChunk, 0xffffffff)) - { - // Chunk has been marked as moveable - can now split the dest chunk and set up the move state. - // If the chunk gets pinned in the meantime, it'll sync (through CancelMove) on the allocator lock. - - if (TryScheduleCopy(candidateChunk, m_chunks[dstChunkIdx], pPM, true)) - { - SplitResult sr = SplitFreeBlock(dstChunkIdx, candidateChunkAttr.GetSize(), candidateChunkAlign, true); - CDBA_ASSERT(sr.bSuccessful); - - MergePatchPrevRemove(freeLists, dstChunkIdx); - - if (sr.nRightSplitChunkIdx != InvalidChunkIdx) - { - MergePatchPrevInsert(freeLists, sr.nRightSplitChunkIdx); - } - - pPM->srcChunkIdx = candidateIdx; - pPM->dstChunkIdx = dstChunkIdx; - - // dstChunk is owned by the allocator, so we don't need to be atomic when changing it's state. - SDefragAllocChunk& dstChunk = m_chunks[dstChunkIdx]; - MarkAsInUse(dstChunk); - dstChunk.attr.SetPinCount(1); - - CDBA_ASSERT(sr.nRightSplitChunkIdx == InvalidChunkIdx || (m_chunks[sr.nRightSplitChunkIdx].ptr > dstChunk.ptr)); - CDBA_ASSERT(dstChunk.ptr < candidateChunk.ptr); - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); -#endif - - pMoves[numMoves++] = pPM; - curAmount += dstChunk.attr.GetSize(); - - candidateIdx = m_chunks[candidateIdx].addrNextIdx; - if (dstChunkIdx == freeChunkIdx) - { - freeChunkIdx = sr.nRightSplitChunkIdx; - } - continue; - } - else - { - MarkAsNotMoving(candidateChunk); - } - } - - // Candidate (probably) got pinned whilst finding a free block, or the copy schedule failed. Nevermind - undo what we need to. - FreePendingMove(pPM); - pPM = NULL; - } - } - - break; - } - } - - if (freeChunkIdx != InvalidChunkIdx) - { - for (Index candidateIdx = m_chunks[freeChunkIdx].addrPrevIdx; numMoves < maxMoves && curAmount < maxAmount; ) - { - SDefragAllocChunk& candidateChunk = m_chunks[candidateIdx]; - SDefragAllocChunkAttr candidateChunkAttr = candidateChunk.attr; - - if (IsMoveableCandidate(candidateChunkAttr, 0xffffffff)) - { -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - size_t candidateChunkAlign = BIT64(candidateChunk.logAlign); -#else - size_t candidateChunkAlign = BIT(candidateChunk.logAlign); -#endif - - // Try and reallocate this chunk. For the time being, assume that it's going to remain in a valid moveable state. - Index dstChunkIdx = Defrag_Bwd_FindFreeBlockFor(candidateChunkAttr.GetSize(), candidateChunkAlign, candidateChunk.ptr); - CDBA_ASSERT(dstChunkIdx != freeChunkIdx); - - if (dstChunkIdx != InvalidChunkIdx) - { - PendingMove* pPM = AllocPendingMove(); - IF_UNLIKELY (!pPM) - { - return numMoves; - } - - // Found a possible move, so try and mark the chunk as moveable - as long as it's still a valid candidate. - if (TryMarkAsMoving(candidateChunk, 0xffffffff)) - { - // Chunk has been marked as moveable - can now split the chunk and set up the move state. - // If the chunk gets pinned in the meantime, it'll sync (through CancelMove) on the allocator lock. - - if (TryScheduleCopy(candidateChunk, m_chunks[dstChunkIdx], pPM, true)) - { - SplitResult sr = SplitFreeBlock(dstChunkIdx, candidateChunkAttr.GetSize(), candidateChunkAlign, true); - CDBA_ASSERT(sr.bSuccessful); - - MergePatchPrevRemove(freeLists, dstChunkIdx); - - if (sr.nRightSplitChunkIdx != InvalidChunkIdx) - { - MergePatchPrevInsert(freeLists, sr.nRightSplitChunkIdx); - } - - pPM->srcChunkIdx = candidateIdx; - pPM->dstChunkIdx = dstChunkIdx; - - // dstChunk is owned by the allocator, so don't need to be atomic when changing it's state. - SDefragAllocChunk& dstChunk = m_chunks[dstChunkIdx]; - MarkAsInUse(dstChunk); - dstChunk.attr.SetPinCount(1); - - CDBA_ASSERT(sr.nRightSplitChunkIdx == InvalidChunkIdx || (m_chunks[sr.nRightSplitChunkIdx].ptr > dstChunk.ptr)); - CDBA_ASSERT(dstChunk.ptr < candidateChunk.ptr); - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); -#endif - - pMoves[numMoves++] = pPM; - curAmount += dstChunk.attr.GetSize(); - - candidateIdx = m_chunks[candidateIdx].addrPrevIdx; - continue; - } - else - { - MarkAsNotMoving(candidateChunk); - } - } - - // Candidate (probably) got pinned whilst finding a free block, or the copy schedule failed. Nevermind - undo what we need to. - FreePendingMove(pPM); - pPM = NULL; - } - } - - break; - } - } - bIsLast = false; - } - while (numMoves < maxMoves); - - return numMoves; -} - -size_t CDefragAllocator::Defrag_FindMovesFwd(PendingMove** pMoves, size_t maxMoves, size_t& curAmount, size_t maxAmount) -{ - Index freeLists[NumBuckets]; - - size_t numMoves = 0; - - PrepareMergePopNext(freeLists); - - // Try and copy a block from the front to the back - do - { - size_t freeChunkList = MergePeekNextChunk(freeLists); - if (freeChunkList == (size_t)-1) - { - break; - } - - assert(freeChunkList < sizeof(freeLists) / sizeof(freeLists[0])); - - Index freeChunkIdx = freeLists[freeChunkList]; - MergePopNextChunk(freeLists, freeChunkList); - - CDBA_ASSERT(!m_chunks[freeChunkIdx].attr.IsBusy()); - - for (Index candidateIdx = m_chunks[freeChunkIdx].addrNextIdx; numMoves < maxMoves && curAmount < maxAmount; ) - { - SDefragAllocChunk& freeChunk = m_chunks[freeChunkIdx]; - SDefragAllocChunk& candidateChunk = m_chunks[candidateIdx]; - SDefragAllocChunkAttr candidateChunkAttr = candidateChunk.attr; - - if (IsMoveableCandidate(candidateChunkAttr, 0xffffffff)) - { -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - size_t candidateChunkAlign = BIT64(candidateChunk.logAlign); -#else - size_t candidateChunkAlign = BIT(candidateChunk.logAlign); -#endif - - // Try and reallocate this chunk. For the time being, assume that it's going to remain in a valid moveable state. - Index dstChunkIdx = Defrag_Fwd_FindFreeBlockFor(candidateChunkAttr.GetSize(), candidateChunkAlign, freeChunk.ptr + freeChunk.attr.GetSize()); - - CDBA_ASSERT(dstChunkIdx != freeChunkIdx); - - if (dstChunkIdx != InvalidChunkIdx) - { - PendingMove* pPM = AllocPendingMove(); - IF_UNLIKELY (!pPM) - { - return numMoves; - } - - CDBA_ASSERT(!m_chunks[dstChunkIdx].attr.IsBusy()); - CDBA_ASSERT(m_chunks[dstChunkIdx].attr.GetSize() >= candidateChunkAttr.GetSize()); - - // Found a possible move, so try and mark the chunk as moveable - as long as it's still a valid candidate. - if (TryMarkAsMoving(candidateChunk, 0xffffffff)) - { - // Chunk has been marked as moveable - can now split the dest chunk and set up the move state. - // If the chunk gets pinned in the meantime, it'll sync (through CancelMove) on the allocator lock. - - if (TryScheduleCopy(candidateChunk, m_chunks[dstChunkIdx], pPM, false)) - { - SplitResult sr = SplitFreeBlock(dstChunkIdx, candidateChunkAttr.GetSize(), candidateChunkAlign, false); - CDBA_ASSERT(sr.bSuccessful); - - MergePatchNextRemove(freeLists, dstChunkIdx); - - if (sr.nLeftSplitChunkIdx != InvalidChunkIdx) - { - MergePatchNextInsert(freeLists, sr.nLeftSplitChunkIdx); - } - - pPM->srcChunkIdx = candidateIdx; - pPM->dstChunkIdx = dstChunkIdx; - - // dstChunk is owned by the allocator, so we don't need to be atomic when changing it's state. - SDefragAllocChunk& dstChunk = m_chunks[dstChunkIdx]; - MarkAsInUse(dstChunk); - dstChunk.attr.SetPinCount(1); - - CDBA_ASSERT(sr.nLeftSplitChunkIdx == InvalidChunkIdx || (m_chunks[sr.nLeftSplitChunkIdx].ptr < dstChunk.ptr)); - CDBA_ASSERT(dstChunk.ptr > candidateChunk.ptr); - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); -#endif - - pMoves[numMoves++] = pPM; - curAmount += dstChunk.attr.GetSize(); - - candidateIdx = m_chunks[candidateIdx].addrNextIdx; - continue; - } - else - { - MarkAsNotMoving(candidateChunk); - } - } - - // Candidate (probably) got pinned whilst finding a free block, or the copy schedule failed. Nevermind - undo what we need to. - FreePendingMove(pPM); - pPM = NULL; - } - } - - break; - } - } - while (numMoves < maxMoves); - - return numMoves; -} - -bool CDefragAllocator::Defrag_CompletePendingMoves() -{ - CDBA_ASSERT(m_policy.pDefragPolicy); - - bool bHasMoves = false; - - for (DynArray::iterator it = m_pendingMoves.begin(), itEnd = m_pendingMoves.end(); it != itEnd; ++it) - { - if (it->notify.bCancel) - { - // Currently only support cancelling before a move has really begun - // Also assume that there is no copy in flight - the policy has requested it, so it's their responsibility to - // make sure that this is the case - CDBA_ASSERT(!it->relocated); - - MarkAsFree(m_chunks[it->dstChunkIdx]); - MergeFreeBlock(it->dstChunkIdx); - - MarkAsNotMoving(m_chunks[it->srcChunkIdx]); - - FreePendingMove(&*it); - } - else - { - if (it->notify.bDstIsValid) - { - if (!it->relocated) - { - CDBA_ASSERT(it->dstChunkIdx != InvalidChunkIdx); - - if (!it->cancelled) - { - Relocate(it->userMoveId, it->srcChunkIdx, it->dstChunkIdx); - } - - it->relocated = true; - } - - if (it->notify.bSrcIsUnneeded) - { - SDefragAllocChunk& dst = m_chunks[it->dstChunkIdx]; - MarkAsFree(dst); - MergeFreeBlock(it->dstChunkIdx); - - if (!it->cancelled) - { - CDBA_ASSERT(it->srcChunkIdx != InvalidChunkIdx); - - SDefragAllocChunk& src = m_chunks[it->srcChunkIdx]; - - // Should be the last thing to occur during move - MarkAsNotMoving(src); - } - else - { - // Only the destination chunk is now valid - just free it. - CDBA_ASSERT(it->srcChunkIdx == InvalidChunkIdx); - } - - FreePendingMove(&*it); - } - } - - if (it->dstChunkIdx != InvalidChunkIdx) - { - bHasMoves = true; - } - } - } - - return bHasMoves; -} - -CDefragAllocator::Index CDefragAllocator::Defrag_Bwd_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressLimit) -{ - Index bestChunkIdx = InvalidChunkIdx; - UINT_PTR maxAddress = addressLimit; - - int minBucket = BucketForSize(sz); - - // Search for an exact fit - { - size_t rootIdx = m_freeBuckets[minBucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freeNextIdx; idx != rootIdx; idx = m_chunks[idx].freeNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << minBucket)); - - UINT_PTR chunkBase = chunk.ptr; - UINT_PTR chunkEnd = chunkBase + chunk.attr.GetSize(); - UINT_PTR allocBase = Align(chunkBase, alignment); - UINT_PTR allocEnd = allocBase + sz; - - if (chunk.ptr < maxAddress) - { - if (chunkBase == allocBase && chunkEnd == allocEnd) - { - bestChunkIdx = idx; - maxAddress = chunk.ptr; - break; - } - } - else - { - break; - } - } - } - - for (size_t bucket = minBucket; (bestChunkIdx == InvalidChunkIdx) && (bucket < NumBuckets); ++bucket) - { - size_t rootIdx = m_freeBuckets[bucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freeNextIdx; idx != rootIdx; idx = m_chunks[idx].freeNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << bucket)); - - UINT_PTR chunkBase = chunk.ptr; - UINT_PTR chunkEnd = chunkBase + chunk.attr.GetSize(); - UINT_PTR allocBase = Align(chunkBase, alignment); - UINT_PTR allocEnd = allocBase + sz; - - if (allocEnd <= maxAddress) - { - if (chunkBase <= allocBase && allocEnd <= chunkEnd) - { - bestChunkIdx = idx; - maxAddress = chunkBase; - break; - } - } - else - { - // Chunks are ordered by address. If the maxAddress has been exceeded, there's no point in searching the rest of the list. - break; - } - } - } - - return bestChunkIdx; -} - -CDefragAllocator::Index CDefragAllocator::Defrag_Fwd_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressLimit) -{ - Index bestChunkIdx = InvalidChunkIdx; - UINT_PTR minAddress = addressLimit; - - int minBucket = BucketForSize(sz); - - // Search for an exact fit - { - size_t rootIdx = m_freeBuckets[minBucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freePrevIdx; idx != rootIdx; idx = m_chunks[idx].freePrevIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << minBucket)); - - UINT_PTR chunkBase = chunk.ptr; - UINT_PTR chunkEnd = chunkBase + chunk.attr.GetSize(); - UINT_PTR allocBase = (chunkEnd - sz) & ~(alignment - 1); - UINT_PTR allocEnd = allocBase + sz; - - if (chunkBase >= minAddress) - { - if (allocBase == chunkBase && allocEnd == chunkEnd) - { - bestChunkIdx = idx; - minAddress = chunk.ptr; - break; - } - } - else - { - break; - } - } - } - - for (size_t bucket = minBucket; (bestChunkIdx == InvalidChunkIdx) && (bucket < NumBuckets); ++bucket) - { - size_t rootIdx = m_freeBuckets[bucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freePrevIdx; idx != rootIdx; idx = m_chunks[idx].freePrevIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << bucket)); - - UINT_PTR chunkBase = chunk.ptr; - UINT_PTR chunkEnd = chunkBase + chunk.attr.GetSize(); - UINT_PTR allocBase = (chunkEnd - sz) & ~(alignment - 1); - UINT_PTR allocEnd = allocBase + sz; - - if (chunkBase > minAddress) - { - if (chunkBase <= allocBase && allocEnd <= chunkEnd) - { - bestChunkIdx = idx; - minAddress = chunkBase; - break; - } - } - else - { - // Chunks are ordered by address. If the minAddress has been exceeded, there's no point in searching the rest of the list. - break; - } - } - } - - return bestChunkIdx; -} - -CDefragAllocator::PendingMove* CDefragAllocator::AllocPendingMove() -{ - // Naive - just search for a free slot. - for (PendingMoveVec::iterator it = m_pendingMoves.begin(), itEnd = m_pendingMoves.end(); it != itEnd; ++it) - { - if (it->dstChunkIdx == InvalidChunkIdx) - { - return &*it; - } - } - - return NULL; -} - -void CDefragAllocator::FreePendingMove(PendingMove* pMove) -{ - stl::reconstruct(*pMove); -} - -void CDefragAllocator::CancelMove(Index srcChunkIdx, bool bIsContentNeeded) -{ - CryOptionalAutoLock lock(m_lock, m_isThreadSafe); - CancelMove_Locked(srcChunkIdx, bIsContentNeeded); -} - -void CDefragAllocator::CancelMove_Locked(Index srcChunkIdx, [[maybe_unused]] bool bIsContentNeeded) -{ - SDefragAllocChunk* pChunk = &m_chunks[srcChunkIdx]; - - // In theory CancelMove could get called twice for the same chunk - make sure that - // redundant cancels are ignored - if (pChunk->attr.IsMoving()) - { - // Chunk is being moved. Find the job responsible and cancel it (if it's not complete). - PendingMoveVec::iterator it = std::find_if(m_pendingMoves.begin(), m_pendingMoves.end(), PendingMoveSrcChunkPredicate(srcChunkIdx)); - CDBA_ASSERT(it != m_pendingMoves.end()); - CDBA_ASSERT(it->srcChunkIdx != InvalidChunkIdx); - - if (it->notify.bDstIsValid && it->notify.bSrcIsUnneeded) - { - // Chunk has actually completed, just not finalised. Discard the destination chunk. - MarkAsFree(m_chunks[it->dstChunkIdx]); - MergeFreeBlock(it->dstChunkIdx); - FreePendingMove(&*it); - } - else - { - // Chunk is still in flight. - - // If the content is important, then we can either cancel the copy (if not overlapped), or - // sync and wait for it complete. TODO. - - m_policy.pDefragPolicy->CancelCopy(it->userMoveId, pChunk->pContext, false); - it->srcChunkIdx = InvalidChunkIdx; - it->cancelled = true; - } - - MarkAsNotMoving(*pChunk); - ++m_nCancelledMoves; - } -} - -void CDefragAllocator::Relocate(uint32 userMoveId, Index srcChunkIdx, Index dstChunkIdx) -{ - using std::swap; - - SDefragAllocChunk* pChunks = &m_chunks[0]; - uint32 logAlignment = m_logMinAlignment; - - SDefragAllocChunk& src = pChunks[srcChunkIdx]; - SDefragAllocChunk& dst = pChunks[dstChunkIdx]; - SDefragAllocChunkAttr srcAttr = src.attr; - SDefragAllocChunkAttr dstAttr = dst.attr; - - CDBA_ASSERT(srcAttr.IsMoving()); - CDBA_ASSERT(dstAttr.IsPinned()); - CDBA_ASSERT(!dstAttr.IsMoving()); - CDBA_ASSERT(srcAttr.GetSize() == dstAttr.GetSize()); - - UINT_PTR oldPtr = src.ptr; - UINT_PTR newPtr = dst.ptr; - - // src and dst are linked in the addr chain only - src needs to move where dst is (so user handles remain consistent) - // and the src block be freed. - - SDefragAllocChunk* pA = &dst; - SDefragAllocChunk* pB = &src; - - CDBA_ASSERT(pChunks[pA->addrPrevIdx].ptr + pChunks[pA->addrPrevIdx].attr.GetSize() == pA->ptr); - CDBA_ASSERT(pA->ptr + pA->attr.GetSize() == pChunks[pA->addrNextIdx].ptr); - CDBA_ASSERT(pChunks[pB->addrPrevIdx].ptr + pChunks[pB->addrPrevIdx].attr.GetSize() == pB->ptr); - CDBA_ASSERT(pB->ptr + pB->attr.GetSize() == pChunks[pB->addrNextIdx].ptr); - CDBA_ASSERT(&pChunks[pChunks[pA->addrNextIdx].addrPrevIdx] == pA); - CDBA_ASSERT(&pChunks[pChunks[pA->addrPrevIdx].addrNextIdx] == pA); - CDBA_ASSERT(&pChunks[pChunks[pB->addrNextIdx].addrPrevIdx] == pB); - CDBA_ASSERT(&pChunks[pChunks[pB->addrPrevIdx].addrNextIdx] == pB); - - Index nA = dstChunkIdx; - Index nB = srcChunkIdx; - - if (pA->addrNextIdx == nB) - { - // Neighbours - pB->addrPrevIdx = pA->addrPrevIdx; - pA->addrNextIdx = pB->addrNextIdx; - pA->addrPrevIdx = nB; - pB->addrNextIdx = nA; - pChunks[pB->addrPrevIdx].addrNextIdx = nB; - pChunks[pA->addrNextIdx].addrPrevIdx = nA; - } - else if (pA->addrPrevIdx == nB) - { - // Neighbours - pB->addrNextIdx = pA->addrNextIdx; - pA->addrPrevIdx = pB->addrPrevIdx; - pB->addrPrevIdx = nA; - pA->addrNextIdx = nB; - pChunks[pA->addrPrevIdx].addrNextIdx = nA; - pChunks[pB->addrNextIdx].addrPrevIdx = nB; - } - else - { - swap(pB->addrNextIdx, pA->addrNextIdx); - swap(pA->addrPrevIdx, pB->addrPrevIdx); - pChunks[pA->addrPrevIdx].addrNextIdx = nA; - pChunks[pA->addrNextIdx].addrPrevIdx = nA; - pChunks[pB->addrNextIdx].addrPrevIdx = nB; - pChunks[pB->addrPrevIdx].addrNextIdx = nB; - } - - swap(src.packedPtr, dst.packedPtr); - -#ifdef CDBA_MORE_DEBUG - ValidateAddressChain(); -#endif - - CDBA_ASSERT(pChunks[pA->addrPrevIdx].ptr + pChunks[pA->addrPrevIdx].attr.GetSize() == pA->ptr); - CDBA_ASSERT(pA->ptr + pA->attr.GetSize() == pChunks[pA->addrNextIdx].ptr); - CDBA_ASSERT(pChunks[pB->addrPrevIdx].ptr + pChunks[pB->addrPrevIdx].attr.GetSize() == pB->ptr); - CDBA_ASSERT(pB->ptr + pB->attr.GetSize() == pChunks[pB->addrNextIdx].ptr); - CDBA_ASSERT(&pChunks[pChunks[pA->addrNextIdx].addrPrevIdx] == pA); - CDBA_ASSERT(&pChunks[pChunks[pA->addrPrevIdx].addrNextIdx] == pA); - CDBA_ASSERT(&pChunks[pChunks[pB->addrNextIdx].addrPrevIdx] == pB); - CDBA_ASSERT(&pChunks[pChunks[pB->addrPrevIdx].addrNextIdx] == pB); - - if (userMoveId != IDefragAllocatorPolicy::InvalidUserMoveId) - { - m_policy.pDefragPolicy->Relocate(userMoveId, src.pContext, newPtr << logAlignment, oldPtr << logAlignment, (UINT_PTR)srcAttr.GetSize() << logAlignment); - } -} - -void CDefragAllocator::SyncMoveSegment(uint32 seg) -{ - SDefragAllocSegment& segment = m_segments[seg]; - SDefragAllocChunk& headSentinalChunk = m_chunks[segment.headSentinalChunkIdx]; - - // Assert that the segment is empty. - uint32 endAddress = segment.address + segment.capacity; - - Index chunkIdx = headSentinalChunk.addrNextIdx; - SDefragAllocChunk* pChunk = &m_chunks[chunkIdx]; - - int numValidSegs = seg; - - while (pChunk->ptr != endAddress) - { - if (pChunk->attr.IsBusy()) - { - CDBA_ASSERT(!pChunk->attr.IsMoving()); - CDBA_ASSERT(!pChunk->attr.IsPinned()); - CDBA_ASSERT(m_policy.pDefragPolicy != NULL); - -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - size_t chunkAlign = BIT64(pChunk->logAlign); -#else - size_t chunkAlign = BIT(pChunk->logAlign); -#endif - - // Try and synchronously move the allocation - Index destinationChunkIdx = InvalidChunkIdx; - for (int segIdx = 0; destinationChunkIdx == InvalidChunkIdx && segIdx < numValidSegs; ++segIdx) - { - destinationChunkIdx = BestFit_FindFreeBlockForSegment(pChunk->attr.GetSize(), chunkAlign, segIdx); - } - - CDBA_ASSERT(destinationChunkIdx != InvalidChunkIdx); - - SplitResult sr = SplitFreeBlock(destinationChunkIdx, pChunk->attr.GetSize(), chunkAlign, true); - CDBA_ASSERT(sr.bSuccessful); - - SDefragAllocChunk& destinationChunk = m_chunks[destinationChunkIdx]; - MarkAsInUse(destinationChunk); - - Pin(ChunkHdlFromIdx(destinationChunkIdx)); - MarkAsMoving(*pChunk); - - m_policy.pDefragPolicy->SyncCopy(pChunk->pContext, destinationChunk.ptr << m_logMinAlignment, pChunk->ptr << m_logMinAlignment, (UINT_PTR)pChunk->attr.GetSize() << m_logMinAlignment); - Relocate(IDefragAllocatorPolicy::InvalidUserMoveId, chunkIdx, destinationChunkIdx); - - MarkAsNotMoving(*pChunk); - Unpin(ChunkHdlFromIdx(destinationChunkIdx)); - - MarkAsFree(destinationChunk); - destinationChunkIdx = MergeFreeBlock(destinationChunkIdx); - pChunk = &m_chunks[destinationChunkIdx]; - } - - chunkIdx = pChunk->addrNextIdx; - pChunk = &m_chunks[chunkIdx]; - } -} - -void CDefragAllocator::RebuildFreeLists() -{ - for (int bi = 0; bi < NumBuckets; ++bi) - { - Index ci = m_freeBuckets[bi]; - m_chunks[ci].freeNextIdx = ci; - m_chunks[ci].freePrevIdx = ci; - } - - for (Index ci = m_chunks[AddrStartSentinal].addrNextIdx; ci != AddrEndSentinal; ci = m_chunks[ci].addrNextIdx) - { - SDefragAllocChunk& ch = m_chunks[ci]; - if (!ch.attr.IsBusy()) - { - LinkFreeChunk(ci); - } - } - -#ifdef CDBA_MORE_DEBUG - ValidateFreeLists(); -#endif -} - -void CDefragAllocator::ValidateAddressChain() -{ - UINT_PTR p = 0; - - Index hdr = 0; - for (Index ci = m_chunks[hdr].addrNextIdx; ci != hdr; ) - { - SDefragAllocChunk& c = m_chunks[ci]; - - CDBA_ASSERT(p == c.ptr); - p += c.attr.GetSize(); - - ci = c.addrNextIdx; - } - - for (int bi = 0; bi < NumBuckets; ++bi) - { - hdr = m_freeBuckets[bi]; - - for (Index ci = m_chunks[hdr].freeNextIdx; ci != hdr; ) - { - SDefragAllocChunk& c = m_chunks[ci]; - - CDBA_ASSERT(!c.attr.IsBusy()); - - ci = c.freeNextIdx; - } - } -} - -void CDefragAllocator::ValidateFreeLists() -{ -#if defined(CDBA_DEBUG) - for (size_t bucket = 0; bucket < NumBuckets; ++bucket) - { - size_t rootIdx = m_freeBuckets[bucket]; - SDefragAllocChunk& root = m_chunks[rootIdx]; - - for (size_t idx = root.freeNextIdx; idx != rootIdx; idx = m_chunks[idx].freeNextIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << bucket)); - CDBA_ASSERT(idx >= NumBuckets + 2); - - CDBA_ASSERT(m_chunks[chunk.freeNextIdx].freePrevIdx == idx); - CDBA_ASSERT(m_chunks[chunk.freePrevIdx].freeNextIdx == idx); - } - - for (size_t idx = root.freePrevIdx; idx != rootIdx; idx = m_chunks[idx].freePrevIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - - CDBA_ASSERT(!chunk.attr.IsBusy()); - CDBA_ASSERT(max((uint32)1, (uint32)chunk.attr.GetSize()) >= (1U << bucket)); - CDBA_ASSERT(idx >= NumBuckets + 2); - - CDBA_ASSERT(m_chunks[chunk.freeNextIdx].freePrevIdx == idx); - CDBA_ASSERT(m_chunks[chunk.freePrevIdx].freeNextIdx == idx); - } - } -#endif -} diff --git a/Code/CryEngine/CrySystem/DefragAllocator.h b/Code/CryEngine/CrySystem/DefragAllocator.h deleted file mode 100644 index 183b10bb7f..0000000000 --- a/Code/CryEngine/CrySystem/DefragAllocator.h +++ /dev/null @@ -1,712 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_DEFRAGALLOCATOR_H -#define CRYINCLUDE_CRYSYSTEM_DEFRAGALLOCATOR_H -#pragma once - - -#include "IDefragAllocator.h" - -#include "System.h" - -#ifndef _RELEASE -#define CDBA_DEBUG -#endif - -//#define CDBA_MORE_DEBUG - -#ifdef CDBA_DEBUG -#define CDBA_ASSERT(x) do { assert(x); if (!(x)) {__debugbreak(); } \ -} while (0) -#else -#define CDBA_ASSERT(x) assert(x) -#endif - -union SDefragAllocChunkAttr -{ - enum - { - SizeWidth = 27, - SizeMask = (1 << SizeWidth) - 1, - BusyMask = 1 << 27, - MovingMask = 1 << 28, - MaxPinCount = 7, - PinnedCountShift = 29, - PinnedIncMask = 1 << PinnedCountShift, - PinnedCountMask = MaxPinCount << PinnedCountShift, - }; - - uint32 ui; - - ILINE unsigned int GetSize() const { return ui & SizeMask; } - ILINE void SetSize(unsigned int size) { ui = (ui & ~SizeMask) | size; } - ILINE void AddSize(int size) { ui += size; } - ILINE bool IsBusy() const { return (ui & BusyMask) != 0; } - ILINE void SetBusy(bool b) { ui = b ? (ui | BusyMask) : (ui & ~BusyMask); } - ILINE bool IsMoving() const { return (ui & MovingMask) != 0; } - ILINE void SetMoving(bool m) { ui = m ? (ui | MovingMask) : (ui & ~MovingMask); } - ILINE void IncPinCount() { ui += PinnedIncMask; } - ILINE void DecPinCount() { ui -= PinnedIncMask; } - ILINE bool IsPinned() const { return (ui & PinnedCountMask) != 0; } - ILINE unsigned int GetPinCount() const { return (ui & PinnedCountMask) >> PinnedCountShift; } - ILINE void SetPinCount(unsigned int p) { ui = (ui & ~PinnedCountMask) | (p << PinnedCountShift); } -}; - -struct SDefragAllocChunk -{ - enum - { - AlignBitCount = 4, - }; - typedef IDefragAllocator::Hdl Index; - - Index addrPrevIdx; - Index addrNextIdx; - - union - { - struct - { - UINT_PTR ptr : sizeof(UINT_PTR) * 8 - AlignBitCount; - UINT_PTR logAlign: AlignBitCount; - }; - UINT_PTR packedPtr; - }; - SDefragAllocChunkAttr attr; - - union - { - void* pContext; - struct - { - Index freePrevIdx; - Index freeNextIdx; - }; - }; - -#ifndef _RELEASE - const char* source; -#endif - - void SwapEndian() - { - ::SwapEndian(addrPrevIdx, true); - ::SwapEndian(addrNextIdx, true); - ::SwapEndian(packedPtr, true); - ::SwapEndian(attr.ui, true); - - if (attr.IsBusy()) - { - ::SwapEndian(pContext, true); - } - else - { - ::SwapEndian(freePrevIdx, true); - ::SwapEndian(freeNextIdx, true); - } - -#ifndef _RELEASE - ::SwapEndian(source, true); -#endif - } -}; - -struct SDefragAllocSegment -{ - uint32 address; - uint32 capacity; - SDefragAllocChunk::Index headSentinalChunkIdx; - - void SwapEndian() - { - ::SwapEndian(address, true); - ::SwapEndian(capacity, true); - ::SwapEndian(headSentinalChunkIdx, true); - } -}; - -class CDefragAllocator; - -class CDefragAllocatorWalker -{ -public: - explicit CDefragAllocatorWalker(CDefragAllocator& alloc); - ~CDefragAllocatorWalker(); - - const SDefragAllocChunk* Next(); - -private: - CDefragAllocatorWalker(const CDefragAllocatorWalker&); - CDefragAllocatorWalker& operator = (const CDefragAllocatorWalker&); - -private: - CDefragAllocator* m_pAlloc; - SDefragAllocChunk::Index m_nChunkIdx; -}; - -class CDefragAllocator - : public IDefragAllocator -{ - friend class CDefragAllocatorWalker; - typedef SDefragAllocChunk::Index Index; - -public: - CDefragAllocator(); - - void Release(bool bDiscard); - - void Init(UINT_PTR capacity, UINT_PTR minAlignment, const Policy& policy); - -#ifndef _RELEASE - void DumpState(const char* filename); - void RestoreState(const char* filename); -#endif - - // allocatorDisplayOffset will offset the statistics for the allocator depending on the index. - // 0 means no offset and default location, 1 means bar will be rendered above the 0th bar and stats to the right of the 0th stats - void DisplayMemoryUsage(const char* title, unsigned int allocatorDisplayOffset = 0); - - bool AppendSegment(UINT_PTR capacity); - void UnAppendSegment(); - - Hdl Allocate(size_t sz, const char* source, void* pContext = NULL); - Hdl AllocateAligned(size_t sz, size_t alignment, const char* source, void* pContext = NULL); - AllocatePinnedResult AllocatePinned(size_t sz, const char* source, void* pContext = NULL); - bool Free(Hdl hdl); - - void ChangeContext(Hdl hdl, void* pNewContext); - - size_t GetAllocated() const { return (size_t)(m_capacity - m_available) << m_logMinAlignment; } - IDefragAllocatorStats GetStats(); - - size_t DefragmentTick(size_t maxMoves, size_t maxAmount, bool bForce); - - ILINE UINT_PTR UsableSize(Hdl hdl) - { - Index chunkIdx = ChunkIdxFromHdl(hdl); - CDBA_ASSERT(chunkIdx < m_chunks.size()); - - SDefragAllocChunk& chunk = m_chunks[chunkIdx]; - SDefragAllocChunkAttr attr = chunk.attr; - - CDBA_ASSERT(attr.IsBusy()); - return (UINT_PTR)attr.GetSize() << m_logMinAlignment; - } - - // Pin the chunk until the next defrag tick, when it will be automatically unpinned - ILINE UINT_PTR WeakPin(Hdl hdl) - { - Index chunkIdx = ChunkIdxFromHdl(hdl); - CDBA_ASSERT(chunkIdx < m_chunks.size()); - - SDefragAllocChunk& chunk = m_chunks[chunkIdx]; - SDefragAllocChunkAttr attr = chunk.attr; - CDBA_ASSERT(attr.IsBusy()); - - if (attr.IsMoving()) - { - CancelMove(chunkIdx, true); - } - - return chunk.ptr << m_logMinAlignment; - } - - // Pin the chunk until Unpin is called - ILINE UINT_PTR Pin(Hdl hdl) - { - Index chunkIdx = ChunkIdxFromHdl(hdl); - - SDefragAllocChunk& chunk = m_chunks[chunkIdx]; - SDefragAllocChunkAttr attr; - SDefragAllocChunkAttr newAttr; - - do - { - attr.ui = const_cast(chunk.attr.ui); - newAttr.ui = attr.ui; - - CDBA_ASSERT(attr.GetPinCount() < SDefragAllocChunkAttr::MaxPinCount); - CDBA_ASSERT(attr.IsBusy()); - - newAttr.IncPinCount(); - } - while (CryInterlockedCompareExchange(alias_cast(&chunk.attr.ui), newAttr.ui, attr.ui) != attr.ui); - - // Potentially a Relocate could be in progress here. Either the Relocate is mid-way, in which case 'IsMoving()' will - // still be set, and CancelMove will sync and all is well. - - // If 'IsMoving()' is not set, the Relocate should have just completed, in which case ptr should validly point - // to the new location. - - if (attr.IsMoving()) - { - CancelMove(chunkIdx, true); - } - - return chunk.ptr << m_logMinAlignment; - } - - ILINE void Unpin(Hdl hdl) - { - SDefragAllocChunk& chunk = m_chunks[ChunkIdxFromHdl(hdl)]; - SDefragAllocChunkAttr attr; - SDefragAllocChunkAttr newAttr; - do - { - attr.ui = const_cast(chunk.attr.ui); - newAttr.ui = attr.ui; - - CDBA_ASSERT(attr.IsPinned()); - CDBA_ASSERT(attr.IsBusy()); - - newAttr.DecPinCount(); - } - while (CryInterlockedCompareExchange(alias_cast(&chunk.attr.ui), newAttr.ui, attr.ui) != attr.ui); - } - - ILINE const char* GetSourceOf([[maybe_unused]] Hdl hdl) - { -#ifndef _RELEASE - return m_chunks[ChunkIdxFromHdl(hdl)].source; -#else - return ""; -#endif - } - -private: - enum - { - NumBuckets = 31, // 2GB - MaxPendingMoves = 64, - - AddrStartSentinal = 0, - AddrEndSentinal = 1, - }; - - struct SplitResult - { - bool bSuccessful; - Index nLeftSplitChunkIdx; - Index nRightSplitChunkIdx; - }; - - struct PendingMove - { - PendingMove() - : srcChunkIdx(InvalidChunkIdx) - , dstChunkIdx(InvalidChunkIdx) - , userMoveId(0) - , relocated(false) - , cancelled(false) - { - } - - Index srcChunkIdx; - Index dstChunkIdx; - uint32 userMoveId; - IDefragAllocatorCopyNotification notify; - bool relocated; - bool cancelled; - - void SwapEndian() - { - ::SwapEndian(srcChunkIdx, true); - ::SwapEndian(dstChunkIdx, true); - ::SwapEndian(userMoveId, true); - } - }; - - struct PendingMoveSrcChunkPredicate - { - PendingMoveSrcChunkPredicate(Index ci) - : m_ci(ci) {} - bool operator () (const PendingMove& pm) const { return pm.srcChunkIdx == m_ci; } - Index m_ci; - }; - - typedef DynArray PendingMoveVec; - typedef std::vector SegmentVec; - - static const Index InvalidChunkIdx = (Index) - 1; - -private: - static ILINE Index ChunkIdxFromHdl(Hdl id) { return id - 1; } - static ILINE Hdl ChunkHdlFromIdx(Index idx) { return idx + 1; } - -private: - ~CDefragAllocator(); - - Index AllocateChunk(); - void ReleaseChunk(Index idx); - - ILINE void MarkAsInUse(SDefragAllocChunk& chunk) - { - CDBA_ASSERT(!chunk.attr.IsBusy()); - - chunk.attr.SetBusy(true); - m_available -= chunk.attr.GetSize(); - ++m_numAllocs; - - // m_available is unsigned, so check for underflow - CDBA_ASSERT(m_available <= m_capacity); - } - - ILINE void MarkAsFree(SDefragAllocChunk& chunk) - { - CDBA_ASSERT(chunk.attr.IsBusy()); - - chunk.attr.SetPinCount(0); - chunk.attr.SetMoving(false); - chunk.attr.SetBusy(0); - m_available += chunk.attr.GetSize(); - --m_numAllocs; - - // m_available is unsigned, so check for underflow - CDBA_ASSERT(m_available <= m_capacity); - } - - void LinkFreeChunk(Index idx); - void UnlinkFreeChunk(Index idx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - m_chunks[chunk.freePrevIdx].freeNextIdx = chunk.freeNextIdx; - m_chunks[chunk.freeNextIdx].freePrevIdx = chunk.freePrevIdx; - } - - void LinkAddrChunk(Index idx, Index afterIdx) - { - SDefragAllocChunk& chunk = m_chunks[idx]; - SDefragAllocChunk& afterChunk = m_chunks[afterIdx]; - - chunk.addrNextIdx = afterChunk.addrNextIdx; - chunk.addrPrevIdx = afterIdx; - m_chunks[chunk.addrNextIdx].addrPrevIdx = idx; - afterChunk.addrNextIdx = idx; - } - - void UnlinkAddrChunk(Index id) - { - SDefragAllocChunk& chunk = m_chunks[id]; - - m_chunks[chunk.addrPrevIdx].addrNextIdx = chunk.addrNextIdx; - m_chunks[chunk.addrNextIdx].addrPrevIdx = chunk.addrPrevIdx; - } - - void PrepareMergePopNext(Index* pLists) - { - for (int bucketIdx = 0; bucketIdx < NumBuckets; ++bucketIdx) - { - Index hdrChunkId = m_freeBuckets[bucketIdx]; - Index nextId = m_chunks[hdrChunkId].freeNextIdx; - if (nextId != hdrChunkId) - { - pLists[bucketIdx] = nextId; - } - else - { - pLists[bucketIdx] = InvalidChunkIdx; - } - } - } - - size_t MergePeekNextChunk(Index* pLists) - { - size_t farList = (size_t)-1; - UINT_PTR farPtr = (UINT_PTR)-1; - - for (size_t listIdx = 0; listIdx < NumBuckets; ++listIdx) - { - Index chunkIdx = pLists[listIdx]; - if (chunkIdx != InvalidChunkIdx) - { - SDefragAllocChunk& chunk = m_chunks[chunkIdx]; - if (chunk.ptr < farPtr) - { - farPtr = chunk.ptr; - farList = listIdx; - } - } - } - - return farList; - } - - void MergePopNextChunk(Index* pLists, size_t list) - { - using std::swap; - - Index fni = m_chunks[pLists[list]].freeNextIdx; - pLists[list] = fni; - if (m_chunks[fni].attr.IsBusy()) - { - // End of the list - pLists[list] = InvalidChunkIdx; - } - } - - void MergePatchNextRemove(Index* pLists, Index removeIdx) - { - for (int bucketIdx = 0; bucketIdx < NumBuckets; ++bucketIdx) - { - if (pLists[bucketIdx] == removeIdx) - { - Index nextIdx = m_chunks[removeIdx].freeNextIdx; - if (!m_chunks[nextIdx].attr.IsBusy()) - { - pLists[bucketIdx] = nextIdx; - } - else - { - pLists[bucketIdx] = InvalidChunkIdx; - } - } - } - } - - void MergePatchNextInsert(Index* pLists, Index insertIdx) - { - SDefragAllocChunk& insertChunk = m_chunks[insertIdx]; - int bucket = BucketForSize(insertChunk.attr.GetSize()); - - if (pLists[bucket] != InvalidChunkIdx) - { - SDefragAllocChunk& listChunk = m_chunks[pLists[bucket]]; - if (listChunk.ptr > insertChunk.ptr) - { - pLists[bucket] = insertIdx; - } - } - } - - void PrepareMergePopPrev(Index* pLists) - { - for (int bucketIdx = 0; bucketIdx < NumBuckets; ++bucketIdx) - { - Index hdrChunkId = m_freeBuckets[bucketIdx]; - Index prevIdx = m_chunks[hdrChunkId].freePrevIdx; - if (prevIdx != hdrChunkId) - { - pLists[bucketIdx] = prevIdx; - } - else - { - pLists[bucketIdx] = InvalidChunkIdx; - } - } - } - - size_t MergePeekPrevChunk(Index* pLists) - { - size_t farList = (size_t)-1; - UINT_PTR farPtr = 0; - - for (size_t listIdx = 0; listIdx < NumBuckets; ++listIdx) - { - Index chunkIdx = pLists[listIdx]; - if (chunkIdx != InvalidChunkIdx) - { - SDefragAllocChunk& chunk = m_chunks[chunkIdx]; - if (chunk.ptr >= farPtr) - { - farPtr = chunk.ptr; - farList = listIdx; - } - } - } - - return farList; - } - - void MergePopPrevChunk(Index* pLists, size_t list) - { - using std::swap; - - Index fpi = m_chunks[pLists[list]].freePrevIdx; - pLists[list] = fpi; - if (m_chunks[fpi].attr.IsBusy()) - { - // End of the list - pLists[list] = InvalidChunkIdx; - } - } - - void MergePatchPrevInsert(Index* pLists, Index insertIdx) - { - SDefragAllocChunk& insertChunk = m_chunks[insertIdx]; - int bucket = BucketForSize(insertChunk.attr.GetSize()); - - if (pLists[bucket] != InvalidChunkIdx) - { - SDefragAllocChunk& listChunk = m_chunks[pLists[bucket]]; - if (listChunk.ptr < insertChunk.ptr) - { - pLists[bucket] = insertIdx; - } - } - } - - void MergePatchPrevRemove(Index* pLists, Index removeIdx) - { - for (int bucketIdx = 0; bucketIdx < NumBuckets; ++bucketIdx) - { - if (pLists[bucketIdx] == removeIdx) - { - Index nextIdx = m_chunks[removeIdx].freePrevIdx; - if (!m_chunks[nextIdx].attr.IsBusy()) - { - pLists[bucketIdx] = nextIdx; - } - else - { - pLists[bucketIdx] = InvalidChunkIdx; - } - } - } - } - - void MarkAsMoving(SDefragAllocChunk& src) - { - SDefragAllocChunkAttr srcAttr, srcNewAttr; - do - { - srcAttr.ui = const_cast(src.attr.ui); - srcNewAttr.ui = srcAttr.ui; - srcNewAttr.SetMoving(true); - } - while (CryInterlockedCompareExchange(alias_cast(&src.attr.ui), srcNewAttr.ui, srcAttr.ui) != srcAttr.ui); - } - - void MarkAsNotMoving(SDefragAllocChunk& src) - { - SDefragAllocChunkAttr srcAttr, srcNewAttr; - do - { - srcAttr.ui = const_cast(src.attr.ui); - srcNewAttr.ui = srcAttr.ui; - srcNewAttr.SetMoving(false); - } - while (CryInterlockedCompareExchange(alias_cast(&src.attr.ui), srcNewAttr.ui, srcAttr.ui) != srcAttr.ui); - } - - ILINE bool IsMoveableCandidate(const SDefragAllocChunkAttr& a, uint32 sizeUpperBound) - { - return a.IsBusy() && !a.IsPinned() && !a.IsMoving() && (0 < a.GetSize()) && (a.GetSize() <= sizeUpperBound); - } - - bool TryMarkAsMoving(SDefragAllocChunk& src, uint32 sizeUpperBound) - { - SDefragAllocChunkAttr srcAttr, srcNewAttr; - do - { - srcAttr.ui = const_cast(src.attr.ui); - srcNewAttr.ui = srcAttr.ui; - if (!IsMoveableCandidate(srcAttr, sizeUpperBound)) - { - return false; - } - srcNewAttr.SetMoving(true); - } - while (CryInterlockedCompareExchange(alias_cast(&src.attr.ui), srcNewAttr.ui, srcAttr.ui) != srcAttr.ui); - return true; - } - - bool TryScheduleCopy(SDefragAllocChunk& srcChunk, SDefragAllocChunk& dstChunk, PendingMove* pPM, bool bLowHalf) - { - UINT_PTR dstChunkBase = dstChunk.ptr; - UINT_PTR dstChunkEnd = dstChunkBase + dstChunk.attr.GetSize(); -#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_BIT64 - UINT_PTR allocAlign = BIT64(srcChunk.logAlign); -#else - UINT_PTR allocAlign = BIT(srcChunk.logAlign); -#endif - UINT_PTR allocSize = srcChunk.attr.GetSize(); - UINT_PTR dstAllocBase = bLowHalf - ? Align(dstChunkBase, allocAlign) - : ((dstChunkEnd - allocSize) & ~(allocAlign - 1)); - - uint32 userId = m_policy.pDefragPolicy->BeginCopy( - srcChunk.pContext, - dstAllocBase << m_logMinAlignment, - srcChunk.ptr << m_logMinAlignment, - allocSize << m_logMinAlignment, - &pPM->notify); - pPM->userMoveId = userId; - - return userId != 0; - } - - Hdl Allocate_Locked(size_t sz, size_t alignment, const char* source, void* pContext); - SplitResult SplitFreeBlock(Index fbId, size_t sz, size_t alignment, bool allocateInLowHalf); - Index MergeFreeBlock(Index fbId); - -#ifdef CDBA_MORE_DEBUG - void Defrag_ValidateFreeBlockIteration(); -#endif - - Index BestFit_FindFreeBlockForSegment(size_t sz, size_t alignment, uint32 nSegment); - Index BestFit_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressMin, UINT_PTR addressMax, bool allocateInLowHalf); - Index FirstFit_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressMin, UINT_PTR addressMax, bool allocateInLowHalf); - - size_t Defrag_FindMovesBwd(PendingMove** pMoves, size_t maxMoves, size_t& curAmount, size_t maxAmount); - size_t Defrag_FindMovesFwd(PendingMove** pMoves, size_t maxMoves, size_t& curAmount, size_t maxAmount); - bool Defrag_CompletePendingMoves(); - Index Defrag_Bwd_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressLimit); - Index Defrag_Fwd_FindFreeBlockFor(size_t sz, size_t alignment, UINT_PTR addressLimit); - - PendingMove* AllocPendingMove(); - void FreePendingMove(PendingMove* pMove); - - void CancelMove(Index srcChunkIdx, bool bIsContentNeeded); - void CancelMove_Locked(Index srcChunkIdx, bool bIsContentNeeded); - void Relocate(uint32 userMoveId, Index srcChunkIdx, Index dstChunkIdx); - - void SyncMoveSegment(uint32 seg); - - void RebuildFreeLists(); - void ValidateAddressChain(); - void ValidateFreeLists(); - - int BucketForSize(size_t sz) const - { - return sz > 0 - ? static_cast(IntegerLog2(sz)) - : 0; - } - -private: - bool m_isThreadSafe; - bool m_chunksAreFixed; - - CryCriticalSection m_lock; - - uint32 m_capacity; - uint32 m_available; - Index m_numAllocs; - - uint16 m_minAlignment; - uint16 m_logMinAlignment; - - Index m_freeBuckets[NumBuckets]; - - std::vector m_chunks; - std::vector m_unusedChunks; - PendingMoveVec m_pendingMoves; - SegmentVec m_segments; - - uint32 m_nCancelledMoves; - - Policy m_policy; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_DEFRAGALLOCATOR_H diff --git a/Code/CryEngine/CrySystem/HMDCVars.cpp b/Code/CryEngine/CrySystem/HMDCVars.cpp deleted file mode 100644 index 4ef08db729..0000000000 --- a/Code/CryEngine/CrySystem/HMDCVars.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "HMDCVars.h" -#include -#include - -namespace AZ -{ -namespace VR -{ - -void HMDCVars::OnHMDRecenter([[maybe_unused]] IConsoleCmdArgs* args) -{ - EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, RecenterPose); -} - -void HMDCVars::OnHMDTrackingLevelChange(IConsoleCmdArgs* args) -{ - if (args->GetArgCount() != 2) - { - // First arg should be the command itself, second arg should be the requested tracking level. - return; - } - - // Read the new tracking level. - int argVal = 0; - std::stringstream stream(args->GetArg(1)); - stream >> argVal; - - AZ::VR::HMDTrackingLevel level = static_cast(argVal); - EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, SetTrackingLevel, level); -} - -void HMDCVars::OnOutputToHMDChanged(ICVar* var) -{ - // Set the necessary cvars for turning on/off output to an HMD. - ICVar* mode = gEnv->pConsole->GetCVar("r_StereoMode"); - ICVar* output = gEnv->pConsole->GetCVar("r_StereoOutput"); - ICVar* height = gEnv->pConsole->GetCVar("r_height"); - ICVar* width = gEnv->pConsole->GetCVar("r_width"); - - if (!mode || !output || !height || !width) - { - return; - } - - bool enable = (var->GetIVal() == 1); - if (enable) - { - // Auto-set the resolution. - { - const AZ::VR::HMDDeviceInfo* deviceInfo = nullptr; - EBUS_EVENT_RESULT(deviceInfo, AZ::VR::HMDDeviceRequestBus, GetDeviceInfo); - - // If the device info exists then there is a VR device connected and working. - if (deviceInfo) - { - mode->Set(EStereoMode::STEREO_MODE_DUAL_RENDERING); - output->Set(EStereoOutput::STEREO_OUTPUT_HMD); - - width->Set(static_cast(deviceInfo->renderWidth)); - height->Set(static_cast(deviceInfo->renderHeight)); - } - } - } - else - { - mode->Set(EStereoMode::STEREO_MODE_NO_STEREO); - output->Set(EStereoOutput::STEREO_OUTPUT_STANDARD); - } -} - -void HMDCVars::OnHMDDebugInfo(ICVar* var) -{ - bool enable = (var->GetIVal() == 1); - EBUS_EVENT(AZ::VR::HMDDebuggerRequestBus, EnableInfo, enable); -} - -void HMDCVars::OnHMDDebugCamera(ICVar* var) -{ - bool enable = (var->GetIVal() == 1); - EBUS_EVENT(AZ::VR::HMDDebuggerRequestBus, EnableCamera, enable); -} - -int HMDCVars::hmd_social_screen = static_cast(HMDSocialScreen::UndistortedLeftEye); -int HMDCVars::hmd_debug_info = 0; -int HMDCVars::hmd_debug_camera = 0; - -} // namespace VR -} // namespace AZ diff --git a/Code/CryEngine/CrySystem/HMDCVars.h b/Code/CryEngine/CrySystem/HMDCVars.h deleted file mode 100644 index f449bb0725..0000000000 --- a/Code/CryEngine/CrySystem/HMDCVars.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - - -#pragma once - -#include -#include - -namespace AZ -{ - namespace VR - { - class HMDCVars - { - public: - - static int hmd_social_screen; - static int hmd_debug_info; - static int hmd_debug_camera; - - static void Register() - { - REGISTER_CVAR2("hmd_social_screen", &hmd_social_screen, hmd_social_screen, - VF_NULL, "Selects the social screen mode: \n" - "-1- Off\n" - "0 - Undistorted left eye\n" - "1 - Undistorted right eye\n" - ); - - REGISTER_INT_CB("hmd_debug_info", 0, VF_ALWAYSONCHANGE, - "Enable/disable HMD and VR controller debug info/rendering", - OnHMDDebugInfo); - - REGISTER_INT_CB("hmd_debug_camera", 0, VF_ALWAYSONCHANGE, - "Enable/disable HMD debug camera", - OnHMDDebugCamera); - - REGISTER_COMMAND("hmd_tracking_level", &OnHMDTrackingLevelChange, - VF_NULL, "Set the HMD center reference point.\n" - "0 - Camera (Actor's head)\n" - "1 - Actor's feet (floor)\n"); - - REGISTER_COMMAND("hmd_recenter_pose", &OnHMDRecenter, - VF_NULL, "Re-centers sensor orientation of the HMD."); - - REGISTER_INT_CB("output_to_hmd", 0, VF_ALWAYSONCHANGE, - "Enable/disable output to any connected HMD (for VR)", - OnOutputToHMDChanged); - } - - private: - - static void OnHMDRecenter(IConsoleCmdArgs* args); - static void OnHMDTrackingLevelChange(IConsoleCmdArgs* args); - static void OnOutputToHMDChanged(ICVar* var); - static void OnHMDDebugInfo(ICVar* var); - static void OnHMDDebugCamera(ICVar* var); - }; - } // namespace VR -} // namespace AZ diff --git a/Code/CryEngine/CrySystem/IDebugCallStack.cpp b/Code/CryEngine/CrySystem/IDebugCallStack.cpp index d73d70ab8b..3d865dee6c 100644 --- a/Code/CryEngine/CrySystem/IDebugCallStack.cpp +++ b/Code/CryEngine/CrySystem/IDebugCallStack.cpp @@ -258,28 +258,6 @@ void IDebugCallStack::WriteLineToLog(const char* format, ...) } } -void IDebugCallStack::Screenshot(const char* szFileName) -{ - WriteLineToLog("Attempting to create error screenshot \"%s\"", szFileName); - - static int g_numScreenshots = 0; - if (gEnv->pRenderer && !g_numScreenshots++) - { - if (gEnv->pRenderer->ScreenShot(szFileName)) - { - WriteLineToLog("Successfully created screenshot."); - } - else - { - WriteLineToLog("Error creating screenshot."); - } - } - else - { - WriteLineToLog("Ignoring multiple calls to Screenshot"); - } -} - ////////////////////////////////////////////////////////////////////////// void IDebugCallStack::StartMemLog() { diff --git a/Code/CryEngine/CrySystem/IDebugCallStack.h b/Code/CryEngine/CrySystem/IDebugCallStack.h index 7b54c0cac0..f181b73913 100644 --- a/Code/CryEngine/CrySystem/IDebugCallStack.h +++ b/Code/CryEngine/CrySystem/IDebugCallStack.h @@ -77,8 +77,6 @@ protected: static const char* TranslateExceptionCode(DWORD dwExcept); static void PutVersion(char* str, size_t length); - static void Screenshot(const char* szFileName); - bool m_bIsFatalError; static const char* const s_szFatalErrorCode; diff --git a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp index 8818dfa0d9..b8002b74a9 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp @@ -20,7 +20,6 @@ #include "IMaterialEffects.h" #include #include -#include "IDeferredCollisionEvent.h" #include "CryPath.h" #include @@ -846,11 +845,6 @@ void CLevelSystem::OnLoadingError(const char* levelName, const char* error) return; } - if (gEnv->pRenderer) - { - gEnv->pRenderer->SetTexturePrecaching(false); - } - for (AZStd::vector::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) { (*it)->OnLoadingError(levelName, error); @@ -968,33 +962,6 @@ void CLevelSystem::UnloadLevel() CTimeValue tBegin = gEnv->pTimer->GetAsyncTime(); - //AM: Flush render thread (Flush is not exposed - using EndFrame()) - //We are about to delete resources that could be in use - if (gEnv->pRenderer) - { - gEnv->pRenderer->EndFrame(); - - - bool isLoadScreenPlaying = false; -#if AZ_LOADSCREENCOMPONENT_ENABLED - LoadScreenBus::BroadcastResult(isLoadScreenPlaying, &LoadScreenBus::Events::IsPlaying); -#endif // if AZ_LOADSCREENCOMPONENT_ENABLED - - // force a black screen as last render command. - //if load screen is playing do not call this draw as it may lead to a crash due to UI loading code getting - //pumped while loading the shaders for this draw. - if (!isLoadScreenPlaying) - { - gEnv->pRenderer->BeginFrame(); - gEnv->pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); - gEnv->pRenderer->Draw2dImage(0, 0, 800, 600, -1, 0.0f, 0.0f, 1.0f, 1.0f, 0.f, 0.0f, 0.0f, 0.0f, 1.0, 0.f); - gEnv->pRenderer->EndFrame(); - } - - //flush any outstanding texture requests - gEnv->pRenderer->FlushPendingTextureTasks(); - } - // Clear level entities and prefab instances. EBUS_EVENT(AzFramework::GameEntityContextRequestBus, ResetGameContext); @@ -1045,27 +1012,6 @@ void CLevelSystem::UnloadLevel() // Normally the GC step is triggered at the end of this method (by the ESYSTEM_EVENT_LEVEL_POST_UNLOAD event). EBUS_EVENT(AZ::ScriptSystemRequestBus, GarbageCollect); - // Force to clean render resources left after deleting all objects and materials. - IRenderer* pRenderer = gEnv->pRenderer; - if (pRenderer) - { - pRenderer->FlushRTCommands(true, true, true); - - CryComment("Deleting Render meshes, render resources and flush texture streaming"); - // This may also release some of the materials. - int flags = FRR_DELETED_MESHES | FRR_FLUSH_TEXTURESTREAMING | FRR_OBJECTS | FRR_RENDERELEMENTS | FRR_RP_BUFFERS | FRR_POST_EFFECTS; - - // Always keep the system resources around in the editor. - // If a level load fails for any reason, then do not unload the system resources, otherwise we will not have any system resources to continue rendering the console and debug output text. - if (!gEnv->IsEditor() && !GetLevelLoadFailed()) - { - flags |= FRR_SYSTEM_RESOURCES; - } - - pRenderer->FreeResources(flags); - CryComment("done"); - } - // Perform level unload procedures for the LyShine UI system if (gEnv && gEnv->pLyShine) { diff --git a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index 4b6e210522..2a7f8d5c5e 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -15,7 +15,6 @@ #include #include "IMovieSystem.h" #include -#include "IDeferredCollisionEvent.h" #include @@ -423,11 +422,6 @@ namespace LegacyLevelSystem { AZ_Error("LevelSystem", false, "Error loading level '%s': %s\n", levelName, error); - if (gEnv->pRenderer) - { - gEnv->pRenderer->SetTexturePrecaching(false); - } - for (auto& listener : m_listeners) { listener->OnLoadingError(levelName, error); @@ -541,32 +535,6 @@ namespace LegacyLevelSystem CTimeValue tBegin = gEnv->pTimer->GetAsyncTime(); - // AM: Flush render thread (Flush is not exposed - using EndFrame()) - // We are about to delete resources that could be in use - if (gEnv->pRenderer) - { - gEnv->pRenderer->EndFrame(); - - bool isLoadScreenPlaying = false; - #if AZ_LOADSCREENCOMPONENT_ENABLED - LoadScreenBus::BroadcastResult(isLoadScreenPlaying, &LoadScreenBus::Events::IsPlaying); - #endif // if AZ_LOADSCREENCOMPONENT_ENABLED - - // force a black screen as last render command. - // if load screen is playing do not call this draw as it may lead to a crash due to UI loading code getting - // pumped while loading the shaders for this draw. - if (!isLoadScreenPlaying) - { - gEnv->pRenderer->BeginFrame(); - gEnv->pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); - gEnv->pRenderer->Draw2dImage(0, 0, 800, 600, -1, 0.0f, 0.0f, 1.0f, 1.0f, 0.f, 0.0f, 0.0f, 0.0f, 1.0, 0.f); - gEnv->pRenderer->EndFrame(); - } - - // flush any outstanding texture requests - gEnv->pRenderer->FlushPendingTextureTasks(); - } - // Clear level entities and prefab instances. EBUS_EVENT(AzFramework::GameEntityContextRequestBus, ResetGameContext); @@ -608,28 +576,6 @@ namespace LegacyLevelSystem // Normally the GC step is triggered at the end of this method (by the ESYSTEM_EVENT_LEVEL_POST_UNLOAD event). EBUS_EVENT(AZ::ScriptSystemRequestBus, GarbageCollect); - // Force to clean render resources left after deleting all objects and materials. - IRenderer* pRenderer = gEnv->pRenderer; - if (pRenderer) - { - pRenderer->FlushRTCommands(true, true, true); - - CryComment("Deleting Render meshes, render resources and flush texture streaming"); - // This may also release some of the materials. - int flags = FRR_DELETED_MESHES | FRR_FLUSH_TEXTURESTREAMING | FRR_OBJECTS | FRR_RENDERELEMENTS | FRR_RP_BUFFERS | FRR_POST_EFFECTS; - - // Always keep the system resources around in the editor. - // If a level load fails for any reason, then do not unload the system resources, otherwise we will not have any system resources to - // continue rendering the console and debug output text. - if (!gEnv->IsEditor() && !GetLevelLoadFailed()) - { - flags |= FRR_SYSTEM_RESOURCES; - } - - pRenderer->FreeResources(flags); - CryComment("done"); - } - // Perform level unload procedures for the LyShine UI system if (gEnv && gEnv->pLyShine) { diff --git a/Code/CryEngine/CrySystem/LocalizedStringManager.cpp b/Code/CryEngine/CrySystem/LocalizedStringManager.cpp index a11e068a9b..7a2ad51e8b 100644 --- a/Code/CryEngine/CrySystem/LocalizedStringManager.cpp +++ b/Code/CryEngine/CrySystem/LocalizedStringManager.cpp @@ -32,9 +32,6 @@ #include #include -#if !defined(_RELEASE) -#include "CrySizerImpl.h" -#endif //#if !defined(_RELEASE) #define MAX_CELL_COUNT 32 @@ -165,52 +162,6 @@ static void TestFormatMessage ([[maybe_unused]] IConsoleCmdArgs* pArgs) } #endif //#if !defined(_RELEASE) - -////////////////////////////////////////////////////////////////////////// -#if !defined(_RELEASE) -void CLocalizedStringsManager::LocalizationDumpLoadedInfo([[maybe_unused]] IConsoleCmdArgs* pArgs) -{ - CLocalizedStringsManager* pLoca = (CLocalizedStringsManager*) gEnv->pSystem->GetLocalizationManager(); - - for (TTagFileNames::iterator tagit = pLoca->m_tagFileNames.begin(); tagit != pLoca->m_tagFileNames.end(); ++tagit) - { - CryLogAlways("Tag %s (%d)", tagit->first.c_str(), tagit->second.id); - - int entries = 0; - CrySizerImpl* pSizer = new CrySizerImpl(); - - for (tmapFilenames::iterator it = pLoca->m_loadedTables.begin(); it != pLoca->m_loadedTables.end(); it++) - { - if (tagit->second.id == it->second.nTagID) - { - CryLogAlways("\t%s", it->first.c_str()); - } - - if (pLoca->m_pLanguage) - { - const uint32 numEntries = pLoca->m_pLanguage->m_vLocalizedStrings.size(); - for (int32 i = numEntries - 1; i >= 0; i--) - { - SLocalizedStringEntry* entry = pLoca->m_pLanguage->m_vLocalizedStrings[i]; - if (tagit->second.id == entry->nTagID) - { - entries++; - entry->GetMemoryUsage((ICrySizer*) pSizer); - } - } - } - } - - // This line messes up Uncrustify so turn it off: *INDENT-OFF* - CryLogAlways("\t\tEntries %d, Approx Size %" PRISIZE_T "Kb", entries, pSizer->GetTotalSize() / 1024); - // turn it back on again: *INDENT-ON* - - SAFE_RELEASE(pSizer); - } -} - -#endif //#if !defined(_RELEASE) - ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -249,9 +200,6 @@ CLocalizedStringsManager::CLocalizedStringsManager(ISystem* pSystem) "0: No encoding, store as wide strings\n" "1: Huffman encode translated text, saves approx 30% with a small runtime performance cost\n" "Default is 1."); - - - REGISTER_COMMAND("LocalizationDumpLoadedInfo", LocalizationDumpLoadedInfo, VF_NULL, "Dump out into about the loaded localization files"); #endif //#if !defined(_RELEASE) REGISTER_CVAR2(c_sys_localization_format, &m_cvarLocalizationFormat, 1, VF_NULL, diff --git a/Code/CryEngine/CrySystem/LocalizedStringManager.h b/Code/CryEngine/CrySystem/LocalizedStringManager.h index 6b7ef6060b..1f18ba5c4a 100644 --- a/Code/CryEngine/CrySystem/LocalizedStringManager.h +++ b/Code/CryEngine/CrySystem/LocalizedStringManager.h @@ -96,10 +96,6 @@ public: void GetLoadedTags(TLocalizationTagVec& tagVec); void FreeLocalizationData(); -#if !defined(_RELEASE) - static void LocalizationDumpLoadedInfo(IConsoleCmdArgs* pArgs); -#endif //#if !defined(_RELEASE) - private: void SetAvailableLocalizationsBitfield(const ILocalizationManager::TLocalizationBitfield availableLocalizations); diff --git a/Code/CryEngine/CrySystem/MemoryFragmentationProfiler.h b/Code/CryEngine/CrySystem/MemoryFragmentationProfiler.h deleted file mode 100644 index 7d373bb472..0000000000 --- a/Code/CryEngine/CrySystem/MemoryFragmentationProfiler.h +++ /dev/null @@ -1,325 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_MEMORYFRAGMENTATIONPROFILER_H -#define CRYINCLUDE_CRYSYSTEM_MEMORYFRAGMENTATIONPROFILER_H -#pragma once - - -// useful class to investigate memory fragmentation -// every time you call this from the console: -// -// #System.DumpMemoryCoverage() -// -// it adds a line to "MemoryCoverage.bmp" (generated the first time, there is a max line count) -// blue stripes mark some special positions (DLL positions) - -// Dependencies: only CryLog() - - -#include // STL vector<> - - -#if defined(WIN32) || defined(WIN64) - -class CMemoryFragmentationProfiler -{ -public: - - // constructor - clean file - CMemoryFragmentationProfiler() - : m_dwLine(0xffffffff) // 0xffffffff means not initialized yet - { - } - - // call this if you want to add one line (on first call the file is generated) - void DumpMemoryCoverage() - { - if (m_dwLine == 0xffffffff) - { - Init(); - } - - const size_t nMinMemoryPerUnit = 4 * 1024; // down to a few KB - const size_t nUnitsPerLine = 1024 * 8; // amount of bits, should only occupy a few KB memory - - const size_t nMaxMemoryPerUnit = 0x100000000 / nUnitsPerLine; // 4GB in total - - static std::vector vCoverage; - - vCoverage.clear(); - vCoverage.resize(nUnitsPerLine, 0); // should occupy nUnitsPerLine/8 bytes (vector is specialized) - - size_t nAvailableMem = 0, nUsedMem = 0; - - const size_t nMallocOverhead = 24; // depends on used runtime (debug:32, release:24) - - size_t nCurrentUnitSize = 256 * 1024 * 1024; // start with 256 MB blocks - - void** pMemoryBlocks = 0; // linked list of memory blocks (to free them) - - size_t nUnits = 0; - uint32 dwAllocCnt = 0, dwFreeCnt = 0; - - while (nCurrentUnitSize >= nMinMemoryPerUnit) - { - size_t nLocalUnits = 0; - - for (;; ) - { - void** pMem = (void**)::malloc(nCurrentUnitSize - nMallocOverhead); - - if (!pMem) - { - break; - } - - ++dwAllocCnt; - - // update coverage (conservative) - { - size_t nStartUnit = ((size_t)pMem + nMaxMemoryPerUnit - 1) / (nMaxMemoryPerUnit); - size_t nEndUnit = ((size_t)pMem + nCurrentUnitSize) / (nMaxMemoryPerUnit); - - if (nStartUnit > nUnitsPerLine) - { - nStartUnit = nUnitsPerLine; - } - - if (nEndUnit > nUnitsPerLine) - { - nEndUnit = nUnitsPerLine; - } - - for (size_t i = nStartUnit; i < nEndUnit; ++i) - { - vCoverage[i] = 1; - } - } - - ++nLocalUnits; - - // insert in linked list - *pMem = pMemoryBlocks; - pMemoryBlocks = pMem; - } - - nUnits += nLocalUnits; - nAvailableMem += nLocalUnits * nCurrentUnitSize; - - nCurrentUnitSize /= 2; - nUnits *= 2; - } - - // free all memory blocks allocated - while (pMemoryBlocks) - { - void* pNext = *pMemoryBlocks; - - ::free(pMemoryBlocks); - ++dwFreeCnt; - - pMemoryBlocks = (void**)pNext; - } - - - // _heapmin(); - - CryLog("CMemoryFragmentationProfiler Y=%d, available memory=%d MB, used memory=%d MB", - m_dwLine, (nAvailableMem + 1024 * 1024 - 1) / (1024 * 1024), (nUsedMem + 1024 * 1024 - 1) / (1024 * 1024)); - - LogCoverage(vCoverage); - - DumpToRAWCoverage(vCoverage); - } - -private: // ------------------------------------------------------------------ - - void Init() - { - FILE* out = nullptr; - azfopen(&out, "MemoryCoverage.bmp", "wb"); - - if (out) - { - BITMAPFILEHEADER pHeader; - BITMAPINFOHEADER pInfoHeader; - - memset(&pHeader, 0, sizeof(BITMAPFILEHEADER)); - memset(&pInfoHeader, 0, sizeof(BITMAPINFOHEADER)); - - pHeader.bfType = 0x4D42; - pHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_nPixelsPerLine * m_nLineCount * 3; - pHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - - pInfoHeader.biSize = sizeof(BITMAPINFOHEADER); - pInfoHeader.biWidth = m_nPixelsPerLine; - pInfoHeader.biHeight = m_nLineCount; - pInfoHeader.biPlanes = 1; - pInfoHeader.biBitCount = 24; - pInfoHeader.biCompression = 0; - pInfoHeader.biSizeImage = m_nPixelsPerLine * m_nLineCount; - - fwrite(&pHeader, 1, sizeof(BITMAPFILEHEADER), out); - fwrite(&pInfoHeader, 1, sizeof(BITMAPINFOHEADER), out); - - for (int y = 0; y < m_nLineCount; y++) // amount of lines - { - for (int x = 0; x < m_nPixelsPerLine; x++) - { - size_t nAddress = x * (0x100000000 / m_nPixelsPerLine); - - if (nAddress == 0x30000000 - || nAddress == 0x30500000 - || nAddress == 0x31000000 - || nAddress == 0x31500000 - || nAddress == 0x32000000 - || nAddress == 0x32500000 - || nAddress == 0x33500000 - || nAddress == 0x34000000 - || nAddress == 0x35000000 - || nAddress == 0x35500000 - || nAddress == 0x36000000 - || nAddress == 0x36500000 - || nAddress == 0x38000000 - || nAddress == 0x39000000) - { - putc((unsigned char)100, out); // blue DLL start - } - else - { - putc((unsigned char)0, out); // black - } - putc((unsigned char)0, out); - putc((unsigned char)0, out); - } - } - - fclose(out); - m_dwLine = 0; - } - } - - void LogCoverage(std::vector& vCov) - { - const size_t nCharPerLine = 128; // readable amount - - char szResult[nCharPerLine + 1], * pCursor = szResult; - - szResult[nCharPerLine] = 0; // zero termination - - size_t nSize = vCov.size(); - size_t nUnitsPerChar = nSize / nCharPerLine; - - for (size_t i = 0; i < nSize; ) - { - unsigned int nLocalCov = 0; - - for (size_t e = 0; e < nUnitsPerChar; ++e, ++i) - { - if (vCov[i]) - { - ++nLocalCov; - } - } - - if (nLocalCov == 0) - { - *pCursor++ = '#'; // occupied - } - else if (nLocalCov == nUnitsPerChar) - { - *pCursor++ = '.'; // free - } - else - { - *pCursor++ = '+'; // partly - } - } - - CryLog(" Coverage=%s", szResult); - } - - - void DumpToRAWCoverage(std::vector& vCov) - { - FILE* out = nullptr; - azfopen(&out, "MemoryCoverage.bmp", "rb+"); - - if (!out) - { - return; - } - - if (fseek(out, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 3 * (m_nLineCount - 1 - m_dwLine) * m_nPixelsPerLine, SEEK_SET) != 0) - { - fclose(out); - return; - } - - size_t nSize = vCov.size(); - size_t nUnitsPerChar = nSize / m_nPixelsPerLine; - - for (size_t i = 0; i < nSize; ) - { - unsigned int nLocalCov = 0; - - for (size_t e = 0; e < nUnitsPerChar; ++e, ++i) - { - if (vCov[i]) - { - ++nLocalCov; - } - } - - size_t Val = 256 - (256 * nLocalCov) / nUnitsPerChar; - - if (Val > 0) - { - Val = 127 + Val / 2; - } - - putc((unsigned char)Val, out); - putc((unsigned char)Val, out); - putc((unsigned char)Val, out); // grey - } - - fclose(out); - - ++m_dwLine; - } - - - - unsigned int m_dwLine; // [0..m_nLineCount-1], m_nLineCount means bitmap is full, 0xffffffff means not initialized yet - static const size_t m_nPixelsPerLine = 1024; // bitmap width - static const size_t m_nLineCount = 128; // -}; - - -#else // defined(WIN32) || defined(WIN64) - - -class CMemoryFragmentationProfiler -{ -public: - void DumpMemoryCoverage() {} -}; - -#endif // defined(WIN32) || defined(WIN64) - - - -#endif // CRYINCLUDE_CRYSYSTEM_MEMORYFRAGMENTATIONPROFILER_H - - diff --git a/Code/CryEngine/CrySystem/MemoryManager.cpp b/Code/CryEngine/CrySystem/MemoryManager.cpp index 4704d2f5fe..3021d68539 100644 --- a/Code/CryEngine/CrySystem/MemoryManager.cpp +++ b/Code/CryEngine/CrySystem/MemoryManager.cpp @@ -17,7 +17,6 @@ #include "CustomMemoryHeap.h" #include "GeneralMemoryHeap.h" #include "PageMappingHeap.h" -#include "DefragAllocator.h" #if defined(AZ_RESTRICTED_PLATFORM) @@ -217,11 +216,6 @@ IPageMappingHeap* CCryMemoryManager::CreatePageMappingHeap(size_t addressSpace, return new CPageMappingHeap(addressSpace, sName); } -IDefragAllocator* CCryMemoryManager::CreateDefragAllocator() -{ - return new CDefragAllocator(); -} - extern "C" { CRYMEMORYMANAGER_API void CryGetIMemoryManagerInterface(void** pIMemoryManager) diff --git a/Code/CryEngine/CrySystem/MemoryManager.h b/Code/CryEngine/CrySystem/MemoryManager.h index e9d748e481..e29d5404d8 100644 --- a/Code/CryEngine/CrySystem/MemoryManager.h +++ b/Code/CryEngine/CrySystem/MemoryManager.h @@ -44,8 +44,6 @@ public: virtual IMemoryAddressRange* ReserveAddressRange(size_t capacity, const char* sName); virtual IPageMappingHeap* CreatePageMappingHeap(size_t addressSpace, const char* sName); - - virtual IDefragAllocator* CreateDefragAllocator(); }; #else typedef IMemoryManager CCryMemoryManager; diff --git a/Code/CryEngine/CrySystem/MiniGUI/DrawContext.cpp b/Code/CryEngine/CrySystem/MiniGUI/DrawContext.cpp deleted file mode 100644 index a45fde272b..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/DrawContext.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "DrawContext.h" -#include -#include -#include - -MINIGUI_BEGIN - -////////////////////////////////////////////////////////////////////////// -CDrawContext::CDrawContext(SMetrics* pMetrics) -{ - m_currentStackLevel = 0; - m_x = 0; - m_y = 0; - m_pMetrics = pMetrics; - m_color = ColorB(0, 0, 0, 0); - m_defaultZ = 0.0f; - m_pAuxRender = gEnv->pRenderer->GetIRenderAuxGeom(); - - m_frameWidth = (float)gEnv->pRenderer->GetWidth(); - m_frameHeight = (float)gEnv->pRenderer->GetHeight(); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::SetColor(ColorB color) -{ - m_color = color; -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::DrawLine(float x0, float y0, float x1, float y1, float thickness /*= 1.0f */) -{ - m_pAuxRender->DrawLine(Vec3(m_x + x0, m_y + y0, m_defaultZ), m_color, Vec3(m_x + x1, m_y + y1, m_defaultZ), m_color, thickness); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::DrawTriangle(float x0, float y0, float x1, float y1, float x2, float y2) -{ - m_pAuxRender->DrawTriangle(Vec3(m_x + x0, m_y + y0, m_defaultZ), m_color, Vec3(m_x + x1, m_y + y1, m_defaultZ), m_color, Vec3(m_x + x2, m_y + y2, m_defaultZ), m_color); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::DrawRect(const Rect& rc) -{ - m_pAuxRender->DrawTriangle(Vec3(m_x + rc.left, m_y + rc.top, m_defaultZ), m_color, Vec3(m_x + rc.left, m_y + rc.bottom, m_defaultZ), m_color, Vec3(m_x + rc.right, m_y + rc.top, m_defaultZ), m_color); - m_pAuxRender->DrawTriangle(Vec3(m_x + rc.left, m_y + rc.bottom, m_defaultZ), m_color, Vec3(m_x + rc.right, m_y + rc.bottom, m_defaultZ), m_color, Vec3(m_x + rc.right, m_y + rc.top, m_defaultZ), m_color); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::DrawFrame(const Rect& rc, ColorB lineColor, ColorB solidColor, float thickness) -{ - ColorB prevColor = m_color; - - SetColor(solidColor); - DrawRect(rc); - - SetColor(lineColor); - - uint32 curFlags = m_pAuxRender->GetRenderFlags().m_renderFlags; - m_pAuxRender->SetRenderFlags(curFlags | e_DrawInFrontOn); - DrawLine(rc.left, rc.top, rc.right, rc.top, thickness); - DrawLine(rc.right, rc.top, rc.right, rc.bottom, thickness); - DrawLine(rc.left, rc.top, rc.left, rc.bottom, thickness); - DrawLine(rc.left, rc.bottom, rc.right, rc.bottom, thickness); - m_pAuxRender->SetRenderFlags(curFlags); - - m_color = prevColor; -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::StartDrawing() -{ - uint32 width = gEnv->pRenderer->GetWidth(); - uint32 height = gEnv->pRenderer->GetHeight(); - - gEnv->pRenderer->Set2DMode(width, height, m_backupSceneMatrices); - - m_prevRenderFlags = m_pAuxRender->GetRenderFlags().m_renderFlags; - m_pAuxRender->SetRenderFlags(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOff); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::StopDrawing() -{ - // Restore old flags that where set before our draw context. - m_pAuxRender->SetRenderFlags(m_prevRenderFlags); - - gEnv->pRenderer->Unset2DMode(m_backupSceneMatrices); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::DrawString(float x, float y, float font_size, ETextAlign align, const char* format, ...) -{ - //text will be off screen - if (y > m_frameHeight || x > m_frameWidth) - { - return; - } - - va_list args; - va_start(args, format); - SDrawTextInfo ti; - ti.xscale = ti.yscale = font_size / 12.0f; // font size in pixels to text scale. - - ti.flags = eDrawText_Monospace | eDrawText_2D | eDrawText_FixedSize | eDrawText_IgnoreOverscan; - if (align == eTextAlign_Left) - { - } - else if (align == eTextAlign_Right) - { - ti.flags |= eDrawText_Right; - } - else if (align == eTextAlign_Center) - { - ti.flags |= eDrawText_Center; - } - ti.color[0] = (float)m_color.r / 255.0f; - ti.color[1] = (float)m_color.g / 255.0f; - ti.color[2] = (float)m_color.b / 255.0f; - ti.color[3] = (float)m_color.a / 255.0f; - gEnv->pRenderer->DrawTextQueued(Vec3(m_x + x, m_y + y, m_defaultZ), ti, format, args); - va_end(args); -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::PushClientRect(const Rect& rc) -{ - m_currentStackLevel++; - assert(m_currentStackLevel < MAX_ORIGIN_STACK); - m_clientRectStack[m_currentStackLevel] = rc; - m_x += rc.left; - m_y += rc.top; -} - -////////////////////////////////////////////////////////////////////////// -void CDrawContext::PopClientRect() -{ - if (m_currentStackLevel > 0) - { - Rect& rc = m_clientRectStack[m_currentStackLevel]; - m_x -= rc.left; - m_y -= rc.top; - - m_currentStackLevel--; - } -} -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/DrawContext.h b/Code/CryEngine/CrySystem/MiniGUI/DrawContext.h deleted file mode 100644 index 6b1b8000ae..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/DrawContext.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : DrawContext helper class for MiniGUI - - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_DRAWCONTEXT_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_DRAWCONTEXT_H -#pragma once - - -#include "ICryMiniGUI.h" -#include - -struct IRenderAuxGeom; - -MINIGUI_BEGIN - -enum ETextAlign -{ - eTextAlign_Left, - eTextAlign_Right, - eTextAlign_Center -}; - -////////////////////////////////////////////////////////////////////////// -// Context of MiniGUI drawing. -////////////////////////////////////////////////////////////////////////// -class CDrawContext -{ -public: - CDrawContext(SMetrics* pMetrics); - - // Must be called before any drawing happens - void StartDrawing(); - // Must be called after all drawing have been complete. - void StopDrawing(); - - void PushClientRect(const Rect& rc); - void PopClientRect(); - - SMetrics& Metrics() { return *m_pMetrics; } - void SetColor(ColorB color); - - void DrawLine(float x0, float y0, float x1, float y1, float thickness = 1.0f); - void DrawTriangle(float x0, float y0, float x1, float y1, float x2, float y2); - void DrawRect(const Rect& rc); - void DrawFrame(const Rect& rc, ColorB lineColor, ColorB solidColor, float thickness = 1.0f); - - void DrawString(float x, float y, float font_size, ETextAlign align, const char* format, ...); - - -protected: - SMetrics* m_pMetrics; - - ColorB m_color; - float m_defaultZ; - IRenderAuxGeom* m_pAuxRender; - uint32 m_prevRenderFlags; - - enum - { - MAX_ORIGIN_STACK = 16 - }; - - int m_currentStackLevel; - float m_x, m_y; // Reference X,Y positions - Rect m_clientRectStack[MAX_ORIGIN_STACK]; - - float m_frameWidth; - float m_frameHeight; - -private: - TransformationMatrices m_backupSceneMatrices; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_DRAWCONTEXT_H diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniButton.cpp b/Code/CryEngine/CrySystem/MiniGUI/MiniButton.cpp deleted file mode 100644 index cbedfe1eae..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniButton.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#include "CrySystem_precompiled.h" -#include "MiniButton.h" -#include "DrawContext.h" -#include -#include - -MINIGUI_BEGIN - - -CMiniButton::CMiniButton() -{ - m_pCVar = NULL; - m_fCVarValue[0] = 0; - m_fCVarValue[1] = 1; - m_saveStateOn = false; - m_clickCallback = NULL; - m_pCallbackData = NULL; - m_pConnectedCtrl = NULL; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::Reset() -{ - /*if (m_pCVar) - { - pCVar->Set( m_fCVarValue[0] ); - }*/ - - /*if(m_pConnectedCtrl) - { - m_pConnectedCtrl->SetVisible(false); - }*/ - - clear_flag(eCtrl_Checked); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::SaveState() -{ - if (is_flag(eCtrl_Checked)) - { - if (m_pConnectedCtrl && m_pConnectedCtrl->CheckFlag(eCtrl_Hidden)) - { - m_saveStateOn = false; - } - else - { - m_saveStateOn = true; - } - } - else - { - m_saveStateOn = false; - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::RestoreState() -{ - if (m_pCVar) - { - if (m_pCVar->GetFVal() == m_fCVarValue[1]) - { - set_flag(eCtrl_Checked); - - - //Restoring CVars has caused a few issues, especially when the user is changing - //CVars through the console while perfHud is active, removing for now - //pCVar->Set( m_saveStateOn ? m_fCVarValue[1] : m_fCVarValue[0] ); - } - else - { - clear_flag(eCtrl_Checked); - } - } - else - { - //connected controls (tables / info boxes etc) now look after themselves - /*if(m_pConnectedCtrl) - { - m_pConnectedCtrl->SetVisible(m_saveStateOn); - }*/ - - if (CheckFlag(eCtrl_CheckButton)) - { - if (m_saveStateOn) - { - set_flag(eCtrl_Checked); - } - else - { - clear_flag(eCtrl_Checked); - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::OnPaint(CDrawContext& dc) -{ - ColorB bkgColor = dc.Metrics().clrBackground; - - if (is_flag(eCtrl_Highlight)) - { - bkgColor = dc.Metrics().clrBackgroundHighlight; - } - else if (is_flag(eCtrl_Checked)) - { - //if connected control has been hidden, this button should not be checked - if (m_pConnectedCtrl && m_pConnectedCtrl->CheckFlag(eCtrl_Hidden)) - { - clear_flag(eCtrl_Checked); - } - else - { - bkgColor = dc.Metrics().clrBackgroundSelected; - } - } - - float borderThickness = 1.0f; - - if (is_flag(eCtrl_Focus)) - { - borderThickness = 3.0f; - } - - ColorB borderCol = dc.Metrics().clrFrameBorder; - - if (!m_pGUI->InFocus()) - { - borderCol = dc.Metrics().clrFrameBorderOutOfFocus; - bkgColor.a = dc.Metrics().outOfFocusAlpha; - } - - dc.DrawFrame(m_rect, borderCol, bkgColor, borderThickness); - - ColorB textColor = dc.Metrics().clrText; - - if (is_flag(eCtrl_Checked | eCtrl_Highlight)) - { - textColor = dc.Metrics().clrTextSelected; - } - - dc.SetColor(textColor); - - ETextAlign align; - float startX; - - if (is_flag(eCtrl_TextAlignCentre)) - { - startX = (m_rect.left + m_rect.right) / 2.f; - align = eTextAlign_Center; - } - else - { - startX = m_rect.left + 5.f; - align = eTextAlign_Left; - } - - dc.DrawString(startX, m_rect.top, dc.Metrics().fTitleSize, align, GetTitle()); - - //Check not very obvious -#if 0 - if (is_flag(eCtrl_Checked)) - { - // Draw checked mark. - float checkX = m_rect.left + 4; - float checkY = (m_rect.bottom + m_rect.top) * 0.5f; - dc.SetColor(dc.Metrics().clrChecked); - dc.DrawLine(checkX, checkY, checkX + 3, checkY + 3); - dc.DrawLine(checkX + 3, checkY + 3, checkX + 7, checkY - 6); - } -#endif -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::SetRect(const Rect& rc) -{ - Rect newrc = rc; - newrc.bottom = newrc.top + m_pGUI->Metrics().fTitleSize + 2; - CMiniCtrl::SetRect(newrc); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniButton::OnEvent(float x, float y, EMiniCtrlEvent event) -{ - switch (event) - { - case eCtrlEvent_LButtonDown: - { - SCommand cmd; - - if (CheckFlag(eCtrl_CheckButton)) - { - if (!CheckFlag(eCtrl_Checked)) - { - cmd.command = eCommand_ButtonChecked; - } - else - { - cmd.command = eCommand_ButtonUnchecked; - } - } - else - { - cmd.command = eCommand_ButtonPress; - } - - cmd.nCtrlID = GetId(); - cmd.pCtrl = this; - GetGUI()->OnCommand(cmd); - - if (CheckFlag(eCtrl_CheckButton)) - { - bool bOn = false; - - if (CheckFlag(eCtrl_Checked)) - { - bOn = false; - ClearFlag(eCtrl_Checked); - } - else - { - bOn = true; - SetFlag(eCtrl_Checked); - } - - if (m_pCVar) - { - m_pCVar->Set(m_fCVarValue[bOn ? 1 : 0]); - } - - if (m_pConnectedCtrl) - { - m_pConnectedCtrl->SetVisible(bOn); - } - } - else - { - //cross button behavior - if (m_pConnectedCtrl) - { - m_pConnectedCtrl->SetVisible(false); - } - } - - if (m_clickCallback) - { - m_clickCallback(m_pCallbackData, true); - } - } - break; - case eCtrlEvent_MouseOff: - { - if (m_pParent) - { - m_pParent->OnEvent(x, y, eCtrlEvent_MouseOff); - } - } - break; - } -} - -////////////////////////////////////////////////////////////////////////// -bool CMiniButton::SetControlCVar(const char* sCVarName, float fOffValue, float fOnValue) -{ - m_pCVar = GetISystem()->GetIConsole()->GetCVar(sCVarName); - - if (!m_pCVar) - { - CryLogAlways("failed to find CVar: %s\n", sCVarName); - } - - m_fCVarValue[0] = fOffValue; - m_fCVarValue[1] = fOnValue; - - if (m_pCVar && m_pCVar->GetFVal() == fOnValue) - { - set_flag(eCtrl_Checked); - } - - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CMiniButton::SetClickCallback(ClickCallback callback, void* pCallbackData) -{ - m_clickCallback = callback; - m_pCallbackData = pCallbackData; - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CMiniButton::SetConnectedCtrl(IMiniCtrl* pConnectedCtrl) -{ - m_pConnectedCtrl = pConnectedCtrl; - return true; -} - -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniButton.h b/Code/CryEngine/CrySystem/MiniGUI/MiniButton.h deleted file mode 100644 index 3e45f6b4e4..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniButton.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIBUTTON_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIBUTTON_H -#pragma once - - -#include "MiniGUI.h" - -MINIGUI_BEGIN - -////////////////////////////////////////////////////////////////////////// -// Root window all other controls derive from -class CMiniButton - : public CMiniCtrl -{ -public: - CMiniButton(); - - ////////////////////////////////////////////////////////////////////////// - // CMiniCtrl interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual EMiniCtrlType GetType() const { return eCtrlType_Button; } - virtual void SetRect(const Rect& rc); - virtual void OnPaint(CDrawContext& dc); - virtual void OnEvent(float x, float y, EMiniCtrlEvent event); - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - ////////////////////////////////////////////////////////////////////////// - - virtual bool SetControlCVar(const char* sCVarName, float fOffValue, float fOnValue); - virtual bool SetClickCallback(ClickCallback callback, void* pCallbackData); - virtual bool SetConnectedCtrl(IMiniCtrl* pConnectedCtrl); - -protected: - ICVar* m_pCVar; - float m_fCVarValue[2]; - ClickCallback m_clickCallback; - void* m_pCallbackData; - IMiniCtrl* m_pConnectedCtrl; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIBUTTON_H diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.cpp b/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.cpp deleted file mode 100644 index 9b074ce537..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.cpp +++ /dev/null @@ -1,862 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Implementation of the MiniGUI class - - -#include "CrySystem_precompiled.h" -#include "MiniGUI.h" -#include "DrawContext.h" - -#include "MiniButton.h" -#include "MiniMenu.h" -#include "MiniInfoBox.h" -#include "MiniTable.h" - -#include -#include - -#include -#include -#include - -namespace minigui -{ - CRYREGISTER_SINGLETON_CLASS(CMiniGUI) -} - - -MINIGUI_BEGIN - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::InitMetrics() -{ - m_metrics.clrText = ColorB(255, 255, 255, 255); - m_metrics.clrTextSelected = ColorB(0, 255, 0, 255); - m_metrics.fTextSize = 12.0f; - - m_metrics.clrTitle = ColorB(255, 255, 255, 255); - - m_metrics.fTitleSize = 14.0f; - - const int backgroundAlpha = 255; - - m_metrics.clrBackground = ColorB(20, 20, 20, backgroundAlpha); - m_metrics.clrBackgroundHighlight = ColorB(10, 10, 150, backgroundAlpha); - m_metrics.clrBackgroundSelected = ColorB(10, 120, 10, backgroundAlpha); - - m_metrics.clrFrameBorder = ColorB(255, 0, 0, 255); - m_metrics.clrFrameBorderHighlight = ColorB(255, 255, 0, 255); - m_metrics.clrFrameBorderOutOfFocus = ColorB(0, 0, 0, 255); - - m_metrics.clrChecked = ColorB(0, 0, 0, 255); - m_metrics.outOfFocusAlpha = 32; -} - -class CMiniCtrlRoot - : public CMiniCtrl -{ -public: - CMiniCtrlRoot() {}; - virtual EMiniCtrlType GetType() const { return eCtrlType_Unknown; }; - virtual void OnPaint([[maybe_unused]] class CDrawContext& dc) {}; -}; - -////////////////////////////////////////////////////////////////////////// -CMiniGUI::CMiniGUI() - : m_enabled(false) - , m_inFocus(true) - , m_pDPadMenu(NULL) - , m_pMovingCtrl(NULL) -{ -} - -////////////////////////////////////////////////////////////////////////// -CMiniGUI::~CMiniGUI() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::Init() -{ - m_pEventListener = NULL; - InitMetrics(); - - AzFramework::InputChannelEventListener::Connect(); - - m_pRootCtrl = new CMiniCtrlRoot; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::Reset() -{ - m_pRootCtrl->Reset(); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SaveState() -{ - m_pRootCtrl->SaveState(); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::RestoreState() -{ - m_pRootCtrl->RestoreState(); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SetEnabled(bool status) -{ - m_enabled = status; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SetInFocus(bool status) -{ - if (status) - { - m_inFocus = true; - } - else - { - CloseDPadMenu(); - m_inFocus = false; - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::Done() -{ - AzFramework::InputChannelEventListener::Disconnect(); -} - - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::Draw() -{ - FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_SYSTEM, g_bProfilerEnabled); - - // When console opened hide MiniGui - bool bConsoleOpened = gEnv->pConsole->IsOpened(); - if (m_enabled && !bConsoleOpened) - { - ProcessInput(); - - CDrawContext dc(&m_metrics); - dc.StartDrawing(); - { - // Draw all controls. - m_pRootCtrl->DrawCtrl(dc); - } - dc.StopDrawing(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::ProcessInput() -{ - //check we are not in digital selection mode - if (!m_pDPadMenu) - { - float mx(0), my(0); - AZ::Vector2 systemCursorPositionNormalized = AZ::Vector2::CreateZero(); - AzFramework::InputSystemCursorRequestBus::EventResult(systemCursorPositionNormalized, - AzFramework::InputDeviceMouse::Id, - &AzFramework::InputSystemCursorRequests::GetSystemCursorPositionNormalized); - mx = systemCursorPositionNormalized.GetX() * gEnv->pRenderer->GetWidth(); - my = systemCursorPositionNormalized.GetY() * gEnv->pRenderer->GetHeight(); - - //update moving control - if (m_pMovingCtrl) - { - m_pMovingCtrl->Move(mx, my); - } - - IMiniCtrl* pCtrl = GetCtrlFromPoint(mx, my); - if (pCtrl) - { - SetHighlight(pCtrl, true, mx, my); - } - else - { - SetHighlight(m_highlightedCtrl, false, mx, my); - } - } -} - -////////////////////////////////////////////////////////////////////////// -IMiniCtrl* CMiniGUI::GetCtrlFromPoint(float x, float y) const -{ - // Draw all controls. - return m_pRootCtrl->GetCtrlFromPoint(x, y); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SetHighlight(IMiniCtrl* pCtrl, bool bEnable, float x, float y) -{ - if (pCtrl) - { - if (m_highlightedCtrl && m_highlightedCtrl != pCtrl) - { - m_highlightedCtrl->OnEvent(x, y, eCtrlEvent_MouseOff); - m_highlightedCtrl->ClearFlag(eCtrl_Highlight); - } - - if (bEnable) - { - pCtrl->OnEvent(x, y, eCtrlEvent_MouseOver); - pCtrl->SetFlag(eCtrl_Highlight); - - m_highlightedCtrl = pCtrl; - } - else - { - pCtrl->OnEvent(x, y, eCtrlEvent_MouseOff); - pCtrl->ClearFlag(eCtrl_Highlight); - m_highlightedCtrl = NULL; - } - } - else - { - assert(bEnable == false); - - if (m_highlightedCtrl) - { - m_highlightedCtrl->OnEvent(x, y, eCtrlEvent_MouseOff); - m_highlightedCtrl->ClearFlag(eCtrl_Highlight); - m_highlightedCtrl = NULL; - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SetFocus(IMiniCtrl* pCtrl, bool bEnable) -{ - if (m_focusCtrl) - { - m_focusCtrl->ClearFlag(eCtrl_Focus); - } - m_focusCtrl = pCtrl; - if (m_focusCtrl) - { - if (bEnable) - { - m_focusCtrl->SetFlag(eCtrl_Focus); - } - else - { - m_focusCtrl->ClearFlag(eCtrl_Focus); - } - } -} - -////////////////////////////////////////////////////////////////////////// -SMetrics& CMiniGUI::Metrics() -{ - return m_metrics; -} - -////////////////////////////////////////////////////////////////////////// -IMiniCtrl* CMiniGUI::CreateCtrl(IMiniCtrl* pParentCtrl, int nCtrlID, EMiniCtrlType type, int nCtrlFlags, const Rect& rc, const char* title) -{ - CMiniCtrl* pCtrl = 0; - // Test code. - switch (type) - { - case eCtrlType_Button: - pCtrl = new CMiniButton; - break; - case eCtrlType_Menu: - pCtrl = new CMiniMenu; - break; - case eCtrlType_InfoBox: - pCtrl = new CMiniInfoBox; - break; - case eCtrlType_Table: - pCtrl = new CMiniTable; - break; - default: - assert(0 && "Unknown MiniGUI control type"); - break; - } - ; - if (pCtrl) - { - pCtrl->SetGUI(this); - pCtrl->SetFlag(nCtrlFlags); - pCtrl->SetTitle(title); - pCtrl->SetRect(rc); - pCtrl->SetId(nCtrlID); - - if (pCtrl->CheckFlag(eCtrl_AutoResize)) - { - pCtrl->AutoResize(); - } - - if (pCtrl->CheckFlag(eCtrl_CloseButton)) - { - pCtrl->CreateCloseButton(); - } - - if (pParentCtrl) - { - pParentCtrl->AddSubCtrl(pCtrl); - } - else - { - m_pRootCtrl->AddSubCtrl(pCtrl); - } - - if (type == eCtrlType_Menu && pParentCtrl == NULL) - { - m_rootMenus.push_back(pCtrl); - } - } - return pCtrl; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::OnCommand(SCommand& cmd) -{ - if (m_pEventListener) - { - m_pEventListener->OnCommand(cmd); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::OnMouseInputEvent(const AzFramework::InputChannel& inputChannel) -{ - if (!m_inFocus || !m_enabled) - { - return; - } - - const AzFramework::InputChannel::PositionData2D* positionData2D = inputChannel.GetCustomData(); - if (!positionData2D) - { - return; - } - const float mx = positionData2D->m_normalizedPosition.GetX() * gEnv->pRenderer->GetWidth(); - const float my = positionData2D->m_normalizedPosition.GetY() * gEnv->pRenderer->GetHeight(); - IMiniCtrl* pCtrl = GetCtrlFromPoint(mx, my); - if (pCtrl) - { - const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); - if (channelId == AzFramework::InputDeviceMouse::Button::Left) - { - if (inputChannel.IsStateBegan()) - { - pCtrl->OnEvent(mx, my, eCtrlEvent_LButtonDown); - } - else if (inputChannel.IsStateEnded()) - { - pCtrl->OnEvent(mx, my, eCtrlEvent_LButtonUp); - } - } - } -} - -void CMiniGUI::SetDPadMenu(IMiniCtrl* pMenu) -{ - m_pDPadMenu = (CMiniMenu*)pMenu; - UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter); -} - -void CMiniGUI::CloseDPadMenu() -{ - if (m_pDPadMenu) - { - CMiniMenu* closeMenu = m_pDPadMenu; - - //close menu and all parent menus - do - { - closeMenu->Close(); - closeMenu = (CMiniMenu*)closeMenu->GetParent(); - } while (closeMenu->GetType() == eCtrlType_Menu); - - m_pDPadMenu->ClearFlag(eCtrl_Highlight); - m_pDPadMenu = NULL; - UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter); - } -} - -void CMiniGUI::UpdateDPadMenu(const AzFramework::InputChannel& inputChannel) -{ - const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); - const bool isPressed = inputChannel.IsStateBegan(); - - if (m_pDPadMenu) - { - if (channelId == AzFramework::InputDeviceGamepad::Button::B) - { - CloseDPadMenu(); - return; - } - - if (isPressed) - { - if (channelId == AzFramework::InputDeviceGamepad::Button::DD || - channelId == AzFramework::InputDeviceGamepad::ThumbStickDirection::LD) - { - m_pDPadMenu = m_pDPadMenu->UpdateSelection(eCtrlEvent_DPadDown); - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::DU || - channelId == AzFramework::InputDeviceGamepad::ThumbStickDirection::LU) - { - m_pDPadMenu = m_pDPadMenu->UpdateSelection(eCtrlEvent_DPadUp); - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::DL || - channelId == AzFramework::InputDeviceGamepad::ThumbStickDirection::LL) - { - CMiniMenu* pNewMenu = m_pDPadMenu->UpdateSelection(eCtrlEvent_DPadLeft); - - //get previous root menu - if (pNewMenu == NULL) - { - int i = 0, nRootMenus = m_rootMenus.size(); - - for (i = 0; i < nRootMenus; i++) - { - if (m_rootMenus[i] == m_pDPadMenu) - { - break; - } - } - - if (i > 0) - { - m_pDPadMenu->Close(); - m_pDPadMenu->ClearFlag(eCtrl_Highlight); - - m_pDPadMenu = (CMiniMenu*)m_rootMenus[i - 1]; - m_pDPadMenu->Open(); - m_pDPadMenu->SetFlag(eCtrl_Highlight); - } - //else selected menu remains the same - } - else - { - m_pDPadMenu = pNewMenu; - } - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::DR || - channelId == AzFramework::InputDeviceGamepad::ThumbStickDirection::LR) - { - CMiniMenu* pNewMenu = m_pDPadMenu->UpdateSelection(eCtrlEvent_DPadRight); - - //get next root menu - if (pNewMenu == NULL) - { - int i = 0, nRootMenus = m_rootMenus.size(); - - for (i = 0; i < nRootMenus; i++) - { - if (m_rootMenus[i] == m_pDPadMenu) - { - break; - } - } - - if (i < nRootMenus - 1) - { - m_pDPadMenu->Close(); - m_pDPadMenu->ClearFlag(eCtrl_Highlight); - - m_pDPadMenu = (CMiniMenu*)m_rootMenus[i + 1]; - m_pDPadMenu->Open(); - m_pDPadMenu->SetFlag(eCtrl_Highlight); - } - //else selected menu remains the same - } - else - { - m_pDPadMenu = pNewMenu; - } - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::A) - { - m_pDPadMenu = m_pDPadMenu->UpdateSelection(eCtrlEvent_LButtonDown); - } - } - } -} - -bool CMiniGUI::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) -{ - const AzFramework::InputDeviceId& deviceId = inputChannel.GetInputDevice().GetInputDeviceId(); - if (AzFramework::InputDeviceMouse::IsMouseDevice(deviceId)) - { - OnMouseInputEvent(inputChannel); - return false; - } - - if (!m_inFocus) - { - return false; - } - - if (!AzFramework::InputDeviceGamepad::IsGamepadDevice(deviceId)) - { - return false; - } - - if (m_pDPadMenu) - { - UpdateDPadMenu(inputChannel); - } - else - { - float posX = 0.0f; - float posY = 0.0f; - const AzFramework::InputChannel::PositionData2D* positionData2D = inputChannel.GetCustomData(); - if (positionData2D) - { - posX = positionData2D->m_normalizedPosition.GetX() * gEnv->pRenderer->GetWidth(); - posY = positionData2D->m_normalizedPosition.GetY() * gEnv->pRenderer->GetHeight(); - } - - IMiniCtrl* pCtrl = GetCtrlFromPoint(posX, posY); - - if (pCtrl) - { - const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); - if (channelId == AzFramework::InputDeviceGamepad::Button::A) - { - switch (inputChannel.GetState()) - { - case AzFramework::InputChannel::State::Began: - pCtrl->OnEvent(posX, posY, eCtrlEvent_LButtonDown); - break; - - case AzFramework::InputChannel::State::Ended: - pCtrl->OnEvent(posX, posY, eCtrlEvent_LButtonUp); - break; - - case AzFramework::InputChannel::State::Updated: - pCtrl->OnEvent(posX, posY, eCtrlEvent_LButtonPressed); - - //if we've clicked on a menu, enter menu selection mode, disable mouse - if (pCtrl->GetType() == eCtrlType_Menu) - { - SetDPadMenu(pCtrl); - } - - break; - } - } - } - } - - return false; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::SetEventListener(IMiniGUIEventListener* pListener) -{ - m_pEventListener = pListener; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniGUI::RemoveAllCtrl() -{ - m_highlightedCtrl = NULL; - - //reset all console variables to default state - Reset(); - - m_pRootCtrl->RemoveAllSubCtrl(); -} - -////////////////////////////////////////////////////////////////////////// -//CMiniCtrl -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::Reset() -{ - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->Reset(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::SaveState() -{ - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->SaveState(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::RestoreState() -{ - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->RestoreState(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::AddSubCtrl(IMiniCtrl* pCtrl) -{ - assert(pCtrl); - _smart_ptr pTempCtrl(pCtrl); - IMiniCtrl* pParent = pCtrl->GetParent(); - if (pParent) - { - pParent->RemoveSubCtrl(pCtrl); - } - - static_cast(pCtrl)->m_pParent = this; - m_subCtrls.push_back(pCtrl); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::RemoveSubCtrl(IMiniCtrl* pCtrl) -{ - assert(pCtrl); - _smart_ptr pTempCtrl(pCtrl); - IMiniCtrl* pParent = pCtrl->GetParent(); - if (pParent == this) - { - static_cast(pCtrl)->m_pParent = 0; - for (int i = 0, num = (int)m_subCtrls.size(); i < num; i++) - { - if (m_subCtrls[i] == pCtrl) - { - m_subCtrls.erase(m_subCtrls.begin() + i); - break; - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::RemoveAllSubCtrl() -{ - int nSubCtrls = m_subCtrls.size(); - - if (nSubCtrls) - { - for (int i = 0; i < nSubCtrls; i++) - { - IMiniCtrl* pSubCtrl = m_subCtrls[i].get(); - pSubCtrl->RemoveAllSubCtrl(); - } - - m_subCtrls.clear(); - } -} - -////////////////////////////////////////////////////////////////////////// -IMiniCtrl* CMiniCtrl::GetCtrlFromPoint(float x, float y) -{ - if (is_flag(eCtrl_Hidden)) - { - return 0; - } - - for (int i = 0, num = (int)m_subCtrls.size(); i < num; i++) - { - float lx = x - m_rect.left; - float ly = y - m_rect.top; - IMiniCtrl* pHit = m_subCtrls[i]->GetCtrlFromPoint(lx, ly); - if (pHit) - { - return pHit; - } - } - if (m_rect.IsPointInside(x, y)) - { - return this; - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::DrawCtrl(CDrawContext& dc) -{ - OnPaint(dc); - - dc.PushClientRect(m_rect); - - for (int i = 0, num = (int)m_subCtrls.size(); i < num; i++) - { - CMiniCtrl* pCtrl = static_cast((IMiniCtrl*)m_subCtrls[i]); - if (!pCtrl->is_flag(eCtrl_Hidden)) - { - pCtrl->DrawCtrl(dc); - } - } - - dc.PopClientRect(); -} - -////////////////////////////////////////////////////////////////////////// -int CMiniCtrl::GetSubCtrlCount() const -{ - return (int)m_subCtrls.size(); -} - -////////////////////////////////////////////////////////////////////////// -IMiniCtrl* CMiniCtrl::GetSubCtrl(int nIndex) const -{ - assert(nIndex >= 0 && nIndex < (int)m_subCtrls.size()); - return m_subCtrls[nIndex]; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::SetRect(const Rect& rc) -{ - m_rect = rc; - - if (m_pCloseButton) - { - float width = rc.Width(); - - //relative position of cross box - Rect closeRect(width - 20.f, 0.f, width, 20.f); - m_pCloseButton->SetRect(closeRect); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::SetVisible(bool state) -{ - if (state) - { - clear_flag(eCtrl_Hidden); - } - else - { - set_flag(eCtrl_Hidden); - } - - if (m_pCloseButton) - { - m_pCloseButton->SetVisible(state); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::AutoResize() -{ - uint32 stringLen = m_title.length(); - - if (stringLen) - { - //just an approximation for now - should take into account font size / kerning - m_rect.right = m_rect.left + (8.5f * stringLen); - } - - m_requiresResize = false; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::StartMoving(float x, float y) -{ - if (!m_moving) - { - m_prevX = x; - m_prevY = y; - m_moving = true; - - m_pGUI->SetMovingCtrl(this); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::StopMoving() -{ - if (m_moving) - { - m_moving = false; - m_pGUI->SetMovingCtrl(NULL); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::Move(float x, float y) -{ - if (m_moving) - { - float moveX = x - m_prevX; - float moveY = y - m_prevY; - - m_rect.top += moveY; - m_rect.bottom += moveY; - - m_rect.left += moveX; - m_rect.right += moveX; - - m_prevX = x; - m_prevY = y; - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::OnEvent(float x, float y, EMiniCtrlEvent event) -{ - switch (event) - { - case eCtrlEvent_LButtonDown: - { - if (is_flag(eCtrl_Highlight | eCtrl_Moveable)) - { - StartMoving(x, y); - } - } - break; - - case eCtrlEvent_LButtonUp: - if (m_moving) - { - StopMoving(); - } - break; - - case eCtrlEvent_MouseOver: - break; - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniCtrl::CreateCloseButton() -{ - if (m_pGUI) - { - m_pCloseButton = m_pGUI->CreateCtrl(this, 100, eCtrlType_Button, 0, Rect(0, 0, 100, 20), "X"); - - if (m_pCloseButton) - { - m_pCloseButton->SetConnectedCtrl(this); - - float width = m_rect.Width(); - - //relative position of cross box - Rect closeRect(width - 20.f, 0.f, width, 20.f); - m_pCloseButton->SetRect(closeRect); - } - } -} - -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.h b/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.h deleted file mode 100644 index a4db53070f..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniGUI.h +++ /dev/null @@ -1,219 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Mini GUI subsystem - - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIGUI_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIGUI_H -#pragma once - - -#include "ICryMiniGUI.h" -#include - -#include - -#include - -MINIGUI_BEGIN - -class CMiniMenu; - -////////////////////////////////////////////////////////////////////////// -// Root window all other controls derive from -class CMiniCtrl - : public IMiniCtrl -{ -public: - - CMiniCtrl() - : m_nFlags(0) - , m_id(0) - , m_renderCallback(NULL) - , m_fTextSize(12.f) - , m_prevX(0.f) - , m_prevY(0.f) - , m_moving(false) - , m_requiresResize(false) - , m_pCloseButton(NULL) - , m_saveStateOn(false) - {}; - - ////////////////////////////////////////////////////////////////////////// - // IMiniCtrl interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - - virtual void SetGUI(IMiniGUI* pGUI) { m_pGUI = pGUI; }; - virtual IMiniGUI* GetGUI() const { return m_pGUI; }; - - virtual int GetId() const { return m_id; }; - virtual void SetId(int id) { m_id = id; }; - - virtual const char* GetTitle() const { return m_title; }; - virtual void SetTitle(const char* title) { m_title = title; }; - - virtual Rect GetRect() const { return m_rect; } - virtual void SetRect(const Rect& rc); - - virtual void SetFlag(uint32 flag) { set_flag(flag); } - virtual void ClearFlag(uint32 flag) { clear_flag(flag); }; - virtual bool CheckFlag(uint32 flag) const { return is_flag(flag); } - - virtual void AddSubCtrl(IMiniCtrl* pCtrl); - virtual void RemoveSubCtrl(IMiniCtrl* pCtrl); - virtual void RemoveAllSubCtrl(); - virtual int GetSubCtrlCount() const; - virtual IMiniCtrl* GetSubCtrl(int nIndex) const; - virtual IMiniCtrl* GetParent() const { return m_pParent; }; - - virtual IMiniCtrl* GetCtrlFromPoint(float x, float y); - - virtual void SetVisible(bool state); - - virtual void OnEvent(float x, float y, EMiniCtrlEvent); - - virtual bool SetRenderCallback(RenderCallback callback) { m_renderCallback = callback; return true; }; - - - // Not implemented in base control - virtual bool SetControlCVar([[maybe_unused]] const char* sCVarName, [[maybe_unused]] float fOffValue, [[maybe_unused]] float fOnValue) { assert(0); return false; }; - virtual bool SetClickCallback([[maybe_unused]] ClickCallback callback, [[maybe_unused]] void* pCallbackData) { assert(0); return false; }; - virtual bool SetConnectedCtrl([[maybe_unused]] IMiniCtrl* pConnectedCtrl) { assert(0); return false; }; - - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - virtual void AutoResize(); - - ////////////////////////////////////////////////////////////////////////// - virtual void CreateCloseButton(); - - void DrawCtrl(CDrawContext& dc); - - virtual void Move(float x, float y); - -protected: - void set_flag(uint32 flag) { m_nFlags |= flag; } - void clear_flag(uint32 flag) { m_nFlags &= ~flag; }; - bool is_flag(uint32 flag) const { return (m_nFlags & flag) == flag; } - - //dynamic movement - void StartMoving(float x, float y); - void StopMoving(); - -protected: - int m_id; - IMiniGUI* m_pGUI; - uint32 m_nFlags; - CryFixedStringT<32> m_title; - Rect m_rect; - _smart_ptr m_pParent; - std::vector m_subCtrls; - RenderCallback m_renderCallback; - float m_fTextSize; - - //optional close 'X' button on controls, ref counted by m_subCtrls - IMiniCtrl* m_pCloseButton; - - //dynamic movement - float m_prevX; - float m_prevY; - bool m_moving; - bool m_requiresResize; - bool m_saveStateOn; -}; - -////////////////////////////////////////////////////////////////////////// -class CMiniGUI - : public IMiniGUI - , public AzFramework::InputChannelEventListener -{ -public: - CRYINTERFACE_BEGIN() - CRYINTERFACE_ADD(IMiniGUI) - CRYINTERFACE_END() - CRYGENERATE_SINGLETONCLASS(CMiniGUI, "MiniGUI", 0x1a049b879a4e4b58, 0xac14026e17e6255e) - -public: - void InitMetrics(); - void ProcessInput(); - - ////////////////////////////////////////////////////////////////////////// - // IMiniGUI interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual void Init(); - virtual void Done(); - virtual void Draw(); - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - virtual void SetEnabled(bool status); - virtual void SetInFocus(bool status); - virtual bool InFocus() {return m_inFocus; } - - virtual void SetEventListener(IMiniGUIEventListener* pListener); - - virtual SMetrics& Metrics(); - - virtual void OnCommand(SCommand& cmd); - - virtual void RemoveAllCtrl(); - virtual IMiniCtrl* CreateCtrl(IMiniCtrl* pParentCtrl, int nCtrlID, EMiniCtrlType type, int nCtrlFlags, const Rect& rc, const char* title); - - virtual IMiniCtrl* GetCtrlFromPoint(float x, float y) const; - - void SetHighlight(IMiniCtrl* pCtrl, bool bEnable, float x, float y); - void SetFocus(IMiniCtrl* pCtrl, bool bEnable); - - // AzFramework::InputChannelEventListener - bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - AZ::s32 GetPriority() const override { return AzFramework::InputChannelEventListener::GetPriorityUI(); } - - virtual void SetMovingCtrl(IMiniCtrl* pCtrl) - { - m_pMovingCtrl = pCtrl; - } - -protected: - void OnMouseInputEvent(const AzFramework::InputChannel& inputChannel); - - //DPad menu navigation - void UpdateDPadMenu(const AzFramework::InputChannel& inputChannel); - void SetDPadMenu(IMiniCtrl* pMenu); - void CloseDPadMenu(); - -protected: - bool m_enabled; - bool m_inFocus; - - SMetrics m_metrics; - - _smart_ptr m_pRootCtrl; - - _smart_ptr m_highlightedCtrl; - _smart_ptr m_focusCtrl; - - IMiniGUIEventListener* m_pEventListener; - - CMiniMenu* m_pDPadMenu; - IMiniCtrl* m_pMovingCtrl; - std::vector m_rootMenus; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIGUI_H diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.cpp b/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.cpp deleted file mode 100644 index 74114b9156..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#include "CrySystem_precompiled.h" -#include "MiniInfoBox.h" -#include "DrawContext.h" -#include - -MINIGUI_BEGIN - - -CMiniInfoBox::CMiniInfoBox() - : m_fTextIndent(4) -{ -} - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::SaveState() -{ - if (CheckFlag(eCtrl_Hidden)) - { - m_saveStateOn = false; - } - else - { - m_saveStateOn = true; - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::Reset() -{ - SetFlag(eCtrl_Hidden); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::RestoreState() -{ - if (m_saveStateOn) - { - ClearFlag(eCtrl_Hidden); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::OnPaint(CDrawContext& dc) -{ - if (m_requiresResize) - { - AutoResize(); - } - - ColorB borderCol = dc.Metrics().clrFrameBorder; - ColorB backgroundCol = dc.Metrics().clrBackground; - - if (!m_pGUI->InFocus()) - { - borderCol = dc.Metrics().clrFrameBorderOutOfFocus; - backgroundCol.a = dc.Metrics().outOfFocusAlpha; - } - else if (m_moving) - { - borderCol = dc.Metrics().clrFrameBorderHighlight; - } - - dc.DrawFrame(m_rect, borderCol, backgroundCol); - - dc.SetColor(dc.Metrics().clrTitle); - dc.DrawString(m_rect.left + 4, m_rect.top, dc.Metrics().fTitleSize, eTextAlign_Left, GetTitle()); - - float fTextSize = m_fTextSize; - if (fTextSize == 0) - { - fTextSize = dc.Metrics().fTextSize; - } - - float x = m_fTextIndent + m_rect.left + 8; - float y = m_rect.top + fTextSize + fTextSize; - // Draw entries. - for (int i = 0, num = (int)m_entries.size(); i < num; i++) - { - SInfoEntry& info = m_entries[i]; - dc.SetColor(info.color); - dc.DrawString(x, y, info.textSize, eTextAlign_Left, info.text); - y += info.textSize * 0.8f; - if (y + info.textSize > m_rect.bottom) - { - break; - } - } - - if (m_renderCallback) - { - m_renderCallback(m_rect.left, m_rect.top); - } -} - - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::OnEvent(float x, float y, EMiniCtrlEvent event) -{ - CMiniCtrl::OnEvent(x, y, event); -} - -void CMiniInfoBox::AddEntry(const char* str, ColorB col, float textSize) -{ - SInfoEntry info; - - info.color = col; - info.textSize = textSize; - cry_strcpy(info.text, str); - - m_entries.push_back(info); - - if (CheckFlag(eCtrl_AutoResize)) - { - //set dirty flag instead of resizing for every elem - m_requiresResize = true; //AutoResize(); - } -} - -void CMiniInfoBox::ClearEntries() -{ - m_entries.clear(); - m_requiresResize = true; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniInfoBox::AutoResize() -{ - float width = 0.f; - float height = 32.f; - - //must be at least the size of title and cross box - width = m_fTextIndent + ((float)m_title.size() * 14.f) + 30.f; - - for (int i = 0, num = (int)m_entries.size(); i < num; i++) - { - SInfoEntry& info = m_entries[i]; - - uint32 strLength = strlen(info.text); - - float strSize = info.textSize * strLength; - - width = max(strSize, width); - height += info.textSize * 0.8f; - } - - //scale width, could do with kerning info - width *= 0.6f; - - Rect newRect = m_rect; - newRect.right = newRect.left + width; - newRect.bottom = newRect.top + height; - - SetRect(newRect); - - m_requiresResize = false; -} - -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.h b/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.h deleted file mode 100644 index dbe8a668d6..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniInfoBox.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIINFOBOX_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIINFOBOX_H -#pragma once - - -#include "MiniGUI.h" - -MINIGUI_BEGIN - -////////////////////////////////////////////////////////////////////////// -// Root window all other controls derive from -class CMiniInfoBox - : public CMiniCtrl - , public IMiniInfoBox -{ -public: - CMiniInfoBox(); - - ////////////////////////////////////////////////////////////////////////// - // CMiniCtrl interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual EMiniCtrlType GetType() const { return eCtrlType_InfoBox; } - virtual void OnPaint(CDrawContext& dc); - virtual void OnEvent(float x, float y, EMiniCtrlEvent event); - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - virtual void AutoResize(); - ////////////////////////////////////////////////////////////////////////// - - virtual void SetTextIndent(float x) { m_fTextIndent = x; } - virtual void SetTextSize(float sz) { m_fTextSize = sz; } - virtual void ClearEntries(); - virtual void AddEntry(const char* str, ColorB col, float textSize); - - ////////////////////////////////////////////////////////////////////////// - // IMiniTable interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual bool IsHidden() { return CheckFlag(eCtrl_Hidden); } - virtual void Hide(bool stat) { SetVisible(!stat); } - -public: - - ////////////////////////////////////////////////////////////////////////// - - static const int MAX_TEXT_LENGTH = 64; - - struct SInfoEntry - { - char text[MAX_TEXT_LENGTH]; - ColorB color; - float textSize; - }; - ////////////////////////////////////////////////////////////////////////// - -protected: - - std::vector m_entries; - float m_fTextIndent; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIINFOBOX_H diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.cpp b/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.cpp deleted file mode 100644 index f905f0f998..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#include "CrySystem_precompiled.h" -#include "MiniMenu.h" -#include "DrawContext.h" - -MINIGUI_BEGIN - - -CMiniMenu::CMiniMenu() -{ - m_bVisible = false; - m_bSubMenu = false; - m_menuWidth = 0.f; - m_selectionIndex = -1; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::OnPaint(CDrawContext& dc) -{ - CMiniButton::OnPaint(dc); - - if (m_bSubMenu) - { - // Draw checked mark. - float x1 = m_rect.right - 12; - float y1 = m_rect.top + 3; - - float x2 = m_rect.right - 3; - float y2 = (m_rect.bottom + m_rect.top) / 2; - - float x3 = m_rect.right - 12; - float y3 = m_rect.bottom - 3; - - dc.SetColor(ColorB(0, 0, 0, 255)); - - dc.DrawLine(x1, y1, x2, y2, 2.f); - dc.DrawLine(x2, y2, x3, y3, 2.f); - - x1 -= 1; - x2 -= 1; - x3 -= 1; - y1 -= 1; - y2 -= 1; - y3 -= 1; - - dc.SetColor(ColorB(255, 255, 255, 255)); - - dc.DrawLine(x1, y1, x2, y2, 2.f); - dc.DrawLine(x2, y2, x3, y3, 2.f); - } - - - //dc.DrawFrame( m_rect,dc.Metrics().clrFrameBorder,dc.Metrics().clrBackground ); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::SetRect(const Rect& rc) -{ - Rect newrc = rc; - newrc.bottom = newrc.top + m_pGUI->Metrics().fTitleSize + 2; - CMiniCtrl::SetRect(newrc); -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::OnEvent(float x, float y, EMiniCtrlEvent event) -{ - switch (event) - { - case eCtrlEvent_LButtonDown: - { - if (m_bVisible) - { - Close(); - } - else - { - Open(); - } - } - break; - case eCtrlEvent_MouseOff: - { - bool closeMenu = true; - IMiniCtrl* pCtrl = m_pGUI->GetCtrlFromPoint(x, y); - - //check if the cursor is still in one of the menu's children - if (pCtrl) - { - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - if (pCtrl == GetSubCtrl(i)) - { - closeMenu = false; - break; - } - } - } - - if (closeMenu) - { - Close(); - - if (m_pParent) - { - m_pParent->OnEvent(x, y, eCtrlEvent_MouseOff); - } - } - } - break; - } -} - -CMiniMenu* CMiniMenu::UpdateSelection(EMiniCtrlEvent event) -{ - CMiniMenu* pNewMenu = this; - IMiniCtrl* pCurrentSelection = NULL; - - if (m_selectionIndex != -1) - { - pCurrentSelection = m_subCtrls[m_selectionIndex]; - } - - switch (event) - { - case eCtrlEvent_DPadLeft: //move to parent - if (!pCurrentSelection) - { - //move to previous root menu - pNewMenu = NULL; - } - else if (m_bSubMenu) - { - Close(); - pNewMenu = (CMiniMenu*)m_pParent.get(); - //pNewMenu->SetFlag(eCtrl_Highlight); - } - break; - - case eCtrlEvent_DPadRight: //move to child - if (!pCurrentSelection) - { - //move to next root menu - pNewMenu = NULL; - } - else if (pCurrentSelection->GetType() == eCtrlType_Menu) - { - pNewMenu = (CMiniMenu*)pCurrentSelection; - pNewMenu->Open(); - pNewMenu->ClearFlag(eCtrl_Highlight); - } - break; - - case eCtrlEvent_DPadUp: //move up list - if (m_bSubMenu) - { - if (m_selectionIndex > 0) - { - m_selectionIndex--; - } - } - else - { - if (m_selectionIndex >= 0) - { - m_selectionIndex--; - - if (m_selectionIndex == -1) - { - SetFlag(eCtrl_Highlight); - } - } - } - break; - - case eCtrlEvent_DPadDown: //move down the list - if (m_selectionIndex < (int)(m_subCtrls.size() - 1)) - { - if (m_selectionIndex == -1) - { - ClearFlag(eCtrl_Highlight); - } - m_selectionIndex++; - } - break; - - case eCtrlEvent_LButtonDown: //pass on button press - { - if (pCurrentSelection) - { - if (pCurrentSelection->GetType() == eCtrlType_Menu) - { - pNewMenu = (CMiniMenu*)pCurrentSelection; - } - pCurrentSelection->OnEvent(0, 0, eCtrlEvent_LButtonDown); - } - else - { - OnEvent(0, 0, eCtrlEvent_LButtonDown); - } - } - break; - } - - if (pCurrentSelection) - { - pCurrentSelection->ClearFlag(eCtrl_Highlight); - } - - if (m_selectionIndex >= 0) - { - m_subCtrls[m_selectionIndex]->SetFlag(eCtrl_Highlight); - } - - return pNewMenu; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::Open() -{ - m_bVisible = true; - - Rect rc(0, 0, m_menuWidth, 1); - - //render sub menu to the right - if (m_bSubMenu) - { - CMiniMenu* pParent = static_cast(m_pParent.get()); - rc.left = pParent->m_menuWidth; //rcParent.right; - rc.right = rc.left + m_menuWidth; - } - else - { - Rect rcThis = GetRect(); - rc.top = rcThis.Height(); - } - - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->ClearFlag(eCtrl_Hidden); - float h = pSubCtrl->GetRect().Height(); - Rect rcCtrl = rc; - rcCtrl.top = rc.top; - rcCtrl.bottom = rcCtrl.top + h; - pSubCtrl->SetRect(rcCtrl); - rc.top += h; - } - - //highlight first item when opened - if (m_bSubMenu) - { - m_selectionIndex = 0; - m_subCtrls[m_selectionIndex]->SetFlag(eCtrl_Highlight); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::Close() -{ - m_bVisible = false; - - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->SetFlag(eCtrl_Hidden); - } - - if (m_selectionIndex != -1) - { - m_subCtrls[m_selectionIndex]->ClearFlag(eCtrl_Highlight); - } - m_selectionIndex = -1; -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::Reset() -{ - m_bVisible = false; - - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->Reset(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::SaveState() -{ - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->SaveState(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::RestoreState() -{ - for (int i = 0, num = GetSubCtrlCount(); i < num; i++) - { - IMiniCtrl* pSubCtrl = GetSubCtrl(i); - pSubCtrl->RestoreState(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CMiniMenu::AddSubCtrl(IMiniCtrl* pCtrl) -{ - assert(pCtrl); - pCtrl->SetFlag(eCtrl_Hidden); - pCtrl->SetFlag(eCtrl_NoBorder); - - bool bSubMenu = false; - - if (pCtrl->GetType() == eCtrlType_Menu) - { - CMiniMenu* pSubMenu = static_cast(pCtrl); - pSubMenu->m_bSubMenu = true; - bSubMenu = true; - } - - if (!m_bSubMenu) - { - //menu is at least the size of title bar - m_menuWidth = max(m_menuWidth, strlen(GetTitle()) * 8.5f); - } - - const char* title = pCtrl->GetTitle(); - - if (title) - { - uint32 titleLen = strlen(title); - - float width = (float)titleLen * 8.5f; - - if (bSubMenu) - { - //increase width for submenu arrow - width += 10.f; - } - - m_menuWidth = max(m_menuWidth, width); - } - - // Call parent - CMiniButton::AddSubCtrl(pCtrl); -} -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.h b/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.h deleted file mode 100644 index c288d840df..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniMenu.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIMENU_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIMENU_H -#pragma once - - -#include "MiniGUI.h" -#include "MiniButton.h" - -MINIGUI_BEGIN - -////////////////////////////////////////////////////////////////////////// -// Root window all other controls derive from -class CMiniMenu - : public CMiniButton -{ -public: - CMiniMenu(); - - ////////////////////////////////////////////////////////////////////////// - // CMiniCtrl interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual EMiniCtrlType GetType() const { return eCtrlType_Menu; } - virtual void SetRect(const Rect& rc); - virtual void OnPaint(CDrawContext& dc); - virtual void OnEvent(float x, float y, EMiniCtrlEvent event); - virtual void AddSubCtrl(IMiniCtrl* pCtrl); - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - ////////////////////////////////////////////////////////////////////////// - - //digital selection funcs - CMiniMenu* UpdateSelection(EMiniCtrlEvent event); - - void Open(); - void Close(); - -protected: - -protected: - bool m_bVisible; - bool m_bSubMenu; - float m_menuWidth; - - int m_selectionIndex; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_MINIMENU_H diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniTable.cpp b/Code/CryEngine/CrySystem/MiniGUI/MiniTable.cpp deleted file mode 100644 index 6a306a2f9e..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniTable.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Table implementation in the MiniGUI - - -#include "CrySystem_precompiled.h" -#include "MiniTable.h" -#include "DrawContext.h" - -#include - -MINIGUI_BEGIN - -CMiniTable::CMiniTable() -{ - m_fTextSize = 15.f; - m_pageNum = 0; - m_pageSize = 35; -} - -void CMiniTable::OnPaint(CDrawContext& dc) -{ - if (m_requiresResize) - { - AutoResize(); - } - - ColorB borderCol; - ColorB backgroundCol = dc.Metrics().clrBackground; - - if (m_pGUI->InFocus()) - { - if (m_moving) - { - borderCol = dc.Metrics().clrFrameBorderHighlight; - } - else - { - borderCol = dc.Metrics().clrFrameBorder; - } - } - else - { - borderCol = dc.Metrics().clrFrameBorderOutOfFocus; - backgroundCol.a = dc.Metrics().outOfFocusAlpha; - } - - dc.DrawFrame(m_rect, borderCol, backgroundCol); - - float fTextSize = m_fTextSize; - if (fTextSize == 0) - { - fTextSize = dc.Metrics().fTextSize; - } - - float indent = 4.f; - - float x = m_rect.left + indent; - float y = m_rect.top + indent; - - const int nColumns = m_columns.size(); - int numEntries = nColumns > 0 ? m_columns[0].cells.size() : 0; - - int startIdx = 0; - int endIdx = numEntries; - - //Page number - if (nColumns) - { - int numPages = numEntries / m_pageSize; - - if (numPages) - { - startIdx = m_pageNum * m_pageSize; - endIdx = min(startIdx + m_pageSize, numEntries); - dc.SetColor(ColorB(255, 255, 255, 255)); - - //print page details (adjust for zero indexed) - dc.DrawString(x, y, fTextSize, eTextAlign_Left, "Page %d of %d (Page Up / Page Down)", m_pageNum + 1, numPages + 1); - y += fTextSize; - } - } - - float topOfTable = y; - - for (int i = 0; i < nColumns; i++) - { - SColumn& column = m_columns[i]; - - y = topOfTable; - - dc.SetColor(ColorB(32, 32, 255, 255)); - - dc.DrawString(x, y, fTextSize, eTextAlign_Left, column.name); - y += fTextSize + indent; - - ColorB currentCol(255, 255, 255, 255); - - dc.SetColor(currentCol); - - const int nCells = column.cells.size(); - - for (int j = startIdx; j < endIdx && j < nCells; j++) - { - if (column.cells[j].col != currentCol) - { - dc.SetColor(column.cells[j].col); - currentCol = column.cells[j].col; - } - - dc.DrawString(x, y, fTextSize, eTextAlign_Left, column.cells[j].text); - y += fTextSize; - } - - x += column.width; - } -} - -void CMiniTable::OnEvent(float x, float y, EMiniCtrlEvent event) -{ - //movement - CMiniCtrl::OnEvent(x, y, event); -} - -void CMiniTable::AutoResize() -{ - //must be at least the size of cross box - float tableWidth = 30.f; - - float tableHeight = 0.f; - const float widthScale = 0.6f; - const int nColumns = m_columns.size(); - - int startIdx = 0; - int endIdx = 0; - - bool bPageHeader = false; - - //Update Page index - if (nColumns) - { - int numEntries = m_columns[0].cells.size(); - - //page index is now invalid, cap at max - if ((m_pageNum * m_pageSize) > numEntries) - { - m_pageNum = (numEntries / m_pageSize); - } - - startIdx = m_pageNum * m_pageSize; - endIdx = min(startIdx + m_pageSize, numEntries); - - if (numEntries > m_pageSize) - { - bPageHeader = true; - } - } - - for (int i = 0; i < nColumns; i++) - { - SColumn& column = m_columns[i]; - - float width = strlen(column.name) * m_fTextSize; - - int nCells = column.cells.size(); - - for (int j = startIdx; j < endIdx && j < nCells; j++) - { - width = max(width, strlen(column.cells[j].text) * m_fTextSize); - } - - width *= widthScale; - - column.width = width; - tableWidth += width; - tableHeight = max(tableHeight, min(endIdx - startIdx, m_pageSize) * m_fTextSize); - } - - tableHeight += m_fTextSize * 2.f; - - //Page index - if (bPageHeader) - { - tableHeight += m_fTextSize; - } - - Rect newRect = m_rect; - - newRect.right = newRect.left + tableWidth; - newRect.bottom = newRect.top + tableHeight; - - SetRect(newRect); - - m_requiresResize = false; -} - -void CMiniTable::Reset() -{ - SetFlag(eCtrl_Hidden); - - m_pageNum = 0; -} - -void CMiniTable::SaveState() -{ - if (CheckFlag(eCtrl_Hidden)) - { - m_saveStateOn = false; - } - else - { - m_saveStateOn = true; - } -} - -void CMiniTable::RestoreState() -{ - if (m_saveStateOn) - { - ClearFlag(eCtrl_Hidden); - } -} - -int CMiniTable::AddColumn(const char* name) -{ - assert(name); - - SColumn col; - - cry_strcpy(col.name, name); - col.width = strlen(col.name) * 8.f; - - m_columns.push_back(col); - - m_requiresResize = true; - - return m_columns.size() - 1; -} - -void CMiniTable::RemoveColumns() -{ - m_columns.clear(); -} - -int CMiniTable::AddData(int columnIndex, ColorB col, const char* format, ...) -{ - assert(columnIndex < (int)m_columns.size()); - - SCell cell; - - va_list args; - va_start(args, format); - int written = vsnprintf_s(cell.text, MAX_TEXT_LENGTH, MAX_TEXT_LENGTH - 1, format, args); - va_end(args); - - if (written == -1) - { - cell.text[MAX_TEXT_LENGTH - 1] = '\0'; - } - - cell.col = col; - - m_columns[columnIndex].cells.push_back(cell); - - m_requiresResize = true; - - return m_columns[columnIndex].cells.size() - 1; -} - -void CMiniTable::ClearTable() -{ - const int nColumns = m_columns.size(); - - for (int i = 0; i < nColumns; i++) - { - m_columns[i].cells.clear(); - } -} - -void CMiniTable::SetVisible(bool state) -{ - if (state) - { - clear_flag(eCtrl_Hidden); - AzFramework::InputChannelEventListener::Connect(); - } - else - { - set_flag(eCtrl_Hidden); - AzFramework::InputChannelEventListener::Disconnect(); - } - - if (m_pCloseButton) - { - m_pCloseButton->SetVisible(state); - } -} - -void CMiniTable::Hide(bool stat) -{ - SetVisible(!stat); -} - -bool CMiniTable::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) -{ - if (!IsHidden() && inputChannel.IsStateBegan()) - { - const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); - if (channelId == AzFramework::InputDeviceKeyboard::Key::NavigationPageUp) - { - m_pageNum++; - m_requiresResize = true; - } - else if (channelId == AzFramework::InputDeviceKeyboard::Key::NavigationPageDown) - { - if (m_pageNum > 0) - { - m_pageNum--; - m_requiresResize = true; - } - } - } - return false; -} -MINIGUI_END diff --git a/Code/CryEngine/CrySystem/MiniGUI/MiniTable.h b/Code/CryEngine/CrySystem/MiniGUI/MiniTable.h deleted file mode 100644 index fb89aca2dc..0000000000 --- a/Code/CryEngine/CrySystem/MiniGUI/MiniTable.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Table implementation in the MiniGUI - - -#ifndef CRYINCLUDE_CRYSYSTEM_MINIGUI_MINITABLE_H -#define CRYINCLUDE_CRYSYSTEM_MINIGUI_MINITABLE_H -#pragma once - - -#include "MiniGUI.h" - -MINIGUI_BEGIN - -class CMiniTable - : public CMiniCtrl - , public IMiniTable - , public AzFramework::InputChannelEventListener -{ -public: - CMiniTable(); - - ////////////////////////////////////////////////////////////////////////// - // CMiniCtrl interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual EMiniCtrlType GetType() const { return eCtrlType_Table; } - virtual void OnPaint(CDrawContext& dc); - virtual void OnEvent(float x, float y, EMiniCtrlEvent event); - virtual void Reset(); - virtual void SaveState(); - virtual void RestoreState(); - virtual void AutoResize(); - virtual void SetVisible(bool state); - - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // IMiniTable interface implementation. - ////////////////////////////////////////////////////////////////////////// - - //Add a new column to the table, return column index - virtual int AddColumn(const char* name); - - //Remove all columns an associated data - virtual void RemoveColumns(); - - //Add data to specified column (add onto the end), return row index - virtual int AddData(int columnIndex, ColorB col, const char* format, ...); - - //Clear all data from table - virtual void ClearTable(); - - virtual bool IsHidden() { return CheckFlag(eCtrl_Hidden); } - - virtual void Hide(bool stat); - - // AzFramework::InputChannelEventListener - bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - AZ::s32 GetPriority() const override { return AzFramework::InputChannelEventListener::GetPriorityUI(); } - - static const int MAX_TEXT_LENGTH = 64; - -protected: - - struct SCell - { - char text[MAX_TEXT_LENGTH]; - ColorB col; - }; - - struct SColumn - { - char name[MAX_TEXT_LENGTH]; - float width; - std::vector cells; - }; - - std::vector m_columns; - int m_pageSize; - int m_pageNum; -}; - -MINIGUI_END - -#endif // CRYINCLUDE_CRYSYSTEM_MINIGUI_MINITABLE_H diff --git a/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.cpp b/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.cpp deleted file mode 100644 index 044d44fade..0000000000 --- a/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Manages overload values (eg CPU,GPU etc) -// 1.0="everything is ok" 0.0="very bad frame rate" -// various systems can use this information and control what is currently in the scene - - -#include "CrySystem_precompiled.h" -#include "OverloadSceneManager.h" - -//-------------------------------------------------------------------------------------------------- -// Name: COverloadSceneManager -// Desc: Constructor -//-------------------------------------------------------------------------------------------------- -COverloadSceneManager::COverloadSceneManager() -{ - InitialiseCVars(); - - m_currentFrameStat = 0; - - ResetDefaultValues(); -}//------------------------------------------------------------------------------------------------- - -//-------------------------------------------------------------------------------------------------- -// Desc: static console callback functions -//-------------------------------------------------------------------------------------------------- -static void OnChange_osm_enabled(ICVar* pCVar) -{ - if (pCVar->GetIVal() == 0) - { - gEnv->pOverloadSceneManager->Reset(); - //gEnv->pRenderer->EnablePipelineProfiler(false); // would need push/pop since something else might have enabled it - } - else if (pCVar->GetIVal() == 1) - { - gEnv->pRenderer->EnablePipelineProfiler(true); - } -} - -static void cmd_setFBScale(IConsoleCmdArgs* pParams) -{ - int argCount = pParams->GetArgCount(); - - Vec2 newScale = Vec2(0.0f, 0.0f); - gEnv->pRenderer->EF_Query(EFQ_GetViewportDownscaleFactor, newScale); - - if (argCount > 1) - { - newScale.x = clamp_tpl((float)atof(pParams->GetArg(1)), 0.0f, 1.0f); - - if (argCount > 2) - { - newScale.y = clamp_tpl((float)atof(pParams->GetArg(2)), 0.0f, 1.0f); - } - else - { - newScale.y = newScale.x; - } - - newScale = gEnv->pRenderer->SetViewportDownscale(newScale.x, newScale.y); - } - - int nWidth = gEnv->pRenderer->GetWidth(); - int nHeight = gEnv->pRenderer->GetHeight(); - - gEnv->pLog->LogWithType(ILog::eInputResponse, "Current Viewport Resolution: %dx%d", - int(nWidth * newScale.x), int(nHeight * newScale.y)); -} - -//-------------------------------------------------------------------------------------------------- -// Name: InitialiseCVars -// Desc: Initialises CVars -//-------------------------------------------------------------------------------------------------- -void COverloadSceneManager::InitialiseCVars() -{ - // depending on final requirements, these could be made into const cvars - REGISTER_CVAR_CB(osm_enabled, 0, VF_NULL, "Enables/disables overload scene manager", &OnChange_osm_enabled); - REGISTER_CVAR(osm_historyLength, 5, VF_NULL, "Overload scene manager number of frames to record stats for"); - REGISTER_CVAR(osm_targetFPS, 28.0f, VF_NULL, "Overload scene manager target frame rate"); - REGISTER_CVAR(osm_targetFPSTolerance, 1.0f, VF_NULL, "The overload scene manager will make adjustments if fps is outside targetFPS +/- this value"); - REGISTER_CVAR(osm_fbScaleDeltaDown, 5.0f, VF_NULL, "The speed multiplier for the overload scene manager frame buffer scaling down"); - REGISTER_CVAR(osm_fbScaleDeltaUp, 1.0f, VF_NULL, "The speed multiplier for the overload scene manager frame buffer scaling up"); - REGISTER_CVAR(osm_fbMinScale, 0.66f, VF_NULL, "The minimum scale factor the overload scene manager will drop to"); - - REGISTER_COMMAND("osm_setFBScale", cmd_setFBScale, VF_NULL, "Sets the framebuffer scale to either a single scale on both X and Y, or independent scales.\n" - "NOTE: Will be overridden immediately if Overload scene manager is still enabled - see osm_enabled"); -}//------------------------------------------------------------------------------------------------- - -//-------------------------------------------------------------------------------------------------- -// Name: Reset -// Desc: Resets overload scene manager outputs to sensible defaults -//-------------------------------------------------------------------------------------------------- -void COverloadSceneManager::Reset() -{ - ResetDefaultValues(); - - gEnv->pRenderer->SetViewportDownscale(m_fbScale, m_fbScale); -} - -void COverloadSceneManager::ResetDefaultValues() -{ - m_fbScale = 1.0f; - m_scaleState = FBSCALE_AUTO; - m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f; - m_lerpOverride.m_reversed = false; - m_lerpAuto.m_start = m_lerpAuto.m_length = 1.0f; - m_lerpAuto.m_reversed = true; - m_fbAutoScale = m_fbOverrideDestScale = m_fbOverrideCurScale = 1.0f; - - // completely reset history - for (int i = 0; i < osm_historyLength; i++) - { - SScenePerformanceStats& stats = m_sceneStats[i]; - stats.frameRate = stats.gpuFrameRate = osm_targetFPS; - } - - m_smoothedSceneStats.frameRate = m_smoothedSceneStats.gpuFrameRate = osm_targetFPS; -} -//------------------------------------------------------------------------------------------------- - -//-------------------------------------------------------------------------------------------------- -// Name: Update -// Desc: Updates overload scene manager -//-------------------------------------------------------------------------------------------------- -void COverloadSceneManager::Update() -{ - if (!osm_enabled) - { - return; - } - - UpdateStats(); - ResizeFB(); -}//------------------------------------------------------------------------------------------------- - -//-------------------------------------------------------------------------------------------------- -// Name: OverrideScale and ResetScale -// Desc: sets up appropriate members for lerping between automatic framebuffer scale and manual -// overrides. -//-------------------------------------------------------------------------------------------------- -void COverloadSceneManager::OverrideScale(float frameScale, float dt) -{ - dt = max(dt, 1.0f / 1000.0f); - - float curTime = gEnv->pTimer->GetCurrTime(); - - frameScale = clamp_tpl(frameScale, osm_fbMinScale, 1.0f); - - m_fbOverrideDestScale = frameScale; - - if (m_scaleState == FBSCALE_AUTO) - { - // remove any override lerp - we want to lerp straight from auto to the given value. - m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f; - m_lerpOverride.m_reversed = false; - m_fbOverrideCurScale = frameScale; - - m_lerpAuto.m_start = curTime; - m_lerpAuto.m_length = dt; - m_lerpAuto.m_reversed = false; - } - else if (m_scaleState == FBSCALE_OVERRIDE) - { - m_lerpOverride.m_start = curTime; - m_lerpOverride.m_length = dt; - m_lerpOverride.m_reversed = false; - - m_fbOverrideCurScale = m_fbScale; - } - - m_scaleState = FBSCALE_OVERRIDE; -} - -void COverloadSceneManager::ResetScale(float dt) -{ - dt = max(dt, 1.0f / 1000.0f); - - float curTime = gEnv->pTimer->GetCurrTime(); - - // remove any override lerp - we want to lerp straight to auto - m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f; - m_lerpOverride.m_reversed = false; - m_fbOverrideCurScale = m_fbOverrideDestScale = m_fbScale; - - m_lerpAuto.m_start = curTime; - m_lerpAuto.m_length = dt; - m_lerpAuto.m_reversed = true; // want to lerp back to auto mode - - m_scaleState = FBSCALE_AUTO; -}//------------------------------------------------------------------------------------------------- - -//-------------------------------------------------------------------------------------------------- -// Name: UpdateStats -// Desc: Updates overload stats -//-------------------------------------------------------------------------------------------------- -void COverloadSceneManager::UpdateStats() -{ - m_currentFrameStat++; - - if (m_currentFrameStat >= osm_historyLength) - { - m_currentFrameStat = 0; - } - - SScenePerformanceStats& currentStats = m_sceneStats[m_currentFrameStat]; - const float frameLength = gEnv->pTimer->GetRealFrameTime() * 1000.0f; - const float gpuFrameLength = gEnv->pRenderer->GetGPUFrameTime() * 1000.0f; - - currentStats.frameRate = frameLength > 0.0f ? 1000.0f / frameLength : 0.0f; - currentStats.gpuFrameRate = gpuFrameLength > 0.0f ? 1000.0f / gpuFrameLength : 0.0f; - - CalculateSmoothedStats(); -}//------------------------------------------------------------------------------------------------- - -void COverloadSceneManager::CalculateSmoothedStats() -{ - m_smoothedSceneStats.Reset(); - - for (int i = 0; i < osm_historyLength; i++) - { - SScenePerformanceStats& stats = m_sceneStats[i]; - m_smoothedSceneStats.frameRate += stats.frameRate; - m_smoothedSceneStats.gpuFrameRate += stats.gpuFrameRate; - } - - m_smoothedSceneStats.frameRate /= osm_historyLength; - m_smoothedSceneStats.gpuFrameRate /= osm_historyLength; -} - -float COverloadSceneManager::CalcFBScale() -{ - float curTime = gEnv->pTimer->GetCurrTime(); - - // first calculate delta of the override lerp - float delta = clamp_tpl((curTime - m_lerpOverride.m_start) / m_lerpOverride.m_length, 0.0f, 1.0f); - if (m_lerpOverride.m_reversed) - { - delta = 1.0f - delta; - } - - // get the current target override - float curOverrideScale = LERP(m_fbOverrideCurScale, m_fbOverrideDestScale, delta); - - // calculate the delta from (or two) automatic scaling - delta = clamp_tpl((curTime - m_lerpAuto.m_start) / m_lerpAuto.m_length, 0.0f, 1.0f); - if (m_lerpAuto.m_reversed) - { - delta = 1.0f - delta; - } - - // final lerp from automatic to current override - return LERP(m_fbAutoScale, curOverrideScale, delta); -} - -void COverloadSceneManager::ResizeFB() -{ - // don't do anything for invalid framerates - if (m_smoothedSceneStats.gpuFrameRate < 5.0f || m_smoothedSceneStats.gpuFrameRate > 100.0f) - { - return; - } - - float fpsDiff = fabsf(m_smoothedSceneStats.gpuFrameRate - osm_targetFPS); - - if (m_smoothedSceneStats.gpuFrameRate < osm_targetFPS - osm_targetFPSTolerance) - { - m_fbAutoScale -= osm_fbScaleDeltaDown / 1000.0f * fpsDiff; - } - else if (m_smoothedSceneStats.gpuFrameRate > osm_targetFPS + osm_targetFPSTolerance) - { - m_fbAutoScale += osm_fbScaleDeltaUp / 1000.0f * fpsDiff; - } - - m_fbAutoScale = clamp_tpl(m_fbAutoScale, osm_fbMinScale, 1.0f); - - m_fbScale = clamp_tpl(CalcFBScale(), osm_fbMinScale, 1.0f); - - gEnv->pRenderer->SetViewportDownscale(m_fbScale, m_fbScale); -} diff --git a/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.h b/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.h deleted file mode 100644 index 06a901b3df..0000000000 --- a/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_OVERLOADSCENEMANAGER_OVERLOADSCENEMANAGER_H -#define CRYINCLUDE_CRYSYSTEM_OVERLOADSCENEMANAGER_OVERLOADSCENEMANAGER_H -#pragma once - - -// Includes -#include "IOverloadSceneManager.h" - -#define SCENE_PERFORMANCE_FRAME_HISTORY 64 - -//================================================================================================== -// Name: SOverloadSceneStats -// Desc: Overload scene stats -// Author: James Chilvers -//================================================================================================== -struct SScenePerformanceStats -{ - SScenePerformanceStats() - { - Reset(); - } - - void Reset() - { - frameRate = 0.0f; - gpuFrameRate = 0.0f; - } - - float frameRate; - float gpuFrameRate; -};//------------------------------------------------------------------------------------------------ - -//================================================================================================== -// Name: COverloadSceneManager -// Desc: Manages overload values (eg CPU,GPU etc) -// 1.0="everything is ok" 0.0="very bad frame rate" -// various systems can use this information and control what is currently in the scene -// Author: James Chilvers -//================================================================================================== -class COverloadSceneManager - : public IOverloadSceneManager -{ - friend class COverloadDG; - -public: - - COverloadSceneManager(); - ~COverloadSceneManager() override = default; - - virtual void Reset(); - - virtual void Update(); - - virtual void OverrideScale(float frameScale, float dt); - virtual void ResetScale(float dt); - -private: - - void ResetDefaultValues(); - void InitialiseCVars(); - void UpdateStats(); - void CalculateSmoothedStats(); - void ResizeFB(); - - float CalcFBScale(); // performs all lerping and returns final framebuffer scale - - // cvars - int osm_enabled; - int osm_historyLength; - float osm_targetFPS; - float osm_targetFPSTolerance; - float osm_fbScaleDeltaUp, osm_fbScaleDeltaDown; - float osm_fbMinScale; - - SScenePerformanceStats m_smoothedSceneStats; - SScenePerformanceStats m_sceneStats[SCENE_PERFORMANCE_FRAME_HISTORY]; - int m_currentFrameStat; - - // current output scale, set to the renderer - float m_fbScale; - - // Lerping behaviour is to lerp from autoscale to (lerp between cur/dest override) - // - // m_fbOverrideCurScale - // | - // | - // m_fbAutoScale ---- m_lerpAuto ---> m_lerpOverride - // | - // v - // m_fbOverrideDestScale - - // framebuffer scales to support lerping & overriding of calculated scale - float m_fbAutoScale, m_fbOverrideCurScale, m_fbOverrideDestScale; - - struct ScaleLerp - { - bool m_reversed; // Normally lerp is 0 -> 1. If reversed it's 1 -> 0 - float m_start; // time in seconds - float m_length; // time in seconds - }; - - // lerpAuto is the lerp between auto scale and whatever override is. - // lerpOverride is the lerp between m_fbOverrideCurScale and m_fbOverrideDestScale - ScaleLerp m_lerpAuto, m_lerpOverride; - - // State is the current destination of any lerps. - enum ScaleState - { - FBSCALE_AUTO, - FBSCALE_OVERRIDE, - } m_scaleState; -};//------------------------------------------------------------------------------------------------ - -#endif // CRYINCLUDE_CRYSYSTEM_OVERLOADSCENEMANAGER_OVERLOADSCENEMANAGER_H diff --git a/Code/CryEngine/CrySystem/PerfHUD.cpp b/Code/CryEngine/CrySystem/PerfHUD.cpp deleted file mode 100644 index 2aeabe2650..0000000000 --- a/Code/CryEngine/CrySystem/PerfHUD.cpp +++ /dev/null @@ -1,2166 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - -#include "CrySystem_precompiled.h" - -#ifdef USE_PERFHUD - -#include "PerfHUD.h" -#include "MiniGUI/MiniInfoBox.h" -#include "MiniGUI/MiniMenu.h" -#include "MiniGUI/MiniTable.h" -#include -#include -#include "System.h" - -#include - -#include - -#include -#include - -#include - -#define PERFHUD_CONFIG_FILE "Config/PerfHud_PC.xml" - -using namespace minigui; - -const float CPerfHUD::OVERSCAN_X = 15; -const float CPerfHUD::OVERSCAN_Y = 15; - -const ColorB CPerfHUD::COL_NORM = ColorB(255, 255, 255, 255); -const ColorB CPerfHUD::COL_WARN = ColorB(255, 255, 0, 255); -const ColorB CPerfHUD::COL_ERROR = ColorB(255, 0, 0, 255); - -const float CPerfHUD::TEXT_SIZE_NORM = 14.f; -const float CPerfHUD::TEXT_SIZE_WARN = 18.f; -const float CPerfHUD::TEXT_SIZE_ERROR = 26.f; - -const float CPerfHUD::ACTIVATE_TIME_FROM_GAME = 1.f; -const float CPerfHUD::ACTIVATE_TIME_FROM_HUD = 0.1f; - -CRYREGISTER_SINGLETON_CLASS(CPerfHUD) -CPerfHUD::CPerfHUD() - : m_menuStartX(OVERSCAN_X) - , m_menuStartY(OVERSCAN_Y) - , m_hudCreated(false) - , m_L1Pressed(false) - , m_L2Pressed(false) - , m_R1Pressed(false) - , m_R2Pressed(false) - , m_changingState(false) - , m_hwMouseEnabled(false) - , m_triggersDownStartTime(-1.f) - , m_hudState(eHudOff) - , m_hudLastState(eHudOff) -{ - m_widgets.reserve(ICryPerfHUDWidget::eWidget_Num); -} - -CPerfHUD::~CPerfHUD() {} - -void CPerfHUD::Destroy() -{ - m_widgets.clear(); - - m_rootMenus.clear(); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - pGUI->RemoveAllCtrl(); - } -} - -// -// CONSOLE COMMAND CALLBACKS -// - -int CPerfHUD::m_sys_perfhud = 0; -int CPerfHUD::m_sys_perfhud_pause = 0; - -void CPerfHUD::CVarChangeCallback(ICVar* pCvar) -{ - ICryPerfHUD* pPerfHud = gEnv->pSystem->GetPerfHUD(); - - if (pPerfHud) - { - int val = pCvar->GetIVal(); - //Check for invalid value - if (val >= 0 && val < eHudNumStates) - { - pPerfHud->SetState((EHudState)val); - } - } -} - -SET_WIDGET_DEF(Warnings, eWidget_Warnings) -SET_WIDGET_DEF(RenderSummary, eWidget_RenderStats) -SET_WIDGET_DEF(RenderBatchStats, eWidget_RenderBatchStats) -SET_WIDGET_DEF(FpsBuckets, eWidget_FpsBuckets) -SET_WIDGET_DEF(Particles, eWidget_Particles) -SET_WIDGET_DEF(PakFile, eWidget_PakFile) - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::Init() -{ - m_sys_perfhud_prev = 0; - - if (gEnv->pConsole) - { - REGISTER_CVAR2_CB("sys_perfhud", &m_sys_perfhud, 0, VF_ALWAYSONCHANGE, "PerfHUD 0:off, 1:In focus, 2:Out of focus", CVarChangeCallback); - - REGISTER_CVAR2("sys_perfhud_pause", &m_sys_perfhud_pause, 0, VF_NULL, "Toggle FPS Buckets exclusive / inclusive"); - - SET_WIDGET_COMMAND("stats_Warnings", Warnings); - SET_WIDGET_COMMAND("stats_RenderSummary", RenderSummary); - SET_WIDGET_COMMAND("stats_RenderBatchStats", RenderBatchStats); - SET_WIDGET_COMMAND("stats_FpsBuckets", FpsBuckets); - SET_WIDGET_COMMAND("stats_Particles", Particles); - SET_WIDGET_COMMAND("stats_PakFile", PakFile); - } - - AzFramework::InputChannelEventListener::Connect(); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - InitUI(pGUI.get()); - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::LoadBudgets() -{ - XmlNodeRef budgets = gEnv->pSystem->LoadXmlFromFile(PERFHUD_CONFIG_FILE); - - if (budgets) - { - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - m_widgets[i]->LoadBudgets(budgets); - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::SaveStats(const char* filename) -{ - XmlNodeRef rootNode = GetISystem()->CreateXmlNode("PerfHudStats"); - - if (rootNode) - { - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - m_widgets[i]->SaveStats(rootNode); - } - - if (!filename) - { - filename = "PerfHudStats.xml"; - } - rootNode->saveToFile(filename); - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::ResetWidgets() -{ - TWidgetIterator itWidget; - for (itWidget = m_widgets.begin(); itWidget != m_widgets.end(); ++itWidget) - { - (*itWidget)->Reset(); - } -} - -void CPerfHUD::AddWidget(ICryPerfHUDWidget* pWidget) -{ - assert(pWidget); - static int s_widgetUID = ICryPerfHUDWidget::eWidget_Num; - - if (pWidget->m_id == -1) - { - pWidget->m_id = s_widgetUID++; - } - - m_widgets.push_back(pWidget); -} - -void CPerfHUD::RemoveWidget(ICryPerfHUDWidget* pWidget) -{ - TWidgetIterator widgetIter = m_widgets.begin(); - TWidgetIterator widgetEnd = m_widgets.end(); - - while (widgetIter != widgetEnd) - { - if (pWidget == (*widgetIter).get()) - { - m_widgets.erase(widgetIter); - break; - } - ++widgetIter; - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::Done() -{ - AzFramework::InputChannelEventListener::Disconnect(); -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::Draw() -{ - FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_SYSTEM, g_bProfilerEnabled); - - if (m_hudState != m_hudLastState) - { - //restore gui state if the last state was off - bool bRestoreState = (m_hudLastState == eHudOff); - - Show(bRestoreState); - m_hudLastState = m_hudState; - } - - if (m_hudState != eHudOff) - { - //Pause - if (m_sys_perfhud_pause) - { - if ((gEnv->pRenderer->GetFrameID(false) % 40) < 20) - { - float col[4] = {1.f, 1.f, 0.f, 1.f}; - gEnv->pRenderer->Draw2dLabel(500.f, 220.f, 2.f, col, false, "PefHUD Paused"); - } - } - else //Update - { - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->ShouldUpdate()) - { - m_widgets[i]->Update(); - } - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::Show(bool bRestoreState) -{ - IMiniGUIPtr pGUI; - if (!CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - return; - } - - switch (m_hudState) - { - case eHudInFocus: - { - pGUI->SetEventListener(this); - - if (!m_hudCreated) - { - InitUI(pGUI.get()); - } - else if (bRestoreState) - { - pGUI->RestoreState(); - } - pGUI->SetEnabled(true); - pGUI->SetInFocus(true); - - int nRootMenus = m_rootMenus.size(); - for (int i = 0; i < nRootMenus; i++) - { - m_rootMenus[i]->SetVisible(1); - } - } - break; - - case eHudOutOfFocus: - { - if (bRestoreState) - { - pGUI->RestoreState(); - } - - int nRootMenus = m_rootMenus.size(); - for (int i = 0; i < nRootMenus; i++) - { - m_rootMenus[i]->SetVisible(0); - } - - pGUI->SetEventListener(0); - pGUI->SetEnabled(true); - pGUI->SetInFocus(false); - } - break; - - case eHudOff: - { - pGUI->SaveState(); - pGUI->Reset(); - pGUI->SetEnabled(false); - } - break; - - default: - break; - } -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::InitUI(IMiniGUI* pGUI) -{ - assert(m_hudCreated == false); - - IMiniCtrl* pMenu; - XmlNodeRef perfXML = gEnv->pSystem->LoadXmlFromFile(PERFHUD_CONFIG_FILE); - - // - // RENDERING MENU - // - pMenu = CreateMenu("Rendering"); - - IMiniCtrl* pDebugMenu = CreateMenu("Debug", pMenu); - CreateCVarMenuItem(pDebugMenu, "Wireframe", "r_wireframe", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Overdraw", "r_MeasureOverdrawScale", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Freeze Camera", "e_CameraFreeze", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Post Effects", "r_PostProcessEffects", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Deferred decals debug", "r_deferredDecalsDebug", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Shadows", "e_Shadows", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Ocean", "e_WaterOcean", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Characters", "ca_DrawChr", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Coverage Buffer", "e_CoverageBuffer", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Sun", "e_Sun", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Unlit", "r_Unlit", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Disable Normal Maps", "r_texbindmode", 0, 5); - CreateCVarMenuItem(pDebugMenu, "Env Probes", "r_deferredShadingEnvProbes", 0, 1); - CreateCVarMenuItem(pDebugMenu, "Lighting View", "r_texbindmode", 0, 11); - CreateCVarMenuItem(pDebugMenu, "Normal and Lighting View", "r_texbindmode", 0, 6); - CreateCVarMenuItem(pDebugMenu, "Default Material", "e_defaultMaterial", 0, 1); - - //this cvar is not created when perfHUD is initialised - so it doesn't work - //CreateCVarMenuItem(pDebugMenu, "MFX visual debug", "mfx_DebugVisual", 0, 1 ); - - - IMiniCtrl* pStatsMenu = CreateMenu("Stats", pMenu); - //Render Info - CRenderStatsWidget* pRenderStats = new CRenderStatsWidget(pStatsMenu, this); - - if (pRenderStats) - { - if (perfXML) - { - pRenderStats->LoadBudgets(perfXML); - } - m_widgets.push_back(pRenderStats); - } - - CRenderBatchWidget* pRenderBatchStats = new CRenderBatchWidget(pStatsMenu, this); - - if (pRenderBatchStats) - { - m_widgets.push_back(pRenderBatchStats); - } - -#ifndef _RELEASE - CreateCVarMenuItem(pStatsMenu, "Debug Gun", "e_debugDraw", 0, 16); -#endif - CreateCVarMenuItem(pStatsMenu, "Poly / Lod info", "e_debugDraw", 0, 1); - CreateCVarMenuItem(pStatsMenu, "Texture Memory Usage", "e_debugDraw", 0, 4); - CreateCVarMenuItem(pStatsMenu, "Detailed Render Stats", "r_Stats", 0, 1); - CreateCVarMenuItem(pStatsMenu, "Shader Stats", "r_ProfileShaders", 0, 1); - - // - // SYSTEM MENU - // - pMenu = CreateMenu("System"); - - //FPS Buckets - CWarningsWidget* pWarningsWidget = new CWarningsWidget(pMenu, this); - - if (pWarningsWidget) - { - m_widgets.push_back(pWarningsWidget); - } - - CreateCVarMenuItem(pMenu, "Profiler", "profile", 0, 1); - CreateCVarMenuItem(pMenu, "Thread Summary", "r_showmt", 0, 1); - CreateCVarMenuItem(pMenu, "Track File Access", "sys_PakLogInvalidFileAccess", 0, 1); - - //FPS Buckets - CFpsWidget* pFpsBuckets = new CFpsWidget(pMenu, this); - - if (pFpsBuckets) - { - if (perfXML) - { - pFpsBuckets->LoadBudgets(perfXML); - } - m_widgets.push_back(pFpsBuckets); - } - - // - // STREAMING MENU - // - pMenu = CreateMenu("Streaming"); - CreateCVarMenuItem(pMenu, "Streaming Debug", "sys_streaming_debug", 0, 1); - CreateCVarMenuItem(pMenu, "Loaded Geometry Info", "e_streamcgfdebug", 0, 3); - CreateCVarMenuItem(pMenu, "Texture Load/Unload Debug", "r_TexBindMode", 0, 9); - CreateCVarMenuItem(pMenu, "Textures by Size", "r_TexturesStreamingDebug", 0, 4); - CreateCVarMenuItem(pMenu, "Textures by Prio", "r_TexturesStreamingDebug", 0, 5); - - // - // SETUP MENU - // - pMenu = CreateMenu("Setup"); - CreateCallbackMenuItem(pMenu, "Reset HUD", CPerfHUD::ResetCallback, NULL); - CreateCallbackMenuItem(pMenu, "Reload Budgets", CPerfHUD::ReloadBudgetsCallback, NULL); - CreateCallbackMenuItem(pMenu, "Save Stats", CPerfHUD::SaveStatsCallback, NULL); - CreateCVarMenuItem(pMenu, "Pause PerfHUD", "sys_perfhud_pause", 0, 1); - - //save default windows - pGUI->SaveState(); - - m_hudCreated = true; -} -////////////////////////////////////////////////////////////////////////// -// GUI CREATION HELPER FUNCS -////////////////////////////////////////////////////////////////////////// - -IMiniCtrl* CPerfHUD::CreateMenu(const char* name, IMiniCtrl* pParent) -{ - assert(name); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - bool subMenu = false; - - if (pParent) - { - assert(pParent->GetType() == eCtrlType_Menu); - subMenu = true; - } - - const float ButtonWidth = 10.f; //arbitrary, button will be scaled based on contained text - - int ctrlFlags = 0; - - if (!subMenu) - { - ctrlFlags = eCtrl_TextAlignCentre | eCtrl_AutoResize; - } - - Rect rcMenuBtn = Rect(m_menuStartX, m_menuStartY, m_menuStartX + ButtonWidth, m_menuStartY + 20); - - IMiniCtrl* pMenu = pGUI->CreateCtrl(pParent, 1, eCtrlType_Menu, ctrlFlags, rcMenuBtn, name); - - if (pMenu && !subMenu) - { - const float MenuBtnSepration = 10.f; - - //Update Menu Positions - rcMenuBtn = pMenu->GetRect(); - m_menuStartX = rcMenuBtn.right + MenuBtnSepration; - m_menuStartY = rcMenuBtn.top; - - m_rootMenus.push_back(pMenu); - } - - return pMenu; - } - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -bool CPerfHUD::CreateCVarMenuItem(IMiniCtrl* pMenu, const char* name, const char* controlVar, float controlVarOff, float controlVarOn) -{ - assert(pMenu && name && controlVar); - assert(pMenu->GetType() == eCtrlType_Menu); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - IMiniCtrl* pCtrl = pGUI->CreateCtrl(pMenu, 100, eCtrlType_Button, eCtrl_CheckButton, Rect(0, 0, 100, 20), name); - - if (pCtrl) - { - if (controlVar) - { - pCtrl->SetControlCVar(controlVar, controlVarOff, controlVarOn); - } - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////// -bool CPerfHUD::CreateCallbackMenuItem(IMiniCtrl* pMenu, const char* name, ClickCallback clickCallback, void* pCallbackData) -{ - assert(pMenu && name && clickCallback); - assert(pMenu->GetType() == eCtrlType_Menu); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - IMiniCtrl* pCtrl = pGUI->CreateCtrl(pMenu, 100, eCtrlType_Button, 0 /*eCtrl_CheckButton*/, Rect(0, 0, 100, 20), name); - - if (pCtrl) - { - pCtrl->SetClickCallback(clickCallback, pCallbackData); - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////// -IMiniInfoBox* CPerfHUD::CreateInfoMenuItem(IMiniCtrl* pMenu, const char* name, RenderCallback renderCallback, const Rect& rect, bool onAtStart) -{ - assert(pMenu->GetType() == eCtrlType_Menu); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - IMiniCtrl* pCtrl = pGUI->CreateCtrl(pMenu, 100, eCtrlType_Button, eCtrl_CheckButton, Rect(0, 0, 100, 20), name); - - int infoFlags = eCtrl_Moveable | eCtrl_CloseButton; - - if (!renderCallback) - { - infoFlags |= eCtrl_AutoResize; - } - - CMiniInfoBox* pInfo = (CMiniInfoBox*)pGUI->CreateCtrl(NULL, 200, eCtrlType_InfoBox, infoFlags, rect, name); - - if (pCtrl) - { - pCtrl->SetConnectedCtrl(pInfo); - - if (onAtStart) - { - pCtrl->SetFlag(eCtrl_Checked); - } - else - { - pInfo->SetVisible(false); - } - - if (renderCallback) - { - pInfo->SetRenderCallback(renderCallback); - } - - return pInfo; - } - } - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -IMiniTable* CPerfHUD::CreateTableMenuItem(IMiniCtrl* pMenu, const char* name) -{ - assert(pMenu && name); - assert(pMenu->GetType() == eCtrlType_Menu); - - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - CMiniTable* pTable = (CMiniTable*)pGUI->CreateCtrl(NULL, 200, eCtrlType_Table, eCtrl_AutoResize | eCtrl_Moveable | eCtrl_CloseButton, Rect(50, 100, 400, 350), name); - - if (pTable) - { - IMiniCtrl* pCtrl = pGUI->CreateCtrl(pMenu, 100, eCtrlType_Button, eCtrl_CheckButton, Rect(0, 0, 100, 20), name); - - if (pCtrl) - { - pCtrl->SetConnectedCtrl(pTable); - - pTable->SetVisible(false); - - return pTable; - } - } - } - return NULL; -} - -IMiniCtrl* CPerfHUD::GetMenu(const char* name) -{ - int nRootMenus = m_rootMenus.size(); - - for (int i = 0; i < nRootMenus; i++) - { - if (strcmp(m_rootMenus[i]->GetTitle(), name) == 0) - { - return m_rootMenus[i]; - } - } - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::OnCommand([[maybe_unused]] SCommand& cmd) -{ - //CryLog( "Button Clicked = %d",cmd.nCtrlID ); -} - -////////////////////////////////////////////////////////////////////////// -bool CPerfHUD::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) -{ - const AzFramework::InputChannelId& channelId = inputChannel.GetInputChannelId(); - const AzFramework::InputDeviceId& deviceId = inputChannel.GetInputDevice().GetInputDeviceId(); - if (AzFramework::InputDeviceKeyboard::IsKeyboardDevice(deviceId) && inputChannel.IsStateBegan()) - { - if (channelId == AzFramework::InputDeviceKeyboard::Key::WindowsSystemPrint) - { - //Cycle modes - const AzFramework::ModifierKeyStates* customData = inputChannel.GetCustomData(); - const AzFramework::ModifierKeyStates modifierKeyStates = customData ? *customData : AzFramework::ModifierKeyStates(); - const bool isAltModifierActive = modifierKeyStates.IsActive(AzFramework::ModifierKeyMask::AltAny); - const bool isCtrlModifierActive = modifierKeyStates.IsActive(AzFramework::ModifierKeyMask::CtrlAny); - if (isAltModifierActive || isCtrlModifierActive) - { - SetNextState(); - } - } - else if (channelId == AzFramework::InputDeviceKeyboard::Key::WindowsSystemScrollLock) - { - //toggle pause - m_sys_perfhud_pause ^= 1; - } - } - - - if (deviceId == AzFramework::InputDeviceGamepad::IdForIndex0) - { - if (inputChannel.IsStateBegan()) - { - bool checkState = false; - - if (channelId == AzFramework::InputDeviceGamepad::Button::L1) - { - m_L1Pressed = true; - checkState = true; - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::R1) - { - m_R1Pressed = true; - checkState = true; - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::X) - { - if (m_changingState) - { - SetNextState(); - } - } - - //if(checkState&&m_L1Pressed&&m_L2Pressed&&m_R1Pressed&&m_R2Pressed) - if (checkState && m_L1Pressed && m_R1Pressed) - { - m_triggersDownStartTime = gEnv->pTimer->GetAsyncCurTime(); - } - } - else if (inputChannel.IsStateUpdated()) - { - float activateTime = (m_hudState == eHudOff) ? ACTIVATE_TIME_FROM_GAME : ACTIVATE_TIME_FROM_HUD; - - if (m_triggersDownStartTime > 0.f && gEnv->pTimer->GetAsyncCurTime() - m_triggersDownStartTime > activateTime) - { - m_changingState = true; - - const char* hudStateStr = NULL; - - switch (m_hudState) - { - case eHudInFocus: - hudStateStr = "CryPerfHUD Edit Mode"; - break; - - case eHudOutOfFocus: - hudStateStr = "CryPerfHUD Game Mode"; - break; - - case eHudOff: - hudStateStr = "CryPerfHUD Off"; - break; - - default: - hudStateStr = "CryPerfHud unknown"; - break; - } - - float col[4] = {1.f, 1.f, 1.f, 1.f}; - gEnv->pRenderer->Draw2dLabel(450.f, 200.f, 2.f, col, false, hudStateStr); - gEnv->pRenderer->Draw2dLabel(450.f, 220.f, 2.f, col, false, "Press X to change Mode"); - } - } - else if (inputChannel.IsStateEnded()) - { - bool triggerReleased = false; - - if (channelId == AzFramework::InputDeviceGamepad::Button::L1) - { - m_L1Pressed = false; - triggerReleased = true; - } - else if (channelId == AzFramework::InputDeviceGamepad::Button::R1) - { - m_R1Pressed = false; - triggerReleased = true; - } - - if (triggerReleased) - { - m_triggersDownStartTime = 0.f; - - if (m_changingState) - { - m_changingState = false; - - //workaround: hardware mouse resets all input states when enabled - //this breaks perfhud selection mode (as triggers are released) - //don't enable mouse until we've finished selection mode - if (m_hudState == eHudInFocus) - { - if (!m_hwMouseEnabled) - { - UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter); - m_hwMouseEnabled = true; - } - } - else if (m_hwMouseEnabled) - { - UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter); - m_hwMouseEnabled = false; - } - } - } - } - - if (m_hudState == eHudInFocus) - { - //PerfHUD takes control of the input - return true; - } - } - return false; -} - -void CPerfHUD::SetNextState() -{ - if (m_sys_perfhud != eHudOff) - { - m_hudState = (EHudState)((m_hudState + 1) % eHudNumStates); - //CryLogAlways("Setting new HUD state: %d", m_hudState); - - //what to do about cvar? - //ICVar *pPerfCVar = GetISystem()->GetIConsole()->GetCVar("sys_perfhud"); - //pPerfCVar->Set( 1 ); - } -} - -void CPerfHUD::SetState(EHudState state) -{ - if (state != m_hudState) - { - if (m_hwMouseEnabled) - { - if (state != eHudInFocus) - { - UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter); - m_hwMouseEnabled = false; - } - } - else if (state == eHudInFocus) - { - UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter); - m_hwMouseEnabled = true; - } - - m_hudState = state; - } -} - -void CPerfHUD::Reset() -{ - IMiniGUIPtr pGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pGUI)) - { - pGUI->Reset(); - } -} - -////////////////////////////////////////////////////////////////////////// -// CLICK CALLBACKS -////////////////////////////////////////////////////////////////////////// - -void CPerfHUD::ResetCallback([[maybe_unused]] void* data, [[maybe_unused]] bool status) -{ - ICryPerfHUDPtr pPerfHUD; - if (CryCreateClassInstanceForInterface(cryiidof(), pPerfHUD)) - { - pPerfHUD->Reset(); - } -} - -void CPerfHUD::ReloadBudgetsCallback([[maybe_unused]] void* data, [[maybe_unused]] bool status) -{ - ICryPerfHUDPtr pPerfHUD; - if (CryCreateClassInstanceForInterface(cryiidof(), pPerfHUD)) - { - pPerfHUD->LoadBudgets(); - } -} - -void CPerfHUD::SaveStatsCallback([[maybe_unused]] void* data, [[maybe_unused]] bool status) -{ - ICryPerfHUDPtr pPerfHUD; - if (CryCreateClassInstanceForInterface(cryiidof(), pPerfHUD)) - { - pPerfHUD->SaveStats(); - } -} - -////////////////////////////////////////////////////////////////////////// -// RENDER CALLBACKS -////////////////////////////////////////////////////////////////////////// - -void CPerfHUD::EnableWidget(ICryPerfHUDWidget::EWidgetID id, int mode) -{ - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->m_id == id) - { - m_widgets[i]->Enable(mode); - return; - } - } -} - -void CPerfHUD::DisableWidget(ICryPerfHUDWidget::EWidgetID id) -{ - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->m_id == id) - { - m_widgets[i]->Disable(); - return; - } - } -} - -////////////////////////////////////////////////////////////////////////// -// Widget Specific Interface -////////////////////////////////////////////////////////////////////////// -void CPerfHUD::AddWarning(float duration, const char* fmt, va_list argList) -{ - if (m_hudState != eHudOff) - { - //could cache warnings window ptr for efficiency - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->m_id == ICryPerfHUDWidget::eWidget_Warnings) - { - CWarningsWidget* warnings = (CWarningsWidget*)m_widgets[i].get(); - - if (warnings->ShouldUpdate()) - { - warnings->AddWarningV(duration, fmt, argList); - break; - } - } - } - } -} - -bool CPerfHUD::WarningsWindowEnabled() const -{ - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->m_id == ICryPerfHUDWidget::eWidget_Warnings) - { - return m_widgets[i]->ShouldUpdate(); - } - } - - return false; -} - -const std::vector* CPerfHUD::GetFpsBuckets(float& totalTime) const -{ - const int nWidgets = m_widgets.size(); - - for (int i = 0; i < nWidgets; i++) - { - if (m_widgets[i]->m_id == ICryPerfHUDWidget::eWidget_FpsBuckets) - { - return ((CFpsWidget*)m_widgets[i].get())->GetFpsBuckets(totalTime); - } - } - - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -//FPS Buckets Widget -////////////////////////////////////////////////////////////////////////// - -int CFpsWidget::m_cvarPerfHudFpsExclusive = 0; - -CFpsWidget::CFpsWidget(IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud) - : ICryPerfHUDWidget(eWidget_FpsBuckets) -{ - m_fpsBucketSize = 5.f; - m_fpsBudget = 30.f; - m_dpBudget = 2500.f; - m_dpBucketSize = 250.f; - - //FPS Buckets - IMiniCtrl* pFPSMenu = pPerfHud->CreateMenu("FPS", pParentMenu); - m_pInfoBox = pPerfHud->CreateInfoMenuItem(pFPSMenu, "FPS Buckets", NULL, Rect(850, 395, 860, 405)); - pPerfHud->CreateCallbackMenuItem(pFPSMenu, "Reset Buckets", CFpsWidget::ResetCallback, this); - - //Display framerates buckets as inclusive or exclusive - REGISTER_CVAR2("sys_perfhud_fpsBucketsExclusive", &m_cvarPerfHudFpsExclusive, 0, VF_CHEAT, "Toggle FPS Buckets exclusive / inclusive"); - - Init(); -} - -void CFpsWidget::LoadBudgets(XmlNodeRef PerfXML) -{ - if (PerfXML) - { - XmlNodeRef xmlNode; - - //FPS / GPU - explicit bucket values - if ((xmlNode = PerfXML->findChild("fpsBucketValues"))) - { - m_perfBuckets[BUCKET_FPS].buckets.clear(); - m_perfBuckets[BUCKET_GPU].buckets.clear(); - - uint32 nBuckets = xmlNode->getChildCount(); - - for (uint32 i = 0; i < nBuckets; i++) - { - XmlNodeRef bucketVal = xmlNode->getChild(i); - - float target; - bucketVal->getAttr("value", target); - - ICryPerfHUD::PerfBucket bucket(target); - - m_perfBuckets[BUCKET_FPS].buckets.push_back(bucket); - m_perfBuckets[BUCKET_GPU].buckets.push_back(bucket); - } - - m_perfBuckets[BUCKET_FPS].totalTime = 0.f; - m_perfBuckets[BUCKET_GPU].totalTime = 0.f; - } - //Auto generated buckets based on max fps and bucket size - else if ((xmlNode = PerfXML->findChild("fpsBucketMax"))) - { - xmlNode->getAttr("value", m_fpsBudget); - - if ((xmlNode = PerfXML->findChild("fpsBucketSize"))) - { - xmlNode->getAttr("value", m_fpsBucketSize); - } - else - { - m_fpsBucketSize = 5; - } - - m_perfBuckets[BUCKET_FPS].buckets.clear(); - m_perfBuckets[BUCKET_GPU].buckets.clear(); - - float targetFPS = m_fpsBudget; - - for (uint32 i = 0; i < NUM_FPS_BUCKETS_DEFAULT; i++) - { - ICryPerfHUD::PerfBucket bucket(targetFPS); - - m_perfBuckets[BUCKET_FPS].buckets.push_back(bucket); - m_perfBuckets[BUCKET_GPU].buckets.push_back(bucket); - - targetFPS -= m_fpsBucketSize; - } - - m_perfBuckets[BUCKET_FPS].totalTime = 0.f; - m_perfBuckets[BUCKET_GPU].totalTime = 0.f; - } - - //DP buckets - explicit bucket values - if ((xmlNode = PerfXML->findChild("dpBucketValues"))) - { - m_perfBuckets[BUCKET_DP].buckets.clear(); - - uint32 nBuckets = xmlNode->getChildCount(); - - for (uint32 i = 0; i < nBuckets; i++) - { - XmlNodeRef bucketVal = xmlNode->getChild(i); - - float target; - bucketVal->getAttr("value", target); - - ICryPerfHUD::PerfBucket bucket(target); - - m_perfBuckets[BUCKET_DP].buckets.push_back(bucket); - } - m_perfBuckets[BUCKET_DP].totalTime = 0.f; - } - //DPs auto values - else if ((xmlNode = PerfXML->findChild("drawPrimBucketMax"))) - { - xmlNode->getAttr("value", m_dpBudget); - - //Auto generated buckets based on max dp and bucket size - if ((xmlNode = PerfXML->findChild("dpBucketSize"))) - { - xmlNode->getAttr("value", m_dpBucketSize); - } - else - { - m_dpBucketSize = 250.f; - } - - m_perfBuckets[BUCKET_DP].buckets.clear(); - - float nDPs = m_dpBudget - ((NUM_FPS_BUCKETS_DEFAULT - 1) * m_dpBucketSize); - - for (uint32 i = 0; i < NUM_FPS_BUCKETS_DEFAULT; i++) - { - ICryPerfHUD::PerfBucket bucket(nDPs); - - m_perfBuckets[BUCKET_DP].buckets.push_back(bucket); - - nDPs += m_dpBucketSize; - } - m_perfBuckets[BUCKET_DP].totalTime = 0.f; - } - } -} - -template -void CFpsWidget::UpdateBuckets(PerfBucketsStat& bucketStat, float frameTime, const char* name, float stat) -{ - char entryBuffer[CMiniInfoBox::MAX_TEXT_LENGTH] = {0}; - - const uint32 numBuckets = bucketStat.buckets.size(); - - if (frameTime > 0.f) - { - bucketStat.totalTime += frameTime; - - for (uint32 i = 0; i < numBuckets; i++) - { - if (LESS_THAN) - { - if (stat <= bucketStat.buckets[i].target) - { - bucketStat.buckets[i].timeAtTarget += frameTime; - } - } - else - { - if (stat >= bucketStat.buckets[i].target) - { - bucketStat.buckets[i].timeAtTarget += frameTime; - } - } - } - } - - if (bucketStat.totalTime > 0.f) - { - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "%s: %.2f", name, stat); - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - - //render exclusive stats - if (m_cvarPerfHudFpsExclusive) - { - for (uint32 i = 0; i < numBuckets; i++) - { - //inclusive time - float timeAtTarget = bucketStat.buckets[i].timeAtTarget; - - if (i > 0) - { - //exclusive time - timeAtTarget -= bucketStat.buckets[i - 1].timeAtTarget; - - //Add info to gui - float percentAtTarget = 100.f * (timeAtTarget / bucketStat.totalTime); - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "%.2f%%%% of time %.1f -> %.1f FPS", percentAtTarget, bucketStat.buckets[i].target, bucketStat.buckets[i - 1].target); - } - else - { - float percentAtTarget = 100.f * (bucketStat.buckets[i].timeAtTarget / bucketStat.totalTime); - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "%.2f%%%% of time >= %.1f FPS", percentAtTarget, bucketStat.buckets[i].target); - } - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - } - else //render inclusive stats - { - for (uint32 i = 0; i < numBuckets; i++) - { - float percentAtTarget = 100.f * (bucketStat.buckets[i].timeAtTarget / bucketStat.totalTime); - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "%.2f%%%% of time %s %.1f", percentAtTarget, LESS_THAN ? "<=" : ">=", bucketStat.buckets[i].target); - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - } - } -} - -void CFpsWidget::Update() -{ - m_pInfoBox->ClearEntries(); - - // - // FPS - // - { - float frameTime = gEnv->pTimer->GetRealFrameTime(); - UpdateBuckets(m_perfBuckets[BUCKET_FPS], frameTime, "FPS", 1.f / frameTime); - } - - // - // GPU FPS - // - { - float gpuFrameTime = gEnv->pRenderer->GetGPUFrameTime(); - - if (gpuFrameTime > 0.f) - { - m_pInfoBox->AddEntry("", CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - UpdateBuckets(m_perfBuckets[BUCKET_GPU], gpuFrameTime, "GPU FPS", 1.f / gpuFrameTime); - } - } - - // - // Draw Call - // - { - //ugly, but buckets are float only at the moment - float nDPs = (float)gEnv->pRenderer->GetCurrentNumberOfDrawCalls(); - m_pInfoBox->AddEntry("", CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - UpdateBuckets(m_perfBuckets[BUCKET_DP], 1.f, "DPs", nDPs); - } -} - -//Init buckets with default values -void CFpsWidget::Init() -{ - float targetFPS = m_fpsBudget; - float nDPs = m_dpBudget - ((NUM_FPS_BUCKETS_DEFAULT - 1) * m_dpBucketSize); - - for (uint32 i = 0; i < NUM_FPS_BUCKETS_DEFAULT; i++) - { - ICryPerfHUD::PerfBucket bucket(targetFPS); - - m_perfBuckets[BUCKET_FPS].buckets.push_back(bucket); - m_perfBuckets[BUCKET_GPU].buckets.push_back(bucket); - - bucket.target = (float)nDPs; - - m_perfBuckets[BUCKET_DP].buckets.push_back(bucket); - - targetFPS -= m_fpsBucketSize; - nDPs += m_dpBucketSize; - } - - for (uint32 i = 0; i < BUCKET_TYPE_NUM; i++) - { - m_perfBuckets[i].totalTime = 0.f; - } -} - -//Clear bucket totals -void CFpsWidget::Reset() -{ - for (uint32 i = 0; i < BUCKET_TYPE_NUM; i++) - { - PerfBucketsStat& stat = m_perfBuckets[i]; - - const uint32 nBuckets = stat.buckets.size(); - - //Init fps buckets - for (uint32 j = 0; j < nBuckets; j++) - { - stat.buckets[j].timeAtTarget = 0.f; - } - - stat.totalTime = 0.f; - } -} - -void CFpsWidget::ResetCallback(void* data, [[maybe_unused]] bool status) -{ - assert(data); - ((CFpsWidget*)data)->Reset(); -} - -bool CFpsWidget::ShouldUpdate() -{ - return !m_pInfoBox->IsHidden(); -} - -//TODO -void CFpsWidget::SaveStats(XmlNodeRef statsXML) -{ - if (statsXML) - { - const char* perfBucketTypeStr[] = - { - "BUCKET_FPS", - "BUCKET_GPU", - "BUCKET_DP", - }; - - XmlNodeRef fpsNode; - - for (int i = 0; i < BUCKET_TYPE_NUM; i++) - { - PerfBucketsStat& perfBucket = m_perfBuckets[i]; - - if (perfBucket.totalTime > 0.f) - { - if ((fpsNode = statsXML->newChild(perfBucketTypeStr[i]))) - { - XmlNodeRef child; - - const uint32 numBuckets = perfBucket.buckets.size(); - - for (uint32 j = 0; j < numBuckets; j++) - { - float percentAtTarget = 100.f * (perfBucket.buckets[j].timeAtTarget / perfBucket.totalTime); - - if ((child = fpsNode->newChild("bucket"))) - { - child->setAttr("target", perfBucket.buckets[j].target); - } - - if ((child = fpsNode->newChild("percentAtTime"))) - { - child->setAttr("value", percentAtTarget); - } - } - } - } - } - } -} - -const std::vector* CFpsWidget::GetFpsBuckets(float& totalTime) const -{ - totalTime = m_perfBuckets[BUCKET_FPS].totalTime; - return &m_perfBuckets[BUCKET_FPS].buckets; -} - -////////////////////////////////////////////////////////////////////////// -//Render Stats Widget -////////////////////////////////////////////////////////////////////////// - -CRenderStatsWidget::CRenderStatsWidget(IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud) - : ICryPerfHUDWidget(eWidget_RenderStats) -{ - m_pPerfHUD = pPerfHud; - m_fpsBudget = 30.f; - m_dpBudget = 2000; - m_polyBudget = 500000; - m_postEffectBudget = 3; - m_shadowCastBudget = 2; - m_particlesBudget = 1000; - m_pInfoBox = NULL; - m_buildNum = 0; - - ZeroStruct(m_runtimeData); - - m_pInfoBox = pPerfHud->CreateInfoMenuItem(pParentMenu, "Scene Summary", NULL, Rect(45, 350, 100, 400) /*, true*/); - - //Get build number from BuildName.txt - //FILE *buildFile = fxopen("BuildName.txt", "r"); - CCryFile buildFile; - - if (buildFile.Open("./BuildName.txt", "rb", AZ::IO::IArchive::FOPEN_ONDISK | AZ::IO::IArchive::FOPEN_HINT_QUIET)) - { - size_t fileSize = buildFile.GetLength(); - - if (fileSize > 0 && fileSize < 64) - { - char buffer[64] = {0}; - - buildFile.ReadRaw(buffer, fileSize); - - if (buffer[0]) - { - const char* ptr = strchr(buffer, '('); - - if (ptr) - { - ptr++; - m_buildNum = atoi(ptr); - } - } - } - } -} - -void CRenderStatsWidget::Update() -{ - IRenderer* pRenderer = gEnv->pRenderer; - - char entryBuffer[CMiniInfoBox::MAX_TEXT_LENGTH] = {0}; - - //Clear old entries - m_pInfoBox->ClearEntries(); - ZeroStruct(m_runtimeData); - - // - // FPS - // - m_runtimeData.fps = min(9999.f, gEnv->pTimer->GetFrameRate()); - - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "FPS: %.2f (%.2f)", m_runtimeData.fps, m_fpsBudget); - - if (m_runtimeData.fps >= m_fpsBudget) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "FPS Too Low: %.2f", m_runtimeData.fps); - - //PerfHud / AuxRenderer causes us to be RenderThread limited - //Need to investigate vertex buffer locks in AuxRenderer before enabling - - /* - // Fran: please call me before re-enabling this code - - SRenderTimes renderTimes; - pRenderer->GetRenderTimes(renderTimes); - - //wait for main is never 0 - if(renderTimes.fWaitForMain>renderTimes.fWaitForRender && renderTimes.fWaitForMain>renderTimes.fWaitForGPU) - { - m_pInfoBox->AddEntry("Main Thread Limited", CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_ERROR); - m_pPerfHud->AddWarning("Main Thread Limited",1.f); - } - else if(renderTimes.fWaitForRender>renderTimes.fWaitForGPU) - { - m_pInfoBox->AddEntry("Render Thread Limited", CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_ERROR); - m_pPerfHud->AddWarning("Render Thread Limited",1.f); - } - else - { - m_pInfoBox->AddEntry("GPU Limited", CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_ERROR); - m_pPerfHud->AddWarning("GPU Limited",1.f); - }*/ - } - - // - // GPU Time - // - float gpuTime = pRenderer->GetGPUFrameTime(); - - if (gpuTime > 0.f) - { - float gpuFPS = 1.f / gpuTime; - - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "GPU FPS: %.2f (%.2f)", gpuFPS, m_fpsBudget); - if (gpuFPS >= m_fpsBudget) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "GPU FPS Too Low: %.2f", gpuFPS); - } - } - - - // - // HDR - // - bool bHDRModeEnabled = false; - pRenderer->EF_Query(EFQ_HDRModeEnabled, bHDRModeEnabled); - if (bHDRModeEnabled) - { - m_runtimeData.hdrEnabled = true; - if (!m_runtimeData.hdrEnabled) - { - CryPerfHUDWarning(1.f, "HDR Disabled"); - } - } - - if (!gEnv->IsEditor()) - { - // - // Render Thread - // - static ICVar* pMultiThreaded = gEnv->pConsole->GetCVar("r_MultiThreaded"); - if (pMultiThreaded && pMultiThreaded->GetIVal() > 0) - { - //sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "Render Thread Enabled"); - //m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - m_runtimeData.renderThreadEnabled = true; - } - else - { - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "Render Thread Disabled"); - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - m_runtimeData.renderThreadEnabled = false; - CryPerfHUDWarning(1.f, "Render Thread Disabled"); - } - } - - - // - // Camera - // - Matrix33 m = Matrix33(pRenderer->GetCamera().GetMatrix()); - m_runtimeData.cameraRot = RAD2DEG(Ang3::GetAnglesXYZ(m)); - m_runtimeData.cameraPos = pRenderer->GetCamera().GetPosition(); - - - // - // Polys / Draw Prims - // - int nShadowVolPolys; - int nPolys; - pRenderer->GetPolyCount(nPolys, nShadowVolPolys); - m_runtimeData.nPolys = nPolys; - m_runtimeData.nDrawPrims = pRenderer->GetCurrentNumberOfDrawCalls(); - - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "Draw Calls: %d (%d)", m_runtimeData.nDrawPrims, m_dpBudget); - - if (m_runtimeData.nDrawPrims <= m_dpBudget) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "Too Many Draw Calls: %d", m_runtimeData.nDrawPrims); - } - - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "Num Tris: %d (%d)", m_runtimeData.nPolys, m_polyBudget); - - if (m_runtimeData.nPolys <= m_polyBudget) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "Too Many Tris: %d", m_runtimeData.nPolys); - } - - // - // Post Effects - // - - gEnv->pRenderer->EF_Query(EFQ_NumActivePostEffects, m_runtimeData.nPostEffects); - sprintf_s(entryBuffer, CMiniInfoBox::MAX_TEXT_LENGTH, "Num Post Effects: %d (%d)", m_runtimeData.nPostEffects, m_postEffectBudget); - - if (m_runtimeData.nPostEffects <= m_postEffectBudget) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "Too Many Post Effects: %d", m_runtimeData.nPostEffects); - } - - m_runtimeData.nFwdLights = 0; - m_runtimeData.nFwdShadowLights = 0; - - ////////////////////////////////////////////////////////////////////////// - if (gEnv->pRenderer) - { - STextureStreamingStats textureStats(true); - gEnv->pRenderer->EF_Query(EFQ_GetTexStreamingInfo, textureStats); - - float fTexRequiredMB = (float)(textureStats.nRequiredStreamedTexturesSize) / (1024 * 1024); - sprintf_s(entryBuffer, "Textures Required: %.2f (%dMB)", fTexRequiredMB, azlossy_cast(textureStats.nMaxPoolSize / (1024 * 1024))); - if (fTexRequiredMB < textureStats.nMaxPoolSize) - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_NORM, CPerfHUD::TEXT_SIZE_NORM); - } - else - { - m_pInfoBox->AddEntry(entryBuffer, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_NORM); - CryPerfHUDWarning(1.f, "Too Many Textures: %.2fMB", fTexRequiredMB); - } - } -} -bool CRenderStatsWidget::ShouldUpdate() -{ - if (!m_pInfoBox->IsHidden() || - m_pPerfHUD->WarningsWindowEnabled()) - { - return true; - } - return false; -} - -void CRenderStatsWidget::LoadBudgets(XmlNodeRef perfXML) -{ - if (perfXML) - { - XmlNodeRef xmlNode; - - if ((xmlNode = perfXML->findChild("fps"))) - { - xmlNode->getAttr("value", m_fpsBudget); - } - - if ((xmlNode = perfXML->findChild("drawPrim"))) - { - xmlNode->getAttr("value", m_dpBudget); - } - - if ((xmlNode = perfXML->findChild("tris"))) - { - xmlNode->getAttr("value", m_polyBudget); - } - - if ((xmlNode = perfXML->findChild("postEffects"))) - { - xmlNode->getAttr("value", m_postEffectBudget); - } - - if ((xmlNode = perfXML->findChild("shadowCastingLights"))) - { - xmlNode->getAttr("value", m_shadowCastBudget); - } - - if ((xmlNode = perfXML->findChild("particles"))) - { - xmlNode->getAttr("value", m_particlesBudget); - } - } -} - -void CRenderStatsWidget::SaveStats(XmlNodeRef statsXML) -{ - if (!ShouldUpdate()) - { - //Force update of stats, widget may not be currently enabled - Update(); - } - - if (statsXML) - { - XmlNodeRef renderNode; - - if ((renderNode = statsXML->newChild("RenderStats"))) - { - XmlNodeRef child; - - if ((child = renderNode->newChild("fps"))) - { - child->setAttr("value", m_runtimeData.fps); - } - - if ((child = renderNode->newChild("hdr"))) - { - child->setAttr("value", m_runtimeData.hdrEnabled); - } - - if ((child = renderNode->newChild("renderThread"))) - { - child->setAttr("value", m_runtimeData.renderThreadEnabled); - } - - if ((child = renderNode->newChild("cameraPos"))) - { - child->setAttr("x", m_runtimeData.cameraPos.x); - child->setAttr("y", m_runtimeData.cameraPos.y); - child->setAttr("z", m_runtimeData.cameraPos.z); - } - - if ((child = renderNode->newChild("cameraRot"))) - { - child->setAttr("x", m_runtimeData.cameraRot.x); - child->setAttr("y", m_runtimeData.cameraRot.y); - child->setAttr("z", m_runtimeData.cameraRot.z); - } - - if ((child = renderNode->newChild("drawPrims"))) - { - child->setAttr("value", m_runtimeData.nDrawPrims); - } - - if ((child = renderNode->newChild("numPolys"))) - { - child->setAttr("value", m_runtimeData.nPolys); - } - - if ((child = renderNode->newChild("numPostEffects"))) - { - child->setAttr("value", m_runtimeData.nPostEffects); - } - - if ((child = renderNode->newChild("numFwdLights"))) - { - child->setAttr("value", m_runtimeData.nFwdLights); - } - - if ((child = renderNode->newChild("numFwdShadowLights"))) - { - child->setAttr("value", m_runtimeData.nFwdShadowLights); - } - - if ((child = renderNode->newChild("numDefLights"))) - { - child->setAttr("value", m_runtimeData.nDefLights); - } - - if ((child = renderNode->newChild("numDefShadowLights"))) - { - child->setAttr("value", m_runtimeData.nDefShadowLights); - } - - if ((child = renderNode->newChild("numDefCubeMaps"))) - { - child->setAttr("value", m_runtimeData.nDefCubeMaps); - } - - if ((child = renderNode->newChild("numParticles"))) - { - child->setAttr("value", m_runtimeData.nParticles); - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -//Streaming Stats Widget -////////////////////////////////////////////////////////////////////////// - -CStreamingStatsWidget::CStreamingStatsWidget(IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud) - : ICryPerfHUDWidget(eWidget_StreamingStats) -{ - m_pPerfHUD = pPerfHud; - m_pInfoBox = pPerfHud->CreateInfoMenuItem(pParentMenu, "Streaming", NULL, Rect(45, 200, 100, 300), true); - - //m_maxMeshSizeArroundMB = 0; - //m_maxTextureSizeArroundMB = 0; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingStatsWidget::Update() -{ -} - -////////////////////////////////////////////////////////////////////////// -bool CStreamingStatsWidget::ShouldUpdate() -{ - if (!m_pInfoBox->IsHidden() || - m_pPerfHUD->WarningsWindowEnabled()) - { - return true; - } - return false; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingStatsWidget::LoadBudgets(XmlNodeRef perfXML) -{ - /* -if(perfXML) -{ -XmlNodeRef xmlNode; -if( (xmlNode=perfXML->findChild("MeshSizeArround")) ) -{ - xmlNode->getAttr("value", m_maxMeshSizeArroundMB); -} -if( (xmlNode=perfXML->findChild("TextureSizeArround")) ) -{ - xmlNode->getAttr("value", m_maxTextureSizeArroundMB); -} -} -*/ -} - -////////////////////////////////////////////////////////////////////////// -//Warnings Widget -////////////////////////////////////////////////////////////////////////// - -CWarningsWidget::CWarningsWidget(IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud) - : ICryPerfHUDWidget(eWidget_Warnings) -{ - m_pInfoBox = pPerfHud->CreateInfoMenuItem(pParentMenu, "Warnings", NULL, Rect(890, 150, 900, 200) /*, true*/); - - m_nMainThreadId = CryGetCurrentThreadId(); -} - -void CWarningsWidget::Reset() -{ - m_warnings.clear(); -} - -void CWarningsWidget::Update() -{ - //must be Main thread for MT warnings to work - assert(CryGetCurrentThreadId() == m_nMainThreadId); - - //Update from multithreaded queue - while (!m_threadWarnings.empty()) - { - SWarning warning; - if (m_threadWarnings.try_pop(warning)) - { - AddWarning(warning.remainingDuration, warning.text); - } - } - - float frameTime = gEnv->pTimer->GetRealFrameTime(); - - //delete old warnings - // [K01]: fixing Linux crash - TSWarnings::iterator iter = m_warnings.begin(); - while (iter != m_warnings.end()) - { - SWarning* pW = &(*iter); - pW->remainingDuration -= frameTime; - - if (pW->remainingDuration <= 0.f) - { - iter = m_warnings.erase(iter); - } - else - { - ++iter; - } - } - - int nWarnings = m_warnings.size(); - m_pInfoBox->ClearEntries(); - - //display warnings - for (int i = 0; i < nWarnings; i++) - { - m_pInfoBox->AddEntry(m_warnings[i].text, CPerfHUD::COL_ERROR, CPerfHUD::TEXT_SIZE_WARN); - } -} - -bool CWarningsWidget::ShouldUpdate() -{ - return !m_pInfoBox->IsHidden(); -} - -void CWarningsWidget::SaveStats(XmlNodeRef statsXML) -{ - if (statsXML) - { - const int nWarnings = m_warnings.size(); - - if (nWarnings > 0) - { - XmlNodeRef warningNode; - - if ((warningNode = statsXML->newChild("warnings"))) - { - XmlNodeRef child; - - for (int i = 0; i < nWarnings; i++) - { - if ((child = warningNode->newChild("warning"))) - { - child->setAttr("value", m_warnings[i].text); - } - } - } - } - } -} - -void CWarningsWidget::AddWarningV(float duration, const char* fmt, va_list argList) -{ - char warningText[WARNING_LENGTH]; - - int written = vsnprintf_s(warningText, WARNING_LENGTH, WARNING_LENGTH - 1, fmt, argList); - - if (written == -1) - { - warningText[WARNING_LENGTH - 1] = '\0'; - } - - AddWarning(duration, warningText); -} - -void CWarningsWidget::AddWarning(float duration, const char* warning) -{ - if (CryGetCurrentThreadId() == m_nMainThreadId) - { - const size_t nWarnings = m_warnings.size(); - bool bNewWarning = true; - - ptrdiff_t nCompareLen = strlen(warning); - const char* s = strchr(warning, ':'); - if (s) - { - nCompareLen = s - warning; - } - - for (size_t i = 0; i < nWarnings; i++) - { - if (strncmp(m_warnings[i].text, warning, nCompareLen) == 0) - { - //warning already exists, update duration - m_warnings[i].remainingDuration = duration; - cry_strcpy(m_warnings[i].text, warning); - bNewWarning = false; - break; - } - } - - if (bNewWarning) - { - SWarning newWarning; - newWarning.remainingDuration = duration; - cry_strcpy(newWarning.text, warning); - - m_warnings.push_back(newWarning); - } - } - else - { - //add to thread safe queue, warning will be added next update - SWarning newWarning; - newWarning.remainingDuration = duration; - cry_strcpy(newWarning.text, warning); - m_threadWarnings.push(newWarning); - } -} - -////////////////////////////////////////////////////////////////////////// -//Render Batch Stats Widget -////////////////////////////////////////////////////////////////////////// - -CRenderBatchWidget::CRenderBatchWidget(IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud) - : ICryPerfHUDWidget(eWidget_RenderBatchStats) -{ - m_pTable = pPerfHud->CreateTableMenuItem(pParentMenu, "Render Batch Stats"); - - m_pRStatsCVar = GetISystem()->GetIConsole()->GetCVar("r_stats"); - - m_displayMode = DISPLAY_MODE_BATCH_STATS; - - m_pTable->RemoveColumns(); - m_pTable->AddColumn("Name"); - m_pTable->AddColumn("DPs"); - m_pTable->AddColumn("Instances"); - m_pTable->AddColumn("ZPass"); - m_pTable->AddColumn("Shadows"); - m_pTable->AddColumn("General"); - m_pTable->AddColumn("Transparent"); - m_pTable->AddColumn("Misc"); -} - -void CRenderBatchWidget::Reset() -{ -} - -void CRenderBatchWidget::SaveStats(XmlNodeRef statsXML) -{ -} - -void CRenderBatchWidget::Enable(int mode) -{ - mode = min(mode, DISPLAY_MODE_NUM - 1); - EDisplayMode newMode = (EDisplayMode)mode; - - if (m_displayMode != newMode) - { - //workaround for now, - //since we poke renderer in order to gather stats - switch (m_displayMode) - { - case DISPLAY_MODE_BATCH_STATS: - gEnv->pRenderer->CollectDrawCallsInfo(false); - break; - - case DISPLAY_MODE_GPU_TIMES: - m_pRStatsCVar->Set(0); - break; - } - - switch (newMode) - { - case DISPLAY_MODE_BATCH_STATS: - m_pTable->RemoveColumns(); - m_pTable->AddColumn("Name"); - m_pTable->AddColumn("DPs"); - m_pTable->AddColumn("Instances"); - m_pTable->AddColumn("ZPass"); - m_pTable->AddColumn("Shadows"); - m_pTable->AddColumn("General"); - m_pTable->AddColumn("Transparent"); - m_pTable->AddColumn("Misc"); - m_displayMode = newMode; - break; - - case DISPLAY_MODE_GPU_TIMES: - m_pTable->RemoveColumns(); - m_pTable->AddColumn("Name"); - m_pTable->AddColumn("Num Batches"); - m_pTable->AddColumn("Num Verts"); - m_pTable->AddColumn("Num Tris"); - m_displayMode = newMode; - break; - - default: - CryLogAlways("[Render Batch Stats] Attempting to set incorrect display mode set: %d", mode); - break; - } - } - - m_pTable->Hide(false); -} - -void CRenderBatchWidget::Disable() -{ - //ensure renderer is not doing unnecessary work - m_pRStatsCVar->Set(0); - gEnv->pRenderer->CollectDrawCallsInfo(false); - m_pTable->Hide(true); -} - - -bool CRenderBatchWidget::ShouldUpdate() -{ - return !m_pTable->IsHidden(); -} - -void CRenderBatchWidget::Update() -{ - switch (m_displayMode) - { - case DISPLAY_MODE_BATCH_STATS: - Update_ModeBatchStats(); - break; - case DISPLAY_MODE_GPU_TIMES: - Update_ModeGpuTimes(); - break; - default: - CryLogAlways("[Render Batch Stats]Incorrect Display mode set: %d", m_displayMode); - break; - } -} - -void CRenderBatchWidget::Update_ModeBatchStats() -{ -#if !defined(_RELEASE) - IRenderer* pRenderer = gEnv->pRenderer; - - pRenderer->CollectDrawCallsInfo(true); - - typedef std::map BatchMap; - typedef std::map::iterator BatchMapItor; - - //sorted Map elements - std::vector sortedBatchList; - - BatchMap batchMap; - - //mesh totals - static const char* strMeshTotals = "TOTAL (Mesh)"; - BatchInfoPerPass totalsMesh; - totalsMesh.col.set(255, 255, 255, 255); - totalsMesh.name = strMeshTotals; - - int nDPs = gEnv->pRenderer->GetCurrentNumberOfDrawCalls(); - - //scene totals - static const char* strSceneTotals = "TOTAL (Scene)"; - - BatchInfoPerPass totalsScene; - totalsScene.col.set(0, 255, 255, 255); - totalsScene.name = strSceneTotals; - totalsScene.nBatches = nDPs; - - int unknownDPs = nDPs; - - m_pTable->ClearTable(); - - IRenderer::RNDrawcallsMapMesh& drawCallsInfo = gEnv->pRenderer->GetDrawCallsInfoPerMesh(); - - IRenderer::RNDrawcallsMapMeshItor pEnd = drawCallsInfo.end(); - IRenderer::RNDrawcallsMapMeshItor pItor = drawCallsInfo.begin(); - - //Per RenderNode Stats - for (; pItor != pEnd; ++pItor) - { - IRenderer::SDrawCallCountInfo& drawInfo = pItor->second; - - uint32 nDrawcalls = drawInfo.nShadows + drawInfo.nZpass + drawInfo.nGeneral + drawInfo.nTransparent + drawInfo.nMisc; - - const char* pRenderNodeName = drawInfo.meshName; - const char* pNameShort = strrchr(pRenderNodeName, '/'); - - if (pNameShort) - { - pRenderNodeName = pNameShort + 1; - } - - BatchInfoPerPass batch; - - batch.name = pRenderNodeName; - batch.nBatches = nDrawcalls; - batch.nInstances = 1; - batch.nZpass = drawInfo.nZpass; - batch.nShadows = drawInfo.nShadows; - batch.nGeneral = drawInfo.nGeneral; - batch.nTransparent = drawInfo.nTransparent; - batch.nMisc = drawInfo.nMisc; - - BatchMapItor batchIter = batchMap.find(string(pRenderNodeName)); - - //already an entry for this stat obj - append details - if (batchIter != batchMap.end()) - { - BatchInfoPerPass& currentBatch = batchIter->second; - currentBatch += batch; - } - else - { - //insert new entry into map - std::pair newElem = batchMap.insert(BatchMapItor::value_type(string(pRenderNodeName), batch)); - BatchInfoPerPass& newBatch = newElem.first->second; - sortedBatchList.push_back(&newBatch); - } - - totalsMesh += batch; - } - - unknownDPs -= totalsMesh.nBatches; - - // - // Unknown counts (sceneDP - sum of batches) - // - //could be -ve or +ve (-ve for conditional rendering) - if (unknownDPs != 0) - { - static const char* s_strUnknown = "Unknown"; - static BatchInfoPerPass s_unknownBatch; - s_unknownBatch.Reset(); - s_unknownBatch.name = s_strUnknown; - s_unknownBatch.nBatches = max(0, unknownDPs); - s_unknownBatch.col.set(255, 255, 0, 255); - sortedBatchList.push_back(&s_unknownBatch); - } - - //Scene Totals - m_pTable->AddData(0, totalsScene.col, totalsScene.name); - m_pTable->AddData(1, totalsScene.col, "%d", totalsScene.nBatches); - m_pTable->AddData(2, totalsScene.col, "%d", totalsScene.nInstances); - m_pTable->AddData(3, totalsScene.col, "%d", totalsScene.nZpass); - m_pTable->AddData(4, totalsScene.col, "%d", totalsScene.nShadows); - m_pTable->AddData(5, totalsScene.col, "%d", totalsScene.nGeneral); - m_pTable->AddData(6, totalsScene.col, "%d", totalsScene.nTransparent); - m_pTable->AddData(7, totalsScene.col, "%d", totalsScene.nMisc); - - //Mesh Totals - m_pTable->AddData(0, totalsMesh.col, totalsMesh.name); - m_pTable->AddData(1, totalsMesh.col, "%d", totalsMesh.nBatches); - m_pTable->AddData(2, totalsMesh.col, "%d", totalsMesh.nInstances); - m_pTable->AddData(3, totalsMesh.col, "%d", totalsMesh.nZpass); - m_pTable->AddData(4, totalsMesh.col, "%d", totalsMesh.nShadows); - m_pTable->AddData(5, totalsMesh.col, "%d", totalsMesh.nGeneral); - m_pTable->AddData(6, totalsMesh.col, "%d", totalsMesh.nTransparent); - m_pTable->AddData(7, totalsMesh.col, "%d", totalsMesh.nMisc); - - - if (int nBatches = sortedBatchList.size()) - { - std::sort(sortedBatchList.begin(), sortedBatchList.end(), BatchInfoSortPerPass()); - - for (int i = 0; i < nBatches; i++) - { - BatchInfoPerPass* batch = sortedBatchList[i]; - - int nInstances = max(1, (int)batch->nInstances); - - m_pTable->AddData(0, batch->col, batch->name); - - //Due to different render meshes with the same name, averaged - //stats are a bit confusing, disabling for now - if constexpr (0 && batch->nInstances > 1) - { - m_pTable->AddData(1, batch->col, "%d (%d)", batch->nBatches, batch->nBatches / nInstances); - m_pTable->AddData(2, batch->col, "%d", batch->nInstances); - m_pTable->AddData(3, batch->col, "%d (%d)", batch->nZpass, batch->nZpass / nInstances); - m_pTable->AddData(4, batch->col, "%d (%d)", batch->nShadows, batch->nShadows / nInstances); - m_pTable->AddData(5, batch->col, "%d (%d)", batch->nGeneral, batch->nGeneral / nInstances); - m_pTable->AddData(6, batch->col, "%d (%d)", batch->nTransparent, batch->nTransparent / nInstances); - m_pTable->AddData(7, batch->col, "%d (%d)", batch->nMisc, batch->nMisc / nInstances); - } - else - { - m_pTable->AddData(1, batch->col, "%d", batch->nBatches); - m_pTable->AddData(2, batch->col, "%d", batch->nInstances); - m_pTable->AddData(3, batch->col, "%d", batch->nZpass); - m_pTable->AddData(4, batch->col, "%d", batch->nShadows); - m_pTable->AddData(5, batch->col, "%d", batch->nGeneral); - m_pTable->AddData(6, batch->col, "%d", batch->nTransparent); - m_pTable->AddData(7, batch->col, "%d", batch->nMisc); - } - } - } -#else - m_pTable->ClearTable(); - m_pTable->AddData(0, ColorB(255, 0, 0, 255), "Not supported in Release builds"); -#endif//RELEASE (DO_RENDERSTATS - not available in CrySystem) -} - -void CRenderBatchWidget::Update_ModeGpuTimes() -{ - m_pTable->ClearTable(); - m_pTable->AddData(0, ColorB(255, 0, 0, 255), "Not supported for this platform"); -} - - -#endif //USE_PERFHUD - diff --git a/Code/CryEngine/CrySystem/PerfHUD.h b/Code/CryEngine/CrySystem/PerfHUD.h deleted file mode 100644 index 27078eb3c6..0000000000 --- a/Code/CryEngine/CrySystem/PerfHUD.h +++ /dev/null @@ -1,478 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Button implementation in the MiniGUI - - -#ifndef CRYINCLUDE_CRYSYSTEM_PERFHUD_H -#define CRYINCLUDE_CRYSYSTEM_PERFHUD_H -#pragma once - - -#include - -#ifdef USE_PERFHUD - -#include -#include "MiniGUI/MiniInfoBox.h" -#include "MiniGUI/MiniTable.h" - -//Macros for console based widget control - -#define SET_WIDGET_DECL(WIDGET_NAME) \ - static int s_cvar_##WIDGET_NAME; \ - static void Set_##WIDGET_NAME##_Widget(ICVar * pCvar); - -#define SET_WIDGET_DEF(WIDGET_NAME, WIDGET_ID) \ - int CPerfHUD::s_cvar_##WIDGET_NAME = 0; \ - void CPerfHUD::Set_##WIDGET_NAME##_Widget(ICVar * pCvar) \ - { \ - ICryPerfHUD* pPerfHud = gEnv->pSystem->GetPerfHUD(); \ - if (pPerfHud) \ - { \ - int val = pCvar->GetIVal(); \ - if (val) \ - { \ - pPerfHud->SetState(eHudOutOfFocus); \ - pPerfHud->EnableWidget(ICryPerfHUDWidget::WIDGET_ID, val); \ - } \ - else \ - { \ - pPerfHud->DisableWidget(ICryPerfHUDWidget::WIDGET_ID); \ - } \ - } \ - } - -#define SET_WIDGET_COMMAND(COMMAND_NAME, WIDGET_NAME) \ - REGISTER_CVAR2_CB(COMMAND_NAME, &s_cvar_##WIDGET_NAME, 0, VF_ALWAYSONCHANGE, "", Set_##WIDGET_NAME##_Widget); - -////////////////////////////////////////////////////////////////////////// -// Root window all other controls derive from -class CPerfHUD - : public ICryPerfHUD - , public minigui::IMiniGUIEventListener - , public AzFramework::InputChannelEventListener -{ -public: - CRYINTERFACE_BEGIN() - CRYINTERFACE_ADD(ICryPerfHUD) - CRYINTERFACE_END() - CRYGENERATE_SINGLETONCLASS(CPerfHUD, "PerfHUD", 0x006945f9985e4ce2, 0x872120bfdec09ca5) - -public: - ////////////////////////////////////////////////////////////////////////// - // ICryPerfHUD implementation - ////////////////////////////////////////////////////////////////////////// - virtual void Init(); - virtual void Done(); - virtual void Draw(); - virtual void LoadBudgets(); - virtual void SaveStats(const char* filename); - virtual void ResetWidgets(); - virtual void Reset(); - virtual void Destroy(); - - //Set state through code (rather than using joypad input) - virtual void SetState(EHudState state); - - virtual void Show(bool bRestoreState); - - virtual void AddWidget(ICryPerfHUDWidget* pWidget); - virtual void RemoveWidget(ICryPerfHUDWidget* pWidget); - - ////////////////////////////////////////////////////////////////////////// - // Gui Creation helper funcs - ////////////////////////////////////////////////////////////////////////// - virtual minigui::IMiniCtrl* CreateMenu(const char* name, minigui::IMiniCtrl* pParent = NULL); - virtual bool CreateCVarMenuItem(minigui::IMiniCtrl* pMenu, const char* name, const char* controlVar, float controlVarOn, float controlVarOff); - virtual bool CreateCallbackMenuItem(minigui::IMiniCtrl* pMenu, const char* name, minigui::ClickCallback callback, void* pCallbackData); - virtual minigui::IMiniInfoBox* CreateInfoMenuItem(minigui::IMiniCtrl* pMenu, const char* name, minigui::RenderCallback renderCallback, const minigui::Rect& rect, bool onAtStart = false); - virtual minigui::IMiniTable* CreateTableMenuItem(minigui::IMiniCtrl* pMenu, const char* name); - - virtual minigui::IMiniCtrl* GetMenu(const char* name); - - virtual void EnableWidget(ICryPerfHUDWidget::EWidgetID id, int mode); - virtual void DisableWidget(ICryPerfHUDWidget::EWidgetID id); - - ////////////////////////////////////////////////////////////////////////// - // WARNINGS - Widget Specific Interface - ////////////////////////////////////////////////////////////////////////// - virtual void AddWarning(float duration, const char* fmt, va_list argList); - virtual bool WarningsWindowEnabled() const; - - ////////////////////////////////////////////////////////////////////////// - // FPS - Widget Specific Interface - ////////////////////////////////////////////////////////////////////////// - virtual const std::vector* GetFpsBuckets(float& totalTime) const; - - ////////////////////////////////////////////////////////////////////////// - // IMiniGUIEventListener implementation - ////////////////////////////////////////////////////////////////////////// - virtual void OnCommand(minigui::SCommand& cmd); - ////////////////////////////////////////////////////////////////////////// - - // AzFramework::InputChannelEventListener - bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - AZ::s32 GetPriority() const override { return AzFramework::InputChannelEventListener::GetPriorityUI(); } - - ////////////////////////////////////////////////////////////////////////// - // CLICK CALLBACKS - ////////////////////////////////////////////////////////////////////////// - - static void ResetCallback(void* data, bool status); - static void ReloadBudgetsCallback(void* data, bool status); - static void SaveStatsCallback(void* data, bool status); - - ////////////////////////////////////////////////////////////////////////// - // RENDER CALLBACKS - ////////////////////////////////////////////////////////////////////////// - - static void DisplayRenderInfoCallback(const minigui::Rect& rect); - - ////////////////////////////////////////////////////////////////////////// - // CVAR CALLBACK - ////////////////////////////////////////////////////////////////////////// - - static void CVarChangeCallback(ICVar* pCvar); - - SET_WIDGET_DECL(Warnings); - SET_WIDGET_DECL(RenderSummary); - SET_WIDGET_DECL(RenderBatchStats); - SET_WIDGET_DECL(FpsBuckets); - SET_WIDGET_DECL(Particles); - SET_WIDGET_DECL(PakFile); - - ////////////////////////////////////////////////////////////////////////// - // Static Data - ////////////////////////////////////////////////////////////////////////// - - static const float OVERSCAN_X; - static const float OVERSCAN_Y; - - static const ColorB COL_NORM; - static const ColorB COL_WARN; - static const ColorB COL_ERROR; - - static const float TEXT_SIZE_NORM; - static const float TEXT_SIZE_WARN; - static const float TEXT_SIZE_ERROR; - - static const float ACTIVATE_TIME_FROM_GAME; - static const float ACTIVATE_TIME_FROM_HUD; - -protected: - void InitUI(minigui::IMiniGUI* pGUI); - void SetNextState(); - -protected: - - static int m_sys_perfhud; - static int m_sys_perfhud_pause; - - int m_sys_perfhud_prev; - - //record last menu position - float m_menuStartX; - float m_menuStartY; - - bool m_hudCreated; - - bool m_L1Pressed; - bool m_L2Pressed; - bool m_R1Pressed; - bool m_R2Pressed; - bool m_changingState; - bool m_hwMouseEnabled; - - float m_triggersDownStartTime; - - EHudState m_hudState; - EHudState m_hudLastState; - - typedef std::vector< _smart_ptr, stl::STLGlobalAllocator<_smart_ptr > >::iterator TWidgetIterator; - - std::vector< _smart_ptr, stl::STLGlobalAllocator<_smart_ptr > > m_widgets; - std::vector > m_rootMenus; -}; - -class CFpsWidget - : public ICryPerfHUDWidget -{ -public: - - CFpsWidget(minigui::IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud); - - virtual void Reset(); - virtual void Update(); - virtual bool ShouldUpdate(); - virtual void LoadBudgets(XmlNodeRef perfXML); - virtual void SaveStats(XmlNodeRef statsXML); - virtual void Enable([[maybe_unused]] int mode) { m_pInfoBox->Hide(false); } - virtual void Disable() { m_pInfoBox->Hide(true); } - - void Init(); - - const std::vector* GetFpsBuckets(float& totalTime) const; - - static void ResetCallback(void* data, bool status); - -protected: - - static const uint32 NUM_FPS_BUCKETS_DEFAULT = 6; - - struct PerfBucketsStat - { - std::vector buckets; - float totalTime; - }; - - template - void UpdateBuckets(PerfBucketsStat& buckets, float frameTime, const char* name, float stat); - - // Data - static int m_cvarPerfHudFpsExclusive; - - enum EPerfBucketType - { - BUCKET_FPS = 0, - BUCKET_GPU, - BUCKET_DP, - BUCKET_TYPE_NUM - }; - - - PerfBucketsStat m_perfBuckets[BUCKET_TYPE_NUM]; - - float m_fpsBucketSize; - float m_fpsBudget; - float m_dpBudget; - float m_dpBucketSize; - - minigui::IMiniInfoBox* m_pInfoBox; -}; - -class CRenderStatsWidget - : public ICryPerfHUDWidget -{ -public: - - CRenderStatsWidget(minigui::IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud); - - virtual void Reset() {} - virtual void Update(); - virtual bool ShouldUpdate(); - virtual void LoadBudgets(XmlNodeRef perfXML); - virtual void SaveStats(XmlNodeRef statsXML); - virtual void Enable([[maybe_unused]] int mode) { m_pInfoBox->Hide(false); } - virtual void Disable() { m_pInfoBox->Hide(true); } - -protected: - - //budgets - float m_fpsBudget; - uint32 m_dpBudget; - uint32 m_polyBudget; - uint32 m_postEffectBudget; - uint32 m_shadowCastBudget; - uint32 m_particlesBudget; - - //runtime data - struct SRuntimeData - { - Vec3 cameraPos; - Ang3 cameraRot; - float fps; - uint32 nDrawPrims; - uint32 nPolys; - uint32 nPostEffects; - uint32 nFwdLights; - uint32 nFwdShadowLights; - uint32 nDefLights; - uint32 nDefShadowLights; - uint32 nDefCubeMaps; - int nParticles; - bool hdrEnabled; - bool renderThreadEnabled; - }; - - SRuntimeData m_runtimeData; - minigui::IMiniInfoBox* m_pInfoBox; - ICryPerfHUD* m_pPerfHUD; - uint32 m_buildNum; -}; - -class CStreamingStatsWidget - : public ICryPerfHUDWidget -{ -public: - - CStreamingStatsWidget(minigui::IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud); - - virtual void Reset() {} - virtual void Update(); - virtual bool ShouldUpdate(); - virtual void LoadBudgets(XmlNodeRef perfXML); - virtual void SaveStats(XmlNodeRef statsXML) {}; - virtual void Enable([[maybe_unused]] int mode) { m_pInfoBox->Hide(false); } - virtual void Disable() { m_pInfoBox->Hide(true); } - -protected: - //float m_maxMeshSizeArroundMB; - //float m_maxTextureSizeArroundMB; - minigui::IMiniInfoBox* m_pInfoBox; - ICryPerfHUD* m_pPerfHUD; -}; - - -class CWarningsWidget - : public ICryPerfHUDWidget -{ -public: - - CWarningsWidget(minigui::IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud); - - virtual void Reset(); - virtual void Update(); - virtual bool ShouldUpdate(); - virtual void LoadBudgets(XmlNodeRef perfXML) {}; - virtual void SaveStats(XmlNodeRef statsXML); - virtual void Enable([[maybe_unused]] int mode) { m_pInfoBox->Hide(false); } - virtual void Disable() { m_pInfoBox->Hide(true); } - - void AddWarningV(float duration, const char* fmt, va_list argList); - void AddWarning(float duration, const char* warning); - -protected: - - static const uint32 WARNING_LENGTH = 64; - - struct SWarning - { - char text[WARNING_LENGTH]; - float remainingDuration; - }; - - minigui::IMiniInfoBox* m_pInfoBox; - - typedef std::vector< SWarning > TSWarnings; - - TSWarnings m_warnings; - - CryMT::queue m_threadWarnings; - - threadID m_nMainThreadId; -}; - -class CRenderBatchWidget - : public ICryPerfHUDWidget -{ -public: - - CRenderBatchWidget(minigui::IMiniCtrl* pParentMenu, ICryPerfHUD* pPerfHud); - - virtual void Reset(); - virtual void Update(); - virtual bool ShouldUpdate(); - virtual void LoadBudgets(XmlNodeRef perfXML) {}; - virtual void SaveStats(XmlNodeRef statsXML); - virtual void Enable(int mode); - virtual void Disable(); - - void Update_ModeGpuTimes(); - void Update_ModeBatchStats(); - -protected: - - struct BatchInfoGpuTimes - { - const char* name; - uint32 nBatches; - float gpuTime; - int numVerts; - int numIndices; - }; - - struct BatchInfoSortGpuTimes - { - inline bool operator() (const BatchInfoGpuTimes& lhs, const BatchInfoGpuTimes& rhs) const - { - return lhs.gpuTime > rhs.gpuTime; - } - }; - - struct BatchInfoPerPass - { - const char* name; - uint16 nBatches; - uint16 nInstances; - uint16 nZpass; - uint16 nShadows; - uint16 nGeneral; - uint16 nTransparent; - uint16 nMisc; - ColorB col; - - BatchInfoPerPass() - { - Reset(); - } - - void Reset() - { - name = NULL; - nBatches = 0; - nInstances = 0; - nZpass = 0; - nShadows = 0; - nGeneral = 0; - nTransparent = 0; - nMisc = 0; - col.set(255, 255, 255, 255); - } - - void operator += (const BatchInfoPerPass& rhs) - { - nBatches += rhs.nBatches; - nInstances += rhs.nInstances; - nZpass += rhs.nZpass; - nShadows += rhs.nShadows; - nGeneral += rhs.nGeneral; - nTransparent += rhs.nTransparent; - nMisc += rhs.nMisc; - } - }; - - struct BatchInfoSortPerPass - { - inline bool operator() (const BatchInfoPerPass* lhs, const BatchInfoPerPass* rhs) const - { - return lhs->nBatches > rhs->nBatches; - } - }; - - enum EDisplayMode - { - DISPLAY_MODE_NONE = 0, - DISPLAY_MODE_BATCH_STATS, - DISPLAY_MODE_GPU_TIMES, - DISPLAY_MODE_NUM, - }; - - minigui::IMiniTable* m_pTable; - ICVar* m_pRStatsCVar; - EDisplayMode m_displayMode; -}; - -#endif //USE_PERFHUD - -#endif // CRYINCLUDE_CRYSYSTEM_PERFHUD_H diff --git a/Code/CryEngine/CrySystem/ResourceManager.cpp b/Code/CryEngine/CrySystem/ResourceManager.cpp index 08a674136d..f78538760f 100644 --- a/Code/CryEngine/CrySystem/ResourceManager.cpp +++ b/Code/CryEngine/CrySystem/ResourceManager.cpp @@ -320,7 +320,6 @@ bool CResourceManager::LoadFastLoadPaks(bool bToMemory) } const char* const assetsDir = "@assets@"; - const char* shaderPakPath = "ShaderCacheStartup.pak"; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_2 @@ -328,7 +327,6 @@ bool CResourceManager::LoadFastLoadPaks(bool bToMemory) #endif gEnv->pCryPak->OpenPacks(assetsDir, AZ::IO::PathString(FAST_LOADING_PAKS_SRC_FOLDER) + "*.pak", nPakPreloadFlags, &m_fastLoadPakPaths); - gEnv->pCryPak->OpenPack(assetsDir, shaderPakPath, AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK); gEnv->pCryPak->OpenPack(assetsDir, "Engine.pak", AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY); return !m_fastLoadPakPaths.empty(); } @@ -343,11 +341,6 @@ void CResourceManager::UnloadFastLoadPaks() gEnv->pCryPak->ClosePack(m_fastLoadPakPaths[i].c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL); } m_fastLoadPakPaths.clear(); - - if (gEnv && gEnv->pRenderer) - { - gEnv->pRenderer->UnloadShaderStartupCache(); - } } ////////////////////////////////////////////////////////////////////////// @@ -712,23 +705,11 @@ void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_P } } - //Load and precache frontend shader cache - if (g_cvars.archiveVars.nLoadFrontendShaderCache) - { - gEnv->pRenderer->LoadShaderLevelCache(); - gEnv->pRenderer->EF_Query(EFQ_SetShaderCombinations); - } - break; } case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE: { - if (g_cvars.archiveVars.nLoadFrontendShaderCache) - { - gEnv->pRenderer->UnloadShaderLevelCache(); - } - if (!gEnv->bMultiplayer) { UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp"); diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp index 37a7de8391..7f8c75b2a8 100644 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp +++ b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp @@ -1211,20 +1211,9 @@ void CStreamEngine::TempFree(void* p, size_t nSize) namespace { #ifdef STREAMENGINE_ENABLE_STATS - void DrawText(const float x, const float y, ColorF c, const char* format, ...) - { - va_list args; - va_start(args, format); - - SDrawTextInfo ti; - ti.flags = eDrawText_FixedSize | eDrawText_2D | eDrawText_Monospace; - ti.xscale = ti.yscale = 1.2f; - ti.color[0] = c.r; - ti.color[1] = c.g; - ti.color[2] = c.b; - ti.color[3] = c.a; - gEnv->pRenderer->DrawTextQueued(Vec3(x, y, 1.0f), ti, format, args); - va_end(args); + void DrawText(const float, const float, ColorF, const char*, ...) + { + // ToDo: Remove whole file with SPEC-343, or update to draw with Atom? Likely the former as I think this whole system is dead. } #endif diff --git a/Code/CryEngine/CrySystem/System.cpp b/Code/CryEngine/CrySystem/System.cpp index af9b674f6a..31eb286a17 100644 --- a/Code/CryEngine/CrySystem/System.cpp +++ b/Code/CryEngine/CrySystem/System.cpp @@ -127,7 +127,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include #include #include -#include "VisRegTest.h" #include #include @@ -135,8 +134,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include #include "XConsole.h" #include "Log.h" -#include "CrySizerStats.h" -#include "CrySizerImpl.h" #include "NotificationNetwork.h" #include "ProfileLog.h" @@ -153,7 +150,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include "ServerThrottle.h" #include "ResourceManager.h" #include "HMDBus.h" -#include "OverloadSceneManager/OverloadSceneManager.h" #include #include "IZLibCompressor.h" @@ -318,11 +314,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_pSystemEventDispatcher->RegisterListener(this); } -#ifdef WIN32 - m_hInst = NULL; - m_hWnd = NULL; -#endif - ////////////////////////////////////////////////////////////////////////// // Clear environment. ////////////////////////////////////////////////////////////////////////// @@ -357,7 +348,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_pIFont = NULL; m_pIFontUi = NULL; - m_pVisRegTest = NULL; m_rWidth = NULL; m_rHeight = NULL; m_rWidthAndHeightAsFractionOfScreenSize = NULL; @@ -368,7 +358,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_cvSSInfo = NULL; m_rStencilBits = NULL; m_rFullscreen = NULL; - m_rDriver = NULL; m_sysNoUpdate = NULL; m_pMemoryManager = NULL; m_pProcess = NULL; @@ -413,7 +402,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_pCpu = NULL; m_bInitializedSuccessfully = false; - m_bShaderCacheGenMode = false; m_bRelaunch = false; m_iLoadingMode = 0; m_bTestMode = false; @@ -430,9 +418,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_expectingMapCommand = false; #endif - // no mem stats at the moment - m_pMemStats = NULL; - m_pSizer = NULL; m_pCVarQuit = NULL; m_bForceNonDevMode = false; @@ -468,9 +453,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) InitThreadSystem(); - m_pMiniGUI = NULL; - m_pPerfHUD = NULL; - g_pPakHeap = new CMTSafeHeap; if (!AZ::AllocatorInstance::IsReady()) @@ -516,7 +498,6 @@ CSystem::~CSystem() CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere"); - SAFE_DELETE(m_pVisRegTest); SAFE_DELETE(m_pXMLUtils); SAFE_DELETE(m_pArchiveHost); SAFE_DELETE(m_pThreadTaskManager); @@ -704,13 +685,6 @@ void CSystem::ShutDown() SAFE_RELEASE(m_pViewSystem); SAFE_RELEASE(m_pLevelSystem); - //Can't kill renderer before we delete CryFont, 3DEngine, etc - if (GetIRenderer()) - { - GetIRenderer()->ShutDown(); - SAFE_RELEASE(m_env.pRenderer); - } - if (m_env.pLog) { m_env.pLog->UnregisterConsoleVariables(); @@ -731,7 +705,6 @@ void CSystem::ShutDown() SAFE_RELEASE(m_cvSSInfo); SAFE_RELEASE(m_rStencilBits); SAFE_RELEASE(m_rFullscreen); - SAFE_RELEASE(m_rDriver); SAFE_RELEASE(m_sysWarnings); SAFE_RELEASE(m_sysKeyboard); @@ -751,13 +724,9 @@ void CSystem::ShutDown() SAFE_RELEASE(m_pNotificationNetwork); SAFE_DELETE(m_env.pSoftCodeMgr); - SAFE_DELETE(m_pMemStats); - SAFE_DELETE(m_pSizer); SAFE_DELETE(m_pDefaultValidator); m_pValidator = nullptr; - SAFE_DELETE(m_env.pOverloadSceneManager); - SAFE_DELETE(m_pLocalizationManager); //DebugStats(false, false);//true); @@ -816,11 +785,6 @@ void CSystem::Quit() m_pUserCallback->OnQuit(); } - if (GetIRenderer()) - { - GetIRenderer()->RestoreGamma(); - } - gEnv->pLog->FlushAndClose(); // Latest possible place to flush any pending messages to disk before the forceful termination. @@ -1229,8 +1193,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) } #endif //EXCLUDE_UPDATE_ON_CONSOLE - gEnv->pOverloadSceneManager->Update(); - #ifdef WIN32 // enable/disable SSE fp exceptions (#nan and /0) // need to do it each frame since sometimes they are being reset @@ -1242,12 +1204,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) m_nUpdateCounter++; #ifndef EXCLUDE_UPDATE_ON_CONSOLE - if (!m_sDelayedScreeenshot.empty()) - { - gEnv->pRenderer->ScreenShot(m_sDelayedScreeenshot.c_str()); - m_sDelayedScreeenshot.clear(); - } - // Check if game needs to be sleeping when not active. SleepIfInactive(); @@ -1278,27 +1234,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) #ifdef USE_REMOTE_CONSOLE GetIRemoteConsole()->Update(); #endif - - if (!gEnv->IsEditor() && gEnv->pRenderer) - { - // If the dimensions of the render target change, - // or are different from the camera defaults, - // we need to update the camera frustum. - CCamera& viewCamera = GetViewCamera(); - const int renderTargetWidth = m_rWidth->GetIVal(); - const int renderTargetHeight = m_rHeight->GetIVal(); - - if (renderTargetWidth != viewCamera.GetViewSurfaceX() || - renderTargetHeight != viewCamera.GetViewSurfaceZ()) - { - viewCamera.SetFrustum(renderTargetWidth, - renderTargetHeight, - viewCamera.GetFov(), - viewCamera.GetNearPlane(), - viewCamera.GetFarPlane(), - gEnv->pRenderer->GetPixelAspectRatio()); - } - } if (nPauseMode != 0) { m_bPaused = true; @@ -1346,53 +1281,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) m_pStreamEngine->Update(); } - if (g_cvars.az_streaming_stats) - { - SDrawTextInfo ti; - ti.flags = eDrawText_FixedSize | eDrawText_2D | eDrawText_Monospace; - ti.xscale = ti.yscale = 1.2f; - - const int viewportHeight = GetViewCamera().GetViewSurfaceZ(); - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_8 -#include AZ_RESTRICTED_FILE(System_cpp) -#else - float y = static_cast(viewportHeight) - 85.0f; -#endif - - AZStd::vector stats; - AZ::Interface::Get()->CollectStatistics(stats); - - for (AZ::IO::Statistic& stat : stats) - { - switch (stat.GetType()) - { - case AZ::IO::Statistic::Type::FloatingPoint: - gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, - AZStd::string::format("%s/%s: %.3f", stat.GetOwner().data(), stat.GetName().data(), stat.GetFloatValue()).c_str()); - break; - case AZ::IO::Statistic::Type::Integer: - gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, - AZStd::string::format("%s/%s: %lli", stat.GetOwner().data(), stat.GetName().data(), stat.GetIntegerValue()).c_str()); - break; - case AZ::IO::Statistic::Type::Percentage: - gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, - AZStd::string::format("%s/%s: %.2f (percent)", stat.GetOwner().data(), stat.GetName().data(), stat.GetPercentage()).c_str()); - break; - default: - gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, AZStd::string::format("Unsupported stat type: %i", static_cast(stat.GetType())).c_str()); - break; - } - y -= 12.0f; - if (y < 0.0f) - { - //Exit the loop because there's no purpose on rendering text outside of the visible area. - break; - } - } - } - #ifndef EXCLUDE_UPDATE_ON_CONSOLE if (m_bIgnoreUpdates) { @@ -1476,12 +1364,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) m_pServerThrottle->Update(); } - ////////////////////////////////////////////////////////////////////////// - if (m_env.pRenderer && m_env.pRenderer->GetIStereoRenderer()->IsRenderingToHMD()) - { - EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, UpdateInternalState); - } - ////////////////////////////////////////////////////////////////////// //update console system if (m_env.pConsole) @@ -1527,6 +1409,7 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) ////////////////////////////////////////////////////////////////////////// // Update Threads Task Manager. ////////////////////////////////////////////////////////////////////////// + if (m_pThreadTaskManager) { FRAME_PROFILER("SysUpdate:ThreadTaskManager", this, PROFILE_SYSTEM); m_pThreadTaskManager->OnUpdate(); @@ -2000,12 +1883,6 @@ void CSystem::Relaunch(bool bRelaunch) SaveConfiguration(); } -////////////////////////////////////////////////////////////////////////// -ICrySizer* CSystem::CreateSizer() -{ - return new CrySizerImpl; -} - ////////////////////////////////////////////////////////////////////////// uint32 CSystem::GetUsedMemory() { @@ -2113,11 +1990,6 @@ void CSystem::ExecuteCommandLine(bool deferred) //gEnv->pConsole->ExecuteString("sys_RestoreSpec test*"); // to get useful debugging information about current spec settings to the log file } -void CSystem::DumpMemoryCoverage() -{ - m_MemoryFragmentationProfiler.DumpMemoryCoverage(); -} - ITextModeConsole* CSystem::GetITextModeConsole() { if (m_bDedicatedServer) diff --git a/Code/CryEngine/CrySystem/System.h b/Code/CryEngine/CrySystem/System.h index f5235f2ea8..5f87fd1ad1 100644 --- a/Code/CryEngine/CrySystem/System.h +++ b/Code/CryEngine/CrySystem/System.h @@ -26,7 +26,6 @@ #include "MTSafeAllocator.h" #include "CPUDetect.h" #include -#include "MemoryFragmentationProfiler.h" // CMemoryFragmentationProfiler #include "ThreadTask.h" #include "RenderBus.h" @@ -48,12 +47,6 @@ struct IZLibCompressor; class CWatchdogThread; class CThreadManager; -struct ICryPerfHUD; -namespace minigui -{ - struct IMiniGUI; -} - #if defined(AZ_RESTRICTED_PLATFORM) #undef AZ_RESTRICTED_SECTION #define SYSTEM_H_SECTION_1 1 @@ -214,7 +207,6 @@ namespace Audio } // namespace Audio struct SDefaultValidator; struct IDataProbe; -class CVisRegTest; #define PHSYICS_OBJECT_ENTITY 0 @@ -227,7 +219,6 @@ extern VTuneFunction VTPause; struct SSystemCVars { - int az_streaming_stats; int sys_streaming_requests_grouping_time_period; int sys_streaming_sleep; int sys_streaming_memory_budget; @@ -270,15 +261,6 @@ struct SSystemCVars int sys_error_debugbreak; int sys_FilesystemCaseSensitivity; - int sys_rendersplashscreen; - const char* sys_splashscreen; - - enum SplashScreenScaleMode - { - SplashScreenScaleMode_Fit = 0, - SplashScreenScaleMode_Fill - }; - int sys_splashScreenScaleMode; int sys_deferAudioUpdateOptim; #if USE_STEAM @@ -424,10 +406,6 @@ public: uint32 GetUsedMemory(); - virtual void DumpMemoryUsageStatistics(bool bUseKB); - virtual void DumpMemoryCoverage(); - void CollectMemInfo(SCryEngineStatsGlobalMemInfo&); - #ifndef _RELEASE virtual void GetCheckpointData(ICheckpointData& data); virtual void IncreaseCheckpointLoadCount(); @@ -444,7 +422,6 @@ public: void Quit(); bool IsQuitting() const; void ShutdownFileSystem(); // used to cleanup any file resources, such as cache handle. - bool IsShaderCacheGenMode() const { return m_bShaderCacheGenMode; } void SetAffinity(); virtual const char* GetUserName(); virtual int GetApplicationInstance(); @@ -452,7 +429,6 @@ public: virtual sUpdateTimes& GetCurrentUpdateTimeStats(); virtual const sUpdateTimes* GetUpdateTimeStats(uint32&, uint32&); - IRenderer* GetIRenderer(){ return m_env.pRenderer; } ITimer* GetITimer(){ return m_env.pTimer; } AZ::IO::IArchive* GetIPak() { return m_env.pCryPak; }; IConsole* GetIConsole() { return m_env.pConsole; }; @@ -472,16 +448,13 @@ public: IThreadTaskManager* GetIThreadTaskManager(); IResourceManager* GetIResourceManager(); ITextModeConsole* GetITextModeConsole(); - IFileChangeMonitor* GetIFileChangeMonitor() { return m_env.pFileChangeMonitor; } IVisualLog* GetIVisualLog() { return m_env.pVisualLog; } INotificationNetwork* GetINotificationNetwork() { return m_pNotificationNetwork; } IProfilingSystem* GetIProfilingSystem() { return &m_ProfilingSystem; } - ICryPerfHUD* GetPerfHUD() { return m_pPerfHUD; } IZLibCompressor* GetIZLibCompressor() { return m_pIZLibCompressor; } IZLibDecompressor* GetIZLibDecompressor() { return m_pIZLibDecompressor; } ILZ4Decompressor* GetLZ4Decompressor() { return m_pILZ4Decompressor; } IZStdDecompressor* GetZStdDecompressor() { return m_pIZStdDecompressor; } - WIN_HWND GetHWND(){ return m_hWnd; } ////////////////////////////////////////////////////////////////////////// // retrieves the perlin noise singleton instance CPNoise3* GetNoiseGen(); @@ -499,7 +472,6 @@ public: void SetIMaterialEffects(IMaterialEffects* pMaterialEffects) { m_env.pMaterialEffects = pMaterialEffects; } void SetIOpticsManager(IOpticsManager* pOpticsManager) { m_env.pOpticsManager = pOpticsManager; } - void SetIFileChangeMonitor(IFileChangeMonitor* pFileChangeMonitor) { m_env.pFileChangeMonitor = pFileChangeMonitor; } void SetIVisualLog(IVisualLog* pVisualLog) { m_env.pVisualLog = pVisualLog; } void DetectGameFolderAccessRights(); @@ -603,7 +575,6 @@ public: ////////////////////////////////////////////////////////////////////////// virtual int SetThreadState(ESubsystem subsys, bool bActive); - virtual ICrySizer* CreateSizer(); virtual bool IsPaused() const { return m_bPaused; }; virtual ILocalizationManager* GetLocalizationManager(); @@ -616,18 +587,6 @@ public: virtual ICryFactoryRegistry* GetCryFactoryRegistry() const; public: - // this enumeration describes the purpose for which the statistics is gathered. - // if it's gathered to be dumped, then some different rules may be applied - enum MemStatsPurposeEnum - { - nMSP_ForDisplay, nMSP_ForDump, nMSP_ForCrashLog, nMSP_ForBudget - }; - // collects the whole memory statistics into the given sizer object - void CollectMemStats (class ICrySizer* pSizer, MemStatsPurposeEnum nPurpose = nMSP_ForDisplay, std::vector* pStats = 0); - void GetExeSizes (ICrySizer* pSizer, MemStatsPurposeEnum nPurpose = nMSP_ForDisplay); - //! refreshes the m_pMemStats if necessary; creates it if it's not created - void TickMemStats(MemStatsPurposeEnum nPurpose = nMSP_ForDisplay, IResourceCollector* pResourceCollector = 0); - #if !defined(RELEASE) void SetVersionInfo(const char* const szVersion); #endif @@ -680,7 +639,6 @@ private: ////////////////////////////////////////////////////////////////////////// // Helper functions. ////////////////////////////////////////////////////////////////////////// - void CreateRendererVars(const SSystemInitParams& startupParams); void CreateSystemVars(); void CreateAudioVars(); @@ -755,23 +713,9 @@ public: CCpuFeatures* GetCPUFeatures() { return m_pCpu; }; - string& GetDelayedScreeenshot() {return m_sDelayedScreeenshot; } - - CVisRegTest*& GetVisRegTestPtrRef() {return m_pVisRegTest; } - const CTimeValue& GetLastTickTime(void) const { return m_lastTickTime; } const ICVar* GetDedicatedMaxRate(void) const { return m_svDedicatedMaxRate; } - const char* GetRenderingDriverName(void) const - { - if(m_rDriver) - { - return m_rDriver->GetString(); - } - return nullptr; - } - - std::shared_ptr CreateLocalFileIO(); // Gets the dimensions (in pixels) of the primary physical display. @@ -787,7 +731,6 @@ private: // ------------------------------------------------------ CTimer m_Time; //!< CCamera m_ViewCamera; //!< bool m_bInitializedSuccessfully; //!< true if the system completed all initialization steps - bool m_bShaderCacheGenMode;//!< true if the application runs in shader cache generation mode bool m_bRelaunch; //!< relaunching the app or not (true beforerelaunch) int m_iLoadingMode; //!< Game is loading w/o changing context (0 not, 1 quickloading, 2 full loading) bool m_bTestMode; //!< If running in testing mode. @@ -804,7 +747,6 @@ private: // ------------------------------------------------------ bool m_bInDevMode; //!< Set to true if was in dev mode. bool m_bGameFolderWritable;//!< True when verified that current game folder have write access. SDefaultValidator* m_pDefaultValidator; //!< - string m_sDelayedScreeenshot;//!< to delay a screenshot call for a frame CCpuFeatures* m_pCpu; //!< CPU features int m_ttMemStatSS; //!< Time to memstat screenshot string m_szCmdLine; @@ -917,7 +859,6 @@ private: // ------------------------------------------------------ ICVar* m_rFullscreen; ICVar* m_rFullscreenWindow; ICVar* m_rFullscreenNativeRes; - ICVar* m_rDriver; ICVar* m_rDisplayInfo; ICVar* m_rOverscanBordersDrawDebugView; ICVar* m_sysNoUpdate; @@ -966,17 +907,6 @@ private: // ------------------------------------------------------ ILoadConfigurationEntrySink* m_pCVarsWhitelistConfigSink; #endif // defined(CVARS_WHITELIST) - WIN_HWND m_hWnd; - WIN_HINSTANCE m_hInst; - - // this is the memory statistics that is retained in memory between frames - // in which it's not gathered - class CrySizerStats* m_pMemStats; - class CrySizerImpl* m_pSizer; - - ICryPerfHUD* m_pPerfHUD; - minigui::IMiniGUI* m_pMiniGUI; - //int m_nCurrentLogVerbosity; SFileVersion m_fileVersion; @@ -1085,7 +1015,6 @@ protected: // ------------------------------------------------------------- ILoadingProgressListener* m_pProgressListener; CCmdLine* m_pCmdLine; - CVisRegTest* m_pVisRegTest; CThreadManager* m_pThreadManager; CThreadTaskManager* m_pThreadTaskManager; class CResourceManager* m_pResourceManager; @@ -1097,8 +1026,6 @@ protected: // ------------------------------------------------------------- std::vector< std::pair > m_updateTimes; - CMemoryFragmentationProfiler m_MemoryFragmentationProfiler; - struct SErrorMessage { string m_Message; diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 22445ec4a5..83ef4fcd2b 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -95,7 +95,6 @@ #include #include #include -#include "HMDCVars.h" #include #include @@ -112,7 +111,6 @@ #include "SystemCFG.h" #include "AutoDetectSpec.h" #include "ResourceManager.h" -#include "VisRegTest.h" #include "MTSafeAllocator.h" #include "NotificationNetwork.h" #include "ExtensionSystem/CryFactoryRegistryImpl.h" @@ -123,7 +121,6 @@ #include "ZLibDecompressor.h" #include "ZStdDecompressor.h" #include "LZ4Decompressor.h" -#include "OverloadSceneManager/OverloadSceneManager.h" #include "ServiceNetwork.h" #include "RemoteCommand.h" #include "LevelSystem/LevelSystem.h" @@ -134,9 +131,6 @@ #include #include -#include "PerfHUD.h" -#include "MiniGUI/MiniGUI.h" - #if USE_STEAM #include "Steamworks/public/steam/steam_api.h" #include "Steamworks/public/steam/isteamremotestorage.h" @@ -740,28 +734,6 @@ static void LoadDetectedSpec(ICVar* pVar) GetISystem()->LoadConfiguration("editor.cfg"); } - bool bMultiGPUEnabled = false; - if (gEnv->pRenderer) - { - gEnv->pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPUEnabled); - -#if defined(AZ_PLATFORM_ANDROID) - AZStd::string gpuConfigFile; - const AZStd::string& adapterDesc = gEnv->pRenderer->GetAdapterDescription(); - const AZStd::string& apiver = gEnv->pRenderer->GetApiVersion(); - - if (!adapterDesc.empty()) - { - MobileSysInspect::GetSpecForGPUAndAPI(adapterDesc, apiver, gpuConfigFile); - GetISystem()->LoadConfiguration(gpuConfigFile.c_str(), pSysSpecOverrideSinkConsole); - } -#endif - } - if (bMultiGPUEnabled) - { - GetISystem()->LoadConfiguration("mgpu.cfg"); - } - // override cvars just loaded based on current API version/GPU GetISystem()->SetConfigSpec(static_cast(spec), platform, false); @@ -1279,7 +1251,7 @@ void CSystem::ShutdownFileSystem() } ///////////////////////////////////////////////////////////////////////////////// -bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams) +bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&) { LOADING_TIME_PROFILE_SECTION; { @@ -1320,10 +1292,6 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams& initPara static const char* g_additionalConfig = gEnv->IsDedicated() ? "server_cfg" : "client_cfg"; LoadConfiguration(g_additionalConfig, nullptr, false); - if (initParams.bShaderCacheGen) - { - LoadConfiguration("shadercachegen.cfg"); - } // We do not use CVar groups on the consoles AddCVarGroupDirectory("Config/CVarGroups"); @@ -1359,7 +1327,6 @@ bool CSystem::InitAudioSystem(const SSystemInitParams& initParams) bool useRealAudioSystem = false; if (!initParams.bPreview - && !initParams.bShaderCacheGen && !initParams.bMinimal && !m_bDedicatedServer && m_sys_audio_disable->GetIVal() == 0) @@ -1859,7 +1826,6 @@ bool CSystem::Init(const SSystemInitParams& startupParams) m_env.bTesting = startupParams.bTesting; m_env.bNoAssertDialog = startupParams.bTesting; m_env.bNoRandomSeed = startupParams.bNoRandom; - m_bShaderCacheGenMode = startupParams.bShaderCacheGen; m_bNoCrashDialog = gEnv->IsDedicated(); @@ -1938,9 +1904,6 @@ AZ_POP_DISABLE_WARNING QueryVersionInfo(); DetectGameFolderAccessRights(); - m_hInst = (WIN_HINSTANCE)startupParams.hInstance; - m_hWnd = (WIN_HWND)startupParams.hWnd; - m_bEditor = startupParams.bEditor; m_bPreviewMode = startupParams.bPreview; m_bTestMode = startupParams.bTestMode; @@ -2226,11 +2189,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init Create console"); - if (!startupParams.bSkipRenderer) - { - CreateRendererVars(startupParams); - } - // Need to load the engine.pak that includes the config files needed during initialization m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); #if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) @@ -2305,17 +2263,6 @@ AZ_POP_DISABLE_WARNING // Optional user defined overrides LoadConfiguration("user.cfg", pCVarsWhiteListConfigSink); - if (!startupParams.bSkipRenderer) - { - // Load the hmd.cfg if it exists. This will enable optional stereo rendering. - LoadConfiguration("hmd.cfg"); - } - - if (startupParams.bShaderCacheGen) - { - LoadConfiguration("shadercachegen.cfg", pCVarsWhiteListConfigSink); - } - #if defined(ENABLE_STATS_AGENT) if (m_pCmdLine->FindArg(eCLAT_Pre, "useamblecfg")) { @@ -2365,30 +2312,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init LoadConfigurations"); - m_env.pOverloadSceneManager = new COverloadSceneManager; - - if (m_bDedicatedServer && m_rDriver) - { - m_sSavedRDriver = m_rDriver->GetString(); - m_rDriver->Set("NULL"); - } - -#if defined(WIN32) || defined(WIN64) - if (!startupParams.bSkipRenderer) - { - if (azstricmp(m_rDriver->GetString(), "Auto") == 0) - { - m_rDriver->Set("DX11"); - } - } - - if (gEnv->IsEditor() && azstricmp(m_rDriver->GetString(), "DX12") == 0) - { - AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "DX12 mode is not supported in the editor. Reverting to DX11 mode."); - m_rDriver->Set("DX11"); - } -#endif - #ifdef WIN32 if ((g_cvars.sys_WER) && (!startupParams.bMinimal)) { @@ -2410,72 +2333,6 @@ AZ_POP_DISABLE_WARNING m_thermalInfoHandler = AZStd::make_unique(); #endif - if (g_cvars.sys_rendersplashscreen && !startupParams.bEditor && !startupParams.bShaderCacheGen) - { - if (m_env.pRenderer) - { - LOADING_TIME_PROFILE_SECTION_NAMED("Rendering Splash Screen"); - ITexture* pTex = m_env.pRenderer->EF_LoadTexture(g_cvars.sys_splashscreen, FT_DONT_STREAM | FT_NOMIPS | FT_USAGE_ALLOWREADSRGB); - //check the width and height as extra verification hack. This texture is loaded before the replace me, so there is - //no backup if it fails to load. - if (pTex && pTex->GetWidth() && pTex->GetHeight()) - { - const int splashWidth = pTex->GetWidth(); - const int splashHeight = pTex->GetHeight(); - - const int screenWidth = m_env.pRenderer->GetOverlayWidth(); - const int screenHeight = m_env.pRenderer->GetOverlayHeight(); - - const float scaleX = (float)screenWidth / (float)splashWidth; - const float scaleY = (float)screenHeight / (float)splashHeight; - - float scale = 1.0f; - switch (g_cvars.sys_splashScreenScaleMode) - { - case SSystemCVars::SplashScreenScaleMode_Fit: - { - scale = AZStd::GetMin(scaleX, scaleY); - } - break; - case SSystemCVars::SplashScreenScaleMode_Fill: - { - scale = AZStd::GetMax(scaleX, scaleY); - } - break; - } - - const float w = splashWidth * scale; - const float h = splashHeight * scale; - const float x = (screenWidth - w) * 0.5f; - const float y = (screenHeight - h) * 0.5f; - - const float vx = (800.0f / (float) screenWidth); - const float vy = (600.0f / (float) screenHeight); - - m_env.pRenderer->SetViewport(0, 0, screenWidth, screenHeight); - -#if defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_MAC) - // Pump system events in order to update the screen - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty); -#endif - - pTex->Release(); - } - - #if defined(AZ_PLATFORM_ANDROID) - bool engineSplashEnabled = (g_cvars.sys_rendersplashscreen != 0); - if (engineSplashEnabled) - { - AZ::Android::Utils::DismissSplashScreen(); - } - #endif - } - else - { - AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "Could not load startscreen image: %s.", g_cvars.sys_splashscreen); - } - } - ////////////////////////////////////////////////////////////////////////// // Open basic pak files after intro movie playback started ////////////////////////////////////////////////////////////////////////// @@ -2507,21 +2364,6 @@ AZ_POP_DISABLE_WARNING m_pUserCallback->OnInitProgress("First time asset processing - may take a minute..."); } - ////////////////////////////////////////////////////////////////////////// - // POST RENDERER - ////////////////////////////////////////////////////////////////////////// - if (!startupParams.bSkipRenderer && m_env.pRenderer) - { - m_env.pRenderer->PostInit(); - - if (!startupParams.bShaderCacheGen) - { - // try to do a flush to keep the renderer busy during loading - m_env.pRenderer->TryFlush(); - } - } - InlineInitializationProcessing("CSystem::Init Renderer::PostInit"); - #ifdef SOFTCODE_SYSTEM_ENABLED m_env.pSoftCodeMgr = new SoftCodeMgr(); #else @@ -2537,10 +2379,8 @@ AZ_POP_DISABLE_WARNING // - System cursor has to be enabled manually by the Game if needed; the custom UiCursor will typically be used instead if (!gEnv->IsDedicated() && - m_env.pRenderer && !gEnv->IsEditor() && - !startupParams.bTesting && - !m_pCmdLine->FindArg(eCLAT_Pre, "nomouse")) + !startupParams.bTesting) { AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::SetSystemCursorState, @@ -2561,7 +2401,7 @@ AZ_POP_DISABLE_WARNING ////////////////////////////////////////////////////////////////////////// // UI. Should be after input and hardware mouse ////////////////////////////////////////////////////////////////////////// - if (!startupParams.bShaderCacheGen && !m_bDedicatedServer) + if (!m_bDedicatedServer) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "UI system initialization"); INDENT_LOG_DURING_SCOPE(); @@ -2573,21 +2413,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init InitShine"); - ////////////////////////////////////////////////////////////////////////// - // Create MiniGUI - ////////////////////////////////////////////////////////////////////////// - if (!startupParams.bMinimal) - { - minigui::IMiniGUIPtr pMiniGUI; - if (CryCreateClassInstanceForInterface(cryiidof(), pMiniGUI)) - { - m_pMiniGUI = pMiniGUI.get(); - m_pMiniGUI->Init(); - } - } - - InlineInitializationProcessing("CSystem::Init InitMiniGUI"); - ////////////////////////////////////////////////////////////////////////// // CONSOLE ////////////////////////////////////////////////////////////////////////// @@ -2612,62 +2437,6 @@ AZ_POP_DISABLE_WARNING m_env.pRemoteCommandManager = new CRemoteCommandManager(); } - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // VR SYSTEM INITIALIZATION - ////////////////////////////////////////////////////////////////////////// - if ((!startupParams.bSkipRenderer) && (!startupParams.bMinimal)) - { - if (m_pUserCallback) - { - m_pUserCallback->OnInitProgress("Initializing VR Systems..."); - } - - AZStd::vector devices; - AZ::VR::HMDInitRequestBus::EnumerateHandlers([&devices](AZ::VR::HMDInitBus* device) - { - devices.emplace_back(device); - return true; - }); - - // Order the devices so that devices that only support one type of HMD are ordered first as we want - // to use any device-specific drivers over more general ones. - std::sort(devices.begin(), devices.end(), [](AZ::VR::HMDInitBus* left, AZ::VR::HMDInitBus* right) - { - return left->GetInitPriority() > right->GetInitPriority(); - }); - - //Start up a job to init the HMDs since they may take a while to start up - AZ::JobContext* jobContext = nullptr; - EBUS_EVENT_RESULT(jobContext, AZ::JobManagerBus, GetGlobalContext); - AZ::Job* hmdJob = AZ::CreateJobFunction([devices]() - { - // Loop through the attached devices and attempt to initialize them. We'll use the first - // one that succeeds since we currently only support a single HMD. - for (AZ::VR::HMDInitBus* device : devices) - { - if (device->AttemptInit()) - { - // At this point if any device connected to the HMDDeviceRequestBus then we are good to go for VR. - EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, OutputHMDInfo); - EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, EnableDebugging, false); - - // Since this was a job and we may have beaten the level's output_to_hmd cvar initialization - // We just want to retrigger the callback to this cvar - ICVar* outputToHMD = gEnv->pConsole->GetCVar("output_to_hmd"); - if (outputToHMD != nullptr) - { - int outputToHMDVal = gEnv->pConsole->GetCVar("output_to_hmd")->GetIVal(); - gEnv->pConsole->GetCVar("output_to_hmd")->Set(outputToHMDVal); - } - break; - } - } - }, true, jobContext); - hmdJob->Start(); - } - if (m_pUserCallback) { m_pUserCallback->OnInitProgress("Initializing additional systems..."); @@ -2724,28 +2493,10 @@ AZ_POP_DISABLE_WARNING m_pIZStdDecompressor = new CZStdDecompressor(); InlineInitializationProcessing("CSystem::Init ZStdDecompressor"); - ////////////////////////////////////////////////////////////////////////// - // Create PerfHUD - ////////////////////////////////////////////////////////////////////////// - -#if defined(USE_PERFHUD) - if (!gEnv->bTesting && !gEnv->IsInToolMode()) - { - //Create late in Init so that associated CVars have already been created - ICryPerfHUDPtr pPerfHUD; - if (CryCreateClassInstanceForInterface(cryiidof(), pPerfHUD)) - { - m_pPerfHUD = pPerfHUD.get(); - m_pPerfHUD->Init(); - } - } -#endif - ////////////////////////////////////////////////////////////////////////// // Initialize task threads. ////////////////////////////////////////////////////////////////////////// - if (!startupParams.bSkipRenderer) { m_pThreadTaskManager->InitThreads(); @@ -2775,12 +2526,6 @@ AZ_POP_DISABLE_WARNING AZ::Interface::Get()->VisitRegisteredFunctors([](AZ::ConsoleFunctorBase* functor) { AzConsoleToCryConsoleBinder::Visit(functor); }); AzConsoleToCryConsoleBinder::s_commandRegisteredHandler.Connect(AZ::Interface::Get()->GetConsoleCommandRegisteredEvent()); - // final tryflush to be sure that all framework init request have been processed - if (!startupParams.bShaderCacheGen && m_env.pRenderer) - { - m_env.pRenderer->TryFlush(); - } - if (g_cvars.sys_float_exceptions > 0) { if (g_cvars.sys_float_exceptions == 3 && gEnv->IsEditor()) // Turn off float exceptions in editor if sys_float_exceptions = 3 @@ -2874,99 +2619,6 @@ static string ConcatPath(const char* szPart1, const char* szPart2) return ret; } -static void ScreenshotCmd(IConsoleCmdArgs* pParams) -{ - assert(pParams); - - uint32 dwCnt = pParams->GetArgCount(); - - if (dwCnt <= 1) - { - if (!gEnv->IsEditing()) - { - // open console one line only - - //line should lie within title safe area, so calculate overscan border - Vec2 overscanBorders = Vec2(0.0f, 0.0f); - gEnv->pRenderer->EF_Query(EFQ_OverscanBorders, overscanBorders); - float yDelta = /*((float)gEnv->pRenderer->GetHeight())*/ 600.0f * overscanBorders.y; - - //set console height depending on top/bottom overscan border - gEnv->pConsole->ShowConsole(true, (int)(16 + yDelta)); - gEnv->pConsole->SetInputLine("Screenshot "); - } - else - { - gEnv->pLog->LogWithType(ILog::eInputResponse, "Screenshot missing - no screenshot was done"); - } - } - else - { - static int iScreenshotNumber = -1; - - const char* szPrefix = "Screenshot"; - uint32 dwPrefixSize = strlen(szPrefix); - - char path[AZ::IO::IArchive::MaxPath]; - path[sizeof(path) - 1] = 0; - gEnv->pCryPak->AdjustFileName("@user@/ScreenShots", path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); - - if (iScreenshotNumber == -1) // first time - find max number to start - { - auto pCryPak = gEnv->pCryPak; - - AZ::IO::ArchiveFileIterator handle = pCryPak->FindFirst((string(path) + "/*").c_str()); // mastercd folder - if (handle) - { - do - { - int iCurScreenshotNumber; - - if (_strnicmp(handle.m_filename.data(), szPrefix, dwPrefixSize) == 0) - { - int iCnt = azsscanf(handle.m_filename.data() + dwPrefixSize, "%d", &iCurScreenshotNumber); - - if (iCnt) - { - iScreenshotNumber = max(iCurScreenshotNumber, iScreenshotNumber); - } - } - - handle = pCryPak->FindNext(handle); - } while (handle); - pCryPak->FindClose(handle); - } - } - - ++iScreenshotNumber; - - char szNumber[16]; - azsprintf(szNumber, "%.4d ", iScreenshotNumber); - - string sScreenshotName = string(szPrefix) + szNumber; - - for (uint32 dwI = 1; dwI < dwCnt; ++dwI) - { - if (dwI > 1) - { - sScreenshotName += "_"; - } - - sScreenshotName += pParams->GetArg(dwI); - } - - sScreenshotName.replace("\\", "_"); - sScreenshotName.replace("/", "_"); - sScreenshotName.replace(":", "_"); - sScreenshotName.replace(".", "_"); - - gEnv->pConsole->ShowConsole(false); - - CSystem* pCSystem = (CSystem*)(gEnv->pSystem); - pCSystem->GetDelayedScreeenshot() = string(path) + "/" + sScreenshotName;// to delay a screenshot call for a frame - } -} - // Helper to maintain backwards compatibility with our CVar but not force our new code to // pull in CryCommon by routing through an environment variable void CmdSetAwsLogLevel(IConsoleCmdArgs* pArgs) @@ -3182,18 +2834,6 @@ void ChangeLogAllocations(ICVar* pVal) } } -static void VisRegTest(IConsoleCmdArgs* pParams) -{ - CSystem* pCSystem = (CSystem*)(gEnv->pSystem); - CVisRegTest*& visRegTest = pCSystem->GetVisRegTestPtrRef(); - if (!visRegTest) - { - visRegTest = new CVisRegTest(); - } - - visRegTest->Init(pParams); -} - ////////////////////////////////////////////////////////////////////////// void CSystem::CreateSystemVars() { @@ -3278,28 +2918,10 @@ void CSystem::CreateSystemVars() attachVariable("sys_PakLogAllFileAccess", &g_cvars.archiveVars.nLogAllFileAccess, "Log all file access allowing you to easily see whether a file has been loaded directly, or which pak file."); #endif attachVariable("sys_PakValidateFileHash", &g_cvars.archiveVars.nValidateFileHashes, "Validate file hashes in pak files for collisions"); - attachVariable("sys_LoadFrontendShaderCache", &g_cvars.archiveVars.nLoadFrontendShaderCache, "Load frontend shader cache (on/off)"); attachVariable("sys_UncachedStreamReads", &g_cvars.archiveVars.nUncachedStreamReads, "Enable stream reads via an uncached file handle"); attachVariable("sys_PakDisableNonLevelRelatedPaks", &g_cvars.archiveVars.nDisableNonLevelRelatedPaks, "Disables all paks that are not required by specific level; This is used with per level splitted assets."); attachVariable("sys_PakWarnOnPakAccessFailures", &g_cvars.archiveVars.nWarnOnPakAccessFails, "If 1, access failure for Paks is treated as a warning, if zero it is only a log message."); - - { - int nDefaultRenderSplashScreen = 1; -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_10 -#include AZ_RESTRICTED_FILE(SystemInit_cpp) -#endif - REGISTER_CVAR2("sys_rendersplashscreen", &g_cvars.sys_rendersplashscreen, nDefaultRenderSplashScreen, VF_NULL, - "Render the splash screen during game initialization"); - REGISTER_CVAR2("sys_splashscreenscalemode", &g_cvars.sys_splashScreenScaleMode, static_cast(SSystemCVars::SplashScreenScaleMode_Fill), VF_NULL, - "0 - scale to fit (letterbox)\n" - "1 - scale to fill (cropped)\n" - "Default is 1"); - REGISTER_CVAR2("sys_splashscreen", &g_cvars.sys_splashscreen, "EngineAssets/Textures/startscreen.tif", VF_NULL, - "The splash screen to render during game initialization"); - } - static const int fileSystemCaseSensitivityDefault = 0; REGISTER_CVAR2("sys_FilesystemCaseSensitivity", &g_cvars.sys_FilesystemCaseSensitivity, fileSystemCaseSensitivityDefault, VF_NULL, "0 - CryPak lowercases all input file names\n" @@ -3452,10 +3074,6 @@ void CSystem::CreateSystemVars() REGISTER_CVAR2("sys_streaming_max_finalize_per_frame", &g_cvars.sys_streaming_max_finalize_per_frame, 0, VF_NULL, "Maximum stream finalizing calls per frame to reduce the CPU impact on main thread (0 to disable)"); REGISTER_CVAR2("sys_streaming_max_bandwidth", &g_cvars.sys_streaming_max_bandwidth, 0, VF_NULL, "Enables capping of max streaming bandwidth in MB/s"); - REGISTER_CVAR2("az_streaming_stats", &g_cvars.az_streaming_stats, 0, VF_NULL, "Show stats from AZ::IO::Streamer\n" - "0=off\n" - "1=on\n" - ); REGISTER_CVAR2("sys_streaming_debug", &g_cvars.sys_streaming_debug, 0, VF_NULL, "Enable streaming debug information\n" "0=off\n" "1=Streaming Stats\n" @@ -3580,12 +3198,6 @@ void CSystem::CreateSystemVars() m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F12", "Screenshot"); m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F11", "RecordClip"); - // screenshot functionality in system as console - REGISTER_COMMAND("Screenshot", &ScreenshotCmd, VF_BLOCKFRAME, - "Create a screenshot with annotation\n" - "e.g. Screenshot beach scene with shark\n" - "Usage: Screenshot "); - /* // experimental feature? - needs to be created very early m_sys_filecache = REGISTER_INT("sys_FileCache",0,0, @@ -3606,9 +3218,6 @@ void CSystem::CreateSystemVars() "'test*' and 'info' log to the log file only\n" "Usage: sys_RestoreSpec [test|test*|apply|info]"); - REGISTER_COMMAND("VisRegTest", &VisRegTest, 0, "Run visual regression test.\n" - "Usage: VisRegTest [=test] [=visregtest.xml] [quit=false]"); - #if defined(WIN32) REGISTER_CVAR2("sys_display_threads", &g_cvars.sys_display_threads, 0, 0, "Displays Thread info"); #elif defined(AZ_RESTRICTED_PLATFORM) @@ -3629,9 +3238,6 @@ void CSystem::CreateSystemVars() REGISTER_CVAR2("sys_error_debugbreak", &g_cvars.sys_error_debugbreak, 0, VF_CHEAT, "__debugbreak() if a VALIDATOR_ERROR_DBGBREAK message is hit"); - // [VR] - AZ::VR::HMDCVars::Register(); - REGISTER_STRING("dlc_directory", "", 0, "Holds the path to the directory where DLC should be installed to and read from"); #if defined(MAP_LOADING_SLICING) @@ -3694,11 +3300,6 @@ void CSystem::AddCVarGroupDirectory(const string& sPath) string sCVarName = sFilePath; PathUtil::RemoveExtension(sCVarName); - - if (m_env.pConsole != 0) - { - ((CXConsole*)m_env.pConsole)->RegisterCVarGroup(PathUtil::GetFile(sCVarName), sFilePath); - } } } while (handle = gEnv->pCryPak->FindNext(handle)); diff --git a/Code/CryEngine/CrySystem/SystemRender.cpp b/Code/CryEngine/CrySystem/SystemRender.cpp index 68045a86ea..9e148bbc2b 100644 --- a/Code/CryEngine/CrySystem/SystemRender.cpp +++ b/Code/CryEngine/CrySystem/SystemRender.cpp @@ -35,15 +35,10 @@ #include "PhysRenderer.h" #include -#include "CrySizerStats.h" -#include "CrySizerImpl.h" -#include "VisRegTest.h" #include "ITextModeConsole.h" #include #include -#include "MiniGUI/MiniGUI.h" -#include "PerfHUD.h" #include "ThreadInfo.h" #include @@ -61,17 +56,6 @@ extern CMTSafeHeap* g_pPakHeap; extern int CryMemoryGetAllocatedSize(); -///////////////////////////////////////////////////////////////////////////////// -static void VerifySizeRenderVar(ICVar* pVar) -{ - const int size = pVar->GetIVal(); - if (size <= 0) - { - AZ_Error("Console Variable", false, "'%s' set to invalid value: %i. Setting to nearest safe value: 1.", pVar->GetName(), size); - pVar->Set(1); - } -} - ///////////////////////////////////////////////////////////////////////////////// bool CSystem::GetPrimaryPhysicalDisplayDimensions([[maybe_unused]] int& o_widthPixels, [[maybe_unused]] int& o_heightPixels) { @@ -97,130 +81,6 @@ bool CSystem::IsTablet() #endif } -///////////////////////////////////////////////////////////////////////////////// -void CSystem::CreateRendererVars(const SSystemInitParams& startupParams) -{ - int iFullScreenDefault = 1; - int iDisplayInfoDefault = 0; - int iWidthDefault = 1280; - int iHeightDefault = 720; -#if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) - GetPrimaryPhysicalDisplayDimensions(iWidthDefault, iHeightDefault); -#elif defined(WIN32) || defined(WIN64) - iFullScreenDefault = 0; - iWidthDefault = GetSystemMetrics(SM_CXFULLSCREEN) * 2 / 3; - iHeightDefault = GetSystemMetrics(SM_CYFULLSCREEN) * 2 / 3; -#endif - - if (IsDevMode()) - { - iFullScreenDefault = 0; - iDisplayInfoDefault = 1; - } - - // load renderer settings from engine.ini - m_rWidth = REGISTER_INT_CB("r_Width", iWidthDefault, VF_DUMPTODISK, - "Sets the display width, in pixels. Default is 1280.\n" - "Usage: r_Width [800/1024/..]", VerifySizeRenderVar); - m_rHeight = REGISTER_INT_CB("r_Height", iHeightDefault, VF_DUMPTODISK, - "Sets the display height, in pixels. Default is 720.\n" - "Usage: r_Height [600/768/..]", VerifySizeRenderVar); - m_rWidthAndHeightAsFractionOfScreenSize = REGISTER_FLOAT("r_WidthAndHeightAsFractionOfScreenSize", 1.0f, VF_DUMPTODISK, - "(iOS/Android only) Sets the display width and height as a fraction of the physical screen size. Default is 1.0.\n" - "Usage: rWidthAndHeightAsFractionOfScreenSize [0.1 - 1.0]"); - m_rTabletWidthAndHeightAsFractionOfScreenSize = REGISTER_FLOAT("r_TabletWidthAndHeightAsFractionOfScreenSize", 1.0f, VF_DUMPTODISK, - "(iOS only) NOTE: TABLETS ONLY Sets the display width and height as a fraction of the physical screen size. Default is 1.0.\n" - "Usage: rTabletWidthAndHeightAsFractionOfScreenSize [0.1 - 1.0]"); - m_rMaxWidth = REGISTER_INT("r_MaxWidth", 0, VF_DUMPTODISK, - "(iOS/Android only) Sets the maximum display width while maintaining the device aspect ratio.\n" - "Usage: r_MaxWidth [1024/1920/..] (0 for no max), combined with r_WidthAndHeightAsFractionOfScreenSize [0.1 - 1.0]"); - m_rMaxHeight = REGISTER_INT("r_MaxHeight", 0, VF_DUMPTODISK, - "(iOS/Android only) Sets the maximum display height while maintaining the device aspect ratio.\n" - "Usage: r_MaxHeight [768/1080/..] (0 for no max), combined with r_WidthAndHeightAsFractionOfScreenSize [0.1 - 1.0]"); - m_rColorBits = REGISTER_INT("r_ColorBits", 32, VF_DUMPTODISK, - "Sets the color resolution, in bits per pixel. Default is 32.\n" - "Usage: r_ColorBits [32/24/16/8]"); - m_rDepthBits = REGISTER_INT("r_DepthBits", 24, VF_DUMPTODISK | VF_REQUIRE_APP_RESTART, - "Sets the depth precision, in bits per pixel. Default is 24.\n" - "Usage: r_DepthBits [32/24]"); - m_rStencilBits = REGISTER_INT("r_StencilBits", 8, VF_DUMPTODISK, - "Sets the stencil precision, in bits per pixel. Default is 8.\n"); - - // Needs to be initialized as soon as possible due to swap chain creation modifications.. - m_rHDRDolby = REGISTER_INT_CB("r_HDRDolby", 0, VF_DUMPTODISK, - "HDR dolby output mode\n" - "Usage: r_HDRDolby [Value]\n" - "0: Off (default)\n" - "1: Dolby maui output\n" - "2: Dolby vision output\n", - [] (ICVar* cvar) - { - eDolbyVisionMode mode = static_cast(cvar->GetIVal()); - - if (mode == eDVM_Vision && gEnv->IsEditor()) - { - cvar->Set(static_cast(eDVM_Disabled)); - } - }); - // Restrict the limits of this cvar to the eDolbyVisionMode values - m_rHDRDolby->SetLimits(static_cast(eDVM_Disabled), static_cast(eDVM_Vision)); - -#if defined(WIN32) || defined(WIN64) - REGISTER_INT("r_overrideDXGIAdapter", -1, VF_REQUIRE_APP_RESTART, - "Specifies index of the preferred video adapter to be used for rendering (-1=off, loops until first suitable adapter is found).\n" - "Use this to resolve which video card to use if more than one DX11 capable GPU is available in the system."); -#endif - -#if defined(WIN32) || defined(WIN64) - const char* p_r_DriverDef = "Auto"; -#elif defined(APPLE) - const char* p_r_DriverDef = "METAL"; -#elif defined(ANDROID) - const char* p_r_DriverDef = "GL"; -#elif defined(LINUX) - const char* p_r_DriverDef = "GL"; - if (gEnv->IsDedicated()) - { - p_r_DriverDef = "NULL"; - } -#elif defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION SYSTEMRENDERER_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(SystemRender_cpp) -#else - const char* p_r_DriverDef = "DX9"; // required to be deactivated for final release -#endif - if (startupParams.pCvarsDefault) - { // hack to customize the default value of r_Driver - SCvarsDefault* pCvarsDefault = startupParams.pCvarsDefault; - if (pCvarsDefault->sz_r_DriverDef && pCvarsDefault->sz_r_DriverDef[0]) - { - p_r_DriverDef = startupParams.pCvarsDefault->sz_r_DriverDef; - } - } - - m_rDriver = REGISTER_STRING("r_Driver", p_r_DriverDef, VF_DUMPTODISK | VF_INVISIBLE, - "Sets the renderer driver ( DX11/AUTO/NULL ).\n" - "Specify in bootstrap.cfg like this: r_Driver = \"DX11\""); - - m_rFullscreen = REGISTER_INT("r_Fullscreen", iFullScreenDefault, VF_DUMPTODISK, - "Toggles fullscreen mode. Default is 1 in normal game and 0 in DevMode.\n" - "Usage: r_Fullscreen [0=window/1=fullscreen]"); - - m_rFullscreenWindow = REGISTER_INT("r_FullscreenWindow", 0, VF_DUMPTODISK, - "Toggles fullscreen-as-window mode. Fills screen but allows seamless switching. Default is 0.\n" - "Usage: r_FullscreenWindow [0=locked fullscreen/1=fullscreen as window]"); - - m_rFullscreenNativeRes = REGISTER_INT("r_FullscreenNativeRes", 0, VF_DUMPTODISK, ""); - - m_rDisplayInfo = REGISTER_INT("r_DisplayInfo", iDisplayInfoDefault, VF_RESTRICTEDMODE | VF_DUMPTODISK, - "Toggles debugging information display.\n" - "Usage: r_DisplayInfo [0=off/1=show/2=enhanced/3=compact]"); - - m_rOverscanBordersDrawDebugView = REGISTER_INT("r_OverscanBordersDrawDebugView", 0, VF_RESTRICTEDMODE | VF_DUMPTODISK, - "Toggles drawing overscan borders.\n" - "Usage: r_OverscanBordersDrawDebugView [0=off/1=show]"); -} - void CSystem::OnScene3DEnd() { //Render Console diff --git a/Code/CryEngine/CrySystem/SystemWin32.cpp b/Code/CryEngine/CrySystem/SystemWin32.cpp index b47519eb03..c694979a14 100644 --- a/Code/CryEngine/CrySystem/SystemWin32.cpp +++ b/Code/CryEngine/CrySystem/SystemWin32.cpp @@ -53,8 +53,6 @@ #endif #include "XConsole.h" -#include "CrySizerStats.h" -#include "CrySizerImpl.h" #include "StreamEngine/StreamEngine.h" #include "LocalizedStringManager.h" #include "XML/XmlUtils.h" @@ -69,51 +67,6 @@ __pragma(comment(lib, "Winmm.lib")) #include #endif - - -static AZStd::vector GetModuleNames() -{ - AZStd::vector moduleNames; - if (moduleNames.empty()) - { -# ifdef MODULE_EXTENSION -# error MODULE_EXTENSION already defined! -# endif -# if defined(LINUX) -# define MODULE_EXTENSION ".so" -# elif defined(APPLE) -# define MODULE_EXTENSION ".dylib" -# else -# define MODULE_EXTENSION ".dll" -# endif - - moduleNames.push_back("Cry3DEngine" MODULE_EXTENSION); - moduleNames.push_back("CryFont" MODULE_EXTENSION); - moduleNames.push_back("CrySystem" MODULE_EXTENSION); - -#undef MODULE_EXTENSION - -# if defined(LINUX) - moduleNames.push_back("CryRenderNULL.so"); -# elif defined(APPLE) - moduleNames.push_back("CryRenderNULL.dylib"); -# else - moduleNames.push_back("Editor.exe"); - moduleNames.push_back("CryRenderD3D9.dll"); - moduleNames.push_back("CryRenderD3D10.dll"); - moduleNames.push_back("CryRenderNULL.dll"); - //TODO: launcher? -# endif - } - - return moduleNames; -} - -static bool QueryModuleMemoryInfo([[maybe_unused]] SCryEngineStatsModuleInfo& moduleInfo, [[maybe_unused]] int index) -{ - return false; -} - // this is the list of modules that can be loaded into the game process // Each array element contains 2 strings: the name of the module (case-insensitive) // and the name of the group the module belongs to @@ -158,30 +111,6 @@ void CSystem::SetAffinity() #endif } - - - - -//! dumps the memory usage statistics to the log -////////////////////////////////////////////////////////////////////////// -void CSystem::DumpMemoryUsageStatistics(bool bUseKB) -{ - // CResourceCollector ResourceCollector; - - // TickMemStats(nMSP_ForDump,&ResourceCollector); - TickMemStats(nMSP_ForDump); - - CrySizerStatsRenderer StatsRenderer (this, m_pMemStats, 10, 0); - StatsRenderer.dump(bUseKB); - - // since we've recalculated this mem stats for dumping, we'll want to calculate it anew the next time it's rendered - SAFE_DELETE(m_pMemStats); -} - -// collects the whole memory statistics into the given sizer object -////////////////////////////////////////////////////////////////////////// - - #if defined(WIN32) #pragma pack(push,1) struct PEHeader_DLL @@ -207,162 +136,6 @@ const SmallModuleInfo* FindModuleInfo(std::vector& vec, const c return 0; } -////////////////////////////////////////////////////////////////////////// -void CSystem::CollectMemInfo(SCryEngineStatsGlobalMemInfo& m_stats) -{ - m_stats.totalUsedInModules = 0; - m_stats.totalCodeAndStatic = 0; - m_stats.countedMemoryModules = 0; - m_stats.totalAllocatedInModules = 0; - m_stats.totalNumAllocsInModules = 0; - - AZStd::vector szModules = GetModuleNames(); - const int numModules = szModules.size(); - - ////////////////////////////////////////////////////////////////////////// - // Hardcoded value for the OS memory allocation. - ////////////////////////////////////////////////////////////////////////// - for (int i = 0; i < numModules; i++) - { - const char* szModule = szModules[i].c_str(); - - SCryEngineStatsModuleInfo moduleInfo; - ZeroStruct(moduleInfo.memInfo); - moduleInfo.moduleStaticSize = moduleInfo.SizeOfCode = moduleInfo.SizeOfInitializedData = moduleInfo.SizeOfUninitializedData = moduleInfo.usedInModule = 0; - moduleInfo.name = szModule; - - if (!QueryModuleMemoryInfo(moduleInfo, i)) - { - continue; - } - - m_stats.totalNumAllocsInModules += moduleInfo.memInfo.num_allocations; - m_stats.totalAllocatedInModules += moduleInfo.memInfo.allocated; - m_stats.totalUsedInModules += moduleInfo.usedInModule; - m_stats.countedMemoryModules++; - m_stats.totalCodeAndStatic += moduleInfo.moduleStaticSize; - - m_stats.modules.push_back(moduleInfo); - } -} - - -void CSystem::CollectMemStats (ICrySizer* pSizer, MemStatsPurposeEnum nPurpose, std::vector* pStats) -{ - std::vector stats; - if (pStats) - { - pStats->assign(stats.begin(), stats.end()); - } - - if (nMSP_ForCrashLog == nPurpose || nMSP_ForBudget == nPurpose) - { - return; - } - - { - SIZER_COMPONENT_NAME(pSizer, "CrySystem"); - { - pSizer->AddObject(this, sizeof(*this)); - { - //SIZER_COMPONENT_NAME (pSizer, "$Allocations waste"); - //const SmallModuleInfo* info = FindModuleInfo(stats, "CrySystem.dll"); - //if (info) - //pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested ); - } - - { - SIZER_COMPONENT_NAME(pSizer, "VFS"); - if (m_pStreamEngine) - { - SIZER_COMPONENT_NAME(pSizer, "Stream Engine"); - m_pStreamEngine->GetMemoryStatistics(pSizer); - } - } - { - SIZER_COMPONENT_NAME(pSizer, "Localization Data"); - m_pLocalizationManager->GetMemoryUsage(pSizer); - } - { - SIZER_COMPONENT_NAME(pSizer, "XML"); - m_pXMLUtils->GetMemoryUsage(pSizer); - } - if (m_env.pConsole) - { - SIZER_COMPONENT_NAME (pSizer, "Console"); - m_env.pConsole->GetMemoryUsage (pSizer); - } - - if (m_env.pLog) - { - SIZER_COMPONENT_NAME (pSizer, "Log"); - m_env.pLog->GetMemoryUsage(pSizer); - } - } - } - - if (m_env.pRenderer) - { - SIZER_COMPONENT_NAME(pSizer, "CryRenderer"); - { - { - SIZER_COMPONENT_NAME (pSizer, "$Allocations waste D3D9"); - const SmallModuleInfo* info = FindModuleInfo(stats, "CryRenderD3D9.dll"); - if (info) - { - pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested); - } - } - { - SIZER_COMPONENT_NAME (pSizer, "$Allocations waste D3D10"); - const SmallModuleInfo* info = FindModuleInfo(stats, "CryRenderD3D10.dll"); - if (info) - { - pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested); - } - } - - m_env.pRenderer->GetMemoryUsage(pSizer); - } - } - - if (m_env.pCryFont) - { - SIZER_COMPONENT_NAME(pSizer, "CryFont"); - { - { - SIZER_COMPONENT_NAME (pSizer, "$Allocations waste"); - const SmallModuleInfo* info = FindModuleInfo(stats, "CryFont.dll"); - if (info) - { - pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested); - } - } - - m_env.pCryFont->GetMemoryUsage(pSizer); - // m_pIFont and m_pIFontUi are both counted in pCryFont sizing if they exist. - // no need to manually add them here. - } - } - - { - SIZER_COMPONENT_NAME(pSizer, "UserData"); - if (m_pUserCallback) - { - m_pUserCallback->GetMemoryUsage(pSizer); - } - } - -#ifdef WIN32 - { - SIZER_COMPONENT_NAME(pSizer, "Code"); - GetExeSizes (pSizer, nPurpose); - } -#endif - - pSizer->End(); -} - ////////////////////////////////////////////////////////////////////////// const char* CSystem::GetUserName() { @@ -460,52 +233,6 @@ int CSystem::GetApplicationLogInstance([[maybe_unused]] const char* logFilePath) #endif } - -// refreshes the m_pMemStats if necessary; creates it if it's not created -////////////////////////////////////////////////////////////////////////// -void CSystem::TickMemStats(MemStatsPurposeEnum nPurpose, IResourceCollector* pResourceCollector) -{ - // gather the statistics, if required - // if there's no object, or if it's time to recalculate, or if it's for dump, then recalculate it - if (!m_pMemStats || (m_env.pRenderer->GetFrameID(false) % m_cvMemStats->GetIVal()) == 0 || nPurpose == nMSP_ForDump) - { - if (!m_pMemStats) - { - if (m_cvMemStats->GetIVal() < 4 && m_cvMemStats->GetIVal()) - { - GetILog()->LogToConsole("memstats is too small (%d). Performance impact can be significant. Please set to a greater value.", m_cvMemStats->GetIVal()); - } - m_pMemStats = new CrySizerStats(); - } - - if (!m_pSizer) - { - m_pSizer = new CrySizerImpl(); - } - - m_pSizer->SetResourceCollector(pResourceCollector); - - m_pMemStats->startTimer(0, GetITimer()); - CollectMemStats (m_pSizer, nPurpose); - m_pMemStats->stopTimer(0, GetITimer()); - - m_pMemStats->startTimer(1, GetITimer()); - CrySizerStatsBuilder builder (m_pSizer); - builder.build (m_pMemStats); - m_pMemStats->stopTimer(1, GetITimer()); - - m_pMemStats->startTimer(2, GetITimer()); - m_pSizer->clear(); - m_pMemStats->stopTimer(2, GetITimer()); - } - else - { - m_pMemStats->incAgeFrames(); - } -} - -//#define __HASXP - // these 2 functions are duplicated in System.cpp in editor ////////////////////////////////////////////////////////////////////////// #if !defined(LINUX) @@ -839,51 +566,6 @@ const char* GetModuleGroup (const char* szString) return "Other"; } -////////////////////////////////////////////////////////////////////////// -void CSystem::GetExeSizes (ICrySizer* pSizer, MemStatsPurposeEnum nPurpose) -{ - HANDLE hSnapshot; - hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); - if (hSnapshot == INVALID_HANDLE_VALUE) - { - CryLogAlways ("Cannot get the module snapshot, error code %d", GetLastError()); - return; - } - - DWORD dwProcessID = GetCurrentProcessId(); - - MODULEENTRY32 me; - memset (&me, 0, sizeof(me)); - me.dwSize = sizeof(me); - - if (Module32First (hSnapshot, &me)) - { - // the sizes of each module group - StringToSizeMap mapGroupSize; - do - { - dwProcessID = me.th32ProcessID; - const char* szGroup = GetModuleGroup (me.szModule); - SIZER_COMPONENT_NAME(pSizer, szGroup); - if (nPurpose == nMSP_ForDump) - { - SIZER_COMPONENT_NAME(pSizer, me.szModule); - pSizer->AddObject(me.modBaseAddr, me.modBaseSize); - } - else - { - pSizer->AddObject(me.modBaseAddr, me.modBaseSize); - } - } while (Module32Next(hSnapshot, &me)); - } - else - { - CryLogAlways ("No modules to dump"); - } - - CloseHandle (hSnapshot); -} - #endif ////////////////////////////////////////////////////////////////////////// @@ -1061,18 +743,11 @@ void CSystem::FatalError(const char* format, ...) LogSystemInfo(); - CollectMemStats(0, nMSP_ForCrashLog); - OutputDebugString(szBuffer); #ifdef WIN32 OnFatalError(szBuffer); if (!g_cvars.sys_no_crash_dialog) { - ICVar* pFullscreen = (gEnv && gEnv->pConsole) ? gEnv->pConsole->GetCVar("r_Fullscreen") : 0; - if (pFullscreen && pFullscreen->GetIVal() != 0 && gEnv->pRenderer && gEnv->pRenderer->GetHWND()) - { - ::ShowWindow((HWND)gEnv->pRenderer->GetHWND(), SW_MINIMIZE); - } ::MessageBox(NULL, szBuffer, "Open 3D Engine Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); } @@ -1169,12 +844,6 @@ void CSystem::debug_LogCallStack(int nMaxFuncs, [[maybe_unused]] int nFlags) // Print call stack for each find. const char* funcs[32]; int nCount = nMaxFuncs; - int nCurFrame = 0; - if (m_env.pRenderer) - { - nCurFrame = (int)m_env.pRenderer->GetFrameID(false); - } - CryLogAlways(" ----- CallStack (Frame: %d) -----", nCurFrame); GetISystem()->debug_GetCallStack(funcs, nCount); for (int i = 1; i < nCount; i++) // start from 1 to skip this function. { diff --git a/Code/CryEngine/CrySystem/Tests/Test_CrySizer.cpp b/Code/CryEngine/CrySystem/Tests/Test_CrySizer.cpp deleted file mode 100644 index c9aa248eee..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_CrySizer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "CrySystem_precompiled.h" - -#include -#include -#include - -#include - -#include "CrySizerImpl.h" - -namespace UnitTest -{ - class CrySizerTest - : public AllocatorsFixture - { - public: - void SetUp() override - { - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - m_sizer = new CrySizerImpl(); - } - - void TearDown() override - { - delete m_sizer; - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - } - protected: - CrySizerImpl* m_sizer; - }; //class StatisticsTest - - /** - * The key data structures fed to ICrySizer in CTerrain::GetMemoryUsage(class ICrySizer* pSizer): - * 1. structs and classes. - * 2. PodArray< of structs / classes> - * 3. PodArray< of pointers> - */ - TEST_F(CrySizerTest, CrySizerTest_AddSomeObjectsUsedInCTerrain_GetExpectedSize) - { - struct TmpStruct - { - AZ::u32 a; - AZ::u32 b; - }; - TmpStruct tmpStructObj; - //Tracking a simple struct. - m_sizer->AddObjectSize(&tmpStructObj); - - //The AddObject method is only available when using the ICrySizer base class. - ICrySizer* sizer = static_cast(m_sizer); - - const int numItemsPerArray = 1024; - - //PodArray of structs - PodArray podArrayOfTmpStruct; - podArrayOfTmpStruct.resize(numItemsPerArray); - sizer->AddObject(podArrayOfTmpStruct); - - //PodArray of pointers - PodArray podArrayOfTmpStructPointers; - podArrayOfTmpStructPointers.resize(numItemsPerArray); - sizer->AddObject(podArrayOfTmpStructPointers); - - //PodArray of Array2d of pointers. - const int array2dAxisSize = 64; - PodArray> podArrayOfArray2d; - podArrayOfArray2d.resize(numItemsPerArray); - for (int i = 0; i < numItemsPerArray; ++i) - { - //Array2d will allocate array2dAxisSize * array2dAxisSize elements. - podArrayOfArray2d[i].Allocate(array2dAxisSize); - } - sizer->AddObject(podArrayOfArray2d); - - //Calculate the total expected size - const size_t expectedSizeOfArray2d = sizeof(Array2d) - + (array2dAxisSize * array2dAxisSize) * sizeof(TmpStruct*); - const size_t expectedTotalSize = sizeof(TmpStruct) - + numItemsPerArray * sizeof(TmpStruct) - + numItemsPerArray * sizeof(TmpStruct*) - + numItemsPerArray * expectedSizeOfArray2d; - - EXPECT_EQ( m_sizer->GetTotalSize(), expectedTotalSize); - } - -}//namespace UnitTest diff --git a/Code/CryEngine/CrySystem/Timer.cpp b/Code/CryEngine/CrySystem/Timer.cpp index eb53c1b257..7545b42765 100644 --- a/Code/CryEngine/CrySystem/Timer.cpp +++ b/Code/CryEngine/CrySystem/Timer.cpp @@ -26,9 +26,6 @@ #include "Mmsystem.h" #endif -//this should not be included here -#include // needed for m_pSystem->GetIRenderer()->EF_Query(EFQ_RecurseLevel) - //#define PROFILING 1 #ifdef PROFILING static int64 g_lCurrentTime = 0; @@ -432,7 +429,7 @@ void CTimer::UpdateOnFrameStart() if (m_TimeDebug > 1) { - CryLogAlways("[CTimer]: Frame=%d Cur=%lld Now=%lld Off=%lld Async=%f CurrTime=%f UI=%f", gEnv->pRenderer->GetFrameID(false), (long long)currentTime, (long long)now, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); + CryLogAlways("[CTimer]: Cur=%lld Now=%lld Off=%lld Async=%f CurrTime=%f UI=%f", (long long)currentTime, (long long)now, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); } } @@ -558,7 +555,7 @@ void CTimer::Serialize(TSerialize ser) if (m_TimeDebug) { const int64 now = CryGetTicks(); - CryLogAlways("[CTimer]: Serialize: Frame=%d Last=%lld Now=%lld Off=%lld Async=%f CurrTime=%f UI=%f", gEnv->pRenderer->GetFrameID(false), (long long)m_lLastTime, (long long)now, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); + CryLogAlways("[CTimer]: Serialize: Last=%lld Now=%lld Off=%lld Async=%f CurrTime=%f UI=%f", (long long)m_lLastTime, (long long)now, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); } } } @@ -584,7 +581,7 @@ bool CTimer::PauseTimer(ETimer which, bool bPause) m_lGameTimerPausedTime = m_lLastTime + m_lOffsetTime; if (m_TimeDebug) { - CryLogAlways("[CTimer]: Pausing ON: Frame=%d Last=%lld Off=%lld Async=%f CurrTime=%f UI=%f", gEnv->pRenderer->GetFrameID(false), (long long)m_lLastTime, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); + CryLogAlways("[CTimer]: Pausing ON: Last=%lld Off=%lld Async=%f CurrTime=%f UI=%f", (long long)m_lLastTime, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); } } else @@ -593,7 +590,7 @@ bool CTimer::PauseTimer(ETimer which, bool bPause) m_lGameTimerPausedTime = 0; if (m_TimeDebug) { - CryLogAlways("[CTimer]: Pausing OFF: Frame=%d Last=%lld Off=%lld Async=%f CurrTime=%f UI=%f", gEnv->pRenderer->GetFrameID(false), (long long)m_lLastTime, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); + CryLogAlways("[CTimer]: Pausing OFF: Last=%lld Off=%lld Async=%f CurrTime=%f UI=%f", (long long)m_lLastTime, (long long)m_lOffsetTime, GetAsyncCurTime(), GetCurrTime(ETIMER_GAME), GetCurrTime(ETIMER_UI)); } } diff --git a/Code/CryEngine/CrySystem/Validator.h b/Code/CryEngine/CrySystem/Validator.h index 409377ee28..83dc0533f6 100644 --- a/Code/CryEngine/CrySystem/Validator.h +++ b/Code/CryEngine/CrySystem/Validator.h @@ -43,11 +43,6 @@ struct SDefaultValidator } #ifdef WIN32 - ICVar* pFullscreen = (gEnv && gEnv->pConsole) ? gEnv->pConsole->GetCVar("r_Fullscreen") : 0; - if (pFullscreen && pFullscreen->GetIVal() != 0 && gEnv->pRenderer && gEnv->pRenderer->GetHWND()) - { - ::ShowWindow((HWND)gEnv->pRenderer->GetHWND(), SW_MINIMIZE); - } string strMessage = record.text; strMessage += "\n---------------------------------------------\nAbort - terminate application\nRetry - continue running the application\nIgnore - don't show this message box any more"; switch (::MessageBox(NULL, strMessage.c_str(), "CryEngine Warning", MB_ABORTRETRYIGNORE | MB_DEFBUTTON2 | MB_ICONWARNING | MB_SYSTEMMODAL)) diff --git a/Code/CryEngine/CrySystem/ViewSystem/DebugCamera.cpp b/Code/CryEngine/CrySystem/ViewSystem/DebugCamera.cpp index ace30d5df7..f38dda32c7 100644 --- a/Code/CryEngine/CrySystem/ViewSystem/DebugCamera.cpp +++ b/Code/CryEngine/CrySystem/ViewSystem/DebugCamera.cpp @@ -137,15 +137,6 @@ void DebugCamera::PostUpdate() CCamera& camera = gEnv->pSystem->GetViewCamera(); camera.SetMatrix(Matrix34(m_view, m_position)); - - const float FONT_COLOR[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; - gEnv->pRenderer->Draw2dLabel(0.0f, 700.0f, 1.3f, FONT_COLOR, false, - "Debug Camera: pos [ %.3f, %.3f, %.3f ] p/y [ %.1f, %.1f ] dir [ %.3f, %.3f, %.3f ] scl %.2f inv %d", - m_position.x, m_position.y, m_position.z, - m_cameraPitch, m_cameraYaw, - m_view.GetColumn1().x, m_view.GetColumn1().y, m_view.GetColumn1().z, - m_moveScale, - m_isYInverted); } /////////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/ViewSystem/View.cpp b/Code/CryEngine/CrySystem/ViewSystem/View.cpp index f8b84bea19..0ab2d6169b 100644 --- a/Code/CryEngine/CrySystem/ViewSystem/View.cpp +++ b/Code/CryEngine/CrySystem/ViewSystem/View.cpp @@ -101,25 +101,6 @@ void CView::Update(float frameTime, bool isActive) const float farPlane = (m_viewParams.farplane > 0.f) ? m_viewParams.farplane : DEFAULT_FAR; float fov = (m_viewParams.fov < 0.001f) ? DEFAULT_FOV : m_viewParams.fov; - // [VR] specific - // Modify FOV based on the HMD device configuration - bool isRenderingToHMD = gEnv->pRenderer ? gEnv->pRenderer->GetIStereoRenderer()->IsRenderingToHMD() : false; - if (isRenderingToHMD) - { - const AZ::VR::HMDDeviceInfo* deviceInfo = nullptr; - EBUS_EVENT_RESULT(deviceInfo, AZ::VR::HMDDeviceRequestBus, GetDeviceInfo); - if (deviceInfo) - { - //Add 12 degrees to the FOV here used for culling. - //It won't be used for rendering, just to make sure we don't cull - //anything out incorrectly. - //This value was decided based on experimentation with the HTC Vive - //and works perfectly fine for the Oculus Rift - const float fovCorrection = 12.0f; - fov = deviceInfo->fovV + DEG2RAD(fovCorrection); - } - } - m_camera.SetFrustum(pSysCam->GetViewSurfaceX(), pSysCam->GetViewSurfaceZ(), fov, nearPlane, farPlane, pSysCam->GetPixelAspectRatio()); //apply shake & set the view matrix @@ -140,20 +121,6 @@ void CView::Update(float frameTime, bool isActive) Vec3 pos = m_viewParams.position; Vec3 p = Vec3(ZERO); - if (isRenderingToHMD) - { - //This HMD tracking state is used JUST for use in the visibility system. - //RT_SetStereoCamera in D3DRendPipeline will override this info before rendering with the absolute - //latest tracking info. - const AZ::VR::TrackingState* trackingState = nullptr; - EBUS_EVENT_RESULT(trackingState, AZ::VR::HMDDeviceRequestBus, GetTrackingState); - if (trackingState && trackingState->CheckStatusFlags(AZ::VR::HMDStatus_IsUsable)) - { - p = q * AZVec3ToLYVec3(trackingState->pose.position); - q = q * AZQuaternionToLYQuaternion(trackingState->pose.orientation); - } - } - Matrix34 viewMtx(q); viewMtx.SetTranslation(pos + p); m_camera.SetMatrix(viewMtx); diff --git a/Code/CryEngine/CrySystem/ViewSystem/ViewSystem.cpp b/Code/CryEngine/CrySystem/ViewSystem/ViewSystem.cpp index 13f7f5b82d..c0f681511b 100644 --- a/Code/CryEngine/CrySystem/ViewSystem/ViewSystem.cpp +++ b/Code/CryEngine/CrySystem/ViewSystem/ViewSystem.cpp @@ -640,30 +640,6 @@ void CViewSystem::ClearAllViews() //////////////////////////////////////////////////////////////////// void CViewSystem::DebugDraw() { - IRenderer* pRenderer = gEnv->pRenderer; - if (pRenderer) - { - float xpos = 20; - float ypos = 15; - float fColor[4] = {1.0f, 1.0f, 1.0f, 0.7f}; - float fColorRed[4] = {1.0f, 0.0f, 0.0f, 0.7f}; - float fColorGreen[4] = {0.0f, 1.0f, 0.0f, 0.7f}; - - pRenderer->Draw2dLabel(xpos, 5, 1.35f, fColor, false, "ViewSystem Stats: %" PRISIZE_T " Views ", m_views.size()); - - IView* pActiveView = GetActiveView(); - for (TViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) - { - IView* pView = it->second; - const CCamera& cam = pView->GetCamera(); - bool isActive = (pView == pActiveView); - Vec3 pos = cam.GetPosition(); - Ang3 ang = cam.GetAngles(); - pRenderer->Draw2dLabel(xpos, ypos, 1.35f, isActive ? fColorGreen : fColorRed, false, "View Camera: %p . View Id: %d, pos (%f, %f, %f), ang (%f, %f, %f)", &cam, it->first, pos.x, pos.y, pos.z, ang.x, ang.y, ang.z); - - ypos += 11; - } - } } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/VisRegTest.cpp b/Code/CryEngine/CrySystem/VisRegTest.cpp deleted file mode 100644 index 206d8f349a..0000000000 --- a/Code/CryEngine/CrySystem/VisRegTest.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Visual Regression Test - - -#include "CrySystem_precompiled.h" -#include "VisRegTest.h" - -#include "ISystem.h" -#include "IRenderer.h" -#include "IConsole.h" -#include "ITimer.h" -#include "IStreamEngine.h" -#include - -#include - -const float CVisRegTest::MaxStreamingWait = 30.0f; - -CVisRegTest::CVisRegTest() - : m_nextCmd(0) - , m_waitFrames(0) -{ - CryLog("Enabled visual regression tests"); -} - - -void CVisRegTest::Init(IConsoleCmdArgs* pParams) -{ - assert(pParams); - - stack_string configFile("visregtest.xml"); - - // Reset - m_cmdBuf.clear(); - m_dataSamples.clear(); - m_nextCmd = 0; - m_cmdFreq = 0; - m_waitFrames = 0; - m_streamingTimeout = 0.0f; - m_testName = "test"; - m_quitAfterTests = false; - - // Parse arguments - if (pParams->GetArgCount() >= 2) - { - m_testName = pParams->GetArg(1); - } - if (pParams->GetArgCount() >= 3) - { - configFile = pParams->GetArg(2); - } - if (pParams->GetArgCount() >= 4) - { - if (_stricmp(pParams->GetArg(3), "quit") == 0) - { - m_quitAfterTests = true; - } - } - - // Fill cmd buffer - if (!LoadConfig(configFile.c_str())) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "VisRegTest: Failed to load config file '%s' from game folder", configFile.c_str()); - return; - } - - gEnv->pTimer->SetTimeScale(0); - GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RANDOM_SEED, 0, 0); - srand(0); - - gEnv->pRenderer->EnableGPUTimers2(true); -} - - -void CVisRegTest::AfterRender() -{ - ExecCommands(); -} - - -bool CVisRegTest::LoadConfig(const char* configFile) -{ - XmlNodeRef rootNode = GetISystem()->LoadXmlFromFile(configFile); - if (!rootNode || !rootNode->isTag("VisRegTest")) - { - return false; - } - - m_cmdBuf.push_back(SCmd(eCMDStart, "")); - - for (int i = 0; i < rootNode->getChildCount(); ++i) - { - XmlNodeRef node = rootNode->getChild(i); - - if (node->isTag("Config")) - { - SCmd cmd; - for (int j = 0; j < node->getChildCount(); ++j) - { - XmlNodeRef node2 = node->getChild(j); - - if (node2->isTag("ConsoleCmd")) - { - m_cmdBuf.push_back(SCmd(eCMDConsoleCmd, node2->getAttr("cmd"))); - } - } - } - else if (node->isTag("Map")) - { - const char* mapName = node->getAttr("name"); - int imageIndex = 0; - - m_cmdBuf.push_back(SCmd(eCMDLoadMap, mapName)); - m_cmdBuf.push_back(SCmd(eCMDOnMapLoaded, "")); - - for (int j = 0; j < node->getChildCount(); ++j) - { - XmlNodeRef node2 = node->getChild(j); - - if (node2->isTag("ConsoleCmd")) - { - m_cmdBuf.push_back(SCmd(eCMDConsoleCmd, node2->getAttr("cmd"))); - } - else if (node2->isTag("Sample")) - { - m_cmdBuf.push_back(SCmd(eCMDGoto, node2->getAttr("location"))); - m_cmdBuf.push_back(SCmd(eCMDWaitStreaming, "")); - - char strbuf[256]; -#ifdef WIN32 - sprintf_s(strbuf, "%s_%i.bmp", mapName, imageIndex++); -#else - sprintf_s(strbuf, "%s_%i.tga", mapName, imageIndex++); -#endif - m_cmdBuf.push_back(SCmd(eCMDCaptureSample, strbuf, SampleCount)); - } - } - } - } - - m_cmdBuf.push_back(SCmd(eCMDFinish, "")); - - return true; -} - - -void CVisRegTest::ExecCommands() -{ - if (m_nextCmd >= m_cmdBuf.size()) - { - return; - } - - float col[] = {0, 1, 0, 1}; - gEnv->pRenderer->Draw2dLabel(10, 10, 2, col, false, "Visual Regression Test"); - - if (m_waitFrames > 0) - { - --m_waitFrames; - return; - } - else if (m_waitFrames < 0) // Wait for streaming - { - SStreamEngineOpenStats stats; - gEnv->pSystem->GetStreamEngine()->GetStreamingOpenStatistics(stats); - if (stats.nOpenRequestCount > 0 && m_streamingTimeout > 0) - { - gEnv->pConsole->ExecuteString("t_FixedStep 0"); - m_streamingTimeout -= gEnv->pTimer->GetRealFrameTime(); - m_waitFrames = -16; - } - else if (++m_waitFrames == 0) - { - gEnv->pConsole->ExecuteString("t_FixedStep 0.033333"); - m_waitFrames = 64; // Wait some more frames for tone-mapper to adapt - } - - return; - } - - stack_string tmp; - - while (m_nextCmd < m_cmdBuf.size()) - { - SCmd& cmd = m_cmdBuf[m_nextCmd]; - - if (m_cmdFreq == 0) - { - m_cmdFreq = cmd.freq; - } - - switch (cmd.cmd) - { - case eCMDStart: - break; - case eCMDFinish: - Finish(); - break; - case eCMDOnMapLoaded: - gEnv->pTimer->SetTimer(ITimer::ETIMER_GAME, 0); - gEnv->pTimer->SetTimer(ITimer::ETIMER_UI, 0); - gEnv->pConsole->ExecuteString("t_FixedStep 0.033333"); - GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RANDOM_SEED, 0, 0); - srand(0); - break; - case eCMDConsoleCmd: - gEnv->pConsole->ExecuteString(cmd.args.c_str()); - break; - case eCMDLoadMap: - LoadMap(cmd.args.c_str()); - break; - case eCMDWaitStreaming: - m_waitFrames = -1; - m_streamingTimeout = MaxStreamingWait; - break; - case eCMDWaitFrames: - m_waitFrames = (uint32)atoi(cmd.args.c_str()); - break; - case eCMDGoto: - tmp = "playerGoto "; - tmp.append(cmd.args.c_str()); - gEnv->pConsole->ExecuteString(tmp.c_str()); - m_waitFrames = 1; - break; - case eCMDCaptureSample: - CaptureSample(cmd); - break; - } - - if (m_cmdFreq-- == 1) - { - ++m_nextCmd; - } - - if (m_waitFrames != 0) - { - break; - } - } -} - - -void CVisRegTest::LoadMap(const char* mapName) -{ - string mapCmd("map "); - mapCmd.append(mapName); - gEnv->pConsole->ExecuteString(mapCmd.c_str()); - - gEnv->pTimer->SetTimer(ITimer::ETIMER_GAME, 0); - gEnv->pTimer->SetTimer(ITimer::ETIMER_UI, 0); - gEnv->pConsole->ExecuteString("t_FixedStep 0"); - GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RANDOM_SEED, 0, 0); - srand(0); -} - - -void CVisRegTest::CaptureSample(const SCmd& cmd) -{ - if (m_cmdFreq == SampleCount) // First sample - { - m_dataSamples.push_back(SSample()); - gEnv->pConsole->ExecuteString("t_FixedStep 0"); - } - - SSample& sample = m_dataSamples.back(); - - // Collect stats - sample.imageName = cmd.args.c_str(); - sample.frameTime += gEnv->pTimer->GetRealFrameTime() * 1000.f; - sample.drawCalls += gEnv->pRenderer->GetCurrentNumberOfDrawCalls(); - - const RPProfilerStats* pRPPStats = gEnv->pRenderer->GetRPPStatsArray(); - - if (pRPPStats) - { - sample.gpuTimes[0] += pRPPStats[eRPPSTATS_OverallFrame].gpuTime; - - sample.gpuTimes[1] += pRPPStats[eRPPSTATS_SceneOverall].gpuTime; - sample.gpuTimes[2] += pRPPStats[eRPPSTATS_ShadowsOverall].gpuTime; - sample.gpuTimes[3] += pRPPStats[eRPPSTATS_LightingOverall].gpuTime; - sample.gpuTimes[4] += pRPPStats[eRPPSTATS_VfxOverall].gpuTime; - } - - if (m_cmdFreq == 1) // Final sample - { - // Screenshot - stack_string filename("@usercache@/TestResults/VisReg/"); // the default unaliased assets folder is read-only! - filename += m_testName + "/" + cmd.args.c_str(); - gEnv->pRenderer->ScreenShot(filename); - - // Average results - sample.frameTime /= (float)SampleCount; - sample.drawCalls /= SampleCount; - for (uint32 i = 0; i < MaxNumGPUTimes; ++i) - { - sample.gpuTimes[i] /= (float)SampleCount; - } - - gEnv->pConsole->ExecuteString("t_FixedStep 0.033333"); - } -} - - -void CVisRegTest::Finish() -{ - WriteResults(); - - gEnv->pConsole->ExecuteString("t_FixedStep 0"); - gEnv->pTimer->SetTimeScale(1); - - gEnv->pRenderer->EnableGPUTimers2(false); - - CryLog("VisRegTest: Finished tests"); - - if (m_quitAfterTests) - { - gEnv->pConsole->ExecuteString("quit"); - return; - } -} - - -bool CVisRegTest::WriteResults() -{ - stack_string filename("@usercache@/TestResults/VisReg/"); - filename += m_testName + "/visreg_results.xml"; - - AZ::IO::HandleType fileHandle = fxopen(filename.c_str(), "wb"); - if (fileHandle == AZ::IO::InvalidHandle) - { - return false; - } - - AZ::IO::Print(fileHandle, "\n"); - AZ::IO::Print(fileHandle, "\t\n"); - - for (int i = 0; i < (int)m_dataSamples.size(); ++i) - { - SSample sample = m_dataSamples[i]; - - AZ::IO::Print(fileHandle, "\t\t\n", i, sample.imageName); - - AZ::IO::Print(fileHandle, "\t\t\t\n"); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.frameTime); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.drawCalls); - AZ::IO::Print(fileHandle, "\t\t\t\n"); - - AZ::IO::Print(fileHandle, "\t\t\t\n"); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[0]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[1]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[2]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[3]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[4]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[5]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[6]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[7]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[8]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[9]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[10]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[11]); - AZ::IO::Print(fileHandle, "\t\t\t\t\n", sample.gpuTimes[12]); - AZ::IO::Print(fileHandle, "\t\t\t\n"); - - AZ::IO::Print(fileHandle, "\t\t\n"); - } - - AZ::IO::Print(fileHandle, "\t\n"); - AZ::IO::Print(fileHandle, ""); - gEnv->pFileIO->Close(fileHandle); - - return true; -} diff --git a/Code/CryEngine/CrySystem/VisRegTest.h b/Code/CryEngine/CrySystem/VisRegTest.h deleted file mode 100644 index 19653940a4..0000000000 --- a/Code/CryEngine/CrySystem/VisRegTest.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Visual Regression Test - - -#ifndef CRYINCLUDE_CRYSYSTEM_VISREGTEST_H -#define CRYINCLUDE_CRYSYSTEM_VISREGTEST_H -#pragma once - - -struct IConsoleCmdArgs; - -class CVisRegTest -{ -public: - static const uint32 SampleCount = 16; - static const uint32 MaxNumGPUTimes = 13; - static const float MaxStreamingWait; - -protected: - - enum ECmd - { - eCMDStart, - eCMDFinish, - eCMDOnMapLoaded, - eCMDConsoleCmd, - eCMDLoadMap, - eCMDWaitStreaming, - eCMDWaitFrames, - eCMDGoto, - eCMDCaptureSample - }; - - struct SCmd - { - ECmd cmd; - uint32 freq; - string args; - - SCmd() {} - SCmd(ECmd _cmd, const string& _args, uint32 _freq = 1) - { this->cmd = _cmd; this->args = _args; this->freq = _freq; } - }; - - struct SSample - { - const char* imageName; - float frameTime; - uint32 drawCalls; - float gpuTimes[MaxNumGPUTimes]; - - SSample() - : imageName(NULL) - , frameTime(0.f) - , drawCalls(0) - { - for (uint32 i = 0; i < MaxNumGPUTimes; ++i) - { - gpuTimes[i] = 0; - } - } - }; - -protected: - string m_testName; - std::vector< SCmd > m_cmdBuf; - std::vector< SSample > m_dataSamples; - uint32 m_nextCmd; - uint32 m_cmdFreq; - int m_waitFrames; - float m_streamingTimeout; - int m_curSample; - bool m_quitAfterTests; - -public: - - CVisRegTest(); - - void Init(IConsoleCmdArgs* pParams); - void AfterRender(); - -protected: - - bool LoadConfig(const char* configFile); - void ExecCommands(); - void LoadMap(const char* mapName); - void CaptureSample(const SCmd& cmd); - void Finish(); - bool WriteResults(); -}; - -#endif // CRYINCLUDE_CRYSYSTEM_VISREGTEST_H diff --git a/Code/CryEngine/CrySystem/XConsole.cpp b/Code/CryEngine/CrySystem/XConsole.cpp index f4271d6dc4..ee5b500b0b 100644 --- a/Code/CryEngine/CrySystem/XConsole.cpp +++ b/Code/CryEngine/CrySystem/XConsole.cpp @@ -328,7 +328,6 @@ CXConsole::CXConsole() m_fRepeatTimer = 0; m_pSysDeactivateConsole = 0; m_pFont = NULL; - m_pRenderer = NULL; m_pImage = NULL; m_nCursorPos = 0; m_nScrollPos = 0; @@ -397,18 +396,6 @@ CXConsole::~CXConsole() ////////////////////////////////////////////////////////////////////////// void CXConsole::FreeRenderResources() { - if (m_pRenderer) - { - if (m_nLoadingBackTexID) - { - m_pRenderer->RemoveTexture(m_nLoadingBackTexID); - m_nLoadingBackTexID = -1; - } - if (m_pImage) - { - m_pImage->Release(); - } - } } ////////////////////////////////////////////////////////////////////////// @@ -485,7 +472,6 @@ void CXConsole::Init(ISystem* pSystem) { m_pFont = pSystem->GetICryFont()->GetFont("default"); } - m_pRenderer = pSystem->GetIRenderer(); m_pTimer = pSystem->GetITimer(); AzFramework::InputChannelEventListener::Connect(); @@ -534,10 +520,7 @@ void CXConsole::Init(ISystem* pSystem) // ---------------------------------------------------------- - if (!m_pRenderer || gEnv->IsInToolMode()) - { - m_nLoadingBackTexID = -1; - } + m_nLoadingBackTexID = -1; if (gEnv->IsDedicated()) { @@ -1176,7 +1159,6 @@ void CXConsole::Clear() ////////////////////////////////////////////////////////////////////////// void CXConsole::Update() { - // Repeat GetIRenderer (For Editor). if (!m_pSystem) { return; @@ -1192,8 +1174,6 @@ void CXConsole::Update() // Execute the deferred commands ExecuteDeferredCommands(); - m_pRenderer = m_pSystem->GetIRenderer(); - if (!m_bConsoleActive) { m_nRepeatEventId = s_nullRepeatEventId; @@ -1588,206 +1568,10 @@ const char* CXConsole::GetHistoryElement(const bool bUpOrDown) ////////////////////////////////////////////////////////////////////////// void CXConsole::Draw() { - //ShowConsole(true); - if (!m_pSystem || !m_nTempScrollMax) - { - return; - } - - if (!m_pRenderer) - { - // For Editor. - m_pRenderer = m_pSystem->GetIRenderer(); - } - - if (!m_pRenderer) - { - return; - } - - if (!m_pFont) - { - // For Editor. - ICryFont* pICryFont = m_pSystem->GetICryFont(); - - if (pICryFont) - { - m_pFont = m_pSystem->GetICryFont()->GetFont("default"); - } - } - - ScrollConsole(); - - if (!m_bConsoleActive && con_display_last_messages == 0) - { - return; - } - - if (m_pRenderer->GetIRenderAuxGeom()) - { - m_pRenderer->GetIRenderAuxGeom()->Flush(); - } - - m_pRenderer->EF_RenderTextMessages(); - - m_pRenderer->PushProfileMarker("DISPLAY_CONSOLE"); - - if (m_nScrollPos <= 0) - { - DrawBuffer(70, "console"); - } - else - { - // cursor blinking - { - m_fCursorBlinkTimer += gEnv->pTimer->GetRealFrameTime(); // works even when time is manipulated - // m_fCursorBlinkTimer += gEnv->pTimer->GetFrameTime(ITimer::ETIMER_UI); // can be used once ETIMER_UI works even with t_FixedTime - - const float fCursorBlinkDelay = 0.5f; // in sec (similar to Windows default but might differ from actual setting) - - if (m_fCursorBlinkTimer > fCursorBlinkDelay) - { - m_bDrawCursor = !m_bDrawCursor; - m_fCursorBlinkTimer = 0.0f; - } - } - - CScopedWireFrameMode scopedWireFrame(m_pRenderer, R_SOLID_MODE); - - if (!m_nProgressRange) - { - int whiteTexId = gEnv->pRenderer ? gEnv->pRenderer->GetWhiteTextureId() : -1; - - if (m_bStaticBackground) - { - m_pRenderer->SetState(GS_NODEPTHTEST); - m_pRenderer->Draw2dImage(0, 0, 800, 600, m_pImage ? m_pImage->GetTextureID() : whiteTexId, 0.0f, 1.0f, 1.0f, 0.0f); - } - else - { - TransformationMatrices backupSceneMatrices; - m_pRenderer->Set2DMode(m_pRenderer->GetWidth(), m_pRenderer->GetHeight(), backupSceneMatrices); - - float fReferenceSize = 600.0f; - - float fSizeX = (float)m_pRenderer->GetWidth(); - float fSizeY = m_nTempScrollMax * m_pRenderer->GetHeight() / fReferenceSize; - - m_pRenderer->SetState(GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); - m_pRenderer->DrawImage(0, 0, fSizeX, fSizeY, whiteTexId, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.7f); - m_pRenderer->DrawImage(0, fSizeY, fSizeX, 2.0f * m_pRenderer->GetHeight() / fReferenceSize, whiteTexId, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 1.0f); - - m_pRenderer->Unset2DMode(backupSceneMatrices); - } - } - - // draw progress bar - if (m_nProgressRange) - { - m_pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); - m_pRenderer->Draw2dImage(0.0, 0.0, 800.0f, 600.0f, m_nLoadingBackTexID, 0.0f, 1.0f, 1.0f, 0.0f); - } - - DrawBuffer(m_nScrollPos, "console"); - } - - m_pRenderer->PopProfileMarker("DISPLAY_CONSOLE"); } -void CXConsole::DrawBuffer(int nScrollPos, const char* szEffect) +void CXConsole::DrawBuffer(int, const char*) { - if (m_pFont && m_pRenderer) - { - // The scroll position is in pixels for a 800x600 screen so we scale it to the current resolution. - Vec2 referenceSize(800.0f, 600.0f); - const float fontSizeIn800x600 = 14; - const float maxYPos = nScrollPos * (m_pRenderer->GetHeight() / referenceSize.y); - // We also scale the font from the original 800x600 size - float fontSize = fontSizeIn800x600 * (m_pRenderer->GetWidth() / referenceSize.x); - const float fontAspectRatio = 0.75f; - float minFontSize = 10.f; - float maxFontSize = 50.f; - ICVar* minFontCVar = GetCVar("r_minConsoleFontSize"); - if (minFontCVar) - { - minFontSize = minFontCVar->GetFVal(); - } - - ICVar* maxFontCVar = GetCVar("r_maxConsoleFontSize"); - if (maxFontCVar) - { - maxFontSize = maxFontCVar->GetFVal(); - } - - // Limit max font size in case minFontSize > maxFontSize - maxFontSize = AZStd::max(minFontSize, maxFontSize); - fontSize = AZStd::min(AZStd::max(fontSize, minFontSize), maxFontSize); - - STextDrawContext ctx; - //ctx.Reset(); - ctx.SetEffect(m_pFont->GetEffectId(szEffect)); - ctx.SetProportional(false); - ctx.SetCharWidthScale(0.5f); - ctx.SetSize(Vec2(fontSize, fontAspectRatio * fontSize)); - ctx.SetColor(ColorF(1, 1, 1, 1)); - ctx.SetFlags(eDrawText_CenterV | eDrawText_2D); - - float csize = 0.8f * ctx.GetCharHeight(); - ctx.SetSizeIn800x600(false); - - float yPos = maxYPos - csize - 3.0f; - float xPos = LINE_BORDER; - - float fCharWidth = (ctx.GetCharWidth() * ctx.GetCharWidthScale()); - - //int ypos=nScrollPos-csize-3; - - //Draw the input line - if (m_bConsoleActive && !m_nProgressRange) - { - /*m_pRenderer->DrawString(xPos-nCharWidth, yPos, false, ">"); - m_pRenderer->DrawString(xPos, yPos, false, m_sInputBuffer.c_str()); - if(m_bDrawCursor) - m_pRenderer->DrawString(xPos+nCharWidth*m_nCursorPos, yPos, false, "_");*/ - - m_pFont->DrawString((float)(xPos - fCharWidth), (float)yPos, ">", false, ctx); - m_pFont->DrawString((float)xPos, (float)yPos, m_sInputBuffer.c_str(), false, ctx); - - if (m_bDrawCursor) - { - string szCursorLeft(m_sInputBuffer.c_str(), m_sInputBuffer.c_str() + m_nCursorPos); - int n = m_pFont->GetTextLength(szCursorLeft.c_str(), false); - - m_pFont->DrawString((float)(xPos + (fCharWidth * n)), (float)yPos, "_", false, ctx); - } - } - - yPos -= csize; - - ConsoleBufferRItor ritor; - ritor = m_dqConsoleBuffer.rbegin(); - int nScroll = 0; - while (ritor != m_dqConsoleBuffer.rend() && yPos >= 0) - { - if (nScroll >= m_nScrollLine) - { - const char* buf = ritor->c_str();// GetBuf(k); - - if (*buf > 0 && *buf < 32) - { - buf++; // to jump over verbosity level character - } - if (yPos + csize > 0) - { - m_pFont->DrawString((float)xPos, (float)yPos, buf, false, ctx); - } - yPos -= csize; - } - nScroll++; - - ++ritor; - } //k - } } @@ -1828,44 +1612,6 @@ int CXConsole::GetLineCount() const ////////////////////////////////////////////////////////////////////////// void CXConsole::ScrollConsole() { - if (!m_pRenderer) - { - return; - } - - int nCurrHeight = m_pRenderer->GetHeight(); - - switch (m_sdScrollDir) - { - ///////////////////////////////// - case sdDOWN: // The console is scrolling down - - // Vlads note: console should go down immediately, otherwise it can look very bad on startup - //m_nScrollPos+=nCurrHeight/2; - m_nScrollPos = m_nTempScrollMax; - - if (m_nScrollPos > m_nTempScrollMax) - { - m_nScrollPos = m_nTempScrollMax; - m_sdScrollDir = sdNONE; - } - break; - ///////////////////////////////// - case sdUP: // The console is scrolling up - - m_nScrollPos -= nCurrHeight;//2; - - if (m_nScrollPos < 0) - { - m_nScrollPos = 0; - m_sdScrollDir = sdNONE; - } - break; - ///////////////////////////////// - case sdNONE: - break; - ///////////////////////////////// - } } @@ -2467,13 +2213,6 @@ void CXConsole::ExecuteStringInternal(const char* command, const bool bFromConso if (!sTemp.empty() || (pCVar->GetType() == CVAR_STRING)) { - // renderer cvars will be updated in the render thread - if ((pCVar->GetFlags() & VF_RENDERER_CVAR) && m_pRenderer) - { - m_pRenderer->SetRendererCVar(pCVar, sTemp.c_str(), bSilentMode); - continue; - } - pCVar->Set(sTemp.c_str()); } } @@ -2500,36 +2239,8 @@ void CXConsole::ExecuteDeferredCommands() { TDeferredCommandList::iterator it; - // const float fontHeight = 10; - // ColorF col = Col_Yellow; - // - // float curX = 10; - // float curY = 10; - - //IRenderer* pRenderer = gEnv->pRenderer; - - // Print the deferred messages - // it = m_deferredCommands.begin(); - // if (it != m_deferredCommands.end()) - // { - // pRenderer->Draw2dLabel( curX, curY += fontHeight, 1.2f, &col.r, false - // , "Pending deferred commands = %d", m_deferredCommands.size() ); - // } - // - // for ( - // ; it != m_deferredCommands.end() - // ; ++it - // ) - // { - // pRenderer->Draw2dLabel( curX + fontHeight * 2.0f, curY += fontHeight, 1.2f, &col.r, false - // , "Cmd: %s", it->command.c_str() ); - // } - if (m_waitFrames) { - // pRenderer->Draw2dLabel( curX, curY += fontHeight, 1.2f, &col.r, false - // , "Waiting frames = %d", m_waitFrames ); - --m_waitFrames; return; } @@ -2538,10 +2249,6 @@ void CXConsole::ExecuteDeferredCommands() { if (m_waitSeconds > gEnv->pTimer->GetFrameStartTime()) { - // pRenderer->Draw2dLabel( curX, curY += fontHeight, 1.2f, &col.r, false - // , "Waiting seconds = %f" - // , m_waitSeconds.GetSeconds() - gEnv->pTimer->GetFrameStartTime().GetSeconds() ); - return; } @@ -2566,8 +2273,6 @@ void CXConsole::ExecuteDeferredCommands() break; } } - - //m_deferredExecution = false; } ////////////////////////////////////////////////////////////////////////// @@ -3143,71 +2848,18 @@ void CXConsole::PostLine(const char* lineOfText, size_t len) } ////////////////////////////////////////////////////////////////////////// -void CXConsole::ResetProgressBar(int nProgressBarRange) +void CXConsole::ResetProgressBar(int) { - m_nProgressRange = nProgressBarRange; - m_nProgress = 0; - - if (nProgressBarRange < 0) - { - nProgressBarRange = 0; - } - - if (!m_nProgressRange) - { - if (m_nLoadingBackTexID) - { - if (m_pRenderer) - { - m_pRenderer->RemoveTexture(m_nLoadingBackTexID); - } - m_nLoadingBackTexID = -1; - } - } - - static ICVar* log_Verbosity = GetCVar("log_Verbosity"); - - if (log_Verbosity && (!log_Verbosity->GetIVal())) - { - Clear(); - } } ////////////////////////////////////////////////////////////////////////// void CXConsole::TickProgressBar() { - if (m_nProgressRange != 0 && m_nProgressRange > m_nProgress) - { - m_nProgress++; - m_pSystem->UpdateLoadingScreen(); - } - if (m_pSystem->GetIRenderer()) - { - m_pSystem->GetIRenderer()->FlushRTCommands(false, false, false); // Try to switch render thread contexts to make RT always busy during loading - } } ////////////////////////////////////////////////////////////////////////// -void CXConsole::SetLoadingImage(const char* szFilename) +void CXConsole::SetLoadingImage(const char*) { - ITexture* pTex = 0; - - pTex = m_pSystem->GetIRenderer()->EF_LoadTexture(szFilename, FT_DONT_STREAM | FT_NOMIPS); - - if (!pTex || (pTex->GetFlags() & FT_FAILED)) - { - SAFE_RELEASE(pTex); - pTex = m_pSystem->GetIRenderer()->EF_LoadTexture("Textures/Console/loadscreen_default.dds", FT_DONT_STREAM | FT_NOMIPS); - } - - if (pTex) - { - m_nLoadingBackTexID = pTex->GetTextureID(); - } - else - { - m_nLoadingBackTexID = -1; - } } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/XConsole.h b/Code/CryEngine/CrySystem/XConsole.h index ed3a3e9b82..01649872ba 100644 --- a/Code/CryEngine/CrySystem/XConsole.h +++ b/Code/CryEngine/CrySystem/XConsole.h @@ -418,7 +418,6 @@ private: // ---------------------------------------------------------- CSystem* m_pSystem; IFFont* m_pFont; - IRenderer* m_pRenderer; ITimer* m_pTimer; ICVar* m_pSysDeactivateConsole; diff --git a/Code/CryEngine/CrySystem/crysystem_files.cmake b/Code/CryEngine/CrySystem/crysystem_files.cmake index bfc7b092fd..0b62483e43 100644 --- a/Code/CryEngine/CrySystem/crysystem_files.cmake +++ b/Code/CryEngine/CrySystem/crysystem_files.cmake @@ -19,7 +19,6 @@ set(FILES ConsoleBatchFile.cpp ConsoleHelpGen.cpp CryAsyncMemcpy.cpp - CrySizerStats.cpp DebugCallStack.cpp GeneralMemoryHeap.cpp HandlerBase.cpp @@ -57,7 +56,6 @@ set(FILES UnixConsole.h SystemInit.h Serialization/MemoryReader.h - MemoryFragmentationProfiler.h XML/ReadWriteXMLSink.h Serialization/ArchiveHost.h Serialization/MemoryWriter.h @@ -70,7 +68,6 @@ set(FILES CmdLineArg.h ConsoleBatchFile.h ConsoleHelpGen.h - CrySizerStats.h CryWaterMark.h DebugCallStack.h GeneralMemoryHeap.h @@ -92,13 +89,11 @@ set(FILES crash_face.bmp ImageHandler.h ImageHandler.cpp - DefragAllocator.cpp MemoryAddressRange.cpp PageMappingHeap.cpp CustomMemoryHeap.cpp MemoryManager.cpp MTSafeAllocator.cpp - DefragAllocator.h MemoryAddressRange.h PageMappingHeap.h MemoryManager.h @@ -118,10 +113,8 @@ set(FILES XML/WriteXMLSource.cpp ZipFile.h ZipFileFormat_info.h - PerfHUD.cpp ProfileLogSystem.cpp Sampler.cpp - PerfHUD.h ProfileLogSystem.h Sampler.h LocalizedStringManager.cpp @@ -138,24 +131,10 @@ set(FILES ExtensionSystem/CryFactoryRegistryImpl.h ExtensionSystem/TestCases/TestExtensions.cpp ExtensionSystem/TestCases/TestExtensions.h - MiniGUI/DrawContext.cpp - MiniGUI/MiniButton.cpp - MiniGUI/MiniGUI.cpp - MiniGUI/MiniInfoBox.cpp - MiniGUI/MiniMenu.cpp - MiniGUI/MiniTable.cpp - MiniGUI/DrawContext.h - MiniGUI/MiniButton.h - MiniGUI/MiniGUI.h - MiniGUI/MiniInfoBox.h - MiniGUI/MiniMenu.h - MiniGUI/MiniTable.h ZLibCompressor.cpp ZLibCompressor.h SoftCode/SoftCodeMgr.cpp SoftCode/SoftCodeMgr.h - OverloadSceneManager/OverloadSceneManager.cpp - OverloadSceneManager/OverloadSceneManager.h Huffman.cpp Huffman.h RemoteConsole/RemoteConsole.cpp @@ -197,8 +176,6 @@ set(FILES Serialization/XmlIArchive.h Serialization/XmlOArchive.cpp Serialization/XmlOArchive.h - HMDCVars.h - HMDCVars.cpp StreamEngine/StreamAsyncFileRequest.cpp StreamEngine/StreamAsyncFileRequest_Jobs.cpp StreamEngine/StreamEngine.cpp @@ -210,13 +187,9 @@ set(FILES StreamEngine/StreamIOThread.h StreamEngine/StreamReadStream.h StreamEngine/AZRequestReadStream.h - VisRegTest.cpp - VisRegTest.h CrashHandler.rc CrySystem_precompiled.cpp CPUDetect.cpp CPUDetect.h - CrySizerImpl.cpp - CrySizerImpl.h WindowsErrorReporting.cpp ) diff --git a/Code/CryEngine/CrySystem/crysystem_test_files.cmake b/Code/CryEngine/CrySystem/crysystem_test_files.cmake index 650e9b0063..fc236afcf3 100644 --- a/Code/CryEngine/CrySystem/crysystem_test_files.cmake +++ b/Code/CryEngine/CrySystem/crysystem_test_files.cmake @@ -15,7 +15,6 @@ set(FILES Tests/Test_CLog.cpp Tests/Test_CommandRegistration.cpp Tests/Test_CryPrimitives.cpp - Tests/Test_CrySizer.cpp Tests/test_CrySystem.cpp Tests/Test_Localization.cpp Tests/test_Main.cpp diff --git a/Code/Framework/AtomCore/AtomCore/Serialization/Json/JsonUtils.cpp b/Code/Framework/AtomCore/AtomCore/Serialization/Json/JsonUtils.cpp index dbc0be55f9..dc7d26577b 100644 --- a/Code/Framework/AtomCore/AtomCore/Serialization/Json/JsonUtils.cpp +++ b/Code/Framework/AtomCore/AtomCore/Serialization/Json/JsonUtils.cpp @@ -189,7 +189,7 @@ namespace AZ if (!WasLoadSuccess(result.GetOutcome())) { // This if is a hack around fault in the JSON serialization system - // Jira: https://jira.agscollab.com/browse/LY-106587 + // Jira: LY-106587 if (message != "No part of the string could be interpreted as a uuid.") { deserializeError.append(message); diff --git a/Code/Framework/AzCore/AzCore/Component/Component.cpp b/Code/Framework/AzCore/AzCore/Component/Component.cpp index f1e8aa1fb0..498e4d03d3 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Component.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -173,7 +174,11 @@ namespace AZ //========================================================================= void ComponentDescriptor::ReleaseDescriptor() { - EBUS_EVENT(ComponentApplicationBus, UnregisterComponentDescriptor, this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->UnregisterComponentDescriptor(this); + } delete this; } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index d0f277a6b8..daf5b5efd2 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -526,6 +526,11 @@ namespace AZ // are destroyed m_commandLine = {}; + m_entityAddedEvent.DisconnectAllHandlers(); + m_entityRemovedEvent.DisconnectAllHandlers(); + m_entityActivatedEvent.DisconnectAllHandlers(); + m_entityDeactivatedEvent.DisconnectAllHandlers(); + DestroyAllocator(); } @@ -980,6 +985,26 @@ namespace AZ handler.Connect(m_entityRemovedEvent); } + void ComponentApplication::RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) + { + handler.Connect(m_entityActivatedEvent); + } + + void ComponentApplication::RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) + { + handler.Connect(m_entityDeactivatedEvent); + } + + void ComponentApplication::SignalEntityActivated(AZ::Entity* entity) + { + m_entityActivatedEvent.Signal(entity); + } + + void ComponentApplication::SignalEntityDeactivated(AZ::Entity* entity) + { + m_entityDeactivatedEvent.Signal(entity); + } + //========================================================================= // AddEntity // [5/30/2012] diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index 8617aa5f2e..fac2867074 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -204,6 +204,10 @@ namespace AZ void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) override final; void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) override final; void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final; + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final; + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final; + void SignalEntityActivated(Entity* entity) override final; + void SignalEntityDeactivated(Entity* entity) override final; bool AddEntity(Entity* entity) override; bool RemoveEntity(Entity* entity) override; bool DeleteEntity(const EntityId& id) override; @@ -382,6 +386,8 @@ namespace AZ AZStd::unique_ptr m_settingsRegistry; EntityAddedEvent m_entityAddedEvent; EntityRemovedEvent m_entityRemovedEvent; + EntityAddedEvent m_entityActivatedEvent; + EntityRemovedEvent m_entityDeactivatedEvent; AZ::IConsole* m_console{}; Descriptor m_descriptor; bool m_isStarted{ false }; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h index 3582e6ebb8..c93f07f347 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h @@ -72,6 +72,8 @@ namespace AZ using EntityAddedEvent = AZ::Event; using EntityRemovedEvent = AZ::Event; + using EntityActivatedEvent = AZ::Event; + using EntityDeactivatedEvent = AZ::Event; //! Interface that components can use to make requests of the main application. class ComponentApplicationRequests @@ -102,6 +104,22 @@ namespace AZ //! @param handler the event handler to signal. virtual void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) = 0; + //! Registers an event handler that will be signalled whenever an entity is added. + //! @param handler the event handler to signal. + virtual void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) = 0; + + //! Registers an event handler that will be signalled whenever an entity is removed. + //! @param handler the event handler to signal. + virtual void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) = 0; + + //! Signals that the provided entity has been activated. + //! @param entity the entity being activated. + virtual void SignalEntityActivated(AZ::Entity* entity) = 0; + + //! Signals that the provided entity has been deactivated. + //! @param entity the entity being deactivated. + virtual void SignalEntityDeactivated(AZ::Entity* entity) = 0; + //! Adds an entity to the application's registry. //! Calling Init() on an entity automatically performs this operation. //! @param entity A pointer to the entity to add to the application's registry. diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index b18474e428..b7c161b53c 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -112,7 +112,11 @@ namespace AZ { EBUS_EVENT(EntitySystemBus, OnEntityDestruction, m_id); EBUS_EVENT_ID(m_id, EntityBus, OnEntityDestruction, m_id); - EBUS_EVENT(ComponentApplicationBus, RemoveEntity, this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->RemoveEntity(this); + } m_stateEvent.Signal(State::Init, State::Destroying); } @@ -216,12 +220,22 @@ namespace AZ EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityActivated, m_id); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->SignalEntityActivated(this); + } } void Entity::Deactivate() { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->SignalEntityDeactivated(this); + } EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id); diff --git a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp index 6c142975e0..c004e2c406 100644 --- a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp @@ -126,9 +126,11 @@ namespace AZ char buffer[MaxLogBufferSize]; const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args); - buffer[AZStd::min(length, MaxLogBufferSize - 2)] = '\n'; buffer[AZStd::min(length + 1, MaxLogBufferSize - 1)] = '\0'; + m_logEvent.Signal(level, buffer, file, function, line); + // Force a new-line before calling the AZ::Debug::Trace functions, as they assume a newline is present + buffer[AZStd::min(length + 1, MaxLogBufferSize - 2)] = '\n'; switch (level) { case LogLevel::Warn: @@ -142,8 +144,6 @@ namespace AZ AZ::Debug::Trace::Output("Logger", buffer); break; } - - m_logEvent.Signal(level, buffer, file, function, line); } void LoggerSystemComponent::SetLevel(const AZ::ConsoleCommandContainer& arguments) diff --git a/Code/Framework/AzCore/AzCore/EBus/Event.inl b/Code/Framework/AzCore/AzCore/EBus/Event.inl index 82f5645ccd..3786f1c26b 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Event.inl +++ b/Code/Framework/AzCore/AzCore/EBus/Event.inl @@ -233,6 +233,14 @@ namespace AZ AZ_Assert(handler->m_event == this, "Entry event does not match"); handler->Disconnect(); } + + // Free up any owned memory + AZStd::vector freeHandlers; + m_handlers.swap(freeHandlers); + AZStd::vector freeAdds; + m_addList.swap(freeAdds); + AZStd::stack freeFree; + m_freeList.swap(freeFree); } diff --git a/Code/Framework/AzCore/AzCore/Math/MathUtils.h b/Code/Framework/AzCore/AzCore/Math/MathUtils.h index 4a331e4a83..a7fedf5ffa 100644 --- a/Code/Framework/AzCore/AzCore/Math/MathUtils.h +++ b/Code/Framework/AzCore/AzCore/Math/MathUtils.h @@ -13,16 +13,17 @@ #pragma once #include +#include +#include +#include #include #include #include -#include + #include #include -#include +#include #include -#include -#include // We have a separate inline define for math functions. // The performance of these functions is very sensitive to inlining, and some compilers don't deal well with this. @@ -308,12 +309,12 @@ namespace AZ AZ_MATH_INLINE bool IsClose(float a, float b, float tolerance = Constants::Tolerance) { - return (fabsf(a - b) <= tolerance); + return (AZStd::abs(a - b) <= tolerance); } AZ_MATH_INLINE bool IsClose(double a, double b, double tolerance = Constants::Tolerance) { - return (fabs(a - b) <= tolerance); + return (AZStd::abs(a - b) <= tolerance); } //! Returns x >= 0.0f ? 1.0f : -1.0f. @@ -402,12 +403,12 @@ namespace AZ AZ_MATH_INLINE float GetAbs(float a) { - return fabsf(a); + return AZStd::abs(a); } AZ_MATH_INLINE double GetAbs(double a) { - return std::abs(a); + return AZStd::abs(a); } AZ_MATH_INLINE float GetMod(float a, float b) @@ -441,7 +442,7 @@ namespace AZ template AZ_MATH_INLINE bool IsCloseMag(T x, T y, T epsilonValue = std::numeric_limits::epsilon()) { - return (std::fabs(x - y) <= epsilonValue * GetMax(GetMax(T(1.0), std::fabs(x)), std::fabs(y))); + return (AZStd::abs(x - y) <= epsilonValue * GetMax(GetMax(T(1.0), AZStd::abs(x)), AZStd::abs(y))); } //! ClampIfCloseMag(x, y, epsilon) returns y when x and y are within epsilon of each other (taking magnitude into account). Otherwise returns x. diff --git a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h index e15071f56c..873bb5ad22 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h @@ -33,6 +33,10 @@ namespace UnitTest MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&)); diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index 71f01cb349..7025b3977e 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -169,5 +169,10 @@ namespace AZ::Utils template AZ::Outcome, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize); template AZ::Outcome, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize); - + AZ::IO::FixedMaxPathString GetO3deManifestDirectory() + { + AZ::IO::FixedMaxPath path = GetHomeDirectory(); + path /= ".o3de"; + return path.Native(); + } } diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.h b/Code/Framework/AzCore/AzCore/Utils/Utils.h index f6152d0e9b..4e64ce5a39 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.h +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.h @@ -88,6 +88,9 @@ namespace AZ //! Retrieves the project name from the settings registry AZ::SettingsRegistryInterface::FixedValueString GetProjectName(); + //! Retrieves the full directory to the Home directory, i.e. " or overrideHomeDirectory" + AZ::IO::FixedMaxPathString GetHomeDirectory(); + //! Retrieves the full directory to the O3DE manifest directory, i.e. "/.o3de" AZ::IO::FixedMaxPathString GetO3deManifestDirectory(); diff --git a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake index 8de54138ee..ebf26cad68 100644 --- a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake +++ b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake @@ -31,6 +31,7 @@ set(FILES iterator.h limits.h numeric.h + math.h optional.h ratio.h reference_wrapper.h diff --git a/Code/Framework/AzCore/AzCore/std/math.h b/Code/Framework/AzCore/AzCore/std/math.h new file mode 100644 index 0000000000..9e9be7944a --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/math.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 + +namespace AZStd +{ + using std::abs; + using std::acos; + using std::asin; + using std::atan; + using std::atan2; + using std::cos; + using std::exp2; + using std::fmod; + using std::round; + using std::sin; + using std::sqrt; + using std::tan; +} // namespace AZStd diff --git a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp index 20a9edbe2c..0ea17e938a 100644 --- a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp +++ b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp @@ -14,7 +14,7 @@ namespace AZ::Utils { - AZ::IO::FixedMaxPathString GetO3deManifestDirectory() + AZ::IO::FixedMaxPathString GetHomeDirectory() { return {}; } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp index 2763baac1d..9dbe8f7264 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp @@ -25,8 +25,19 @@ namespace AZ void NativeErrorMessageBox(const char*, const char*) {} - AZ::IO::FixedMaxPathString GetO3deManifestDirectory() + AZ::IO::FixedMaxPathString GetHomeDirectory() { + constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir"; + AZ::IO::FixedMaxPathString overrideHomeDir; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey)) + { + AZ::IO::FixedMaxPath path{overrideHomeDir}; + return path.Native(); + } + } + if (const char* homePath = std::getenv("HOME"); homePath != nullptr) { AZ::IO::FixedMaxPath path{homePath}; diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp index 2ade67955b..18cef227db 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp @@ -22,15 +22,25 @@ namespace AZ::Utils ::MessageBox(0, message, title, MB_OK | MB_ICONERROR); } - AZ::IO::FixedMaxPathString GetO3deManifestDirectory() + AZ::IO::FixedMaxPathString GetHomeDirectory() { + constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir"; + AZ::IO::FixedMaxPathString overrideHomeDir; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey)) + { + AZ::IO::FixedMaxPath path{overrideHomeDir}; + return path.Native(); + } + } + char userProfileBuffer[AZ::IO::MaxPathLength]{}; size_t variableSize = 0; auto err = getenv_s(&variableSize, userProfileBuffer, AZ::IO::MaxPathLength, "USERPROFILE"); if (!err) { AZ::IO::FixedMaxPath path{ userProfileBuffer }; - path /= ".o3de"; return path.Native(); } diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 687aee8aa4..6ae97e1304 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -49,9 +49,13 @@ namespace UnitTest // ComponentApplicationBus AZ::ComponentApplication* GetApplication() override { return nullptr; } void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} + void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override {} void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override {} - void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override {} + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override {} + void SignalEntityActivated(AZ::Entity*) override {} + void SignalEntityDeactivated(AZ::Entity*) override {} bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index 35cf17c2e0..036942f9dd 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1232,6 +1232,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(Entity*) override { } + void SignalEntityDeactivated(Entity*) override { } bool AddEntity(Entity*) override { return false; } bool RemoveEntity(Entity*) override { return false; } bool DeleteEntity(const EntityId&) override { return false; } @@ -1252,6 +1256,7 @@ namespace UnitTest m_serializeContext.reset(aznew AZ::SerializeContext()); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); @@ -1270,6 +1275,7 @@ namespace UnitTest AZ::AllocatorInstance::Destroy(); AZ::AllocatorInstance::Destroy(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h index fd72c37b60..4e89e0a45c 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h @@ -51,7 +51,6 @@ namespace AZ::IO : ArchiveLocationPriority::ePakPriorityFileFirst }; // Which file location to favor (loose vs. pak files) int nMessageInvalidFileAccess{}; int nLogInvalidFileAccess{ IsReleaseConfig ? 0 : 1 }; - int nLoadFrontendShaderCache{ FRONTEND_SHADER_CACHE_DEFAULT }; int nDisableNonLevelRelatedPaks{ 1 }; int nWarnOnPakAccessFails{ 1 }; // Whether to treat failed pak access as a warning or log message int nSetLogLevel{ 3 }; diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 910d6749af..5605fe567c 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -11,10 +11,12 @@ */ #include +#include #include #include #include #include +#include #include #include @@ -693,9 +695,8 @@ namespace AzFramework parentId = handler->GetParentId(); } #endif - - AZ::Entity* parentEntity = nullptr; - EBUS_EVENT_RESULT(parentEntity, AZ::ComponentApplicationBus, FindEntity, parentEntityId); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(parentEntityId) : nullptr; AZ_Assert(parentEntity, "We expect to have a parent entity associated with the provided parent's entity Id."); if (parentEntity) { @@ -744,8 +745,8 @@ namespace AzFramework m_parentId = parentId; if (m_parentId.IsValid()) { - AZ::Entity* parentEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(m_parentId) : nullptr; m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active); m_onNewParentKeepWorldTM = isKeepWorldTM; @@ -832,6 +833,12 @@ namespace AzFramework EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM); m_transformChangedEvent.Signal(m_localTM, m_worldTM); + + AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface::Get(); + if (boundsUnion != nullptr) + { + boundsUnion->OnTransformUpdated(GetEntity()); + } } void TransformComponent::ComputeWorldTM() diff --git a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp index 999013fdf8..461d578e28 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp @@ -93,6 +93,8 @@ namespace AzFramework InitContext(); GameEntityContextRequestBus::Handler::BusConnect(); + + m_entityVisibilityBoundsUnionSystem.Connect(); } //========================================================================= @@ -100,6 +102,8 @@ namespace AzFramework //========================================================================= void GameEntityContextComponent::Deactivate() { + m_entityVisibilityBoundsUnionSystem.Disconnect(); + GameEntityContextRequestBus::Handler::BusDisconnect(); DestroyContext(); diff --git a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h index 482b2133ca..35424fd09c 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "EntityContext.h" @@ -91,6 +92,9 @@ namespace AzFramework { required.push_back(AZ_CRC("SliceSystemService", 0x1a5b7aad)); } + + private: + AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp b/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp index 23d74f7578..143c1f7916 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp +++ b/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp @@ -139,7 +139,8 @@ namespace AzFramework "Implementers of IntersectionRequestBus must also implement BoundsRequestBus to ensure valid " "bounds are returned"); - m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entityId) }); + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entity) }); } m_dirtyEntities.clear(); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index e9dace3433..4c95865938 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -29,14 +29,14 @@ namespace AzFramework AZ_CVAR(float, ed_cameraSystemOrbitDollyScrollSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemOrbitDollyCursorSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemScrollTranslateSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); - AZ_CVAR(float, ed_cameraSystemDefaultOrbitDistance, 60.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); - AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 100.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); + AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 60.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemLookSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemTranslateSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemRotateSpeed, 0.005f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemPanSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(bool, ed_cameraSystemPanInvertX, true, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(bool, ed_cameraSystemPanInvertY, true, nullptr, AZ::ConsoleFunctorFlags::Null, ""); + AZ_CVAR(float, ed_cameraSystemLookDeadzone, 2.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR( AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, ""); @@ -125,22 +125,22 @@ namespace AzFramework { if (orientation.GetElement(2, 0) > -1.0f) { - x = std::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2)); - y = std::asin(-orientation.GetElement(2, 0)); - z = std::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0)); + x = AZStd::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2)); + y = AZStd::asin(-orientation.GetElement(2, 0)); + z = AZStd::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0)); } else { x = 0.0f; y = AZ::Constants::Pi * 0.5f; - z = -std::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1)); + z = -AZStd::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1)); } } else { x = 0.0f; y = -AZ::Constants::Pi * 0.5f; - z = std::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1)); + z = AZStd::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1)); } return {x, y, z}; @@ -150,31 +150,35 @@ namespace AzFramework { const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform)); - camera.m_lookAt = transform.GetTranslation(); camera.m_pitch = eulerAngles.GetX(); camera.m_yaw = eulerAngles.GetZ(); + // note: m_lookDist is negative so we must invert it here + camera.m_lookAt = transform.GetTranslation() + (camera.Rotation().GetBasisY() * -camera.m_lookDist); + } + + static ScreenVector CursorDelta(const AZStd::optional& currentPosition, const AZStd::optional& lastPosition) + { + return currentPosition.has_value() && lastPosition.has_value() ? currentPosition.value() - lastPosition.value() + : ScreenVector(0, 0); } bool CameraSystem::HandleEvents(const InputEvent& event) { - if (const auto& cursor_motion = AZStd::get_if(&event)) + if (const auto& cursor = AZStd::get_if(&event)) { - m_currentCursorPosition = cursor_motion->m_position; + m_currentCursorPosition = cursor->m_position; } else if (const auto& scroll = AZStd::get_if(&event)) { m_scrollDelta = scroll->m_delta; } - return m_cameras.HandleEvents(event); + return m_cameras.HandleEvents(event, CursorDelta(m_currentCursorPosition, m_lastCursorPosition), m_scrollDelta); } Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime) { - const auto cursorDelta = m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value() - ? m_currentCursorPosition.value() - m_lastCursorPosition.value() - : ScreenVector(0, 0); - + const auto cursorDelta = CursorDelta(m_currentCursorPosition, m_lastCursorPosition); if (m_currentCursorPosition.has_value()) { m_lastCursorPosition = m_currentCursorPosition; @@ -192,18 +196,18 @@ namespace AzFramework m_idleCameraInputs.push_back(AZStd::move(cameraInput)); } - bool Cameras::HandleEvents(const InputEvent& event) + bool Cameras::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) { bool handling = false; for (auto& cameraInput : m_activeCameraInputs) { - cameraInput->HandleEvents(event); + cameraInput->HandleEvents(event, cursorDelta, scrollDelta); handling = !cameraInput->Idle() || handling; } for (auto& cameraInput : m_idleCameraInputs) { - cameraInput->HandleEvents(event); + cameraInput->HandleEvents(event, cursorDelta, scrollDelta); } return handling; @@ -215,8 +219,8 @@ namespace AzFramework { auto& cameraInput = m_idleCameraInputs[i]; const bool canBegin = cameraInput->Beginning() && - std::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(), - [](const auto& input) { return !input->Exclusive(); }) && + AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(), + [](const auto& input) { return !input->Exclusive(); }) && (!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty())); if (canBegin) @@ -271,7 +275,7 @@ namespace AzFramework } } - void RotateCameraInput::HandleEvents(const InputEvent& event) + void RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto& input = AZStd::get_if(&event)) { @@ -279,14 +283,27 @@ namespace AzFramework { if (input->m_state == InputChannel::State::Began) { - BeginActivation(); + m_tryingToBegin = true; + m_moveAccumulator = 0.0f; } else if (input->m_state == InputChannel::State::Ended) { + m_tryingToBegin = false; EndActivation(); } } } + + if (m_tryingToBegin) + { + // only allow the action to begin if the mouse has been moved a small amount + m_moveAccumulator += ScreenVectorLength(cursorDelta); + if (m_moveAccumulator > ed_cameraSystemLookDeadzone) + { + BeginActivation(); + m_tryingToBegin = false; + } + } } Camera RotateCameraInput::StepCamera( @@ -298,7 +315,7 @@ namespace AzFramework nextCamera.m_pitch -= float(cursorDelta.m_y) * ed_cameraSystemRotateSpeed; nextCamera.m_yaw -= float(cursorDelta.m_x) * ed_cameraSystemRotateSpeed; - const auto clampRotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; + const auto clampRotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; nextCamera.m_yaw = clampRotation(nextCamera.m_yaw); // clamp pitch to be +-90 degrees @@ -307,7 +324,8 @@ namespace AzFramework return nextCamera; } - void PanCameraInput::HandleEvents(const InputEvent& event) + void PanCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto& input = AZStd::get_if(&event)) { @@ -382,7 +400,8 @@ namespace AzFramework return TranslationType::Nil; } - void TranslateCameraInput::HandleEvents(const InputEvent& event) + void TranslateCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto& input = AZStd::get_if(&event)) { @@ -478,7 +497,7 @@ namespace AzFramework m_boost = false; } - void OrbitCameraInput::HandleEvents(const InputEvent& event) + void OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) { if (const auto* input = AZStd::get_if(&event)) { @@ -497,7 +516,7 @@ namespace AzFramework if (Active()) { - m_orbitCameras.HandleEvents(event); + m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta); } } @@ -509,8 +528,10 @@ namespace AzFramework if (Beginning()) { float hit_distance = 0.0f; - if (AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight)) - .CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance)) + AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight)) + .CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance); + + if (hit_distance > 0.0f) { hit_distance = AZStd::min(hit_distance, ed_cameraSystemMaxOrbitDistance); nextCamera.m_lookDist = -hit_distance; @@ -539,7 +560,8 @@ namespace AzFramework return nextCamera; } - void OrbitDollyScrollCameraInput::HandleEvents(const InputEvent& event) + void OrbitDollyScrollCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) { @@ -557,7 +579,8 @@ namespace AzFramework return nextCamera; } - void OrbitDollyCursorMoveCameraInput::HandleEvents(const InputEvent& event) + void OrbitDollyCursorMoveCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto& input = AZStd::get_if(&event)) { @@ -584,7 +607,8 @@ namespace AzFramework return nextCamera; } - void ScrollTranslationCameraInput::HandleEvents(const InputEvent& event) + void ScrollTranslationCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) { @@ -610,7 +634,7 @@ namespace AzFramework Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const float deltaTime) { - const auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; + const auto clamp_rotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; // keep yaw in 0 - 360 range float targetYaw = clamp_rotation(targetCamera.m_yaw); @@ -621,7 +645,7 @@ namespace AzFramework // ensure smooth transition when moving across 0 - 360 boundary const float yawDelta = targetYaw - currentYaw; - if (std::abs(yawDelta) >= AZ::Constants::Pi) + if (AZStd::abs(yawDelta) >= AZ::Constants::Pi) { targetYaw -= AZ::Constants::TwoPi * sign(yawDelta); } @@ -629,12 +653,12 @@ namespace AzFramework Camera camera; // note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent // article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php - const float lookRate = std::exp2(ed_cameraSystemLookSmoothness); - const float lookT = std::exp2(-lookRate * deltaTime); + const float lookRate = AZStd::exp2(ed_cameraSystemLookSmoothness); + const float lookT = AZStd::exp2(-lookRate * deltaTime); camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookT); camera.m_yaw = AZ::Lerp(targetYaw, currentYaw, lookT); - const float moveRate = std::exp2(ed_cameraSystemTranslateSmoothness); - const float moveT = std::exp2(-moveRate * deltaTime); + const float moveRate = AZStd::exp2(ed_cameraSystemTranslateSmoothness); + const float moveT = AZStd::exp2(-moveRate * deltaTime); camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveT); camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveT); return camera; @@ -655,7 +679,7 @@ namespace AzFramework const auto* position = inputChannel.GetCustomData(); AZ_Assert(position, "Expected PositionData2D but found nullptr"); - return CursorMotionEvent{ScreenPoint( + return CursorEvent{ScreenPoint( position->m_normalizedPosition.GetX() * windowSize.m_width, position->m_normalizedPosition.GetY() * windowSize.m_height)}; } else if (inputChannelId == InputDeviceMouse::Movement::Z) diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index 6ccd7c43eb..6475753017 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -70,7 +70,7 @@ namespace AzFramework void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform); - struct CursorMotionEvent + struct CursorEvent { ScreenPoint m_position; }; @@ -86,7 +86,7 @@ namespace AzFramework InputChannel::State m_state; //!< Channel state. (e.g. Begin/update/end event). }; - using InputEvent = AZStd::variant; + using InputEvent = AZStd::variant; class CameraInput { @@ -147,7 +147,7 @@ namespace AzFramework ResetImpl(); } - virtual void HandleEvents(const InputEvent& event) = 0; + virtual void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0; virtual Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) = 0; virtual bool Exclusive() const @@ -170,7 +170,7 @@ namespace AzFramework { public: void AddCamera(AZStd::shared_ptr cameraInput); - bool HandleEvents(const InputEvent& event); + bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta); Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime); void Reset(); @@ -201,11 +201,13 @@ namespace AzFramework { } - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; private: InputChannelId m_rotateChannelId; + float m_moveAccumulator = 0.0f; + bool m_tryingToBegin = false; }; struct PanAxes @@ -243,7 +245,7 @@ namespace AzFramework , m_panChannelId(panChannelId) { } - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; private: @@ -285,7 +287,7 @@ namespace AzFramework : m_translationAxesFn(AZStd::move(translationAxesFn)) { } - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; void ResetImpl() override; @@ -354,7 +356,7 @@ namespace AzFramework class OrbitDollyScrollCameraInput : public CameraInput { public: - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; }; @@ -364,7 +366,7 @@ namespace AzFramework explicit OrbitDollyCursorMoveCameraInput(const InputChannelId dollyChannelId) : m_dollyChannelId(dollyChannelId) {} - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; private: @@ -374,14 +376,14 @@ namespace AzFramework class ScrollTranslationCameraInput : public CameraInput { public: - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; }; class OrbitCameraInput : public CameraInput { public: - void HandleEvents(const InputEvent& event) override; + void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; bool Exclusive() const override { diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h index d3ae4e16f3..c48b1a5878 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h @@ -134,11 +134,16 @@ namespace AzFramework return !operator==(lhs, rhs); } + inline float ScreenVectorLength(const ScreenVector& screenVector) + { + return aznumeric_cast(AZStd::sqrt(screenVector.m_x * screenVector.m_x + screenVector.m_y * screenVector.m_y)); + } + inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize) { return ScreenPoint( - aznumeric_caster(std::round(screenNDC.GetX() * viewportSize.GetX())), - aznumeric_caster(std::round((1.0f - screenNDC.GetY()) * viewportSize.GetY()))); + aznumeric_caster(AZStd::round(screenNDC.GetX() * viewportSize.GetX())), + aznumeric_caster(AZStd::round((1.0f - screenNDC.GetY()) * viewportSize.GetY()))); } inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize) diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h index 65c62c7e64..3ffe9990df 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include @@ -27,7 +28,8 @@ namespace AZ namespace AzFramework { //! Implemented by components that provide bounds for use with various systems. - class BoundsRequests : public AZ::ComponentBus + class BoundsRequests + : public AZ::ComponentBus { public: static void Reflect(AZ::ReflectContext* context); @@ -37,6 +39,7 @@ namespace AzFramework //! more than one component may be providing a bound. It isn't guaranteed which bound //! will be returned by a single call to GetWorldBounds. virtual AZ::Aabb GetWorldBounds() = 0; + //! Returns an axis aligned bounding box in local space. //! @note It is preferred to use CalculateEntityLocalBoundsUnion in the general case as //! more than one component may be providing a bound. It isn't guaranteed which bound @@ -46,17 +49,15 @@ namespace AzFramework protected: ~BoundsRequests() = default; }; - using BoundsRequestBus = AZ::EBus; //! Returns a union of all local Aabbs provided by components implementing the BoundsRequestBus. //! @note It is preferred to call this function as opposed to GetLocalBounds directly as more than one //! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned. - inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::EntityId entityId) + inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::Entity* entity) { AZ::EBusReduceResult aabbResult(AZ::Aabb::CreateNull()); - BoundsRequestBus::EventResult( - aabbResult, entityId, &BoundsRequestBus::Events::GetLocalBounds); + BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetLocalBounds); if (aabbResult.value.IsValid()) { @@ -69,18 +70,18 @@ namespace AzFramework //! Returns a union of all world Aabbs provided by components implementing the BoundsRequestBus. //! @note It is preferred to call this function as opposed to GetWorldBounds directly as more than one //! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned. - inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::EntityId entityId) + inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::Entity* entity) { AZ::EBusReduceResult aabbResult(AZ::Aabb::CreateNull()); - BoundsRequestBus::EventResult(aabbResult, entityId, &BoundsRequestBus::Events::GetWorldBounds); + BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetWorldBounds); if (aabbResult.value.IsValid()) { return aabbResult.value; } - AZ::Vector3 worldTranslation = AZ::Vector3::CreateZero(); - AZ::TransformBus::EventResult(worldTranslation, entityId, &AZ::TransformBus::Events::GetWorldTranslation); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Vector3 worldTranslation = transformInterface->GetWorldTranslation(); return AZ::Aabb::CreateCenterHalfExtents(worldTranslation, AZ::Vector3(0.5f)); } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h index 4424cbcf60..e95e25871a 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h @@ -23,9 +23,11 @@ namespace AzFramework { //! Provides an interface to retrieve and update the union of all Aabbs on a single Entity. //! @note This will be the combination/union of all individual Component Aabbs. - class EntityBoundsUnionRequests : public AZ::EBusTraits + class IEntityBoundsUnion { public: + AZ_RTTI(IEntityBoundsUnion, "{106968DD-43C0-478E-8045-523E0BF5D0F5}"); + //! Requests the cached union of component Aabbs to be recalculated as one may have changed. //! @note This is used to drive event driven updates to the visibility system. virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0; @@ -38,9 +40,21 @@ namespace AzFramework //! also be called explicitly (e.g. For testing purposes). virtual void ProcessEntityBoundsUnionRequests() = 0; + //! Notifies the EntityBoundsUnion system that an entities transform has been modified. + //! @param entity the entity whose transform has been modified. + virtual void OnTransformUpdated(AZ::Entity* entity) = 0; + protected: - ~EntityBoundsUnionRequests() = default; + ~IEntityBoundsUnion() = default; }; - using EntityBoundsUnionRequestBus = AZ::EBus; + // EBus wrapper for ScriptCanvas + class IEntityBoundsUnionTraits + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + }; + using IEntityBoundsUnionRequestBus = AZ::EBus; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp index e9b0d4609e..c71adc5c3f 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp @@ -17,69 +17,70 @@ namespace AzFramework { - void EntityVisibilityBoundsUnionSystem::Connect() + EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem() + : m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); }) + , m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); }) { - EntityBoundsUnionRequestBus::Handler::BusConnect(); - AZ::TransformNotificationBus::Router::BusRouterConnect(); - AZ::EntitySystemBus::Handler::BusConnect(); - AZ::TickBus::Handler::BusConnect(); + ; } - void EntityVisibilityBoundsUnionSystem::Disconnect() + void EntityVisibilityBoundsUnionSystem::Connect() { - AZ::TickBus::Handler::BusDisconnect(); - AZ::EntitySystemBus::Handler::BusDisconnect(); - AZ::TransformNotificationBus::Router::BusRouterDisconnect(); - EntityBoundsUnionRequestBus::Handler::BusDisconnect(); + AZ::Interface::Register(this); + IEntityBoundsUnionRequestBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusConnect(); + + AZ::Interface::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler); + AZ::Interface::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler); } - static void SetUserDataEntityId(VisibilityEntry& visibilityEntry, const AZ::EntityId entityId) + void EntityVisibilityBoundsUnionSystem::Disconnect() { - static_assert( - sizeof(AZ::EntityId) <= sizeof(visibilityEntry.m_userData), "Ensure EntityId fits into m_userData"); - - visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity; + m_entityActivatedEventHandler.Disconnect(); + m_entityDeactivatedEventHandler.Disconnect(); - std::memcpy(&visibilityEntry.m_userData, &entityId, sizeof(AZ::EntityId)); + AZ::TickBus::Handler::BusDisconnect(); + IEntityBoundsUnionRequestBus::Handler::BusDisconnect(); + AZ::Interface::Unregister(this); } - void EntityVisibilityBoundsUnionSystem::OnEntityActivated(const AZ::EntityId& entityId) + void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); // ignore any entity that might activate which does not have a TransformComponent - if (!AZ::TransformBus::HasHandlers(entityId)) + if (entity->GetTransform() == nullptr) { return; } - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it == m_entityVisibilityBoundsUnionInstanceMapping.end()) { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Vector3 entityPosition = transformInterface->GetWorldTranslation(); EntityVisibilityBoundsUnionInstance instance; - instance.m_worldTransform = worldFromLocal; - instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId); - SetUserDataEntityId(instance.m_visibilityEntry, entityId); + instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity); + instance.m_visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity; + instance.m_visibilityEntry.m_userData = static_cast(entity); - auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({entityId, instance}); - UpdateVisibilitySystem(next_it.first->second); + auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({ entity, instance }); + UpdateVisibilitySystem(entity, next_it.first->second); } } - void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(const AZ::EntityId& entityId) + void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); // ignore any entity that might deactivate which does not have a TransformComponent - if (!AZ::TransformBus::HasHandlers(entityId)) + if (entity->GetTransform() == nullptr) { return; } - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { if (IVisibilitySystem* visibilitySystem = AZ::Interface::Get()) @@ -90,7 +91,7 @@ namespace AzFramework } } - void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance) + void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); @@ -98,8 +99,8 @@ namespace AzFramework { // note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb // there will be some wasted space but it should be sufficient for the visibility system - const AZ::Aabb worldEntityBoundsUnion = - localEntityBoundsUnions.GetTransformedAabb(instance.m_worldTransform); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Aabb worldEntityBoundsUnion = localEntityBoundsUnions.GetTransformedAabb(transformInterface->GetWorldTM()); IVisibilitySystem* visibilitySystem = AZ::Interface::Get(); if (visibilitySystem && !worldEntityBoundsUnion.IsClose(instance.m_visibilityEntry.m_boundingVolume)) { @@ -111,19 +112,27 @@ namespace AzFramework void EntityVisibilityBoundsUnionSystem::RefreshEntityLocalBoundsUnion(const AZ::EntityId entityId) { - // track entities that need their bounds union to be recalculated - m_entityIdsBoundsDirty.insert(entityId); + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (entity != nullptr) + { + // track entities that need their bounds union to be recalculated + m_entityBoundsDirty.insert(entity); + } } AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityLocalBoundsUnion(const AZ::EntityId entityId) const { - // if the EntityId is not found in the mapping then return a null Aabb, this is to mimic - // as closely as possible the behavior of an individual GetLocalBounds call to an Entity that - // had been deleted (there would be no response, leaving the default value assigned) - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); - instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (entity != nullptr) { - return instance_it->second.m_localEntityBoundsUnion; + // if the entity is not found in the mapping then return a null Aabb, this is to mimic + // as closely as possible the behavior of an individual GetLocalBounds call to an Entity that + // had been deleted (there would be no response, leaving the default value assigned) + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); + instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) + { + return instance_it->second.m_localEntityBoundsUnion; + } } return AZ::Aabb::CreateNull(); @@ -134,45 +143,29 @@ namespace AzFramework AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); // iterate over all entities whose bounds changed and recalculate them - for (const auto& entityId : m_entityIdsBoundsDirty) - { - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); - instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) - { - instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId); - } - } - - auto allDirtyEntityIds = m_entityIdsTransformDirty; - allDirtyEntityIds.insert(m_entityIdsBoundsDirty.begin(), m_entityIdsBoundsDirty.end()); - - for (const auto& dirtyEntityId : allDirtyEntityIds) + for (const auto& entity : m_entityBoundsDirty) { - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(dirtyEntityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { - UpdateVisibilitySystem(instance_it->second); + instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity); + UpdateVisibilitySystem(entity, instance_it->second); } } // clear dirty entities once the visibility system has been updated - m_entityIdsBoundsDirty.clear(); - m_entityIdsTransformDirty.clear(); + m_entityBoundsDirty.clear(); } - void EntityVisibilityBoundsUnionSystem::OnTransformChanged( - [[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) + void EntityVisibilityBoundsUnionSystem::OnTransformUpdated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); - const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId(); - m_entityIdsTransformDirty.insert(entityId); - // update the world transform of the visibility bounds union - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { - instance_it->second.m_worldTransform = world; + UpdateVisibilitySystem(entity, instance_it->second); } } diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h index 56d6ba9670..808f834ebc 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h @@ -23,12 +23,12 @@ namespace AzFramework { //! Provide a unified hook between entities and the visibility system. class EntityVisibilityBoundsUnionSystem - : public EntityBoundsUnionRequestBus::Handler - , private AZ::EntitySystemBus::Handler - , private AZ::TransformNotificationBus::Router + : public IEntityBoundsUnionRequestBus::Handler , private AZ::TickBus::Handler { public: + EntityVisibilityBoundsUnionSystem(); + void Connect(); void Disconnect(); @@ -36,34 +36,31 @@ namespace AzFramework void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override; AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override; void ProcessEntityBoundsUnionRequests() override; + void OnTransformUpdated(AZ::Entity* entity) override; private: struct EntityVisibilityBoundsUnionInstance { - AZ::Transform m_worldTransform = AZ::Transform::CreateIdentity(); //!< The world transform of the Entity. - AZ::Aabb m_localEntityBoundsUnion = - AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space. + AZ::Aabb m_localEntityBoundsUnion = AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space. VisibilityEntry m_visibilityEntry; //!< Hook into the IVisibilitySystem interface. }; - using UniqueEntityIds = AZStd::unordered_set; + using UniqueEntities = AZStd::set; using EntityVisibilityBoundsUnionInstanceMapping = - AZStd::unordered_map; + AZStd::unordered_map; + + void OnEntityActivated(AZ::Entity* entity); + void OnEntityDeactivated(AZ::Entity* entity); // TickBus overrides ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - // EntitySystemBus overrides ... - void OnEntityActivated(const AZ::EntityId& entityId) override; - void OnEntityDeactivated(const AZ::EntityId& entityId) override; - - // TransformNotificationBus overrides ... - void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; - - void UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance); + void UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance); EntityVisibilityBoundsUnionInstanceMapping m_entityVisibilityBoundsUnionInstanceMapping; - UniqueEntityIds m_entityIdsBoundsDirty; - UniqueEntityIds m_entityIdsTransformDirty; + UniqueEntities m_entityBoundsDirty; + + AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler; + AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp index fd119c8199..3d3d4bc65b 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,7 @@ namespace AzFramework octreeDebug.m_nodeBounds.push_back(nodeData.m_bounds); } + visibleEntityIdsOut.reserve(visibleEntityIdsOut.size() + nodeData.m_entries.size()); for (const auto* visibilityEntry : nodeData.m_entries) { if (ed_visibility_showDebug) @@ -88,8 +90,7 @@ namespace AzFramework octreeDebug.m_entryAabbsInFrustum.push_back(visibilityEntry->m_boundingVolume); } - AZ::EntityId entityId; - std::memcpy(&entityId, &visibilityEntry->m_userData, sizeof(AZ::EntityId)); + AZ::EntityId entityId = static_cast(visibilityEntry->m_userData)->GetId(); visibleEntityIdsOut.push_back(entityId); } }); diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/Archive/ArchiveVars_Android.h b/Code/Framework/AzFramework/Platform/Android/AzFramework/Archive/ArchiveVars_Android.h index f8ca242409..40fbe0bf30 100644 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/Archive/ArchiveVars_Android.h +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Archive/ArchiveVars_Android.h @@ -13,4 +13,3 @@ #pragma once #define STREAM_CACHE_DEFAULT 0 -#define FRONTEND_SHADER_CACHE_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Archive/ArchiveVars_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Archive/ArchiveVars_Linux.h index f8ca242409..40fbe0bf30 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Archive/ArchiveVars_Linux.h +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Archive/ArchiveVars_Linux.h @@ -13,4 +13,3 @@ #pragma once #define STREAM_CACHE_DEFAULT 0 -#define FRONTEND_SHADER_CACHE_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Archive/ArchiveVars_Mac.h b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Archive/ArchiveVars_Mac.h index f8ca242409..40fbe0bf30 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Archive/ArchiveVars_Mac.h +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Archive/ArchiveVars_Mac.h @@ -13,4 +13,3 @@ #pragma once #define STREAM_CACHE_DEFAULT 0 -#define FRONTEND_SHADER_CACHE_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Archive/ArchiveVars_Windows.h b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Archive/ArchiveVars_Windows.h index f8ca242409..40fbe0bf30 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Archive/ArchiveVars_Windows.h +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Archive/ArchiveVars_Windows.h @@ -13,4 +13,3 @@ #pragma once #define STREAM_CACHE_DEFAULT 0 -#define FRONTEND_SHADER_CACHE_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Archive/ArchiveVars_iOS.h b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Archive/ArchiveVars_iOS.h index f8ca242409..40fbe0bf30 100644 --- a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Archive/ArchiveVars_iOS.h +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Archive/ArchiveVars_iOS.h @@ -13,4 +13,3 @@ #pragma once #define STREAM_CACHE_DEFAULT 0 -#define FRONTEND_SHADER_CACHE_DEFAULT 0 diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp index 80096365a4..c7f47cbc04 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp @@ -19,9 +19,10 @@ namespace AzNetworking static const int32_t FloatHashMinValue = (INT_MIN >> 7); static const int32_t FloatHashMaxValue = (INT_MAX >> 7); - AZ::HashValue64 HashSerializer::GetHash() const + AZ::HashValue32 HashSerializer::GetHash() const { - return m_hash; + // Just truncate the upper bits + return static_cast(m_hash); } SerializerMode HashSerializer::GetSerializerMode() const diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h index b4bc991746..2f86d1aafe 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h @@ -27,7 +27,7 @@ namespace AzNetworking HashSerializer() = default; - AZ::HashValue64 GetHash() const; + AZ::HashValue32 GetHash() const; // ISerializer interfaces SerializerMode GetSerializerMode() const override; diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp new file mode 100644 index 0000000000..bcd09f274c --- /dev/null +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp @@ -0,0 +1,162 @@ +/* +* 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 + +namespace AzNetworking +{ + StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator) + : m_delimeter(delimeter) + , m_outputFieldNames(outputFieldNames) + , m_separator(seperator) + { + ; + } + + const AZStd::string& StringifySerializer::GetString() const + { + return m_string; + } + + const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const + { + return m_map; + } + + SerializerMode StringifySerializer::GetSerializerMode() const + { + return SerializerMode::ReadFromObject; + } + + bool StringifySerializer::Serialize(bool& value, const char* name) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(char& value, const char* name, char, char) + { + const int val = value; // Print chars as integers + return ProcessData(name, val); + } + + bool StringifySerializer::Serialize(int8_t& value, const char* name, int8_t, int8_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int16_t& value, const char* name, int16_t, int16_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int32_t& value, const char* name, int32_t, int32_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int64_t& value, const char* name, int64_t, int64_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint8_t& value, const char* name, uint8_t, uint8_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint16_t& value, const char* name, uint16_t, uint16_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint32_t& value, const char* name, uint32_t, uint32_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint64_t& value, const char* name, uint64_t, uint64_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(float& value, const char* name, float, float) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(double& value, const char* name, double, double) + { + return ProcessData(name, value); + } + + bool StringifySerializer::SerializeBytes(uint8_t* buffer, uint32_t, bool isString, uint32_t&, const char* name) + { + if (isString) + { + AZ::CVarFixedString value = reinterpret_cast(buffer); + return ProcessData(name, value); + } + return false; + } + + bool StringifySerializer::BeginObject(const char* name, const char*) + { + m_prefixSizeStack.push_back(m_prefix.size()); + m_prefix += name; + m_prefix += "."; + return true; + } + + bool StringifySerializer::EndObject(const char*, const char*) + { + m_prefix.resize(m_prefixSizeStack.back()); + m_prefixSizeStack.pop_back(); + return true; + } + + const uint8_t* StringifySerializer::GetBuffer() const + { + return nullptr; + } + + uint32_t StringifySerializer::GetCapacity() const + { + return 0; + } + + uint32_t StringifySerializer::GetSize() const + { + return 0; + } + + template + bool StringifySerializer::ProcessData(const char* name, const T& value) + { + // Only add delimeters after we have processed at least one element + if (!m_string.empty()) + { + m_string += m_delimeter; + } + + if (m_outputFieldNames) + { + m_string += m_prefix; + m_string += name; + m_string += m_separator; + } + + AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value); + m_string += string.c_str(); + m_map[m_prefix + name] = string.c_str(); + return true; + } +} diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h new file mode 100644 index 0000000000..aa8c58ae60 --- /dev/null +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h @@ -0,0 +1,80 @@ +/* +* 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 +#include + +namespace AzNetworking +{ + // StringifySerializer + // Generate a debug string of a serializable object + class StringifySerializer + : public ISerializer + { + public: + + using StringMap = AZStd::map; + + StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "="); + + // GetString + // After serializing objects, get the serialized values as a single string + const AZStd::string& GetString() const; + + // GetValueMap + // After serializing objects, get the serialized values as key value pairs + const StringMap& GetValueMap() const; + + // ISerializer interfaces + SerializerMode GetSerializerMode() const override; + bool Serialize(bool& value, const char* name) override; + bool Serialize(char& value, const char* name, char minValue, char maxValue) override; + bool Serialize(int8_t& value, const char* name, int8_t minValue, int8_t maxValue) override; + bool Serialize(int16_t& value, const char* name, int16_t minValue, int16_t maxValue) override; + bool Serialize(int32_t& value, const char* name, int32_t minValue, int32_t maxValue) override; + bool Serialize(int64_t& value, const char* name, int64_t minValue, int64_t maxValue) override; + bool Serialize(uint8_t& value, const char* name, uint8_t minValue, uint8_t maxValue) override; + bool Serialize(uint16_t& value, const char* name, uint16_t minValue, uint16_t maxValue) override; + bool Serialize(uint32_t& value, const char* name, uint32_t minValue, uint32_t maxValue) override; + bool Serialize(uint64_t& value, const char* name, uint64_t minValue, uint64_t maxValue) override; + bool Serialize(float& value, const char* name, float minValue, float maxValue) override; + bool Serialize(double& value, const char* name, double minValue, double maxValue) override; + bool SerializeBytes(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name) override; + bool BeginObject(const char* name, const char* typeName) override; + bool EndObject(const char* name, const char* typeName) override; + + const uint8_t* GetBuffer() const override; + uint32_t GetCapacity() const override; + uint32_t GetSize() const override; + void ClearTrackedChangesFlag() override {} + bool GetTrackedChangesFlag() const override { return false; } + // ISerializer interfaces + + private: + + template + bool ProcessData(const char* name, const T& value); + + private: + + char m_delimeter; + bool m_outputFieldNames = true; + + StringMap m_map; + AZStd::string m_string; + AZStd::string m_prefix; + AZStd::string m_separator; + AZStd::deque m_prefixSizeStack; + }; +} diff --git a/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake b/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake index ea84f3fdc9..b8d488a1e4 100644 --- a/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake +++ b/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake @@ -65,6 +65,8 @@ set(FILES Serialization/NetworkOutputSerializer.cpp Serialization/NetworkOutputSerializer.h Serialization/NetworkOutputSerializer.inl + Serialization/StringifySerializer.cpp + Serialization/StringifySerializer.h Serialization/TrackChangedSerializer.h Serialization/TrackChangedSerializer.inl TcpTransport/TcpConnection.cpp diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp index 2cfe2a7abf..5ba223dec4 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp @@ -180,6 +180,8 @@ namespace AzQtComponents textSearch->setFrame(false); textSearch->setText(QString()); textSearch->setPlaceholderText(QObject::tr("Search...")); + textSearch->setClearButtonEnabled(true); + LineEdit::applySearchStyle(textSearch); connect(textSearch, &QLineEdit::textChanged, this, &SearchTypeSelector::FilterTextChanged); m_searchLayout->addWidget(textSearch); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index 83e40474d6..82fa3f94f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -761,16 +761,6 @@ namespace AzToolsFramework /// If the view pane was not registered with the ViewPaneOptions.isDeletable set to true, the view pane will be hidden instead. virtual void CloseViewPane(const char* /*paneName*/) {} - /// Request generation of all level cubemaps. - virtual void GenerateAllCubemaps() {} - - /// Regenerate cubemap for a particular entity. - /// \param entityId ID of the entity that the cubemap is for - /// \param cubemapOutputPath path to a image file to generate - /// \param hideEntity Indicates whether the entity should be hidden during cubemap generation. Controls whether the entity's current cubemap output is baked into the new cubemap. - virtual void GenerateCubemapForEntity(AZ::EntityId /*entityId*/, AZStd::string* /*cubemapOutputPath*/, bool /*hideEntity*/) {} - virtual void GenerateCubemapWithIDForEntity(AZ::EntityId /*entityId*/, AZ::Uuid /*cubemapId*/, AZStd::string* /*cubemapOutputPath*/, bool /*hideEntity*/, bool /*hasCubemapId*/) {} - //! Spawn asset browser for the appropriate asset types. virtual void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp index 44c8487272..041a0f4195 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp @@ -189,9 +189,6 @@ namespace AzToolsFramework SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect(); EditorLegacyGameModeNotificationBus::Handler::BusConnect(); - - m_entityVisibilityBoundsUnionSystem.Connect(); - } //========================================================================= @@ -199,8 +196,6 @@ namespace AzToolsFramework //========================================================================= void EditorEntityContextComponent::Deactivate() { - m_entityVisibilityBoundsUnionSystem.Disconnect(); - EditorLegacyGameModeNotificationBus::Handler::BusDisconnect(); SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h index 2313f27437..92c7f84703 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h @@ -189,8 +189,6 @@ namespace AzToolsFramework //! EditorEntityContextRequestBus::Events::AddRequiredComponents() AZ::ComponentTypeList m_requiredEditorComponentTypes; - //! Edit time visibility management integrating entities with the IVisibilitySystem. - AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; bool m_isLegacySliceService; UndoSystem::UndoCacheInterface* m_undoCacheInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp index 6fbd467f04..9a4a952d8f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp @@ -85,14 +85,14 @@ namespace AzToolsFramework // if we're snapping, only increment current radians when we know // preSnapRadians is greater than the angleStep - if (snapping) + if (snapping && AZStd::abs(angleStepDegrees) > 0.0f) { actionInternal.m_current.m_preSnapRadians += rotationAngleRad * rotateSign; const float angleStepRad = AZ::DegToRad(angleStepDegrees); const float preSnapRotateSign = Sign(actionInternal.m_current.m_preSnapRadians); // if we move more than angleStep in a frame, make sure we catch up - while (fabsf(actionInternal.m_current.m_preSnapRadians) >= angleStepRad) + while (AZStd::abs(actionInternal.m_current.m_preSnapRadians) >= angleStepRad) { actionInternal.m_current.m_radians += angleStepRad * preSnapRotateSign; actionInternal.m_current.m_preSnapRadians -= angleStepRad * preSnapRotateSign; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index d4485f8e99..14537683ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -89,7 +89,7 @@ namespace AzToolsFramework if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances)) { return AZ::Failure( - AZStd::string("Could not create a new prefab out of the entities provided - entities do not share a common root.")); + AZStd::string("Could not create a new prefab out of the entities provided - invalid selection.")); } // When we create a prefab with other prefab instances, we have to remove the existing links between the source and @@ -140,9 +140,13 @@ namespace AzToolsFramework // Mark them as dirty so this change is correctly applied to the template for (AZ::Entity* topLevelEntity : topLevelEntities) { - m_prefabUndoCache.UpdateCache(topLevelEntity->GetId()); - undoBatch.MarkEntityDirty(topLevelEntity->GetId()); - AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId); + AZ::EntityId topLevelEntityId = topLevelEntity->GetId(); + if (topLevelEntityId.IsValid()) + { + m_prefabUndoCache.UpdateCache(topLevelEntityId); + undoBatch.MarkEntityDirty(topLevelEntityId); + AZ::TransformBus::Event(topLevelEntityId, &AZ::TransformBus::Events::SetParent, containerEntityId); + } } // Select Container Entity @@ -237,6 +241,21 @@ namespace AzToolsFramework // Retrieve entityList from entityIds inputEntityList = EntityIdListToEntityList(entityIds); + // Remove Level Container Entity if it's part of the list + AZ::EntityId levelEntityId = GetLevelInstanceContainerEntityId(); + if (levelEntityId.IsValid()) + { + AZ::Entity* levelEntity = GetEntityById(levelEntityId); + if (levelEntity) + { + auto levelEntityIter = AZStd::find(inputEntityList.begin(), inputEntityList.end(), levelEntity); + if (levelEntityIter != inputEntityList.end()) + { + inputEntityList.erase(levelEntityIter); + } + } + } + // Find common root and top level entities bool entitiesHaveCommonRoot = false; @@ -807,6 +826,11 @@ namespace AzToolsFramework const EntityList& inputEntities, Instance& commonRootEntityOwningInstance, EntityList& outEntities, AZStd::vector>& outInstances) const { + if (inputEntities.size() == 0) + { + return false; + } + AZStd::queue entityQueue; for (auto inputEntity : inputEntities) @@ -894,7 +918,7 @@ namespace AzToolsFramework outInstances.push_back(AZStd::move(commonRootEntityOwningInstance.DetachNestedInstance(instancePtr->GetInstanceAlias()))); } - return true; + return (outEntities.size() + outInstances.size()) > 0; } bool PrefabPublicHandler::EntitiesBelongToSameInstance(const EntityIdList& entityIds) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceUtilities.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceUtilities.cpp index 75070d9b41..4b73166b3d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceUtilities.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceUtilities.cpp @@ -1353,7 +1353,7 @@ namespace AzToolsFramework // Iterate over the entities left in the instance and if none of them have this // asset entity as its ancestor, then we want to remove it. // \todo - Investigate ways to make this non-linear time. Tricky since removed entities - // obviously aren't maintained in any maps. (https://jira.agscollab.com/browse/LY-88218) + // obviously aren't maintained in any maps. (LY-88218) bool foundAsAncestor = false; for (const AZ::Entity* instanceEntity : instanceEntities) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index f8d02b6581..ac5f1136f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -265,6 +266,13 @@ namespace AzToolsFramework AZ::TransformNotificationBus::Event( GetEntityId(), &TransformNotification::OnTransformChanged, localTM, worldTM); + m_transformChangedEvent.Signal(localTM, worldTM); + + AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface::Get(); + if (boundsUnion != nullptr) + { + boundsUnion->OnTransformUpdated(GetEntity()); + } } } @@ -933,15 +941,14 @@ namespace AzToolsFramework { return nullptr; } - - AZ::Entity* pEntity = nullptr; - EBUS_EVENT_RESULT(pEntity, AZ::ComponentApplicationBus, FindEntity, otherEntityId); - if (!pEntity) + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(otherEntityId); + if (!entity) { return nullptr; } - return pEntity->FindComponent(); + return entity->FindComponent(); } AZ::TransformInterface* TransformComponent::GetParent() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 6ce3fdc755..7f28080e9e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -151,32 +151,36 @@ namespace AzToolsFramework { if (!selectedEntities.empty()) { - bool layerInSelection = false; - - for (AZ::EntityId entityId : selectedEntities) + // Hide if the only selected entity is the Level Container + if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0])) { - if (!layerInSelection) - { - AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult( - layerInSelection, entityId, - &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); + bool layerInSelection = false; - if (layerInSelection) + for (AZ::EntityId entityId : selectedEntities) + { + if (!layerInSelection) { - break; + AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult( + layerInSelection, entityId, + &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); + + if (layerInSelection) + { + break; + } } } - } - // Layers can't be in prefabs. - if (!layerInSelection) - { - QAction* createAction = menu->addAction(QObject::tr("Create Prefab...")); - createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities.")); + // Layers can't be in prefabs. + if (!layerInSelection) + { + QAction* createAction = menu->addAction(QObject::tr("Create Prefab...")); + createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities.")); - QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] { - ContextMenu_CreatePrefab(selectedEntities); - }); + QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] { + ContextMenu_CreatePrefab(selectedEntities); + }); + } } } } @@ -272,6 +276,15 @@ namespace AzToolsFramework QWidget* activeWindow = QApplication::activeWindow(); const AZStd::string prefabFilesPath = "@devassets@/Prefabs"; + // Remove Level entity if it's part of the list + + auto levelContainerIter = + AZStd::find(selectedEntities.begin(), selectedEntities.end(), s_prefabPublicInterface->GetLevelInstanceContainerEntityId()); + if (levelContainerIter != selectedEntities.end()) + { + selectedEntities.erase(levelContainerIter); + } + // Set default folder for prefabs AZ::IO::FileIOBase* fileIoBaseInstance = AZ::IO::FileIOBase::GetInstance(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index bfb2ff4256..d0f3fa452a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -335,6 +335,7 @@ namespace AzToolsFramework m_gui->m_entityDetailsLabel->setObjectName("LabelEntityDetails"); m_gui->m_entitySearchBox->setReadOnly(false); m_gui->m_entitySearchBox->setContextMenuPolicy(Qt::CustomContextMenu); + m_gui->m_entitySearchBox->setClearButtonEnabled(true); AzQtComponents::LineEdit::applySearchStyle(m_gui->m_entitySearchBox); AzFramework::ApplicationRequests::Bus::BroadcastResult( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 68a5b43d73..d649e036ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -68,6 +68,7 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); AzFramework::EntityDebugDisplayEventBus::Event( entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, viewportInfo, debugDisplay); @@ -84,10 +85,9 @@ namespace AzToolsFramework if (ed_visibility_showAggregateEntityTransformedLocalBounds) { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::Transform worldFromLocal = entity->GetTransform()->GetWorldTM(); - if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entityId); localAabb.IsValid()) + if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entity); localAabb.IsValid()) { const AZ::Aabb worldAabb = localAabb.GetTransformedAabb(worldFromLocal); debugDisplay.SetColor(AZ::Colors::Turquoise); @@ -97,7 +97,7 @@ namespace AzToolsFramework if (ed_visibility_showAggregateEntityWorldBounds) { - if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entityId); worldAabb.IsValid()) + if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entity); worldAabb.IsValid()) { debugDisplay.SetColor(AZ::Colors::Magenta); debugDisplay.DrawWireBox(worldAabb.GetMin(), worldAabb.GetMax()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp index 3be4bc9db2..88b92e8c41 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp @@ -13,7 +13,9 @@ #include "EditorSelectionUtil.h" #include +#include #include +#include #include #include #include @@ -28,7 +30,8 @@ namespace AzToolsFramework { if (Centered(pivot)) { - if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entityId); + const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entity); localBound.IsValid()) { return localBound.GetCenter(); diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp index 8b3a564c4d..8f4133de63 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp @@ -211,6 +211,15 @@ namespace UnitTest EXPECT_EQ(screenPoint, ScreenPoint(45, 170)); } + TEST(ViewportScreen, ScreenVectorLengthReturned) + { + using AzFramework::ScreenVector; + + EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(1, 1)), 1.41421f, 0.001f); + EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(3, 4)), 5.0f, 0.001f); + EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(12, 15)), 19.20937f, 0.001f); + } + TEST(ViewportScreen, CanGetCameraTransformFromCameraViewAndBack) { const auto screenDimensions = AZ::Vector2(1024.0f, 768.0f); diff --git a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp index 0b059594be..a7aeee5660 100644 --- a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp @@ -62,8 +62,8 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative y-axis moved just back from the origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -101,8 +101,8 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative x-axis moved along the x-axis and tilted slightly down AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -143,15 +143,15 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); const AZ::EntityId entityIdToMove = m_editorEntityIds[10]; AZ::TransformBus::Event( entityIdToMove, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3::CreateAxisZ(100.0f)); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative y-axis moved just back from the origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -241,8 +241,8 @@ namespace UnitTest { m_localAabb = localAabb; - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); } TEST_F(EditorVisibilityFixture, UpdatedBoundsIntersectingFrustumAddsVisibleEntity) @@ -264,8 +264,8 @@ namespace UnitTest entityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(40.0f, -3.0f, 20.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the positive x-axis moved to position offset from world origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -288,8 +288,8 @@ namespace UnitTest testBoundComponent->ChangeBounds(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-2.5f), AZ::Vector3(2.5f))); // perform an 'update' of the visibility system - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); entityVisibilityQuery.UpdateVisibility(cameraState); diff --git a/Code/Framework/Tests/ComponentAddRemove.cpp b/Code/Framework/Tests/ComponentAddRemove.cpp index e47b69c977..4fd6db7dde 100644 --- a/Code/Framework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/Tests/ComponentAddRemove.cpp @@ -1100,6 +1100,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const ComponentDescriptor*) override {} void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override {} void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {} + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {} + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {} + void SignalEntityActivated(Entity*) override {} + void SignalEntityDeactivated(Entity*) override {} bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const EntityId&) override { return true; } @@ -1125,6 +1129,7 @@ namespace UnitTest AllocatorsFixture::SetUp(); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); m_serializeContext.reset(aznew AZ::SerializeContext(true, true)); Entity::Reflect(m_serializeContext.get()); @@ -1139,6 +1144,7 @@ namespace UnitTest m_descriptors.set_capacity(0); m_serializeContext.reset(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); AllocatorsFixture::TearDown(); diff --git a/Code/Framework/Tests/NetBindingMocks.h b/Code/Framework/Tests/NetBindingMocks.h index a07cae0077..3973fe670d 100644 --- a/Code/Framework/Tests/NetBindingMocks.h +++ b/Code/Framework/Tests/NetBindingMocks.h @@ -279,6 +279,10 @@ namespace UnitTest MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&)); diff --git a/Code/Sandbox/Editor/2DViewport.cpp b/Code/Sandbox/Editor/2DViewport.cpp index 0487c9381f..9eab4df16d 100644 --- a/Code/Sandbox/Editor/2DViewport.cpp +++ b/Code/Sandbox/Editor/2DViewport.cpp @@ -86,7 +86,6 @@ inline Vec3 SnapToSize(Vec3 v, double size) ////////////////////////////////////////////////////////////////////// Q2DViewport::Q2DViewport(QWidget* parent) : QtViewport(parent) - , m_renderer(nullptr) { // Scroll offset equals origin m_rcSelect.setRect(0, 0, 0, 0); @@ -528,15 +527,6 @@ void Q2DViewport::paintEvent([[maybe_unused]] QPaintEvent* event) ////////////////////////////////////////////////////////////////////////// int Q2DViewport::OnCreate() { - m_renderer = GetIEditor()->GetRenderer(); - assert (m_renderer != NULL); - if (m_renderer) - { - WIN_HWND previousContext = m_renderer->GetCurrentContextHWND(); - m_renderer->CreateContext(renderOverlayHWND()); - m_renderer->SetCurrentContext(previousContext); - } - // Calculate the View transformation matrix. CalculateViewTM(); @@ -641,10 +631,6 @@ void Q2DViewport::OnTitleMenu(QMenu* menu) ////////////////////////////////////////////////////////////////////////// void Q2DViewport::OnDestroy() { - if (m_renderer) - { - m_renderer->DeleteContext(renderOverlayHWND()); - } } ////////////////////////////////////////////////////////////////////////// @@ -674,9 +660,7 @@ void Q2DViewport::Draw(DisplayContext& dc) ////////////////////////////////////////////////////////////////////////// void Q2DViewport::DrawGrid(DisplayContext& dc, bool bNoXNumbers) { - CGrid* pGrid = GetIEditor()->GetViewManager()->GetGrid(); - float gridSize = pGrid->size; - + float gridSize = 1.0f; if (gridSize < 0.00001f) { return; @@ -707,8 +691,6 @@ void Q2DViewport::DrawGrid(DisplayContext& dc, bool bNoXNumbers) pixelsPerGrid = gridSize * fScale; while (pixelsPerGrid <= 5 && griditers++ < 20) { - m_fGridZoom *= pGrid->majorLine; - gridSize = gridSize * pGrid->majorLine; pixelsPerGrid = gridSize * fScale; } } @@ -757,7 +739,7 @@ void Q2DViewport::DrawGrid(DisplayContext& dc, bool bNoXNumbers) ////////////////////////////////////////////////////////////////////////// // Draw Major grid lines. ////////////////////////////////////////////////////////////////////////// - gridSize = gridSize * pGrid->majorLine; + gridSize = gridSize * 1.0f; if (m_bAutoAdjustGrids) { diff --git a/Code/Sandbox/Editor/2DViewport.h b/Code/Sandbox/Editor/2DViewport.h index 818f01064c..d7e6ee17f4 100644 --- a/Code/Sandbox/Editor/2DViewport.h +++ b/Code/Sandbox/Editor/2DViewport.h @@ -159,7 +159,6 @@ protected: ////////////////////////////////////////////////////////////////////////// // Variables. ////////////////////////////////////////////////////////////////////////// - IRenderer* m_renderer; //! XY/XZ/YZ mode of this 2D viewport. EViewportType m_viewType; diff --git a/Code/Sandbox/Editor/ActionManager.h b/Code/Sandbox/Editor/ActionManager.h index d536fd4121..3f599ecf82 100644 --- a/Code/Sandbox/Editor/ActionManager.h +++ b/Code/Sandbox/Editor/ActionManager.h @@ -169,6 +169,13 @@ public: return *this; } + template + ActionWrapper& RegisterUpdateCallback(Fn&& fn) + { + m_actionManager->RegisterUpdateCallback(m_action->data().toInt(), AZStd::forward(fn)); + return *this; + } + private: friend ActionManager; friend DynamicMenu; @@ -315,11 +322,17 @@ public: void DetachOverride() override; template - void RegisterUpdateCallback(int id, T* object, void (T::* method)(QAction*)) + void RegisterUpdateCallback(int id, T* object, void (T::*method)(QAction*)) + { + Q_ASSERT(m_actions.contains(id)); + m_updateCallbacks[id] = [action = m_actions.value(id), object, method] { AZStd::invoke(method, object, action); }; + } + + template + void RegisterUpdateCallback(int id, Fn&& fn) { Q_ASSERT(m_actions.contains(id)); - auto f = std::bind(method, object, m_actions.value(id)); - m_updateCallbacks[id] = f; + m_updateCallbacks[id] = [action = m_actions.value(id), fn] { fn(action); }; } template diff --git a/Code/Sandbox/Editor/Controls/ConsoleSCB.cpp b/Code/Sandbox/Editor/Controls/ConsoleSCB.cpp index 590f7941c4..f6616197aa 100644 --- a/Code/Sandbox/Editor/Controls/ConsoleSCB.cpp +++ b/Code/Sandbox/Editor/Controls/ConsoleSCB.cpp @@ -26,6 +26,7 @@ // AzQtComponents #include #include +#include #include #include @@ -314,7 +315,10 @@ CConsoleSCB::CConsoleSCB(QWidget* parent) setMinimumHeight(120); ui->findBar->setVisible(false); - + ui->lineEditFind->setPlaceholderText(QObject::tr("Search...")); + ui->lineEditFind->setClearButtonEnabled(true); + AzQtComponents::LineEdit::applySearchStyle(ui->lineEditFind); + // Setup the color table for the default (light) theme m_colorTable << QColor(0, 0, 0) << QColor(0, 0, 0) diff --git a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp index f0367ffdc1..3f7a3142e9 100644 --- a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp +++ b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp @@ -28,7 +28,6 @@ void RegisterReflectedVarHandlers() registered = true; EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AnimationPropertyWidgetHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FileResourceSelectorWidgetHandler()); - EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ShaderPropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ReverbPresetPropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequencePropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequenceIdPropertyHandler()); diff --git a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp index 75344b2172..5fde2c39a5 100644 --- a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp +++ b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp @@ -26,7 +26,6 @@ #include // Editor -#include "ShadersDialog.h" #include "SelectLightAnimationDialog.h" #include "SelectSequenceDialog.h" #include "SelectEAXPresetDlg.h" @@ -78,16 +77,6 @@ void GenericPopupPropertyEditor::SetPropertyType(PropertyType type) m_propertyType = type; } -void ShaderPropertyEditor::onEditClicked() -{ - CShadersDialog cShaders(GetValue()); - if (cShaders.exec() == QDialog::Accepted) - { - SetValue(cShaders.GetSelection()); - } - -} - void ReverbPresetPropertyEditor::onEditClicked() { CSelectEAXPresetDlg PresetDlg(this); diff --git a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h index cdbb18ae12..f0d5ed4db7 100644 --- a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h +++ b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h @@ -100,15 +100,6 @@ public: } }; -class ShaderPropertyEditor - : public GenericPopupPropertyEditor -{ -public: - ShaderPropertyEditor(QWidget* pParent = nullptr) - : GenericPopupPropertyEditor(pParent){} - void onEditClicked() override; -}; - class ReverbPresetPropertyEditor : public GenericPopupPropertyEditor { @@ -168,7 +159,6 @@ public: // So we use our own #define CONST_AZ_CRC(name, value) AZ::u32(value) -using ShaderPropertyHandler = GenericPopupWidgetHandler; using ReverbPresetPropertyHandler = GenericPopupWidgetHandler; using MissionObjPropertyHandler = GenericPopupWidgetHandler; using SequencePropertyHandler = GenericPopupWidgetHandler; diff --git a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp index 13584d9b82..4ac5733401 100644 --- a/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp +++ b/Code/Sandbox/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp @@ -268,7 +268,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var) case ePropertyUser: m_reflectedVarAdapter = new ReflectedVarUserAdapter; break; - case ePropertyShader: case ePropertyEquip: case ePropertyReverbPreset: case ePropertyGameToken: diff --git a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp index 869fa2fe25..0ce3fa55f5 100644 --- a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp @@ -514,7 +514,7 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe /* * The following block of code is part of the feature "Isolation Mode" and is temporarily * disabled for 1.10 release. - * Jira: https://jira.agscollab.com/browse/LY-49532 + * Jira: LY-49532 // Isolate Selected QAction* isolateSelectedAction = editMenu->addAction(tr("Isolate Selected")); @@ -729,9 +729,6 @@ QMenu* LevelEditorMenuHandler::CreateViewMenu() viewportViewsMenuWrapper.AddAction(ID_WIREFRAME); viewportViewsMenuWrapper.AddSeparator(); - viewportViewsMenuWrapper.AddAction(ID_VIEW_GRIDSETTINGS); - viewportViewsMenuWrapper.AddSeparator(); - if (CViewManager::IsMultiViewportEnabled()) { viewportViewsMenuWrapper.AddAction(ID_VIEW_CONFIGURELAYOUT); diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index b88aee8bd9..6e33d32c6e 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -95,7 +95,6 @@ AZ_POP_DISABLE_WARNING #include "Core/QtEditorApplication.h" #include "StringDlg.h" #include "NewLevelDialog.h" -#include "GridSettingsDialog.h" #include "LayoutConfigDialog.h" #include "ViewManager.h" #include "FileTypeUtils.h" @@ -132,7 +131,6 @@ AZ_POP_DISABLE_WARNING #include "Util/AutoDirectoryRestoreFileDialog.h" #include "Util/EditorAutoLevelLoadTest.h" -#include "Util/Ruler.h" #include "Util/IndexedFiles.h" #include "AboutDialog.h" #include @@ -390,7 +388,6 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_PREFERENCES, OnPreferences) ON_COMMAND(ID_REDO, OnRedo) ON_COMMAND(ID_TOOLBAR_WIDGET_REDO, OnRedo) - ON_COMMAND(ID_RELOAD_TEXTURES, OnReloadTextures) ON_COMMAND(ID_FILE_OPEN_LEVEL, OnOpenLevel) #ifdef ENABLE_SLICE_EDITOR ON_COMMAND(ID_FILE_NEW_SLICE, OnCreateSlice) @@ -400,11 +397,8 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_GAME_SYNCPLAYER, OnSyncPlayer) ON_COMMAND(ID_RESOURCES_REDUCEWORKINGSET, OnResourcesReduceworkingset) - ON_COMMAND(ID_SNAP_TO_GRID, OnSnap) - ON_COMMAND(ID_WIREFRAME, OnWireframe) - ON_COMMAND(ID_VIEW_GRIDSETTINGS, OnViewGridsettings) ON_COMMAND(ID_VIEW_CONFIGURELAYOUT, OnViewConfigureLayout) ON_COMMAND(IDC_SELECTION, OnDummyCommand) @@ -444,7 +438,6 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_VIEW_CYCLE2DVIEWPORT, OnViewCycle2dviewport) #endif ON_COMMAND(ID_DISPLAY_GOTOPOSITION, OnDisplayGotoPosition) - ON_COMMAND(ID_SNAPANGLE, OnSnapangle) ON_COMMAND(ID_CHANGEMOVESPEED_INCREASE, OnChangemovespeedIncrease) ON_COMMAND(ID_CHANGEMOVESPEED_DECREASE, OnChangemovespeedDecrease) ON_COMMAND(ID_CHANGEMOVESPEED_CHANGESTEP, OnChangemovespeedChangestep) @@ -527,12 +520,6 @@ public: bool m_bExportTexture = false; bool m_bMatEditMode = false; - bool m_bPrecacheShaders = false; - bool m_bPrecacheShadersLevels = false; - bool m_bPrecacheShaderList = false; - bool m_bStatsShaders = false; - bool m_bStatsShaderList = false; - bool m_bMergeShaders = false; bool m_bConsoleMode = false; bool m_bNullRenderer = false; @@ -574,12 +561,6 @@ public: { "exportTexture", m_bExportTexture }, { "test", m_bTest }, { "auto_level_load", m_bAutoLoadLevel }, - { "PrecacheShaders", m_bPrecacheShaders }, - { "PrecacheShadersLevels", m_bPrecacheShadersLevels }, - { "PrecacheShaderList", m_bPrecacheShaderList }, - { "StatsShaders", m_bStatsShaders }, - { "StatsShaderList", m_bStatsShaderList }, - { "MergeShaders", m_bMergeShaders }, { "MatEdit", m_bMatEditMode }, { "BatchMode", m_bConsoleMode }, { "NullRenderer", m_bNullRenderer }, @@ -1024,26 +1005,12 @@ void CCryEditApp::OutputStartupMessage(QString str) ////////////////////////////////////////////////////////////////////////// void CCryEditApp::InitFromCommandLine(CEditCommandLineInfo& cmdInfo) { - //! Setup flags from command line - if (cmdInfo.m_bPrecacheShaders || cmdInfo.m_bPrecacheShadersLevels || cmdInfo.m_bMergeShaders - || cmdInfo.m_bPrecacheShaderList || cmdInfo.m_bStatsShaderList || cmdInfo.m_bStatsShaders) - { - m_bPreviewMode = true; - m_bConsoleMode = true; - m_bTestMode = true; - } m_bConsoleMode |= cmdInfo.m_bConsoleMode; inEditorBatchMode = AZ::Environment::CreateVariable("InEditorBatchMode", m_bConsoleMode); m_bTestMode |= cmdInfo.m_bTest; m_bSkipWelcomeScreenDialog = cmdInfo.m_bSkipWelcomeScreenDialog || !cmdInfo.m_execFile.isEmpty() || !cmdInfo.m_execLineCmd.isEmpty() || cmdInfo.m_bAutotestMode; - m_bPrecacheShaderList = cmdInfo.m_bPrecacheShaderList; - m_bStatsShaderList = cmdInfo.m_bStatsShaderList; - m_bStatsShaders = cmdInfo.m_bStatsShaders; - m_bPrecacheShaders = cmdInfo.m_bPrecacheShaders; - m_bPrecacheShadersLevels = cmdInfo.m_bPrecacheShadersLevels; - m_bMergeShaders = cmdInfo.m_bMergeShaders; m_bExportMode = cmdInfo.m_bExport; m_bRunPythonTestScript = cmdInfo.m_bRunPythonTestScript; m_bRunPythonScript = cmdInfo.m_bRunPythonScript || cmdInfo.m_bRunPythonTestScript; @@ -1079,11 +1046,9 @@ void CCryEditApp::InitFromCommandLine(CEditCommandLineInfo& cmdInfo) ///////////////////////////////////////////////////////////////////////////// AZ::Outcome CCryEditApp::InitGameSystem(HWND hwndForInputSystem) { - bool bShaderCacheGen = m_bPrecacheShaderList | m_bPrecacheShaders | m_bPrecacheShadersLevels; - CGameEngine* pGameEngine = new CGameEngine; - AZ::Outcome initOutcome = pGameEngine->Init(m_bPreviewMode, m_bTestMode, bShaderCacheGen, qApp->arguments().join(" ").toUtf8().data(), g_pInitializeUIInfo, hwndForInputSystem); + AZ::Outcome initOutcome = pGameEngine->Init(m_bPreviewMode, m_bTestMode, qApp->arguments().join(" ").toUtf8().data(), g_pInitializeUIInfo, hwndForInputSystem); if (!initOutcome.IsSuccess()) { return initOutcome; @@ -1124,8 +1089,7 @@ BOOL CCryEditApp::CheckIfAlreadyRunning() } } - // Shader pre-caching may start multiple editor copies - if (!FirstInstance(bForceNewInstance) && !m_bPrecacheShaderList) + if (!FirstInstance(bForceNewInstance)) { return false; } @@ -1347,37 +1311,6 @@ void CCryEditApp::InitLevel(const CEditCommandLineInfo& cmdInfo) ///////////////////////////////////////////////////////////////////////////// BOOL CCryEditApp::InitConsole() { - if (m_bPrecacheShaderList) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_PrecacheShaderList"); - return false; - } - else if (m_bStatsShaderList) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_StatsShaderList"); - return false; - } - else if (m_bStatsShaders) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_StatsShaders"); - return false; - } - else if (m_bPrecacheShaders) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_PrecacheShaders"); - return false; - } - else if (m_bPrecacheShadersLevels) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_PrecacheShadersLevels"); - return false; - } - else if (m_bMergeShaders) - { - GetIEditor()->GetSystem()->GetIConsole()->ExecuteString("r_MergeShaders"); - return false; - } - // Execute command from cmdline -exec_line if applicable if (!m_execLineCmd.isEmpty()) { @@ -2930,14 +2863,6 @@ void CCryEditApp::OnPreferences() */ } -void CCryEditApp::OnReloadTextures() -{ - QWaitCursor wait; - CLogFile::WriteLine("Reloading Static objects textures and shaders."); - GetIEditor()->GetObjectManager()->SendEvent(EVENT_RELOAD_TEXTURES); - GetIEditor()->GetRenderer()->EF_ReloadTextures(); -} - ////////////////////////////////////////////////////////////////////////// void CCryEditApp::OnUndo() { @@ -3493,14 +3418,6 @@ void CCryEditApp::OnResourcesReduceworkingset() #endif } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnSnap() -{ - // Switch current snap to grid state. - bool bGridEnabled = gSettings.pGrid->IsEnabled(); - gSettings.pGrid->Enable(!bGridEnabled); -} - void CCryEditApp::OnWireframe() { int nWireframe(R_SOLID_MODE); @@ -3540,14 +3457,6 @@ void CCryEditApp::OnUpdateWireframe(QAction* action) action->setChecked(nWireframe == R_WIREFRAME_MODE); } - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnViewGridsettings() -{ - CGridSettingsDialog dlg; - dlg.exec(); -} - ////////////////////////////////////////////////////////////////////////// void CCryEditApp::OnViewConfigureLayout() { @@ -3749,19 +3658,6 @@ void CCryEditApp::OnDisplayGotoPosition() dlg.exec(); } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnSnapangle() -{ - gSettings.pGrid->EnableAngleSnap(!gSettings.pGrid->IsAngleSnapEnabled()); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnUpdateSnapangle(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - action->setChecked(gSettings.pGrid->IsAngleSnapEnabled()); -} - ////////////////////////////////////////////////////////////////////////// void CCryEditApp::OnChangemovespeedIncrease() { diff --git a/Code/Sandbox/Editor/CryEdit.h b/Code/Sandbox/Editor/CryEdit.h index c0b26a9405..2e71ca6a58 100644 --- a/Code/Sandbox/Editor/CryEdit.h +++ b/Code/Sandbox/Editor/CryEdit.h @@ -229,7 +229,6 @@ public: void OnFileResaveSlices(); void OnFileEditEditorini(); void OnPreferences(); - void OnReloadTextures(); void OnRedo(); void OnUpdateRedo(QAction* action); void OnUpdateUndo(QAction* action); @@ -284,12 +283,6 @@ private: //! Test mode is a special mode enabled when Editor ran with /test command line. //! In this mode editor starts up, but exit immediately after all initialization. bool m_bTestMode = false; - bool m_bPrecacheShaderList = false; - bool m_bPrecacheShaders = false; - bool m_bPrecacheShadersLevels = false; - bool m_bMergeShaders = false; - bool m_bStatsShaderList = false; - bool m_bStatsShaders = false; //! In this mode editor will load specified cry file, export t, and then close. bool m_bExportMode = false; QString m_exportFile; @@ -371,10 +364,8 @@ private: AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING friend struct PythonTestOutputHandler; - void OnSnap(); void OnWireframe(); void OnUpdateWireframe(QAction* action); - void OnViewGridsettings(); void OnViewConfigureLayout(); // Tag Locations. @@ -409,8 +400,6 @@ private: void OnToolsScriptHelp(); void OnViewCycle2dviewport(); void OnDisplayGotoPosition(); - void OnSnapangle(); - void OnUpdateSnapangle(QAction* action); void OnChangemovespeedIncrease(); void OnChangemovespeedDecrease(); void OnChangemovespeedChangestep(); diff --git a/Code/Sandbox/Editor/CryEditDoc.cpp b/Code/Sandbox/Editor/CryEditDoc.cpp index ffcbd00a5f..a6c5f73c7f 100644 --- a/Code/Sandbox/Editor/CryEditDoc.cpp +++ b/Code/Sandbox/Editor/CryEditDoc.cpp @@ -51,7 +51,6 @@ #include "Include/IObjectManager.h" #include "ErrorReportDialog.h" #include "SurfaceTypeValidator.h" -#include "ShaderCache.h" #include "Util/AutoLogTime.h" #include "CheckOutDialog.h" #include "GameExporter.h" @@ -143,7 +142,6 @@ CCryEditDoc::CCryEditDoc() m_environmentTemplate = XmlHelpers::CreateXmlNode("Environment"); } - m_pLevelShaderCache = new CLevelShaderCache; m_bDocumentReady = false; GetIEditor()->SetDocument(this); CLogFile::WriteLine("Document created"); @@ -156,8 +154,6 @@ CCryEditDoc::~CCryEditDoc() { GetIEditor()->SetDocument(nullptr); - delete m_pLevelShaderCache; - CLogFile::WriteLine("Document destroyed"); AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect(); @@ -337,7 +333,6 @@ void CCryEditDoc::Save(TDocMultiArchive& arrXmlAr) // Fog settings /////////////////////////////////////////////////////// SerializeFogSettings((*arrXmlAr[DMAS_GENERAL])); - SerializeShaderCache((*arrXmlAr[DMAS_GENERAL_NAMED_DATA])); SerializeNameSelection((*arrXmlAr[DMAS_GENERAL])); } } @@ -486,7 +481,6 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename) { // Serialize Shader Cache. CAutoLogTime logtime("Load Level Shader Cache"); - SerializeShaderCache((*arrXmlAr[DMAS_GENERAL_NAMED_DATA])); } { @@ -585,23 +579,13 @@ void CCryEditDoc::SerializeViewSettings(CXmlArchive& xmlAr) view->getAttr(viewerAnglesName.toUtf8().constData(), va); } - CViewport* pVP = GetIEditor()->GetViewManager()->GetView(i); - - - if (pVP) - { - Matrix34 tm = Matrix34::CreateRotationXYZ(va); - tm.SetTranslation(vp); - pVP->SetViewTM(tm); - } - - // Load grid. - auto gridName = QString("Grid%1").arg(useOldViewFormat ? "" : QString::number(i)); - XmlNodeRef gridNode = xmlAr.root->newChild(gridName.toUtf8().constData()); + Matrix34 tm = Matrix34::CreateRotationXYZ(va); + tm.SetTranslation(vp); - if (gridNode) + auto viewportContextManager = AZ::Interface::Get(); + if (auto viewportContext = viewportContextManager->GetViewportContextById(i)) { - GetIEditor()->GetViewManager()->GetGrid()->Serialize(gridNode, xmlAr.bLoading); + viewportContext->SetCameraTransform(LYTransformToAZTransform(tm)); } } } @@ -628,11 +612,6 @@ void CCryEditDoc::SerializeViewSettings(CXmlArchive& xmlAr) auto viewerAnglesName = QString("ViewerAngles%1").arg(i); view->setAttr(viewerAnglesName.toUtf8().constData(), angles); } - - // Save grid. - auto gridName = QString("Grid%1").arg(i); - XmlNodeRef gridNode = xmlAr.root->newChild(gridName.toUtf8().constData()); - GetIEditor()->GetViewManager()->GetGrid()->Serialize(gridNode, xmlAr.bLoading); } } } @@ -668,39 +647,6 @@ void CCryEditDoc::SerializeFogSettings(CXmlArchive& xmlAr) } } -void CCryEditDoc::SerializeShaderCache(CXmlArchive& xmlAr) -{ - if (xmlAr.bLoading) - { - void* pData = 0; - int nSize = 0; - - if (xmlAr.pNamedData->GetDataBlock("ShaderCache", pData, nSize)) - { - if (nSize <= 0) - { - return; - } - - QByteArray str(nSize + 1, 0); - memcpy(str.data(), pData, nSize); - str[nSize] = 0; - m_pLevelShaderCache->LoadBuffer(str); - } - } - else - { - QString buf; - - m_pLevelShaderCache->SaveBuffer(buf); - - if (!buf.isEmpty()) - { - xmlAr.pNamedData->AddDataBlock("ShaderCache", buf.toUtf8().data(), buf.toUtf8().count()); - } - } -} - void CCryEditDoc::SerializeNameSelection(CXmlArchive& xmlAr) { IObjectManager* pObjManager = GetIEditor()->GetObjectManager(); diff --git a/Code/Sandbox/Editor/CryEditDoc.h b/Code/Sandbox/Editor/CryEditDoc.h index be8a5fcec7..1ca3dc85f4 100644 --- a/Code/Sandbox/Editor/CryEditDoc.h +++ b/Code/Sandbox/Editor/CryEditDoc.h @@ -22,7 +22,6 @@ #include #endif -class CLevelShaderCache; class CClouds; struct LightingSettings; struct IVariable; @@ -123,7 +122,6 @@ public: // Create from serialization only const char* GetTemporaryLevelName() const; void DeleteTemporaryLevel(); - CLevelShaderCache* GetShaderCache() { return m_pLevelShaderCache; } CClouds* GetClouds() { return m_pClouds; } void SetWaterColor(const QColor& col) { m_waterColor = col; } QColor GetWaterColor() { return m_waterColor; } @@ -165,7 +163,6 @@ protected: bool LoadEntitiesFromSlice(const QString& sliceFile); void SerializeFogSettings(CXmlArchive& xmlAr); virtual void SerializeViewSettings(CXmlArchive& xmlAr); - void SerializeShaderCache(CXmlArchive& xmlAr); void SerializeNameSelection(CXmlArchive& xmlAr); void LogLoadTime(int time); @@ -201,7 +198,6 @@ protected: CClouds* m_pClouds; std::list m_listeners; bool m_bDocumentReady; - CLevelShaderCache* m_pLevelShaderCache; ICVar* doc_validate_surface_types; int m_modifiedModuleFlags; bool m_boLevelExported; diff --git a/Code/Sandbox/Editor/EditorFileMonitor.cpp b/Code/Sandbox/Editor/EditorFileMonitor.cpp index 1898ae5f7a..f627b61255 100644 --- a/Code/Sandbox/Editor/EditorFileMonitor.cpp +++ b/Code/Sandbox/Editor/EditorFileMonitor.cpp @@ -35,9 +35,6 @@ void CEditorFileMonitor::OnEditorNotifyEvent(EEditorNotifyEvent ev) { if (ev == eNotify_OnInit) { - // Setup file change monitoring - gEnv->pSystem->SetIFileChangeMonitor(this); - // We don't want the file monitor to be enabled while // in console mode... if (!GetIEditor()->IsInConsolewMode()) @@ -49,7 +46,6 @@ void CEditorFileMonitor::OnEditorNotifyEvent(EEditorNotifyEvent ev) } else if (ev == eNotify_OnQuit) { - gEnv->pSystem->SetIFileChangeMonitor(NULL); CFileChangeMonitor::Instance()->StopMonitor(); GetIEditor()->UnregisterNotifyListener(this); } diff --git a/Code/Sandbox/Editor/EditorFileMonitor.h b/Code/Sandbox/Editor/EditorFileMonitor.h index 9af68a6179..916c0cb11a 100644 --- a/Code/Sandbox/Editor/EditorFileMonitor.h +++ b/Code/Sandbox/Editor/EditorFileMonitor.h @@ -15,7 +15,6 @@ #define CRYINCLUDE_EDITOR_EDITORFILEMONITOR_H #pragma once #include "Include/IEditorFileMonitor.h" -#include "IFileChangeMonitor.h" #include "Util/FileChangeMonitor.h" class CEditorFileMonitor diff --git a/Code/Sandbox/Editor/EditorViewportSettings.cpp b/Code/Sandbox/Editor/EditorViewportSettings.cpp new file mode 100644 index 0000000000..362d0fab48 --- /dev/null +++ b/Code/Sandbox/Editor/EditorViewportSettings.cpp @@ -0,0 +1,116 @@ +/* + * 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 + +#include +#include +#include + +namespace Editor +{ + constexpr AZStd::string_view GridSnappingSetting = "/Amazon/Preferences/Editor/GridSnapping"; + constexpr AZStd::string_view GridSizeSetting = "/Amazon/Preferences/Editor/GridSize"; + constexpr AZStd::string_view AngleSnappingSetting = "/Amazon/Preferences/Editor/AngleSnapping"; + constexpr AZStd::string_view AngleSizeSetting = "/Amazon/Preferences/Editor/AngleSize"; + constexpr AZStd::string_view ShowGridSetting = "/Amazon/Preferences/Editor/ShowGrid"; + + bool GridSnappingEnabled() + { + bool enabled = false; + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Get(enabled, GridSnappingSetting); + } + return enabled; + } + + float GridSnappingSize() + { + double gridSize = 0.1; + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Get(gridSize, GridSizeSetting); + } + return aznumeric_cast(gridSize); + } + + bool AngleSnappingEnabled() + { + bool enabled = false; + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Get(enabled, AngleSnappingSetting); + } + return enabled; + } + + float AngleSnappingSize() + { + double angleSize = 5.0; + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Get(angleSize, AngleSizeSetting); + } + return aznumeric_cast(angleSize); + } + + bool ShowingGrid() + { + bool enabled = false; + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Get(enabled, ShowGridSetting); + } + return enabled; + } + + void SetGridSnapping(const bool enabled) + { + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Set(GridSnappingSetting, enabled); + } + } + + void SetGridSnappingSize(const float size) + { + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Set(GridSizeSetting, size); + } + } + + void SetAngleSnapping(const bool enabled) + { + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Set(AngleSnappingSetting, enabled); + } + } + + void SetAngleSnappingSize(const float size) + { + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Set(AngleSizeSetting, size); + } + } + + void SetShowingGrid(const bool showing) + { + if (auto* registry = AZ::SettingsRegistry::Get()) + { + registry->Set(ShowGridSetting, showing); + } + } +} // namespace Editor diff --git a/Code/Sandbox/Editor/EditorViewportSettings.h b/Code/Sandbox/Editor/EditorViewportSettings.h new file mode 100644 index 0000000000..ca6a5f0797 --- /dev/null +++ b/Code/Sandbox/Editor/EditorViewportSettings.h @@ -0,0 +1,38 @@ +/* + * 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 + +namespace Editor +{ + EDITOR_CORE_API bool GridSnappingEnabled(); + + EDITOR_CORE_API float GridSnappingSize(); + + EDITOR_CORE_API bool AngleSnappingEnabled(); + + EDITOR_CORE_API float AngleSnappingSize(); + + EDITOR_CORE_API bool ShowingGrid(); + + EDITOR_CORE_API void SetGridSnapping(bool enabled); + + EDITOR_CORE_API void SetGridSnappingSize(float size); + + EDITOR_CORE_API void SetAngleSnapping(bool enabled); + + EDITOR_CORE_API void SetAngleSnappingSize(float size); + + EDITOR_CORE_API void SetShowingGrid(bool showing); +} // namespace Editor diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 0b3ff87e43..db37653cf1 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -75,6 +75,7 @@ #include "ViewportManipulatorController.h" #include "LegacyViewportCameraController.h" #include "ModernViewportCameraController.h" +#include "EditorViewportSettings.h" #include "ViewPane.h" #include "CustomResolutionDlg.h" @@ -127,6 +128,18 @@ AZ_CVAR( bool, ed_useNewCameraSystem, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new Editor camera system (the Atom-native Editor viewport (experimental) must also be enabled)"); +//! Viewport settings for the EditorViewportWidget +struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::ViewportSettings +{ + bool GridSnappingEnabled() const override; + float GridSize() const override; + bool ShowGrid() const override; + bool AngleSnappingEnabled() const override; + float AngleStep() const override; +}; + +static const EditorViewportSettings g_EditorViewportSettings; + namespace AZ::ViewportHelpers { static const char TextCantCreateCameraNoLevel[] = "Cannot create camera when no level is loaded."; @@ -170,7 +183,6 @@ EditorViewportWidget::EditorViewportWidget(const QString& name, QWidget* parent) , m_camFOV(gSettings.viewports.fDefaultFov) , m_defaultViewName(name) , m_renderViewport(nullptr) //m_renderViewport is initialized later, in SetViewportId - , m_editorViewportSettings(this) { // need this to be set in order to allow for language switching on Windows setAttribute(Qt::WA_InputMethodEnabled); @@ -441,8 +453,11 @@ void EditorViewportWidget::Update() } m_updatingCameraPosition = true; - auto transform = LYTransformToAZTransform(m_Camera.GetMatrix()); - m_renderViewport->GetViewportContext()->SetCameraTransform(transform); + if (!ed_useNewCameraSystem) + { + m_renderViewport->GetViewportContext()->SetCameraTransform(LYTransformToAZTransform(m_Camera.GetMatrix())); + } + AZ::Matrix4x4 clipMatrix; AZ::MakePerspectiveFovMatrixRH( clipMatrix, @@ -791,10 +806,6 @@ void EditorViewportWidget::OnRender() // This is necessary so that automated editor tests using the null renderer to test systems like dynamic vegetation // are still able to manipulate the current logical camera position, even if nothing is rendered. GetIEditor()->GetSystem()->SetViewCamera(m_Camera); - if (GetIEditor()->GetRenderer()) - { - GetIEditor()->GetRenderer()->SetCamera(gEnv->pSystem->GetViewCamera()); - } return; } @@ -1250,7 +1261,7 @@ void EditorViewportWidget::SetViewportId(int id) m_renderViewport->GetControllerList()->Add(AZStd::make_shared()); } - m_renderViewport->SetViewportSettings(&m_editorViewportSettings); + m_renderViewport->SetViewportSettings(&g_EditorViewportSettings); UpdateScene(); @@ -2871,35 +2882,29 @@ void EditorViewportWidget::SetAsActiveViewport() } } -EditorViewportSettings::EditorViewportSettings(const EditorViewportWidget* editorViewportWidget) - : m_editorViewportWidget(editorViewportWidget) -{ -} - bool EditorViewportSettings::GridSnappingEnabled() const { - return m_editorViewportWidget->GetViewManager()->GetGrid()->IsEnabled(); + return Editor::GridSnappingEnabled(); } float EditorViewportSettings::GridSize() const { - const CGrid* grid = m_editorViewportWidget->GetViewManager()->GetGrid(); - return grid->scale * grid->size; + return Editor::GridSnappingSize(); } bool EditorViewportSettings::ShowGrid() const { - return gSettings.viewports.bShowGridGuide; + return Editor::ShowingGrid(); } bool EditorViewportSettings::AngleSnappingEnabled() const { - return m_editorViewportWidget->GetViewManager()->GetGrid()->IsAngleSnapEnabled(); + return Editor::AngleSnappingEnabled(); } float EditorViewportSettings::AngleStep() const { - return m_editorViewportWidget->GetViewManager()->GetGrid()->GetAngleSnap(); + return Editor::AngleSnappingSize(); } #include diff --git a/Code/Sandbox/Editor/EditorViewportWidget.h b/Code/Sandbox/Editor/EditorViewportWidget.h index 8675c035f6..4062a3c801 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.h +++ b/Code/Sandbox/Editor/EditorViewportWidget.h @@ -65,23 +65,6 @@ namespace AzToolsFramework class ManipulatorManager; } -class EditorViewportWidget; - -//! Viewport settings for the EditorViewportWidget -struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::ViewportSettings -{ - explicit EditorViewportSettings(const EditorViewportWidget* editorViewportWidget); - - bool GridSnappingEnabled() const override; - float GridSize() const override; - bool ShowGrid() const override; - bool AngleSnappingEnabled() const override; - float AngleStep() const override; - -private: - const EditorViewportWidget* m_editorViewportWidget = nullptr; -}; - // EditorViewportWidget window AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING @@ -607,7 +590,5 @@ private: AZ::Name m_defaultViewportContextName; - EditorViewportSettings m_editorViewportSettings; - AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING }; diff --git a/Code/Sandbox/Editor/GameEngine.cpp b/Code/Sandbox/Editor/GameEngine.cpp index 073684eaad..1c91ce58aa 100644 --- a/Code/Sandbox/Editor/GameEngine.cpp +++ b/Code/Sandbox/Editor/GameEngine.cpp @@ -38,7 +38,6 @@ // CryCommon #include -#include #include #include @@ -46,7 +45,6 @@ #include "CryEdit.h" #include "ViewManager.h" -#include "Util/Ruler.h" #include "AnimationContext.h" #include "UndoViewPosition.h" #include "UndoViewRotation.h" @@ -386,7 +384,6 @@ void CGameEngine::SetCurrentViewRotation(const AZ::Vector3& rotation) AZ::Outcome CGameEngine::Init( bool bPreviewMode, bool bTestMode, - bool bShaderCacheGen, const char* sInCmdLine, IInitializeUIInfo* logo, HWND hwndForInputSystem) @@ -444,10 +441,6 @@ AZ::Outcome CGameEngine::Init( m_modalWindowDismisser = AZStd::make_unique(); } - if (bShaderCacheGen) - { - sip.bSkipFont = true; - } AssetProcessConnectionStatus apConnectionStatus; m_pISystem = pfnCreateSystemInterface(sip); @@ -620,12 +613,6 @@ void CGameEngine::SwitchToInGame() m_pISystem->GetIMovieSystem()->EnablePhysicsEvents(true); m_bInGameMode = true; - CRuler* pRuler = GetIEditor()->GetRuler(); - if (pRuler) - { - pRuler->SetActive(false); - } - gEnv->pSystem->GetViewCamera().SetMatrix(m_playerViewTM); // Disable accelerators. @@ -792,12 +779,6 @@ void CGameEngine::SetSimulationMode(bool enabled, bool bOnlyPhysics) if (enabled) { - CRuler* pRuler = GetIEditor()->GetRuler(); - if (pRuler) - { - pRuler->SetActive(false); - } - GetIEditor()->Notify(eNotify_OnBeginSimulationMode); } else @@ -923,9 +904,6 @@ void CGameEngine::Update() // but if in game mode, 'cos is already done in the above call to game->update() unsigned int updateFlags = ESYSUPDATE_EDITOR; - CRuler* pRuler = GetIEditor()->GetRuler(); - const bool bRulerNeedsUpdate = (pRuler && pRuler->HasQueuedPaths()); - if (!m_bSimulationMode) { updateFlags |= ESYSUPDATE_IGNORE_PHYSICS; diff --git a/Code/Sandbox/Editor/GameEngine.h b/Code/Sandbox/Editor/GameEngine.h index b59e2c9ac8..669b37bbb3 100644 --- a/Code/Sandbox/Editor/GameEngine.h +++ b/Code/Sandbox/Editor/GameEngine.h @@ -79,7 +79,6 @@ public: AZ::Outcome Init( bool bPreviewMode, bool bTestMode, - bool bShaderCacheGen, const char* sCmdLine, IInitializeUIInfo* logo, HWND hwndForInputSystem); diff --git a/Code/Sandbox/Editor/GameExporter.cpp b/Code/Sandbox/Editor/GameExporter.cpp index 1b42f75ba3..60746041a7 100644 --- a/Code/Sandbox/Editor/GameExporter.cpp +++ b/Code/Sandbox/Editor/GameExporter.cpp @@ -24,7 +24,6 @@ #include "GameExporter.h" #include "GameEngine.h" #include "CryEditDoc.h" -#include "ShaderCache.h" #include "UsedResources.h" #include "WaitProgress.h" #include "Util/CryMemFile.h" @@ -197,7 +196,6 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE ExportLevelResourceList(sLevelPath); ExportLevelUsedResourceList(sLevelPath); - ExportLevelShaderCache(sLevelPath); ////////////////////////////////////////////////////////////////////////// // End Exporting Game data. @@ -379,18 +377,6 @@ void CGameExporter::ExportLevelUsedResourceList(const QString& path) m_levelPak.m_pakFile.UpdateFile(resFile.toUtf8().data(), memFile, true); } -////////////////////////////////////////////////////////////////////////// -void CGameExporter::ExportLevelShaderCache(const QString& path) -{ - QString buf; - GetIEditor()->GetDocument()->GetShaderCache()->SaveBuffer(buf); - CCryMemFile memFile; - memFile.Write(buf.toUtf8().data(), buf.toUtf8().length()); - - QString filename = Path::Make(path, SHADER_LIST_FILE); - m_levelPak.m_pakFile.UpdateFile(filename.toUtf8().data(), memFile, true); -} - ////////////////////////////////////////////////////////////////////////// void CGameExporter::ExportFileList(const QString& path, const QString& levelName) { diff --git a/Code/Sandbox/Editor/GameExporter.h b/Code/Sandbox/Editor/GameExporter.h index 18ec79189a..08af3e7473 100644 --- a/Code/Sandbox/Editor/GameExporter.h +++ b/Code/Sandbox/Editor/GameExporter.h @@ -95,8 +95,6 @@ private: void ExportLevelResourceList(const QString& path); void ExportLevelUsedResourceList(const QString& path); - void ExportLevelShaderCache(const QString& path); - void ExportGameData(const QString& path); void ExportFileList(const QString& path, const QString& levelName); void Error(const QString& error); diff --git a/Code/Sandbox/Editor/Grid.cpp b/Code/Sandbox/Editor/Grid.cpp deleted file mode 100644 index 50702f8cb2..0000000000 --- a/Code/Sandbox/Editor/Grid.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "Grid.h" - -// Editor -#include "Settings.h" -#include "Objects/SelectionGroup.h" - -////////////////////////////////////////////////////////////////////////// -CGrid::CGrid() -{ - scale = 1; - size = 1; - majorLine = 16; - bEnabled = true; - rotationAngles = Ang3(0.0f, 0.0f, 0.0f); - translation = Vec3(0.0f, 0.0f, 0.0f); - - bAngleSnapEnabled = true; - angleSnap = 5; -} - -////////////////////////////////////////////////////////////////////////// -Vec3 CGrid::Snap(const Vec3& vec) const -{ - if (!bEnabled || size < 0.001) - { - return vec; - } - Vec3 snapped; - snapped.x = floor((vec.x / size) / scale + 0.5) * size * scale; - snapped.y = floor((vec.y / size) / scale + 0.5) * size * scale; - snapped.z = floor((vec.z / size) / scale + 0.5) * size * scale; - return snapped; -} - -////////////////////////////////////////////////////////////////////////// -Vec3 CGrid::Snap(const Vec3& vec, double fZoom) const -{ - if (!bEnabled || size < 0.001f) - { - return vec; - } - - Matrix34 tm = GetMatrix(); - - double zoomscale = scale * fZoom; - Vec3 snapped; - - Matrix34 invtm = tm.GetInverted(); - - snapped = invtm * vec; - - snapped.x = floor((snapped.x / size) / zoomscale + 0.5) * size * zoomscale; - snapped.y = floor((snapped.y / size) / zoomscale + 0.5) * size * zoomscale; - snapped.z = floor((snapped.z / size) / zoomscale + 0.5) * size * zoomscale; - - snapped = tm * snapped; - - return snapped; -} - -////////////////////////////////////////////////////////////////////////// -double CGrid::SnapAngle(double angle) const -{ - if (!bAngleSnapEnabled) - { - return angle; - } - return floor(angle / angleSnap + 0.5) * angleSnap; -} - -////////////////////////////////////////////////////////////////////////// -Ang3 CGrid::SnapAngle(const Ang3& vec) const -{ - if (!bAngleSnapEnabled) - { - return vec; - } - Ang3 snapped; - snapped.x = floor(vec.x / angleSnap + 0.5) * angleSnap; - snapped.y = floor(vec.y / angleSnap + 0.5) * angleSnap; - snapped.z = floor(vec.z / angleSnap + 0.5) * angleSnap; - return snapped; -} - -////////////////////////////////////////////////////////////////////////// -void CGrid::Serialize(XmlNodeRef& xmlNode, bool bLoading) -{ - if (bLoading) - { - // Loading. - xmlNode->getAttr("Size", size); - xmlNode->getAttr("Scale", scale); - xmlNode->getAttr("Enabled", bEnabled); - xmlNode->getAttr("MajorSize", majorLine); - xmlNode->getAttr("AngleSnap", angleSnap); - xmlNode->getAttr("AngleSnapEnabled", bAngleSnapEnabled); - if (size < 0.01) - { - size = 0.01; - } - } - else - { - // Saving. - xmlNode->setAttr("Size", size); - xmlNode->setAttr("Scale", scale); - xmlNode->setAttr("Enabled", bEnabled); - xmlNode->setAttr("MajorSize", majorLine); - xmlNode->setAttr("AngleSnap", angleSnap); - xmlNode->setAttr("AngleSnapEnabled", bAngleSnapEnabled); - } -} - -////////////////////////////////////////////////////////////////////////// -Matrix34 CGrid::GetMatrix() const -{ - Matrix34 tm; - - if (gSettings.snap.bGridUserDefined) - { - Ang3 angles = Ang3(rotationAngles.x * gf_PI / 180.0, rotationAngles.y * gf_PI / 180.0, rotationAngles.z * gf_PI / 180.0); - - tm = Matrix33::CreateRotationXYZ(angles); - } - else if (GetIEditor()->GetReferenceCoordSys() == COORDS_LOCAL) - { - tm.SetIdentity(); - } - else - { - tm.SetIdentity(); - } - - return tm; -} diff --git a/Code/Sandbox/Editor/Grid.h b/Code/Sandbox/Editor/Grid.h deleted file mode 100644 index dd761ad058..0000000000 --- a/Code/Sandbox/Editor/Grid.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_GRID_H -#define CRYINCLUDE_EDITOR_GRID_H - -#pragma once - -/** Definition of grid used in 2D viewports. -*/ -class SANDBOX_API CGrid -{ -public: - //! Resolution of grid, it must be multiply of 2. - double size; - //! Draw major lines every Nth grid line. - int majorLine; - //! True if grid enabled. - bool bEnabled; - //! Meters per grid unit. - double scale; - - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING - Ang3 rotationAngles; - Vec3 translation; - AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - - //! If snap to angle. - bool bAngleSnapEnabled; - double angleSnap; - - ////////////////////////////////////////////////////////////////////////// - CGrid(); - - //! Snap vector to this grid. - Vec3 Snap(const Vec3& vec) const; - Vec3 Snap(const Vec3& vec, double fZoom) const; - - //! Snap angle to current angle snapping value. - double SnapAngle(double angle) const; - //! Snap angle to current angle snapping value. - Ang3 SnapAngle(const Ang3& angle) const; - - //! Enable or disable grid. - void Enable(bool enable) { bEnabled = enable; } - //! Check if grid enabled. - bool IsEnabled() const { return bEnabled; } - - //! Enables or disable angle snapping. - void EnableAngleSnap(bool enable) { bAngleSnapEnabled = enable; }; - - //! Return if snapping of angle is enabled. - bool IsAngleSnapEnabled() const { return bAngleSnapEnabled; }; - //! Returns ammount of snapping for angle in degrees. - double GetAngleSnap() const { return angleSnap; }; - - void Serialize(XmlNodeRef& xmlNode, bool bLoading); - - //! Get transformation matrix of gird. - Matrix34 GetMatrix() const; -}; - - -#endif // CRYINCLUDE_EDITOR_GRID_H diff --git a/Code/Sandbox/Editor/GridSettingsDialog.cpp b/Code/Sandbox/Editor/GridSettingsDialog.cpp deleted file mode 100644 index ecabdc4e6a..0000000000 --- a/Code/Sandbox/Editor/GridSettingsDialog.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "GridSettingsDialog.h" - -// Editor -#include "Settings.h" -#include "Objects/SelectionGroup.h" -#include "ViewManager.h" - - -AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING -#include -AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - -// CGridSettingsDialog dialog - -CGridSettingsDialog::CGridSettingsDialog(QWidget* pParent /*=NULL*/) - : QDialog(pParent) - , ui(new Ui::CGridSettingsDialog) -{ - ui->setupUi(this); - - setWindowTitle(tr("Grid/Snap Settings")); - - OnInitDialog(); - - connect(ui->m_userDefined, &QCheckBox::clicked, this, &CGridSettingsDialog::OnBnUserDefined); - connect(ui->m_getFromObject, &QCheckBox::clicked, this, &CGridSettingsDialog::OnBnGetFromObject); - - auto doubleSpinBoxValueChanged = static_cast(&QDoubleSpinBox::valueChanged); - - connect(ui->m_angleX, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - connect(ui->m_angleY, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - connect(ui->m_angleZ, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - - connect(ui->m_gridSize, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - connect(ui->m_gridScale, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - connect(ui->m_CPSize, doubleSpinBoxValueChanged, this, &CGridSettingsDialog::OnValueUpdate); - - connect(ui->m_displayCP, &QCheckBox::clicked, this, &CGridSettingsDialog::OnValueUpdate); - connect(ui->m_getFromObject, &QCheckBox::clicked, this, &CGridSettingsDialog::OnValueUpdate); - - connect(ui->m_buttonBox, &QDialogButtonBox::accepted, this, &CGridSettingsDialog::accept); - connect(ui->m_buttonBox, &QDialogButtonBox::rejected, this, &CGridSettingsDialog::reject); -} - -CGridSettingsDialog::~CGridSettingsDialog() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CGridSettingsDialog::OnInitDialog() -{ - CGrid* pGrid = GetIEditor()->GetViewManager()->GetGrid(); - - ui->m_userDefined->setChecked(gSettings.snap.bGridUserDefined); - ui->m_getFromObject->setChecked(gSettings.snap.bGridGetFromSelected); - - ui->m_angleX->setValue(pGrid->rotationAngles.x); - ui->m_angleY->setValue(pGrid->rotationAngles.y); - ui->m_angleZ->setValue(pGrid->rotationAngles.z); - - ui->m_translationX->setValue(pGrid->translation.x); - ui->m_translationY->setValue(pGrid->translation.y); - ui->m_translationZ->setValue(pGrid->translation.z); - - ui->m_gridSize->setValue(pGrid->size); - ui->m_gridScale->setValue(pGrid->scale); - ui->m_snapToGrid->setChecked(pGrid->IsEnabled()); - - ui->m_angleSnap->setChecked(pGrid->IsAngleSnapEnabled()); - ui->m_angleSnapScale->setValue(pGrid->GetAngleSnap()); - ui->m_displayCP->setChecked(gSettings.snap.constructPlaneDisplay); - - ui->m_CPSize->setValue(gSettings.snap.constructPlaneSize); - ui->m_displaySnapMarker->setChecked(gSettings.snap.markerDisplay); - ui->m_snapMarkerSize->setValue(gSettings.snap.markerSize); - - ui->m_snapMarkerColor->SetColor(gSettings.snap.markerColor); - - EnableGridPropertyControls(gSettings.snap.bGridUserDefined, gSettings.snap.bGridGetFromSelected); -} - -////////////////////////////////////////////////////////////////////////// -void CGridSettingsDialog::accept() -{ - UpdateValues(); - gSettings.Save(); - QDialog::accept(); -} - -void CGridSettingsDialog::OnBnUserDefined() -{ - EnableGridPropertyControls(ui->m_userDefined->isChecked(), ui->m_getFromObject->isChecked()); - OnValueUpdate(); -} - -void CGridSettingsDialog::OnBnGetFromObject() -{ - EnableGridPropertyControls(ui->m_userDefined->isChecked(), ui->m_getFromObject->isChecked()); -} - -void CGridSettingsDialog::EnableGridPropertyControls(const bool isUserDefined, const bool isGetFromObject) -{ - ui->m_getFromObject->setEnabled(isUserDefined == true); - - ui->m_angleX->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_angleY->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_angleZ->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_translationX->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_translationY->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_translationZ->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_getAnglesFromObject->setEnabled(isUserDefined == true && isGetFromObject == false); - ui->m_getTranslationFromObject->setEnabled(isUserDefined == true && isGetFromObject == false); -} - -////////////////////////////////////////////////////////////////////////// -void CGridSettingsDialog::UpdateValues() -{ - CGrid* pGrid = GetIEditor()->GetViewManager()->GetGrid(); - - pGrid->Enable(ui->m_snapToGrid->isChecked()); - pGrid->size = ui->m_gridSize->value(); - pGrid->scale = ui->m_gridScale->value(); - - gSettings.snap.bGridUserDefined = ui->m_userDefined->isChecked(); - gSettings.snap.bGridGetFromSelected = ui->m_getFromObject->isChecked(); - pGrid->rotationAngles.x = ui->m_angleX->value(); - pGrid->rotationAngles.y = ui->m_angleY->value(); - pGrid->rotationAngles.z = ui->m_angleZ->value(); - pGrid->translation.x = ui->m_translationX->value(); - pGrid->translation.y = ui->m_translationY->value(); - pGrid->translation.z = ui->m_translationZ->value(); - - pGrid->bAngleSnapEnabled = ui->m_angleSnap->isChecked(); - pGrid->angleSnap = ui->m_angleSnapScale->value(); - - gSettings.snap.constructPlaneDisplay = ui->m_displayCP->isChecked(); - gSettings.snap.constructPlaneSize = ui->m_CPSize->value(); - - gSettings.snap.markerDisplay = ui->m_displaySnapMarker->isChecked(); - gSettings.snap.markerSize = ui->m_snapMarkerSize->value(); - gSettings.snap.markerColor = ui->m_snapMarkerColor->Color(); - - NotificationBus::Broadcast(&Notifications::OnGridValuesUpdated); -} - - -////////////////////////////////////////////////////////////////////////// -void CGridSettingsDialog::OnValueUpdate() -{ - UpdateValues(); - GetIEditor()->UpdateViews(eRedrawViewports); -} - -#include diff --git a/Code/Sandbox/Editor/GridSettingsDialog.h b/Code/Sandbox/Editor/GridSettingsDialog.h deleted file mode 100644 index fe5934ec7e..0000000000 --- a/Code/Sandbox/Editor/GridSettingsDialog.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_GRIDSETTINGSDIALOG_H -#define CRYINCLUDE_EDITOR_GRIDSETTINGSDIALOG_H - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#endif - -// CGridSettingsDialog dialog - -namespace Ui { - class CGridSettingsDialog; -} - -class CGridSettingsDialog - : public QDialog -{ - Q_OBJECT -public: - - class Notifications - : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - - virtual void OnGridValuesUpdated() {} - }; - - using NotificationBus = AZ::EBus; - - CGridSettingsDialog(QWidget* pParent = nullptr); // standard constructor - virtual ~CGridSettingsDialog(); - -private slots: - void accept() override; - void OnBnUserDefined(); - void OnBnGetFromObject(); - void OnValueUpdate(); - -private: - void EnableGridPropertyControls(const bool isUserDefined, const bool isGetFromObject); - - void OnInitDialog(); - void UpdateValues(); - - QScopedPointer ui; -}; - -#endif // CRYINCLUDE_EDITOR_GRIDSETTINGSDIALOG_H diff --git a/Code/Sandbox/Editor/GridSettingsDialog.ui b/Code/Sandbox/Editor/GridSettingsDialog.ui deleted file mode 100644 index f77abbece7..0000000000 --- a/Code/Sandbox/Editor/GridSettingsDialog.ui +++ /dev/null @@ -1,505 +0,0 @@ - - - CGridSettingsDialog - - - - 0 - 0 - 307 - 707 - - - - - - - - - Grid - - - - - - Snap to Grid - - - - - - - Grid Lines Every: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - 1024.000000000000000 - - - 0.010000000000000 - - - - - - - units - - - - - - - Units Per Meter: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - 1024.000000000000000 - - - 0.010000000000000 - - - - - - - meters - - - - - - - User Defined Grid - - - - - - - Get Angles And Trans. From Selected - - - - - - - Rotation by X: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - -180.000000000000000 - - - 180.000000000000000 - - - 0.010000000000000 - - - - - - - degrees - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Rotation by Y: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - -180.000000000000000 - - - 180.000000000000000 - - - 0.010000000000000 - - - - - - - degrees - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Rotation by Z: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - -180.000000000000000 - - - 180.000000000000000 - - - 0.010000000000000 - - - - - - - degrees - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Translation by X: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - - - - - Translation by Y: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - - - - - Translation by Z: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - - - - - Get Angles From Selected - - - - - - - Get Translation From Selected - - - - - - - - - - Angle Snapping - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 80 - 0 - - - - degrees - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Angle Snap - - - - - - - Angle Snap: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - - 40 - 0 - - - - - - - - - - - Construction Plane - - - - - - Size: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Display - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 80 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - m_displayCP - m_CPSize - - - - - - Snap Marker - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0.010000000000000 - - - - - - - Display - - - - - - - - 80 - 0 - - - - Color - - - - - - - Size: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - ColorButton - QToolButton -
QtUI/ColorButton.h
-
-
- - -
diff --git a/Code/Sandbox/Editor/IEditor.h b/Code/Sandbox/Editor/IEditor.h index f11beacf10..62672a6505 100644 --- a/Code/Sandbox/Editor/IEditor.h +++ b/Code/Sandbox/Editor/IEditor.h @@ -66,7 +66,6 @@ class CDialog; #if defined(AZ_PLATFORM_WINDOWS) class C3DConnexionDriver; #endif -class CRuler; class CSettingsManager; struct IExportManager; class CDisplaySettings; @@ -425,7 +424,6 @@ struct IEditor virtual void DeleteThis() = 0; //! Access to Editor ISystem interface. virtual ISystem* GetSystem() = 0; - virtual IRenderer* GetRenderer() = 0; //! Access to class factory. virtual IEditorClassFactory* GetClassFactory() = 0; //! Access to commands manager. @@ -589,8 +587,6 @@ struct IEditor virtual void SetSelectedRegion(const AABB& box) = 0; //! Get currently selected region. virtual void GetSelectedRegion(AABB& box) = 0; - //! Get current ruler - virtual CRuler* GetRuler() = 0; virtual void SetOperationMode(EOperationMode mode) = 0; virtual EOperationMode GetOperationMode() = 0; @@ -635,7 +631,6 @@ struct IEditor //! Returns true if selection is made and false if selection is canceled. virtual bool SelectColor(QColor& color, QWidget* parent = 0) = 0; //! Get shader enumerator. - virtual class CShaderEnum* GetShaderEnum() = 0; virtual class CUndoManager* GetUndoManager() = 0; //! Begin operation requiring undo //! Undo manager enters holding state. diff --git a/Code/Sandbox/Editor/IEditorImpl.cpp b/Code/Sandbox/Editor/IEditorImpl.cpp index 53a2c120c4..95091a5992 100644 --- a/Code/Sandbox/Editor/IEditorImpl.cpp +++ b/Code/Sandbox/Editor/IEditorImpl.cpp @@ -49,7 +49,6 @@ AZ_POP_DISABLE_WARNING #include "Objects/GizmoManager.h" #include "Objects/AxisGizmo.h" #include "DisplaySettings.h" -#include "ShaderEnum.h" #include "KeyboardCustomizationSettings.h" #include "Export/ExportManager.h" #include "LevelIndependentFileMan.h" @@ -60,7 +59,6 @@ AZ_POP_DISABLE_WARNING #include "MainWindow.h" #include "Alembic/AlembicCompiler.h" #include "UIEnumsDatabase.h" -#include "Util/Ruler.h" #include "RenderHelpers/AxisHelper.h" #include "Settings.h" #include "Include/IObjectManager.h" @@ -134,7 +132,6 @@ CEditorImpl::CEditorImpl() , m_bUpdates(true) , m_bTerrainAxisIgnoreObjects(false) , m_pDisplaySettings(nullptr) - , m_pShaderEnum(nullptr) , m_pIconManager(nullptr) , m_bSelectionLocked(true) , m_pAxisGizmo(nullptr) @@ -149,7 +146,6 @@ CEditorImpl::CEditorImpl() , m_pSourceControl(nullptr) , m_pSelectionTreeManager(nullptr) , m_pUIEnumsDatabase(nullptr) - , m_pRuler(nullptr) , m_pConsoleSync(nullptr) , m_pSettingsManager(nullptr) , m_pLevelIndependentFileMan(nullptr) @@ -185,7 +181,6 @@ CEditorImpl::CEditorImpl() m_pBackgroundScheduleManager.reset(new BackgroundScheduleManager::CScheduleManager); m_pUIEnumsDatabase = new CUIEnumsDatabase; m_pDisplaySettings = new CDisplaySettings; - m_pShaderEnum = new CShaderEnum; m_pDisplaySettings->LoadRegistry(); m_pPluginManager = new CPluginManager; @@ -202,7 +197,6 @@ CEditorImpl::CEditorImpl() m_pImageUtil = new CImageUtil_impl(); m_pResourceSelectorHost.reset(CreateResourceSelectorHost()); - m_pRuler = new CRuler; m_selectedRegion.min = Vec3(0, 0, 0); m_selectedRegion.max = Vec3(0, 0, 0); DetectVersion(); @@ -335,8 +329,6 @@ CEditorImpl::~CEditorImpl() } SAFE_DELETE(m_pDisplaySettings) - SAFE_DELETE(m_pRuler) - SAFE_DELETE(m_pShaderEnum) SAFE_DELETE(m_pToolBoxManager) SAFE_DELETE(m_pCommandManager) SAFE_DELETE(m_pClassFactory) @@ -419,7 +411,6 @@ void CEditorImpl::Update() m_bUpdates = false; FUNCTION_PROFILER(GetSystem(), PROFILE_EDITOR); - m_pRuler->Update(); //@FIXME: Restore this latter. //if (GetGameEngine() && GetGameEngine()->IsLevelLoaded()) @@ -440,15 +431,6 @@ ISystem* CEditorImpl::GetSystem() return m_pSystem; } -IRenderer* CEditorImpl::GetRenderer() -{ - if (gEnv) - { - return gEnv->pRenderer; - } - return nullptr; -} - IEditorClassFactory* CEditorImpl::GetClassFactory() { return m_pClassFactory; @@ -1182,11 +1164,6 @@ void CEditorImpl::AddTemplate(const QString& templateName, XmlNodeRef& tmpl) m_templateRegistry.AddTemplate(templateName, tmpl); } -CShaderEnum* CEditorImpl::GetShaderEnum() -{ - return m_pShaderEnum; -} - bool CEditorImpl::ExecuteConsoleApp(const QString& CommandLine, QString& OutputText, [[maybe_unused]] bool bNoTimeOut, bool bShowWindow) { CLogFile::FormatLine("Executing console application '%s'", CommandLine.toUtf8().data()); @@ -1569,7 +1546,6 @@ void CEditorImpl::ReduceMemory() GetIEditor()->GetUndoManager()->ClearRedoStack(); GetIEditor()->GetUndoManager()->ClearUndoStack(); GetIEditor()->GetObjectManager()->SendEvent(EVENT_FREE_GAME_DATA); - gEnv->pRenderer->FreeResources(FRR_TEXTURES); #if defined(AZ_PLATFORM_WINDOWS) HANDLE hHeap = GetProcessHeap(); diff --git a/Code/Sandbox/Editor/IEditorImpl.h b/Code/Sandbox/Editor/IEditorImpl.h index bbef338cb2..7ad97d79e5 100644 --- a/Code/Sandbox/Editor/IEditorImpl.h +++ b/Code/Sandbox/Editor/IEditorImpl.h @@ -53,7 +53,6 @@ class CAlembicCompiler; struct IBackgroundTaskManager; struct IBackgroundScheduleManager; struct IEditorFileMonitor; -class CShaderEnum; class CVegetationMap; @@ -116,7 +115,6 @@ public: bool IsInitialized() const{ return m_bInitialized; } bool SaveDocument(); ISystem* GetSystem(); - IRenderer* GetRenderer(); void WriteToConsole(const char* string) { CLogFile::WriteLine(string); }; void WriteToConsole(const QString& string) { CLogFile::WriteLine(string); }; // Change the message in the status bar @@ -215,7 +213,6 @@ public: void SetMarkerPosition(const Vec3& pos) { m_marker = pos; }; void SetSelectedRegion(const AABB& box); void GetSelectedRegion(AABB& box); - CRuler* GetRuler() { return m_pRuler; } bool AddToolbarItem(uint8 iId, IUIEvent* pIHandler); void SetDataModified(); void SetOperationMode(EOperationMode mode); @@ -256,7 +253,6 @@ public: SFileVersion GetFileVersion() { return m_fileVersion; }; SFileVersion GetProductVersion() { return m_productVersion; }; //! Get shader enumerator. - CShaderEnum* GetShaderEnum(); CUndoManager* GetUndoManager() { return m_pUndoManager; }; void BeginUndo(); void RestoreUndo(bool undo); @@ -365,7 +361,6 @@ protected: SFileVersion m_productVersion; CXmlTemplateRegistry m_templateRegistry; CDisplaySettings* m_pDisplaySettings; - CShaderEnum* m_pShaderEnum; CIconManager* m_pIconManager; std::unique_ptr m_pGizmoParameters; QString m_primaryCDFolder; @@ -390,8 +385,6 @@ protected: CSelectionTreeManager* m_pSelectionTreeManager; CUIEnumsDatabase* m_pUIEnumsDatabase; - //! Currently used ruler - CRuler* m_pRuler; //! CConsole Synchronization CConsoleSynchronization* m_pConsoleSync; //! Editor Settings Manager diff --git a/Code/Sandbox/Editor/Include/IEditorFileMonitor.h b/Code/Sandbox/Editor/Include/IEditorFileMonitor.h index 670e4fdf7e..cfd14f8942 100644 --- a/Code/Sandbox/Editor/Include/IEditorFileMonitor.h +++ b/Code/Sandbox/Editor/Include/IEditorFileMonitor.h @@ -15,9 +15,43 @@ #define CRYINCLUDE_EDITOR_INCLUDE_IEDITORFILEMONITOR_H #pragma once -#include +struct IFileChangeListener +{ + enum EChangeType + { + //! error or unknown change type + eChangeType_Unknown, + //! the file was created + eChangeType_Created, + //! the file was deleted + eChangeType_Deleted, + //! the file was modified (size changed,write) + eChangeType_Modified, + //! this is the old name of a renamed file + eChangeType_RenamedOldName, + //! this is the new name of a renamed file + eChangeType_RenamedNewName + }; + + virtual ~IFileChangeListener() = default; + + virtual void OnFileChange(const char* sFilename, EChangeType eType) = 0; +}; -struct IFileChangeListener; +struct IFileChangeMonitor +{ + virtual ~IFileChangeMonitor() = default; + + // + // Register the path of a file or directory to monitor + // Path is relative to game directory, e.g. "Libs/WoundSystem/" or "Libs/WoundSystem/HitLocations.xml" + virtual bool RegisterListener(IFileChangeListener* pListener, const char* sMonitorItem) = 0; + // This function can be used to monitor files of specific type, e.g. + // RegisterListener(pListener, "Animations", "caf") + virtual bool RegisterListener(IFileChangeListener* pListener, const char* sFolder, const char* sExtension) = 0; + virtual bool UnregisterListener(IFileChangeListener* pListener) = 0; + // +}; struct IEditorFileMonitor : public IFileChangeMonitor diff --git a/Code/Sandbox/Editor/Include/ObjectEvent.h b/Code/Sandbox/Editor/Include/ObjectEvent.h index 3f6addb736..e90610872f 100644 --- a/Code/Sandbox/Editor/Include/ObjectEvent.h +++ b/Code/Sandbox/Editor/Include/ObjectEvent.h @@ -33,7 +33,6 @@ enum ObjectEvent EVENT_DBLCLICK, //!< Signals that object have been double clicked. EVENT_KEEP_HEIGHT, //!< Signals that object must preserve its height over changed terrain. EVENT_RELOAD_ENTITY,//!< Signals that entities scripts must be reloaded. - EVENT_RELOAD_TEXTURES,//!< Signals that all possible textures in objects should be reloaded. EVENT_RELOAD_GEOM, //!< Signals that all possible geometries should be reloaded. EVENT_UNLOAD_GEOM, //!< Signals that all possible geometries should be unloaded. EVENT_MISSION_CHANGE, //!< Signals that mission have been changed. diff --git a/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h b/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h index 4a20bd6b60..38a35e6684 100644 --- a/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h +++ b/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h @@ -32,7 +32,6 @@ public: public: MOCK_METHOD0(DeleteThis, void()); MOCK_METHOD0(GetSystem, ISystem*()); - MOCK_METHOD0(GetRenderer, IRenderer* ()); MOCK_METHOD0(GetClassFactory, IEditorClassFactory* ()); MOCK_METHOD0(GetCommandManager, CEditorCommandManager*()); MOCK_METHOD0(GetICommandManager, ICommandManager* ()); @@ -117,7 +116,6 @@ public: MOCK_METHOD1(SetMarkerPosition, void(const Vec3&)); MOCK_METHOD1(SetSelectedRegion, void(const AABB& box)); MOCK_METHOD1(GetSelectedRegion, void(AABB& box)); - MOCK_METHOD0(GetRuler, CRuler* ()); MOCK_METHOD1(SetOperationMode, void(EOperationMode )); MOCK_METHOD0(GetOperationMode, EOperationMode()); MOCK_METHOD1(ShowTransformManipulator, ITransformManipulator* (bool)); @@ -140,7 +138,6 @@ public: MOCK_METHOD1(OpenWinWidget, QWidget* (WinWidgetId )); MOCK_CONST_METHOD0(GetWinWidgetManager, WinWidget::WinWidgetManager* ()); MOCK_METHOD2(SelectColor, bool(QColor &, QWidget *)); - MOCK_METHOD0(GetShaderEnum, class CShaderEnum* ()); MOCK_METHOD0(GetUndoManager, class CUndoManager* ()); MOCK_METHOD0(BeginUndo, void()); MOCK_METHOD1(RestoreUndo, void(bool)); diff --git a/Code/Sandbox/Editor/MainWindow.cpp b/Code/Sandbox/Editor/MainWindow.cpp index e9bfd96a1d..b1d85c2999 100644 --- a/Code/Sandbox/Editor/MainWindow.cpp +++ b/Code/Sandbox/Editor/MainWindow.cpp @@ -66,7 +66,6 @@ AZ_POP_DISABLE_WARNING #include "AssetImporter/AssetImporterManager/AssetImporterDragAndDropHandler.h" #include "CryEdit.h" #include "Controls/ConsoleSCB.h" -#include "Grid.h" #include "ViewManager.h" #include "CryEditDoc.h" #include "ToolBox.h" @@ -78,6 +77,7 @@ AZ_POP_DISABLE_WARNING #include "Core/QtEditorApplication.h" #include "UndoDropDown.h" #include "CVarMenu.h" +#include "EditorViewportSettings.h" #include "KeyboardCustomizationSettings.h" #include "CustomizeKeyboardDialog.h" @@ -96,7 +96,6 @@ AZ_POP_DISABLE_WARNING #include "AzAssetBrowser/AzAssetBrowserWindow.h" #include "AssetEditor/AssetEditorWindow.h" -#include "GridSettingsDialog.h" #include "ActionManager.h" // uncomment this to show thumbnail demo widget @@ -122,12 +121,6 @@ static const char* g_openLocationAttributeName = "OpenLocation"; //Indicates whe static const char* g_assetImporterName = "AssetImporter"; -static const char* g_snapToGridEnabled = "mainwindow/snapGridEnabled"; -static const char* g_snapToGridSize = "mainwindow/snapGridSize"; -static const char* g_snapAngleEnabled = "mainwindow/snapAngleEnabled"; -static const char* g_snapAngle = "mainwindow/snapAngle"; -static const char* g_terrainFollow = "mainwindow/terrainFollow"; - class CEditorOpenViewCommand : public _i_reference_target_t { @@ -307,10 +300,8 @@ namespace class SnapToWidget : public QWidget - , public CGridSettingsDialog::NotificationBus::Handler { public: - typedef AZStd::function SetValueCallback; typedef AZStd::function GetValueCallback; @@ -334,12 +325,13 @@ public: m_spinBox->setEnabled(defaultAction->isChecked()); m_spinBox->setMinimum(1e-2f); - OnGridValuesUpdated(); + { + QSignalBlocker signalBlocker(m_spinBox); + m_spinBox->setValue(m_getValueCallback()); + } QObject::connect(m_spinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &SnapToWidget::OnValueChanged); QObject::connect(defaultAction, &QAction::changed, this, &SnapToWidget::OnActionChanged); - - CGridSettingsDialog::NotificationBus::Handler::BusConnect(); } void SetIcon(QIcon icon) @@ -347,14 +339,6 @@ public: m_toolButton->setIcon(icon); } - void OnGridValuesUpdated() override - { - // Blocking signals to not trigger the valueChanged callback when we set the value on the spin box. - QSignalBlocker signalBlocker(m_spinBox); - double value = m_getValueCallback(); - m_spinBox->setValue(value); - } - protected: void OnValueChanged(double value) @@ -542,7 +526,6 @@ void MainWindow::Initialize() RegisterStdViewClasses(); InitCentralWidget(); - LoadConfig(); InitActions(); // load toolbars ("shelves") and macros @@ -672,31 +655,8 @@ void MainWindow::closeEvent(QCloseEvent* event) QMainWindow::closeEvent(event); } -void MainWindow::LoadConfig() -{ - CGrid* grid = gSettings.pGrid; - Q_ASSERT(grid); - bool terrainValue; - - ReadConfigValue(g_snapAngleEnabled, grid->bAngleSnapEnabled); - ReadConfigValue(g_snapAngle, grid->angleSnap); - ReadConfigValue(g_snapToGridEnabled, grid->bEnabled); - ReadConfigValue(g_snapToGridSize, grid->size); - ReadConfigValue(g_terrainFollow, terrainValue); - GetIEditor()->SetTerrainAxisIgnoreObjects(terrainValue); -} - void MainWindow::SaveConfig() { - CGrid* grid = gSettings.pGrid; - Q_ASSERT(grid); - - m_settings.setValue(g_snapAngleEnabled, grid->bAngleSnapEnabled); - m_settings.setValue(g_snapAngle, grid->angleSnap); - m_settings.setValue(g_snapToGridEnabled, grid->bEnabled); - m_settings.setValue(g_snapToGridSize, grid->size); - m_settings.setValue(g_terrainFollow, GetIEditor()->IsTerrainAxisIgnoreObjects()); - m_settings.setValue("mainWindowState", saveState()); QtViewPaneManager::instance()->SaveLayout(); if (m_pLayoutWnd) @@ -915,13 +875,22 @@ void MainWindow::InitActions() .SetToolTip(tr("Snap to grid (G)")) .SetStatusTip(tr("Toggles snap to grid")) .SetCheckable(true) - .RegisterUpdateCallback(this, &MainWindow::OnUpdateSnapToGrid); + .RegisterUpdateCallback([](QAction* action) { + Q_ASSERT(action->isCheckable()); + action->setChecked(Editor::GridSnappingEnabled()); + }) + .Connect(&QAction::triggered, []() { Editor::SetGridSnapping(!Editor::GridSnappingEnabled()); }); + am->AddAction(ID_SNAPANGLE, tr("Snap angle")) .SetIcon(Style::icon("Angle")) .SetApplyHoverEffect() .SetStatusTip(tr("Snap angle")) .SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateSnapangle); + .RegisterUpdateCallback([](QAction* action) { + Q_ASSERT(action->isCheckable()); + action->setChecked(Editor::AngleSnappingEnabled()); + }) + .Connect(&QAction::triggered, []() { Editor::SetAngleSnapping(!Editor::AngleSnappingEnabled()); }); // Display actions am->AddAction(ID_WIREFRAME, tr("&Wireframe")) @@ -931,7 +900,6 @@ void MainWindow::InitActions() .SetStatusTip(tr("Render in Wireframe Mode.")) .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateWireframe); - am->AddAction(ID_VIEW_GRIDSETTINGS, tr("Grid Settings...")); am->AddAction(ID_SWITCHCAMERA_DEFAULTCAMERA, tr("Default Camera")).SetCheckable(true) .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateSwitchToDefaultCamera); am->AddAction(ID_SWITCHCAMERA_SEQUENCECAMERA, tr("Sequence Camera")).SetCheckable(true) @@ -1075,8 +1043,6 @@ void MainWindow::InitActions() .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateSelected); // Tools actions - am->AddAction(ID_RELOAD_TEXTURES, tr("Reload Textures/Shaders")) - .SetStatusTip(tr("Reload all textures.")); am->AddAction(ID_TOOLS_ENABLEFILECHANGEMONITORING, tr("Enable File Change Monitoring")); am->AddAction(ID_CLEAR_REGISTRY, tr("Clear Registry Data")) .SetStatusTip(tr("Clear Registry Data")); @@ -1434,12 +1400,12 @@ QWidget* MainWindow::CreateSnapToGridWidget() { SnapToWidget::SetValueCallback setCallback = [](double snapStep) { - GetIEditor()->GetViewManager()->GetGrid()->size = snapStep; + Editor::SetGridSnappingSize(snapStep); }; SnapToWidget::GetValueCallback getCallback = []() { - return GetIEditor()->GetViewManager()->GetGrid()->size; + return Editor::GridSnappingSize(); }; return new SnapToWidget(m_actionManager->GetAction(ID_SNAP_TO_GRID), setCallback, getCallback); @@ -1449,12 +1415,12 @@ QWidget* MainWindow::CreateSnapToAngleWidget() { SnapToWidget::SetValueCallback setCallback = [](double snapAngle) { - GetIEditor()->GetViewManager()->GetGrid()->angleSnap = snapAngle; + Editor::SetAngleSnappingSize(snapAngle); }; SnapToWidget::GetValueCallback getCallback = []() { - return GetIEditor()->GetViewManager()->GetGrid()->angleSnap; + return Editor::AngleSnappingSize(); }; return new SnapToWidget(m_actionManager->GetAction(ID_SNAPANGLE), setCallback, getCallback); @@ -1471,15 +1437,6 @@ MainStatusBar* MainWindow::StatusBar() const return static_cast(statusBar()); } -void MainWindow::OnUpdateSnapToGrid(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - bool bEnabled = gSettings.pGrid->IsEnabled(); - action->setChecked(bEnabled); - - action->setText(QObject::tr("Snap To Grid")); -} - KeyboardCustomizationSettings* MainWindow::GetShortcutManager() const { return m_keyboardCustomization; diff --git a/Code/Sandbox/Editor/MainWindow.h b/Code/Sandbox/Editor/MainWindow.h index adf271b383..ca8cc11677 100644 --- a/Code/Sandbox/Editor/MainWindow.h +++ b/Code/Sandbox/Editor/MainWindow.h @@ -191,9 +191,7 @@ private: void InitToolActionHandlers(); void InitToolBars(); void InitStatusBar(); - void OnUpdateSnapToGrid(QAction* action); void OnViewPaneCreated(const QtViewPane* pane); - void LoadConfig(); template void ReadConfigValue(const QString& key, TValue& value) diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.cpp b/Code/Sandbox/Editor/ModernViewportCameraController.cpp index 1c2771514f..f5df8d48ca 100644 --- a/Code/Sandbox/Editor/ModernViewportCameraController.cpp +++ b/Code/Sandbox/Editor/ModernViewportCameraController.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -64,17 +65,20 @@ namespace SandboxEditor } } - ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance(const AzFramework::ViewportId viewportId, ModernViewportCameraController* controller) + ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance( + const AzFramework::ViewportId viewportId, ModernViewportCameraController* controller) : MultiViewportControllerInstanceInterface(viewportId, controller) { controller->SetupCameras(m_cameraSystem.m_cameras); if (auto viewportContext = RetrieveViewportContext(GetViewportId())) { - auto handleCameraChange = [this](const AZ::Matrix4x4& matrix) { - UpdateCameraFromTransform( - m_targetCamera, - AZ::Transform::CreateFromMatrix3x3AndTranslation(AZ::Matrix3x3::CreateFromMatrix4x4(matrix), matrix.GetTranslation())); + auto handleCameraChange = [this, viewportContext](const AZ::Matrix4x4&) { + if (!m_updatingTransform) + { + UpdateCameraFromTransform(m_targetCamera, viewportContext->GetCameraTransform()); + m_camera = m_targetCamera; + } }; m_cameraViewMatrixChangeHandler = AZ::RPI::ViewportContext::MatrixChangedEvent::Handler(handleCameraChange); @@ -124,6 +128,8 @@ namespace SandboxEditor { if (auto viewportContext = RetrieveViewportContext(GetViewportId())) { + m_updatingTransform = true; + if (m_cameraMode == CameraMode::Control) { m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count()); @@ -155,6 +161,8 @@ namespace SandboxEditor viewportContext->SetCameraTransform(current); } + + m_updatingTransform = false; } } diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.h b/Code/Sandbox/Editor/ModernViewportCameraController.h index b1ff8d1039..edc034a78a 100644 --- a/Code/Sandbox/Editor/ModernViewportCameraController.h +++ b/Code/Sandbox/Editor/ModernViewportCameraController.h @@ -20,14 +20,13 @@ namespace SandboxEditor { class ModernViewportCameraControllerInstance; - class ModernViewportCameraController - : public AzFramework::MultiViewportController + class ModernViewportCameraController : public AzFramework::MultiViewportController { public: using CameraListBuilder = AZStd::function; + //! Sets the camera list builder callback used to populate new ModernViewportCameraControllerInstances void SetCameraListBuilderCallback(const CameraListBuilder& builder); - //! Sets up a camera list based on this controller's CameraListBuilderCallback void SetupCameras(AzFramework::Cameras& cameras); @@ -35,9 +34,9 @@ namespace SandboxEditor CameraListBuilder m_cameraListBuilder; }; - class ModernViewportCameraControllerInstance final - : public AzFramework::MultiViewportControllerInstanceInterface - , private AzFramework::ViewportDebugDisplayEventBus::Handler + class ModernViewportCameraControllerInstance final + : public AzFramework::MultiViewportControllerInstanceInterface, + private AzFramework::ViewportDebugDisplayEventBus::Handler { public: explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModernViewportCameraController* controller); @@ -65,6 +64,7 @@ namespace SandboxEditor AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); float m_animationT = 0.0f; CameraMode m_cameraMode = CameraMode::Control; + bool m_updatingTransform = false; AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler; }; diff --git a/Code/Sandbox/Editor/Objects/AxisGizmo.cpp b/Code/Sandbox/Editor/Objects/AxisGizmo.cpp index ef2b91685a..8e10d03080 100644 --- a/Code/Sandbox/Editor/Objects/AxisGizmo.cpp +++ b/Code/Sandbox/Editor/Objects/AxisGizmo.cpp @@ -18,7 +18,6 @@ // Editor #include "Viewport.h" #include "GizmoManager.h" -#include "Grid.h" #include "ViewManager.h" #include "Settings.h" #include "RenderHelpers/AxisHelper.h" @@ -244,7 +243,8 @@ Matrix34 CAxisGizmo::GetTransformation(RefCoordSys coordSys, IDisplayViewport* v break; case COORDS_USERDEFINED: { - Matrix34 userTM = GetIEditor()->GetViewManager()->GetGrid()->GetMatrix(); + Matrix34 userTM; + userTM.SetIdentity(); userTM.SetTranslation(m_object->GetWorldTM().GetTranslation()); return userTM; } diff --git a/Code/Sandbox/Editor/Objects/BaseObject.cpp b/Code/Sandbox/Editor/Objects/BaseObject.cpp index 3ec505172e..4c76f68f2f 100644 --- a/Code/Sandbox/Editor/Objects/BaseObject.cpp +++ b/Code/Sandbox/Editor/Objects/BaseObject.cpp @@ -894,314 +894,10 @@ void CBaseObject::DrawDefault(DisplayContext& dc, const QColor& labelColor) } ////////////////////////////////////////////////////////////////////////// -void CBaseObject::DrawDimensions(DisplayContext& dc, AABB* pMergedBoundBox) +void CBaseObject::DrawDimensions(DisplayContext&, AABB*) { - if (HasMeasurementAxis() && GetIEditor()->GetDisplaySettings()->IsDisplayDimensionFigures()) - { - AABB localBoundBox; - GetLocalBounds(localBoundBox); - DrawDimensionsImpl(dc, localBoundBox, pMergedBoundBox); - } } -////////////////////////////////////////////////////////////////////////// -void CBaseObject::DrawDimensionsImpl(DisplayContext& dc, const AABB& localBoundBox, AABB* pMergedBoundBox) -{ - AABB boundBox; - Matrix34 rotatedTM; - bool bHave2Axis(false); - float xLength(0); - float yLength(0); - float zLength(0); - - if (pMergedBoundBox) - { - rotatedTM = Matrix34::CreateIdentity(); - boundBox = *pMergedBoundBox; - xLength = boundBox.max.x - boundBox.min.x; - zLength = boundBox.max.z - boundBox.min.z; - yLength = boundBox.max.y - boundBox.min.y; - } - else - { - rotatedTM = GetWorldRotTM(); - Matrix34 scaledTranslatedTM = GetWorldScaleTM(); - scaledTranslatedTM.SetTranslation(GetWorldPos()); - boundBox.SetTransformedAABB(scaledTranslatedTM, localBoundBox); - - IVariable* pVarXLength(NULL); - IVariable* pVarYLength(NULL); - IVariable* pVarZLength(NULL); - - IVariable* pVarDimX(NULL); - IVariable* pVarDimY(NULL); - IVariable* pVarDimZ(NULL); - - CVarBlock* pVarBlock(GetVarBlock()); - if (pVarBlock) - { - pVarXLength = pVarBlock->FindVariable("Width"); - pVarYLength = pVarBlock->FindVariable("Length"); - pVarZLength = pVarBlock->FindVariable("Height"); - pVarDimX = pVarBlock->FindVariable("DimX"); - pVarDimY = pVarBlock->FindVariable("DimY"); - pVarDimZ = pVarBlock->FindVariable("DimZ"); - } - - xLength = boundBox.max.x - boundBox.min.x; - zLength = boundBox.max.z - boundBox.min.z; - yLength = boundBox.max.y - boundBox.min.y; - - if (pVarDimX && pVarDimY && pVarDimZ) - { - pVarDimX->Get(xLength); - pVarDimZ->Get(zLength); - pVarDimY->Get(yLength); - xLength *= m_scale.x; - zLength *= m_scale.z; - yLength *= m_scale.y; - } - else if (pVarXLength && pVarYLength && pVarZLength) - { - // A case of an area box. - pVarXLength->Get(xLength); - pVarZLength->Get(zLength); - pVarYLength->Get(yLength); - xLength *= m_scale.x; - zLength *= m_scale.z; - yLength *= m_scale.y; - } - else if (!pVarXLength && !pVarYLength && pVarZLength) - { - // A case of an area shape. - pVarZLength->Get(zLength); - zLength *= m_scale.z; - } - } - - const float kMinimumLimitation(0.4f); - if (xLength < kMinimumLimitation && yLength < kMinimumLimitation && zLength < kMinimumLimitation) - { - return; - } - - const float kEpsilon(0.001f); - bHave2Axis = fabs(zLength) < kEpsilon; - - Vec3 basePoints[] = { - Vec3(boundBox.min.x, boundBox.min.y, boundBox.min.z), - Vec3(boundBox.min.x, boundBox.max.y, boundBox.min.z), - Vec3(boundBox.max.x, boundBox.max.y, boundBox.min.z), - Vec3(boundBox.max.x, boundBox.min.y, boundBox.min.z), - Vec3(boundBox.min.x, boundBox.min.y, boundBox.max.z), - Vec3(boundBox.min.x, boundBox.max.y, boundBox.max.z), - Vec3(boundBox.max.x, boundBox.max.y, boundBox.max.z), - Vec3(boundBox.max.x, boundBox.min.y, boundBox.max.z) - }; - const int kElementSize(sizeof(basePoints) / sizeof(*basePoints)); - Vec3 axisDirections[kElementSize] = { Vec3(1, 1, 1), Vec3(1, -1, 1), Vec3(-1, -1, 1), Vec3(-1, 1, 1), Vec3(1, 1, -1), Vec3(1, -1, -1), Vec3(-1, -1, -1), Vec3(-1, 1, -1) }; - int nLoopCount = bHave2Axis ? (kElementSize / 2) : kElementSize; - if (bHave2Axis) - { - for (int i = 0; i < nLoopCount; ++i) - { - basePoints[i].z = 0.5f * (boundBox.min.z + boundBox.max.z); - } - } - - // Find out the nearest base point of a bounding box from a camera position and use it as a pivot. - const CCamera& camera = gEnv->pRenderer->GetCamera(); - Vec3 cameraPos(camera.GetPosition()); - Vec3 pivot(rotatedTM.TransformVector(basePoints[0] - GetWorldPos()) + GetWorldPos()); - float fNearestDist = (cameraPos - pivot).GetLength(); - int nNearestAxisIndex(0); - bool bPrevVisible(camera.IsPointVisible(pivot)); - - for (int i = 1; i < nLoopCount; ++i) - { - Vec3 candidatePivot(rotatedTM.TransformVector(basePoints[i] - GetWorldPos()) + GetWorldPos()); - float candidateLength = (candidatePivot - cameraPos).GetLength(); - bool bVisible = camera.IsPointVisible(candidatePivot); - if (bVisible) - { - if (!bPrevVisible || candidateLength < fNearestDist) - { - fNearestDist = candidateLength; - pivot = candidatePivot; - nNearestAxisIndex = i; - } - bPrevVisible = bVisible; - } - } - - float fScale = dc.view->GetScreenScaleFactor(pivot); - float fArrowScale = fScale * 0.04f; - - Vec3 vX(xLength, 0, 0); - Vec3 vY(0, yLength, 0); - Vec3 vZ(0, 0, zLength); - - vX = vX * axisDirections[nNearestAxisIndex].x; - vY = vY * axisDirections[nNearestAxisIndex].y; - vZ = vZ * axisDirections[nNearestAxisIndex].z; - vX = rotatedTM.TransformVector(vX); - vY = rotatedTM.TransformVector(vY); - vZ = rotatedTM.TransformVector(vZ); - - const float kArrowPivotOffset = 0.1f; - pivot = pivot + (-(vX + vY + vZ)).GetNormalized() * kArrowPivotOffset; - - Vec3 centerPt(boundBox.GetCenter()); - - // Display texts of width, height and depth - float fTextScale(1.3f); - dc.SetColor(QColor(200, 200, 200)); - QString str; - - const float kBrightness(0.35f); - const ColorF kXColor(1.0f, kBrightness, kBrightness, 0.9f); - const ColorF kYColor(kBrightness, 1.0f, kBrightness, 0.9f); - const ColorF kZColor(kBrightness, kBrightness, 1.0f, 0.9f); - const ColorF TextBoxColor(0, 0, 0, 0.75f); - - ColorB backupcolor = dc.GetColor(); - uint32 backupstate = dc.GetState(); - int backupThickness = dc.GetLineWidth(); - - dc.SetState(backupstate | e_DepthTestOff); - - Vec3 vNX = vX.GetNormalized(); - Vec3 vNY = vY.GetNormalized(); - Vec3 vNZ = vZ.GetNormalized(); - - const float kMinimumOffset(0.20f); - const float kMaximumOffset(30.0f); - float fMaximumOffset[3] = { kMaximumOffset, kMaximumOffset, kMaximumOffset }; - if (xLength > kMaximumOffset * 0.5f) - { - fMaximumOffset[0] = xLength * 3.0f; - } - if (yLength > kMaximumOffset * 0.5f) - { - fMaximumOffset[1] = yLength * 3.0f; - } - if (zLength > kMaximumOffset * 0.5f) - { - fMaximumOffset[2] = zLength * 3.0f; - } - Vec3 textPos[3] = {pivot, pivot, pivot}; - Vec3 textMinPos[3] = { pivot + vNX * kMinimumOffset, pivot + vNY * kMinimumOffset, pivot + vNZ * kMinimumOffset }; - Vec3 textCenterPos[3] = { pivot + vX * 0.5f, pivot + vY * 0.5f, pivot + vZ * 0.5f }; - Vec3 textMaxPos[3] = { pivot + vNX * fMaximumOffset[0], pivot + vNY * fMaximumOffset[1], pivot + vNZ * fMaximumOffset[2] }; - - const Vec3& cameraDir(camera.GetViewdir()); - - for (int i = 0; i < 3; ++i) - { - Vec3 d = (textMaxPos[i] - cameraPos).GetNormalized(); - float fCameraDir = d.Dot(cameraDir); - if (fCameraDir < 0) - { - fCameraDir = 0; - } - textPos[i] = textMinPos[i] + (textCenterPos[i] - textPos[i]) * fCameraDir; - } - - str = QString::number(xLength, 'f', 3); - DrawTextOn2DBox(dc, textPos[0], str.toUtf8().data(), fTextScale, kXColor, TextBoxColor); - - if (!bHave2Axis) - { - str = QString::number(zLength, 'f', 3); - DrawTextOn2DBox(dc, textPos[2], str.toUtf8().data(), fTextScale, kZColor, TextBoxColor); - } - - str = QString::number(yLength, 'f', 3); - DrawTextOn2DBox(dc, textPos[1], str.toUtf8().data(), fTextScale, kYColor, TextBoxColor); - - dc.SetState(backupstate | e_DepthTestOn); - dc.SetLineWidth(4); - - // Draw arrows of each axis. - dc.SetColor(kXColor); - dc.DrawArrow(pivot, pivot + vX, fArrowScale, true); - if (!bHave2Axis) - { - dc.SetColor(kZColor); - dc.DrawArrow(pivot, pivot + vZ, fArrowScale, true); - } - dc.SetColor(kYColor); - dc.DrawArrow(pivot, pivot + vY, fArrowScale, true); - - dc.SetState(backupstate); - dc.SetColor(backupcolor); - dc.SetLineWidth(backupThickness); -} - -////////////////////////////////////////////////////////////////////////// -void CBaseObject::DrawTextOn2DBox(DisplayContext& dc, const Vec3& pos, const char* text, float textScale, const ColorF& TextColor, const ColorF& TextBackColor) -{ - Vec3 worldPos = dc.ToWorldSpacePosition(pos); - int vx, vy, vw, vh; - gEnv->pRenderer->GetViewport(&vx, &vy, &vw, &vh); - - const CCamera& camera = gEnv->pRenderer->GetCamera(); - Vec3 screenPos; - camera.Project(worldPos, screenPos, Vec2i(0, 0), Vec2i(0, 0)); - - //! Font size information doesn't seem to exist so the proper size is used - int textlen = strlen(text); - float fontsize = 7.5f; - float textwidth = fontsize * textlen; - float textheight = 16.0f; - - screenPos.x = screenPos.x - textwidth * 0.5f; - - Vec3 textregion[4] = { - Vec3(screenPos.x, screenPos.y, screenPos.z), - Vec3(screenPos.x + textwidth, screenPos.y, screenPos.z), - Vec3(screenPos.x + textwidth, screenPos.y + textheight, screenPos.z), - Vec3(screenPos.x, screenPos.y + textheight, screenPos.z) - }; - - Vec3 textworldreign[4]; - Matrix34 dcInvTm = dc.GetMatrix().GetInverted(); - - Matrix44A mProj, mView; - mathMatrixPerspectiveFov(&mProj, camera.GetFov(), camera.GetProjRatio(), camera.GetNearPlane(), camera.GetFarPlane()); - mathMatrixLookAt(&mView, camera.GetPosition(), camera.GetPosition() + camera.GetViewdir(), Vec3(0, 0, 1)); - Matrix44A mInvViewProj = (mView * mProj).GetInverted(); - - for (int i = 0; i < 4; ++i) - { - Vec4 projectedpos = Vec4((textregion[i].x - vx) / vw * 2.0f - 1.0f, - -((textregion[i].y - vy) / vh) * 2.0f + 1.0f, - textregion[i].z, - 1.0f); - - Vec4 wp = projectedpos * mInvViewProj; - wp.x /= wp.w; - wp.y /= wp.w; - wp.z /= wp.w; - textworldreign[i] = dcInvTm.TransformPoint(Vec3(wp.x, wp.y, wp.z)); - } - - ColorB backupcolor = dc.GetColor(); - uint32 backupstate = dc.GetState(); - - dc.SetColor(TextBackColor); - dc.SetDrawInFrontMode(true); - - dc.DrawQuad(textworldreign[3], textworldreign[2], textworldreign[1], textworldreign[0]); - dc.SetColor(TextColor); - dc.DrawTextLabel(pos, textScale, text); - - dc.SetDrawInFrontMode(false); - dc.SetColor(backupcolor); - dc.SetState(backupstate); -} - - ////////////////////////////////////////////////////////////////////////// void CBaseObject::DrawSelectionHelper(DisplayContext& dc, const Vec3& pos, const QColor& labelColor, [[maybe_unused]] float alpha) { @@ -1572,12 +1268,6 @@ int CBaseObject::MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& if (event == eMouseWheel) { double angle = 1; - - if (view->GetViewManager()->GetGrid()->IsAngleSnapEnabled()) - { - angle = view->GetViewManager()->GetGrid()->GetAngleSnap(); - } - Quat rot = GetRotation(); rot.SetRotationXYZ(Ang3(0, 0, rot.GetRotZ() + DEG2RAD(flags > 0 ? angle * (-1) : angle))); SetRotation(rot); diff --git a/Code/Sandbox/Editor/Objects/BaseObject.h b/Code/Sandbox/Editor/Objects/BaseObject.h index 5d6f800a58..73e2394f6c 100644 --- a/Code/Sandbox/Editor/Objects/BaseObject.h +++ b/Code/Sandbox/Editor/Objects/BaseObject.h @@ -604,9 +604,6 @@ public: virtual IStatObj* GetIStatObj() { return NULL; } - //! Display length of each axis. - void DrawDimensionsImpl(DisplayContext& dc, const AABB& localBoundBox, AABB* pMergedBoundBox = NULL); - // Invalidates cached transformation matrix. // nWhyFlags - Flags that indicate the reason for matrix invalidation. virtual void InvalidateTM(int nWhyFlags); @@ -678,8 +675,6 @@ protected: virtual void DrawTextureIcon(DisplayContext& dc, const Vec3& pos, float alpha = 1.0f); //! Draw warning icons virtual void DrawWarningIcons(DisplayContext& dc, const Vec3& pos); - //! Display text with a 3d world coordinate. - void DrawTextOn2DBox(DisplayContext& dc, const Vec3& pos, const char* text, float textScale, const ColorF& TextColor, const ColorF& TextBackColor); //! Check if dimension's figures can be displayed before draw them. virtual void DrawDimensions(DisplayContext& dc, AABB* pMergedBoundBox = NULL); diff --git a/Code/Sandbox/Editor/Objects/DisplayContext.h b/Code/Sandbox/Editor/Objects/DisplayContext.h index 13363a923e..de33388eb4 100644 --- a/Code/Sandbox/Editor/Objects/DisplayContext.h +++ b/Code/Sandbox/Editor/Objects/DisplayContext.h @@ -227,7 +227,6 @@ struct SANDBOX_API DisplayContext void DrawTextLabel(const Vec3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int scrOffsetY = 0); void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false); - void DrawTextOn2DBox(const Vec3& pos, const char* text, float textScale, const ColorF& TextColor, const ColorF& TextBackColor); void SetLineWidth(float width); //! Is given bbox visible in this display context. diff --git a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl index 4d284faea7..419b7c0406 100644 --- a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl +++ b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl @@ -37,7 +37,7 @@ DisplayContext::DisplayContext() m_currentMatrix = 0; m_matrixStack[m_currentMatrix].SetIdentity(); - pRenderAuxGeom = gEnv->pRenderer ? gEnv->pRenderer->GetIRenderAuxGeom() : nullptr; + pRenderAuxGeom = nullptr; // ToDo: Remove DisplayContext or update to work with Atom: LYN-3670 m_thickness = 0; m_width = 0; @@ -1105,85 +1105,6 @@ void DisplayContext::Draw2dTextLabel(float x, float y, float size, const char* t renderer->Draw2dLabel(x, y, size, col, bCenter, "%s", text); } -void DisplayContext::DrawTextOn2DBox(const Vec3& pos, const char* text, float textScale, const ColorF& TextColor, const ColorF& TextBackColor) -{ - Vec3 worldPos = ToWorldSpacePosition(pos); - int vx, vy, vw, vh; - gEnv->pRenderer->GetViewport(&vx, &vy, &vw, &vh); - uint32 backupstate = GetState(); - - SetState(backupstate | e_DepthTestOff); - - const CCamera& renderCamera = gEnv->pRenderer->GetCamera(); - Vec3 screenPos; - - renderCamera.Project(worldPos, screenPos, Vec2i(0, 0), Vec2i(0, 0)); - - //! Font size information doesn't seem to exist so the proper size is used - int textlen = strlen(text); - float fontsize = 7.5f * textScale; - float textwidth = fontsize * textlen; - float textheight = 16.0f * textScale; - - screenPos.x = screenPos.x - (textwidth * 0.5f); - - Vec3 textregion[4] = { - Vec3(screenPos.x, screenPos.y, screenPos.z), - Vec3(screenPos.x + textwidth, screenPos.y, screenPos.z), - Vec3(screenPos.x + textwidth, screenPos.y + textheight, screenPos.z), - Vec3(screenPos.x, screenPos.y + textheight, screenPos.z) - }; - - Vec3 textworldreign[4]; - Matrix34 dcInvTm = GetMatrix().GetInverted(); - - Matrix44A mProj, mView; - mathMatrixPerspectiveFov(&mProj, renderCamera.GetFov(), renderCamera.GetProjRatio(), renderCamera.GetNearPlane(), renderCamera.GetFarPlane()); - mathMatrixLookAt(&mView, renderCamera.GetPosition(), renderCamera.GetPosition() + renderCamera.GetViewdir(), Vec3(0, 0, 1)); - Matrix44A mInvViewProj = (mView * mProj).GetInverted(); - - if (vw == 0) - { - vw = 1; - } - - if (vh == 0) - { - vh = 1; - } - - for (int i = 0; i < 4; ++i) - { - Vec4 projectedpos = Vec4((textregion[i].x - vx) / vw * 2.0f - 1.0f, - -((textregion[i].y - vy) / vh) * 2.0f + 1.0f, - textregion[i].z, - 1.0f); - - Vec4 wp = projectedpos * mInvViewProj; - - if (wp.w == 0.0f) - { - wp.w = 0.0001f; - } - - wp.x /= wp.w; - wp.y /= wp.w; - wp.z /= wp.w; - textworldreign[i] = dcInvTm.TransformPoint(Vec3(wp.x, wp.y, wp.z)); - } - - ColorB backupcolor = GetColor(); - - SetColor(TextBackColor); - SetDrawInFrontMode(true); - DrawQuad(textworldreign[3], textworldreign[2], textworldreign[1], textworldreign[0]); - SetColor(TextColor); - DrawTextLabel(pos, textScale, text); - SetDrawInFrontMode(false); - SetColor(backupcolor); - SetState(backupstate); -} - ////////////////////////////////////////////////////////////////////////// void DisplayContext::SetLineWidth(float width) { diff --git a/Code/Sandbox/Editor/Objects/SelectionGroup.cpp b/Code/Sandbox/Editor/Objects/SelectionGroup.cpp index 98e00645ee..a2c88c7302 100644 --- a/Code/Sandbox/Editor/Objects/SelectionGroup.cpp +++ b/Code/Sandbox/Editor/Objects/SelectionGroup.cpp @@ -342,7 +342,8 @@ void CSelectionGroup::Rotate(const Matrix34& rotateTM, int referenceCoordSys) if (referenceCoordSys == COORDS_USERDEFINED) { - Matrix34 userTM = GetIEditor()->GetViewManager()->GetGrid()->GetMatrix(); + Matrix34 userTM; + userTM.SetIdentity(); Matrix34 invUserTM = userTM.GetInvertedFast(); ToOrigin = invUserTM * ToOrigin; diff --git a/Code/Sandbox/Editor/PythonEditorFuncs.cpp b/Code/Sandbox/Editor/PythonEditorFuncs.cpp index 29cb8eb478..afd28f7070 100644 --- a/Code/Sandbox/Editor/PythonEditorFuncs.cpp +++ b/Code/Sandbox/Editor/PythonEditorFuncs.cpp @@ -31,7 +31,6 @@ #include "ViewManager.h" #include "StringDlg.h" #include "GenericSelectItemDialog.h" -#include "Util/Ruler.h" #include "Objects/BaseObject.h" #include "Commands/CommandManager.h" @@ -608,8 +607,9 @@ namespace } else { - float color[] = {r, g, b, a}; - gEnv->pRenderer->Draw2dLabel(x, y, size, color, false, pLabel); + // ToDo: Remove function or update to work with Atom? LYN-3672 + // float color[] = {r, g, b, a}; + // ???->Draw2dLabel(x, y, size, color, false, pLabel); } } diff --git a/Code/Sandbox/Editor/RenderViewport.cpp b/Code/Sandbox/Editor/RenderViewport.cpp index 49064b5bc5..f199590e4f 100644 --- a/Code/Sandbox/Editor/RenderViewport.cpp +++ b/Code/Sandbox/Editor/RenderViewport.cpp @@ -1993,28 +1993,27 @@ AzFramework::CameraState CRenderViewport::GetCameraState() bool CRenderViewport::GridSnappingEnabled() { - return GetViewManager()->GetGrid()->IsEnabled(); + return false; } float CRenderViewport::GridSize() { - const CGrid* grid = GetViewManager()->GetGrid(); - return grid->scale * grid->size; + return 0.0f; } bool CRenderViewport::ShowGrid() { - return gSettings.viewports.bShowGridGuide; + return false; } bool CRenderViewport::AngleSnappingEnabled() { - return GetViewManager()->GetGrid()->IsAngleSnapEnabled(); + return false; } float CRenderViewport::AngleStep() { - return GetViewManager()->GetGrid()->GetAngleSnap(); + return 0.0f; } AZ::Vector3 CRenderViewport::PickTerrain(const AzFramework::ScreenPoint& point) @@ -3890,94 +3889,13 @@ void CRenderViewport::ActivateWindowAndSetFocus() ////////////////////////////////////////////////////////////////////////// void CRenderViewport::RenderConstructionPlane() { - DisplayContext& dc = m_displayContext; - - int prevState = dc.GetState(); - dc.DepthWriteOff(); - // Draw Construction plane. - - CGrid* pGrid = GetViewManager()->GetGrid(); - - RefCoordSys coordSys = COORDS_WORLD; - - Vec3 p = m_constructionMatrix[coordSys].GetTranslation(); - Vec3 n = m_constructionPlane.n; - - Vec3 u = Vec3(1, 0, 0); - Vec3 v = Vec3(0, 1, 0); - - - if (gSettings.snap.bGridUserDefined) - { - Ang3 angles = Ang3(pGrid->rotationAngles.x * gf_PI / 180.0, pGrid->rotationAngles.y * gf_PI / 180.0, pGrid->rotationAngles.z * gf_PI / 180.0); - Matrix34 tm = Matrix33::CreateRotationXYZ(angles); - - u = tm * u; - v = tm * v; - } - - float step = pGrid->scale * pGrid->size; - float size = gSettings.snap.constructPlaneSize; - - dc.SetColor(0, 0, 1, 0.1f); - - float s = size; - - dc.DrawQuad(p - u * s - v * s, p + u * s - v * s, p + u * s + v * s, p - u * s + v * s); - - int nSteps = int(size / step); - int i; - // Draw X lines. - dc.SetColor(1, 0, 0.2f, 0.3f); - - for (i = -nSteps; i <= nSteps; i++) - { - dc.DrawLine(p - u * size + v * (step * i), p + u * size + v * (step * i)); - } - // Draw Y lines. - dc.SetColor(0.2f, 1.0f, 0, 0.3f); - for (i = -nSteps; i <= nSteps; i++) - { - dc.DrawLine(p - v * size + u * (step * i), p + v * size + u * (step * i)); - } - - // Draw origin lines. - - dc.SetLineWidth(2); - - //X - dc.SetColor(1, 0, 0); - dc.DrawLine(p - u * s, p + u * s); - - //Y - dc.SetColor(0, 1, 0); - dc.DrawLine(p - v * s, p + v * s); - - //Z - dc.SetColor(0, 0, 1); - dc.DrawLine(p - n * s, p + n * s); - - dc.SetLineWidth(0); - - dc.SetState(prevState); + // noop } ////////////////////////////////////////////////////////////////////////// void CRenderViewport::RenderSnappingGrid() { - // First, Check whether we should draw the grid or not. - CGrid* pGrid = GetViewManager()->GetGrid(); - if (pGrid->IsEnabled() == false && pGrid->IsAngleSnapEnabled() == false) - { - return; - } - - DisplayContext& dc = m_displayContext; - - int prevState = dc.GetState(); - dc.DepthWriteOff(); - - dc.SetState(prevState); + // noop } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/Resource.h b/Code/Sandbox/Editor/Resource.h index ea8ec828cf..31fc9909f1 100644 --- a/Code/Sandbox/Editor/Resource.h +++ b/Code/Sandbox/Editor/Resource.h @@ -79,7 +79,6 @@ #define ID_EDIT_HIDE 32898 #define ID_EDIT_UNHIDEALL 32899 #define ID_RELOAD_TERRAIN 32902 -#define ID_VIEW_GRIDSETTINGS 32904 #define ID_VIEW_CONFIGURELAYOUT 32906 #define ID_TOOLS_LOGMEMORYUSAGE 32908 #define ID_TERRAIN_EXPORTBLOCK 32909 @@ -99,7 +98,6 @@ #define ID_FILE_SAVELEVELRESOURCES 32942 #define ID_VALIDATELEVEL 32943 #define ID_TERRAIN_RESIZE 32944 -#define ID_RELOAD_TEXTURES 32952 #define ID_TERRAIN_COLLISION 32960 #define ID_TOOL_FIRST 32972 #define ID_EDIT_UNFREEZE 32973 diff --git a/Code/Sandbox/Editor/Settings.h b/Code/Sandbox/Editor/Settings.h index 93e61bc1ed..b4609555df 100644 --- a/Code/Sandbox/Editor/Settings.h +++ b/Code/Sandbox/Editor/Settings.h @@ -40,8 +40,6 @@ #include -class CGrid; - struct SGizmoSettings { float axisGizmoSize; @@ -393,9 +391,6 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING //! Keeps the editor active even if no focus is set int keepEditorActive; - //! Pointer to currently used grid. - CGrid* pGrid; - SGizmoSettings gizmo; // Settings of the snapping. diff --git a/Code/Sandbox/Editor/ShaderCache.cpp b/Code/Sandbox/Editor/ShaderCache.cpp deleted file mode 100644 index 3beeb9a7c4..0000000000 --- a/Code/Sandbox/Editor/ShaderCache.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "ShaderCache.h" - -// Editor -#include "GameEngine.h" - - -////////////////////////////////////////////////////////////////////////// -bool CLevelShaderCache::Reload() -{ - return Load(m_filename.toUtf8().data()); -} - -////////////////////////////////////////////////////////////////////////// -bool CLevelShaderCache::Load(const char* filename) -{ - FILE* f = nullptr; - azfopen(&f, filename, "rt"); - if (!f) - { - return false; - } - - int nNumLines = 0; - m_entries.clear(); - m_filename = filename; - char str[65535]; - while (fgets(str, sizeof(str), f) != NULL) - { - if (str[0] == '<') - { - m_entries.insert(str); - nNumLines++; - } - } - fclose(f); - if (nNumLines == m_entries.size()) - { - m_bModified = false; - } - else - { - m_bModified = true; - } - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CLevelShaderCache::LoadBuffer(const QString& textBuffer, bool bClearOld) -{ - const char* separators = "\r\n,"; - - int nNumLines = 0; - if (bClearOld) - { - m_entries.clear(); - } - m_filename = ""; - - for (auto resToken : textBuffer.split(QRegularExpression(QStringLiteral("[%1]").arg(separators)), Qt::SkipEmptyParts)) - { - if (!resToken.isEmpty() && resToken[0] == '<') - { - m_entries.insert(resToken); - nNumLines++; - } - } - if (nNumLines == m_entries.size() && !bClearOld) - { - m_bModified = false; - } - else - { - m_bModified = true; - } - - int numShaders = m_entries.size(); - CLogFile::FormatLine("%d shader combination loaded for level %s", numShaders, GetIEditor()->GetGameEngine()->GetLevelPath().toUtf8().data()); - - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CLevelShaderCache::Save() -{ - if (m_filename.isEmpty()) - { - return false; - } - - Update(); - - FILE* f = nullptr; - azfopen(&f, m_filename.toUtf8().data(), "wt"); - if (f) - { - for (Entries::iterator it = m_entries.begin(); it != m_entries.end(); ++it) - { - fputs(it->toLatin1().data(), f); - } - fclose(f); - } - m_bModified = false; - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CLevelShaderCache::SaveBuffer(QString& textBuffer) -{ - Update(); - - textBuffer.reserve(m_entries.size() * 1024); - for (Entries::iterator it = m_entries.begin(); it != m_entries.end(); ++it) - { - textBuffer += (*it); - textBuffer += "\n"; - } - m_bModified = false; - - return true; -} - -////////////////////////////////////////////////////////////////////////// -void CLevelShaderCache::Update() -{ - IRenderer* pRenderer = gEnv->pRenderer; - if (pRenderer) - { - QString buf; - char* str = NULL; - pRenderer->EF_Query(EFQ_GetShaderCombinations, str); - if (str) - { - buf = str; - pRenderer->EF_Query(EFQ_DeleteMemoryArrayPtr, str); - } - LoadBuffer(buf, true); - } -} - -////////////////////////////////////////////////////////////////////////// -void CLevelShaderCache::Clear() -{ - m_entries.clear(); - m_bModified = true; -} - -////////////////////////////////////////////////////////////////////////// -void CLevelShaderCache::ActivateShaders() -{ - bool bPreload = false; - ICVar* pSysPreload = gEnv->pConsole->GetCVar("sys_preload"); - if (pSysPreload && pSysPreload->GetIVal() != 0) - { - bPreload = true; - } - - if (bPreload) - { - QString textBuffer; - textBuffer.reserve(m_entries.size() * 1024); - for (Entries::iterator it = m_entries.begin(); it != m_entries.end(); ++it) - { - textBuffer += (*it); - textBuffer += "\n"; - } - gEnv->pRenderer->EF_Query(EFQ_SetShaderCombinations, textBuffer); - } -} diff --git a/Code/Sandbox/Editor/ShaderCache.h b/Code/Sandbox/Editor/ShaderCache.h deleted file mode 100644 index c75ab1554f..0000000000 --- a/Code/Sandbox/Editor/ShaderCache.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_SHADERCACHE_H -#define CRYINCLUDE_EDITOR_SHADERCACHE_H -#pragma once - -////////////////////////////////////////////////////////////////////////// -class CLevelShaderCache -{ -public: - CLevelShaderCache() - { - m_bModified = false; - } - bool Load(const char* filename); - bool LoadBuffer(const QString& textBuffer, bool bClearOld = true); - bool SaveBuffer(QString& textBuffer); - bool Save(); - bool Reload(); - void Clear(); - - void Update(); - void ActivateShaders(); - -private: - ////////////////////////////////////////////////////////////////////////// - bool m_bModified; - QString m_filename; - typedef std::set Entries; - Entries m_entries; -}; - - -#endif // CRYINCLUDE_EDITOR_SHADERCACHE_H diff --git a/Code/Sandbox/Editor/ShaderEnum.cpp b/Code/Sandbox/Editor/ShaderEnum.cpp deleted file mode 100644 index 65518303ce..0000000000 --- a/Code/Sandbox/Editor/ShaderEnum.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Enumerate Installed Shaders. - - -#include "EditorDefs.h" - -#include "ShaderEnum.h" - -////////////////////////////////////////////////////////////////////////// -CShaderEnum::CShaderEnum() -{ - m_bEnumerated = false; -} - -CShaderEnum::~CShaderEnum() -{ -} - - -inline bool ShaderLess(const CShaderEnum::ShaderDesc& s1, const CShaderEnum::ShaderDesc& s2) -{ - return QString::compare(s1.name, s2.name, Qt::CaseInsensitive) < 0; -} -/* -struct StringLess { - bool operator()( const CString &s1,const CString &s2 ) - { - return _stricmp( s1,s2 ) < 0; - } -}; -*/ - -//! Enum shaders. -int CShaderEnum::EnumShaders() -{ - IRenderer* renderer = GetIEditor()->GetSystem()->GetIRenderer(); - if (!renderer) - { - return 0; - } - - m_bEnumerated = true; - - m_shaders.clear(); - m_shaders.reserve(100); - //! Enumerate Shaders. - int nNumShaders = 0; - string* files = renderer->EF_GetShaderNames(nNumShaders); - for (int i = 0; i < nNumShaders; i++) - { - ShaderDesc sd; - sd.name = files[i].c_str(); - sd.file = files[i].c_str(); - if (!sd.name.isEmpty()) - { - // Capitalize first character of the string. - sd.name[0] = sd.name[0].toUpper(); - } - m_shaders.push_back(sd); - } - - XmlNodeRef root = GetISystem()->GetXmlUtils()->LoadXmlFromFile("Materials/ShaderList.xml"); - if (root) - { - for (int i = 0; i < root->getChildCount(); ++i) - { - XmlNodeRef ChildNode = root->getChild(i); - const char* pTagName = ChildNode->getTag(); - if (!_stricmp(pTagName, "Shader")) - { - QString name; - if (ChildNode->getAttr("name", name) && !name.isEmpty()) - { - // make sure there is no duplication - bool isUnique = true; - for (std::vector::iterator pSD = m_shaders.begin(); pSD != m_shaders.end(); ++pSD) - { - if (!QString::compare((*pSD).file, name, Qt::CaseInsensitive)) - { - isUnique = false; - break; - } - } - if (isUnique) - { - ShaderDesc sd; - sd.name = name; - sd.file = name.toLower(); - m_shaders.push_back(sd); - } - } - } - } - } - - std::sort(m_shaders.begin(), m_shaders.end(), ShaderLess); - return m_shaders.size(); -} - -int CShaderEnum::GetShaderCount() const -{ - return m_shaders.size(); -} - -QString CShaderEnum::GetShader(int i) const -{ - return m_shaders[i].name; -} - -QString CShaderEnum::GetShaderFile(int i) const -{ - return m_shaders[i].file; -} diff --git a/Code/Sandbox/Editor/ShaderEnum.h b/Code/Sandbox/Editor/ShaderEnum.h deleted file mode 100644 index ccc86bd089..0000000000 --- a/Code/Sandbox/Editor/ShaderEnum.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Enumerate Installed Shaders. - - -#ifndef CRYINCLUDE_EDITOR_SHADERENUM_H -#define CRYINCLUDE_EDITOR_SHADERENUM_H - -#pragma once - -/*! - * CShaderEnum class enumerates shaders installed on system. - * It scans all effector files, and gather from them all defined effectors. - */ -class CShaderEnum -{ -public: - struct ShaderDesc - { - QString name; - QString file; - }; - - CShaderEnum(); - virtual ~CShaderEnum(); - - //! Enumerate shaders installed on system. - //! @return Number of enumerated shaders. - virtual int EnumShaders(); - - //! Get number of shaders in system. - //! @return Number of installed shaders. - virtual int GetShaderCount() const; - - //! Get name of shader by index. - //! index must be between 0 and number returned by EnumShaders. - //! @return Name of shader. - virtual QString GetShader(int i) const; - virtual QString GetShaderFile(int i) const; - -private: - bool m_bEnumerated; - - //! Array of shader names. - std::vector m_shaders; -}; - - -#endif // CRYINCLUDE_EDITOR_SHADERENUM_H diff --git a/Code/Sandbox/Editor/ShadersDialog.cpp b/Code/Sandbox/Editor/ShadersDialog.cpp deleted file mode 100644 index 6a09d00232..0000000000 --- a/Code/Sandbox/Editor/ShadersDialog.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "ShadersDialog.h" - -// Qt -#include - -// Editor -#include "ShaderEnum.h" - - -AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING -#include -AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - -///////////////////////////////////////////////////////////////////////////// -// CShadersDialog dialog - - -CShadersDialog::CShadersDialog(const QString& selection, QWidget* pParent /*=NULL*/) - : QDialog(pParent) - , m_shadersModel(new QStringListModel(this)) - , ui(new Ui::CShadersDialog) - , m_selection(selection) -{ - ui->setupUi(this); - ui->m_shaders->setModel(m_shadersModel); - OnInitDialog(); - - connect(ui->m_shaders->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CShadersDialog::OnSelchangeShaders); - connect(ui->m_shaders, &QListView::doubleClicked, this, &CShadersDialog::OnDblclkShaders); - connect(ui->m_shaderText, &QTextEdit::textChanged, this, &CShadersDialog::OnEnChangeText); - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(ui->m_saveButton, &QPushButton::clicked, this, &CShadersDialog::OnBnClickedSave); - connect(ui->m_editButton, &QPushButton::clicked, this, &CShadersDialog::OnBnClickedEdit); -} - - -CShadersDialog::~CShadersDialog() -{ -} - - -void CShadersDialog::OnSelchangeShaders() -{ - // When shader changes. - // Edit shader file. - auto index = ui->m_shaders->currentIndex(); - if (index.isValid()) - { - QString file = GetIEditor()->GetShaderEnum()->GetShaderFile(index.row()); - file.replace('/', '\\'); - ui->m_shaderText->LoadFile(file); - // Just loaded file.. Not savable. - ui->m_saveButton->setEnabled(false); - - QString shaderName = QStringLiteral("'%1'").arg(index.data().toString()); - - if (ui->m_shaderText->find(shaderName)) - { - auto cursor = ui->m_shaderText->textCursor(); - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, shaderName.size()); - } - - m_selection = index.data().toString(); - } -} - -void CShadersDialog::OnInitDialog() -{ - QWaitCursor wait; - - // Fill with shaders. - CShaderEnum* shaderEnum = GetIEditor()->GetShaderEnum(); - int numShaders = shaderEnum->EnumShaders(); - - QStringList shaders; - for (int i = 0; i < numShaders; i++) - { - shaders.append(shaderEnum->GetShader(i)); - } - m_shadersModel->setStringList(shaders); - - /* - if (numShaders > 0) - { - int i = m_shaders.FindString(m_sel); - if (i != LB_ERR) - m_shaders.SetCurSel( i ); - } - */ -} - -void CShadersDialog::OnDblclkShaders() -{ - // Same as IDOK. - accept(); -} - -void CShadersDialog::OnBnClickedEdit() -{ - // Edit shader file. - auto index = ui->m_shaders->currentIndex(); - if (index.isValid()) - { - CShaderEnum* shaderEnum = GetIEditor()->GetShaderEnum(); - QString file = shaderEnum->GetShaderFile(index.row()); - CFileUtil::EditTextFile(file.toUtf8().data(), IFileUtil::FILE_TYPE_SHADER); - } -} - -////////////////////////////////////////////////////////////////////////// -void CShadersDialog::OnBnClickedSave() -{ - if (ui->m_shaderText->IsModified()) - { - ui->m_shaderText->SaveFile(ui->m_shaderText->GetFilename()); - if (ui->m_shaderText->IsModified()) - { - ui->m_saveButton->setEnabled(true); - } - else - { - ui->m_saveButton->setEnabled(false); - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CShadersDialog::OnEnChangeText() -{ - // File can be saved. - ui->m_saveButton->setEnabled(true); -} - -#include diff --git a/Code/Sandbox/Editor/ShadersDialog.h b/Code/Sandbox/Editor/ShadersDialog.h deleted file mode 100644 index bafad56a8f..0000000000 --- a/Code/Sandbox/Editor/ShadersDialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_SHADERSDIALOG_H -#define CRYINCLUDE_EDITOR_SHADERSDIALOG_H - -#pragma once -// ShadersDialog.h : header file -// - -#if !defined(Q_MOC_RUN) -#include -#endif - -class QStringListModel; - -namespace Ui { - class CShadersDialog; -} - -///////////////////////////////////////////////////////////////////////////// -// CShadersDialog dialog - -class CShadersDialog - : public QDialog -{ - Q_OBJECT - - // Construction -public: - CShadersDialog(const QString& selection, QWidget* pParent = nullptr); // standard constructor - ~CShadersDialog(); - - QString m_selection; - - QString GetSelection() { return m_selection; }; - -protected: - void OnSelchangeShaders(); - virtual void OnInitDialog(); - void OnDblclkShaders(); - -public: - void OnBnClickedEdit(); - void OnBnClickedSave(); - void OnEnChangeText(); - - QStringListModel* m_shadersModel; - QScopedPointer ui; -}; - -#endif // CRYINCLUDE_EDITOR_SHADERSDIALOG_H diff --git a/Code/Sandbox/Editor/ShadersDialog.ui b/Code/Sandbox/Editor/ShadersDialog.ui deleted file mode 100644 index c103cd0dec..0000000000 --- a/Code/Sandbox/Editor/ShadersDialog.ui +++ /dev/null @@ -1,118 +0,0 @@ - - - CShadersDialog - - - - 0 - 0 - 615 - 458 - - - - Select Shader - - - - - - - - - - Select Shader - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - - - - - Shader Script - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - - - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Save - - - - - - - External Edit - - - - - - - - - - CTextEditorCtrl - QTextEdit -
Controls/TextEditorCtrl.h
-
-
- - -
diff --git a/Code/Sandbox/Editor/TopRendererWnd.cpp b/Code/Sandbox/Editor/TopRendererWnd.cpp index bc979902e7..78fce1bc24 100644 --- a/Code/Sandbox/Editor/TopRendererWnd.cpp +++ b/Code/Sandbox/Editor/TopRendererWnd.cpp @@ -150,7 +150,7 @@ void QTopRendererWnd::UpdateContent(int flags) } ////////////////////////////////////////////////////////////////////////// -void QTopRendererWnd::Draw(DisplayContext& dc) +void QTopRendererWnd::Draw([[maybe_unused]] DisplayContext& dc) { FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR); @@ -165,7 +165,8 @@ void QTopRendererWnd::Draw(DisplayContext& dc) //////////////////////////////////////////////////////////////////////// // Render the 2D map //////////////////////////////////////////////////////////////////////// - if (!m_terrainTextureId) + // ToDo: Remove TopRendererWnd or update to work with Atom: LYN-3671 + /*if (!m_terrainTextureId) { //GL_BGRA_EXT if (m_terrainTexture.IsValid()) @@ -238,7 +239,7 @@ void QTopRendererWnd::Draw(DisplayContext& dc) dc.DepthTestOn(); - Q2DViewport::Draw(dc); + Q2DViewport::Draw(dc);*/ } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp index 73f8ce7344..69322c481c 100644 --- a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -643,7 +643,7 @@ void CSequenceBatchRenderDialog::OnResolutionSelected() CCustomResolutionDlg resDlg(defaultW, defaultH, this); if (resDlg.exec() == QDialog::Accepted) { - const int maxRes = GetIEditor()->GetRenderer()->GetMaxSquareRasterDimension(); + const int maxRes = 8192; m_customResW = min(resDlg.GetWidth(), maxRes); m_customResH = min(resDlg.GetHeight(), maxRes); const QString resText = QString(customResFormat).arg(m_customResW).arg(m_customResH); diff --git a/Code/Sandbox/Editor/Util/ArcBall.cpp b/Code/Sandbox/Editor/Util/ArcBall.cpp deleted file mode 100644 index 25607e392b..0000000000 --- a/Code/Sandbox/Editor/Util/ArcBall.cpp +++ /dev/null @@ -1,769 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "ArcBall.h" - -bool CArcBall3D::ArcControl(const Matrix34& reference, const Ray& ray, uint32 mouseleft) -{ - RotControl <<= 1; - - if (mouseleft) - { - RotControl |= 1; - } - - Quat WObjectRotation = Quat(reference * Matrix34(ObjectRotation)); - Matrix34 WMat = reference * Matrix34(Matrix33(DragRotation * ObjectRotation), sphere.center); - Sphere WSphere(WMat.GetTranslation(), sphere.radius); - - Mouse_CutFlag = 0; - Vec3 Mouse_CutOn3DSphere(0, 0, 0); - Mouse_CutOnUnitSphere = Vec3(ZERO); - Mouse_CutFlag = Intersect::Ray_SphereFirst(ray, WSphere, Mouse_CutOn3DSphere); - - if (Mouse_CutFlag) - { - Mouse_CutOnUnitSphere = WObjectRotation.GetInverted() * (Mouse_CutOn3DSphere - WSphere.center).GetNormalized(); - } - - if (RotControl & 3) - { - if (Mouse_CutFlag) - { - if ((RotControl & 3) == 0x01) - { - Mouse_CutFlagStart = 1; - LineStart3D = Mouse_CutOnUnitSphere; - AxisSnap = 0; - - Matrix33 bym33; - - //get the distance to the axis - f32 xdist = fabsf(Mouse_CutOnUnitSphere.x); - f32 ydist = fabsf(Mouse_CutOnUnitSphere.y); - f32 zdist = fabsf(Mouse_CutOnUnitSphere.z); - - //if to close to an axis-crossing, disable axis choosing - if ((xdist < CrossDist) && (zdist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - if ((xdist < CrossDist) && (ydist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - if ((ydist < CrossDist) && (zdist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - - //check snap with YZ-plane - if (xdist < AxisDist) - { - bym33.SetIdentity(); - - if ((LineStart3D.x) || (LineStart3D.z)) - { - Vec3 n = Vec3(LineStart3D.x, 0, LineStart3D.z).GetNormalized(); - bym33.SetRotationY(acos_tpl(fabsf(n.z))); - } - - Vec3 SnapLineStart3D = bym33 * Vec3(fabsf(LineStart3D.x), LineStart3D.y, -fabsf(LineStart3D.z)); - - if (LineStart3D.z > 0.0f) - { - SnapLineStart3D.z = -SnapLineStart3D.z; - } - - LineStart3D = SnapLineStart3D; - AxisSnap = 1; - } - - //check snap with XZ-plane - if (ydist < AxisDist) - { - bym33.SetIdentity(); - - if ((LineStart3D.y) || (LineStart3D.z)) - { - Vec3 bn_xz = Vec3(0, LineStart3D.y, LineStart3D.z).GetNormalized(); - bym33.SetRotationX(-acos_tpl(fabsf(bn_xz.z))); - } - - Vec3 SnapLineStart3D = bym33 * Vec3((LineStart3D.x), fabsf(LineStart3D.y), -fabsf(LineStart3D.z)); - - if (LineStart3D.z > 0.0f) - { - SnapLineStart3D.z = -SnapLineStart3D.z; - } - - LineStart3D = SnapLineStart3D; - AxisSnap = 2; - } - - //check snap with XY-plane - if (zdist < AxisDist) - { - bym33.SetIdentity(); - - if ((LineStart3D.x) || (LineStart3D.z)) - { - Vec3 bn_xz = Vec3(LineStart3D.x, 0, LineStart3D.z).GetNormalized(); - bym33.SetRotationY(-acos_tpl(fabsf(bn_xz.x))); - } - - Vec3 SnapLineStart3D = bym33 * Vec3(fabsf(LineStart3D.x), LineStart3D.y, -fabsf(LineStart3D.z)); - - if (LineStart3D.x < 0.0f) - { - SnapLineStart3D.x = -SnapLineStart3D.x; - } - - LineStart3D = SnapLineStart3D; - AxisSnap = 3; - } - } - - if ((RotControl & 3) == 0x03) - { - ArcRotation(); - } - - if ((RotControl & 3) == 0x02) - { - ObjectRotation = (DragRotation * ObjectRotation).GetNormalized(); - DragRotation.SetIdentity(); - Mouse_CutFlagStart = 0; - LineStart3D = Vec3(0, -1, 0); - AxisSnap = 0; - - return true; - } - } - else - { - Vec3 ClostestPointOnLine; - IntersectSphereLineSegment(WSphere, ray.origin, ray.origin + ray.direction * 1000.0f, ClostestPointOnLine); - - Mouse_CutOn3DSphere = ((ClostestPointOnLine - WSphere.center).GetNormalized() * WSphere.radius) + WSphere.center; - Mouse_CutOnUnitSphere = WObjectRotation.GetInverted() * (Mouse_CutOn3DSphere - WSphere.center).GetNormalized(); - - if ((RotControl & 3) == 0x01) - { - LineStart3D = Mouse_CutOnUnitSphere; - Mouse_CutFlagStart = 0; - AxisSnap = 0; - } - - if ((RotControl & 3) == 0x03) - { - ArcRotation(); - } - - if ((RotControl & 3) == 0x02) - { - ObjectRotation = (DragRotation * ObjectRotation).GetNormalized(); - DragRotation.SetIdentity(); - Mouse_CutFlagStart = 0; - LineStart3D = Vec3(0, -1, 0); - AxisSnap = 0; - - return true; - } - } - } - - return false; -} - -void CArcBall3D::ArcRotation() -{ - Vec3 rv; - f32 gradius = 0; - f32 distance_YZ = 0; - f32 bias = 0; - f32 cosine = 0; - Vec3 XYVector; - - DragRotation.SetIdentity(); - - //first we calculate an ordinary drag-quaternion - cosine = (LineStart3D | Mouse_CutOnUnitSphere); - - if (fabsf(cosine) < 0.99999f) - { - DragRotation.SetRotationAA(acos_tpl(cosine), (LineStart3D % Mouse_CutOnUnitSphere).GetNormalized()); - } - - if (AxisSnap == 1) - { - //m_ButtonArcRotate an UpVector with our drag-quaternion - rv = (DragRotation) * Vec3(0, -1, 0); - DragRotation.SetIdentity(); - - //project rotated UpVector into XY_Plane (this is a simple y_axis rotation) - Matrix33 ym33; - ym33.SetIdentity(); - - if ((rv.x) || (rv.z)) - { - Vec3 n_xz = Vec3(rv.x, 0, rv.z).GetNormalized(); - ym33.SetRotationY(-acos_tpl(fabsf(n_xz.z))); - } - - XYVector = ym33 * Vec3(-fabsf(rv.x), rv.y, -fabsf(rv.z)); - - //find the rotation direction around z-axis - if (rv.z > 0) - { - XYVector.z = -XYVector.z; - } - - //calculate the xy-constrained quaternion - cosine = (Vec3(0, -1, 0) | XYVector); - - if (fabsf(cosine) < 0.99999f) - { - gradius = Vec3(rv.x, 0, rv.z).GetLength(); - distance_YZ = fabsf(rv.z); - bias = distance_YZ / gradius; - DragRotation.SetRotationAA(acos_tpl(cosine) * bias, (Vec3(0, -1, 0) % XYVector).GetNormalized()); - } - } - - if (AxisSnap == 2) - { - //m_ButtonArcRotate an UpVector with our DRAG-QUATERNION - rv = DragRotation * Vec3(-1, 0, 0); - DragRotation.SetIdentity(); - - //project rotated UpVector into XY_Plane (this is a simple x_axis rotation) - Matrix33 ym33; - ym33.SetIdentity(); - - if ((rv.y) || (rv.z)) - { - Vec3 n_xz = Vec3(0, rv.y, rv.z).GetNormalized(); - ym33.SetRotationX(-acos_tpl(fabsf(n_xz.z))); - } - - XYVector = ym33 * Vec3((rv.x), fabsf(rv.y), -fabsf(rv.z)); - - //find the rotation direction around y-axis - if (rv.z > 0) - { - XYVector.z = -XYVector.z; - } - - //calculate the xz-constrained quaternion - cosine = (Vec3(-1, 0, 0) | XYVector); - - if (fabsf(cosine) < 0.99999f) - { - gradius = Vec3(0, rv.y, rv.z).GetLength(); - distance_YZ = fabsf(rv.z); - bias = distance_YZ / gradius; - DragRotation.SetRotationAA(acos_tpl(cosine) * bias, (Vec3(-1, 0, 0) % XYVector).GetNormalized()); - } - } - - if (AxisSnap == 3) - { - //m_ButtonArcRotate an UpVector with our DRAG-QUATERNION - rv = DragRotation * Vec3(0, -1, 0); - DragRotation.SetIdentity(); - - //project rotated UpVector into XY_Plane (this is a simple y_axis rotation) - Matrix33 ym33; - - ym33.SetIdentity(); - - if ((rv.x) || (rv.z)) - { - Vec3 n_xz = Vec3(rv.x, 0, rv.z).GetNormalized(); - ym33.SetRotationY(-acos_tpl(fabsf(n_xz.x))); - } - - XYVector = ym33 * Vec3(fabsf(rv.x), rv.y, -fabsf(rv.z)); - - //find the rotation direction around z-axis - if (rv.x < 0) - { - XYVector.x = -XYVector.x; - } - - //calculate the xy-constrained quaternion - cosine = (Vec3(0, -1, 0) | XYVector); - - if (fabsf(cosine) < 0.99999f) - { - gradius = Vec3(rv.x, 0, rv.z).GetLength(); - distance_YZ = fabsf(rv.x); - bias = distance_YZ / gradius; - DragRotation.SetRotationAA(acos_tpl(cosine) * bias, (Vec3(0, -1, 0) % XYVector).GetNormalized()); - } - } - - //BINGO!!!! the final drag quaternion - DragRotation = ObjectRotation * DragRotation * ObjectRotation.GetInverted(); -} - -uint32 CArcBall3D::IntersectSphereLineSegment(const Sphere& sphere, const Vec3& LineStart, const Vec3& LineEnd, Vec3& I) -{ - //this is the code to produce a real z-rotation! - Vec3 LineDir = (LineEnd - LineStart).GetNormalized(); - Vec3 ShereCenterDir = (sphere.center - LineStart).GetNormalized(); - f32 LengthToSphereCenter = (sphere.center - LineStart).GetLength(); - - f32 cosine = (ShereCenterDir | LineDir); - - //this vector is perpendicular to the vector "ShereCenterDir" - Vec3 PerpVector = LengthToSphereCenter / cosine * LineDir + LineStart; - Vec3 PerpVectorOnSphere = ((PerpVector - sphere.center).GetNormalized() * sphere.radius) + sphere.center; - I = PerpVectorOnSphere; - - { - //find closest point on Lineseg - Vec3 LineDir2 = (LineEnd - LineStart).GetNormalized(); - f32 proj = LineDir2 | (sphere.center - LineStart); - I = LineDir2 * proj + LineStart; - } - - return 0; -} - -void CArcBall3D::DrawSphere(const Matrix34& reference, const CCamera& cam, IRenderAuxGeom* pRenderer) -{ - f32 thicknessX = 1.0f; - f32 thicknessY = 1.0f; - f32 thicknessZ = 1.0f; - - uint32 start; - Vec3 Vertices3D[64 * 32]; - Vec3 sVertices3D[64 * 32]; - Vec3 tVertices3D[64 * 32]; - uint32 c; - - Matrix34 WMat = reference * Matrix34(Matrix33(DragRotation * ObjectRotation), sphere.center); - Quat WObjectRotation = Quat(reference * Matrix34(ObjectRotation)); - Quat WRotation = Quat(reference * Matrix34(DragRotation * ObjectRotation)); - Sphere WSphere(WMat.GetTranslation(), sphere.radius); - - SAuxGeomRenderFlags renderFlags(e_Def3DPublicRenderflags); - renderFlags.SetDepthWriteFlag(e_DepthWriteOff); - renderFlags.SetFillMode(e_FillModeSolid); - - //------------------------------------------------------------------------------------------------------ - - uint32 s = 0; - uint32 t = 0; - Vec3 CamPos = cam.GetPosition(); - - renderFlags.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags); - pRenderer->DrawSphere(WSphere.center, WSphere.radius, RGBA8(0x3f, 0x3f, 0x3f, 0x00)); - - ColorB col; - f32 xdist = fabsf(Mouse_CutOnUnitSphere.x); - f32 ydist = fabsf(Mouse_CutOnUnitSphere.y); - f32 zdist = fabsf(Mouse_CutOnUnitSphere.z); - - if ((xdist < CrossDist) && (zdist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - if ((xdist < CrossDist) && (ydist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - if ((ydist < CrossDist) && (zdist < CrossDist)) - { - xdist = 1.0f; - ydist = 1.0f; - zdist = 1.0f; - } - - //---------------------------------------------------------------------------------- - // draw circle around X-axis - //---------------------------------------------------------------------------------- - thicknessX = 1.0f; - - if (AxisSnap == 0) - { - if (Mouse_CutFlag) - { - if (xdist < AxisDist) - { - thicknessX = 5.0f; - } - } - } - else if (AxisSnap == 1) - { - thicknessX = 5.0f; - } - - c = 0; - - for (f32 cz = 0; cz < (gf_PI * 2); cz = cz + (2 * gf_PI / 256.0f), ++c) - { - Vertices3D[c] = WMat * (Vec3(0, -cosf(cz), sinf(cz)) * WSphere.radius); - } - - assert(c == 0x100); - - for (start = 0; start < c; ++start) - { - Vec3 p0 = Vertices3D[(start + 0) & 0xff]; - f32 dot0 = (p0 - CamPos) | (p0 - WSphere.center); - Vec3 p1 = Vertices3D[(start + 1) & 0xff]; - f32 dot1 = (p1 - CamPos) | (p1 - WSphere.center); - - if ((dot0 < 0) && !(dot1 < 0)) - { - break; - } - } - - s = 0; - t = 0; - start = (start + 1) & 0xff; - - for (uint32 i = 0; i < c; ++i) - { - Vec3 p = Vertices3D[start]; - f32 dot = (p - CamPos) | (p - WSphere.center); - - if (dot < 0) - { - sVertices3D[s] = p; - s++; - } - else - { - tVertices3D[t] = p; - t++; - } - - start = (start + 1) & 0xff; - } - - renderFlags.SetAlphaBlendMode(e_AlphaNone); - pRenderer->SetRenderFlags(renderFlags); - - if (s > 2) - { - pRenderer->DrawPolyline(sVertices3D, s, 0, RGBA8(0xff, 0x12, 0x12, 0x00), thicknessX); - } - - renderFlags.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags); - - if (t > 2) - { - pRenderer->DrawPolyline(tVertices3D, t, 0, RGBA8(0x1f, 0x07, 0x07, 0x00), thicknessX); - } - - //---------------------------------------------------------------------------------- - // draw circle around Y-axis - //---------------------------------------------------------------------------------- - thicknessY = 1.0f; - - if (AxisSnap == 0) - { - if (Mouse_CutFlag) - { - if (ydist < AxisDist) - { - thicknessY = 5.0f; - } - } - } - else if (AxisSnap == 2) - { - thicknessY = 5.0f; - } - - c = 0; - - for (f32 cz = 0; cz < (gf_PI * 2); cz = cz + (2 * gf_PI / 256.0f), ++c) - { - Vertices3D[c] = WMat * (Vec3(-cosf(cz), 0, sinf(cz)) * WSphere.radius); - } - - assert(c == 0x100); - - for (start = 0; start < c; ++start) - { - Vec3 p0 = Vertices3D[(start + 0) & 0xff]; - f32 dot0 = (p0 - CamPos) | (p0 - WSphere.center); - Vec3 p1 = Vertices3D[(start + 1) & 0xff]; - f32 dot1 = (p1 - CamPos) | (p1 - WSphere.center); - - if ((dot0 < 0) && !(dot1 < 0)) - { - break; - } - } - - s = 0; - t = 0; - start = (start + 1) & 0xff; - - for (uint32 i = 0; i < c; ++i) - { - Vec3 p = Vertices3D[start]; - f32 dot = (p - CamPos) | (p - WSphere.center); - if (dot < 0) - { - sVertices3D[s] = p; - s++; - } - else - { - tVertices3D[t] = p; - t++; - } - - start = (start + 1) & 0xff; - } - - renderFlags.SetAlphaBlendMode(e_AlphaNone); - pRenderer->SetRenderFlags(renderFlags); - - if (s > 2) - { - pRenderer->DrawPolyline(sVertices3D, s, 0, RGBA8(0x12, 0xff, 0x12, 0x00), thicknessY); - } - - renderFlags.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags); - - if (t > 2) - { - pRenderer->DrawPolyline(tVertices3D, t, 0, RGBA8(0x07, 0x1f, 0x07, 0x00), thicknessY); - } - - //---------------------------------------------------------------------------------- - // draw circle around Z-axis - //---------------------------------------------------------------------------------- - thicknessZ = 1.0f; - - if (AxisSnap == 0) - { - if (Mouse_CutFlag) - { - if (zdist < AxisDist) - { - thicknessZ = 5.0f; - } - } - } - else if (AxisSnap == 3) - { - thicknessZ = 5.0f; - } - - c = 0; - for (f32 cz = 0; cz < (gf_PI * 2); cz = cz + (2 * gf_PI / 256.0f), ++c) - { - Vertices3D[c] = WMat * (Vec3(sinf(cz), -cosf(cz), 0) * WSphere.radius); - } - - assert(c == 0x100); - - for (start = 0; start < c; ++start) - { - Vec3 p0 = Vertices3D[(start + 0) & 0xff]; - f32 dot0 = (p0 - CamPos) | (p0 - WSphere.center); - Vec3 p1 = Vertices3D[(start + 1) & 0xff]; - f32 dot1 = (p1 - CamPos) | (p1 - WSphere.center); - - if ((dot0 < 0) && !(dot1 < 0)) - { - break; - } - } - - s = 0; - t = 0; - start = (start + 1) & 0xff; - - for (uint32 i = 0; i < c; ++i) - { - Vec3 p = Vertices3D[start]; - f32 dot = (p - CamPos) | (p - WSphere.center); - - if (dot < 0) - { - sVertices3D[s] = p; - s++; - } - else - { - tVertices3D[t] = p; - t++; - } - - start = (start + 1) & 0xff; - } - - renderFlags.SetAlphaBlendMode(e_AlphaNone); - pRenderer->SetRenderFlags(renderFlags); - - if (s > 2) - { - pRenderer->DrawPolyline(sVertices3D, s, 0, RGBA8(0x12, 0x12, 0xff, 0x00), thicknessZ); - } - - renderFlags.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags); - - if (t > 2) - { - pRenderer->DrawPolyline(tVertices3D, t, 0, RGBA8(0x07, 0x07, 0x1f, 0x00), thicknessZ); - } - - uint32 v; - - Vec3 VBuffer[1000]; - ColorB CBuffer[1000]; - - if ((RotControl & 3) == 3) - { - Vec3 Blue = WObjectRotation * LineStart3D; - Vec3 Red = WObjectRotation * Mouse_CutOnUnitSphere; - - VBuffer[0] = Vec3(0, 0, 0); - CBuffer[0] = RGBA8(0x00, 0x00, 0x00, 0x00); - - VBuffer[1] = Blue; - CBuffer[1] = RGBA8(0x00, 0x00, 0xff, 0x00); - - VBuffer[102] = Red; - CBuffer[102] = RGBA8(0xff, 0x00, 0x00, 0x00); - - for (v = 0; v < 100; ++v) - { - f32 t0 = (1.0f / 101.0f * v) + 1.0f / 101.0f; - - VBuffer[v + 2] = Vec3::CreateSlerp(Blue, Red, t0); - - f32 t1 = (1.0f / 101.0f * v); - - CBuffer[v + 2].b = uint8((1.0f - t1) * CBuffer[1].b + t1 * CBuffer[102].b); - CBuffer[v + 2].g = uint8((1.0f - t1) * CBuffer[1].g + t1 * CBuffer[102].g); - CBuffer[v + 2].r = uint8((1.0f - t1) * CBuffer[1].r + t1 * CBuffer[102].r); - } - - for (v = 0; v < 103; ++v) - { - VBuffer[v] = VBuffer[v] * WSphere.radius + WSphere.center; - } - - if (AxisSnap == 0) - { - SAuxGeomRenderFlags renderFlags2(e_Def3DPublicRenderflags); - - renderFlags2.SetFillMode(e_FillModeSolid); - renderFlags2.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags2); - - for (v = 0; v < 100; ++v) - { - pRenderer->DrawTriangle(VBuffer[0], CBuffer[0], VBuffer[v + 1], CBuffer[v + 1], VBuffer[v + 2], CBuffer[v + 2]); - pRenderer->DrawTriangle(VBuffer[0], CBuffer[0], VBuffer[v + 2], CBuffer[v + 2], VBuffer[v + 1], CBuffer[v + 1]); - } - } - } - - if (AxisSnap) - { - //project vector into the xy-plane - VBuffer[0] = Vec3(0, 0, 0); - CBuffer[0] = RGBA8(0x00, 0x00, 0x00, 0x00); - - VBuffer[1] = WObjectRotation * LineStart3D; - CBuffer[1] = RGBA8(0x12, 0x1f, 0x12, 0x00); - - VBuffer[102] = WRotation * LineStart3D; - CBuffer[102] = RGBA8(0x22, 0x7f, 0x22, 0x00); - - ColorB c0 = CBuffer[1]; - ColorB c1 = CBuffer[102]; - - for (v = 0; v < 100; ++v) - { - f32 t0 = (1.0f / 101.0f * v) + 1.0f / 101.0f; - - VBuffer[v + 2] = Vec3::CreateSlerp(VBuffer[1], VBuffer[102], t0); - - f32 t1 = (1.0f / 101.0f * v); - CBuffer[v + 2].r = uint8((1.0f - t1) * c0.r + t1 * c1.r); - CBuffer[v + 2].g = uint8((1.0f - t1) * c0.g + t1 * c1.g); - CBuffer[v + 2].b = uint8((1.0f - t1) * c0.b + t1 * c1.b); - } - - for (v = 0; v < 103; ++v) - { - VBuffer[v] = VBuffer[v] * WSphere.radius + WSphere.center; - } - - SAuxGeomRenderFlags renderFlags2(e_Def3DPublicRenderflags); - renderFlags2.SetFillMode(e_FillModeSolid); - renderFlags2.SetAlphaBlendMode(e_AlphaAdditive); - pRenderer->SetRenderFlags(renderFlags2); - - for (v = 0; v < 100; ++v) - { - pRenderer->DrawTriangle(VBuffer[0], CBuffer[0], VBuffer[v + 1], CBuffer[v + 1], VBuffer[v + 2], CBuffer[v + 2]); - pRenderer->DrawTriangle(VBuffer[0], CBuffer[0], VBuffer[v + 2], CBuffer[v + 2], VBuffer[v + 1], CBuffer[v + 1]); - } - } - - renderFlags = e_Def3DPublicRenderflags; - renderFlags.SetFillMode(e_FillModeSolid); - renderFlags.SetAlphaBlendMode(e_AlphaNone); - pRenderer->SetRenderFlags(renderFlags); - - #define CROSS (0.25f) - - Vec3 rmin = WMat * Vec3(0, 0.0f, 0.0f); - Vec3 rmax = WMat * Vec3(CROSS, 0.0f, 0.0f); - - pRenderer->DrawLine(rmin, RGBA8(0xff, 0x00, 0x00, 0x00), rmax, RGBA8(0xff, 0x7f, 0x7f, 0x00), thicknessX); - - Vec3 gmin = WMat * Vec3(0.0f, 0, 0.0f); - Vec3 gmax = WMat * Vec3(0.0f, CROSS, 0.0f); - - pRenderer->DrawLine(gmin, RGBA8(0x00, 0xff, 0x00, 0x00), gmax, RGBA8(0x7f, 0xff, 0x7f, 0x00), thicknessY); - - Vec3 bmin = WMat * Vec3(0.0f, 0.0f, 0); - Vec3 bmax = WMat * Vec3(0.0f, 0.0f, CROSS); - - pRenderer->DrawLine(bmin, RGBA8(0x00, 0x00, 0xff, 0x00), bmax, RGBA8(0x7f, 0x7f, 0xff, 0x00), thicknessZ); - renderFlags.SetDepthWriteFlag(e_DepthWriteOn); - pRenderer->SetRenderFlags(renderFlags); -} diff --git a/Code/Sandbox/Editor/Util/ArcBall.h b/Code/Sandbox/Editor/Util/ArcBall.h deleted file mode 100644 index 5adf02216c..0000000000 --- a/Code/Sandbox/Editor/Util/ArcBall.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_UTIL_ARCBALL_H -#define CRYINCLUDE_EDITOR_UTIL_ARCBALL_H -#pragma once -#include -#include - -#define CrossDist (0.05f) -#define AxisDist (0.05f) - -class SANDBOX_API CArcBall3D -{ -public: - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING - uint32 RotControl; - Sphere sphere; - uint32 Mouse_CutFlag; - uint32 Mouse_CutFlagStart; - uint32 AxisSnap; - Vec3 LineStart3D; - Vec3 Mouse_CutOnUnitSphere; - Quat DragRotation; - Quat ObjectRotation; - AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - - CArcBall3D() - { - InitArcBall(); - }; - - void InitArcBall() - { - RotControl = 0; - sphere(Vec3(ZERO), 0.25f); - Mouse_CutFlag = 0; - Mouse_CutOnUnitSphere(0, 0, 0); - LineStart3D(0, -1, 0); - AxisSnap = 0; - DragRotation.SetIdentity(); - ObjectRotation.SetIdentity(); - } - - //--------------------------------------------------------------- - // ArcControl - // Returns true if the rotation has changed - //--------------------------------------------------------------- - bool ArcControl(const Matrix34& reference, const Ray& ray, uint32 mouseleft); - void ArcRotation(); - void DrawSphere(const Matrix34& reference, const CCamera& cam, struct IRenderAuxGeom* pRenderer); - static uint32 IntersectSphereLineSegment(const Sphere& s, const Vec3& LineStart, const Vec3& LineEnd, Vec3& I); -}; -#endif // CRYINCLUDE_EDITOR_UTIL_ARCBALL_H diff --git a/Code/Sandbox/Editor/Util/CubemapUtils.cpp b/Code/Sandbox/Editor/Util/CubemapUtils.cpp deleted file mode 100644 index bd650abaa8..0000000000 --- a/Code/Sandbox/Editor/Util/CubemapUtils.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "CubemapUtils.h" - -// Qt -#include -#include -#include -#include -#include -#include - -// AzToolsFramework -#include - -// Editor -#include "Util/ImageTIF.h" -#include "Objects/BaseObject.h" - -#include - -class CubemapSizeModel - : public QAbstractListModel -{ -public: - CubemapSizeModel(QObject* parent = nullptr) - : QAbstractListModel(parent) - { } - - int rowCount(const QModelIndex& parent = {}) const override - { - return parent.isValid() ? 0 : kNumResolutions; - } - - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override - { - if (!index.isValid() || index.row() >= kNumResolutions) - { - return {}; - } - - switch (role) - { - case Qt::DisplayRole: - case Qt::UserRole: - return 32 << index.row(); - } - - return {}; - } - -private: - static const int kNumResolutions = 6; -}; - -class CubemapSizeDialog - : public QDialog -{ -public: - CubemapSizeDialog(QWidget* parent = nullptr) - : QDialog(parent) - , m_model(new CubemapSizeModel(this)) - { - setWindowTitle(tr("Enter Cubemap Resolution")); - - m_comboBox = new QComboBox; - m_comboBox->setModel(m_model); - m_comboBox->setCurrentIndex(3); - - auto horLine = new QLabel; - horLine->setFrameShape(QFrame::HLine); - horLine->setFrameShadow(QFrame::Sunken); - - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - - auto layout = new QVBoxLayout; - layout->addWidget(m_comboBox); - layout->addWidget(horLine); - layout->addWidget(buttonBox); - - setLayout(layout); - } - - int GetValue() const - { - return m_comboBox->currentData().toInt(); - } - -private: - CubemapSizeModel* m_model; - QComboBox* m_comboBox; -}; - -/////////////////////////////////////////////////////////////////////////////////// -bool CubemapUtils::GenCubemapWithObjectPathAndSize(QString& filename, CBaseObject* pObject, const int size, const bool hideObject) -{ - if (!pObject) - { - Warning("Select One Entity to Generate Cubemap"); - return false; - } - - if (pObject->GetType() != OBJTYPE_AZENTITY) - { - Warning("Only Entities are allowed as a selected object. Please Select Entity objects"); - return false; - } - - int res = 1; - // Make size power of 2. - for (int i = 0; i < 16; i++) - { - if (res * 2 > size) - { - break; - } - res *= 2; - } - if (res > 4096) - { - Warning("Bad texture resolution.\nMust be power of 2 and less or equal to 4096"); - return false; - } - - IRenderNode* pRenderNode = pObject->GetEngineNode(); - - // Hide the object before Cubemap generation (maybe). This is useful for when generating a cubemap at an entity's position, like the player, - // and you don't want their model showing up in the cubemap. But you want to leave the entity alone if it's a light or something that - // has a desired contribution to the cubemap. - bool bIsHidden = false; - if (pRenderNode) - { - bIsHidden = (pRenderNode->GetRndFlags() & ERF_HIDDEN) != 0; - if (hideObject) - { - pRenderNode->SetRndFlags(ERF_HIDDEN, true); - } - } - - QString texname = Path::GetFileName(filename); - QString path = Path::GetPath(filename); - - // Add _CM suffix if missing - int32 nCMSufixCheck = texname.indexOf("_cm"); - texname = Path::Make(path, texname + ((nCMSufixCheck == -1) ? "_cm.tif" : ".tif")); - - // Assign this texname to current material. - texname = Path::ToUnixPath(texname); - - // Temporary solution to save both dds and tiff hdr cubemap - AABB pObjAABB; - pObject->GetBoundBox(pObjAABB); - - Vec3 pObjCenter = pObjAABB.GetCenter(); - - bool success = GenHDRCubemapTiff(texname, res, pObjCenter); - - // restore object's visibility - if (pRenderNode) - { - pRenderNode->SetRndFlags(ERF_HIDDEN, bIsHidden); - } - - filename = Path::ToUnixPath(texname); - - return success; -} - -////////////////////////////////////////////////////////////////////////// -bool CubemapUtils::GenHDRCubemapTiff(const QString& fileName, int nDstSize, Vec3& pos) -{ - int nSrcSize = nDstSize * 4; // Render 16x bigger cubemap (4x4) - 16x SSAA - - TArray vecData; - vecData.Reserve(nSrcSize * nSrcSize * 6 * 4); - vecData.SetUse(0); - - if (!GetIEditor()->GetRenderer()->EF_RenderEnvironmentCubeHDR(nSrcSize, pos, vecData)) - { - assert(0); - return false; - } - - assert(vecData.size() == nSrcSize * nSrcSize * 6 * 4); - - // todo: such big downsampling should be on gpu - - // save data to tiff - // resample the image at the original size - CWordImage img; - img.Allocate(nDstSize * 4 * 6, nDstSize); - - size_t srcPitch = nSrcSize * 4; - size_t srcSlideSize = nSrcSize * srcPitch; - - size_t dstPitch = nDstSize * 4; - for (int side = 0; side < 6; ++side) - { - for (uint32 y = 0; y < nDstSize; ++y) - { - CryHalf4* pSrcSide = (CryHalf4*)&vecData[side * srcSlideSize]; - CryHalf4* pDst = (CryHalf4*)&img.ValueAt(side * dstPitch, y); - for (uint32 x = 0; x < nDstSize; ++x) - { - Vec4 cResampledColor(0.f, 0.f, 0.f, 0.f); - - // resample the image at the original size - for (uint32 yres = 0; yres < 4; ++yres) - { - for (uint32 xres = 0; xres < 4; ++xres) - { - const CryHalf4& pSrc = pSrcSide[(y * 4 + yres) * nSrcSize + (x * 4 + xres)]; - cResampledColor += Vec4(CryConvertHalfToFloat(pSrc.x), CryConvertHalfToFloat(pSrc.y), CryConvertHalfToFloat(pSrc.z), CryConvertHalfToFloat(pSrc.w)); - } - } - - cResampledColor /= 16.f; - - *pDst++ = CryHalf4(cResampledColor.x, cResampledColor.y, cResampledColor.z, cResampledColor.w); - } - } - } - - assert(CryMemory::IsHeapValid()); - - CImageTIF tif; - const bool res = tif.SaveRAW(fileName, img.GetData(), nDstSize * 6, nDstSize, 2, 4, true, "HDRCubemap_highQ"); - assert(res); - return res; -} - -//function will recurse all probes and generate a cubemap for each -void CubemapUtils::RegenerateAllEnvironmentProbeCubemaps() -{ - EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, GenerateAllCubemaps); -} diff --git a/Code/Sandbox/Editor/Util/CubemapUtils.h b/Code/Sandbox/Editor/Util/CubemapUtils.h deleted file mode 100644 index dfc2d47306..0000000000 --- a/Code/Sandbox/Editor/Util/CubemapUtils.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_UTIL_CUBEMAPUTILS_H -#define CRYINCLUDE_EDITOR_UTIL_CUBEMAPUTILS_H -#pragma once - - -namespace CubemapUtils -{ - //! Generate a cubemap - //! \param filename - //! \param pObject The cubemap will be generated at this object's location - //! \param size Texel dimension of the cubemap - //! \param hideObject If true, pObject will be hidden when rendering the cubemap. For example, set this to true if pObject is a model that shouldn't - //! show up in the cubemap, or set to false if pObject is a light or probe that should contribute to the cubemap. - SANDBOX_API bool GenCubemapWithObjectPathAndSize(QString& filename, CBaseObject* pObject, const int size, const bool hideObject); - - SANDBOX_API bool GenHDRCubemapTiff(const QString& fileName, int size, Vec3& pos); - SANDBOX_API void RegenerateAllEnvironmentProbeCubemaps(); -} - -#endif // CRYINCLUDE_EDITOR_UTIL_CUBEMAPUTILS_H diff --git a/Code/Sandbox/Editor/Util/ImageUtil.cpp b/Code/Sandbox/Editor/Util/ImageUtil.cpp index ae44833a75..874d74e9bb 100644 --- a/Code/Sandbox/Editor/Util/ImageUtil.cpp +++ b/Code/Sandbox/Editor/Util/ImageUtil.cpp @@ -22,7 +22,6 @@ #include "Util/ImageGif.h" #include "Util/ImageTIF.h" #include "Util/ImageHDR.h" -#include "Util/Image_DXTC.h" ////////////////////////////////////////////////////////////////////////// bool CImageUtil::Save(const QString& strFileName, CImageEx& inImage) @@ -272,10 +271,6 @@ bool CImageUtil::LoadImage(const QString& fileName, CImageEx& image, bool* pQual { return LoadPGM(fileName, image); } - else if (azstricmp(ext, ".dds") == 0) - { - return CImage_DXTC().Load(fileName.toUtf8().data(), image, pQualityLoss); - } else if (azstricmp(ext, ".png") == 0) { return CImageUtil::Load(fileName, image); diff --git a/Code/Sandbox/Editor/Util/Image_DXTC.cpp b/Code/Sandbox/Editor/Util/Image_DXTC.cpp deleted file mode 100644 index 834da7b5a3..0000000000 --- a/Code/Sandbox/Editor/Util/Image_DXTC.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "Image_DXTC.h" - -// CryCommon -#include -#include - -// Editor -#include "Util/Image.h" -#include "BitFiddling.h" - - -#ifndef MAKEFOURCC -#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ - ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ - ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) -#endif //defined(MAKEFOURCC) - - -////////////////////////////////////////////////////////////////////////// -// HDR_UPPERNORM -> factor used when converting from [0,32768] high dynamic range images -// to [0,1] low dynamic range images; 32768 = 2^(2^4-1), 4 exponent bits -// LDR_UPPERNORM -> factor used when converting from [0,1] low dynamic range images -// to 8bit outputs - -#define HDR_UPPERNORM 1.0f // factor set to 1.0, to be able to see content in our rather dark HDR images -#define LDR_UPPERNORM 255.0f - -static float GammaToLinear(float x) -{ - return (x <= 0.04045f) ? x / 12.92f : powf((x + 0.055f) / 1.055f, 2.4f); -} - -static float LinearToGamma(float x) -{ - return (x <= 0.0031308f) ? x * 12.92f : 1.055f * powf(x, 1.0f / 2.4f) - 0.055f; -} - -////////////////////////////////////////////////////////////////////////// - -// Squish uses non-standard inline friend templates which Recode cannot parse -#ifndef __RECODE__ -AZ_PUSH_DISABLE_WARNING(4819 4828, "-Wunknown-warning-option") // Invalid character not in default code page -#include -AZ_POP_DISABLE_WARNING -#endif - -// number of bytes per block per type -#define BLOCKSIZE_BC1 8 -#define BLOCKSIZE_BC2 16 -#define BLOCKSIZE_BC3 16 -#define BLOCKSIZE_BC4 8 -#define BLOCKSIZE_BC5 16 -#define BLOCKSIZE_BC6 16 -#define BLOCKSIZE_BC7 16 - -CImage_DXTC::COMPRESSOR_ERROR CImage_DXTC::DecompressTextureBTC( - int width, - int height, - ETEX_Format sourceFormat, - CImage_DXTC::UNCOMPRESSED_FORMAT destinationFormat, - [[maybe_unused]] const int imageFlags, - const void* sourceData, - void* destinationData, - int destinationDataSize, - int destinationPageOffset) -{ - // Squish uses non-standard inline friend templates which Recode cannot parse -#ifndef __RECODE__ - { - const COMPRESSOR_ERROR result = CheckParameters( - width, - height, - destinationFormat, - sourceData, - destinationData, - destinationDataSize); - - if (result != COMPRESSOR_ERROR_NONE) - { - return result; - } - } - - int flags = 0; - int offs = 0; - int sourceChannels = 4; - switch (sourceFormat) - { - case eTF_BC1: - sourceChannels = 4; - flags = squish::kBtc1; - break; - case eTF_BC2: - sourceChannels = 4; - flags = squish::kBtc2; - break; - case eTF_BC3: - sourceChannels = 4; - flags = squish::kBtc3; - break; - case eTF_BC4U: - sourceChannels = 1; - flags = squish::kBtc4; - break; - case eTF_BC5U: - sourceChannels = 2; - flags = squish::kBtc5 + squish::kColourMetricUnit; - break; - case eTF_BC6UH: - sourceChannels = 3; - flags = squish::kBtc6; - break; - case eTF_BC7: - sourceChannels = 4; - flags = squish::kBtc7; - break; - - case eTF_BC4S: - sourceChannels = 1; - flags = squish::kBtc4 + squish::kSignedInternal + squish::kSignedExternal; - offs = 0x80; - break; - case eTF_BC5S: - sourceChannels = 2; - flags = squish::kBtc5 + squish::kSignedInternal + squish::kSignedExternal + squish::kColourMetricUnit; - offs = 0x80; - break; - case eTF_BC6SH: - sourceChannels = 3; - flags = squish::kBtc6 + squish::kSignedInternal + squish::kSignedExternal; - offs = 0x80; - break; - - default: - return COMPRESSOR_ERROR_UNSUPPORTED_SOURCE_FORMAT; - } - - squish::sqio::dtp datatype = !IsLimitedHDR(sourceFormat) ? squish::sqio::dtp::DT_U8 : squish::sqio::dtp::DT_F23; - switch (destinationFormat) - { - case FORMAT_ARGB_8888: /*datatype = squish::sqio::dtp::DT_U8;*/ - break; - // case FORMAT_ARGB_16161616: datatype = squish::sqio::dtp::DT_U16; break; - // case FORMAT_ARGB_32323232F: datatype = squish::sqio::dtp::DT_F23; break; - default: - return COMPRESSOR_ERROR_UNSUPPORTED_DESTINATION_FORMAT; - } - - struct squish::sqio sqio = squish::GetSquishIO(width, height, datatype, flags); - - const int blockChannels = 4; - const int blockWidth = 4; - const int blockHeight = 4; - - const int pixelStride = blockChannels * sizeof(uint8); - const int rowStride = (destinationPageOffset ? destinationPageOffset : pixelStride * width); - - if ((datatype == squish::sqio::dtp::DT_U8) && (destinationFormat == FORMAT_ARGB_8888)) - { - const char* src = (const char*)sourceData; - for (int y = 0; y < height; y += blockHeight) - { - uint8* dst = ((uint8*)destinationData) + (y * rowStride); - - for (int x = 0; x < width; x += blockWidth) - { - uint8 values[blockHeight][blockWidth][blockChannels] = { { { 0 } } }; - - // decode - sqio.decoder((uint8*)values, src, sqio.flags); - - // transfer - for (int by = 0; by < blockHeight; by += 1) - { - uint8* bdst = ((uint8*)dst) + (by * rowStride); - - for (int bx = 0; bx < blockWidth; bx += 1) - { - bdst[bx * pixelStride + 0] = sourceChannels <= 0 ? 0U : (values[by][bx][0] + offs); - bdst[bx * pixelStride + 1] = sourceChannels <= 1 ? bdst[bx * pixelStride + 0] : (values[by][bx][1] + offs); - bdst[bx * pixelStride + 2] = sourceChannels <= 1 ? bdst[bx * pixelStride + 0] : (values[by][bx][2] + offs); - bdst[bx * pixelStride + 3] = sourceChannels <= 3 ? 255U : (values[by][bx][3]); - } - } - - dst += blockWidth * pixelStride; - src += sqio.blocksize; - } - } - } - else if ((datatype == squish::sqio::dtp::DT_F23) && (destinationFormat == FORMAT_ARGB_8888)) - { - const char* src = (const char*)sourceData; - for (int y = 0; y < height; y += blockHeight) - { - uint8* dst = ((uint8*)destinationData) + (y * rowStride); - - for (int x = 0; x < width; x += blockWidth) - { - float values[blockHeight][blockWidth][blockChannels] = { { { 0 } } }; - - // decode - sqio.decoder((float*)values, src, sqio.flags); - - // transfer - for (int by = 0; by < blockHeight; by += 1) - { - uint8* bdst = ((uint8*)dst) + (by * rowStride); - - for (int bx = 0; bx < blockWidth; bx += 1) - { - bdst[bx * pixelStride + 0] = sourceChannels <= 0 ? 0U : std::min((uint8)255, (uint8)floorf(values[by][bx][0] * LDR_UPPERNORM / HDR_UPPERNORM + 0.5f)); - bdst[bx * pixelStride + 1] = sourceChannels <= 1 ? bdst[bx * pixelStride + 0] : std::min((uint8)255, (uint8)floorf(values[by][bx][1] * LDR_UPPERNORM / HDR_UPPERNORM + 0.5f)); - bdst[bx * pixelStride + 2] = sourceChannels <= 1 ? bdst[bx * pixelStride + 0] : std::min((uint8)255, (uint8)floorf(values[by][bx][2] * LDR_UPPERNORM / HDR_UPPERNORM + 0.5f)); - bdst[bx * pixelStride + 3] = sourceChannels <= 3 ? 255U : 255U; - } - } - - dst += blockWidth * pixelStride; - src += sqio.blocksize; - } - } - } -#endif - - return COMPRESSOR_ERROR_NONE; -} - -////////////////////////////////////////////////////////////////////////// -CImage_DXTC::CImage_DXTC() -{ -} -////////////////////////////////////////////////////////////////////////// -CImage_DXTC::~CImage_DXTC() -{ -} -////////////////////////////////////////////////////////////////////////// -bool CImage_DXTC::Load(const char* filename, CImageEx& outImage, bool* pQualityLoss) -{ - if (pQualityLoss) - { - *pQualityLoss = false; - } - - _smart_ptr pImage = gEnv->pRenderer->EF_LoadImage(filename, 0); - - if (!pImage) - { - return(false); - } - - BYTE* pDecompBytes; - - ETEX_Format eFormat = pImage->mfGetFormat(); - int imageFlags = pImage->mfGet_Flags(); - - if (eFormat == eTF_Unknown) - { - return false; - } - - _smart_ptr pAlphaImage; - - ETEX_Format eAttachedFormat = eTF_Unknown; - - if (imageFlags & FIM_HAS_ATTACHED_ALPHA) - { - if (pAlphaImage = gEnv->pRenderer->EF_LoadImage(filename, FIM_ALPHA)) - { - eAttachedFormat = pAlphaImage->mfGetFormat(); - } - } - - const bool bIsSRGB = (imageFlags & FIM_SRGB_READ) != 0; - outImage.SetSRGB(bIsSRGB); - - const uint32 imageWidth = pImage->mfGet_width(); - const uint32 imageHeight = pImage->mfGet_height(); - const uint32 numMips = pImage->mfGet_numMips(); - - int nHorizontalFaces(1); - int nVerticalFaces(1); - int nTargetPitch(imageWidth * 4); - int nTargetPageSize(nTargetPitch * imageHeight); - - int nHorizontalPageOffset(nTargetPitch); - int nVerticalPageOffset(0); - bool boIsCubemap = pImage->mfGet_NumSides() == 6; - if (boIsCubemap) - { - nHorizontalFaces = 3; - nVerticalFaces = 2; - nHorizontalPageOffset = nTargetPitch * nHorizontalFaces; - nVerticalPageOffset = nTargetPageSize * nHorizontalFaces; - } - - outImage.Allocate(imageWidth * nHorizontalFaces, imageHeight * nVerticalFaces); - pDecompBytes = (BYTE*)outImage.GetData(); - if (!pDecompBytes) - { - Warning("Cannot allocate image %dx%d, Out of memory", imageWidth, imageHeight); - return false; - } - - if (pQualityLoss) - { - *pQualityLoss = CImageExtensionHelper::IsQuantized(eFormat); - } - - bool bOk = true; - - int nCurrentFace(0); - int nCurrentHorizontalFace(0); - int nCurrentVerticalFace(0); - unsigned char* dest(NULL); - const unsigned char* src(NULL); - - unsigned char* basedest(NULL); - const unsigned char* basesrc(NULL); - - for (nCurrentHorizontalFace = 0; nCurrentHorizontalFace < nHorizontalFaces; ++nCurrentHorizontalFace) - { - basedest = &pDecompBytes[nTargetPitch * nCurrentHorizontalFace]; // Horizontal offset. - for (nCurrentVerticalFace = 0; nCurrentVerticalFace < nVerticalFaces; ++nCurrentVerticalFace, ++nCurrentFace) - { - basedest += nVerticalPageOffset * nCurrentVerticalFace; // Vertical offset. - - basesrc = src = pImage->mfGet_image(nCurrentFace); - - if (eFormat == eTF_R8G8B8A8 || eFormat == eTF_R8G8B8A8S) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; - - dest += 4; - src += 4; - } - } - } - else if (eFormat == eTF_B8G8R8A8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = src[2]; - dest[1] = src[1]; - dest[2] = src[0]; - dest[3] = src[3]; - - dest += 4; - src += 4; - } - } - } - else if (eFormat == eTF_B8G8R8X8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = src[2]; - dest[1] = src[1]; - dest[2] = src[0]; - dest[3] = 255; - - dest += 4; - src += 4; - } - } - } - else if (eFormat == eTF_B8G8R8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = src[2]; - dest[1] = src[1]; - dest[2] = src[0]; - dest[3] = 255; - - dest += 4; - src += 3; - } - } - } - else if (eFormat == eTF_L8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = *src; - dest[1] = *src; - dest[2] = *src; - dest[3] = 255; - - dest += 4; - src += 1; - } - } - } - else if (eFormat == eTF_A8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - dest[3] = *src; - - dest += 4; - src += 1; - } - } - } - else if (eFormat == eTF_A8L8) - { - for (int y = 0; y < imageHeight; y++) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - dest[0] = src[0]; - dest[1] = src[0]; - dest[2] = src[0]; - dest[3] = src[1]; - - dest += 4; - src += 2; - } - } - } - else if (eFormat == eTF_R9G9B9E5) - { - const int nSourcePitch = imageWidth * 4; - - for (int y = 0; y < imageHeight; y++) - { - src = basesrc + nSourcePitch * y; //Scanline position. - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; x++) - { - const struct RgbE - { - unsigned int r : 9, g : 9, b : 9, e : 5; - }* srcv = (const struct RgbE*)src; - - const float escale = powf(2.0f, int(srcv->e) - 15 - 9) * LDR_UPPERNORM / HDR_UPPERNORM; - - dest[0] = std::min((uint8)255, (uint8)floorf(srcv->r * escale + 0.5f)); - dest[1] = std::min((uint8)255, (uint8)floorf(srcv->g * escale + 0.5f)); - dest[2] = std::min((uint8)255, (uint8)floorf(srcv->b * escale + 0.5f)); - dest[3] = 255U; - - dest += 4; - src += 4; - } - } - } - else - { - const int pixelCount = imageWidth * imageHeight; - const int outputBufferSize = pixelCount * 4; - const int mipCount = numMips; - - const COMPRESSOR_ERROR err = DecompressTextureBTC(imageWidth, imageHeight, eFormat, FORMAT_ARGB_8888, imageFlags, basesrc, basedest, outputBufferSize, nHorizontalPageOffset); - if (err != COMPRESSOR_ERROR_NONE) - { - return false; - } - } - - // alpha channel might be attached - if (imageFlags & FIM_HAS_ATTACHED_ALPHA) - { - if (IsBlockCompressed(eAttachedFormat)) - { - const byte* const basealpha = pAlphaImage->mfGet_image(0); - const int alphaImageWidth = pAlphaImage->mfGet_width(); - const int alphaImageHeight = pAlphaImage->mfGet_height(); - const int alphaImageFlags = pAlphaImage->mfGet_Flags(); - const int tmpOutputBufferSize = imageWidth * imageHeight * 4; - uint8* tmpOutputBuffer = new uint8[tmpOutputBufferSize]; - - const COMPRESSOR_ERROR err = DecompressTextureBTC(alphaImageWidth, alphaImageHeight, eAttachedFormat, FORMAT_ARGB_8888, alphaImageFlags, basealpha, tmpOutputBuffer, tmpOutputBufferSize, 0); - if (err != COMPRESSOR_ERROR_NONE) - { - delete []tmpOutputBuffer; - return false; - } - - // assuming attached image can have lower res and difference is power of two - const uint32 reducex = IntegerLog2((uint32)(imageWidth / alphaImageWidth)); - const uint32 reducey = IntegerLog2((uint32)(imageHeight / alphaImageHeight)); - - for (int y = 0; y < imageHeight; ++y) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; ++x) - { - dest[3] = tmpOutputBuffer[((x >> reducex) + (y >> reducey) * alphaImageWidth) * 4]; - dest += 4; - } - } - - delete []tmpOutputBuffer; - } - else if (eAttachedFormat != eTF_Unknown) - { - const byte* const basealpha = pAlphaImage->mfGet_image(0); // assuming it's A8 format (ensured with assets when loading) - const int alphaImageWidth = pAlphaImage->mfGet_width(); - const int alphaImageHeight = pAlphaImage->mfGet_height(); - const int alphaImageFlags = pAlphaImage->mfGet_Flags(); - - // assuming attached image can have lower res and difference is power of two - const uint32 reducex = IntegerLog2((uint32)(imageWidth / alphaImageWidth)); - const uint32 reducey = IntegerLog2((uint32)(imageHeight / alphaImageHeight)); - - for (int y = 0; y < imageHeight; ++y) - { - dest = basedest + nHorizontalPageOffset * y; // Pixel position. - - for (int x = 0; x < imageWidth; ++x) - { - dest[3] = basealpha[(x >> reducex) + (y >> reducey) * alphaImageWidth]; - dest += 4; - } - } - } - } - } - } - - ////////////////////////////////////////////////////////////////////////// - // destination range is 8bits - // rescale in linear space - float cScaleR = 1.0f; - float cScaleG = 1.0f; - float cScaleB = 1.0f; - float cScaleA = 1.0f; - float cLowR = 0.0f; - float cLowG = 0.0f; - float cLowB = 0.0f; - float cLowA = 0.0f; - - if (imageFlags & FIM_RENORMALIZED_TEXTURE) - { - const ColorF cMinColor = pImage->mfGet_minColor(); - const ColorF cMaxColor = pImage->mfGet_maxColor(); - - // base range after normalization, fe. [0,1] for 8bit images, or [0,2^15] for RGBE/HDR data - float cUprValue = 1.0f; - if ((eFormat == eTF_R9G9B9E5) || (eFormat == eTF_BC6UH) || (eFormat == eTF_BC6SH)) - { - cUprValue = cMaxColor.a / HDR_UPPERNORM; - } - - // original range before normalization, fe. [0,1.83567] - cScaleR = (cMaxColor.r - cMinColor.r) / cUprValue; - cScaleG = (cMaxColor.g - cMinColor.g) / cUprValue; - cScaleB = (cMaxColor.b - cMinColor.b) / cUprValue; - // original offset before normalization, fe. [0.0001204] - cLowR = cMinColor.r; - cLowG = cMinColor.g; - cLowB = cMinColor.b; - } - - if (imageFlags & FIM_HAS_ATTACHED_ALPHA) - { - if (pAlphaImage) - { - const int alphaImageFlags = pAlphaImage->mfGet_Flags(); - - if (alphaImageFlags & FIM_RENORMALIZED_TEXTURE) - { - const ColorF cMinColor = pAlphaImage->mfGet_minColor(); - const ColorF cMaxColor = pAlphaImage->mfGet_maxColor(); - - // base range after normalization, fe. [0,1] for 8bit images, or [0,2^15] for RGBE/HDR data - float cUprValue = 1.0f; - if ((eFormat == eTF_R9G9B9E5) || (eFormat == eTF_BC6UH) || (eFormat == eTF_BC6SH)) - { - cUprValue = cMaxColor.a / HDR_UPPERNORM; - } - - // original range before normalization, fe. [0,1.83567] - cScaleA = (cMaxColor.r - cMinColor.r) / cUprValue; - // original offset before normalization, fe. [0.0001204] - cLowA = cMinColor.r; - } - } - } - - if (cScaleR != 1.0f || cScaleG != 1.0f || cScaleB != 1.0f || cScaleA != 1.0f || - cLowR != 0.0f || cLowG != 0.0f || cLowB != 0.0f || cLowA != 0.0f) - { - if ((eFormat == eTF_R9G9B9E5) || (eFormat == eTF_BC6UH) || (eFormat == eTF_BC6SH)) - { - imageFlags &= ~FIM_SRGB_READ; - } - - if (imageFlags & FIM_SRGB_READ) - { - for (int s = 0; s < (imageWidth * nHorizontalFaces * imageHeight * nVerticalFaces * 4); s += 4) - { - pDecompBytes[s + 0] = std::min((uint8)255, uint8(LinearToGamma(GammaToLinear(pDecompBytes[s + 0] / LDR_UPPERNORM) * cScaleR + cLowR) * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 1] = std::min((uint8)255, uint8(LinearToGamma(GammaToLinear(pDecompBytes[s + 1] / LDR_UPPERNORM) * cScaleG + cLowG) * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 2] = std::min((uint8)255, uint8(LinearToGamma(GammaToLinear(pDecompBytes[s + 2] / LDR_UPPERNORM) * cScaleB + cLowB) * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 3] = std::min((uint8)255, uint8(LinearToGamma(GammaToLinear(pDecompBytes[s + 3] / LDR_UPPERNORM) * cScaleA + cLowA) * LDR_UPPERNORM + 0.5f)); - } - } - else - { - for (int s = 0; s < (imageWidth * nHorizontalFaces * imageHeight * nVerticalFaces * 4); s += 4) - { - pDecompBytes[s + 0] = std::min((uint8)255, uint8(pDecompBytes[s + 0] * cScaleR + cLowR * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 1] = std::min((uint8)255, uint8(pDecompBytes[s + 1] * cScaleG + cLowG * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 2] = std::min((uint8)255, uint8(pDecompBytes[s + 2] * cScaleB + cLowB * LDR_UPPERNORM + 0.5f)); - pDecompBytes[s + 3] = std::min((uint8)255, uint8(pDecompBytes[s + 3] * cScaleA + cLowA * LDR_UPPERNORM + 0.5f)); - } - } - } - - bool hasAlpha = (eAttachedFormat != eTF_Unknown) /*|| CImageExtensionHelper::HasAlphaForTextureFormat(eFormat)*/; - for (int s = 0; s < (imageWidth * nHorizontalFaces * imageHeight * nVerticalFaces); s += 4) - { - hasAlpha |= (pDecompBytes[s + 3] != 0xFF); - } - - ////////////////////////////////////////////////////////////////////////// - QString strFormat = NameForTextureFormat(eFormat); - QString mips; - mips = QStringLiteral(" Mips:%1").arg(numMips); - - if (eAttachedFormat != eTF_Unknown) - { - strFormat += " + "; - strFormat += NameForTextureFormat(eAttachedFormat); - } - - strFormat += mips; - - // Check whether it's gamma-corrected or not and add a description accordingly. - if (imageFlags & FIM_SRGB_READ) - { - strFormat += ", SRGB/Gamma corrected"; - } - if (imageFlags & FIM_RENORMALIZED_TEXTURE) - { - strFormat += ", Renormalized"; - } - if (IsLimitedHDR(eFormat)) - { - strFormat += ", HDR"; - } - - outImage.SetFormatDescription(strFormat); - outImage.SetNumberOfMipMaps(numMips); - outImage.SetHasAlphaChannel(hasAlpha); - outImage.SetIsLimitedHDR(IsLimitedHDR(eFormat)); - outImage.SetIsCubemap(boIsCubemap); - outImage.SetFormat(eFormat); - outImage.SetSRGB(imageFlags & FIM_SRGB_READ); - - // done reading file - return bOk; -} - -////////////////////////////////////////////////////////////////////////// -int CImage_DXTC::TextureDataSize(int nWidth, int nHeight, int nDepth, int nMips, ETEX_Format eTF) -{ - if (eTF == eTF_Unknown) - { - return 0; - } - - if (nMips <= 0) - { - nMips = 0; - } - int nSize = 0; - int nM = 0; - while (nWidth || nHeight || nDepth) - { - if (!nWidth) - { - nWidth = 1; - } - if (!nHeight) - { - nHeight = 1; - } - if (!nDepth) - { - nDepth = 1; - } - nM++; - - int nSingleMipSize; - if (IsBlockCompressed(eTF)) - { - int blockSize = CImageExtensionHelper::BytesPerBlock(eTF); - const Vec2i blockDim = CImageExtensionHelper::GetBlockDim(eTF); - nSingleMipSize = ((nWidth + blockDim.x - 1) / blockDim.x) * ((nHeight + blockDim.y - 1) / blockDim.y) * nDepth * blockSize; - } - else - { - nSingleMipSize = nWidth * nHeight * nDepth * CImageExtensionHelper::BytesPerBlock(eTF); - } - nSize += nSingleMipSize; - - nWidth >>= 1; - nHeight >>= 1; - nDepth >>= 1; - if (nMips == nM) - { - break; - } - } - //assert (nM == nMips); - - return nSize; -} - -////////////////////////////////////////////////////////////////////////// -CImage_DXTC::COMPRESSOR_ERROR CImage_DXTC::CheckParameters( - int width, - int height, - CImage_DXTC::UNCOMPRESSED_FORMAT destinationFormat, - const void* sourceData, - void* destinationData, - int destinationDataSize) -{ - const int blockWidth = 4; - const int blockHeight = 4; - - const int bgraPixelSize = 4 * sizeof(uint8); - const int bgraRowSize = bgraPixelSize * width; - - if ((width <= 0) || (height <= 0) || (!sourceData)) - { - return COMPRESSOR_ERROR_NO_INPUT_DATA; - } - - if ((width % blockWidth) || (height % blockHeight)) - { - return COMPRESSOR_ERROR_GENERIC; - } - - if ((destinationData == 0) || (destinationDataSize <= 0)) - { - return COMPRESSOR_ERROR_NO_OUTPUT_POINTER; - } - - if (destinationFormat != FORMAT_ARGB_8888) - { - return COMPRESSOR_ERROR_UNSUPPORTED_DESTINATION_FORMAT; - } - - if ((height * bgraRowSize <= 0) || (height * bgraRowSize > destinationDataSize)) - { - return COMPRESSOR_ERROR_GENERIC; - } - - return COMPRESSOR_ERROR_NONE; -} diff --git a/Code/Sandbox/Editor/Util/Image_DXTC.h b/Code/Sandbox/Editor/Util/Image_DXTC.h deleted file mode 100644 index 507d0232f1..0000000000 --- a/Code/Sandbox/Editor/Util/Image_DXTC.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_UTIL_IMAGE_DXTC_H -#define CRYINCLUDE_EDITOR_UTIL_IMAGE_DXTC_H -#pragma once - -#include "ImageExtensionHelper.h" - -class CImageEx; - -class CImage_DXTC -{ - // Typedefs -public: -protected: - ////////////////////////////////////////////////////////////////////////// - // Extracted from Compressorlib.h on SDKs\CompressATI directory. - // Added here because we are not really using the elements inside - // this header file apart from those definitions as we are currently - // loading the DLL CompressATI2.dll manually as recommended by the rendering - // team. - typedef enum - { - FORMAT_ARGB_8888, - FORMAT_ARGB_TOOBIG - } UNCOMPRESSED_FORMAT; - - typedef enum - { - COMPRESSOR_ERROR_NONE, - COMPRESSOR_ERROR_NO_INPUT_DATA, - COMPRESSOR_ERROR_NO_OUTPUT_POINTER, - COMPRESSOR_ERROR_UNSUPPORTED_SOURCE_FORMAT, - COMPRESSOR_ERROR_UNSUPPORTED_DESTINATION_FORMAT, - COMPRESSOR_ERROR_UNABLE_TO_INIT_CODEC, - COMPRESSOR_ERROR_GENERIC - } COMPRESSOR_ERROR; - ////////////////////////////////////////////////////////////////////////// - - // Methods -public: - CImage_DXTC(); - ~CImage_DXTC(); - - // Arguments: - // pQualityLoss - 0 if info is not needed, pointer to the result otherwise - not need to preinitialize - bool Load(const char* filename, CImageEx& outImage, bool* pQualityLoss = 0); // true if success - - static inline const char* NameForTextureFormat(ETEX_Format ETF) { return CImageExtensionHelper::NameForTextureFormat(ETF); } - static inline bool IsBlockCompressed(ETEX_Format ETF) { return CImageExtensionHelper::IsBlockCompressed(ETF); } - static inline bool IsLimitedHDR(ETEX_Format ETF) { return CImageExtensionHelper::IsRangeless(ETF); } - - int TextureDataSize(int nWidth, int nHeight, int nDepth, int nMips, ETEX_Format eTF); - -private: - static COMPRESSOR_ERROR CheckParameters( - int width, - int height, - UNCOMPRESSED_FORMAT destinationFormat, - const void* sourceData, - void* destinationData, - int destinationDataSize); - - static COMPRESSOR_ERROR DecompressTextureBTC( - int width, - int height, - ETEX_Format sourceFormat, - UNCOMPRESSED_FORMAT destinationFormat, - const int imageFlags, - const void* sourceData, - void* destinationData, - int destinationDataSize, - int destinationPageOffset); -}; - -#endif // CRYINCLUDE_EDITOR_UTIL_IMAGE_DXTC_H diff --git a/Code/Sandbox/Editor/Util/Ruler.cpp b/Code/Sandbox/Editor/Util/Ruler.cpp deleted file mode 100644 index 9f802b8b5e..0000000000 --- a/Code/Sandbox/Editor/Util/Ruler.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Ruler helper for Editor to determine distances - - -#include "EditorDefs.h" - -#include "Ruler.h" - -// Editor -#include "Settings.h" -#include "Viewport.h" -#include "Include/HitContext.h" -#include "Include/IObjectManager.h" -#include "Objects/BaseObject.h" - -// Qt -#include - -////////////////////////////////////////////////////////////////////////// -CRuler::CRuler() - : m_bActive(false) - , m_MouseOverObject(GUID_NULL) - , m_sphereScale(0.5f) - , m_sphereTrans(0.5f) -{ -} - -////////////////////////////////////////////////////////////////////////// -CRuler::~CRuler() -{ - SetActive(false); -} - -////////////////////////////////////////////////////////////////////////// -bool CRuler::HasQueuedPaths() const -{ - return false; -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::SetActive(bool bActive) -{ - if (m_bActive != bActive) - { - m_bActive = bActive; - - if (m_bActive) - { - m_sphereScale = gSettings.gizmo.rulerSphereScale; - m_sphereTrans = gSettings.gizmo.rulerSphereTrans; - } - - // Reset - m_startPoint.Reset(); - m_endPoint.Reset(); - - CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_MouseOverObject); - if (pObject) - { - pObject->SetHighlight(false); - } - m_MouseOverObject = GUID_NULL; - } -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::Update() -{ - if (!IsActive()) - { - return; - } - - if (CheckVirtualKey(Qt::Key_Escape)) - { - SetActive(false); - return; - } - - static const ColorF colours[] = - { - Col_Blue, - Col_Green, - Col_Red, - Col_Yellow, - Col_Magenta, - Col_Black, - }; - - IRenderer* pRenderer = GetIEditor()->GetSystem()->GetIRenderer(); - CRY_ASSERT(pRenderer); - IRenderAuxGeom* pAuxGeom = pRenderer->GetIRenderAuxGeom(); - CRY_ASSERT(pAuxGeom); - - CViewport* pActiveView = GetIEditor()->GetActiveView(); - if (pActiveView) - { - // Draw where cursor currently is - if (!IsObjectSelectMode(pActiveView)) - { - QPoint vCursorPoint = QCursor::pos(); - pActiveView->ScreenToClient(vCursorPoint); - vCursorPoint = QHighDpi::toNativePixels(vCursorPoint, QGuiApplication::screenAt(vCursorPoint)); - Vec3 vCursorWorldPos = pActiveView->SnapToGrid(pActiveView->ViewToWorld(vCursorPoint)); - Vec3 vOffset(0.1f, 0.1f, 0.1f); - pAuxGeom->SetRenderFlags(e_Def3DPublicRenderflags | e_AlphaBlended); - pAuxGeom->DrawSphere(vCursorWorldPos, m_sphereScale, ColorF(0.5, 0.5, 0.5, m_sphereTrans)); - pAuxGeom->DrawAABB(AABB(vCursorWorldPos - vOffset * m_sphereScale, vCursorWorldPos + vOffset * m_sphereScale), false, ColorF(1.0f, 0.0f, 0.0f, 1.0f), eBBD_Faceted); - } - - uint32 x = 12, y = 60; - - if (!m_startPoint.IsEmpty()) - { - //pAuxGeom->DrawSphere(m_startPoint.GetPos(), 1.0f, ColorB(255,255,255,255)); - m_startPoint.Render(pRenderer); - } - if (!m_endPoint.IsEmpty()) - { - //pAuxGeom->DrawSphere(m_endPoint.GetPos(), 1.0f, ColorB(255,255,255,255)); - m_endPoint.Render(pRenderer); - - pAuxGeom->DrawLine(m_startPoint.GetPos(), ColorB(255, 255, 255, 255), m_endPoint.GetPos(), ColorB(255, 255, 255, 255)); - - string sTempText; - - // Compute distance and output results - // TODO: Consider movement speed outputs here as well? - const float fDistance = m_startPoint.GetDistance(m_endPoint); - sTempText.Format("Straight-line distance: %.3f", fDistance); - - // Draw mid text - float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; - pRenderer->Draw2dLabel(x, y, 2.0f, white, false, sTempText.c_str()); - y += 18; - } - } -} - -////////////////////////////////////////////////////////////////////////// -bool CRuler::IsObjectSelectMode([[maybe_unused]] CViewport* pView) const -{ - const bool bShiftDown = CheckVirtualKey(Qt::Key_Shift); - - return (bShiftDown); -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::UpdateRulerPoint(CViewport* pView, const QPoint& point, CRulerPoint& rulerPoint, bool bRequestPath) -{ - CRY_ASSERT(pView); - - const bool bObjectSelect = IsObjectSelectMode(pView); - - rulerPoint.SetHelperSettings(m_sphereScale, m_sphereTrans); - - // Do entity hit check - if (bObjectSelect) - { - HitContext hitInfo; - pView->HitTest(point, hitInfo); - - CBaseObject* pHitObj = hitInfo.object; - rulerPoint.Set(pHitObj); - } - else - { - Vec3 vWorldPoint = pView->SnapToGrid(pView->ViewToWorld(point)); - rulerPoint.Set(vWorldPoint); - } - - if (bRequestPath) - { - RequestPath(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::RequestPath() -{ -} - -////////////////////////////////////////////////////////////////////////// -bool CRuler::MouseCallback(CViewport* pView, EMouseEvent event, QPoint& point, int flags) -{ - bool bResult = IsActive(); - - if (bResult) - { - switch (event) - { - case eMouseMove: - OnMouseMove(pView, point, flags); - break; - case eMouseLUp: - OnLButtonUp(pView, point, flags); - break; - } - } - - return bResult; -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::OnMouseMove(CViewport* pView, QPoint& point, [[maybe_unused]] int flags) -{ - GUID hitGUID = GUID_NULL; - - if (IsObjectSelectMode(pView)) - { - // Check for hit entity - HitContext hitInfo; - pView->HitTest(point, hitInfo); - CBaseObject* pHitObj = hitInfo.object; - if (pHitObj) - { - hitGUID = pHitObj->GetId(); - } - } - - if (hitGUID != m_MouseOverObject) - { - // Kill highlight on old - CBaseObject* pOldObj = GetIEditor()->GetObjectManager()->FindObject(m_MouseOverObject); - if (pOldObj) - { - pOldObj->SetHighlight(false); - } - - CBaseObject* pHitObj = GetIEditor()->GetObjectManager()->FindObject(hitGUID); - if (pHitObj) - { - pHitObj->SetHighlight(true); - } - - m_MouseOverObject = hitGUID; - } -} - -////////////////////////////////////////////////////////////////////////// -void CRuler::OnLButtonUp(CViewport* pView, QPoint& point, [[maybe_unused]] int flags) -{ - if (m_startPoint.IsEmpty()) - { - UpdateRulerPoint(pView, point, m_startPoint, false); - } - else if (m_endPoint.IsEmpty()) - { - UpdateRulerPoint(pView, point, m_endPoint, true); - } - else - { - UpdateRulerPoint(pView, point, m_startPoint, false); - m_endPoint.Reset(); - } -} diff --git a/Code/Sandbox/Editor/Util/Ruler.h b/Code/Sandbox/Editor/Util/Ruler.h deleted file mode 100644 index 1e04e2a1f9..0000000000 --- a/Code/Sandbox/Editor/Util/Ruler.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Ruler helper for Editor to determine distances - - -#ifndef CRYINCLUDE_EDITOR_UTIL_RULER_H -#define CRYINCLUDE_EDITOR_UTIL_RULER_H -#pragma once - - -#include "RulerPoint.h" - -//! The Ruler utility helps to determine distances between user-specified points -class CRuler -{ -public: - CRuler(); - ~CRuler(); - - //! Returns if ruler has queued paths in the path agent - bool HasQueuedPaths() const; - - //! Activate the ruler - void SetActive(bool bActive); - bool IsActive() const { return m_bActive; } - - //! Update - void Update(); - - //! Mouse callback handling from viewport - bool MouseCallback(CViewport* pView, EMouseEvent event, QPoint& point, int flags); - -private: - //! Mouse callback helpers - void OnMouseMove(CViewport* pView, QPoint& point, int flags); - void OnLButtonUp(CViewport* pView, QPoint& point, int flags); - - //! Returns world point based on mouse point - void UpdateRulerPoint(CViewport* pView, const QPoint& point, CRulerPoint& rulerPoint, bool bRequestPath); - - //! Request a path using the path agent - void RequestPath(); - - bool IsObjectSelectMode(CViewport* pView) const; - -private: - bool m_bActive; - GUID m_MouseOverObject; - - // Base point - CRulerPoint m_startPoint; - CRulerPoint m_endPoint; - - float m_sphereScale; - float m_sphereTrans; -}; - -#endif // CRYINCLUDE_EDITOR_UTIL_RULER_H diff --git a/Code/Sandbox/Editor/Util/RulerPoint.cpp b/Code/Sandbox/Editor/Util/RulerPoint.cpp deleted file mode 100644 index d9f148d26a..0000000000 --- a/Code/Sandbox/Editor/Util/RulerPoint.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Ruler helper for Editor to determine distances - - -#include "EditorDefs.h" - -#include "RulerPoint.h" - -// Editor -#include "Objects/BaseObject.h" -#include "Include/IObjectManager.h" - -////////////////////////////////////////////////////////////////////////// -CRulerPoint::CRulerPoint() - : m_type(eType_Invalid) - , m_vPoint(ZERO) - , m_ObjectGUID(GUID_NULL) -{ - Reset(); -} - -////////////////////////////////////////////////////////////////////////// -CRulerPoint& CRulerPoint::operator =(CRulerPoint const& other) -{ - if (this != &other) - { - Reset(); // Manage deselect of current object, etc. - - m_type = other.m_type; - m_vPoint = other.m_vPoint; - m_ObjectGUID = other.m_ObjectGUID; - m_sphereScale = other.m_sphereScale; - m_sphereTrans = other.m_sphereTrans; - } - - return *this; -} - -////////////////////////////////////////////////////////////////////////// -void CRulerPoint::Reset() -{ - // Kill highlight of current object - CBaseObject* pObject = GetObject(); - if (pObject) - { - pObject->SetHighlight(false); - } - - m_type = eType_Invalid; - m_vPoint.zero(); - m_ObjectGUID = GUID_NULL; -} - -////////////////////////////////////////////////////////////////////////// -void CRulerPoint::Render(IRenderer* pRenderer) -{ - CRY_ASSERT(pRenderer); - IRenderAuxGeom* pAuxGeom = pRenderer->GetIRenderAuxGeom(); - - switch (m_type) - { - case eType_Point: - { - Vec3 vOffset(0.1f, 0.1f, 0.1f); - pAuxGeom->SetRenderFlags(e_Def3DPublicRenderflags | e_AlphaBlended); - pAuxGeom->DrawSphere(m_vPoint, m_sphereScale, ColorF(1, 1, 1, m_sphereTrans)); - pAuxGeom->DrawAABB(AABB(m_vPoint - vOffset * m_sphereScale, m_vPoint + vOffset * m_sphereScale), false, ColorF(0.0f, 1.0f, 0.0f, 1.0f), eBBD_Faceted); - } - break; - - case eType_Object: - { - CBaseObject* pObject = GetObject(); - if (pObject) - { - pObject->SetHighlight(true); - } - } - break; - - default: - return; // No extra drawing - } -} - -////////////////////////////////////////////////////////////////////////// -void CRulerPoint::Set(const Vec3& vPos) -{ - Reset(); - - m_type = eType_Point; - m_vPoint = vPos; -} - -////////////////////////////////////////////////////////////////////////// -void CRulerPoint::Set(CBaseObject* pObject) -{ - Reset(); - - m_type = eType_Object; - m_ObjectGUID = (pObject ? pObject->GetId() : GUID_NULL); -} - -////////////////////////////////////////////////////////////////////////// -void CRulerPoint::SetHelperSettings(float scale, float trans) -{ - m_sphereScale = scale; - m_sphereTrans = trans; -} - -////////////////////////////////////////////////////////////////////////// -bool CRulerPoint::IsEmpty() const -{ - bool bResult = true; - - switch (m_type) - { - case eType_Invalid: - bResult = true; - break; - - case eType_Point: - bResult = m_vPoint.IsZero(); - break; - - case eType_Object: - bResult = (GetObject() == 0); - break; - } - - return bResult; -} - -////////////////////////////////////////////////////////////////////////// -Vec3 CRulerPoint::GetPos() const -{ - Vec3 vResult(ZERO); - - switch (m_type) - { - case eType_Point: - vResult = m_vPoint; - break; - - case eType_Object: - { - CBaseObject* pObject = GetObject(); - if (pObject) - { - vResult = pObject->GetWorldPos(); - } - } - break; - } - - return vResult; -} - -////////////////////////////////////////////////////////////////////////// -Vec3 CRulerPoint::GetMidPoint(const CRulerPoint& otherPoint) const -{ - Vec3 vResult(ZERO); - - if (!IsEmpty() && !otherPoint.IsEmpty()) - { - vResult = GetPos() + (otherPoint.GetPos() - GetPos()) * 0.5f; - } - else if (!IsEmpty()) - { - vResult = GetPos(); - } - else - { - vResult = otherPoint.GetPos(); - } - - return vResult; -} - -////////////////////////////////////////////////////////////////////////// -float CRulerPoint::GetDistance(const CRulerPoint& otherPoint) const -{ - float fResult = 0.0f; - - if (!IsEmpty() && !otherPoint.IsEmpty()) - { - fResult = GetPos().GetDistance(otherPoint.GetPos()); - } - - return fResult; -} - -////////////////////////////////////////////////////////////////////////// -CBaseObject* CRulerPoint::GetObject() const -{ - CBaseObject* pResult = NULL; - - if (m_type == eType_Object) - { - pResult = GetIEditor()->GetObjectManager()->FindObject(m_ObjectGUID); - } - - return pResult; -} diff --git a/Code/Sandbox/Editor/Util/RulerPoint.h b/Code/Sandbox/Editor/Util/RulerPoint.h deleted file mode 100644 index 0d68c9450c..0000000000 --- a/Code/Sandbox/Editor/Util/RulerPoint.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Ruler point helper, used by CRuler - - -#ifndef CRYINCLUDE_EDITOR_UTIL_RULERPOINT_H -#define CRYINCLUDE_EDITOR_UTIL_RULERPOINT_H -#pragma once - - -class CRuler; - -//! Ruler point helper - Defines a point for the ruler -class CRulerPoint -{ -public: - CRulerPoint(); - CRulerPoint& operator =(CRulerPoint const& other); - - void Reset(); - void Render(IRenderer* pRenderer); - - //! Set helpers - void Set(const Vec3& vPos); - void Set(CBaseObject* pObject); - void SetHelperSettings(float scale, float trans); - - //! Returns is point has valid data in it (in use) - bool IsEmpty() const; - - //! Helpers to get correct data out - Vec3 GetPos() const; - Vec3 GetMidPoint(const CRulerPoint& otherPoint) const; - float GetDistance(const CRulerPoint& otherPoint) const; - CBaseObject* GetObject() const; - -private: - enum EType - { - eType_Invalid, - eType_Point, - eType_Object, - - eType_COUNT, - }; - EType m_type; - - Vec3 m_vPoint; - GUID m_ObjectGUID; - float m_sphereScale; - float m_sphereTrans; -}; - -#endif // CRYINCLUDE_EDITOR_UTIL_RULERPOINT_H diff --git a/Code/Sandbox/Editor/ViewManager.cpp b/Code/Sandbox/Editor/ViewManager.cpp index 334e78a826..8bb14a3aca 100644 --- a/Code/Sandbox/Editor/ViewManager.cpp +++ b/Code/Sandbox/Editor/ViewManager.cpp @@ -49,8 +49,6 @@ bool CViewManager::IsMultiViewportEnabled() ////////////////////////////////////////////////////////////////////// CViewManager::CViewManager() { - gSettings.pGrid = &m_grid; - m_zoomFactor = 1; m_origin2D(0, 0, 0); diff --git a/Code/Sandbox/Editor/ViewManager.h b/Code/Sandbox/Editor/ViewManager.h index d617b5c54e..e2b42573d5 100644 --- a/Code/Sandbox/Editor/ViewManager.h +++ b/Code/Sandbox/Editor/ViewManager.h @@ -20,7 +20,6 @@ #pragma once #include "Cry_Geo.h" -#include "Grid.h" #include "Viewport.h" #include "Include/IViewPane.h" #include "QtViewPaneManager.h" @@ -67,10 +66,6 @@ public: void SetUpdateRegion(const AABB& updateRegion) { m_updateRegion = updateRegion; }; const AABB& GetUpdateRegion() { return m_updateRegion; }; - /** Retrieve Grid used for viewes. - */ - CGrid* GetGrid() { return &m_grid; }; - /** Get 2D viewports origin. */ Vec3 GetOrigin2D() const { return m_origin2D; } @@ -137,7 +132,6 @@ private: AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AABB m_updateRegion; - CGrid m_grid; //! Origin of 2d viewports. Vec3 m_origin2D; //! Zoom of 2d viewports. diff --git a/Code/Sandbox/Editor/ViewPane.cpp b/Code/Sandbox/Editor/ViewPane.cpp index 480e39bedf..eda0f390fa 100644 --- a/Code/Sandbox/Editor/ViewPane.cpp +++ b/Code/Sandbox/Editor/ViewPane.cpp @@ -643,27 +643,6 @@ void CLayoutViewPane::SetFullscren(bool f) m_bFullscreen = f; } -////////////////////////////////////////////////////////////////////////// -void CLayoutViewPane::SetFullscreenViewport(bool b) -{ - if (!m_viewport) - { - return; - } - - if (b) - { - m_viewport->setParent(0); - - GetIEditor()->GetRenderer()->ChangeResolution(800, 600, 32, 80, true, false); - } - else - { - m_viewport->setParent(this); - GetIEditor()->GetRenderer()->ChangeResolution(800, 600, 32, 80, false, false); - } -} - ////////////////////////////////////////////////////////////////////////// void CLayoutViewPane::SetFocusToViewport() { diff --git a/Code/Sandbox/Editor/ViewPane.h b/Code/Sandbox/Editor/ViewPane.h index 53d13c105d..80647e7a15 100644 --- a/Code/Sandbox/Editor/ViewPane.h +++ b/Code/Sandbox/Editor/ViewPane.h @@ -63,8 +63,6 @@ public: void SetFullscren(bool f); bool IsFullscreen() const { return m_bFullscreen; } - void SetFullscreenViewport(bool b); - QWidget* GetViewport() { return m_viewport; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/Viewport.cpp b/Code/Sandbox/Editor/Viewport.cpp index 37a9ee5f29..da4a389aa0 100644 --- a/Code/Sandbox/Editor/Viewport.cpp +++ b/Code/Sandbox/Editor/Viewport.cpp @@ -30,7 +30,6 @@ #include "Include/HitContext.h" #include "Objects/ObjectManager.h" #include "Util/3DConnexionDriver.h" -#include "Util/Ruler.h" #include "PluginManager.h" #include "Include/IRenderListener.h" #include "GameEngine.h" @@ -1183,12 +1182,12 @@ float QtViewport::GetZoomFactor() const ////////////////////////////////////////////////////////////////////////// Vec3 QtViewport::SnapToGrid(const Vec3& vec) { - return m_viewManager->GetGrid()->Snap(vec, m_fGridZoom); + return vec; } float QtViewport::GetGridStep() const { - return m_viewManager->GetGrid()->scale * m_viewManager->GetGrid()->size; + return 0.0f; } ////////////////////////////////////////////////////////////////////////// @@ -1414,17 +1413,7 @@ bool QtViewport::MouseCallback(EMouseEvent event, const QPoint& point, Qt::Keybo break; } - ////////////////////////////////////////////////////////////////////////// - // Asks Ruler to handle mouse callback. - CRuler* pRuler = GetIEditor()->GetRuler(); QPoint tempPoint(point.x(), point.y()); - if (pRuler) - { - if (pRuler->MouseCallback(this, event, tempPoint, flags)) - { - return true; - } - } ////////////////////////////////////////////////////////////////////////// // Handle viewport manipulators. diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 427a5c32e8..95531e117c 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -95,8 +95,6 @@ CViewportTitleDlg::~CViewportTitleDlg() { GetISystem()->GetISystemEventDispatcher()->RemoveListener(this); GetIEditor()->UnregisterNotifyListener(this); - ICVar* pDisplayInfo(gEnv->pConsole->GetCVar("r_displayInfo")); - pDisplayInfo->RemoveOnChangeFunctor(m_displayInfoCallbackIndex); } ////////////////////////////////////////////////////////////////////////// @@ -158,8 +156,6 @@ void CViewportTitleDlg::OnToggleHelpers() ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::OnToggleDisplayInfo() { - int currentDisplayInfo = gEnv->pConsole->GetCVar("r_displayInfo")->GetIVal(); - gEnv->pConsole->GetCVar("r_displayInfo")->Set(currentDisplayInfo >= 3 ? 0 : currentDisplayInfo + 1); } ////////////////////////////////////////////////////////////////////////// @@ -548,12 +544,8 @@ void CViewportTitleDlg::UpdateCustomPresets(const QString& text, QStringList& cu } } -void CViewportTitleDlg::OnChangedDisplayInfo([[maybe_unused]] ICVar* pDisplayInfo, QAbstractButton* pDisplayInfoButton) +void CViewportTitleDlg::OnChangedDisplayInfo([[maybe_unused]] ICVar* pDisplayInfo, [[maybe_unused]] QAbstractButton* pDisplayInfoButton) { - if (pDisplayInfoButton) - { - pDisplayInfoButton->setChecked(gEnv->pConsole->GetCVar("r_displayInfo")->GetIVal()); - } } bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event) diff --git a/Code/Sandbox/Editor/editor_core_files.cmake b/Code/Sandbox/Editor/editor_core_files.cmake index 1aecbd03f6..486408159a 100644 --- a/Code/Sandbox/Editor/editor_core_files.cmake +++ b/Code/Sandbox/Editor/editor_core_files.cmake @@ -22,6 +22,8 @@ set(FILES Include/IEditorMaterial.h Include/IEditorMaterialManager.h Include/IImageUtil.h + EditorViewportSettings.cpp + EditorViewportSettings.h Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.qrc Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index f6537909e9..4832e2b8c2 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -437,9 +437,6 @@ set(FILES GotoPositionDlg.cpp GotoPositionDlg.h GotoPositionDlg.ui - GridSettingsDialog.cpp - GridSettingsDialog.h - GridSettingsDialog.ui InfoBar.cpp InfoBar.qrc InfoBar.h @@ -465,9 +462,6 @@ set(FILES SelectLightAnimationDialog.h SelectSequenceDialog.cpp SelectSequenceDialog.h - ShadersDialog.cpp - ShadersDialog.h - ShadersDialog.ui StartupLogoDialog.cpp StartupLogoDialog.h StartupLogoDialog.ui @@ -659,10 +653,6 @@ set(FILES ProcessInfo.cpp ProcessInfo.h Report.h - ShaderCache.cpp - ShaderCache.h - ShaderEnum.cpp - ShaderEnum.h SurfaceTypeValidator.cpp SurfaceTypeValidator.h TrackView/AtomOutputFrameCapture.cpp @@ -751,15 +741,11 @@ set(FILES SettingsBlock.cpp SettingsBlock.h Util/AffineParts.h - Util/ArcBall.cpp - Util/ArcBall.h Util/AutoLogTime.cpp Util/AutoLogTime.h Util/AutoDirectoryRestoreFileDialog.h Util/AutoDirectoryRestoreFileDialog.cpp Util/CryMemFile.h - Util/CubemapUtils.cpp - Util/CubemapUtils.h Util/DynamicArray2D.cpp Util/DynamicArray2D.h Util/EditorAutoLevelLoadTest.cpp @@ -833,17 +819,11 @@ set(FILES Util/ImageASC.h Util/ImageBT.cpp Util/ImageBT.h - Util/Image_DXTC.cpp - Util/Image_DXTC.h Util/ImageGif.cpp Util/ImageGif.h Util/ImageTIF.cpp Util/ImageTIF.h Util/Math.h - Util/Ruler.cpp - Util/RulerPoint.cpp - Util/Ruler.h - Util/RulerPoint.h Util/UIEnumerations.cpp Util/UIEnumerations.h WelcomeScreen/WelcomeScreenDialog.h @@ -852,8 +832,6 @@ set(FILES WelcomeScreen/WelcomeScreenDialog.qrc 2DViewport.cpp 2DViewport.h - Grid.cpp - Grid.h LayoutWnd.cpp LayoutWnd.h EditorViewportWidget.cpp diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.cpp deleted file mode 100644 index 2eff76c738..0000000000 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ComponentEntityEditorPlugin_precompiled.h" -#include "ComponentEntityDebugPrinter.h" - -#include -#include - -ComponentEntityDebugPrinter::ComponentEntityDebugPrinter() -{ - AZ::TickBus::Handler::BusConnect(); -} - -void ComponentEntityDebugPrinter::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) -{ - if (!GetIEditor()->GetRenderer()) - { - return; - } - - ICVar* displayInfo = GetIEditor()->GetSystem()->GetIConsole()->GetCVar("r_DisplayInfo"); - if (!displayInfo || displayInfo->GetIVal() == 0) - { - return; - } - - float x = 2.f; - float y = 2.f; - - SDrawTextInfo textInfo; - textInfo.xscale = 1.25f; - textInfo.yscale = textInfo.xscale; - textInfo.flags = eDrawText_2D | eDrawText_FixedSize | eDrawText_800x600 | eDrawText_Monospace; - - // Figure out whether we're querying the Game or Editor entity context - AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); - if (GetIEditor()->IsInGameMode()) - { - AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); - } - else - { - AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(entityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); - } - if (entityContextId.IsNull()) - { - return; - } - - // Print the number of entities in the level - AZ::SliceComponent* rootSlice = nullptr; - AzFramework::SliceEntityOwnershipServiceRequestBus::EventResult(rootSlice, entityContextId, - &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetRootSlice); - if (rootSlice) - { - size_t numEntities = rootSlice->GetInstantiatedEntityCount(); - if (numEntities > 0) - { - GetIEditor()->GetRenderer()->DrawTextQueued(Vec3(x, y, 0), textInfo, AZStd::string::format("Entities: %zu", numEntities).c_str()); - } - } -} diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.h deleted file mode 100644 index 5a8c1d4856..0000000000 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityDebugPrinter.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include - -/** - * Prints debug statistics about Component Entities to screen - */ -class ComponentEntityDebugPrinter - : private AZ::TickBus::Handler -{ -public: - AZ_CLASS_ALLOCATOR(ComponentEntityDebugPrinter, AZ::SystemAllocator, 0); - - ComponentEntityDebugPrinter(); - -private: - ////////////////////////////////////////////////////////////////////////// - // TickBus - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - ////////////////////////////////////////////////////////////////////////// -}; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp index c85ed1248f..df2e6bae10 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp @@ -915,14 +915,6 @@ void CComponentEntityObject::Display(DisplayContext& dc) m_entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, AzFramework::ViewportInfo{ dc.GetView()->asCViewport()->GetViewportId() }, *debugDisplay); - - if (showIcons) - { - if (!displaySelectionHelper && !IsSelected()) - { - m_entityIconVisible = DisplayEntityIcon(dc, *debugDisplay); - } - } } } } @@ -984,38 +976,6 @@ void CComponentEntityObject::OnContextMenu(QMenu* /*pMenu*/) // Deliberately bypass the base class implementation (CEntityObject::OnContextMenu()). } -bool CComponentEntityObject::DisplayEntityIcon( - DisplayContext& displayContext, AzFramework::DebugDisplayRequests& debugDisplay) -{ - if (!m_hasIcon) - { - return false; - } - - const QPoint entityScreenPos = displayContext.GetView()->WorldToView(GetWorldPos()); - - const Vec3 worldPos = GetWorldPos(); - const CCamera& camera = gEnv->pRenderer->GetCamera(); - const Vec3 cameraToEntity = (worldPos - camera.GetMatrix().GetTranslation()); - const float distSq = cameraToEntity.GetLengthSquared(); - if (distSq > square(s_kIconMaxWorldDist)) - { - return false; - } - - // Draw component icons on top of meshes (no depth testing) - int iconFlags = (int) DisplayContext::ETextureIconFlags::TEXICON_ON_TOP; - SetDrawTextureIconProperties(displayContext, worldPos, 1.0f, iconFlags); - - const float iconScale = s_kIconMinScale + (s_kIconMaxScale - s_kIconMinScale) * (1.0f - clamp_tpl(max(0.0f, sqrt_tpl(distSq) - s_kIconCloseDist) / s_kIconFarDist, 0.0f, 1.0f)); - const float worldDistToScreenScaleFraction = 0.045f; - const float screenScale = displayContext.GetView()->GetScreenScaleFactor(GetWorldPos()) * worldDistToScreenScaleFraction; - - debugDisplay.DrawTextureLabel(m_iconTexture, LYVec3ToAZVec3(worldPos), s_kIconSize * iconScale, s_kIconSize * iconScale, GetTextureIconFlags()); - - return true; -} - void CComponentEntityObject::SetupEntityIcon() { bool hideIconInViewport = false; @@ -1031,8 +991,9 @@ void CComponentEntityObject::SetupEntityIcon() { m_hasIcon = true; - int textureId = GetIEditor()->GetIconManager()->GetIconTexture(m_icon.c_str()); - m_iconTexture = GetIEditor()->GetRenderer() ? GetIEditor()->GetRenderer()->EF_GetTextureByID(textureId) : nullptr; + // ToDo: Get from Atom? + // int textureId = GetIEditor()->GetIconManager()->GetIconTexture(m_icon.c_str()); + m_iconTexture = nullptr; } } } diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index c7c501c70a..33d4b5baf4 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -59,7 +59,6 @@ #include #include "Objects/ComponentEntityObject.h" -#include "ComponentEntityDebugPrinter.h" #include "ISourceControl.h" #include "UI/QComponentEntityEditorMainWindow.h" @@ -72,7 +71,6 @@ #include #include #include -#include #include #include #include @@ -141,7 +139,6 @@ SandboxIntegrationManager::SandboxIntegrationManager() , m_startedUndoRecordingNestingLevel(0) , m_dc(nullptr) , m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager()) - , m_entityDebugPrinter(aznew ComponentEntityDebugPrinter()) { // Required to receive events from the Cry Engine undo system GetIEditor()->GetUndoManager()->AddListener(this); @@ -1998,92 +1995,6 @@ void SandboxIntegrationManager::BrowseForAssets(AssetSelectionModel& selection) AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, GetMainWindow()); } -void SandboxIntegrationManager::GenerateCubemapForEntity(AZ::EntityId entityId, AZStd::string* cubemapOutputPath, bool hideEntity) -{ - GenerateCubemapWithIDForEntity(entityId, AZ::Uuid::CreateNull(), cubemapOutputPath, hideEntity, false); -} - -void SandboxIntegrationManager::GenerateCubemapWithIDForEntity(AZ::EntityId entityId, AZ::Uuid cubemapId, - AZStd::string* cubemapOutputPath, bool hideEntity, bool hasCubemapId) -{ - AZ::u32 resolution = 0; - EBUS_EVENT_ID_RESULT(resolution, entityId, LmbrCentral::EditorLightComponentRequestBus, GetCubemapResolution); - - if (resolution > 0) - { - CComponentEntityObject* componentEntity = CComponentEntityObject::FindObjectForEntity(entityId); - - if (componentEntity) - { - QString levelfolder = GetIEditor()->GetGameEngine()->GetLevelPath(); - QString levelname = Path::GetFile(levelfolder).toLower(); - QString fullGameFolder = QString(Path::GetEditingGameDataFolder().c_str()); - QString texturename; - if (hasCubemapId) - { - texturename = QStringLiteral("%1_cm.tif").arg(cubemapId.ToString(false, false)); - } - else - { - texturename = QStringLiteral("%1_cm.tif").arg(static_cast(componentEntity->GetAssociatedEntityId())); - } - texturename = texturename.toLower(); - - QString fullFolder = Path::SubDirectoryCaseInsensitive(fullGameFolder, {"textures", "cubemaps", levelname}); - QString fullFilename = QDir(fullFolder).absoluteFilePath(texturename); - QString relFilename = QDir(fullGameFolder).relativeFilePath(fullFilename); - - bool directlyExists = CFileUtil::CreateDirectory(fullFolder.toUtf8().data()); - if (!directlyExists) - { - QMessageBox::warning(GetMainWindow(), QObject::tr("Cubemap Generation Failed"), QString(QObject::tr("Failed to create destination path '%1'")).arg(fullFolder)); - return; - } - - if (CubemapUtils::GenCubemapWithObjectPathAndSize(fullFilename, componentEntity, static_cast(resolution), hideEntity)) - { - AZStd::string assetPath = relFilename.toUtf8().data(); - AzFramework::StringFunc::Path::ReplaceExtension(assetPath, ".dds"); - - EBUS_EVENT_ID(entityId, LmbrCentral::EditorLightComponentRequestBus, SetCubemap, assetPath); - - if (cubemapOutputPath) - { - *cubemapOutputPath = AZStd::move(assetPath); - } - } - else - { - QMessageBox::warning(GetMainWindow(), QObject::tr("Cubemap Generation Failed"), QObject::tr("Unspecified error")); - } - } - } -} - -void SandboxIntegrationManager::GenerateAllCubemaps() -{ - AZStd::string cubemapOutputPath; - - std::vector results; - results.reserve(128); - GetIEditor()->GetObjectManager()->FindObjectsOfType(OBJTYPE_AZENTITY, results); - for (std::vector::iterator end = results.end(), item = results.begin(); item != end; ++item) - { - CComponentEntityObject* componentEntity = static_cast(*item); - - //check if it's customized cubemap, only generate it if it's not. - bool isCustomizedCubemap = true; - EBUS_EVENT_ID_RESULT(isCustomizedCubemap, componentEntity->GetAssociatedEntityId(), LmbrCentral::EditorLightComponentRequestBus, UseCustomizedCubemap); - - if (isCustomizedCubemap) - { - continue; - } - - GenerateCubemapForEntity(componentEntity->GetAssociatedEntityId(), nullptr, true); - } -} - void SandboxIntegrationManager::SetColor(float r, float g, float b, float a) { if (m_dc) @@ -2575,19 +2486,6 @@ void SandboxIntegrationManager::Draw2dTextLabel(float x, float y, float size, co } } -void SandboxIntegrationManager::DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& textColor, const AZ::Vector4& textBackColor) -{ - if (m_dc) - { - m_dc->DrawTextOn2DBox( - AZVec3ToLYVec3(pos), - text, - textScale, - ColorF(AZVec3ToLYVec3(textColor.GetAsVector3()), textColor.GetW()), - ColorF(AZVec3ToLYVec3(textBackColor.GetAsVector3()), textBackColor.GetW())); - } -} - void SandboxIntegrationManager::DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) { if (m_dc) @@ -2614,8 +2512,12 @@ void SandboxIntegrationManager::DrawTextureLabel(ITexture* texture, const AZ::Ve void SandboxIntegrationManager::DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) { - ITexture* texture = GetIEditor()->GetRenderer()->EF_GetTextureByID(textureId); - DrawTextureLabel(texture, pos, sizeX, sizeY, texIconFlags); + // ToDo: With Atom? + AZ_UNUSED(textureId); + AZ_UNUSED(pos); + AZ_UNUSED(sizeX); + AZ_UNUSED(sizeY); + AZ_UNUSED(texIconFlags); } void SandboxIntegrationManager::SetLineWidth(float width) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 0cbfe1df93..b3c60bca45 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -143,9 +143,6 @@ private: QDockWidget* InstanceViewPane(const char* paneName) override; void CloseViewPane(const char* paneName) override; void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override; - void GenerateAllCubemaps() override; - void GenerateCubemapForEntity(AZ::EntityId entityId, AZStd::string* cubemapOutputPath, bool hideEntity) override; - void GenerateCubemapWithIDForEntity(AZ::EntityId entityId, AZ::Uuid cubemapId, AZStd::string* cubemapOutputPath, bool hideEntity, bool hasCubemapId) override; void HandleObjectModeSelection(const AZ::Vector2& point, int flags, bool& handled) override; void UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) override; void CreateEditorRepresentation(AZ::Entity* entity) override; @@ -249,7 +246,6 @@ private: void DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float fHeadScale, bool b2SidedArrow) override; void DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter, int srcOffsetX, int scrOffsetY) override; void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter) override; - void DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override; void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; void DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; void SetLineWidth(float width) override; @@ -365,8 +361,6 @@ private: DisplayContext* m_dc; - AZStd::unique_ptr m_entityDebugPrinter; - AZStd::vector m_sliceAssetDeletionErrorRestoreInfos; // Tracks new entities that have not yet been saved. diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake index 26998a5bda..6672bc8b47 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake @@ -17,8 +17,6 @@ set(FILES SandboxIntegration.cpp ComponentEntityEditorPlugin_precompiled.cpp ComponentEntityEditorPlugin_precompiled.h - ComponentEntityDebugPrinter.h - ComponentEntityDebugPrinter.cpp UI/ComponentEntityEditorOutlinerWindow.qrc UI/QComponentEntityEditorMainWindow.h UI/QComponentEntityEditorMainWindow.cpp diff --git a/Code/Sandbox/Plugins/EditorCommon/ManipScene.cpp b/Code/Sandbox/Plugins/EditorCommon/ManipScene.cpp deleted file mode 100644 index 5b76ca8804..0000000000 --- a/Code/Sandbox/Plugins/EditorCommon/ManipScene.cpp +++ /dev/null @@ -1,1739 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorCommon_precompiled.h" -#include "ManipScene.h" - -#include "Serialization.h" -#include "QViewportEvents.h" - -#include -#include -#include -#include -#include - -#include "../EditorCommon/QViewport.h" - -#include - -// from Sandbox/Editor: -#include "Include/IDisplayViewport.h" -#include "Include/HitContext.h" -#include "Objects/DisplayContext.h" -#include "RenderHelpers/AxisHelper.h" -#include "Util/EditorUtils.h" -#include "Util/Math.h" -// ^^^ - -#include "DisplayViewportAdapter.h" -#include - -namespace Manip -{ - static unsigned int GetLayerBits(const SElements& elements) - { - unsigned int result = 0; - for (size_t i = 0; i < elements.size(); ++i) - { - result |= 1 << elements[i].layer; - } - return result; - } - - - static unsigned int GetLayerBits(const SElements& elements, const SSelectionSet& selection) - { - unsigned int result = 0; - for (size_t i = 0; i < elements.size(); ++i) - { - if (selection.Contains(elements[i].id)) - { - result |= 1 << elements[i].layer; - } - } - return result; - } - - - static QuatT GetGizmoOrientation(const QuatT& transform, [[maybe_unused]] const CCamera* camera, ETransformationSpace space) - { - if (space == SPACE_LOCAL) - { - return transform; - } - else - { - return QuatT(IDENTITY, transform.t); - } - } - // --------------------------------------------------------------------------- - - SERIALIZATION_ENUM_BEGIN(ETransformationMode, "Transformation Mode") - SERIALIZATION_ENUM(MODE_TRANSLATE, "translate", "Translate") - SERIALIZATION_ENUM(MODE_ROTATE, "rotate", "Rotate") - SERIALIZATION_ENUM(MODE_SCALE, "scale", "Scale") - SERIALIZATION_ENUM_END() - - // --------------------------------------------------------------------------- - - CScene::CScene() - : m_axisHelper(new CAxisHelper()) - , m_showGizmo(true) - , m_transformationMode(MODE_TRANSLATE) - , m_transformationSpace(SPACE_LOCAL) - , m_customDrawer(0) - , m_customTracer(0) - , m_spaceProvider(0) - , m_temporaryLocalDelta(IDENTITY) - , m_visibleLayerMask(0xffffffff) - { - m_axisHelper->SetMode(CAxisHelper::MOVE_MODE); - } - - - CScene::~CScene() - { - } - - static void DrawElement([[maybe_unused]] const SRenderContext& rc, const SElement& element, ElementId highlightedItem, bool isSelected, bool xRay, IElementDrawer* customDrawer, CScene* spaceProvider, const SLookSettings& lookSettings) - { - if (element.hidden) - { - return; - } - - IRenderer* renderer = GetIEditor()->GetRenderer(); - IRenderAuxGeom* aux = renderer->GetIRenderAuxGeom(); - - SAuxGeomRenderFlags defaultFlags(e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeNone | e_DepthWriteOn | e_DepthTestOn); - SAuxGeomRenderFlags xRayFlags(e_Mode3D | e_AlphaBlended | e_DrawInFrontOn | e_FillModeSolid | e_CullModeNone | e_DepthWriteOff | e_DepthTestOff); - aux->SetRenderFlags(xRay ? xRayFlags : defaultFlags); - - QuatT transform = spaceProvider->ElementToWorldSpace(element); - Matrix34 transformM(transform); - - if (element.shape == SHAPE_BOX) - { - OBB obb; - obb.m33 = Matrix33(IDENTITY); - obb.c = element.placement.center; - obb.h = element.placement.size * 0.5f; - - bool isHighlighted2 = highlightedItem == element.id; - ColorB color; - if (isHighlighted2) - { - color = lookSettings.proxyHighlightColor; - } - else if (isSelected) - { - color = lookSettings.proxySelectionColor; - } - else if (element.colorGroup == ELEMENT_COLOR_CLOTH) - { - color = lookSettings.clothProxyColor; - } - else - { - color = lookSettings.proxyColor; - } - - ColorB innerColor = color; - - ColorB edgeColor(innerColor.r, innerColor.g, innerColor.b, 255); - - bool drawBB = false; - if (!customDrawer || !customDrawer->Draw(element)) - { - drawBB = true; - } - - if (isSelected || isHighlighted2) - { - drawBB = true; - } - - if (drawBB) - { - aux->DrawOBB(obb, transformM, false, edgeColor, eBBD_Faceted); - } - } - else if (element.shape == SHAPE_AXES) - { - OBB obb; - obb.m33 = Matrix33(IDENTITY); - obb.c = element.placement.center; - obb.h = Vec3(0.01f, 0.01f, 0.01f); - - bool isHighlighted2 = highlightedItem == element.id; - ColorB color; - if (isHighlighted2) - { - color = lookSettings.proxyHighlightColor; - } - else if (isSelected) - { - color = lookSettings.proxySelectionColor; - } - else - { - color = lookSettings.proxyColor; - } - - ColorB innerColor = color; - - ColorB edgeColor(innerColor.r, innerColor.g, innerColor.b, 255); - - bool drawBB = false; - if (!customDrawer || !customDrawer->Draw(element)) - { - drawBB = true; - } - if (isSelected || isHighlighted2) - { - drawBB = true; - } - - if (drawBB) - { - aux->DrawOBB(obb, transformM, false, edgeColor, eBBD_Faceted); - } - } - } - - void CScene::OnViewportRender(const SRenderContext& rc) - { - SignalRenderElements(m_elements, rc); - - for (int xRayPass = 0; xRayPass < 2; ++xRayPass) - { - size_t numElements = m_elements.size(); - for (size_t i = 0; i < numElements; ++i) - { - SElement& element = m_elements[i]; - bool isSelected = m_selection.Contains(element.id); - if (!isSelected && !IsLayerVisible(element.layer)) - { - continue; - } - - bool xRay = isSelected || element.id == m_highlightedItem || element.alwaysXRay; - - if (int(xRay) != xRayPass) - { - continue; - } - - DrawElement(rc, element, m_highlightedItem, m_selection.Contains(element.id), xRay, m_customDrawer, this, m_lookSettings); - } - } - - if (m_mouseDragHandler.get()) - { - m_mouseDragHandler->Render(rc); - } - - bool hasSelection = !m_selection.IsEmpty(); - - if (m_showGizmo && hasSelection) - { - int selectionCaps = GetSelectionCaps(); - Matrix34 m = Matrix34(GetGizmoOrientation(GetSelectionTransform(SPACE_WORLD), rc.viewport->Camera(), m_transformationSpace)); - DisplayContext dc; - CDisplayViewportAdapter view(rc.viewport); - dc.SetView(&view); - - SGizmoParameters gizmoParameters; - gizmoParameters.axisGizmoScale = 0.2f; - - if (m_axisHelper.get()) - { - switch (m_transformationMode) - { - case MODE_TRANSLATE: - m_axisHelper->SetMode(CAxisHelper::MOVE_MODE); - gizmoParameters.enabled = (selectionCaps & CAP_MOVE) != 0; - break; - case MODE_ROTATE: - m_axisHelper->SetMode(CAxisHelper::ROTATE_MODE); - gizmoParameters.enabled = (selectionCaps & CAP_ROTATE) != 0; - break; - case MODE_SCALE: - m_axisHelper->SetMode(CAxisHelper::SCALE_MODE); - gizmoParameters.enabled = (selectionCaps & CAP_SCALE) != 0; - break; - } - m_axisHelper->DrawAxis(m, gizmoParameters, dc); - } - } - } - - void CScene::SetTransformationMode(ETransformationMode mode) - { - m_transformationMode = mode; - } - - void CScene::SetTransformationSpace(ETransformationSpace space) - { - m_transformationSpace = space; - } - - ETransformationMode CScene::TransformationMode() const - { - return m_transformationMode; - } - - void CScene::SetSelection(const SSelectionSet& selection) - { - if (m_selection != selection) - { - m_selection = selection; - SignalSelectionChanged(); - } - } - - void CScene::AddToSelection(ElementId elementId) - { - m_selection.Add(elementId); - SignalSelectionChanged(); - } - - void CScene::ApplyToAll(EElementAction action) - { - size_t count = m_elements.size(); - for (size_t i = 0; i < count; ++i) - { - SElement& m = m_elements[i]; - if (m.hidden) - { - m.action = action; - //m.hidden = false; - } - } - SignalElementsChanged(GetLayerBits(m_elements)); - } - - void CScene::ApplyToSelection(EElementAction action) - { - size_t count = m_elements.size(); - for (size_t i = 0; i < count; ++i) - { - SElement& m = m_elements[i]; - if (m_selection.Contains(m.id)) - { - m.action = action; - //m.hidden = true; - } - } - SignalElementsChanged(GetLayerBits(m_elements, m_selection)); - } - - void CScene::OnViewportKey(const SKeyEvent& ev) - { - QKeySequence key(ev.key); - if (ev.type == SKeyEvent::TYPE_PRESS) - { - if (key == QKeySequence(Qt::Key_U) || key == QKeySequence(Qt::Key_Z | Qt::CTRL)) - { - SignalUndo(); - } - else if (key == QKeySequence(Qt::Key_Y | Qt::CTRL) || key == QKeySequence(Qt::Key_Z | Qt::CTRL | Qt::SHIFT)) - { - SignalRedo(); - } - else if (key == QKeySequence(Qt::ALT | Qt::Key_H) || key == QKeySequence(Qt::SHIFT | Qt::Key_H)) - { - ApplyToAll(ACTION_UNHIDE); - } - else if (key == QKeySequence(Qt::Key_H)) - { - ApplyToSelection(ACTION_HIDE); - } - else if (key == QKeySequence(Qt::Key_Delete)) - { - ApplyToSelection(ACTION_DELETE); - } - else if (key == QKeySequence(Qt::Key_1)) - { - m_transformationMode = MODE_TRANSLATE; - SignalManipulationModeChanged(); - SignalPropertiesChanged(); - } - else if (key == QKeySequence(Qt::Key_2)) - { - m_transformationMode = MODE_ROTATE; - SignalManipulationModeChanged(); - SignalPropertiesChanged(); - } - else if (key == QKeySequence(Qt::Key_3)) - { - m_transformationMode = MODE_SCALE; - SignalManipulationModeChanged(); - SignalPropertiesChanged(); - } - } - } - - bool CScene::ProcessesViewportKey(const QKeySequence& key) - { - static QSet overriddenKeys = { - QKeySequence(Qt::Key_U), - QKeySequence(Qt::Key_Z | Qt::CTRL), - QKeySequence(Qt::Key_Y | Qt::CTRL), - QKeySequence(Qt::Key_Z | Qt::CTRL | Qt::SHIFT), - QKeySequence(Qt::ALT | Qt::Key_H), - QKeySequence(Qt::SHIFT | Qt::Key_H), - QKeySequence(Qt::Key_H), - QKeySequence(Qt::Key_Delete), - QKeySequence(Qt::Key_1), - QKeySequence(Qt::Key_2), - QKeySequence(Qt::Key_3) - }; - - // Check if the parameter key is one that we care about in OnViewportKey - // If we don't, matching shortcuts attached to the widget will get processed - // instead, and CScene::OnViewportKey will never get called - return overriddenKeys.contains(key); - } - - bool RayHitsElement(Vec3* intersectionPoint, const Ray& ray, const SElement& element, IElementTracer* customTracer, CScene* spaceProvider) - { - QuatT parentSpace(IDENTITY); - if (spaceProvider) - { - parentSpace = spaceProvider->GetParentSpace(element); - } - - OBB obb; - if (element.shape == SHAPE_BOX) - { - obb.m33 = Matrix33((parentSpace * element.placement.transform).q); - obb.c = element.placement.center; - obb.h = element.placement.size * 0.5f; - } - else - { - obb.m33 = IDENTITY; - obb.c = Vec3(ZERO); - obb.h = element.placement.size * 0.5f; - } - - if (Intersect::Ray_OBB(ray, (parentSpace * element.placement.transform).t, obb, *intersectionPoint) != 0) - { - if (customTracer) - { - return customTracer->HitRay(intersectionPoint, ray, element); - } - - return true; - } - return false; - } - - static SElement* HitElementWithRay(Vec3* hitPoint, SElements& elements, const Ray& ray, IElementTracer* customTracer, CScene* spaceProvider) - { - const float BIG_VALUE = 1e20f; - float closestDistanceSquare = BIG_VALUE; - int hitPickPriority = INT_MIN; - SElement* closestElement = 0; - - size_t numElements = elements.size(); - for (size_t i = 0; i < numElements; ++i) - { - SElement& element = elements[i]; - if (element.hidden) - { - continue; - } - if (!spaceProvider->IsLayerVisible(element.layer) && - !spaceProvider->Selection().Contains(element.id)) - { - continue; - } - - Vec3 intersectionPoint; - if (RayHitsElement(&intersectionPoint, ray, element, customTracer, spaceProvider)) - { - float distanceSquare = (intersectionPoint - ray.origin).GetLengthSquared(); - if (distanceSquare < closestDistanceSquare || int(element.mousePickPriority) > hitPickPriority) - { - closestDistanceSquare = distanceSquare; - closestElement = &element; - hitPickPriority = element.mousePickPriority; - *hitPoint = intersectionPoint; - } - } - } - return closestElement; - } - - static ElementId HitSelectionWithRay(Vec3* hitPoint, SElements& elements, const Ray& ray, IElementTracer* customTracer, CScene* spaceProvider) - { - SElement* element = HitElementWithRay(hitPoint, elements, ray, customTracer, spaceProvider); - if (element) - { - return element->id; - } - - return 0; - } - - struct STransformConstraint - { - enum EType - { - NONE, - AXIS, - PLANE - }; - - EType type; - Plane plane; - Vec3 axis; - Vec3 localAxis; - - Vec3 GetAxis(ETransformationSpace space) - { - switch (space) - { - case SPACE_LOCAL: - return localAxis; - default: - return axis; - } - } - - STransformConstraint() - : type(NONE) - { - } - }; - - struct CScene::SMoveHandler - : IMouseDragHandler - { - CScene* m_scene; - Vec3 m_lastPoint; - Vec3 m_startPoint; - Vec2i m_startMousePosition; - STransformConstraint m_constraint; - SElements m_elements; - SElements m_transformedElements; - int m_layerBits; - - SMoveHandler(CScene* scene, const STransformConstraint& constraint) - : m_scene(scene) - , m_constraint(constraint) - , m_layerBits(0) - , m_lastPoint(ZERO) - , m_startPoint(ZERO) - { - } - - bool Begin(const SMouseEvent& ev, Vec3 hitPoint) override - { - m_startMousePosition = Vec2i(ev.x, ev.y); - m_startPoint = hitPoint; - - m_scene->GetSelectedElements(&m_elements); - m_layerBits = GetLayerBits(m_elements); - - if (!ReprojectStartPoint(ev.viewport)) - { - return false; - } - return true; - } - - - bool ReprojectStartPoint(QViewport* viewport) - { - Ray ray; - MAKE_SURE(viewport->ScreenToWorldRay(&ray, m_startMousePosition.x, m_startMousePosition.y), return false); - - if (m_constraint.type == STransformConstraint::PLANE) - { - Intersect::Ray_Plane(ray, m_constraint.plane, m_startPoint, false); - } - else if (m_constraint.type == STransformConstraint::AXIS) - { - Vec3 point; - Vec3 axis = m_constraint.GetAxis(m_scene->TransformationSpace()); - RayToLineDistance(ray.origin, ray.origin + ray.direction, - m_startPoint - axis * 10000.0f, m_startPoint + axis * 10000.0f, point); - m_startPoint = m_startPoint + axis * axis.dot(point - m_startPoint); - } - return true; - } - - void Update(const SMouseEvent& ev) override - { - ReprojectStartPoint(ev.viewport); - - Ray ray; - MAKE_SURE(ev.viewport->ScreenToWorldRay(&ray, ev.x, ev.y), return ); - - if (m_constraint.type == STransformConstraint::PLANE) - { - Vec3 point(0.0f, 0.0f, 0.0f); - Intersect::Ray_Plane(ray, m_constraint.plane, point, false); - - Vec3 delta = point - m_startPoint; - Move(delta); - } - else if (m_constraint.type == STransformConstraint::AXIS) - { - Vec3 point = m_startPoint; - Vec3 axis = m_constraint.GetAxis(m_scene->TransformationSpace()); - RayToLineDistance(ray.origin, ray.origin + ray.direction, - m_startPoint - axis * 10000.0f, m_startPoint + axis * 10000.0f, point); - Vec3 newPoint = m_startPoint + axis * axis.dot(point - m_startPoint); - Vec3 delta = newPoint - m_startPoint; - Move(delta); - } - } - - void Move(Vec3 delta) - { - m_transformedElements = m_elements; - for (size_t i = 0; i < m_transformedElements.size(); ++i) - { - SElement& e = m_transformedElements[i]; - QuatT parentSpace = m_scene->GetParentSpace(e) * QuatT(e.placement.transform.q, ZERO); - QuatT localDelta = parentSpace.GetInverted() * (QuatT(IDENTITY, delta) * parentSpace); - m_scene->m_temporaryLocalDelta = localDelta; - e.placement.transform = e.placement.transform * localDelta; - e.placement.transform.q.Normalize(); - } - m_scene->UpdateElements(m_transformedElements); - m_scene->SignalElementContinousChange(m_layerBits); - } - - void End([[maybe_unused]] const SMouseEvent& ev) override - { - m_scene->m_temporaryLocalDelta = QuatT(IDENTITY); - m_scene->SignalElementsChanged(m_layerBits); - } - }; - - struct CScene::SRotationHandler - : public IMouseDragHandler - { - CScene* m_scene; - STransformConstraint m_constraint; - SElements m_elements; - SElements m_transformedElements; - int m_layerBits; - Vec3 m_origin; - Vec2i m_startPoint; - - SRotationHandler(CScene* scene, const STransformConstraint& constraint) - : m_scene(scene) - , m_constraint(constraint) - , m_layerBits(0) - , m_origin(ZERO) - , m_startPoint(ZERO) - { - if (m_constraint.type == STransformConstraint::PLANE) - { - // TODO: Apart from having rotation around axis of gizmo (as Sandbox does) it - // is possible here to rotate around viewer axis. This part can be considerably - // improved by making sure that picked point on the proxy keeps touching the - // mouse pointer. - - m_constraint.localAxis = m_constraint.plane.n; - m_constraint.axis = Vec3(0.0f, 0.0f, 1.0f); - m_constraint.type = STransformConstraint::AXIS; - } - - m_scene->GetSelectedElements(&m_elements); - m_layerBits = GetLayerBits(m_elements); - - m_origin = m_scene->GetSelectionTransform(SPACE_WORLD).t; - } - - bool Begin(const SMouseEvent& ev, [[maybe_unused]] Vec3 hitPoint) override - { - m_startPoint = Vec2i(ev.x, ev.y); - return true; - } - - void Update(const SMouseEvent& ev) override - { - if (ev.y != m_startPoint.y) - { - float angle = ((ev.y - m_startPoint.y) * 0.01f) * 3.1415926f; - QuatT rotation; - float cos, sin; - sin = sinf(angle); - cos = cosf(angle); - Vec3 axis = m_constraint.GetAxis(m_scene->TransformationSpace()); - rotation.SetRotationAA(cos, sin, axis); - - m_transformedElements = m_elements; - for (size_t i = 0; i < m_elements.size(); ++i) - { - SElement& e = m_transformedElements[i]; - QuatT t = m_scene->ElementToWorldSpace(e); - t.t -= m_origin; - t = rotation * t; - t.t += m_origin; - m_scene->m_temporaryLocalDelta = m_scene->ElementToWorldSpace(m_elements[i]).GetInverted() * t; - m_scene->WorldSpaceToElement(&e, t); - } - m_scene->UpdateElements(m_transformedElements); - m_scene->SignalElementContinousChange(m_layerBits); - } - } - - void End([[maybe_unused]] const SMouseEvent& ev) override - { - m_scene->m_temporaryLocalDelta = QuatT(IDENTITY); - m_scene->SignalElementsChanged(m_layerBits); - } - }; - - static Vec3 ScaleAround(Vec3 p, Vec3 origin, float scale) - { - return (p - origin) * scale + origin; - } - - struct CScene::SScalingHandler - : public IMouseDragHandler - { - CScene* m_scene; - STransformConstraint m_constraint; - SElements m_elements; - SElements m_transformedElements; - Vec3 m_origin; - Vec3 m_size; - Vec3 m_hitPoint; - Vec2i m_startPoint; - unsigned int m_layerBits; - - SScalingHandler(CScene* scene, const STransformConstraint& constraint) - : m_scene(scene) - , m_constraint(constraint) - , m_layerBits(0) - , m_origin(ZERO) - , m_size(ZERO) - , m_hitPoint(ZERO) - , m_startPoint(ZERO) - { - } - - bool Begin(const SMouseEvent& ev, Vec3 hitPoint) override - { - m_hitPoint = hitPoint; - m_startPoint = Vec2i(ev.x, ev.y); - m_scene->GetSelectedElements(&m_elements); - m_layerBits = GetLayerBits(m_elements); - m_origin = m_scene->GetSelectionTransform(SPACE_WORLD).t; - m_size = m_scene->GetSelectionSize(); - return true; - } - - void Update(const SMouseEvent& ev) override - { - float screenScaleFactor = 0.0f; - if (const CCamera* camera = ev.viewport->Camera()) - { - screenScaleFactor = camera->GetPosition().GetDistance(m_hitPoint); - if (screenScaleFactor < camera->GetNearPlane()) - { - screenScaleFactor = camera->GetNearPlane(); - } - } - - m_transformedElements = m_elements; - - if (m_transformedElements.size() == 1) - { - Vec3& size = m_transformedElements[0].placement.size; - float difference = -(ev.y - m_startPoint.y) * 0.01f * screenScaleFactor; - Vec3 axis = m_constraint.GetAxis(m_scene->TransformationSpace()); - size = (size + size.CompMul(axis * difference)).abs(); - } - else - { - float difference = -(ev.y - m_startPoint.y) * 0.01f * screenScaleFactor; - float sizeDifference = max(0.01f, fabsf(1.0f + difference)); - - for (size_t i = 0; i < m_transformedElements.size(); ++i) - { - SElement& g = m_transformedElements[i]; - g.placement.transform.t = ScaleAround(g.placement.transform.t, m_origin, sizeDifference); - g.placement.size = g.placement.size * sizeDifference; - } - } - - m_scene->UpdateElements(m_transformedElements); - m_scene->SignalElementContinousChange(m_layerBits); - } - - void End([[maybe_unused]] const SMouseEvent& ev) override - { - m_scene->SignalElementsChanged(m_layerBits); - } - }; - - template - struct SRange - { - T low; - T high; - - SRange(T low, T high) - : low(low) - , high(high) - { - } - - SRange() - : low(T(0)) - , high(T(0)) - { - } - - void Add(T value) - { - if (value < low) - { - low = value; - } - if (value > high) - { - high = value; - } - } - - bool Intersects(const SRange& r) const - { - if (high < r.low) - { - return false; - } - if (low > r.high) - { - return false; - } - return true; - } - }; - - static bool RectsIntersect(Vec2i amin, Vec2i amax, Vec2i bmin, Vec2i bmax) - { - if (!SRange(amin.x, amax.x).Intersects(SRange(bmin.x, bmax.x))) - { - return false; - } - - if (!SRange(amin.y, amax.y).Intersects(SRange(bmin.y, bmax.y))) - { - return false; - } - - return true; - } - - static bool OBBOverlapsSelectionFrustum(const OBB& box, Vec2i rectMin, Vec2i rectMax, [[maybe_unused]] const Plane (&frustum)[4], IDisplayViewport* viewport) - { - Vec3 s = box.h; - Vec3 points[8] = { - box.m33 * Vec3(-s.x, -s.y, -s.z) + box.c, - box.m33 * Vec3(s.x, -s.y, -s.z) + box.c, - box.m33 * Vec3(s.x, s.y, -s.z) + box.c, - box.m33 * Vec3(-s.x, s.y, -s.z) + box.c, - box.m33 * Vec3(-s.x, -s.y, s.z) + box.c, - box.m33 * Vec3(s.x, -s.y, s.z) + box.c, - box.m33 * Vec3(s.x, s.y, s.z) + box.c, - box.m33 * Vec3(-s.x, s.y, s.z) + box.c, - }; - - Vec2i projectedPoints[8]; - Vec2i boundMin(INT_MAX, INT_MAX); - Vec2i boundMax(INT_MIN, INT_MIN); - for (int i = 0; i < 8; ++i) - { - Vec2i& p = projectedPoints[i]; - QPoint pt = viewport->WorldToView(points[i]); - p.x = pt.x(); - p.y = pt.y(); - if (p.x < boundMin.x) - { - boundMin.x = p.x; - } - if (p.y < boundMin.y) - { - boundMin.y = p.y; - } - if (p.x > boundMax.x) - { - boundMax.x = p.x; - } - if (p.y > boundMax.y) - { - boundMax.y = p.y; - } - } - - if (boundMin.x > rectMin.x && - boundMax.x < rectMax.x && - boundMin.y > rectMin.y && - boundMax.y < rectMax.y) - { - return true; - } - - if (!RectsIntersect(boundMin, boundMax, rectMin, rectMax)) - { - return false; - } - - struct Edge - { - Vec2 a; - Vec2 b; - }; - - Edge boxEdges[12] = { - { projectedPoints[0], projectedPoints[1] }, - { projectedPoints[1], projectedPoints[2] }, - { projectedPoints[2], projectedPoints[3] }, - { projectedPoints[3], projectedPoints[0] }, - { projectedPoints[4], projectedPoints[5] }, - { projectedPoints[5], projectedPoints[6] }, - { projectedPoints[6], projectedPoints[7] }, - { projectedPoints[7], projectedPoints[4] }, - { projectedPoints[0], projectedPoints[4] }, - { projectedPoints[1], projectedPoints[5] }, - { projectedPoints[2], projectedPoints[6] }, - { projectedPoints[3], projectedPoints[7] } - }; - - Vec2 rectPoints[4] = { - Vec2(float(rectMin.x), float(rectMin.y)), - Vec2(float(rectMax.x), float(rectMin.y)), - Vec2(float(rectMin.x), float(rectMax.y)), - Vec2(float(rectMax.x), float(rectMax.y)) - }; - - for (size_t i = 0; i < 12; ++i) - { - const Edge& e = boxEdges[i]; - Vec2 dir = e.b - e.a; - if (dir.GetLength2() < 1.0f) - { - continue; - } - dir.Normalize(); - Vec2 ort(dir.y, -dir.x); - - SRange range1; - range1.low = ort.Dot(projectedPoints[0]); - range1.high = range1.low; - for (size_t j = 1; j < 8; ++j) - { - float pos = ort.Dot(projectedPoints[j]); - range1.Add(pos); - } - - SRange range2; - range2.low = ort.Dot(rectPoints[0]); - range2.high = range2.low; - range2.Add(ort.Dot(rectPoints[1])); - range2.Add(ort.Dot(rectPoints[2])); - range2.Add(ort.Dot(rectPoints[3])); - - if (!range1.Intersects(range2)) - { - return false; - } - } - - return true; - } - - static bool ElementInFrustum(const SElement& element, Vec2i rectMin, Vec2i rectMax, const Plane (&frustum)[4], IDisplayViewport* viewport, CScene* scene) - { - OBB obb; - QuatT parentSpace = scene->GetParentSpace(element); - obb.m33 = Matrix33((parentSpace * element.placement.transform).q); - obb.c = Vec3((parentSpace * element.placement.transform).t); - obb.h = element.placement.size * 0.5f; - - return OBBOverlapsSelectionFrustum(obb, rectMin, rectMax, frustum, viewport); - } - - static void FindElementsInRect(vector* out, Vec2i point1, Vec2i point2, QViewport* viewport, - const vector& elements, [[maybe_unused]] ISpaceProvider* spaceProvider, CScene* scene) - { - int minX = min(point1.x, point2.x); - int minY = min(point1.y, point2.y); - int maxX = max(point1.x, point2.x); - int maxY = max(point1.y, point2.y); - Ray ray1; - if (!viewport->ScreenToWorldRay(&ray1, minX, minY)) - { - return; - } - Ray ray2; - if (!viewport->ScreenToWorldRay(&ray2, maxX, maxY)) - { - return; - } - - Matrix34 m = viewport->Camera()->GetMatrix(); - Vec3 xdir = m.GetColumn0().GetNormalized(); - Vec3 zdir = m.GetColumn2().GetNormalized(); - Vec3 pos = m.GetTranslation(); - - Vec3 normals[4] = { - ray1.direction.Cross(xdir).GetNormalized(), - (zdir).Cross(ray2.direction).GetNormalized(), - ray2.direction.Cross(-xdir).GetNormalized(), - (-zdir).Cross(ray1.direction).GetNormalized(), - }; - Plane frustum[4]; - for (int i = 0; i < 4; ++i) - { - frustum[i].SetPlane(-normals[i], pos); - } - - CDisplayViewportAdapter view(viewport); - - for (int j = 0; j < elements.size(); ++j) - { - const SElement& m2 = elements[j]; - if (m2.hidden) - { - continue; - } - if (!scene->IsLayerVisible(m2.layer) && !scene->Selection().Contains(m2.id)) - { - continue; - } - if (ElementInFrustum(m2, Vec2i(minX, minY), Vec2i(maxX, maxY), frustum, &view, scene)) - { - out->push_back(&m2); - } - } - } - - static void GetSelectionInRect(SSelectionSet* selection, Vec2i p1, Vec2i p2, QViewport* viewport, const vector& elements, ISpaceProvider* spaceProvider, CScene* scene) - { - vector elementsIn; - FindElementsInRect(&elementsIn, p1, p2, viewport, elements, spaceProvider, scene); - - for (size_t i = 0; i < elementsIn.size(); ++i) - { - selection->Add(elementsIn[i]->id); - } - } - - static void DrawLine2D(const SRenderContext& rc, Vec2i p1, Vec2i p2, ColorB color) - { - IRenderer* renderer = GetIEditor()->GetRenderer(); - IRenderAuxGeom* aux = renderer->GetIRenderAuxGeom(); - int w = rc.viewport->Width(); - int h = rc.viewport->Height(); - if (w == 0 || h == 0) - { - return; - } - - int renderFlags = aux->GetRenderFlags().m_renderFlags; - aux->SetRenderFlags((renderFlags | e_Mode2D) & ~e_Mode3D); - - Vec3 start(float(p1.x) / w, float(p1.y) / h, 0.0f); - Vec3 end(float(p2.x) / w, float(p2.y) / h, 0.0f); - aux->DrawLine(start, color, end, color); - - aux->SetRenderFlags(renderFlags); - } - - struct CScene::SBlockSelectHandler - : public IMouseDragHandler - { - CScene* m_scene; - Vec2i m_startPoint; - Vec2i m_endPoint; - SSelectionSet m_lastSelection; - - SBlockSelectHandler(CScene* scene) - : m_scene(scene) - { - } - - bool Begin(const SMouseEvent& ev, [[maybe_unused]] Vec3 hitPoint) override - { - m_startPoint = Vec2i(ev.x, ev.y); - m_endPoint = m_startPoint; - m_scene->SignalPushUndo("Selection change", 0); - m_scene->SetSelection(SSelectionSet()); - return true; - } - - void Update(const SMouseEvent& ev) override - { - m_endPoint = Vec2i(ev.x, ev.y); - - SSelectionSet selection; - GetSelectionInRect(&selection, m_startPoint, m_endPoint, ev.viewport, m_scene->Elements(), m_scene->SpaceProvider(), m_scene); - - if (selection != m_lastSelection || (selection.IsEmpty() && !m_scene->Selection().IsEmpty())) - { - m_scene->SetSelection(selection); - } - } - - void Render(const SRenderContext& rc) override - { - ColorB color(255, 255, 255, 255); - Vec2i points[4] = { m_startPoint, Vec2i(m_startPoint.x, m_endPoint.y), m_endPoint, Vec2i(m_endPoint.x, m_startPoint.y) }; - DrawLine2D(rc, points[0], points[1], color); - DrawLine2D(rc, points[1], points[2], color); - DrawLine2D(rc, points[2], points[3], color); - DrawLine2D(rc, points[3], points[0], color); - } - - void End([[maybe_unused]] const SMouseEvent& ev) override - { - } - }; - - - void CScene::OnMouseMove(const SMouseEvent& ev) - { - SGizmoParameters gizmoParameters; - gizmoParameters.axisGizmoScale = 0.2f; - CDisplayViewportAdapter displayView(ev.viewport); - - QuatT selectionTransform = GetSelectionTransform(SPACE_WORLD); - int selectionCaps = GetSelectionCaps(); - QuatT axesTransform = GetGizmoOrientation(selectionTransform, ev.viewport->Camera(), m_transformationSpace); - - if (m_mouseDragHandler.get()) - { - m_mouseDragHandler->Update(ev); - } - else if (m_showGizmo) - { - bool gizmoEnabled = true; - - switch (m_transformationMode) - { - case MODE_TRANSLATE: - gizmoEnabled = (selectionCaps & CAP_MOVE) != 0; - break; - case MODE_ROTATE: - gizmoEnabled = (selectionCaps & CAP_ROTATE) != 0; - break; - case MODE_SCALE: - gizmoEnabled = (selectionCaps & CAP_SCALE) != 0; - break; - } - - if (gizmoEnabled) - { - HitContext hc; - hc.point2d = QPoint(ev.x, ev.y); - hc.view = &displayView; - m_axisHelper->HitTest(Matrix34(axesTransform), gizmoParameters, hc); - m_axisHelper->SetHighlightAxis(hc.axis); - } - else - { - m_axisHelper->SetHighlightAxis(0); - } - - Ray ray; - if (ev.viewport->ScreenToWorldRay(&ray, ev.x, ev.y)) - { - Vec3 hitPoint; - m_highlightedItem = aznumeric_cast(HitSelectionWithRay(&hitPoint, m_elements, ray, m_customTracer, this)); - } - } - } - - void CScene::OnViewportMouse(const SMouseEvent& ev) - { - if (!ev.viewport) - { - return; - } - - SGizmoParameters gizmoParameters; - gizmoParameters.axisGizmoScale = 0.2f; - CDisplayViewportAdapter displayView(ev.viewport); - - QuatT selectionTransform = GetSelectionTransform(SPACE_WORLD); - int selectionCaps = GetSelectionCaps(); - QuatT axesTransform = GetGizmoOrientation(selectionTransform, ev.viewport->Camera(), m_transformationSpace); - - if (ev.type == SMouseEvent::TYPE_PRESS) - { - int button = ev.button; - if (button == SMouseEvent::BUTTON_LEFT) - { - Ray ray; - if (ev.viewport->ScreenToWorldRay(&ray, ev.x, ev.y)) - { - STransformConstraint constraint; - - Vec3 hitPoint = selectionTransform.t; - if (m_showGizmo) - { - HitContext hc; - hc.point2d = QPoint(ev.x, ev.y); - hc.view = &displayView; - if (!Selection().IsEmpty() && m_axisHelper->HitTest(Matrix34(axesTransform), gizmoParameters, hc)) - { - Quat localRot(selectionTransform.q); - Quat planeRot(GetGizmoOrientation(QuatT(selectionTransform.q, ZERO), ev.viewport->Camera(), m_transformationSpace).q); - switch (hc.axis) - { - case AXIS_X: - constraint.type = STransformConstraint::AXIS; - constraint.axis = Vec3(1.0f, 0.0f, 0.0f); - constraint.localAxis = localRot * constraint.axis; - break; - case AXIS_Y: - constraint.type = STransformConstraint::AXIS; - constraint.axis = Vec3(0.0f, 1.0f, 0.0f); - constraint.localAxis = localRot * constraint.axis; - break; - case AXIS_Z: - constraint.type = STransformConstraint::AXIS; - constraint.axis = Vec3(0.0f, 0.0f, 1.0f); - constraint.localAxis = localRot * constraint.axis; - break; - case AXIS_XY: - constraint.type = STransformConstraint::PLANE; - constraint.plane.SetPlane(planeRot * Vec3(0.0f, 0.0f, 1.0f), hitPoint); - constraint.axis = Vec3(1.0f, 1.0f, 0.0f); - break; - case AXIS_XZ: - constraint.type = STransformConstraint::PLANE; - constraint.plane.SetPlane(planeRot * Vec3(0.0f, 1.0f, 0.0f), hitPoint); - constraint.axis = Vec3(1.0f, 0.0f, 1.0f); - break; - case AXIS_YZ: - constraint.type = STransformConstraint::PLANE; - constraint.plane.SetPlane(planeRot * Vec3(1.0f, 0.0f, 0.0f), hitPoint); - constraint.axis = Vec3(0.0f, 1.0f, 1.0f); - break; - case AXIS_XYZ: - constraint.type = STransformConstraint::AXIS; - constraint.localAxis = Vec3(1.0f, 1.0f, 1.0f); - constraint.axis = Vec3(1.0f, 1.0f, 1.0f); - break; - } - } - } - - if (constraint.type == STransformConstraint::NONE) - { - ElementId selected_id = HitSelectionWithRay(&hitPoint, m_elements, ray, m_customTracer, this); - if (selected_id != 0) - { - if (!m_selection.Contains(aznumeric_cast(selected_id)) || m_selection.Size() > 1) - { - if (ev.control) - { - AddToSelection(selected_id); - } - else - { - SetSelection(SSelectionSet(selected_id)); - } - } - - if (m_transformationMode == MODE_SCALE) - { - constraint.type = STransformConstraint::AXIS; - constraint.axis = Vec3(1.0f, 1.0f, 1.0f); - constraint.localAxis = Vec3(1.0f, 1.0f, 1.0f); - } - else - { - Matrix34 m = ev.viewport->Camera()->GetMatrix(); - Vec3 xdir = m.GetColumn0().GetNormalized(); - Vec3 ydir = m.GetColumn1().GetNormalized(); - Vec3 zdir = m.GetColumn2().GetNormalized(); - Vec3 pos = m.GetTranslation(); - - Vec3 fromScreenToSelection = pos - hitPoint; - float distance = ydir.Dot(fromScreenToSelection); - Vec3 planeCenter = pos + -ydir * distance; - - constraint.type = STransformConstraint::PLANE; - constraint.plane.SetPlane(-ydir, planeCenter); - constraint.axis = Vec3(1.0f, 0.0f, 1.0f); - } - } - else - { - m_mouseDragHandler.reset(new SBlockSelectHandler(this)); - } - } - - if (constraint.type != STransformConstraint::NONE) - { - switch (m_transformationMode) - { - case MODE_TRANSLATE: - if (selectionCaps & CAP_MOVE) - { - m_mouseDragHandler.reset(new SMoveHandler(this, constraint)); - } - break; - case MODE_ROTATE: - if (selectionCaps & CAP_ROTATE) - { - m_mouseDragHandler.reset(new SRotationHandler(this, constraint)); - } - break; - case MODE_SCALE: - if (selectionCaps & CAP_SCALE) - { - m_mouseDragHandler.reset(new SScalingHandler(this, constraint)); - } - break; - default: - break; - } - } - - if (m_mouseDragHandler.get()) - { - if (!m_mouseDragHandler->Begin(ev, hitPoint)) - { - m_mouseDragHandler.reset(); - } - } - } - } - } - else if (ev.type == SMouseEvent::TYPE_RELEASE) - { - if (m_mouseDragHandler.get()) - { - m_mouseDragHandler->End(ev); - m_mouseDragHandler.reset(); - ev.viewport->ReleaseMouse(); - } - } - else if (ev.type == SMouseEvent::TYPE_MOVE) - { - OnMouseMove(ev); - } - } - - struct CScene::STransformBox - { - CScene* m_scene; - - STransformBox(CScene* scene) - : m_scene(scene) - { - } - - void Serialize(IArchive& ar) - { - QuatT transform = m_scene->GetSelectionTransform(SPACE_WORLD); - int caps = m_scene->GetSelectionCaps(); - - Vec3 position = transform.t; - if ((caps & CAP_MOVE)) - { - ar(position, "position", "GetSelectionSize(); - Vec3 sizeOld = size; - if ((caps & CAP_SCALE)) - { - ar(size, "size", "SetSelectionTransform(SPACE_WORLD, transform); - } - - if (sizeChanged) - { - m_scene->SetSelectionSize(size); - } - } - } - }; - - struct SSpaceSelector - { - ETransformationSpace& space; - - SSpaceSelector(ETransformationSpace& space) - : space(space) - { - } - - void Serialize(Serialization::IArchive& ar) - { - using Serialization::RadioButton; - ar(RadioButton((int&)space, SPACE_WORLD), "transformWorld", "^Global"); - ar(RadioButton((int&)space, SPACE_LOCAL), "transformLocal", "^Local"); - } - }; - - - void CScene::Serialize(IArchive& ar) - { - ar(m_transformationMode, "transformationMode", 0); - if (ar.IsEdit()) - { - ar(SSpaceSelector(m_transformationSpace), "transformationSpace", "clear(); - size_t numElements = m_elements.size(); - for (size_t i = 0; i < numElements; ++i) - { - const SElement& element = m_elements[i]; - if (m_selection.Contains(element.id)) - { - elements->push_back(element); - } - } - } - - void CScene::UpdateElements(const SElements& elements) - { - // TODO: remove quadratic complexity here - size_t numElements = m_elements.size(); - for (size_t i = 0; i < numElements; ++i) - { - for (size_t j = 0; j < elements.size(); ++j) - { - if (m_elements[i].id == elements[j].id) - { - m_elements[i].placement = elements[j].placement; - m_elements[i].changed = true; - } - } - } - } - - void CScene::Clear() - { - m_elements.clear(); - m_lastIdByLayer.clear(); - } - - void CScene::ClearLayer(int layer) - { - auto newEnd = std::remove_if(m_elements.begin(), m_elements.end(), [=](const SElement& e){ return e.layer == layer; }); - m_elements.erase(newEnd, m_elements.end()); - if (layer < m_lastIdByLayer.size()) - { - m_lastIdByLayer[layer] = layer << 24; - } - } - - - void CScene::AddElement(const SElement& element) - { - ElementId& lastId = m_lastIdByLayer[element.layer]; - AddElement(element, lastId); - ++lastId; - } - - void CScene::AddElement(const SElement& element, ElementId id) - { - m_elements.push_back(element); - if (element.layer >= m_lastIdByLayer.size()) - { - while (m_lastIdByLayer.size() <= element.layer) - { - m_lastIdByLayer.push_back(m_lastIdByLayer.size() << 24); - } - } - m_elements.back().id = aznumeric_cast(id); - - ElementId& lastId = m_lastIdByLayer[element.layer]; - lastId = max(lastId, id) + 1; - } - - QuatT CScene::GetSelectionTransform(ETransformationSpace space) const - { - if (space == SPACE_WORLD) - { - QuatT r(IDENTITY); - - vector selectedElements; - GetSelectedElements(&selectedElements); - - if (selectedElements.size() == 1) - { - r = ElementToWorldSpace(selectedElements[0]); - } - else if (selectedElements.size() > 1) - { - r = GetParentSpace(selectedElements[0]) * selectedElements[0].placement.transform; - for (size_t i = 1; i < selectedElements.size(); ++i) - { - SElement& e = selectedElements[i]; - QuatT parentSpace = GetParentSpace(e); - r.t = r.t + ElementToWorldSpace(e).t; - } - r.SetTranslation(r.t / float(selectedElements.size())); - } - - if (!_finite(r.t.x) || - !_finite(r.t.y) || - !_finite(r.t.z)) - { - Q_ASSERT(false); - r.SetIdentity(); - } - return r; - } - else if (space == SPACE_LOCAL) - { - return m_temporaryLocalDelta; - } - - return IDENTITY; - } - - bool CScene::SelectionCanBeMoved() const - { - return (GetSelectionCaps() & CAP_MOVE) != 0; - } - - bool CScene::SelectionCanBeRotated() const - { - return (GetSelectionCaps() & CAP_ROTATE) != 0; - } - - int CScene::GetSelectionCaps() const - { - int caps = 0; - vector selectedElements; - GetSelectedElements(&selectedElements); - for (size_t i = 0; i < selectedElements.size(); ++i) - { - if (selectedElements[i].caps & CAP_MOVE && (caps & CAP_MOVE) != 0) - { - // enable rotation and scale of two or more positions - caps |= CAP_ROTATE | CAP_SCALE; - } - - caps |= selectedElements[i].caps; - } - ; - - return caps; - } - - bool CScene::SetSelectionTransform(ETransformationSpace space, const QuatT& newTransform) - { - QuatT transform = GetSelectionTransform(SPACE_WORLD); - QuatT deltaWorld; - if (space == SPACE_WORLD) - { - deltaWorld = transform.GetInverted() * newTransform; - } - else - { - deltaWorld = newTransform; - } - - bool hasElementsChanged = false; - - size_t numElements = m_elements.size(); - for (size_t i = 0; i < numElements; ++i) - { - SElement& element = m_elements[i]; - if (m_selection.Contains(element.id)) - { - QuatT parentSpace = GetParentSpace(element); - QuatT newWorldTransform = parentSpace * element.placement.transform * deltaWorld; - element.placement.transform = parentSpace.GetInverted() * newWorldTransform; - element.changed = true; - hasElementsChanged = true; - } - } - - return hasElementsChanged; - } - - Vec3 CScene::GetSelectionSize() const - { - Vec3 size(1.0f, 1.0f, 1.0f); - - vector selectedElements; - GetSelectedElements(&selectedElements); - - if (selectedElements.size() == 1) - { - size = selectedElements[0].placement.size; - } - else if (selectedElements.size() > 1) - { - AABB combinedSize(AABB::RESET); - - for (size_t i = 0; i < selectedElements.size(); ++i) - { - const SElement& element = m_elements[i]; - AABB box(element.placement.size * -0.5f, element.placement.size * 0.5f); - AABB transformedBox = AABB::CreateTransformedAABB(Matrix34(element.placement.transform), box); - combinedSize.Add(transformedBox); - } - size = combinedSize.IsReset() ? Vec3(1.0f, 1.0f, 1.0f) : combinedSize.GetSize(); - } - - return size; - } - - - bool CScene::SetSelectionSize(const Vec3& size) - { - bool hasElementsChanged = false; - - vector selectedElements; - GetSelectedElements(&selectedElements); - - if (selectedElements.size() == 1) - { - selectedElements[0].placement.size = size; - selectedElements[0].changed = true; - hasElementsChanged = true; - } - - return hasElementsChanged; - } - - void CScene::SetSpaceProvider(ISpaceProvider* provider) - { - m_spaceProvider = provider; - } - - QuatT CScene::GetParentSpace(const SElement& e) const - { - if (!m_spaceProvider) - { - return QuatT(IDENTITY); - } - QuatT result = m_spaceProvider->GetTransform(e.parentSpaceIndex); - return result; - } - - QuatT CScene::ElementToWorldSpace(const SElement& e) const - { - if (!m_spaceProvider) - { - return e.placement.transform; - } - QuatT parent = m_spaceProvider->GetTransform(e.parentSpaceIndex); - if (e.parentOrientationSpaceIndex.m_attachmentCRC32 == -1 && e.parentOrientationSpaceIndex.m_jointCRC32 == -1) - { - return parent * e.placement.transform; - } - - QuatT parentOrientation = m_spaceProvider->GetTransform(e.parentOrientationSpaceIndex); - QuatT result = parent * e.placement.transform; - result.q = parentOrientation.q * e.placement.transform.q; - return result; - } - - - void CScene::WorldSpaceToElement(SElement* e, const QuatT& worldSpaceTransform) - { - if (!e) - { - return; - } - if (!m_spaceProvider) - { - e->placement.transform = worldSpaceTransform; - return; - } - - QuatT parent = m_spaceProvider->GetTransform(e->parentSpaceIndex); - - if (e->parentOrientationSpaceIndex.m_attachmentCRC32 == -1 && e->parentOrientationSpaceIndex.m_jointCRC32 == -1) - { - e->placement.transform = parent.GetInverted() * worldSpaceTransform; - return; - } - QuatT parentOrientation = m_spaceProvider->GetTransform(e->parentOrientationSpaceIndex); - e->placement.transform = parent.GetInverted() * worldSpaceTransform; - e->placement.transform.q = parentOrientation.GetInverted().q * worldSpaceTransform.q; - } - - bool CScene::IsLayerVisible(int layer) const - { - return (m_visibleLayerMask & (1 << layer)) != 0; - } - - void CScene::SetVisibleLayerMask(unsigned int layerMask) - { - m_visibleLayerMask = layerMask; - } -} diff --git a/Code/Sandbox/Plugins/EditorCommon/ManipScene.h b/Code/Sandbox/Plugins/EditorCommon/ManipScene.h deleted file mode 100644 index dbb735d493..0000000000 --- a/Code/Sandbox/Plugins/EditorCommon/ManipScene.h +++ /dev/null @@ -1,336 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITORCOMMON_MANIPSCENE_H -#define CRYINCLUDE_EDITORCOMMON_MANIPSCENE_H -#pragma once - -#include -#include -#include -#include "EditorCommonAPI.h" -#include -#include "QViewportConsumer.h" - - -namespace Serialization { - class IArchive; -} - -class CAxisHelper; - -// Manip is a set of reusable utilities for creating interactive 3d scene that -// can be manipulated with gizmos. -namespace Manip -{ - using std::unique_ptr; - using std::set; - using std::vector; - - enum EElementCaps - { - CAP_SELECT = 1 << 0, - CAP_HIDE = 1 << 1, - CAP_MOVE = 1 << 2, - CAP_ROTATE = 1 << 3, - CAP_SCALE = 1 << 4, - CAP_DELETE = 1 << 5, - }; - - enum EElementShape - { - SHAPE_AXES, - SHAPE_BOX - }; - - enum EElementAction - { - ACTION_NONE, - ACTION_DELETE, - ACTION_HIDE, - ACTION_UNHIDE - }; - - enum EElementColorGroup - { - ELEMENT_COLOR_PROXY, - ELEMENT_COLOR_CLOTH - }; - - struct SElementPlacement - { - QuatT transform; - QuatT startTransform; - Vec3 center; - Vec3 size; - - SElementPlacement() - : transform(IDENTITY) - , startTransform(IDENTITY) - , size(1.0f, 1.0f, 1.0f) - , center(0.0f, 0.0f, 0.0f) - {} - - void Serialize(Serialization::IArchive& ar); - }; - - typedef uint64 ElementId; - - struct SSpaceAndIndex - { - int m_space; - int m_jointCRC32; - int m_attachmentCRC32; - SSpaceAndIndex() - { - m_space = -1; - m_jointCRC32 = -1; - m_attachmentCRC32 = -1; - }; - }; - - struct SElement - { - int id; - union - { - int originalId; - const void* originalHandle; - }; - int layer; - SElementPlacement placement; - int caps; - EElementAction action; - EElementShape shape; - EElementColorGroup colorGroup; - SSpaceAndIndex parentSpaceIndex; - SSpaceAndIndex parentOrientationSpaceIndex; - QuatT parentSpaceConcatenation; - int mousePickPriority; - bool hidden; - bool changed; - bool alwaysXRay; - - SElement() - : id() - , layer(0) - , originalHandle(0) - , action(ACTION_NONE) - , shape(SHAPE_AXES) - , hidden(false) - , changed(false) - , colorGroup(ELEMENT_COLOR_PROXY) - , mousePickPriority(0) - , alwaysXRay(false) - , parentSpaceIndex() - , parentOrientationSpaceIndex() - , parentSpaceConcatenation(IDENTITY) - { - } - }; - typedef std::vector SElements; - - struct SElementData {}; - - struct IMouseDragHandler - { - virtual ~IMouseDragHandler() = default; - virtual bool Begin(const SMouseEvent& ev, Vec3 hitPoint) = 0; - virtual void Update(const SMouseEvent& ev) = 0; - virtual void Render([[maybe_unused]] const SRenderContext& rc) {} - virtual void End(const SMouseEvent& ev) = 0; - }; - - struct SSelectionSet - { - SSelectionSet() {} - SSelectionSet(ElementId id) { items.push_back(id); } - void Clear(); - void Add(ElementId elementId) - { - items.erase(std::remove(items.begin(), items.end(), elementId), items.end()); - items.push_back(elementId); - std::sort(items.begin(), items.end()); - } - void Remove(int elementId); - bool IsEmpty() const{ return items.empty(); } - bool Contains(int id) const{ return std::find(items.begin(), items.end(), id) != items.end(); } - size_t Size() const{ return items.size(); } - - bool operator==(const SSelectionSet& rhs) const - { - return items == rhs.items; - } - - bool operator!=(const SSelectionSet& rhs) const{ return !operator==(rhs); } - - std::vector items; - }; - - struct ICommand {}; - - struct IElementTracer - { - virtual bool HitRay(Vec3* intersectionPoint, const Ray& ray, const SElement& element) const = 0; - }; - - struct IElementDrawer - { - virtual bool Draw(const SElement& element); - }; - - enum ETransformationSpace - { - SPACE_WORLD, - SPACE_LOCAL - }; - - enum ETransformationMode - { - MODE_TRANSLATE, - MODE_ROTATE, - MODE_SCALE - }; - - struct SLookSettings - { - ColorB proxyColor; - ColorB proxySelectionColor; - ColorB proxyHighlightColor; - ColorB clothProxyColor; - - ColorB jointColor; - ColorB jointHighlightColor; - ColorB jointSelectionColor; - - SLookSettings() - : proxyColor(126, 159, 243, 128) - , proxySelectionColor(255, 255, 255, 128) - , proxyHighlightColor(233, 255, 122, 128) - , clothProxyColor(243, 159, 126, 128) - , jointColor(0, 249, 48, 255) - , jointHighlightColor(255, 248, 0, 128) - , jointSelectionColor(255, 255, 255, 128) - { - } - }; - - struct ISpaceProvider - { - virtual ~ISpaceProvider() = default; - virtual SSpaceAndIndex FindSpaceIndexByName(int spaceType, const char* name, int parentsUp) const = 0; - virtual QuatT GetTransform(const SSpaceAndIndex& index) const = 0; - }; - - AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING - class EDITOR_COMMON_API CScene - : public QObject - , public QViewportConsumer - { - AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING - Q_OBJECT - public: - CScene(); - ~CScene(); - - void OnViewportKey(const SKeyEvent& ev) override; - bool ProcessesViewportKey(const QKeySequence& key) override; - void OnViewportMouse(const SMouseEvent& ev) override; - void OnViewportRender(const SRenderContext& rc) override; - - void SetTransformationMode(ETransformationMode mode); - ETransformationMode TransformationMode() const; - void SetTransformationSpace(ETransformationSpace space); - ETransformationSpace TransformationSpace() const { return m_transformationSpace; } - void SetVisibleLayerMask(unsigned int layerMask); - unsigned int VisibleLayerMask() const { return m_visibleLayerMask; } - bool IsLayerVisible(int layer) const; - - void Clear(); - void ClearLayer(int layer); - void AddElement(const SElement& element); - void AddElement(const SElement& element, ElementId id); - void ApplyToAll(EElementAction); - void ApplyToSelection(EElementAction); - - void SetSpaceProvider(ISpaceProvider* spaceProvider); - ISpaceProvider* SpaceProvider() const{ return m_spaceProvider; } - QuatT GetParentSpace(const SElement& e) const; - QuatT ElementToWorldSpace(const SElement& e) const; - void WorldSpaceToElement(SElement* e, const QuatT& worldSpaceTransform); - - void SetCustomTracer(IElementTracer* tracer); - - const SElements& Elements() const{ return m_elements; } - SElements& Elements() { return m_elements; } - void GetSelectedElements(SElements* elements) const; - const SSelectionSet& Selection() const{ return m_selection; } - void SetSelection(const SSelectionSet& selection); - void AddToSelection(const SSelectionSet& selection); - void AddToSelection(ElementId elementId); - - bool SelectionCanBeMoved() const; - bool SelectionCanBeRotated() const; - QuatT GetSelectionTransform(ETransformationSpace space) const; - bool SetSelectionTransform(ETransformationSpace space, const QuatT& newTransform); - - void Serialize(Serialization::IArchive& ar); - signals: - void SignalUndo(); - void SignalRedo(); - void SignalPushUndo(const char* description, ICommand* cause); - void SignalElementsChanged(unsigned int layerBits); - void SignalElementContinousChange(unsigned int layerBits); - void SignalPropertiesChanged(); - void SignalRenderElements(const SElements& elements, const SRenderContext& rc); - void SignalSelectionChanged(); - void SignalManipulationModeChanged(); - - private: - void UpdateElements(const SElements& elements); - bool SetSelectionTransform(const Matrix34& newMatrix); - Matrix34 GetSelectionTransform() const; - int GetSelectionCaps() const; - Vec3 GetSelectionSize() const; - bool SetSelectionSize(const Vec3& size); - void OnMouseMove(const SMouseEvent& ev); - - struct SBlockSelectHandler; - struct SMoveHandler; - struct SRotationHandler; - struct SScalingHandler; - struct STransformBox; - - IElementTracer* m_customTracer; - IElementDrawer* m_customDrawer; - - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING - SSelectionSet m_selection; - unique_ptr m_mouseDragHandler; - ISpaceProvider* m_spaceProvider; - unique_ptr m_axisHelper; - SElements m_elements; - std::vector m_lastIdByLayer; - ETransformationMode m_transformationMode; - ETransformationSpace m_transformationSpace; - int m_highlightItem; - unsigned int m_visibleLayerMask; - bool m_showGizmo; - SLookSettings m_lookSettings; - int m_highlightedItem; - QuatT m_temporaryLocalDelta; - AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - }; -} - -#endif // CRYINCLUDE_EDITORCOMMON_MANIPSCENE_H diff --git a/Code/Sandbox/Plugins/EditorCommon/QViewport.cpp b/Code/Sandbox/Plugins/EditorCommon/QViewport.cpp index 2d9598ba83..36f9511e60 100644 --- a/Code/Sandbox/Plugins/EditorCommon/QViewport.cpp +++ b/Code/Sandbox/Plugins/EditorCommon/QViewport.cpp @@ -145,7 +145,6 @@ QViewport::QViewport(QWidget* parent, StartupMode startupMode) void QViewport::Startup() { m_frameTimer = new QElapsedTimer(); - CreateRenderContext(); m_camera.reset(new CCamera()); ResetCamera(); @@ -162,8 +161,6 @@ void QViewport::Startup() QViewport::~QViewport() { - DestroyRenderContext(); - m_viewportRequests.reset(); } @@ -180,51 +177,14 @@ void QViewport::UpdateBackgroundColor() bool QViewport::ScreenToWorldRay(Ray* ray, int x, int y) { - if (!GetIEditor()->GetEnv()->pRenderer) - { - return false; - } - - SetCurrentContext(); - - Vec3 pos0, pos1; - float wx, wy, wz; - if (!GetIEditor()->GetEnv()->pRenderer->UnProjectFromScreen(float(x), float(m_height - y), 0, &wx, &wy, &wz)) - { - RestorePreviousContext(); - return false; - } - pos0(wx, wy, wz); - if (!GetIEditor()->GetEnv()->pRenderer->UnProjectFromScreen(float(x), float(m_height - y), 1, &wx, &wy, &wz)) - { - RestorePreviousContext(); - return false; - } - pos1(wx, wy, wz); - - RestorePreviousContext(); - - Vec3 v = (pos1 - pos0); - v = v.GetNormalized(); - - ray->origin = pos0; - ray->direction = v; - return true; + AZ_UNUSED(ray); + AZ_UNUSED(x); + AZ_UNUSED(y); + return false; } -QPoint QViewport::ProjectToScreen(const Vec3& wp) +QPoint QViewport::ProjectToScreen(const Vec3&) { - float x, y, z; - - SetCurrentContext(); - GetIEditor()->GetEnv()->pRenderer->ProjectToScreen(wp.x, wp.y, wp.z, &x, &y, &z); - if (_finite(x) || _finite(y)) - { - RestorePreviousContext(); - return QPoint(int((x / 100.0) * Width()), int((y / 100.0) * Height())); - } - RestorePreviousContext(); - return QPoint(0, 0); } @@ -245,105 +205,6 @@ int QViewport::Height() const return rect().height(); } -bool QViewport::CreateRenderContext() -{ - if (m_creatingRenderContext || !isVisible()) - { - return false; - } - - HWND windowHandle = reinterpret_cast(QWidget::winId()); - - if( m_renderContextCreated && windowHandle == m_lastHwnd) - { - // the hwnd has not changed, no need to destroy and recreate context (and swap chain etc) - return false; - } - - m_creatingRenderContext = true; - DestroyRenderContext(); - if (windowHandle && GetIEditor()->GetEnv()->pRenderer && !m_renderContextCreated) - { - m_renderContextCreated = true; - - m_viewportRequests.get()->BusConnect(windowHandle); - AzFramework::WindowSystemNotificationBus::Broadcast(&AzFramework::WindowSystemNotificationBus::Handler::OnWindowCreated, windowHandle); - - m_lastHwnd = windowHandle; - - StorePreviousContext(); - GetIEditor()->GetEnv()->pRenderer->CreateContext(windowHandle); - RestorePreviousContext(); - - m_creatingRenderContext = false; - return true; - } - m_creatingRenderContext = false; - return false; -} - -void QViewport::DestroyRenderContext() -{ - if (GetIEditor()->GetEnv()->pRenderer && m_renderContextCreated) - { - HWND windowHandle = reinterpret_cast(QWidget::winId()); - - if (windowHandle != GetIEditor()->GetEnv()->pRenderer->GetHWND()) - { - GetIEditor()->GetEnv()->pRenderer->DeleteContext(windowHandle); - } - m_renderContextCreated = false; - - AzFramework::WindowNotificationBus::Event(windowHandle, &AzFramework::WindowNotificationBus::Handler::OnWindowClosed); - m_viewportRequests.get()->BusDisconnect(); - m_lastHwnd = 0; - } -} - -void QViewport::StorePreviousContext() -{ - SPreviousContext previous; - previous.width = GetIEditor()->GetEnv()->pRenderer->GetWidth(); - previous.height = GetIEditor()->GetEnv()->pRenderer->GetHeight(); - previous.window = reinterpret_cast(GetIEditor()->GetEnv()->pRenderer->GetCurrentContextHWND()); - previous.renderCamera = GetIEditor()->GetEnv()->pRenderer->GetCamera(); - previous.systemCamera = GetISystem()->GetViewCamera(); - previous.isMainViewport = GetIEditor()->GetEnv()->pRenderer->IsCurrentContextMainVP(); - m_previousContexts.push_back(previous); -} - -void QViewport::SetCurrentContext() -{ - StorePreviousContext(); - - if (m_camera.get() == 0) - { - return; - } - - HWND windowHandle = reinterpret_cast(QWidget::winId()); - GetIEditor()->GetEnv()->pRenderer->SetCurrentContext(windowHandle); - GetIEditor()->GetEnv()->pRenderer->ChangeViewport(0, 0, m_width, m_height); - GetIEditor()->GetEnv()->pRenderer->SetCamera(*m_camera); - GetIEditor()->GetEnv()->pSystem->SetViewCamera(*m_camera); -} - -void QViewport::RestorePreviousContext() -{ - if (m_previousContexts.empty()) - { - assert(0); - return; - } - - SPreviousContext x = m_previousContexts.back(); - m_previousContexts.pop_back(); - GetIEditor()->GetEnv()->pRenderer->SetCurrentContext(x.window); - GetIEditor()->GetEnv()->pRenderer->ChangeViewport(0, 0, x.width, x.height, x.isMainViewport); - GetIEditor()->GetEnv()->pRenderer->SetCamera(x.renderCamera); - GetIEditor()->GetEnv()->pSystem->SetViewCamera(x.systemCamera); -} - void QViewport::Serialize(IArchive& ar) { if (!ar.IsEdit()) @@ -720,45 +581,6 @@ void QViewport::RenderInternal() { } -void QViewport::GetImageOffscreen(CImageEx& image, const QSize& customSize) -{ - if ((m_width == 0) || (m_height == 0)) - { - // This can occur, for example, if the material editor window is sized to zero OR - // if it is docked as a tab in another view pane window and is not the active tab when the editor starts. - image.Allocate(1, 1); - image.Clear(); - return; - } - - IRenderer* renderer = GetIEditor()->GetRenderer(); - - renderer->EnableSwapBuffers(false); - RenderInternal(); - renderer->EnableSwapBuffers(true); - - int w; - int h; - - if (customSize.isValid()) - { - w = customSize.width(); - h = customSize.height(); - } - else - { - w = width(); - h = height(); - } - - image.Allocate(w, h); - - // the renderer will read the frame buffer of the current render context, so we need to set ours as the current before we execute this command. - SetCurrentContext(); - renderer->ReadFrameBufferFast(image.GetData(), w, h); - RestorePreviousContext(); -} - void QViewport::SetWindowTitle(const AZStd::string& title) { // Do not support the WindowRequestBus changing the editor window title @@ -1022,12 +844,6 @@ void QViewport::resizeEvent(QResizeEvent* ev) m_width = cx; m_height = cy; - // We queue the window resize event in case the windows is hidden. - // If the QWidget is hidden, the native windows does not resize and the - // swapchain may have the incorrect size. We need to wait - // until it's visible to trigger the resize event. - m_resizeWindowEvent = true; - GetIEditor()->GetEnv()->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RESIZE, cx, cy); SignalUpdate(); Update(); @@ -1035,18 +851,9 @@ void QViewport::resizeEvent(QResizeEvent* ev) void QViewport::showEvent(QShowEvent* ev) { - // force a context create once we're shown - // This must be queued, as the showEvent is sent before the widget is actually shown, not after - QMetaObject::invokeMethod(this, "ForceRebuildRenderContext", Qt::QueuedConnection); - QWidget::showEvent(ev); } -void QViewport::ForceRebuildRenderContext() -{ - CreateRenderContext(); -} - void QViewport::moveEvent(QMoveEvent* ev) { QWidget::moveEvent(ev); @@ -1058,11 +865,6 @@ bool QViewport::event(QEvent* ev) { bool result = QWidget::event(ev); - if (ev->type() == QEvent::WinIdChange) - { - CreateRenderContext(); - } - if (ev->type() == QEvent::ShortcutOverride) { // When a shortcut is matched, Qt's event processing sends out a shortcut override event diff --git a/Code/Sandbox/Plugins/EditorCommon/QViewport.h b/Code/Sandbox/Plugins/EditorCommon/QViewport.h index 72b2024bc4..5566edc126 100644 --- a/Code/Sandbox/Plugins/EditorCommon/QViewport.h +++ b/Code/Sandbox/Plugins/EditorCommon/QViewport.h @@ -104,7 +104,6 @@ public: int Width() const; int Height() const; void SetSize(const QSize& size); - void GetImageOffscreen(CImageEx& image, const QSize& customSize); // WindowRequestBus::Handler... (handler moved to cpp to resolve link issues in unity builds) void SetWindowTitle(const AZStd::string& title); @@ -119,7 +118,6 @@ public slots: void Update(); protected slots: void RenderInternal(); - void ForceRebuildRenderContext(); signals: void SignalPreRender(const SRenderContext&); void SignalRender(const SRenderContext&); @@ -146,12 +144,6 @@ protected: private: struct SPrivate; - bool CreateRenderContext(); - void DestroyRenderContext(); - void StorePreviousContext(); -protected: - void SetCurrentContext(); - void RestorePreviousContext(); private: void UpdateBackgroundColor(); @@ -198,6 +190,4 @@ private: std::vector m_consumers; AZStd::unique_ptr m_viewportRequests; AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - HWND m_lastHwnd = 0; - bool m_resizeWindowEvent = false; }; diff --git a/Code/Sandbox/Plugins/EditorCommon/editorcommon_files.cmake b/Code/Sandbox/Plugins/EditorCommon/editorcommon_files.cmake index e1a63b77da..5551c07be1 100644 --- a/Code/Sandbox/Plugins/EditorCommon/editorcommon_files.cmake +++ b/Code/Sandbox/Plugins/EditorCommon/editorcommon_files.cmake @@ -15,8 +15,6 @@ set(FILES EditorCommon.rc EditorCommon.qrc EditorCommonAPI.h - ManipScene.cpp - ManipScene.h moc.cpp QViewportConsumer.h TimelineContent.h diff --git a/Code/Sandbox/Plugins/EditorCommon/moc.cpp b/Code/Sandbox/Plugins/EditorCommon/moc.cpp index 9fc66faa8c..ce9570b673 100644 --- a/Code/Sandbox/Plugins/EditorCommon/moc.cpp +++ b/Code/Sandbox/Plugins/EditorCommon/moc.cpp @@ -13,11 +13,9 @@ #include "EditorCommon_precompiled.h" #include -#include #include #include #include -#include #include #include diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.cpp b/Code/Tools/ProjectManager/Source/LinkWidget.cpp new file mode 100644 index 0000000000..fddc4cd8c9 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/LinkWidget.cpp @@ -0,0 +1,52 @@ +/* +* 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 +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + LinkLabel::LinkLabel(const QString& text, const QUrl& url, QWidget* parent) + : QLabel(text, parent) + , m_url(url) + { + SetDefaultStyle(); + } + + void LinkLabel::mousePressEvent([[maybe_unused]] QMouseEvent* event) + { + QDesktopServices::openUrl(m_url); + } + + void LinkLabel::enterEvent([[maybe_unused]] QEvent* event) + { + setStyleSheet("font-size: 9pt; color: #94D2FF; text-decoration: underline;"); + } + + void LinkLabel::leaveEvent([[maybe_unused]] QEvent* event) + { + SetDefaultStyle(); + } + + void LinkLabel::SetUrl(const QUrl& url) + { + m_url = url; + } + + void LinkLabel::SetDefaultStyle() + { + setStyleSheet("font-size: 9pt; color: #94D2FF;"); + } +} // namespace O3DE::ProjectManager diff --git a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.h b/Code/Tools/ProjectManager/Source/LinkWidget.h similarity index 50% rename from Gems/ImageProcessing/Code/Source/Editor/ImagePopup.h rename to Code/Tools/ProjectManager/Source/LinkWidget.h index adc91d9dfe..7055dce2af 100644 --- a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.h +++ b/Code/Tools/ProjectManager/Source/LinkWidget.h @@ -12,33 +12,31 @@ #pragma once - #if !defined(Q_MOC_RUN) -#include -#include -#include +#include +#include #endif -namespace Ui -{ - class ImagePopup; -} +QT_FORWARD_DECLARE_CLASS(QEvent) +QT_FORWARD_DECLARE_CLASS(QMouseEvent) +QT_FORWARD_DECLARE_CLASS(QWidget) -namespace ImageProcessingEditor +namespace O3DE::ProjectManager { - class ImagePopup - : public QDialog + class LinkLabel + : public QLabel { - Q_OBJECT public: - AZ_CLASS_ALLOCATOR(ImagePopup, AZ::SystemAllocator, 0); - explicit ImagePopup(QImage previewImage, QWidget* parent = nullptr); - ~ImagePopup(); + LinkLabel(const QString& text, const QUrl& url = {}, QWidget* parent = nullptr); + void SetUrl(const QUrl& url); private: - QScopedPointer m_ui; - QImage m_previewImage; - - }; -} //namespace ImageProcessingEditor + void mousePressEvent(QMouseEvent* event) override; + void enterEvent(QEvent* event) override; + void leaveEvent(QEvent* event) override; + void SetDefaultStyle(); + private: + QUrl m_url; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp new file mode 100644 index 0000000000..3e80944204 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -0,0 +1,98 @@ +/* +* 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 +#include + +namespace O3DE::ProjectManager +{ + TagWidget::TagWidget(const QString& text, QWidget* parent) + : QLabel(text, parent) + { + setFixedHeight(35); + setMargin(5); + setStyleSheet("font-size: 12pt; background-color: #333333; border-radius: 4px;"); + } + + TagContainerWidget::TagContainerWidget(QWidget* parent) + : QWidget(parent) + { + m_layout = new QVBoxLayout(); + m_layout->setAlignment(Qt::AlignTop); + m_layout->setMargin(0); + setLayout(m_layout); + } + + void TagContainerWidget::Update(const QStringList& tags) + { + QWidget* parentWidget = qobject_cast(parent()); + int width = 250; + if (parentWidget) + { + width = parentWidget->width(); + } + + if (m_widget) + { + // Hide the old widget and request deletion. + m_widget->hide(); + m_widget->deleteLater(); + } + + QVBoxLayout* vLayout = new QVBoxLayout(); + m_widget = new QWidget(this); + m_widget->setLayout(vLayout); + m_layout->addWidget(m_widget); + + vLayout->setAlignment(Qt::AlignTop); + vLayout->setMargin(0); + + QHBoxLayout* hLayout = nullptr; + int usedSpaceInRow = 0; + const int numTags = tags.count(); + + for (int i = 0; i < numTags; ++i) + { + // Create the new tag widget. + TagWidget* tagWidget = new TagWidget(tags[i]); + const int tagWidgetWidth = tagWidget->minimumSizeHint().width(); + + // Calculate the width we're currently using in the current row. Does the new tag still fit in the current row? + const bool isRowFull = width - usedSpaceInRow - tagWidgetWidth < 0; + if (isRowFull || i == 0) + { + // Add a spacer widget after the last tag widget in a row to push the tag widgets to the left. + if (i > 0) + { + QWidget* spacerWidget = new QWidget(); + spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + hLayout->addWidget(spacerWidget); + } + + // Add a new row for the current tag widget. + hLayout = new QHBoxLayout(); + hLayout->setAlignment(Qt::AlignLeft); + hLayout->setMargin(0); + vLayout->addLayout(hLayout); + + // Reset the used space in the row. + usedSpaceInRow = 0; + } + + // Calculate the width of the tag widgets including the spacing between them of the current row. + usedSpaceInRow += tagWidgetWidth + hLayout->spacing(); + + // Add the tag widget to the current row. + hLayout->addWidget(tagWidget); + } + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.h b/Code/Tools/ProjectManager/Source/TagWidget.h new file mode 100644 index 0000000000..5597b302c7 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/TagWidget.h @@ -0,0 +1,52 @@ +/* +* 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 + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QVBoxLayout) + +namespace O3DE::ProjectManager +{ + // Single tag + class TagWidget + : public QLabel + { + Q_OBJECT // AUTOMOC + + public: + explicit TagWidget(const QString& text, QWidget* parent = nullptr); + ~TagWidget() = default; + }; + + // Widget containing multiple tags, automatically wrapping based on the size + class TagContainerWidget + : public QWidget + { + Q_OBJECT // AUTOMOC + + public: + explicit TagContainerWidget(QWidget* parent = nullptr); + ~TagContainerWidget() = default; + + void Update(const QStringList& tags); + + private: + QVBoxLayout* m_layout = nullptr; + QWidget* m_widget = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index b206cf1456..073e220810 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -34,6 +34,10 @@ set(FILES Source/EngineSettings.h Source/EngineSettings.cpp Source/EngineSettings.ui + Source/LinkWidget.h + Source/LinkWidget.cpp + Source/TagWidget.h + Source/TagWidget.cpp Source/GemCatalog/GemCatalog.h Source/GemCatalog/GemCatalog.cpp Source/GemCatalog/GemInfo.h diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp index 8d7fb63baf..3b6625ad5e 100644 --- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp @@ -364,6 +364,10 @@ namespace AZ MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&)); diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index 51fe236171..e40edcc864 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -577,6 +577,10 @@ namespace AWSClientAuthUnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index c1795f7217..540178f4d9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -95,28 +95,32 @@ namespace UnitTest class ImageProcessingTest : public ::testing::Test , public AllocatorsBase - , public ComponentApplicationBus::Handler + , public AZ::ComponentApplicationBus::Handler { public: ////////////////////////////////////////////////////////////////////////// // ComponentApplicationMessages. - ComponentApplication* GetApplication() override { return nullptr; } - void RegisterComponentDescriptor(const ComponentDescriptor*) override { } - void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } - void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } - void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } - bool AddEntity(Entity*) override { return false; } - bool RemoveEntity(Entity*) override { return false; } - bool DeleteEntity(const EntityId&) override { return false; } - Entity* FindEntity(const EntityId&) override { return nullptr; } - SerializeContext* GetSerializeContext() override { return m_context.get(); } - BehaviorContext* GetBehaviorContext() override { return nullptr; } + AZ::ComponentApplication* GetApplication() override { return nullptr; } + void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } + void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } + void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } + void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } + bool AddEntity(AZ::Entity*) override { return false; } + bool RemoveEntity(AZ::Entity*) override { return false; } + bool DeleteEntity(const AZ::EntityId&) override { return false; } + Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } + AZ::SerializeContext* GetSerializeContext() override { return m_context.get(); } + AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return m_jsonRegistrationContext.get(); } const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } - Debug::DrillerManager* GetDrillerManager() override { return nullptr; } - void EnumerateEntities(const EntityCallback& /*callback*/) override {} + AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } + void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} ////////////////////////////////////////////////////////////////////////// @@ -134,6 +138,7 @@ namespace UnitTest // Adding this handler to allow utility functions access the serialize context ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); @@ -212,6 +217,7 @@ namespace UnitTest AZ::AllocatorInstance::Destroy(); AZ::AllocatorInstance::Destroy(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); AllocatorsBase::TeardownAllocator(); } diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index ddf0ae9274..e3bdb28046 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -166,6 +167,18 @@ namespace AZ RPI::RPISystemInterface::Get()->InitializeSystemAssets(); + if (!RPI::RPISystemInterface::Get()->IsInitialized()) + { + AZ::OSString msgBoxMessage; + msgBoxMessage.append("RPI System could not initialize correctly. Check log for detail."); + + AZ::NativeUI::NativeUIRequestBus::Broadcast( + &AZ::NativeUI::NativeUIRequestBus::Events::DisplayOkDialog, "O3DE Fatal Error", msgBoxMessage.c_str(), false); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop); + + return; + } + // In the case of the game we want to call create and register the scene as a soon as we can // because a level could be loaded in autoexec.cfg and that will assert if there is no scene registered // to get the feature processors for the components. So we can't wait until the tick (whereas the Editor wants to wait) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/BlendUtility.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/BlendUtility.azsli index 631a1403d7..5fac839088 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/BlendUtility.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/BlendUtility.azsli @@ -37,8 +37,6 @@ float3 TextureBlend_Overlay(float3 target, float3 blend) //! @return the resulting blended color float3 ApplyTextureBlend(float3 color, float3 blendColor, float factor, TextureBlendMode blendMode) { - // More info to help understand some of these blend modes: https://wiki.agscollab.com/pages/viewpage.action?pageId=15764930 - if(blendMode == TextureBlendMode::Multiply) { return factor * color * blendColor; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli index 001f672631..e27cbc2195 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli @@ -25,7 +25,7 @@ class LightCullingTileIterator float viewz = abs(svPosition.w); - // https://jira.agscollab.com/browse/ATOM-4198 + // ATOM-4198 // Replace GetDimensions() with a cbuffer uint read. Reading it from a cbuffer should be faster uint tileWidth, tileHeight; tileLightDataTex.GetDimensions(tileWidth, tileHeight); diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index a59eb89dc7..b28f0f1708 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -13,6 +13,49 @@ #pragma once #include +#include + +// The order should match m_pointShadowTransforms in PointLightFeatureProcessor.h/.cpp +static const float3 PointLightShadowCubemapDirections[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; + +int GetPointLightShadowCubemapFace(const float3 targetPos, const float3 lightPos) +{ + const float3 toPoint = targetPos - lightPos; + const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); + if (toPoint.x == -maxElement) + { + return 0; + } + else if (toPoint.x == maxElement) + { + return 1; + } + else if (toPoint.y == -maxElement) + { + return 2; + } + else if (toPoint.y == maxElement) + { + return 3; + } + else if (toPoint.z == -maxElement) + { + return 4; + } + else + { + return 5; + } +} + +// PointLight::m_shadowIndices actually consists of uint16_t x 6 on the CPU, but visible as a uint32_t x 3 on the GPU. +// This function returns the proper uint16_t value given an input face in the range 0-5 +int UnpackPointLightShadowIndex(const ViewSrg::PointLight light, const int face) +{ + const int index = face >> 1; + const int shiftAmount = (face & 1) * 16; + return (light.m_shadowIndices[index] >> shiftAmount) & 0xFFFF; +} void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData) { @@ -31,11 +74,38 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD d2 = max(0.001 * 0.001, d2); // clamp the light to at least 1mm away to avoid extreme values. float3 lightIntensity = (light.m_rgbIntensityCandelas / d2) * radiusAttenuation; + // shadow + float litRatio = 1.0; + + // How much is back face shadowed, it's set to the reverse of litRatio to share the same default value with thickness, which should be 0 if no shadow map available + float backShadowRatio = 0.0; + if (o_enableShadows) + { + const int shadowCubemapFace = GetPointLightShadowCubemapFace(surface.position, light.m_position); + const int shadowIndex = UnpackPointLightShadowIndex(light, shadowCubemapFace); + + litRatio *= ProjectedShadow::GetVisibility( + shadowIndex, + light.m_position, + surface.position, + PointLightShadowCubemapDirections[shadowCubemapFace], + surface.normal); + + // Use backShadowRatio to carry thickness from shadow map for thick mode + backShadowRatio = 1.0 - litRatio; + if (o_transmission_mode == TransmissionMode::ThickObject) + { + backShadowRatio = ProjectedShadow::GetThickness( + shadowIndex, + surface.position); + } + } + // Diffuse contribution - lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)); + lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio; // Tranmission contribution - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0); + lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), backShadowRatio); // Adjust the light direcion for specular based on bulb size diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli index a7bb6cd3b1..fdf7ba92de 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli @@ -61,6 +61,8 @@ ShaderResourceGroup RayTracingSceneSrg : SRG_RayTracingScene float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; + uint3 m_shadowIndices; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 5404cf8b69..7a51d4c629 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,6 +73,8 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; + uint3 m_shadowIndices; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 367720d13b..d08c572867 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -17,7 +17,7 @@ #include #include -enum QuadLightFlag // Copied from QuadLight.azsli. See https://jira.agscollab.com/browse/ATOM-3731 +enum QuadLightFlag // Copied from QuadLight.azsli. See ATOM-3731 { None = 0x00, EmitsBothDirections = 0x01, // 1 << 0, // Quad should emit light from both sides @@ -33,7 +33,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass { // Figure out how to remove duplicate struct definitions. // These are also defined in View.srg - // https://jira.agscollab.com/browse/ATOM-3731 + // ATOM-3731 struct SimplePointLight { @@ -59,6 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; + uint3 m_shadowIndices; + uint m_padding; }; struct DiskLight @@ -370,7 +372,7 @@ void CullDecals(uint groupIndex, TileLightData tileLightData, float3 aabb_center float3 decalPosition = WorldToView_Point(decal.m_position); // just wrapping a bounding sphere around a cube for now to get a minor perf boost. i.e. the sphere radius is sqrt(x*x + y*y + z*z) - // https://jira.agscollab.com/browse/ATOM-4224 - try AABB-AABB and implement depth binning for the decals + // ATOM-4224 - try AABB-AABB and implement depth binning for the decals float maxHalfSize = max(max(decal.m_halfSize.x, decal.m_halfSize.y), decal.m_halfSize.z); float boundingSphereRadiusSqr = maxHalfSize * maxHalfSize * 3; @@ -378,7 +380,7 @@ void CullDecals(uint groupIndex, TileLightData tileLightData, float3 aabb_center if (potentiallyIntersects) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 MarkLightAsVisibleInSharedMemory(decalIndex, 0xFFFF); } } @@ -391,7 +393,7 @@ void CullPointLight(uint lightIndex, float3 lightPosition, float invLightRadius, if (potentiallyIntersects) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 uint inside = 0; float2 minmax = ComputePointLightMinMaxZ(rsqrt(invLightRadius), lightPosition); @@ -432,7 +434,7 @@ void CullSimpleSpotLights(uint groupIndex, TileLightData tileLightData, float3 a if (potentiallyIntersects) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 uint inside = 0; float2 minmax = ComputeSimpleSpotLightMinMax(light, lightPosition); @@ -477,7 +479,7 @@ void CullDiskLights(uint groupIndex, TileLightData tileLightData, float3 aabb_ce if (potentiallyIntersects) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 uint inside = 0; float2 minmax = ComputeDiskLightMinMax(light, lightPosition); @@ -505,7 +507,7 @@ void CullCapsuleLights(uint groupIndex, TileLightData tileLightData, float3 aabb if (potentiallyIntersects) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 uint inside = 0; float2 minmax = ComputeCapsuleLightMinMax(light, lightMiddleView, lightFalloffRadius); @@ -520,7 +522,7 @@ void CullCapsuleLights(uint groupIndex, TileLightData tileLightData, float3 aabb void CullQuadLights(uint groupIndex, TileLightData tileLightData, float3 aabb_center, float3 aabb_extents) { // Implement and profile fine-grained light culling testing - // https://jira.agscollab.com/browse/ATOM-3732 + // ATOM-3732 for (uint lightIndex = groupIndex ; lightIndex < PassSrg::m_quadLightCount ; lightIndex += TILE_DIM_X * TILE_DIM_Y) { diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl index 14a5f810cf..eae2acc0bc 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl @@ -242,7 +242,7 @@ PSOutput MainPS(VSOutput IN) // Set this value to > 0 to actually see this pass. It is currently always active. OUT.m_color.w = PassSrg::m_heatmapOpacity; - // https://jira.agscollab.com/browse/ATOM-3682 (improve heatmap integration with the pass system) + // ATOM-3682 (improve heatmap integration with the pass system) return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl index abef44f1fd..f56721b614 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl @@ -186,7 +186,7 @@ void InitWriteIndices(uint3 groupID, uint baseBin, out uint writeIndices[NVLC_MA // light indices until it hits an END_OF_X marker // Note that this code could probably be made faster with wave intrinsics -// https://jira.agscollab.com/browse/ATOM-4104 +// ATOM-4104 [numthreads(NUM_THREADS, 1, 1)] void MainCS( uint3 dispatchThreadID : SV_DispatchThreadID, diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingTilePrepare.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingTilePrepare.azsl index 7279864b09..fba2175c9b 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingTilePrepare.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingTilePrepare.azsl @@ -181,7 +181,7 @@ void WriteTileLightDataToMainMemory(uint groupIndex, uint3 groupID, float2 minma // Note that Nvidia Light Culling framework has some additional code to better calculate this ratio // See cb_perFrame.fRangeThreshold in their framework. This code might be something we want to port over. - // https://jira.agscollab.com/browse/ATOM-5554 + // ATOM-5554 float ratio = tileZ / 1.0f; float logMaxBins = clamp(log2(ratio), 0.0, LOG_MAX_BINS); uint ulogMaxBins = uint(logMaxBins + 0.5); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldBlurBokeh.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldBlurBokeh.azsl index b014f4e3cb..60951ebeb5 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldBlurBokeh.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldBlurBokeh.azsl @@ -41,7 +41,6 @@ ShaderResourceGroup PassSrg : SRG_PerDraw // The number of points to sample. // Sample 6 points around center pixel. // Similarly, sample around it as 12,18,24 points. -// Please refer to “https://wiki.agscollab.com/display/ATOM/Pencil+Map” for details. option enum class SampleNumber { Sample6, // 6 @@ -52,7 +51,6 @@ option enum class SampleNumber o_sampleNumber = SampleNumber::Sample6; // Get CocRadius from dofFactor. -// Please refer to https://wiki.agscollab.com/display/ATOM/Pencil+Map for CocRadius. inline float GetCocRadius(float dofFactor) { float cocRadius = dofFactor * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; @@ -61,14 +59,12 @@ inline float GetCocRadius(float dofFactor) } // Calculate the texcoord U of the pencil map from cocRadius. -// Please refer to https://wiki.agscollab.com/display/ATOM/Pencil+Map for the pencil map. inline float GetPencilMapTexcoordU(float cocRadius) { return cocRadius * ViewSrg::m_dof.m_pencilMapTexcoordToCocRadius + ViewSrg::m_dof.m_pencilMapFocusPointTexcoordU; } // Get the color from the coordinate array. -// Please refer to https://wiki.agscollab.com/display/ATOM/Pencil+Map for details of coordinates. inline float4 SampleColorAndDofFactor(float2 centerTexCoord, float cocRadius, int sampleIndex) { float2 sampleTexcoordOffset = PassSrg::m_sampleTexcoordsRadius[sampleIndex].xy * cocRadius; @@ -78,7 +74,6 @@ inline float4 SampleColorAndDofFactor(float2 centerTexCoord, float cocRadius, in } // Load the pencil map. Since the colors are square rooted, they are decoded (linearized). This is for accuracy. -// Please refer to https://wiki.agscollab.com/display/ATOM/Pencil+Map for the pencil map. inline float4 SamplePencilMap(float lensCoordX, float radius) { float2 bokehTexcoord = float2(lensCoordX, radius); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldComposite.azsl index 5c1973d3b1..0fd89e475e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldComposite.azsl @@ -77,7 +77,6 @@ PSOutput MainPS(VSOutput IN) float3 colorSum = (float3)0; // Combine from the back buffer to the front. - // Please refer to https://wiki.agscollab.com/pages/viewpage.action?spaceKey=ATOM&title=Dof+factor+and+Buffer+composition for details //////////////////////////////////////////////////////////////////////// // Background diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 68e1a01e56..30d88cb839 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -1,19 +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. -* -*/ + * 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 #include +#include +#include namespace AZ { @@ -22,9 +23,25 @@ namespace AZ namespace Render { + struct PointLightData + { + AZStd::array m_position = {{0.0f, 0.0f, 0.0f}}; + + // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. + float m_invAttenuationRadiusSquared = 0.0f; + + AZStd::array m_rgbIntensity = {{0.0f, 0.0f, 0.0f}}; + + // Radius of spherical light in meters. + float m_bulbRadius = 0.0f; + + static const int NumShadowFaces = 6; + AZStd::array m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}}; + uint32_t m_padding; + }; + //! PointLightFeatureProcessorInterface provides an interface to acquire, release, and update a point light. - class PointLightFeatureProcessorInterface - : public RPI::FeatureProcessor + class PointLightFeatureProcessorInterface : public RPI::FeatureProcessor { public: AZ_RTTI(AZ::Render::PointLightFeatureProcessorInterface, "{D3E0B016-F3C6-4C7A-A29E-0B3A4FA87806}", AZ::RPI::FeatureProcessor); @@ -33,7 +50,8 @@ namespace AZ using LightHandle = RHI::Handle; static constexpr PhotometricUnit PhotometricUnitType = PhotometricUnit::Candela; - //! Creates a new point light which can be referenced by the returned LightHandle. Must be released via ReleaseLight() when no longer needed. + //! Creates a new point light which can be referenced by the returned LightHandle. Must be released via ReleaseLight() when no + //! longer needed. virtual LightHandle AcquireLight() = 0; //! Releases a LightHandle which removes the point light. virtual bool ReleaseLight(LightHandle& handle) = 0; @@ -48,6 +66,24 @@ namespace AZ virtual void SetAttenuationRadius(LightHandle handle, float attenuationRadius) = 0; //! Sets the bulb radius for the provided LightHandle. Values greater than zero effectively make it a spherical light. virtual void SetBulbRadius(LightHandle handle, float bulbRadius) = 0; + //! Sets if shadows are enabled + virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; + //! Sets the shadowmap size (width and height) of the light. + virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; + //! Specifies filter method of shadows. + virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; + //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on + //! the boundary. 0 disables softening. + virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; + //! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering + //! sample count. + virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0; + //! Sets sample count for filtering of shadow boundary (up to 64) + virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; + //! Sets the shadowmap Pcf (percentage closer filtering) method. + virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0; + //! Sets all of the the point data for the provided LightHandle. + virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 27bac09a63..ade4b5b592 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1487,7 +1487,6 @@ namespace AZ float depthNear, float depthFar) const { - // For calculation, refer https://wiki.agscollab.com/display/ATOM/Cascaded+Shadowmaps // This calculates the center of bounding sphere for a camera view frustum. // By this, on the camera view (2D), the bounding sphere's center // shifts to the remarkable point. diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index 58bbed699a..d0fb702d5a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -380,7 +380,7 @@ namespace AZ const float invRadiusSquared = diskLight.m_invAttenuationRadiusSquared; if (invRadiusSquared <= 0.f) { - AZ_Assert(false, "Attenuation radius have to be set before use the light."); + AZ_Assert(false, "Attenuation radius must be set before using the light."); return; } const float attenuationRadius = sqrtf(1.f / invRadiusSquared); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 446b008921..8391506f63 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -59,7 +59,7 @@ namespace AZ void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; - void SetPcfMethod(LightHandle handle, PcfMethod method); + void SetPcfMethod(LightHandle handle, PcfMethod method) override; void SetDiskData(LightHandle handle, const DiskLightData& data) override; @@ -84,7 +84,7 @@ namespace AZ template void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); - ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor; + ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_diskLightData; GpuBufferHandler m_lightBufferHandler; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp index eb3e87dcd1..42882cec6e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp @@ -34,7 +34,7 @@ namespace AZ const size_t NumBins = 8; const size_t MaxLightsPerTile = 256; // TODO convert this to R16_UINT. It just needs RHI support - // https://jira.agscollab.com/browse/ATOM-3975 + // ATOM-3975 const RHI::Format LightListRemappedFormat = RHI::Format::R32_UINT; RPI::Ptr LightCullingRemap::Create(const RPI::PassDescriptor& descriptor) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 661a7d4bf4..bb81c52b15 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -44,6 +44,13 @@ namespace AZ PointLightFeatureProcessor::PointLightFeatureProcessor() : PointLightFeatureProcessorInterface() { + // Note must match PointShadowDirections in PointLight.azsli + m_pointShadowTransforms[0] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisX()); + m_pointShadowTransforms[1] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisX()); + m_pointShadowTransforms[2] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisY()); + m_pointShadowTransforms[3] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisY()); + m_pointShadowTransforms[4] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisZ()); + m_pointShadowTransforms[5] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ()); } void PointLightFeatureProcessor::Activate() @@ -54,6 +61,7 @@ namespace AZ desc.m_elementCountSrgName = "m_pointLightCount"; desc.m_elementSize = sizeof(PointLightData); desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgAsset()->GetLayout(); + m_shadowFeatureProcessor = GetParentScene()->GetFeatureProcessor(); m_lightBufferHandler = GpuBufferHandler(desc); } @@ -83,6 +91,15 @@ namespace AZ { if (handle.IsValid()) { + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + ShadowId shadowId = ShadowId(m_pointLightData.GetData(handle.GetIndex()).m_shadowIndices[i]); + if (shadowId.IsValid()) + { + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + } + } + m_pointLightData.RemoveIndex(handle.GetIndex()); m_deviceBufferNeedsUpdate = true; handle.Reset(); @@ -148,6 +165,7 @@ namespace AZ lightPosition.StoreToFloat3(position.data()); m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); } void PointLightFeatureProcessor::SetAttenuationRadius(LightHandle handle, float attenuationRadius) @@ -177,5 +195,122 @@ namespace AZ return m_lightBufferHandler.GetElementCount(); } + void PointLightFeatureProcessor::SetShadowsEnabled(LightHandle handle, bool enabled) + { + auto& light = m_pointLightData.GetData(handle.GetIndex()); + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + ShadowId shadowId = ShadowId(light.m_shadowIndices[i]); + if (shadowId.IsValid() && !enabled) + { + // Disable shadows + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + shadowId.Reset(); + light.m_shadowIndices[i] = shadowId.GetIndex(); + m_deviceBufferNeedsUpdate = true; + } + else if (shadowId.IsNull() && enabled) + { + // Enable shadows + light.m_shadowIndices[i] = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); + + UpdateShadow(handle); + m_deviceBufferNeedsUpdate = true; + } + } + } + + void PointLightFeatureProcessor::SetPointData(LightHandle handle, const PointLightData& data) + { + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetPointData()."); + + m_pointLightData.GetData(handle.GetIndex()) = data; + m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); + } + + void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) + { + constexpr float SqrtHalf = 0.707106781187f; // sqrt(0.5); + + const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + ShadowId shadowId = ShadowId(pointLight.m_shadowIndices[i]); + if (shadowId.IsNull()) + { + // Early out if shadows are disabled. + return; + } + + ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); + // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces + desc.m_fieldOfViewYRadians = DegToRad(91.0f); + desc.m_transform = m_pointShadowTransforms[i]; + desc.m_transform.SetTranslation(pointLight.m_position[0], pointLight.m_position[1], pointLight.m_position[2]); + desc.m_aspectRatio = 1.0f; + desc.m_nearPlaneDistance = SqrtHalf * pointLight.m_bulbRadius; + + const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; + if (invRadiusSquared <= 0.f) + { + AZ_Assert(false, "Attenuation radius must be set before using the light."); + return; + } + const float attenuationRadius = sqrtf(1.f / invRadiusSquared); + desc.m_farPlaneDistance = attenuationRadius + pointLight.m_bulbRadius; + + m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc); + } + } + + template + void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param) + { + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetShadowSetting()."); + + auto& light = m_pointLightData.GetData(handle.GetIndex()); + for (int lightIndex = 0; lightIndex < PointLightData::NumShadowFaces; ++lightIndex) + { + ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]); + + AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled."); + if (shadowId.IsValid()) + { + AZStd::invoke(AZStd::forward(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward(param)); + } + } + } + + void PointLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize); + } + + void PointLightFeatureProcessor::SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); + } + + void PointLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); + } + + void PointLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count); + } + + void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count); + } + + void PointLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 25b9bfa2cd..c0c377e960 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace AZ { @@ -24,15 +25,6 @@ namespace AZ namespace Render { - - struct PointLightData - { - AZStd::array m_position = { { 0.0f, 0.0f, 0.0f } }; - float m_invAttenuationRadiusSquared = 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. - AZStd::array m_rgbIntensity = { { 0.0f, 0.0f, 0.0f } }; - float m_bulbRadius = 0.0f; // Radius of spherical light in meters. - }; - class PointLightFeatureProcessor final : public PointLightFeatureProcessorInterface { @@ -58,18 +50,34 @@ namespace AZ void SetPosition(LightHandle handle, const AZ::Vector3& lightPosition) override; void SetAttenuationRadius(LightHandle handle, float attenuationRadius) override; void SetBulbRadius(LightHandle handle, float bulbRadius) override; + void SetShadowsEnabled(LightHandle handle, bool enabled) override; + void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; + void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; + void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; + void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; + void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; + void SetPcfMethod(LightHandle handle, PcfMethod method) override; + void SetPointData(LightHandle handle, const PointLightData& data) override; const Data::Instance GetLightBuffer() const; uint32_t GetLightCount()const; private: PointLightFeatureProcessor(const PointLightFeatureProcessor&) = delete; + using ShadowId = ProjectedShadowFeatureProcessor::ShadowId; static constexpr const char* FeatureProcessorName = "PointLightFeatureProcessor"; + void UpdateShadow(LightHandle handle); + // Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor + template + void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); + ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_pointLightData; GpuBufferHandler m_lightBufferHandler; bool m_deviceBufferNeedsUpdate = false; + + AZStd::array m_pointShadowTransforms; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp index bad6afbc16..1baa3d072b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp @@ -50,7 +50,7 @@ namespace AZ static constexpr Quality QualitySet[DepthOfField::QualityLevelMax] = { - // It is the radial division count of blur kernel. See "https://wiki.agscollab.com/display/ATOM/Pencil+Map" for details. + // It is the radial division count of blur kernel. {2, 3, 4}, {4, 4, 4} }; @@ -205,7 +205,6 @@ namespace AZ float scaledDiameter = ScreenApertureDiameter * 0.25f; // This is the conversion factor for calculating the blend ratio from DofFactor. - // Please refer to "https://wiki.agscollab.com/display/ATOM/Dof+factor+and+Buffer+composition" for blending of DofFactor and buffer. // coc0 : Confusion circle diameter screen ratio // coc1 : Confusion circle diameter screen ratio of one lower blur level; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.h index eeb1726cfb..6e59b6aa33 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.h @@ -139,7 +139,6 @@ namespace AZ float m_minBokehRadiusDivision8 = 0.0f; // Radial division count of bokeh blur kernel. - // See "https://wiki.agscollab.com/display/ATOM/Pencil+Map" for details. uint32_t m_sampleRadialDivision2 = 0; uint32_t m_sampleRadialDivision4 = 0; uint32_t m_sampleRadialDivision8 = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp index e51bca5fde..4a4a8a8b76 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp @@ -194,7 +194,6 @@ namespace AZ // calculate sampling texcoords. // sample 6 points around center pixel. // Similarly, sample around it as 12,18,24 points. - // Please refer to "https://wiki.agscollab.com/display/ATOM/Pencil+Map" for details. AZ_Assert(radialDivisionCount >= 1 && radialDivisionCount <= 4, "DepthOfFieldBokehBlurPass : radialDivisionCount is illegal value."); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldPencilMap.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldPencilMap.h index 585df1d4da..23a8cf9f51 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldPencilMap.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldPencilMap.h @@ -18,8 +18,6 @@ namespace AZ { namespace PencilMap { - // Please refer to "https://wiki.agscollab.com/display/ATOM/Pencil+Map" for details. - // PencilMap 35mm Film static constexpr unsigned int TextureWidth = 128; static constexpr unsigned int TextureHeight = 64; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index e0b79e23aa..3497855c07 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -120,13 +120,13 @@ namespace AZ { // stencil Srg // Note: the stencil pass uses a slightly reduced inner AABB to avoid seams - Vector3 innerExtentsReduced = m_innerExtents * m_transform.GetScale() - Vector3(0.1f, 0.1f, 0.1f); + Vector3 innerExtentsReduced = m_innerExtents - Vector3(0.1f, 0.1f, 0.1f); Matrix3x4 modelToWorldStencil = Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(innerExtentsReduced); m_stencilSrg->SetConstant(m_reflectionRenderData->m_modelToWorldStencilConstantIndex, modelToWorldStencil); m_stencilSrg->Compile(); // blend weight Srg - Matrix3x4 modelToWorldOuter = Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_outerExtents * m_transform.GetScale()); + Matrix3x4 modelToWorldOuter = Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_outerExtents); m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_modelToWorldRenderConstantIndex, modelToWorldOuter); m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_aabbPosRenderConstantIndex, m_outerAabbWs.GetCenter()); m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_outerAabbMinRenderConstantIndex, m_outerAabbWs.GetMin()); @@ -149,7 +149,7 @@ namespace AZ m_renderOuterSrg->Compile(); // render inner Srg - Matrix3x4 modelToWorldInner = Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_innerExtents * m_transform.GetScale()); + Matrix3x4 modelToWorldInner = Matrix3x4::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_innerExtents); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_modelToWorldRenderConstantIndex, modelToWorldInner); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_aabbPosRenderConstantIndex, m_outerAabbWs.GetCenter()); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_outerAabbMinRenderConstantIndex, m_outerAabbWs.GetMin()); @@ -208,6 +208,12 @@ namespace AZ void ReflectionProbe::SetTransform(const AZ::Transform& transform) { + // retrieve previous scale and revert the scale on the inner/outer extents + AZ::Vector3 previousScale = m_transform.GetScale(); + m_outerExtents /= previousScale; + m_innerExtents /= previousScale; + + // store new transform m_transform = transform; // avoid scaling the visualization sphere @@ -215,22 +221,26 @@ namespace AZ visualizationTransform.ExtractScale(); m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, visualizationTransform); - m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents * m_transform.GetScale() / 2.0f); - m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents * m_transform.GetScale() / 2.0f); + // update the inner/outer extents with the new scale + m_outerExtents *= m_transform.GetScale(); + m_innerExtents *= m_transform.GetScale(); + + m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents / 2.0f); + m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents / 2.0f); m_updateSrg = true; } void ReflectionProbe::SetOuterExtents(const AZ::Vector3& outerExtents) { - m_outerExtents = outerExtents; - m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents * m_transform.GetScale() / 2.0f); + m_outerExtents = outerExtents * m_transform.GetScale(); + m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents / 2.0f); m_updateSrg = true; } void ReflectionProbe::SetInnerExtents(const AZ::Vector3& innerExtents) { - m_innerExtents = innerExtents; - m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents * m_transform.GetScale() / 2.0f); + m_innerExtents = innerExtents * m_transform.GetScale(); + m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents / 2.0f); m_updateSrg = true; } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h index ab0e7a81d3..f062e0a42f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h @@ -78,10 +78,10 @@ namespace AZ const Vector3& GetPosition() const { return m_transform.GetTranslation(); } void SetTransform(const AZ::Transform& transform); - AZ::Vector3 GetOuterExtents() const { return m_outerExtents * m_transform.GetScale(); } + const AZ::Vector3& GetOuterExtents() const { return m_outerExtents; } void SetOuterExtents(const AZ::Vector3& outerExtents); - AZ::Vector3 GetInnerExtents() const { return m_innerExtents * m_transform.GetScale(); } + const AZ::Vector3& GetInnerExtents() const { return m_innerExtents; } void SetInnerExtents(const AZ::Vector3& innerExtents); const Aabb& GetOuterAabbWs() const { return m_outerAabbWs; } diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h index 777a20ada9..30523194b6 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h @@ -124,6 +124,8 @@ namespace AZ // This lock will only be contested when the CpuProfiler's Shutdown() method has been called AZStd::shared_mutex m_shutdownMutex; + + bool m_initialized = false; }; }; // namespace RPI diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index 28c3ef6a7b..8242c89886 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -82,10 +82,15 @@ namespace AZ void CpuProfilerImpl::Init() { Interface::Register(this); + m_initialized = true; } void CpuProfilerImpl::Shutdown() { + if (!m_initialized) + { + return; + } // When this call is made, no more thread profiling calls can be performed anymore Interface::Unregister(this); @@ -97,6 +102,7 @@ namespace AZ // Cleanup all TLS m_registeredThreads.clear(); m_timeRegionMap.clear(); + m_initialized = false; } void CpuProfilerImpl::BeginTimeRegion(TimeRegion& timeRegion) diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index f92d2621b1..95e0a33981 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -200,9 +200,12 @@ namespace AZ m_platformLimitsDescriptor = nullptr; m_pipelineStateCache = nullptr; - m_device->PreShutdown(); - AZ_Assert(m_device->use_count()==1, "The ref count for Device is %i but it should be 1 here to ensure all the resources are released", m_device->use_count()); - m_device = nullptr; + if (m_device) + { + m_device->PreShutdown(); + AZ_Assert(m_device->use_count()==1, "The ref count for Device is %i but it should be 1 here to ensure all the resources are released", m_device->use_count()); + m_device = nullptr; + } m_cpuProfiler.Shutdown(); } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp index f816a7ae04..22849f7236 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp @@ -90,12 +90,16 @@ namespace AZ void AsyncUploadQueue::Shutdown() { - m_copyQueue->Shutdown(); + if (m_copyQueue) + { + m_copyQueue->Shutdown(); + m_copyQueue = nullptr; + } m_commandList = nullptr; - for (size_t i = 0; i < m_descriptor.m_frameCount; ++i) + for (auto& framePacket : m_framePackets) { - m_framePackets[i].m_fence.Shutdown(); + framePacket.m_fence.Shutdown(); } m_framePackets.clear(); m_uploadFence.Shutdown(); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp index 4c133084ac..a31e105b19 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp @@ -109,7 +109,10 @@ namespace AZ AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx) { - m_commandQueues[hardwareQueueIdx]->WaitForIdle(); + if (m_commandQueues[hardwareQueueIdx]) + { + m_commandQueues[hardwareQueueIdx]->WaitForIdle(); + } } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h index 91d60bcb36..c4b6aa74b4 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h @@ -45,6 +45,8 @@ namespace AZ private: RHI::Ptr m_commonPools[static_cast(CommonBufferPoolType::Count)]; + + bool m_initialized = false; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h index 67f33758dc..b8f52a532e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h @@ -80,6 +80,8 @@ namespace AZ Data::Asset m_defaultStreamingImageControllerAsset; AZStd::fixed_vector, static_cast(SystemImage::Count)> m_systemImages; + + bool m_initialized = false; }; } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index e61b90d55a..283cea7c0a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -82,7 +82,7 @@ namespace AZ void RemovePassFromLibrary(Pass* pass); //! Load pass templates which are list in an AssetAliases - void LoadPassTemplateMappings(const AZStd::string& templateMappingPath); + bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath); bool LoadPassTemplateMappings(Data::Asset mappingAsset); //! Returns a list of passes found in the pass name mapping using the provided pass filter diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index acbb914dfa..d37868025c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -66,7 +66,7 @@ namespace AZ // PassSystemInterface functions... void ProcessQueuedChanges() override; - void LoadPassTemplateMappings(const AZStd::string& templateMappingPath) override; + bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath) override; void WriteTemplateToFile(const PassTemplate& passTemplate, AZStd::string_view assetFilePath) override; void DebugPrintPassHierarchy() override; bool IsBuilding() const override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 93754c2229..82d52ab5a2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -65,7 +65,7 @@ namespace AZ virtual void ProcessQueuedChanges() = 0; //! Load pass templates listed in a name-assetid mapping asset - virtual void LoadPassTemplateMappings(const AZStd::string& templateMappingPath) = 0; + virtual bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath) = 0; //! Writes a pass template to a .pass file which can then be used as a pass asset. Useful for //! quickly authoring a pass template in code and then outputting it as a pass asset using JSON diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 80b9022f0d..ff3c784a51 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -70,6 +70,7 @@ namespace AZ void Shutdown(); // RPISystemInterface overrides... + bool IsInitialized() const override; void InitializeSystemAssets() override; void RegisterScene(ScenePtr scene) override; void UnregisterScene(ScenePtr scene) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h index 27b381257d..c2ceca73a9 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h @@ -40,6 +40,9 @@ namespace AZ //! Note: can't rely on the AzFramework::AssetCatalogEventBus's OnCatalogLoaded since the order of calling handlers is undefined. virtual void InitializeSystemAssets() = 0; + //! Was the RPI system initialized properly + virtual bool IsInitialized() const = 0; + //! Register a created scene to RPISystem. Registered scene will be simulated and rendered in RPISystem ticks virtual void RegisterScene(ScenePtr scene) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h index 527bae7e1f..5a169a9e61 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h @@ -15,6 +15,8 @@ #include #include +#include + namespace AZ { namespace RPI @@ -48,6 +50,12 @@ namespace AZ //! @return a null asset if the asset could not be found or loaded. template Data::Asset LoadAssetById(Data::AssetId assetId, TraceLevel reporting = TraceLevel::Warning); + + //! Loads a critial asset using a file path (both source and product path should be same), on the current thread. + //! If the asset wasn't compiled, wait until the asset is compiled. + //! @return a null asset if the asset could not be compiled or loaded. + template + Data::Asset LoadCriticalAsset(const AZStd::string& assetFilePath, TraceLevel reporting = TraceLevel::Error); template bool LoadBlocking(AZ::Data::Asset& asset, TraceLevel reporting = TraceLevel::Warning); @@ -89,7 +97,7 @@ namespace AZ assetId, AZ::Data::AssetLoadBehavior::PreLoad); asset.BlockUntilLoadComplete(); - if (!asset.Get()) + if (!asset.IsReady()) { AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not load '%s'", productPath).c_str()); return {}; @@ -117,7 +125,7 @@ namespace AZ ); asset.BlockUntilLoadComplete(); - if (!asset.Get()) + if (!asset.IsReady()) { AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not load '%s'", assetId.ToString().c_str()).c_str()); return {}; @@ -126,6 +134,21 @@ namespace AZ return asset; } + template + Data::Asset LoadCriticalAsset(const AZStd::string& assetFilePath, TraceLevel reporting) + { + AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; + AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilePath); + + if (status != AzFramework::AssetSystem::AssetStatus_Compiled) + { + AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not compile asset '%s'", assetFilePath.c_str()).c_str()); + return {}; + } + + return LoadAssetByProductPath(assetFilePath.c_str(), reporting); + } + template bool LoadBlocking(AZ::Data::Asset& asset, TraceLevel reporting) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp index 491f57deec..9a9254b0d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp @@ -61,10 +61,16 @@ namespace AZ Data::InstanceDatabase::Create(azrtti_typeid(), handler); } Interface::Register(this); + + m_initialized = true; } void BufferSystem::Shutdown() { + if (!m_initialized) + { + return; + } for (uint8_t index = 0; index < static_cast(CommonBufferPoolType::Count); index++) { m_commonPools[index] = nullptr; @@ -72,6 +78,7 @@ namespace AZ Interface::Unregister(this); Data::InstanceDatabase::Destroy(); Data::InstanceDatabase::Destroy(); + m_initialized = false; } RHI::Ptr BufferSystem::GetCommonBufferPool(CommonBufferPoolType poolType) @@ -87,6 +94,10 @@ namespace AZ bool BufferSystem::CreateCommonBufferPool(CommonBufferPoolType poolType) { + if (!m_initialized) + { + return false; + } auto* device = RHI::RHISystemInterface::Get()->GetDevice(); RHI::Ptr bufferPool = RHI::Factory::Get().CreateBufferPool(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp index ac7ba1e3cc..f7cdc2ff71 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp @@ -148,10 +148,16 @@ namespace AZ CreateDefaultResources(desc); Interface::Register(this); + + m_initialized = true; } void ImageSystem::Shutdown() { + if (!m_initialized) + { + return; + } Interface::Unregister(this); m_defaultStreamingImageControllerAsset.Release(); @@ -167,6 +173,7 @@ namespace AZ Data::InstanceDatabase::Destroy(); m_activeStreamingPools.clear(); + m_initialized = false; } void ImageSystem::Update() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index d8f6416abc..6c1f96e414 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -327,14 +327,15 @@ namespace AZ } } - void PassLibrary::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) + bool PassLibrary::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) { - Data::Asset mappingAsset = AssetUtils::LoadAssetByProductPath(templateMappingPath.c_str(), AssetUtils::TraceLevel::Error); + Data::Asset mappingAsset = AssetUtils::LoadCriticalAsset(templateMappingPath.c_str(), AssetUtils::TraceLevel::Error); bool success = LoadPassTemplateMappings(mappingAsset); if (success) { Data::AssetBus::MultiHandler::BusConnect(mappingAsset->GetId()); } + return success; } bool PassLibrary::LoadPassTemplateMappings(Data::Asset mappingAsset) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 55b71c6962..706d759231 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -100,9 +100,9 @@ namespace AZ m_rootPass->m_flags.m_partOfHierarchy = true; } - void PassSystem::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) + bool PassSystem::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) { - m_passLibrary.LoadPassTemplateMappings(templateMappingPath); + return m_passLibrary.LoadPassTemplateMappings(templateMappingPath); } void PassSystem::WriteTemplateToFile(const PassTemplate& passTemplate, AZStd::string_view assetFilePath) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 52c39d2204..5cd6f93715 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -334,7 +334,6 @@ namespace AZ void RPISystem::InitializeSystemAssets() { - AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; if (m_systemAssetsInitialized) { AZ_Warning("RPISystem", false , "InitializeSystemAssets should only be called once'"); @@ -344,36 +343,47 @@ namespace AZ //[GFX TODO][ATOM-5867] - Move file loading code within RHI to reduce coupling with RPI AZStd::string platformLimitsFilePath = AZStd::string::format("config/platform/%s/%s/platformlimits.azasset", AZ_TRAIT_OS_PLATFORM_NAME, GetRenderApiName().GetCStr()); AZStd::to_lower(platformLimitsFilePath.begin(), platformLimitsFilePath.end()); - // Wait for the platformlimits asset to be compiled (if it exists) - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, platformLimitsFilePath); - Data::Asset platformLimitsAsset = RPI::AssetUtils::LoadAssetByProductPath(platformLimitsFilePath.c_str(), RPI::AssetUtils::TraceLevel::Error); - m_descriptor.m_rhiSystemDescriptor.m_platformLimits = RPI::GetDataFromAnyAsset(platformLimitsAsset); + + Data::Asset platformLimitsAsset; + platformLimitsAsset = RPI::AssetUtils::LoadCriticalAsset(platformLimitsFilePath.c_str(), RPI::AssetUtils::TraceLevel::None); + // Only read the m_platformLimits if the platformLimitsAsset is ready. + // The platformLimitsAsset may not exist for null renderer which is allowed + if (platformLimitsAsset.IsReady()) + { + m_descriptor.m_rhiSystemDescriptor.m_platformLimits = RPI::GetDataFromAnyAsset(platformLimitsAsset); + } + + m_viewSrgAsset = AssetUtils::LoadCriticalAsset( m_descriptor.m_viewSrgAssetPath.c_str()); + if (!m_viewSrgAsset.IsReady()) + { + return; + } + m_sceneSrgAsset = AssetUtils::LoadCriticalAsset(m_descriptor.m_sceneSrgAssetPath.c_str()); + if (!m_sceneSrgAsset.IsReady()) + { + return; + } m_rhiSystem.Init(m_descriptor.m_rhiSystemDescriptor); m_imageSystem.Init(m_descriptor.m_imageSystemDescriptor); m_bufferSystem.Init(); m_dynamicDraw.Init(m_descriptor.m_dynamicDrawSystemDescriptor); - // Wait for the assets be compiled - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_descriptor.m_viewSrgAssetPath); - AZ_Error("RPISystem", status == AzFramework::AssetSystem::AssetStatus_Compiled, "Could not compile view SRG at '%s'", m_descriptor.m_viewSrgAssetPath.c_str()); - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_descriptor.m_sceneSrgAssetPath); - AZ_Error("RPISystem", status == AzFramework::AssetSystem::AssetStatus_Compiled, "Could not compile scene SRG at '%s'", m_descriptor.m_sceneSrgAssetPath.c_str()); - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_descriptor.m_passTemplatesMappingPath); - AZ_Error("RPISystem", status == AzFramework::AssetSystem::AssetStatus_Compiled, "Could not compile pass template mapping at '%s'", m_descriptor.m_passTemplatesMappingPath.c_str()); - - m_viewSrgAsset = AssetUtils::LoadAssetByProductPath(m_descriptor.m_viewSrgAssetPath.c_str(), AssetUtils::TraceLevel::Error); - m_sceneSrgAsset = AssetUtils::LoadAssetByProductPath(m_descriptor.m_sceneSrgAssetPath.c_str(), AssetUtils::TraceLevel::Error); - // Have pass system load default pass template mapping - m_passSystem.LoadPassTemplateMappings(m_descriptor.m_passTemplatesMappingPath); + bool passSystemReady = m_passSystem.LoadPassTemplateMappings(m_descriptor.m_passTemplatesMappingPath); + if (!passSystemReady) + { + return; + } + m_systemAssetsInitialized = true; } + bool RPISystem::IsInitialized() const + { + return m_systemAssetsInitialized; + } + void RPISystem::InitializeSystemAssetsForTests() { if (m_systemAssetsInitialized) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index b5d3f815fe..cc25fb39ba 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -26,6 +26,7 @@ namespace AZ , m_windowContext(AZStd::make_shared()) , m_manager(manager) , m_name(name) + , m_viewportSize(1, 1) { m_windowContext->Initialize(device, nativeWindow); AzFramework::WindowRequestBus::EventResult( @@ -204,6 +205,7 @@ namespace AZ { const auto view = GetDefaultView(); view->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(transform.GetOrthogonalized())); + m_viewMatrixChangedEvent.Signal(view->GetWorldToViewMatrix()); } void ViewportContext::SetDefaultView(ViewPtr view) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderResourceGroupAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderResourceGroupAsset.cpp index d372e1442d..d8f8c7d1ce 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderResourceGroupAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderResourceGroupAsset.cpp @@ -41,7 +41,11 @@ namespace AZ const RHI::ShaderResourceGroupLayout* ShaderResourceGroupAsset::GetLayout() const { - AZ_Assert(m_currentAPITypeIndex < m_perAPILayout.size(), "Invalid API Type index"); + AZ_Error("RHI::ShaderResourceGroupLayout", m_currentAPITypeIndex < m_perAPILayout.size(), "Invalid API Type index"); + if (m_currentAPITypeIndex >= m_perAPILayout.size()) + { + return nullptr; + } return m_perAPILayout[m_currentAPITypeIndex].second.get(); } diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp index 657657d07d..36598fb29f 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp @@ -75,6 +75,7 @@ namespace UnitTest // Adding this handler to allow utility functions access the serialize context ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); // Startup default local FileIO (hits OSAllocator) if not already setup. if (IO::FileIOBase::GetInstance() == nullptr) @@ -113,6 +114,7 @@ namespace UnitTest delete IO::FileIOBase::GetInstance(); IO::FileIOBase::SetInstance(nullptr); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); m_jsonRegistrationContext->EnableRemoveReflection(); diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index 51282642aa..81d9ddb87a 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -41,6 +41,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index f400a171c5..9ab6aea51a 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -38,6 +38,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index ff2a9cdf98..a41c8221f0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -100,7 +100,7 @@ namespace AtomToolsFramework const AzFramework::ScreenPoint& screenPosition) override; //! Set interface for providing viewport specific settings (e.g. snapping properties). - void SetViewportSettings(AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings); + void SetViewportSettings(const AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings); // AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler ... void BeginCursorCapture() override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 961de670e8..cee178c724 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -407,7 +407,7 @@ namespace AtomToolsFramework return m_viewportSettings ? m_viewportSettings->AngleStep() : 0.0f; } - void RenderViewportWidget::SetViewportSettings(AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings) + void RenderViewportWidget::SetViewportSettings(const AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings) { m_viewportSettings = viewportSettings; } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index 8a063cd7a7..482bd21972 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -506,9 +506,10 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + AZStd::vector transformedVertices = ToWorldSpacePosition(vertices); AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = vertices.data(); - drawArgs.m_vertCount = aznumeric_cast(vertices.size()); + drawArgs.m_verts = transformedVertices.data(); + drawArgs.m_vertCount = aznumeric_cast(transformedVertices.size()); drawArgs.m_colors = &color; drawArgs.m_colorCount = 1; drawArgs.m_opacityType = m_rendState.m_opacityType; @@ -526,9 +527,10 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + AZStd::vector transformedVertices = ToWorldSpacePosition(vertices); AZ::RPI::AuxGeomDraw::AuxGeomDynamicIndexedDrawArguments drawArgs; - drawArgs.m_verts = vertices.data(); - drawArgs.m_vertCount = aznumeric_cast(vertices.size()); + drawArgs.m_verts = transformedVertices.data(); + drawArgs.m_vertCount = aznumeric_cast(transformedVertices.size()); drawArgs.m_indices = indices.data(); drawArgs.m_indexCount = aznumeric_cast(indices.size()); drawArgs.m_colors = &color; @@ -659,9 +661,10 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + AZStd::vector transformedLines = ToWorldSpacePosition(lines); AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = lines.data(); - drawArgs.m_vertCount = aznumeric_cast(lines.size()); + drawArgs.m_verts = transformedLines.data(); + drawArgs.m_vertCount = aznumeric_cast(transformedLines.size()); drawArgs.m_colors = &color; drawArgs.m_colorCount = 1; drawArgs.m_size = m_rendState.m_lineWidth; @@ -928,13 +931,14 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement(); const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); m_auxGeomPtr->DrawCylinder( worldCenter, worldAxis, - radius, - height, + scale * radius, + scale * height, m_rendState.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Line, m_rendState.m_depthTest, @@ -954,13 +958,14 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement(); const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); m_auxGeomPtr->DrawCylinder( worldCenter, worldAxis, - radius, - height, + scale * radius, + scale * height, m_rendState.m_color, drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid, m_rendState.m_depthTest, @@ -1064,10 +1069,10 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { - + const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement(); m_auxGeomPtr->DrawSphere( ToWorldSpacePosition(pos), - radius, + scale * radius, m_rendState.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Line, m_rendState.m_depthTest, @@ -1158,12 +1163,13 @@ namespace AZ::AtomBridge { if (m_auxGeomPtr) { + const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement(); const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); const AZ::Vector3 worldDir = ToWorldSpaceVector(dir); m_auxGeomPtr->DrawDisk( worldPos, worldDir, - radius, + scale * radius, m_rendState.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, m_rendState.m_depthTest, @@ -1513,6 +1519,26 @@ namespace AZ::AtomBridge return m_rendState.m_transformStack[m_rendState.m_currentTransform]; } + AZStd::vector AtomDebugDisplayViewportInterface::ToWorldSpacePosition(const AZStd::vector& positions) const + { + AZStd::vector transformedPositions; + transformedPositions.resize_no_construct(positions.size()); + AZStd::transform(positions.begin(), positions.end(), transformedPositions.begin(), [this](const AZ::Vector3& position) { + return ToWorldSpacePosition(position); + }); + return transformedPositions; + } + + AZStd::vector AtomDebugDisplayViewportInterface::ToWorldSpaceVector(const AZStd::vector& vectors) const + { + AZStd::vector transformedVectors; + transformedVectors.resize_no_construct(vectors.size()); + AZStd::transform(vectors.begin(), vectors.end(), transformedVectors.begin(), [this](const AZ::Vector3& vector) { + return ToWorldSpaceVector(vector); + }); + return transformedVectors; + } + AZ::RPI::ViewportContextPtr AtomDebugDisplayViewportInterface::GetViewportContext() const { auto viewContextManager = AZ::Interface::Get(); diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index c872e2b81e..18d280ef88 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -249,6 +249,12 @@ namespace AZ::AtomBridge //! Convert direction to world space (translation is not considered) AZ::Vector3 ToWorldSpaceVector(const AZ::Vector3& v) const { return m_rendState.m_transformStack[m_rendState.m_currentTransform].Multiply3x3(v); } + //! Convert positions to world space. + AZStd::vector ToWorldSpacePosition(const AZStd::vector& positions) const; + + //! Convert directions to world space (translation is not considered) + AZStd::vector ToWorldSpaceVector(const AZStd::vector& vectors) const; + void CalcBasisVectors(const AZ::Vector3& n, AZ::Vector3& b1, AZ::Vector3& b2) const; const AZ::Matrix3x4& GetCurrentTransform() const; diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h index fbefc84aad..d5463fc15c 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h @@ -79,7 +79,6 @@ namespace AZ FontFamilyPtr LoadFontFamily(const char* fontFamilyName) override; FontFamilyPtr GetFontFamily(const char* fontFamilyName) override; void AddCharsToFontTextures(FontFamilyPtr fontFamily, const char* chars, int glyphSizeX = ICryFont::defaultGlyphSizeX, int glyphSizeY = ICryFont::defaultGlyphSizeY) override; - void SetRendererProperties([[maybe_unused]] IRenderer* renderer) override {} void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {} string GetLoadedFontNames() const; void OnLanguageChanged() override; diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomNullFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomNullFont.h index 11efc35109..4951f909e8 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomNullFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomNullFont.h @@ -79,7 +79,6 @@ namespace AZ virtual FontFamilyPtr LoadFontFamily([[maybe_unused]] const char* fontFamilyName) override { CRY_ASSERT(false); return nullptr; } virtual FontFamilyPtr GetFontFamily([[maybe_unused]] const char* fontFamilyName) override { CRY_ASSERT(false); return nullptr; } virtual void AddCharsToFontTextures([[maybe_unused]] FontFamilyPtr fontFamily, [[maybe_unused]] const char* chars, [[maybe_unused]] int glyphSizeX, [[maybe_unused]] int glyphSizeY) override {}; - virtual void SetRendererProperties([[maybe_unused]] IRenderer* pRenderer) override {} virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {} virtual string GetLoadedFontNames() const override { return ""; } virtual void OnLanguageChanged() override { } diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp index 40684640d6..75b0e22e4a 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp @@ -1233,7 +1233,8 @@ void AZ::FFont::WrapText(string& result, float maxWidth, const char* str, const if (ctx.m_sizeIn800x600) { - maxWidth = gEnv->pRenderer->ScaleCoordX(maxWidth); + // ToDo: Update to work with Atom? LYN-3676 + // maxWidth = ???->ScaleCoordX(maxWidth); } Vec2 strSize = GetTextSize(result.c_str(), true, ctx); diff --git a/Gems/AtomLyIntegration/AtomFont/gem.json b/Gems/AtomLyIntegration/AtomFont/gem.json index 2a422eaf53..d5ca7834fd 100644 --- a/Gems/AtomLyIntegration/AtomFont/gem.json +++ b/Gems/AtomLyIntegration/AtomFont/gem.json @@ -1,5 +1,5 @@ { - "gem_name": "AtomLyIntegration_AtomFont", + "gem_name": "AtomFont", "Dependencies": [ ], "GemFormatVersion": 4, diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index 2dc439b846..8f10204ae9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -112,7 +112,7 @@ namespace AZ bool AreaLightComponentConfig::SupportsShadows() const { - return m_shapeType == AZ_CRC_CE("DiskShape"); + return m_lightType == LightType::SpotDisk || m_lightType == LightType::Sphere; } bool AreaLightComponentConfig::ShadowsDisabled() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index de733e255b..e3cf1fac78 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -63,5 +63,64 @@ namespace AZ debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity)); } } + + void SphereLightDelegate::SetEnableShadow(bool enabled) + { + Base::SetEnableShadow(enabled); + + if (GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); + } + } + + void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); + } + } + + void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); + } + } + + void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); + } + } + + void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetPcfMethod(PcfMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method); + } + } + } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 7d790f2d6c..178540fd01 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -24,6 +24,8 @@ namespace AZ class SphereLightDelegate final : public LightDelegateBase { + using Base = LightDelegateBase; + public: SphereLightDelegate(LmbrCentral::SphereShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible); @@ -32,6 +34,13 @@ namespace AZ void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const override; float GetSurfaceArea() const override; float GetEffectiveSolidAngle() const override { return PhotometricValue::OmnidirectionalSteradians; } + void SetEnableShadow(bool enabled) override; + void SetShadowmapMaxSize(ShadowmapSize size) override; + void SetShadowFilterMethod(ShadowFilterMethod method) override; + void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; + void SetPredictionSampleCount(uint32_t count) override; + void SetFilteringSampleCount(uint32_t count) override; + void SetPcfMethod(PcfMethod method) override; private: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 70627fd2f1..a4a91cf708 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -296,8 +296,7 @@ namespace AZ m_configuration.m_modelAsset = modelAsset; MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model); MaterialReceiverNotificationBus::Event(m_entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 772a995584..91040885f1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -253,8 +253,7 @@ namespace AZ m_configuration.m_outerLength = dimensions.GetY(); m_configuration.m_outerHeight = dimensions.GetZ(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); // clamp the inner extents to the outer extents m_configuration.m_innerWidth = AZStd::min(m_configuration.m_innerWidth, m_configuration.m_outerWidth); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index f8b638efaf..d0116452b7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -82,8 +82,7 @@ namespace AZ // Update RenderActorInstance local bounding box m_localAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetStaticBasedAABB().GetMin(), m_actorInstance->GetStaticBasedAABB().GetMax()); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } AZ::Aabb AtomActorInstance:: GetWorldBounds() diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Editor/Scripts/bootstrap.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Editor/Scripts/bootstrap.py index d1c1921ee5..6fd8b03e9e 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Editor/Scripts/bootstrap.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Editor/Scripts/bootstrap.py @@ -16,7 +16,7 @@ with Lumberyard. Note: this boostrap is only designed fo be py3 compatible. If you need DCCsi access in py27 (Autodesk Maya for instance) you may need to implement your own boostrapper module. Currently this is boostrapped from add_dccsi.py, as a temporty measure related to this Jira: -https://jira.agscollab.com/browse/SPEC-2581""" +SPEC-2581""" # standard imports import sys import os diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/SDK/Maya/Scripts/userSetup.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/SDK/Maya/Scripts/userSetup.py index c615311f3c..0a206245c0 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/SDK/Maya/Scripts/userSetup.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/SDK/Maya/Scripts/userSetup.py @@ -25,7 +25,7 @@ the provided env and launcher bat files. If you are developing for the DCCsi you can use this launcher to start Maya: DccScriptingInterface\Launchers\Windows\Launch_Maya_2020.bat" -To Do: https://jira.agscollab.com/browse/ATOM-5861 +To Do: ATOM-5861 """ __project__ = 'DccScriptingInterface' diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/dev/ide/wing/readme.txt b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/dev/ide/wing/readme.txt index 80c950d10b..2d32541c40 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/dev/ide/wing/readme.txt +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/dev/ide/wing/readme.txt @@ -43,7 +43,7 @@ Note: to get this to work unfortunatley each user must configure the wingide pre (there is no shared project / data-driven way that I know of to set this up otherwise) Note: lumberyard is not currently generating __init__.pyi files in that package structure: -https://jira.agscollab.com/browse/SPEC-3315 +SPEC-3315 The workaround is to create them yourself (they can be empty) and needs to be in the root of each package folder, like this: dev\Cache\AtomTechArt\pc\user\python_symbols\azlmbr\__init__.pyi @@ -63,4 +63,4 @@ You might need to reboot wing. Then you should have auto-complete for the lumbe Note: the entirety of azlmbr api does not generate .pyi files currently, all of the "Behaviour Context" based classes do non-BC modules such as azlmbr.paths currently do not -https://jira.agscollab.com/browse/SPEC-3316 +SPEC-3316 diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/core_utils.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/core_utils.py index 6404f3ee07..958d3f688d 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/core_utils.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/core_utils.py @@ -40,7 +40,7 @@ Module Documentation: To Do: - https://jira.agscollab.com/browse/ATOM-5859 + ATOM-5859 ''' # ------------------------------------------------------------------------- diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/envar_utils.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/envar_utils.py index 4e59f86063..acc24f3f79 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/envar_utils.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/shared/common/envar_utils.py @@ -22,7 +22,7 @@ Module: \azpy\shared\common\config_utils.py To Do: - https://jira.agscollab.com/browse/ATOM-5859 + ATOM-5859 ''' # ------------------------------------------------------------------------- diff --git a/Gems/AudioSystem/Code/Source/Engine/ATL.cpp b/Gems/AudioSystem/Code/Source/Engine/ATL.cpp index 2398836e48..dc6742d460 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATL.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATL.cpp @@ -2018,7 +2018,8 @@ namespace Audio { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); - if (IRenderAuxGeom* pAuxGeom = (g_audioCVars.m_nDrawAudioDebug > 0 && gEnv->pRenderer) ? gEnv->pRenderer->GetIRenderAuxGeom() : nullptr) + // ToDo: Update to work with Atom? LYN-3677 + /*if (g_audioCVars.m_nDrawAudioDebug > 0) { DrawAudioObjectDebugInfo(*pAuxGeom); // needs to be called first so that the rest of the labels are printed // on top (Draw2dLabel doesn't provide a way set which labels are printed on top) @@ -2108,7 +2109,7 @@ namespace Audio DrawATLComponentDebugInfo(*pAuxGeom, fPosX, fPosY); pAuxGeom->Commit(7); - } + }*/ } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLAudioObject.cpp b/Gems/AudioSystem/Code/Source/Engine/ATLAudioObject.cpp index 7f3735dacf..3b820eb51d 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLAudioObject.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATLAudioObject.cpp @@ -839,16 +839,16 @@ namespace Audio const AZ::Vector3 vPos(m_oPosition.GetPositionVec()); AZ::Vector3 vScreenPos(0.f); - if (IRenderer* pRenderer = gEnv->pRenderer) - { + // ToDo: Update to work with Atom? LYN-3677 + /*{ float screenProj[3]; - pRenderer->ProjectToScreen(vPos.GetX(), vPos.GetY(), vPos.GetZ(), &screenProj[0], &screenProj[1], &screenProj[2]); + ???->ProjectToScreen(vPos.GetX(), vPos.GetY(), vPos.GetZ(), &screenProj[0], &screenProj[1], &screenProj[2]); - screenProj[0] *= 0.01f * static_cast(pRenderer->GetWidth()); - screenProj[1] *= 0.01f * static_cast(pRenderer->GetHeight()); + screenProj[0] *= 0.01f * static_cast(???->GetWidth()); + screenProj[1] *= 0.01f * static_cast(???->GetHeight()); vScreenPos.Set(screenProj); } - else + else*/ { vScreenPos.SetZ(-1.0f); } @@ -1081,8 +1081,8 @@ namespace Audio ); } - IRenderer* renderer = gEnv->pRenderer; - if (drawLabels && renderer) + // ToDo: Update to work with Atom? LYN-3677 + /*if (drawLabels) { float screenProj[3]; renderer->ProjectToScreen(rayEnd.GetX(), rayEnd.GetY(), rayEnd.GetZ(), @@ -1108,7 +1108,7 @@ namespace Audio rayInfo.GetDistanceScaledContribution() ); } - } + }*/ } auxGeom.SetRenderFlags(previousRenderFlags); diff --git a/Gems/CMakeLists.txt b/Gems/CMakeLists.txt deleted file mode 100644 index 8a9a140008..0000000000 --- a/Gems/CMakeLists.txt +++ /dev/null @@ -1,83 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -add_subdirectory(TextureAtlas) -add_subdirectory(LmbrCentral) -add_subdirectory(LyShine) -add_subdirectory(Maestro) -add_subdirectory(SceneProcessing) -add_subdirectory(SurfaceData) -add_subdirectory(EMotionFX) -add_subdirectory(Achievements) -add_subdirectory(CameraFramework) -add_subdirectory(HttpRequestor) -add_subdirectory(Gestures) -add_subdirectory(FastNoise) -add_subdirectory(GradientSignal) -add_subdirectory(AudioSystem) -add_subdirectory(AudioEngineWwise) -add_subdirectory(GraphCanvas) -add_subdirectory(DebugDraw) -add_subdirectory(ImGui) -add_subdirectory(InAppPurchases) -add_subdirectory(LocalUser) -add_subdirectory(LyShineExamples) -add_subdirectory(ExpressionEvaluation) -add_subdirectory(MessagePopup) -add_subdirectory(PhysX) -add_subdirectory(PhysXDebug) -add_subdirectory(ScriptEvents) -add_subdirectory(AssetValidation) -add_subdirectory(VirtualGamepad) -add_subdirectory(SaveData) -add_subdirectory(Camera) -add_subdirectory(GameState) -add_subdirectory(Vegetation) -add_subdirectory(GameStateSamples) -add_subdirectory(SliceFavorites) -add_subdirectory(Metastream) -add_subdirectory(ScriptCanvas) -add_subdirectory(ScriptedEntityTweener) -add_subdirectory(StartingPointMovement) -add_subdirectory(StartingPointInput) -add_subdirectory(ScriptCanvasPhysics) -add_subdirectory(StartingPointCamera) -add_subdirectory(Presence) -add_subdirectory(ScriptCanvasTesting) -add_subdirectory(TestAssetBuilder) -add_subdirectory(ScriptCanvasDeveloper) -add_subdirectory(CustomAssetExample) -add_subdirectory(AutomatedLauncherTesting) -add_subdirectory(NvCloth) -add_subdirectory(AssetMemoryAnalyzer) -add_subdirectory(CertificateManager) -add_subdirectory(TickBusOrderViewer) -add_subdirectory(MultiplayerCompression) -add_subdirectory(Multiplayer) -add_subdirectory(SceneLoggingExample) -add_subdirectory(VideoPlaybackFramework) -add_subdirectory(CrashReporting) -add_subdirectory(Twitch) -add_subdirectory(EditorPythonBindings) -add_subdirectory(QtForPython) -add_subdirectory(Microphone) -add_subdirectory(Atom) -add_subdirectory(AtomLyIntegration) -add_subdirectory(RADTelemetry) -add_subdirectory(GraphModel) -add_subdirectory(LandscapeCanvas) -add_subdirectory(WhiteBox) -add_subdirectory(Blast) -add_subdirectory(PythonAssetBuilder) -add_subdirectory(Prefab) -add_subdirectory(AWSClientAuth) -add_subdirectory(AWSCore) -add_subdirectory(AWSMetrics) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 8ef87af9a7..982b62fbcf 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -504,8 +504,7 @@ namespace EMotionFX { m_renderActorInstance->OnTick(deltaTime); m_renderActorInstance->UpdateBounds(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); // Optimization: Set the actor instance invisible when character is out of camera view. This will stop the joint transforms update, except the root joint. // Calling it after the bounds on the render actor updated. diff --git a/Gems/EMotionFX/Code/Tests/MorphSkinAttachmentTests.cpp b/Gems/EMotionFX/Code/Tests/MorphSkinAttachmentTests.cpp index 42c2cc2110..d69aa02fc6 100644 --- a/Gems/EMotionFX/Code/Tests/MorphSkinAttachmentTests.cpp +++ b/Gems/EMotionFX/Code/Tests/MorphSkinAttachmentTests.cpp @@ -168,8 +168,8 @@ namespace EMotionFX // The skin attachment should now receive morph values from the main actor. const Pose& attachPose = *m_attachmentActorInstance->GetTransformData()->GetCurrentPose(); ASSERT_EQ(attachPose.GetNumMorphWeights(), 4); - EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(0), 0.0f); // Once we auto register missing morphs this should be 0.5. See https://jira.agscollab.com/browse/LY-100212 - EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(1), 0.0f); // Once we auto register missing morphs this should be 0.6. See https://jira.agscollab.com/browse/LY-100212 + EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(0), 0.0f); // Once we auto register missing morphs this should be 0.5. See LY-100212 + EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(1), 0.0f); // Once we auto register missing morphs this should be 0.6. See LY-100212 EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(2), 0.1f); EXPECT_FLOAT_EQ(attachPose.GetMorphWeight(3), 0.2f); }; diff --git a/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp b/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp index b9b512da36..9fa3e17263 100644 --- a/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp @@ -77,7 +77,6 @@ namespace EMotionFX m_app.RegisterComponentDescriptor(AzFramework::TransformComponent::CreateDescriptor()); m_envPrev = gEnv; - m_env.pRenderer = &m_data.m_renderer; m_env.pSystem = &m_data.m_system; gEnv = &m_env; } diff --git a/Gems/EMotionFX/gem.json b/Gems/EMotionFX/gem.json index 022f3b3077..f116a6a2c0 100644 --- a/Gems/EMotionFX/gem.json +++ b/Gems/EMotionFX/gem.json @@ -1,5 +1,5 @@ { - "gem_name": "EmotionFX", + "gem_name": "EMotionFX", "Dependencies": [ { "Uuid": "ff06785f7145416b9d46fde39098cb0c", diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index 9b594d86f9..2f7d6c6ce7 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -95,8 +95,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) NAME ImGui.Editor GEM_MODULE NAMESPACE Gem - AUTOMOC - AUTOUIC FILES_CMAKE imgui_editor_files.cmake COMPILE_DEFINITIONS @@ -112,9 +110,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::ImGui.Static - 3rdParty::Qt::Widgets - AZ::AzToolsFramework - Legacy::Editor.Headers RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) diff --git a/Gems/ImGui/Code/Editor/ImGuiEditorWindowBus.h b/Gems/ImGui/Code/Editor/ImGuiEditorWindowBus.h deleted file mode 100644 index 1ee987a74d..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiEditorWindowBus.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImGui -{ - class ImGuiEditorWindowRequests - : 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 ImGuiEditorWindowRequestBus = AZ::EBus; -} // namespace ImGuiEditorWindow diff --git a/Gems/ImGui/Code/Editor/ImGuiEditorWindowModule.cpp b/Gems/ImGui/Code/Editor/ImGuiEditorWindowModule.cpp index f44d5cb61e..b02f470ad9 100644 --- a/Gems/ImGui/Code/Editor/ImGuiEditorWindowModule.cpp +++ b/Gems/ImGui/Code/Editor/ImGuiEditorWindowModule.cpp @@ -13,7 +13,6 @@ #include "ImGui_precompiled.h" #include "ImGuiGem.h" -#include "ImGuiEditorWindowSystemComponent.h" namespace ImGui { @@ -26,22 +25,6 @@ namespace ImGui ImGuiEditorWindowModule() : ImGuiModule() { - // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. - m_descriptors.insert(m_descriptors.end(), { - ImGuiEditorWindowSystemComponent::CreateDescriptor(), - }); - } - - /** - * Add required SystemComponents to the SystemEntity. - */ - AZ::ComponentTypeList GetRequiredSystemComponents() const override - { - AZ::ComponentTypeList requiredComponents = ImGuiModule::GetRequiredSystemComponents(); - - requiredComponents.push_back(azrtti_typeid()); - - return requiredComponents; } }; } diff --git a/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.cpp b/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.cpp deleted file mode 100644 index 07ab3b0a42..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImGui_precompiled.h" - -#include -#include -#include -#include "ImGuiEditorWindowSystemComponent.h" -#include "ImGuiMainWindow.h" -#include - -static const char* s_ImGuiQtViewPaneName = "ImGui Editor"; - -namespace ImGui -{ - void ImGuiEditorWindowSystemComponent::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0) - ; - } - } - - void ImGuiEditorWindowSystemComponent::Activate() - { - AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - ImGuiEditorWindowRequestBus::Handler::BusConnect(); - ImGuiUpdateListenerBus::Handler::BusConnect(); - } - - void ImGuiEditorWindowSystemComponent::Deactivate() - { - ImGuiUpdateListenerBus::Handler::BusDisconnect(); - ImGuiEditorWindowRequestBus::Handler::BusDisconnect(); - AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - } - - ImGuiEditorWindowSystemComponent::~ImGuiEditorWindowSystemComponent() - { - EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, UnregisterViewPane, s_ImGuiQtViewPaneName); - } - - void ImGuiEditorWindowSystemComponent::OnOpenEditorWindow() - { - EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, OpenViewPane, s_ImGuiQtViewPaneName); - } - - void ImGuiEditorWindowSystemComponent::NotifyRegisterViews() - { - } -} diff --git a/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.h b/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.h deleted file mode 100644 index 1f9d3cdc52..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiEditorWindowSystemComponent.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -#include -#include -#include "ImGuiManager.h" -#include "ImGuiBus.h" - -namespace ImGui -{ - class ImGuiEditorWindowSystemComponent - : public AZ::Component - , protected ImGuiEditorWindowRequestBus::Handler - , public ImGuiUpdateListenerBus::Handler - , protected AzToolsFramework::EditorEvents::Bus::Handler - { - public: - AZ_COMPONENT(ImGuiEditorWindowSystemComponent, "{91021F3E-B5F0-4E26-A7C9-6ED0F6CB6C5A}"); - - virtual ~ImGuiEditorWindowSystemComponent(); - - static void Reflect(AZ::ReflectContext* context); - - protected: - //////////////////////////////////////////////////////////////////////// - // ImGuiEditorWindowRequestBus interface implementation - - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Activate() override; - void Deactivate() override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // ImGuiUpdateListenerBus interface implementation - void OnOpenEditorWindow() override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // EditorEvents - void NotifyRegisterViews() override; - //////////////////////////////////////////////////////////////////////// - }; -} diff --git a/Gems/ImGui/Code/Editor/ImGuiMainWindow.cpp b/Gems/ImGui/Code/Editor/ImGuiMainWindow.cpp deleted file mode 100644 index b4774d1334..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiMainWindow.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ImGui_precompiled.h" -#include "ImGuiMainWindow.h" -#include "QtViewPaneManager.h" -#include "ImGuiViewport.h" -#include - -using namespace ImGui; - -ImGuiMainWindow::ImGuiMainWindow(QWidget* parent) - : QMainWindow(parent) - , m_ui(new Ui::ImGuiMainWindow) - , m_viewport(new ImGuiViewportWidget(this)) -{ - m_ui->setupUi(this); - - //@rky: Add the ImGuiViewport to this window - m_viewport->setFocusPolicy(Qt::StrongFocus); - m_ui->gridLayout->addWidget(m_viewport, 0, 0, 1, 1); -} - -#include diff --git a/Gems/ImGui/Code/Editor/ImGuiMainWindow.h b/Gems/ImGui/Code/Editor/ImGuiMainWindow.h deleted file mode 100644 index 659ec7b4c1..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiMainWindow.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#ifndef __IMGUI_MAINWINDOW_H__ -#define __IMGUI_MAINWINDOW_H__ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include "IEditor.h" -#include -#endif - -namespace Ui -{ - class ImGuiMainWindow; -} - -namespace ImGui -{ - class ImGuiViewportWidget; - - class ImGuiMainWindow : public QMainWindow - { - Q_OBJECT - public: - - static const GUID& GetClassID() - { - // {ECA9F41C-716E-4395-A096-5A519227F9A4} - static const GUID guid = - { 0xeca9f41c, 0x716e, 0x4395, { 0xa0, 0x96, 0x5a, 0x51, 0x92, 0x27, 0xf9, 0xa4 } }; - - return guid; - } - - explicit ImGuiMainWindow(QWidget* parent = nullptr); - - private: - QScopedPointer m_ui; - - ImGuiViewportWidget* m_viewport; - }; -} - -#endif //__IMGUI_MAINWINDOW_H__ diff --git a/Gems/ImGui/Code/Editor/ImGuiMainwindow.ui b/Gems/ImGui/Code/Editor/ImGuiMainwindow.ui deleted file mode 100644 index 7124e22c7a..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiMainwindow.ui +++ /dev/null @@ -1,33 +0,0 @@ - - - ImGuiMainWindow - - - - 0 - 0 - 1263 - 740 - - - - MainWindow - - - - - - - - 0 - 0 - 1263 - 21 - - - - - - - - diff --git a/Gems/ImGui/Code/Editor/ImGuiViewport.cpp b/Gems/ImGui/Code/Editor/ImGuiViewport.cpp deleted file mode 100644 index 7c467d7f08..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiViewport.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ -#include "ImGui_precompiled.h" - -#include "ImGuiViewport.h" -#include -#include -#include -#include -#include "ImGuiBus.h" -#include "ImGuiManager.h" -#include - -using namespace ImGui; - -ImGuiViewportWidget::ImGuiViewportWidget(QWidget* parent) - : QWidget(parent) - , m_width(0) - , m_height(0) - , m_renderContextCreated(false) - , m_creatingRenderContext(false) - , m_lastTime(0) - , m_lastFrameTime(0.f) - , m_averageFrameTime(0.f) -{ - // Setup a timer for the maximum refresh rate we want. - // Refresh is actually triggered by interaction events and by the IdleUpdate. This avoids the UI - // Editor slowing down the main editor when no UI interaction is occurring. - QObject::connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(RefreshTick())); - const int kUpdateIntervalInMillseconds = 1000 / 60; // 60 Hz - m_updateTimer.start(kUpdateIntervalInMillseconds); - - CreateRenderContext(); -} - -ImGuiViewportWidget::~ImGuiViewportWidget() -{ - DestroyRenderContext(); - ImGuiManagerBus::Broadcast(&IImGuiManager::SetEditorWindowState, - DisplayState::Hidden); -} - -bool ImGuiViewportWidget::CreateRenderContext() -{ - if (m_creatingRenderContext) - { - return false; - } - m_creatingRenderContext = true; - DestroyRenderContext(); - HWND window = (HWND)QWidget::winId(); - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - if (window && editor->GetEnv()->pRenderer && !m_renderContextCreated) - { - m_renderContextCreated = true; - - StorePreviousContext(); - editor->GetEnv()->pRenderer->CreateContext(window); - RestorePreviousContext(); - - ImGuiManagerBus::Broadcast(&IImGuiManager::SetEditorWindowState, - DisplayState::Visible); - - m_creatingRenderContext = false; - return true; - } - m_creatingRenderContext = false; - return false; -} - -void ImGuiViewportWidget::DestroyRenderContext() -{ - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - if (editor->GetEnv()->pRenderer && m_renderContextCreated) - { - HWND window = (HWND)QWidget::winId(); - if (window != editor->GetEnv()->pRenderer->GetHWND()) - { - editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - editor->GetEnv()->pRenderer->DeleteContext(window); - } - m_renderContextCreated = false; - } -} - -void ImGuiViewportWidget::StorePreviousContext() -{ - SPreviousContext previous; - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - previous.width = editor->GetEnv()->pRenderer->GetWidth(); - previous.height = editor->GetEnv()->pRenderer->GetHeight(); - previous.window = (HWND)editor->GetEnv()->pRenderer->GetCurrentContextHWND(); - previous.renderCamera = editor->GetEnv()->pRenderer->GetCamera(); - previous.systemCamera = gEnv->pSystem->GetViewCamera(); - previous.isMainViewport = editor->GetEnv()->pRenderer->IsCurrentContextMainVP(); - m_previousContexts.push(previous); -} - -void ImGuiViewportWidget::SetCurrentContext() -{ - StorePreviousContext(); - - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - - HWND window = (HWND)QWidget::winId(); - editor->GetEnv()->pRenderer->SetCurrentContext(window); - editor->GetEnv()->pRenderer->ChangeViewport(0, 0, m_width, m_height); -} - -void ImGuiViewportWidget::RestorePreviousContext() -{ - if (m_previousContexts.empty()) - { - return; - } - - SPreviousContext x = m_previousContexts.top(); - m_previousContexts.pop(); - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - editor->GetEnv()->pRenderer->SetCurrentContext(x.window); - editor->GetEnv()->pRenderer->ChangeViewport(0, 0, x.width, x.height, x.isMainViewport); - - editor->GetEnv()->pRenderer->SetCamera(x.renderCamera); - gEnv->pSystem->SetViewCamera(x.systemCamera); -} - -void ImGuiViewportWidget::Render() -{ - SetCurrentContext(); - - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - - IRenderer* renderer = editor->GetEnv()->pRenderer; - - ColorF viewportBackgroundColor(Col_Gray); - ColorF stateMessageColor(Col_Gray); - AZStd::string stateMessage = "No State"; - DisplayState visibilityState = DisplayState::Hidden; - ImGuiManagerBus::BroadcastResult(visibilityState, - &IImGuiManager::GetEditorWindowState); - switch (visibilityState) - { - case ImGui::DisplayState::Hidden: - stateMessage = "Invisible"; - break; - case ImGui::DisplayState::Visible: - stateMessage = "ImGui Window"; - stateMessageColor = Col_SteelBlue; - viewportBackgroundColor = Col_SkyBlue; - break; - case ImGui::DisplayState::VisibleNoMouse: - stateMessage = "Game Focus"; - stateMessageColor = Col_Gray; - viewportBackgroundColor = Col_LightGray; - break; - } - - renderer->ClearTargetsImmediately(FRT_CLEAR | FRT_CLEAR_IMMEDIATE, viewportBackgroundColor); - renderer->ResetToDefault(); - - renderer->Draw2dLabel( - 12.0f, m_height - 50.f, 1.25f, Col_White, false, "FPS: %.2f", 1.0f / m_averageFrameTime); - renderer->Draw2dLabel( - 12.0f, m_height - 30.f, 2.f, stateMessageColor, false, "State: %s", stateMessage.c_str()); - - if (ImDrawData* drawData = ImGui::GetDrawData()) - { - // Configure renderer for 2d imgui rendering - renderer->SetCullMode(R_CULL_DISABLE); - TransformationMatrices backupSceneMatrices; - renderer->Set2DMode(renderer->GetWidth(), renderer->GetHeight(), backupSceneMatrices); - renderer->SetColorOp(eCO_REPLACE, eCO_MODULATE, eCA_Diffuse, DEF_TEXARG0); - renderer->SetSrgbWrite(false); - renderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); - - // Expand vertex buffer if necessary - m_vertBuffer.reserve(drawData->TotalVtxCount); - if (m_vertBuffer.size() < drawData->TotalVtxCount) - { - m_vertBuffer.insert(m_vertBuffer.end(), - drawData->TotalVtxCount - m_vertBuffer.size(), - SVF_P3F_C4B_T2F()); - } - - // Expand index buffer if necessary - m_idxBuffer.reserve(drawData->TotalIdxCount); - if (m_idxBuffer.size() < drawData->TotalIdxCount) - { - m_idxBuffer.insert(m_idxBuffer.end(), drawData->TotalIdxCount - m_idxBuffer.size(), 0); - } - - // Process each draw command list individually - for (int n = 0; n < drawData->CmdListsCount; n++) - { - const ImDrawList* cmd_list = drawData->CmdLists[n]; - - // Cache max vert count for easy access - int numVerts = cmd_list->VtxBuffer.Size; - - // Copy command list verts into buffer - for (int i = 0; i < numVerts; ++i) - { - const ImDrawVert& imguiVert = cmd_list->VtxBuffer[i]; - SVF_P3F_C4B_T2F& vert = m_vertBuffer[i]; - - vert.xyz = Vec3(imguiVert.pos.x, imguiVert.pos.y, 0.0f); - // Convert color from RGBA to ARGB - vert.color.dcolor = (imguiVert.col & 0xFF00FF00) - | ((imguiVert.col & 0xFF0000) >> 16) - | ((imguiVert.col & 0xFF) << 16); - vert.st = Vec2(imguiVert.uv.x, imguiVert.uv.y); - } - - // Copy command list indices into buffer - for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) - { - m_idxBuffer[i] = uint16(cmd_list->IdxBuffer[i]); - } - - // Use offset pointer to step along rendering operation - uint16* idxBufferDataOffset = m_idxBuffer.data(); - - // Process each draw command individually - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - - // Defer to user rendering callback, if appropriate - if (pcmd->UserCallback) - { - pcmd->UserCallback(cmd_list, pcmd); - } - // Otherwise render our buffers - else - { - int textureId = ((ITexture*)pcmd->TextureId)->GetTextureID(); - renderer->SetTexture(textureId); - renderer->SetScissor((int)pcmd->ClipRect.x, - (int)(pcmd->ClipRect.y), - (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), - (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); - renderer->DrawDynVB(m_vertBuffer.data(), - idxBufferDataOffset, - numVerts, - pcmd->ElemCount, - prtTriangleList); - } - - // Update offset pointer into command list's index buffer - idxBufferDataOffset += pcmd->ElemCount; - } - } - - // Reset scissor usage on renderer - renderer->SetScissor(); - - // Clean up renderer settings - renderer->Unset2DMode(backupSceneMatrices); - } - - RestorePreviousContext(); -} - -void ImGuiViewportWidget::resizeEvent(QResizeEvent* ev) -{ - QWidget::resizeEvent(ev); - - int cx = ev->size().width(); - int cy = ev->size().height(); - if (cx == 0 || cy == 0) - { - return; - } - - m_width = cx; - m_height = cy; - - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - editor->GetEnv()->pSystem->GetISystemEventDispatcher()->OnSystemEvent( - ESYSTEM_EVENT_RESIZE, cx, cy); - - RefreshTick(); -} - -void ImGuiViewportWidget::RefreshTick() -{ - IEditor* editor = nullptr; - EBUS_EVENT_RESULT(editor, AzToolsFramework::EditorRequests::Bus, GetEditor); - int64 time = editor->GetEnv()->pSystem->GetITimer()->GetAsyncTime().GetMilliSecondsAsInt64(); - if (m_lastTime == 0) - { - m_lastTime = time; - } - m_lastFrameTime = (time - m_lastTime) * 0.001f; - m_lastTime = time; - if (m_averageFrameTime == 0.0f) - { - m_averageFrameTime = m_lastFrameTime; - } - else - { - m_averageFrameTime = 0.01f * m_lastFrameTime + 0.99f * m_averageFrameTime; - } - - Render(); - - m_updateTimer.start(); -} - -bool ImGuiViewportWidget::event(QEvent* ev) -{ - bool result = QWidget::event(ev); - - if (ev->type() == QEvent::WinIdChange) - { - CreateRenderContext(); - } - - return result; -} - -#include diff --git a/Gems/ImGui/Code/Editor/ImGuiViewport.h b/Gems/ImGui/Code/Editor/ImGuiViewport.h deleted file mode 100644 index 2f7c475395..0000000000 --- a/Gems/ImGui/Code/Editor/ImGuiViewport.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#pragma once -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#include -#include -#include -#endif - -namespace ImGui -{ - class ImGuiViewportWidget : public QWidget - { - Q_OBJECT - public: - ImGuiViewportWidget(QWidget* parent); - ~ImGuiViewportWidget(); - - void Render(); - - private slots: - void RefreshTick(); - - private: - struct SPreviousContext - { - int width; - int height; - HWND window; - CCamera renderCamera; - CCamera systemCamera; - bool isMainViewport; - }; - - bool CreateRenderContext(); - void DestroyRenderContext(); - void StorePreviousContext(); - void SetCurrentContext(); - void RestorePreviousContext(); - - void resizeEvent(QResizeEvent* ev) override; - bool event(QEvent* ev) override; - - AZStd::stack m_previousContexts; - unsigned int m_width; - unsigned int m_height; - bool m_renderContextCreated; - bool m_creatingRenderContext; - int64 m_lastTime; - float m_lastFrameTime; - float m_averageFrameTime; - AZStd::vector m_vertBuffer; - AZStd::vector m_idxBuffer; - QTimer m_updateTimer; - }; -} diff --git a/Gems/ImGui/Code/imgui_editor_files.cmake b/Gems/ImGui/Code/imgui_editor_files.cmake index 75a98524ae..842fde7965 100644 --- a/Gems/ImGui/Code/imgui_editor_files.cmake +++ b/Gems/ImGui/Code/imgui_editor_files.cmake @@ -10,15 +10,7 @@ # set(FILES - Editor/ImGuiEditorWindowBus.h Editor/ImGuiEditorWindowModule.cpp - Editor/ImGuiEditorWindowSystemComponent.cpp - Editor/ImGuiEditorWindowSystemComponent.h - Editor/ImGuiMainWindow.h - Editor/ImGuiMainWindow.cpp - Editor/ImGuiMainwindow.ui - Editor/ImGuiViewport.h - Editor/ImGuiViewport.cpp Source/ImGuiGem.h Source/ImGuiGem.cpp ) diff --git a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp index 2555d1a6af..c2db0da54a 100644 --- a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp +++ b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp @@ -7118,7 +7118,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); - IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + + // [GFX TODO] Commented this line until Atom ImGuiPass is refactored (ATOM-15495). + // IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); IM_UNUSED(key_mod_flags); // Recover from errors diff --git a/Gems/ImageProcessing/AssetProcessorGemConfig.setreg b/Gems/ImageProcessing/AssetProcessorGemConfig.setreg deleted file mode 100644 index 17d9887fe8..0000000000 --- a/Gems/ImageProcessing/AssetProcessorGemConfig.setreg +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Amazon": { - "AssetProcessor": { - "Settings": {} - } - } -} diff --git a/Gems/ImageProcessing/Assets/Editor/Backward.png b/Gems/ImageProcessing/Assets/Editor/Backward.png deleted file mode 100644 index 82b3eafbd9..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/Backward.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a1623477f4e2e5ef0440ecfc0c08e775d9b5f12d8ebc6b434e8212bf3445bcd -size 224 diff --git a/Gems/ImageProcessing/Assets/Editor/Forward.png b/Gems/ImageProcessing/Assets/Editor/Forward.png deleted file mode 100644 index a7a29a4c25..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/Forward.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31b247223c1116d4fc014189a9d8d86d4458b792c1120442673631136fd89520 -size 222 diff --git a/Gems/ImageProcessing/Assets/Editor/Resources.qrc b/Gems/ImageProcessing/Assets/Editor/Resources.qrc deleted file mode 100644 index c309d19053..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/Resources.qrc +++ /dev/null @@ -1,11 +0,0 @@ - - - refresh-active.png - warning.png - refresh.png - info.png - Backward.png - Forward.png - reset.png - - diff --git a/Gems/ImageProcessing/Assets/Editor/info.png b/Gems/ImageProcessing/Assets/Editor/info.png deleted file mode 100644 index 002cf9c775..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/info.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3fec3caae92b9c9290c4157b3aeca29dcb366edd12719355e1d93dfb9d80cfed -size 825 diff --git a/Gems/ImageProcessing/Assets/Editor/refresh-active.png b/Gems/ImageProcessing/Assets/Editor/refresh-active.png deleted file mode 100644 index 33bc1c592a..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/refresh-active.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d29af2b69b74815c88352f85a7131384482e4f2d26ecf36581b46dede542fccb -size 2973 diff --git a/Gems/ImageProcessing/Assets/Editor/refresh.png b/Gems/ImageProcessing/Assets/Editor/refresh.png deleted file mode 100644 index fc9ef09987..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/refresh.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36591b457ee3519b16405d281674fcdd18645e3570bfc960a22b8f142ee99a14 -size 436 diff --git a/Gems/ImageProcessing/Assets/Editor/reset.png b/Gems/ImageProcessing/Assets/Editor/reset.png deleted file mode 100644 index ed9c2f016d..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/reset.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0362da38d3804e2911130d138be4fd73040d66c8ac7d1b5f9f60c70037e8ca93 -size 1292 diff --git a/Gems/ImageProcessing/Assets/Editor/warning.png b/Gems/ImageProcessing/Assets/Editor/warning.png deleted file mode 100644 index 6020245f86..0000000000 --- a/Gems/ImageProcessing/Assets/Editor/warning.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf5e987ea92164dcaa6deb88989aaac962bc092f5745274017f71224f48dbf7a -size 651 diff --git a/Gems/ImageProcessing/CMakeLists.txt b/Gems/ImageProcessing/CMakeLists.txt deleted file mode 100644 index 20a680bce9..0000000000 --- a/Gems/ImageProcessing/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -add_subdirectory(Code) diff --git a/Gems/ImageProcessing/Code/CMakeLists.txt b/Gems/ImageProcessing/Code/CMakeLists.txt deleted file mode 100644 index a5cb6f6cb9..0000000000 --- a/Gems/ImageProcessing/Code/CMakeLists.txt +++ /dev/null @@ -1,147 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -ly_add_target( - NAME ImageProcessing.Headers HEADERONLY - NAMESPACE Gem - FILES_CMAKE - imageprocessing_headers_files.cmake - INCLUDE_DIRECTORIES - INTERFACE - Include -) - -if (NOT PAL_TRAIT_BUILD_HOST_TOOLS) - return() -endif() - -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) - -set(platform_tools_files) -set(pal_tools_include_files) -set(pal_tools_dirs) -foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) - string(TOLOWER ${enabled_platform} enabled_platform_lowercase) - ly_get_list_relative_pal_filename(pal_tools_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${enabled_platform}) - list(APPEND platform_tools_files ${pal_tools_dir}/pal_tools_${enabled_platform_lowercase}.cmake) - list(APPEND pal_tools_include_files ${pal_tools_dir}/pal_tools_${enabled_platform_lowercase}_files.cmake) - list(APPEND pal_tools_dirs ${pal_tools_dir}) -endforeach() - -ly_add_target( - NAME ImageProcessing.Static STATIC - NAMESPACE Gem - AUTOMOC - AUTOUIC - FILES_CMAKE - imageprocessing_static_files.cmake - ${pal_tools_include_files} - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake - PLATFORM_INCLUDE_FILES - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake - ${platform_tools_files} - INCLUDE_DIRECTORIES - PRIVATE - . - Source - ../External - ${pal_dir} - ${pal_tools_dirs} - PUBLIC - Include - BUILD_DEPENDENCIES - PRIVATE - 3rdParty::Qt::Core - 3rdParty::Qt::Widgets - 3rdParty::etc2comp - 3rdParty::PVRTexTool - 3rdParty::squish-ccr - 3rdParty::zlib - 3rdParty::tiff - Legacy::CryCommon - AZ::AzCore - AZ::AssetBuilderSDK - Gem::TextureAtlas -) -ly_add_source_properties( - SOURCES - Source/BuilderSettings/BuilderSettingManager.cpp - Source/Processing/ImageConvert.cpp - PROPERTY COMPILE_DEFINITIONS - VALUES ${LY_PAL_TOOLS_DEFINES} -) - -ly_add_target( - NAME ImageProcessing.Editor GEM_MODULE - - NAMESPACE Gem - AUTOMOC - AUTORCC - FILES_CMAKE - imageprocessing_files.cmake - PLATFORM_INCLUDE_FILES - ${platform_tools_files} - INCLUDE_DIRECTORIES - PRIVATE - . - Source - ${pal_dir} - PUBLIC - Include - BUILD_DEPENDENCIES - PRIVATE - 3rdParty::Qt::Widgets - 3rdParty::PVRTexTool - 3rdParty::squish-ccr - Legacy::CryCommon - AZ::AzCore - AZ::AzToolsFramework - AZ::AssetBuilderSDK - Gem::ImageProcessing.Static - Gem::TextureAtlas - RUNTIME_DEPENDENCIES - 3rdParty::ASTCEncoder - Gem::TextureAtlas -) - -if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - ly_add_target( - NAME ImageProcessing.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} - NAMESPACE Gem - FILES_CMAKE - imageprocessing_tests_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Tests - . - Source - ${pal_dir} - BUILD_DEPENDENCIES - PRIVATE - AZ::AzTest - 3rdParty::Qt::Widgets - Legacy::CryCommon - AZ::AssetBuilderSDK - Gem::ImageProcessing.Static - Gem::ImageProcessing.Editor - Gem::TextureAtlas - ) - ly_add_googletest( - NAME Gem::ImageProcessing.Tests - ) - - ly_add_source_properties( - SOURCES Tests/ImageProcessing_Test.cpp - PROPERTY COMPILE_DEFINITIONS - VALUES ${LY_PAL_TOOLS_DEFINES} - ) - -endif() diff --git a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageObject.h b/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageObject.h deleted file mode 100644 index baa6613daf..0000000000 --- a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageObject.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace IO - { - class SystemFileStream; - } -} - -namespace ImageProcessing -{ - class IImageObject; - class TextureSettings; - typedef AZStd::shared_ptr IImageObjectPtr; - - enum class EAlphaContent - { - eAlphaContent_Indeterminate, // the format may have alpha, but can't be calculated - eAlphaContent_Absent, // the format has no alpha - eAlphaContent_OnlyWhite, // alpha contains just white - eAlphaContent_OnlyBlack, // alpha contains just black - eAlphaContent_OnlyBlackAndWhite, // alpha contains just black and white - eAlphaContent_Greyscale // alpha contains grey tones - }; - - //interface for image object. The image object may have mipmaps. - class IImageObject - { - public: - //static functions - static IImageObject* CreateImage(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat); - - virtual ~IImageObject() {}; - public: - //creating new image object outof this image object - virtual IImageObject* Clone() const = 0; - // allocate an empty image object with requested format and same properties with current image - virtual IImageObject* AllocateImage(EPixelFormat pixelFormat) const = 0; - virtual IImageObject* AllocateImage() const = 0; - - //get pixel format - virtual EPixelFormat GetPixelFormat() const = 0; - - virtual AZ::u32 GetPixelCount(AZ::u32 mip) const = 0; - virtual AZ::u32 GetWidth(AZ::u32 mip) const = 0; - virtual AZ::u32 GetHeight(AZ::u32 mip) const = 0; - virtual bool IsCubemap() const = 0; - virtual AZ::u32 GetMipCount() const = 0; - - //get pixel data buffer - virtual void GetImagePointer(AZ::u32 mip, AZ::u8*& pMem, AZ::u32& pitch) const = 0; - virtual AZ::u32 GetMipBufSize(AZ::u32 mip) const = 0; - virtual void SetMipData(AZ::u32 mip, AZ::u8* mipBuf, AZ::u32 bufSize, AZ::u32 pitch) = 0; - - //get/set image flags - virtual AZ::u32 GetImageFlags() const = 0; - virtual void SetImageFlags(AZ::u32 imageFlags) = 0; - virtual void AddImageFlags(AZ::u32 imageFlags) = 0; - virtual void RemoveImageFlags(AZ::u32 imageFlags) = 0; - virtual bool HasImageFlags(AZ::u32 imageFlags) const = 0; - - // image data operations and calculation - // Calculates "(pixel.rgba * scale) + bias" - virtual void ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias) = 0; - // Calculates "clamp(pixel.rgba, min, max)" - virtual void ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max) = 0; - - //transfer alpha coverage from source image - virtual void TransferAlphaCoverage(const TextureSettings* textureSetting, const IImageObjectPtr srcImg) = 0; - // Routines to measure and manipulate alpha coverage - virtual float ComputeAlphaCoverageScaleFactor(AZ::u32 mip, float fDesiredCoverage, float fAlphaRef) const = 0; - virtual float ComputeAlphaCoverage(AZ::u32 mip, float fAlphaRef) const = 0; - - //helper functions - //compare whether two images are same. return true if they are same. - virtual bool CompareImage(const IImageObjectPtr otherImage) const = 0; - - // Writes this image to file used for runtime, overwrites any existing file. - // It may write alpha image as attached image into the same file - // outFilePaths will save filenames finally saved to since the image might be split and saved to multiple files - virtual bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const = 0; - virtual bool SaveImage(AZ::IO::SystemFileStream& out) const = 0; - virtual bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const = 0; - - //get total image data size in memory of all mipmaps. Not includs header and flags. - virtual AZ::u32 GetTextureMemory() const = 0; - - //identify content of the alpha channel - virtual EAlphaContent GetAlphaContent() const = 0; - - //normalize rgb channel for specified mips - virtual void NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount) = 0; - - // use when you convert an image to another one - virtual void CopyPropertiesFrom(const IImageObjectPtr src) = 0; - - //swizzle data for source channels to dest channels - virtual void Swizzle(const char channels[4]) = 0; - - //get/set properties of the image object - virtual void GetColorRange(AZ::Color& minColor, AZ::Color& maxColor) const = 0; - virtual void SetColorRange(const AZ::Color& minColor, const AZ::Color& maxColor) = 0; - virtual AZ::u32 GetNumPersistentMips() const = 0; - virtual void SetNumPersistentMips(AZ::u32 nMips) = 0; - virtual float GetAverageBrightness() const = 0; - virtual void SetAverageBrightness(float avgBrightness) = 0; - - // Derive new roughness from normal variance to preserve the bumpiness of normal map mips and to reduce specular aliasing. - // The derived roughness is combined with the artist authored roughness stored in the alpha channel of the normal map. - // The algorithm is based on the Frequency Domain Normal Mapping implementation presented by Neubelt and Pettineo at Siggraph 2013. - virtual void GlossFromNormals(bool hasAuthoredGloss) = 0; - - //convert gloss map from legacy distribution to new one. New World is still using legacy gloss map. - virtual void ConvertLegacyGloss() = 0; - - //clear image with color - virtual void ClearColor(float r, float g, float b, float a) = 0; - - virtual bool HasPowerOfTwoSizes() const = 0; - }; - - //loading function to load output dds file to a IImageObject - IImageObject* LoadImageFromDdsFile(const AZStd::string& filename); - IImageObject* LoadImageFromDdsFile(AZ::IO::SystemFileStream& fileLoadStream); - IImageObject* LoadAttachedImageFromDdsFile(const AZStd::string& filename, IImageObjectPtr originImage); - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingBus.h b/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingBus.h deleted file mode 100644 index 8b127b3f6e..0000000000 --- a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingBus.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include - -namespace ImageProcessing -{ - class ImageProcessingRequests - : public AZ::EBusTraits - { - public: - ////////////////////////////////////////////////////////////////////////// - // EBusTraits overrides - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - ////////////////////////////////////////////////////////////////////////// - - // Loads an image from a source file path - virtual IImageObjectPtr LoadImage(const AZStd::string& filePath) = 0; - - // Loads an image from a source file path and converts it to a format suitable for previewing in tools - virtual IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) = 0; - }; - using ImageProcessingRequestBus = AZ::EBus; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingEditorBus.h b/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingEditorBus.h deleted file mode 100644 index eae1fdeb6d..0000000000 --- a/Gems/ImageProcessing/Code/Include/ImageProcessing/ImageProcessingEditorBus.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include - -class QString; - -namespace ImageProcessingEditor -{ - class ImageProcessingEditorRequests - : public AZ::EBusTraits - { - public: - ////////////////////////////////////////////////////////////////////////// - // EBusTraits overrides - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - ///////////////////////////////////////////////////////////////////////// - - //! Open single texture file - virtual void OpenSourceTextureFile(const AZ::Uuid& textureSourceID) = 0; - }; - - using ImageProcessingEditorRequestBus = AZ::EBus; -}//namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Include/ImageProcessing/PixelFormats.h b/Gems/ImageProcessing/Code/Include/ImageProcessing/PixelFormats.h deleted file mode 100644 index 2ceb889ac9..0000000000 --- a/Gems/ImageProcessing/Code/Include/ImageProcessing/PixelFormats.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -namespace ImageProcessing -{ - enum EPixelFormat : int - { - //unsigned formats - ePixelFormat_R8G8B8A8 = 0, - ePixelFormat_R8G8B8X8, - ePixelFormat_R8G8, - ePixelFormat_R8, - ePixelFormat_A8, - ePixelFormat_R16G16B16A16, - ePixelFormat_R16G16, - ePixelFormat_R16, - - //Custom FourCC Formats - // Data in these FourCC formats is custom compressed data and only decodable by certain hardware. - //ASTC formats supported by ios devices with A8 processor. Also supported by Android Extension Pack. - ePixelFormat_ASTC_4x4, - ePixelFormat_ASTC_5x4, - ePixelFormat_ASTC_5x5, - ePixelFormat_ASTC_6x5, - ePixelFormat_ASTC_6x6, - ePixelFormat_ASTC_8x5, - ePixelFormat_ASTC_8x6, - ePixelFormat_ASTC_8x8, - ePixelFormat_ASTC_10x5, - ePixelFormat_ASTC_10x6, - ePixelFormat_ASTC_10x8, - ePixelFormat_ASTC_10x10, - ePixelFormat_ASTC_12x10, - ePixelFormat_ASTC_12x12, - //Formats supported by PowerVR GPU. Mainly for ios devices. - ePixelFormat_PVRTC2, //2bpp - ePixelFormat_PVRTC4, //4bpp - //formats for opengl and opengles 3.0 (android devices) - ePixelFormat_EAC_R11, //one channel unsigned data - ePixelFormat_EAC_RG11, //two channel unsigned data - ePixelFormat_ETC2, //Compresses RGB888 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit - ePixelFormat_ETC2a, //Compresses RGBA8888 data with full alpha support - - // Standardized Compressed DXGI Formats (DX10+) - // Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API. - ePixelFormat_BC1, // RGB without alpha, 0.5 byte/px - ePixelFormat_BC1a, // RGB with 1 bit of alpha, 0.5 byte/px. - ePixelFormat_BC3, // RGBA 1 byte/px, color maps with full alpha. - ePixelFormat_BC3t, // BC3 with alpha weighted color - ePixelFormat_BC4, // One color channel, 0.5 byte/px, unsigned - ePixelFormat_BC4s, // BC4, signed - ePixelFormat_BC5, // Two color channels, 1 byte/px, unsigned. Usually use for tangent-space normal maps - ePixelFormat_BC5s, // BC5, signed - ePixelFormat_BC6UH, // RGB, floating-point. Used for HDR images. Decompress to RGB in half floating point - ePixelFormat_BC7, // RGB or RGBA. 1 byte/px. Three color channels (4 to 7 bits per channel) with 0 to 8 bits of alpha - ePixelFormat_BC7t, // BC& with alpha weighted color - - // Float formats - // Data in a Float format is floating point data. - ePixelFormat_R9G9B9E5, - ePixelFormat_R32G32B32A32F, - ePixelFormat_R32G32F, - ePixelFormat_R32F, - ePixelFormat_R16G16B16A16F, - ePixelFormat_R16G16F, - ePixelFormat_R16F, - - //legacy format. Only used to load old converted dds files. - ePixelFormat_B8G8R8A8, //32bits rgba format - - ePixelFormat_R32, - - ePixelFormat_Count, - ePixelFormat_Unknown = ePixelFormat_Count - }; - - inline bool IsASTCFormat(EPixelFormat fmt) - { - return fmt == ePixelFormat_ASTC_4x4 || fmt == ePixelFormat_ASTC_5x4 || fmt == ePixelFormat_ASTC_5x5 || - fmt == ePixelFormat_ASTC_6x5 || fmt == ePixelFormat_ASTC_6x6 || fmt == ePixelFormat_ASTC_8x5 || - fmt == ePixelFormat_ASTC_8x6 || fmt == ePixelFormat_ASTC_8x8 || fmt == ePixelFormat_ASTC_10x5 || - fmt == ePixelFormat_ASTC_10x6 || fmt == ePixelFormat_ASTC_10x8 || fmt == ePixelFormat_ASTC_10x10 || - fmt == ePixelFormat_ASTC_12x10 || fmt == ePixelFormat_ASTC_12x12; - } - - inline bool IsETCFormat(EPixelFormat fmt) - { - return fmt == ePixelFormat_ETC2 || fmt == ePixelFormat_ETC2a || fmt == ePixelFormat_EAC_R11 || - fmt == ePixelFormat_EAC_RG11; - } - - inline bool IsPVRTCFormat(EPixelFormat fmt) - { - return fmt == ePixelFormat_PVRTC2 || fmt == ePixelFormat_PVRTC4; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.cpp b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.cpp deleted file mode 100644 index e8d4948cc9..0000000000 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include "AtlasBuilderComponent.h" - -#include - -namespace TextureAtlasBuilder -{ - // AZ Components should only initialize their members to null and empty in constructor - // Allocation of data should occur in Init(), once we can guarantee reflection and registration of types - AtlasBuilderComponent::AtlasBuilderComponent() - { - } - - // Handle deallocation of your memory allocated in Init() - AtlasBuilderComponent::~AtlasBuilderComponent() - { - } - - // Init is where you'll actually allocate memory or create objects - // This ensures that any dependency components will have been been created and serialized - void AtlasBuilderComponent::Init() - { - } - - // Activate is where you'd perform registration with other objects and systems. - // All builder classes owned by this component should be registered here - // Any EBuses for the builder classes should also be connected at this point - void AtlasBuilderComponent::Activate() - { - AssetBuilderSDK::AssetBuilderDesc builderDescriptor; - builderDescriptor.m_name = "Atlas Worker Builder"; - builderDescriptor.m_version = 1; - builderDescriptor.m_patterns.emplace_back(AssetBuilderSDK::AssetBuilderPattern("*.texatlas", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - builderDescriptor.m_busId = azrtti_typeid(); - builderDescriptor.m_createJobFunction = AZStd::bind(&AtlasBuilderWorker::CreateJobs, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_processJobFunction = AZStd::bind(&AtlasBuilderWorker::ProcessJob, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - - m_atlasBuilder.BusConnect(builderDescriptor.m_busId); - - AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); - } - - // Disconnects from any EBuses we connected to in Activate() - // Unregisters from objects and systems we register with in Activate() - void AtlasBuilderComponent::Deactivate() - { - m_atlasBuilder.BusDisconnect(); - - // We don't need to unregister the builder - the AP will handle this for us, because it is managing the lifecycle of this component - } - - // Reflect the input and output formats for the serializer - void AtlasBuilderComponent::Reflect(AZ::ReflectContext* context) - { - // components also get Reflect called automatically - // this is your opportunity to perform static reflection or type registration of any types you want the serializer to know about - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })) - ; - } - - AtlasBuilderInput::Reflect(context); - } - - void AtlasBuilderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d)); - } - - void AtlasBuilderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d)); - } - - void AtlasBuilderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - AZ_UNUSED(required); - } - - void AtlasBuilderComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) - { - AZ_UNUSED(dependent); - } -} diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.h b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.h deleted file mode 100644 index eb8b85dfcf..0000000000 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderComponent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#pragma once - -#include -#include -#include "AtlasBuilderWorker.h" - -namespace TextureAtlasBuilder -{ - class AtlasBuilderComponent : public AZ::Component - { - public: - AZ_COMPONENT(AtlasBuilderComponent, "{F49987FB-3375-4417-AB83-97B44C78B335}"); - - AtlasBuilderComponent(); - ~AtlasBuilderComponent() override; - - void Init() override; - void Activate() override; - void Deactivate() override; - - //! Reflect formats for input and output - 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); - - private: - AtlasBuilderWorker m_atlasBuilder; - }; -} // namespace TextureAtlasBuilder diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp deleted file mode 100644 index 95cc9b851f..0000000000 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp +++ /dev/null @@ -1,1494 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include "AtlasBuilderWorker.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace TextureAtlasBuilder -{ - //! Counts leading zeros - uint32 CountLeadingZeros32(uint32 x) - { - return x == 0 ? 32 : az_clz_u32(x); - } - - //! Integer log2 - uint32 IntegerLog2(uint32 x) - { - return 31 - CountLeadingZeros32(x); - } - - bool IsFolderPath(const AZStd::string& path) - { - bool hasExtension = AzFramework::StringFunc::Path::HasExtension(path.c_str()); - return !hasExtension; - } - - bool HasTrailingSlash(const AZStd::string& path) - { - size_t pathLength = path.size(); - return (pathLength > 0 && (path.at(pathLength - 1) == '/' || path.at(pathLength - 1) == '\\')); - } - - bool ResolveRelativePath(const AZStd::string& relativePath, const AZStd::string& watchDirectory, AZStd::string& resolvedFullPathOut) - { - // Get full path by appending the relative path to the watch directory - AZ::IO::FixedMaxPath resolvedPath; - AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(resolvedPath, AZ::IO::PathView{relativePath}); - - resolvedPath = (AZ::IO::FixedMaxPath{watchDirectory} / resolvedPath).LexicallyNormal(); - resolvedFullPathOut = resolvedPath.String(); - - return true; - } - - bool GetAbsoluteSourcePathFromRelativePath(const AZStd::string& relativeSourcePath, AZStd::string& absoluteSourcePathOut) - { - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, relativeSourcePath.c_str(), info, watchFolder); - if (result) - { - absoluteSourcePathOut = AZStd::string::format("%s/%s", watchFolder.c_str(), info.m_relativePath.c_str()); - - // Normalize path - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, absoluteSourcePathOut); - } - return result; - } - - const ImageProcessing::PresetSettings* GetImageProcessPresetSettings(const AZStd::string& presetName, const AZStd::string& platformIdentifier) - { - // Get the specified presetId - AZ::Uuid presetId = ImageProcessing::BuilderSettingManager::Instance()->GetPresetIdFromName(presetName); - if (presetId.IsNull()) - { - AZ_Error("Texture Editor", false, "Texture Preset %s has no associated UUID.", presetName.c_str()); - return nullptr; - } - - // Get the preset settings for the platform this job is building for - const ImageProcessing::PresetSettings* presetSettings = ImageProcessing::BuilderSettingManager::Instance()->GetPreset( - presetId, platformIdentifier); - - return presetSettings; - } - - // Reflect the input parameters - void AtlasBuilderInput::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(1) - ->Field("Force Square", &AtlasBuilderInput::m_forceSquare) - ->Field("Force Power of Two", &AtlasBuilderInput::m_forcePowerOf2) - ->Field("Include White Texture", &AtlasBuilderInput::m_includeWhiteTexture) - ->Field("Maximum Dimension", &AtlasBuilderInput::m_maxDimension) - ->Field("Padding", &AtlasBuilderInput::m_padding) - ->Field("UnusedColor", &AtlasBuilderInput::m_unusedColor) - ->Field("PresetName", &AtlasBuilderInput::m_presetName) - ->Field("Textures to Add", &AtlasBuilderInput::m_filePaths); - } - } - - // Supports a custom parser format - AtlasBuilderInput AtlasBuilderInput::ReadFromFile(const AZStd::string& path, const AZStd::string& directory, bool& valid) - { - // Open the file - AZ::IO::FileIOBase* input = AZ::IO::FileIOBase::GetInstance(); - AZ::IO::HandleType handle; - input->Open(path.c_str(), AZ::IO::OpenMode::ModeRead, handle); - - // Read the file - AZ::u64 size; - input->Size(handle, size); - char* buffer = new char[size + 1]; - input->Read(handle, buffer, size); - buffer[size] = 0; - - // Close the file - input->Close(handle); - - // Prepare the output - AtlasBuilderInput data; - - // Parse the input into lines - AZStd::vector lines; - AzFramework::StringFunc::Tokenize(buffer, lines, "\n\t"); - delete[] buffer; - - // Parse the individual lines - for (auto line : lines) - { - line = AzFramework::StringFunc::TrimWhiteSpace(line, true, true); - // Check for comments and empty lines - if ((line.length() >= 2 && line[0] == '/' && line[1] == '/') || line.length() < 1) - { - continue; - } - else if (line.find('=') != -1) - { - AZStd::vector args; - AzFramework::StringFunc::Tokenize(line.c_str(), args, '=', true, true); - - if (args.size() > 2) - { - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to parse line: Excessive '=' symbols were found: \"%s\"", line.c_str()).c_str()); - valid = false; - } - - // Trim whitespace - args[0] = AzFramework::StringFunc::TrimWhiteSpace(args[0], true, true); - args[1] = AzFramework::StringFunc::TrimWhiteSpace(args[1], true, true); - - // No case sensitivity for property names - AZStd::to_lower(args[0].begin(), args[0].end()); - - // Keep track of if the value is rejected - bool accepted = false; - - if (args[0] == "square") - { - accepted = AzFramework::StringFunc::LooksLikeBool(args[1].c_str()); - if (accepted) - { - data.m_forceSquare = AzFramework::StringFunc::ToBool(args[1].c_str()); - } - } - else if (args[0] == "poweroftwo") - { - accepted = AzFramework::StringFunc::LooksLikeBool(args[1].c_str()); - if (accepted) - { - data.m_forcePowerOf2 = AzFramework::StringFunc::ToBool(args[1].c_str()); - } - } - else if (args[0] == "whitetexture") - { - accepted = AzFramework::StringFunc::LooksLikeBool(args[1].c_str()); - if (accepted) - { - data.m_includeWhiteTexture = AzFramework::StringFunc::ToBool(args[1].c_str()); - } - } - else if (args[0] == "maxdimension") - { - accepted = AzFramework::StringFunc::LooksLikeInt(args[1].c_str()); - if (accepted) - { - data.m_maxDimension = AzFramework::StringFunc::ToInt(args[1].c_str()); - } - } - else if (args[0] == "padding") - { - accepted = AzFramework::StringFunc::LooksLikeInt(args[1].c_str()); - if (accepted) - { - data.m_padding = AzFramework::StringFunc::ToInt(args[1].c_str()); - } - } - else if (args[0] == "unusedcolor") - { - accepted = args[1].at(0) == '#' && args[1].length() == 9; - if (accepted) - { - AZStd::string color = AZStd::string::format("%s%s%s%s", args[1].substr(7).c_str(), args[1].substr(5, 2).c_str(), - args[1].substr(3, 2).c_str(), args[1].substr(1, 2).c_str()); - data.m_unusedColor.FromU32(AZStd::stoul(color, nullptr, 16)); - } - } - else if (args[0] == "presetname") - { - accepted = true; - data.m_presetName = args[1]; - } - else - { - // Supress accepted error because this error superceeds it - accepted = true; - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to parse line: Unrecognized property: \"%s\"", args[0].c_str()).c_str()); - } - - // If the property is recognized but the value is rejected, fail the job - if (!accepted) - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to parse line: Invalid value assigned to property: Property: \"%s\" Value: \"%s\"", args[0].c_str(), args[1].c_str()).c_str()); - } - } - else if ((line[0] == '-')) - { - // Remove image files - AZStd::string remove = line.substr(1); - remove = AzFramework::StringFunc::TrimWhiteSpace(remove, true, true); - if (remove.find('*') != -1) - { - AZStd::string resolvedAbsolutePath; - bool resolved = ResolveRelativePath(remove, directory, resolvedAbsolutePath); - if (resolved) - { - RemoveFilesUsingWildCard(data.m_filePaths, resolvedAbsolutePath); - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to resolve relative path: %s", remove.c_str()).c_str()); - } - } - else if (IsFolderPath(remove)) - { - AZStd::string resolvedAbsolutePath; - bool resolved = ResolveRelativePath(remove, directory, resolvedAbsolutePath); - if (resolved) - { - RemoveFolderContents(data.m_filePaths, resolvedAbsolutePath); - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to resolve relative path: %s", remove.c_str()).c_str()); - } - } - else - { - // Get the full path to the source image from the relative source path - AZStd::string fullSourceAssetPathName; - bool fullPathFound = GetAbsoluteSourcePathFromRelativePath(remove, fullSourceAssetPathName); - - if (!fullPathFound) - { - // Try to resolve relative path as it might be using "./" or "../" - fullPathFound = ResolveRelativePath(remove, directory, fullSourceAssetPathName); - } - - if (fullPathFound) - { - for (size_t i = 0; i < data.m_filePaths.size(); ++i) - { - if (data.m_filePaths[i] == fullSourceAssetPathName) - { - data.m_filePaths.erase(data.m_filePaths.begin() + i); - } - } - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to get source asset path for image: %s", remove.c_str()).c_str()); - } - } - } - else - { - // Add image files - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, line); - bool duplicate = false; - if (line.find('*') != -1) - { - AZStd::string resolvedAbsolutePath; - bool resolved = ResolveRelativePath(line, directory, resolvedAbsolutePath); - if (resolved) - { - AddFilesUsingWildCard(data.m_filePaths, resolvedAbsolutePath); - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to resolve relative path: %s", line.c_str()).c_str()); - } - } - else if (IsFolderPath(line)) - { - AZStd::string resolvedAbsolutePath; - bool resolved = ResolveRelativePath(line, directory, resolvedAbsolutePath); - if (resolved) - { - AddFolderContents(data.m_filePaths, resolvedAbsolutePath, valid); - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to resolve relative path: %s", line.c_str()).c_str()); - } - } - else - { - // Get the full path to the source image from the relative source path - AZStd::string fullSourceAssetPathName; - bool fullPathFound = GetAbsoluteSourcePathFromRelativePath(line, fullSourceAssetPathName); - - if (!fullPathFound) - { - // Try to resolve relative path as it might be using "./" or "../" - fullPathFound = ResolveRelativePath(line, directory, fullSourceAssetPathName); - } - - if (fullPathFound) - { - // Prevent duplicates - for (size_t i = 0; i < data.m_filePaths.size() && !duplicate; ++i) - { - duplicate = data.m_filePaths[i] == fullSourceAssetPathName; - } - if (!duplicate) - { - data.m_filePaths.push_back(fullSourceAssetPathName); - } - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to get source asset path for image: %s", line.c_str()).c_str()); - } - } - } - } - - return data; - } - - void AtlasBuilderInput::AddFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& insert) - { - AZ::IO::PathView fullPathView(insert); - - // Find first path element with a wild card in it - AZ::IO::Path staticPath; - auto wildCardPathElementIter = fullPathView.begin(); - for (; wildCardPathElementIter != fullPathView.end(); ++wildCardPathElementIter) - { - if (wildCardPathElementIter->Native().contains('*')) - { - break; - } - staticPath /= *wildCardPathElementIter; - } - - // The remaining path segments are part of the wild card path - - AZStd::vector candidates{ AZStd::move(staticPath) }; - for(; wildCardPathElementIter != fullPathView.end() && !candidates.empty(); ++wildCardPathElementIter) - { - AZStd::vector nextCandidates; - for (const AZ::IO::Path& candidate : candidates) - { - if (QDir inputFolder(QString::fromUtf8(candidate.c_str(), aznumeric_cast(candidate.Native().size()))); - inputFolder.exists()) - { - QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files); - for (const QFileInfo& entry : entries) - { - AZ::IO::Path filenameEntry(entry.fileName().toUtf8().data()); - if (filenameEntry.Match(wildCardPathElementIter->Native())) - { - nextCandidates.push_back(entry.filePath().toUtf8().data()); - } - } - } - } - candidates = nextCandidates; - } - - for (const AZ::IO::Path& candidate : candidates) - { - QFileInfo fileInfo(QString::fromUtf8(candidate.c_str(), aznumeric_cast(candidate.Native().size()))); - if (fileInfo.isFile()) - { - AZStd::string ext = fileInfo.suffix().toUtf8().data(); - if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds") - { - auto FindExistingPath = [&candidate](const AZStd::string& path) - { - return candidate == AZ::IO::PathView(path); - }; - if (auto foundIt = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath); - foundIt == paths.end()) - { - AZStd::string normalizedPath = AZ::IO::Path(candidate.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native(); - paths.push_back(AZStd::move(normalizedPath)); - } - } - } - else if (fileInfo.isDir()) - { - bool waste = true; - AddFolderContents(paths, candidate.Native(), waste); - } - } - } - - void AtlasBuilderInput::RemoveFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& remove) - { - auto RemoveWildCardPath = [&remove](const AZStd::string& subPath) - { - return AZ::IO::PathView(subPath).Match(remove); - }; - AZStd::erase_if(paths, RemoveWildCardPath); - } - - // Replaces all folder paths with the files they contain - void AtlasBuilderInput::AddFolderContents(AZStd::vector& paths, const AZStd::string& insert, bool& valid) - { - if (QDir inputFolder(insert.c_str()); inputFolder.exists()) - { - QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files); - for (const QFileInfo& entry : entries) - { - AZ::IO::Path child = entry.filePath().toUtf8().data(); - AZStd::string ext = entry.suffix().toUtf8().data(); - const bool isDir = entry.isDir(); - if (isDir) - { - AddFolderContents(paths, child.Native(), valid); - } - else if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds") - { - auto FindExistingPath = [&child](const AZStd::string& path) - { - return child == AZ::IO::PathView(path); - }; - if (auto foundIter = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath); - foundIter == paths.end()) - { - // Normalize the path to have posix slashes - AZStd::string normalizedPath = AZ::IO::Path(child.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native(); - paths.push_back(AZStd::move(normalizedPath)); - } - } - } - } - else - { - valid = false; - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to find requested directory: %s", insert.c_str()).c_str()); - } - } - - // Removes all of the contents of a folder - void AtlasBuilderInput::RemoveFolderContents(AZStd::vector& paths, const AZStd::string& remove) - { - auto RemoveSubPath = [folder = AZ::IO::PathView(remove)](const AZStd::string& subPath) - { - return AZ::IO::PathView(subPath).IsRelativeTo(folder); - }; - AZStd::erase_if(paths, RemoveSubPath); - } - - // Note - Shutdown will be called on a different thread than your process job thread - void AtlasBuilderWorker::ShutDown() { m_isShuttingDown = true; } - - void AtlasBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, - AssetBuilderSDK::CreateJobsResponse& response) - { - // Read in settings/filepaths to set dependencies - AZStd::string fullPath; - AzFramework::StringFunc::Path::Join( - request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), fullPath, true, true); - // Check if input is valid - bool valid = true; - AtlasBuilderInput input = AtlasBuilderInput::ReadFromFile(fullPath, request.m_watchFolder, valid); - - // Set dependencies - for (int i = 0; i < input.m_filePaths.size(); ++i) - { - AssetBuilderSDK::SourceFileDependency dependency; - dependency.m_sourceFileDependencyPath = input.m_filePaths[i].c_str(); - response.m_sourceFileDependencyList.push_back(dependency); - } - - // We process the same file for all platforms - for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) - { - if (ImageProcessing::BuilderSettingManager::Instance()->DoesSupportPlatform(info.m_identifier)) - { - AssetBuilderSDK::JobDescriptor descriptor = GetJobDescriptor(request.m_sourceFile, input); - descriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - response.m_createJobOutputs.push_back(descriptor); - } - } - - if (valid) - { - response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; - } - - return; - } - - AssetBuilderSDK::JobDescriptor AtlasBuilderWorker::GetJobDescriptor(const AZStd::string& sourceFile, const AtlasBuilderInput& input) - { - // Get the extension of the file - AZStd::string ext; - AzFramework::StringFunc::Path::GetExtension(sourceFile.c_str(), ext, false); - AZStd::to_upper(ext.begin(), ext.end()); - - AssetBuilderSDK::JobDescriptor descriptor; - descriptor.m_jobKey = ext + " Atlas"; - descriptor.m_critical = false; - descriptor.m_jobParameters[AZ_CRC("forceSquare")] = input.m_forceSquare ? "true" : "false"; - descriptor.m_jobParameters[AZ_CRC("forcePowerOf2")] = input.m_forcePowerOf2 ? "true" : "false"; - descriptor.m_jobParameters[AZ_CRC("includeWhiteTexture")] = input.m_includeWhiteTexture ? "true" : "false"; - descriptor.m_jobParameters[AZ_CRC("padding")] = AZStd::to_string(input.m_padding); - descriptor.m_jobParameters[AZ_CRC("maxDimension")] = AZStd::to_string(input.m_maxDimension); - descriptor.m_jobParameters[AZ_CRC("filePaths")] = AZStd::to_string(input.m_filePaths.size()); - - AZ::u32 col = input.m_unusedColor.ToU32(); - descriptor.m_jobParameters[AZ_CRC("unusedColor")] = AZStd::to_string(*reinterpret_cast(&col)); - descriptor.m_jobParameters[AZ_CRC("presetName")] = input.m_presetName; - - // The starting point for the list - const int start = static_cast(descriptor.m_jobParameters.size()) + 1; - descriptor.m_jobParameters[AZ_CRC("startPoint")] = AZStd::to_string(start); - - for (int i = 0; i < input.m_filePaths.size(); ++i) - { - descriptor.m_jobParameters[start + i] = input.m_filePaths[i]; - } - - return descriptor; - } - - void AtlasBuilderWorker::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, - AssetBuilderSDK::ProcessJobResponse& response) - { - // Before we begin, let's make sure we are not meant to abort. - AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId); - - AZStd::vector productFilepaths; - - const AZStd::string path = request.m_fullPath; - - bool imageProcessingSuccessful = false; - - // read in settings/filepaths - AtlasBuilderInput input; - input.m_forceSquare = AzFramework::StringFunc::ToBool(request.m_jobDescription.m_jobParameters.find(AZ_CRC("forceSquare"))->second.c_str()); - input.m_forcePowerOf2 = AzFramework::StringFunc::ToBool(request.m_jobDescription.m_jobParameters.find(AZ_CRC("forcePowerOf2"))->second.c_str()); - input.m_includeWhiteTexture = AzFramework::StringFunc::ToBool(request.m_jobDescription.m_jobParameters.find(AZ_CRC("includeWhiteTexture"))->second.c_str()); - input.m_padding = AzFramework::StringFunc::ToInt(request.m_jobDescription.m_jobParameters.find(AZ_CRC("padding"))->second.c_str()); - input.m_maxDimension = AzFramework::StringFunc::ToInt(request.m_jobDescription.m_jobParameters.find(AZ_CRC("maxDimension"))->second.c_str()); - int startAsInt = AzFramework::StringFunc::ToInt(request.m_jobDescription.m_jobParameters.find(AZ_CRC("startPoint"))->second.c_str()); - int sizeAsInt = AzFramework::StringFunc::ToInt(request.m_jobDescription.m_jobParameters.find(AZ_CRC("filePaths"))->second.c_str()); - AZ::u32 start = static_cast(AZStd::max(0, startAsInt)); - AZ::u32 size = static_cast(AZStd::max(0, sizeAsInt)); - - int col = AzFramework::StringFunc::ToInt(request.m_jobDescription.m_jobParameters.find(AZ_CRC("unusedColor"))->second.c_str()); - input.m_unusedColor.FromU32(*reinterpret_cast(&col)); - - input.m_presetName = request.m_jobDescription.m_jobParameters.find(AZ_CRC("presetName"))->second; - - for (AZ::u32 i = 0; i < size; ++i) - { - input.m_filePaths.push_back(request.m_jobDescription.m_jobParameters.find(start + i)->second); - } - - if (input.m_filePaths.empty()) - { - AZ_Error("AtlasBuilder", false, "No image files specified. Cannot create an empty atlas."); - return; - } - - // Don't allow padding to be less than zero - if (input.m_padding < 0) - { - input.m_padding = 0; - } - - if (input.m_presetName.empty()) - { - // Default to the TextureAtlas preset which is currently set to use compression for all platforms except for iOS. - // Currently the only fully supported compression for iOS is PVRTC which requires the texture to be square and a power of 2. - // Due to this limitation, we default to using no compression for iOS until ASTC is fully supported - const AZStd::string defaultPresetName = "TextureAtlas"; - input.m_presetName = defaultPresetName; - } - - // Get a preset to use for the output image - const ImageProcessing::PresetSettings* preset = GetImageProcessPresetSettings(input.m_presetName, request.m_platformInfo.m_identifier); - if (preset) - { - // Check the preset's pixel format requirements - const ImageProcessing::PixelFormatInfo* pixelFormatInfo = ImageProcessing::CPixelFormats::GetInstance().GetPixelFormatInfo(preset->m_pixelFormat); - if (pixelFormatInfo && pixelFormatInfo->bSquarePow2) - { - // Override the user config settings to force square and power of 2. - // Otherwise the image conversion process will stretch the image to satisfy these requirements - input.m_forceSquare = true; - input.m_forcePowerOf2 = true; - } - } - else - { - AZ_Error("AtlasBuilder", false, "Could not find a preset setting for the output image."); - return; - } - - // Read in images - AZStd::vector images; - AZ::u64 totalArea = 0; - int maxArea = input.m_maxDimension * input.m_maxDimension; - bool sizeFailure = false; - for (int i = 0; i < input.m_filePaths.size() && !jobCancelListener.IsCancelled(); ++i) - { - ImageProcessing::IImageObject* inputImage = ImageProcessing::LoadImageFromFile(input.m_filePaths[i]); - // Check if we were able to load the image - if (inputImage) - { - ImageProcessing::IImageObjectPtr image = ImageProcessing::IImageObjectPtr(inputImage); - images.push_back(image); - totalArea += inputImage->GetWidth(0) * inputImage->GetHeight(0); - } - else - { - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to load file: %s", input.m_filePaths[i].c_str()).c_str()); - return; - } - if (maxArea < totalArea) - { - sizeFailure = true; - } - } - // If we get cancelled, return - if (jobCancelListener.IsCancelled()) - { - return; - } - - if (sizeFailure) - { - AZ_Error("AtlasBuilder", false, AZStd::string::format("Total image area exceeds maximum alotted area. %llu > %d", totalArea, maxArea).c_str()); - return; - } - - // Convert all image paths to their output format referenced at runtime - for (auto& filePath : input.m_filePaths) - { - // Get path relative to the watch folder - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, filePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error("AtlasBuilder", false, AZStd::string::format("Atlas Builder unable to get relative source path for image: %s", filePath.c_str()).c_str()); - return; - } - - // Remove extension - filePath = info.m_relativePath.substr(0, info.m_relativePath.find_last_of('.')); - - // Normalize path - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, filePath); - } - - // Add white texture if we need to - if (input.m_includeWhiteTexture) - { - ImageProcessing::IImageObjectPtr texture(ImageProcessing::IImageObject::CreateImage( - cellSize, cellSize, 1, ImageProcessing::EPixelFormat::ePixelFormat_R8G8B8A8)); - - // Make the texture white - texture->ClearColor(1, 1, 1, 1); - images.push_back(texture); - input.m_filePaths.push_back("WhiteTexture"); - } - - // Generate algorithm inputs - ImageDimensionData data; - for (int i = 0; i < images.size(); ++i) - { - data.push_back(IndexImageDimension(i, - ImageDimension(images[i]->GetWidth(0), - images[i]->GetHeight(0)))); - } - AZStd::sort(data.begin(), data.end()); - - // Run algorithm - - // Variables that keep track of the optimal solution - int resultWidth = -1; - int resultHeight = -1; - - // Check that the max dimension is not large enough for the area to loop past the maximum integer - // This is important because we do not want the area to be calculated negative - if (input.m_maxDimension > 65535) - { - input.m_maxDimension = 65535; - } - - // Get the optimal mappings based on the input settings - AZStd::vector paddedMap; - size_t amountFit = 0; - if (!TryTightening( - input, data, GetWidest(data), GetTallest(data), aznumeric_cast(totalArea), input.m_padding, resultWidth, resultHeight, amountFit, paddedMap)) - { - AZ_Error("AtlasBuilder", false, AZStd::string::format("Cannot fit images into given maximum atlas size (%dx%d). Only %zu out of %zu images fit.", input.m_maxDimension, input.m_maxDimension, amountFit, input.m_filePaths.size()).c_str()); - // For some reason, failing the assert isn't enough to stop the Asset builder. It will still fail further - // down when it tries to assemble the atlas, but returning here is cleaner. - return; - } - - // Move coordinates from algorithm space to padded result space - TextureAtlasNamespace::AtlasCoordinateSets output; - resultWidth = 0; - resultHeight = 0; - AZStd::vector map; - for (int i = 0; i < paddedMap.size(); ++i) - { - map.push_back(AtlasCoordinates(paddedMap[i].GetLeft(), paddedMap[i].GetLeft() + images[data[i].first]->GetWidth(0), paddedMap[i].GetTop(), paddedMap[i].GetTop() + images[data[i].first]->GetHeight(0))); - resultHeight = resultHeight > map[i].GetBottom() ? resultHeight : map[i].GetBottom(); - resultWidth = resultWidth > map[i].GetRight() ? resultWidth : map[i].GetRight(); - - const AZStd::string& outputFilePath = input.m_filePaths[data[i].first]; - output.push_back(AZStd::pair(outputFilePath, map[i])); - } - if (input.m_forcePowerOf2) - { - resultWidth = aznumeric_cast(pow(2, 1 + IntegerLog2(static_cast(resultWidth - 1)))); - resultHeight = aznumeric_cast(pow(2, 1 + IntegerLog2(static_cast(resultHeight - 1)))); - } - else - { - resultWidth = (resultWidth + (cellSize - 1)) / cellSize * cellSize; - resultHeight = (resultHeight + (cellSize - 1)) / cellSize * cellSize; - } - if (input.m_forceSquare) - { - if (resultWidth > resultHeight) - { - resultHeight = resultWidth; - } - else - { - resultWidth = resultHeight; - } - } - - // Process texture sheet - ImageProcessing::IImageObjectPtr outImage(ImageProcessing::IImageObject::CreateImage( - resultWidth, resultHeight, 1, ImageProcessing::EPixelFormat::ePixelFormat_R8G8B8A8)); - - // Clear the sheet - outImage->ClearColor(input.m_unusedColor.GetR(), input.m_unusedColor.GetG(), input.m_unusedColor.GetB(), input.m_unusedColor.GetA()); - - AZ::u8* outBuffer = nullptr; - AZ::u32 outPitch; - outImage->GetImagePointer(0, outBuffer, outPitch); - - // Copy images over - for (int i = 0; i < map.size() && !jobCancelListener.IsCancelled(); ++i) - { - AZ::u8* inBuffer = nullptr; - AZ::u32 inPitch; - images[data[i].first]->GetImagePointer(0, inBuffer, inPitch); - int j = 0; - - // The padding calculated here is the amount of excess horizontal space measured in bytes that are in each - // row of the destination space AFTER the placement of the source row. - int rightPadding = (paddedMap[i].GetRight() - map[i].GetRight() - input.m_padding); - if (map[i].GetRight() + rightPadding > resultWidth) - { - rightPadding = resultWidth - map[i].GetRight(); - } - rightPadding *= bytesPerPixel; - int bottomPadding = (paddedMap[i].GetBottom() - map[i].GetBottom() - input.m_padding); - if (map[i].GetBottom() + bottomPadding > resultHeight) - { - bottomPadding = resultHeight - map[i].GetBottom(); - } - - int leftPadding = 0; - if (map[i].GetLeft() - input.m_padding >= 0) - { - leftPadding = input.m_padding * bytesPerPixel; - } - - int topPadding = 0; - if (map[i].GetTop() - input.m_padding >= 0) - { - topPadding = input.m_padding; - } - - for (j = 0; j < map[i].GetHeight(); ++j) - { - // When we multiply `map[i].GetLeft()` by 4, we are changing the measure from atlas space, to byte array - // space. The number is 4 because in this format, each pixel is 4 bytes long. - memcpy(outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel), - inBuffer + inPitch * j, - inPitch); - // Fill in the last bit of the row in the destination space with the same colors - SetPixels(outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel) + inPitch, - outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel) + inPitch - bytesPerPixel, - rightPadding); - // Fill in the first bit of the row in the destination space with the same colors - SetPixels(outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel) - leftPadding, - outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel), - leftPadding); - } - // Fill in the last few rows of the buffer with the same colors - for (; j < map[i].GetHeight() + bottomPadding; ++j) - { - memcpy(outBuffer + (map[i].GetTop() + j) * outPitch + (map[i].GetLeft() * bytesPerPixel) - leftPadding, - outBuffer + (map[i].GetBottom() - 1) * outPitch + (map[i].GetLeft() * bytesPerPixel) - leftPadding, - inPitch + leftPadding + rightPadding); - } - for (j = 1; j <= topPadding; ++j) - { - memcpy(outBuffer + (map[i].GetTop() - j) * outPitch + (map[i].GetLeft() * bytesPerPixel) - leftPadding, - outBuffer + map[i].GetTop() * outPitch + (map[i].GetLeft() * bytesPerPixel) - leftPadding, - inPitch + rightPadding + leftPadding); - } - } - - // If we get cancelled, return - if (jobCancelListener.IsCancelled()) - { - return; - } - - // Output Atlas Coordinates - AZStd::string fileName; - AZStd::string outputPath; - AzFramework::StringFunc::Path::GetFullFileName(request.m_sourceFile.c_str(), fileName); - fileName = fileName.append("idx"); - AzFramework::StringFunc::Path::Join( - request.m_tempDirPath.c_str(), fileName.c_str(), outputPath, true, true); - - // Output texture sheet - AZStd::string imageFileName, imageOutputPath; - AzFramework::StringFunc::Path::GetFileName(request.m_sourceFile.c_str(), imageFileName); - imageFileName += ".dds"; - AzFramework::StringFunc::Path::Join( - request.m_tempDirPath.c_str(), imageFileName.c_str(), imageOutputPath, true, true); - - // Let the ImageProcessor do the rest of the work. - ImageProcessing::TextureSettings textureSettings; - textureSettings.m_preset = preset->m_uuid; - - // Mipmaps for the texture atlas would require more work than the Image Processor does. This is because if we - // let the Image Processor make mipmaps, it might bleed the textures in the atlas together. - textureSettings.m_enableMipmap = false; - - // Check if the ImageBuilder wants to enable streaming - bool isStreaming = ImageProcessing::BuilderSettingManager::Instance() - ->GetBuilderSetting(request.m_platformInfo.m_identifier) - ->m_enableStreaming; - - bool canOverridePreset = false; - ImageProcessing::ImageConvertProcess* process = - new ImageProcessing::ImageConvertProcess(outImage, - textureSettings, - *preset, - false, - isStreaming, - canOverridePreset, - imageOutputPath, - request.m_platformInfo.m_identifier); - - if (process != nullptr) - { - // the process can be stopped if the job is cancelled or the worker is shutting down - while (!process->IsFinished() && !m_isShuttingDown && !jobCancelListener.IsCancelled()) - { - process->UpdateProcess(); - } - - // get process result - imageProcessingSuccessful = process->IsSucceed(); - process->GetAppendOutputFilePaths(productFilepaths); - - delete process; - } - else - { - imageProcessingSuccessful = false; - } - - if (imageProcessingSuccessful) - { - TextureAtlasNamespace::TextureAtlasRequestBus::Broadcast( - &TextureAtlasNamespace::TextureAtlasRequests::SaveAtlasToFile, outputPath, output, resultWidth, resultHeight); - response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct(outputPath)); - response.m_outputProducts[static_cast(Product::TexatlasidxProduct)].m_productAssetType = azrtti_typeid(); - response.m_outputProducts[static_cast(Product::TexatlasidxProduct)].m_productSubID = 0; - - // The Image Processing Gem can produce multiple output files under certain - // circumstances, but the texture atlas is not expected to produce such output - if (productFilepaths.size() > 1) - { - AZ_Error("AtlasBuilder", false, "Image processing resulted in multiple output files. Texture atlas is expected to produce one output."); - response.m_outputProducts.clear(); - return; - } - - if (productFilepaths.size() > 0) - { - response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct(productFilepaths[0])); - response.m_outputProducts.back().m_productAssetType = azrtti_typeid(); - response.m_outputProducts.back().m_productSubID = 1; - - // The texatlasidx file is a data file that indicates where the original parts are inside the atlas, - // and this would usually imply that it refers to its dds file in some way or needs it to function. - // The texatlasidx file should be the one that depends on the DDS because its possible to use the DDS - // without the texatlasid, but not the other way around - AZ::Data::AssetId productAssetId(request.m_sourceFileUUID, response.m_outputProducts.back().m_productSubID); - response.m_outputProducts[static_cast(Product::TexatlasidxProduct)].m_dependencies.push_back(AssetBuilderSDK::ProductDependency(productAssetId, 0)); - response.m_outputProducts[static_cast(Product::TexatlasidxProduct)].m_dependenciesHandled = true; // We've populated the dependencies immediately above so it's OK to tell the AP we've handled dependencies - } - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - } - } - - bool AtlasBuilderWorker::TryPack(const ImageDimensionData& images, - int targetWidth, - int targetHeight, - int padding, - size_t& amountFit, - AZStd::vector& out) - { - // Start with one open slot and initialize a vector to store the closed products - AZStd::vector open; - AZStd::vector closed; - open.push_back(AtlasCoordinates(0, targetWidth, 0, targetHeight)); - bool slotNotFound = false; - for (size_t i = 0; i < images.size() && !slotNotFound; ++i) - { - slotNotFound = true; - // Try to place the image in every open slot - for (size_t j = 0; j < open.size(); ++j) - { - if (CanInsert(open[j], images[i].second, padding, targetWidth, targetHeight)) - { - // if it fits, subdivide the excess space in the slot, add it back to the open list and place the - // filled space into the closed vector - slotNotFound = false; - AtlasCoordinates spent(open[j].GetLeft(), - open[j].GetLeft() + images[i].second.m_width, - open[j].GetTop(), - open[j].GetTop() + images[i].second.m_height); - - // We are going to try pushing the object up / left to try to avoid creating tight open spaces. - bool needTrim = false; - AtlasCoordinates coords = spent; - // Modifying left will preserve width - coords.SetLeft(coords.GetLeft() - 1); - AddPadding(coords, padding, targetWidth, targetHeight); - while (spent.GetLeft() > 0 && !Collides(coords, closed)) - { - spent.SetLeft(coords.GetLeft()); - coords = spent; - coords.SetLeft(coords.GetLeft() - 1); - AddPadding(coords, padding, targetWidth, targetHeight); - needTrim = true; - } - // Refocus the search to see if we can push up - coords = spent; - coords.SetTop(coords.GetTop() - 1); - AddPadding(coords, padding, targetWidth, targetHeight); - while (spent.GetTop() > 0 && !Collides(coords, closed)) - { - spent.SetTop(coords.GetTop()); - coords = spent; - coords.SetTop(coords.GetTop() - 1); - AddPadding(coords, padding, targetWidth, targetHeight); - needTrim = true; - } - AddPadding(spent, padding, targetWidth, targetHeight); - if (needTrim) - { - TrimOverlap(open, spent); - closed.push_back(spent); - break; - } - AtlasCoordinates bigCoords; - AtlasCoordinates smallCoords; - - // Create the largest possible subdivision and another subdivision that uses the left over space - if (open[j].GetBottom() - spent.GetBottom() < open[j].GetRight() - spent.GetRight()) - { - smallCoords = AtlasCoordinates( - open[j].GetLeft(), spent.GetRight(), spent.GetBottom(), open[j].GetBottom()); - bigCoords = AtlasCoordinates(spent.GetRight(), open[j].GetRight(), open[j].GetTop(), smallCoords.GetBottom()); - } - else - { - bigCoords = AtlasCoordinates( - open[j].GetLeft(), open[j].GetRight(), spent.GetBottom(), open[j].GetBottom()); - smallCoords = AtlasCoordinates(spent.GetRight(), open[j].GetRight(), open[j].GetTop(), bigCoords.GetTop()); - } - - open.erase(open.begin() + j, open.begin() + j + 1); - if (bigCoords.GetHeight() > 0 && bigCoords.GetHeight() > 0) - { - InsertInOrder(open, bigCoords); - } - if (smallCoords.GetHeight() > 0 && smallCoords.GetHeight() > 0) - { - InsertInOrder(open, smallCoords); - } - - closed.push_back(spent); - break; - } - } - if (slotNotFound) - { - // If no single open slot can fit the object, do one last check to see if we can fit it in at any open - // corner. The reason we perform this check is in case the object can be fit across multiple different - // open spaces. If there is a space that an object can be fit in, it will probably involve the top left - // corner of that object in the top left corner of an open slot. This may miss some odd fits, but due to - // the nature of the packing algorithm, such solutions are highly unlikely to exist. If we wanted to - // expand the algorithm, we could theoretically base it on edges instead of corners to find all results, - // but it would not be time efficient. - for (size_t j = 0; j < open.size(); ++j) - { - AtlasCoordinates insert = AtlasCoordinates(open[j].GetLeft(), - open[j].GetLeft() + images[i].second.m_width, - open[j].GetTop(), - open[j].GetTop() + images[i].second.m_height); - AddPadding(insert, padding, targetWidth, targetHeight); - if (insert.GetRight() <= targetWidth && insert.GetBottom() <= targetHeight) - { - bool collision = Collides(insert, closed); - if (!collision) - { - closed.push_back(insert); - // Trim overlapping open slots - TrimOverlap(open, insert); - slotNotFound = false; - break; - } - } - } - } - } - // If we succeeded, update the output - if (!slotNotFound) - { - out = closed; - } - amountFit = amountFit > closed.size() ? amountFit : closed.size(); - return !slotNotFound; - } - - // Modifies slotList so that no items in slotList overlap with item - void AtlasBuilderWorker::TrimOverlap(AZStd::vector& slotList, AtlasCoordinates item) - { - for (size_t i = 0; i < slotList.size(); ++i) - { - if (Collides(slotList[i], item)) - { - // Subdivide the overlapping slot to seperate overlapping and non overlapping portions - AtlasCoordinates overlap = GetOverlap(item, slotList[i]); - AZStd::vector excess; - excess.push_back(AtlasCoordinates( - slotList[i].GetLeft(), overlap.GetRight(), slotList[i].GetTop(), overlap.GetTop())); - excess.push_back(AtlasCoordinates( - slotList[i].GetLeft(), overlap.GetLeft(), overlap.GetTop(), slotList[i].GetBottom())); - excess.push_back(AtlasCoordinates( - overlap.GetRight(), slotList[i].GetRight(), slotList[i].GetTop(), overlap.GetBottom())); - excess.push_back(AtlasCoordinates( - overlap.GetLeft(), slotList[i].GetRight(), overlap.GetBottom(), slotList[i].GetBottom())); - slotList.erase(slotList.begin() + i); - for (size_t j = 0; j < excess.size(); ++j) - { - if (excess[j].GetWidth() > 0 && excess[j].GetHeight() > 0) - { - InsertInOrder(slotList, excess[j]); - } - } - --i; - } - } - } - - // This function interprets input and performs the proper tightening option - bool AtlasBuilderWorker::TryTightening(AtlasBuilderInput input, - const ImageDimensionData& images, - int smallestWidth, - int smallestHeight, - int targetArea, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out) - { - if (input.m_forceSquare) - { - return TryTighteningSquare(images, - smallestWidth > smallestHeight ? smallestWidth : smallestHeight, - input.m_maxDimension, - targetArea, - input.m_forcePowerOf2, - padding, - resultWidth, - resultHeight, - amountFit, - out); - } - else - { - return TryTighteningOptimal(images, - smallestWidth, - smallestHeight, - input.m_maxDimension, - targetArea, - input.m_forcePowerOf2, - padding, - resultWidth, - resultHeight, - amountFit, - out); - } - } - - // Finds the optimal square solution by starting with the ideal solution and expanding the size of the space until everything fits - bool AtlasBuilderWorker::TryTighteningSquare(const ImageDimensionData& images, - int lowerBound, - int maxDimension, - int targetArea, - bool powerOfTwo, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out) - { - // Square solution cannot be smaller than the target area - int dimension = aznumeric_cast(sqrt(static_cast(targetArea))); - // Solution cannot be smaller than the smallest side - dimension = dimension > lowerBound ? dimension : lowerBound; - if (powerOfTwo) - { - // Starting dimension needs to be rounded up to the nearest power of two - dimension = aznumeric_cast(pow(2, 1 + IntegerLog2(static_cast(dimension - 1)))); - } - - AZStd::vector track; - // Expand the square until the contents fit - while (!TryPack(images, dimension, dimension, padding, amountFit, track) && dimension <= maxDimension) - { - // Step to the next valid value - dimension = powerOfTwo ? dimension * 2 : dimension + cellSize; - } - // Make sure we found a solution - if (dimension > maxDimension) - { - return false; - } - - resultHeight = dimension; - resultWidth = dimension; - out = track; - return true; - } - - // Finds the optimal solution by starting with a somewhat optimal solution and searching for better solutions - bool AtlasBuilderWorker::TryTighteningOptimal(const ImageDimensionData& images, - int smallestWidth, - int smallestHeight, - int maxDimension, - int targetArea, - bool powerOfTwo, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out) - { - AZStd::vector track; - - // round max dimension down to a multiple of cellSize - AZ::u32 maxDimensionRounded = maxDimension - (maxDimension % cellSize); - - // The starting width is the larger of the widest individual texture and the width required - // to fit the total texture area given the max dimension - AZ::u32 smallestWidthDueToArea = targetArea / maxDimensionRounded; - AZ::u32 minWidth = AZStd::max(static_cast(smallestWidth), smallestWidthDueToArea); - - if (powerOfTwo) - { - // Starting dimension needs to be rounded up to the nearest power of two - minWidth = aznumeric_cast(pow(2, 1 + IntegerLog2(static_cast(minWidth - 1)))); - } - - // Round min width up to the nearest compression unit - minWidth = (minWidth + (cellSize - 1)) / cellSize * cellSize; - - AZ::u32 height = 0; - // Finds the optimal thin solution - // This uses a standard binary search to find the smallest width that can pack everything - AZ::u32 lower = minWidth; - AZ::u32 upper = maxDimensionRounded; - AZ::u32 width = 0; - while (lower <= upper) - { - AZ::u32 testWidth = (lower + upper) / 2; // must be divisible by cellSize because lower and upper are - bool canPack = TryPack(images, testWidth, maxDimension, padding, amountFit, track); - if (canPack) - { - // it packed, continue looking for smaller widths that pack - width = testWidth; // best fit so far - upper = testWidth - cellSize; - } - else - { - // it failed to pack, don't try any widths smaller than this - lower = testWidth + cellSize; - } - } - // Make sure we found a solution - if (width == 0) - { - return false; - } - - // Find the height of the solution - for (int i = 0; i < track.size(); ++i) - { - uint32 bottom = static_cast(AZStd::max(0, track[i].GetBottom())); - if (height < bottom) - { - height = bottom; - } - } - - // Fix height for power of two when applicable - if (powerOfTwo) - { - // Starting dimensions need to be rounded up to the nearest power of two - height = aznumeric_cast(pow(2, 1 + IntegerLog2(static_cast(height - 1)))); - } - - AZ::u32 resultArea = height * width; - // This for loop starts with the optimal thin width and makes it wider at each step. For each width, it - // calculates what height would be neccesary to have a more optimal solution than the stored solution. If the - // more optimal solution is valid, it tries shrinking the height until the solution fails. The loop ends when it - // is determined that a valid solution cannot exist at further steps - for (AZ::u32 testWidth = width; testWidth <= maxDimensionRounded && resultArea / testWidth >= static_cast(smallestHeight); - testWidth = powerOfTwo ? testWidth * 2 : testWidth + cellSize) - { - // The area of test height and width should be equal or less than resultArea - // Note: We don't need to force powers of two here because the Area and the width are already powers of two - int testHeight = resultArea / testWidth * cellSize / cellSize; - // Try the tighter pack - while (TryPack(images, static_cast(testWidth), testHeight, padding, amountFit, track)) - { - // Loop and continue to shrink the height until you cannot do so any further - width = testWidth; - height = testHeight; - resultArea = height * width; - // Try to step down a level - testHeight = powerOfTwo ? testHeight / 2 : testHeight - cellSize; - } - } - // Output the results of the function - out = track; - resultHeight = height; - resultWidth = width; - return true; - } - - // Allows us to keep the list of open spaces in order from lowest to highest area - void AtlasBuilderWorker::InsertInOrder(AZStd::vector& slotList, AtlasCoordinates item) - { - int area = item.GetWidth() * item.GetHeight(); - for (size_t i = 0; i < slotList.size(); ++i) - { - if (area < slotList[i].GetWidth() * slotList[i].GetHeight()) - { - slotList.insert(slotList.begin() + i, item); - return; - } - } - slotList.push_back(item); - } - - // Defines priority so that sorting can be meaningful. It may seem odd that larger items are "less than" smaller - // ones, but as this is a deduction of priority, not value, it is correct. - static bool operator<(ImageDimension a, ImageDimension b) - { - // Prioritize first by longest size - if ((a.m_width > a.m_height ? a.m_width : a.m_height) != (b.m_width > b.m_height ? b.m_width : b.m_height)) - { - return (a.m_width > a.m_height ? a.m_width : a.m_height) > (b.m_width > b.m_height ? b.m_width : b.m_height); - } - // Prioritize second by the length of the smaller side - if (a.m_width * a.m_height != b.m_width * b.m_height) - { - return a.m_width * a.m_height > b.m_width * b.m_height; - } - // Prioritize wider objects over taller objects for objects of the same size - else - { - return a.m_width > b.m_width; - } - } - - // Exposes priority logic to the sorting algorithm - static bool operator<(IndexImageDimension a, IndexImageDimension b) { return a.second < b.second; } - - // Tests if two coordinate sets intersect - bool Collides(AtlasCoordinates a, AtlasCoordinates b) - { - return !((a.GetRight() <= b.GetLeft()) || (a.GetBottom() <= b.GetTop()) || (b.GetRight() <= a.GetLeft()) - || (b.GetBottom() <= a.GetTop())); - } - - // Tests if an item collides with any items in a list - bool Collides(AtlasCoordinates item, AZStd::vector list) - { - for (size_t i = 0; i < list.size(); ++i) - { - if (Collides(list[i], item)) - { - return true; - } - } - return false; - } - - // Returns the overlap of two intersecting coordinate sets - AtlasCoordinates GetOverlap(AtlasCoordinates a, AtlasCoordinates b) - { - return AtlasCoordinates(b.GetLeft() > a.GetLeft() ? b.GetLeft() : a.GetLeft(), - b.GetRight() < a.GetRight() ? b.GetRight() : a.GetRight(), - b.GetTop() > a.GetTop() ? b.GetTop() : a.GetTop(), - b.GetBottom() < a.GetBottom() ? b.GetBottom() : a.GetBottom()); - } - - // Returns the width of the widest element in imageList - int AtlasBuilderWorker::GetWidest(const ImageDimensionData& imageList) - { - int max = 0; - for (size_t i = 0; i < imageList.size(); ++i) - { - if (max < imageList[i].second.m_width) - { - max = imageList[i].second.m_width; - } - } - return max; - } - - // Returns the height of the tallest element in imageList - int AtlasBuilderWorker::GetTallest(const ImageDimensionData& imageList) - { - int max = 0; - for (size_t i = 0; i < imageList.size(); ++i) - { - if (max < imageList[i].second.m_height) - { - max = imageList[i].second.m_height; - } - } - return max; - } - - // Performs an operation that copies a pixel to the output - void SetPixels(AZ::u8* dest, const AZ::u8* source, int destBytes) - { - if (destBytes >= bytesPerPixel) - { - memcpy(dest, source, bytesPerPixel); - int bytesCopied = bytesPerPixel; - while (bytesCopied * 2 < destBytes) - { - memcpy(dest + bytesCopied, dest, bytesCopied); - bytesCopied *= 2; - } - memcpy(dest + bytesCopied, dest, destBytes - bytesCopied); - } - } - - // Checks if we can insert an image into a slot - bool CanInsert(AtlasCoordinates slot, ImageDimension image, int padding, int farRight, int farBot) - { - int right = slot.GetLeft() + image.m_width; - if (slot.GetRight() < farRight) - { - // Add padding for my right border - right += padding; - // Round up to the nearest compression unit - right = (right + (cellSize - 1)) / cellSize * cellSize; - // Add padding for an adjacent unit's left border - right += padding; - } - - int bot = slot.GetTop() + image.m_height; - if (slot.GetBottom() < farBot) - { - // Add padding for my right border - bot += padding; - // Round up to the nearest compression unit - bot = (bot + (cellSize - 1)) / cellSize * cellSize; - // Add padding for an adjacent unit's left border - bot += padding; - } - - return slot.GetRight() >= right && slot.GetBottom() >= bot; - } - - // Adds the necessary padding to an Atlas Coordinate - void AddPadding(AtlasCoordinates& slot, int padding, [[maybe_unused]] int farRight, [[maybe_unused]] int farBot) - { - // Add padding for my right border - int right = slot.GetRight() + padding; - // Round up to the nearest compression unit - right = (right + (cellSize - 1)) / cellSize * cellSize; - // Add padding for an adjacent unit's left border - right += padding; - - // Add padding for my right border - int bot = slot.GetBottom() + padding; - // Round up to the nearest compression unit - bot = (bot + (cellSize - 1)) / cellSize * cellSize; - // Add padding for an adjacent unit's left border - bot += padding; - - slot.SetRight(right); - slot.SetBottom(bot); - } - -} diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h deleted file mode 100644 index f28535998e..0000000000 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace TextureAtlasBuilder -{ - //! Struct that is used to communicate input commands - struct AtlasBuilderInput - { - AZ_CLASS_ALLOCATOR(AtlasBuilderInput, AZ::SystemAllocator, 0); - AZ_TYPE_INFO(AtlasBuilderInput, "{F54477F9-1BDE-4274-8CC0-8320A3EF4A42}"); - - bool m_forceSquare; - bool m_forcePowerOf2; - // Includes a white default texture for the UI to use under certain circumstances - bool m_includeWhiteTexture; - int m_maxDimension; - // At least this much padding will surround each texture except on the edges of the atlas - int m_padding; - // Color used in wasted space - AZ::Color m_unusedColor; - // A preset to use for the texture atlas image processing - AZStd::string m_presetName; - - AZStd::vector m_filePaths; - AtlasBuilderInput(): - m_forceSquare(false), - m_forcePowerOf2(false), - m_includeWhiteTexture(true), - m_maxDimension(4096), - m_padding(1), - // Default color should be a non-transparent color that isn't used often in uis - m_unusedColor(.235f, .702f, .443f, 1) - { - } - - static void Reflect(AZ::ReflectContext* context); - - //! Attempts to read the input from a .texatlas file. "valid" is for reporting exceptions and telling the asset - //! proccesor to fail the job. Supports parsing through a human readable custom parser. - static AtlasBuilderInput ReadFromFile(const AZStd::string& path, const AZStd::string& directory, bool& valid); - - //! Resolves any wild cards in paths - static void AddFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& insert); - - //! Removes anything that matches the wildcard - static void RemoveFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& remove); - - //! Resolves any folder paths into image file paths - static void AddFolderContents(AZStd::vector& paths, const AZStd::string& insert, bool& valid); - - //! Resolves remove commands for folders - static void RemoveFolderContents(AZStd::vector& paths, const AZStd::string& remove); - }; - - //! Struct that is used to represent an object with a width and height in pixels - struct ImageDimension - { - int m_width; - int m_height; - - ImageDimension(int width, int height) - { - m_width = width; - m_height = height; - } - }; - - //! Typedef for an ImageDimension paired with an integer - using IndexImageDimension = AZStd::pair; - - //! Typedef for a list of ImageDimensions paired with integers - using ImageDimensionData = AZStd::vector; - - //! Typedef to simplify references to TextureAtlas::AtlasCoordinates - using AtlasCoordinates = TextureAtlasNamespace::AtlasCoordinates; - - //! Number of bytes in a pixel - const int bytesPerPixel = 4; - - //! The size of the padded sorting units (important for compression) - const int cellSize = 4; - - //! Indexes of the products - enum class Product - { - TexatlasidxProduct = 0, - DdsProduct = 1 - }; - - //! An asset builder for texture atlases - class AtlasBuilderWorker : public AssetBuilderSDK::AssetBuilderCommandBus::Handler - { - public: - AZ_RTTI(AtlasBuilderWorker, "{79036188-E017-4575-9EC0-8D39CB560EA6}"); - - AtlasBuilderWorker() = default; - ~AtlasBuilderWorker() = default; - - //! Asset Builder Callback Functions - - //! Called by asset processor to gather information on a job for a ".texatlas" file - void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, - AssetBuilderSDK::CreateJobsResponse& response); - //! Called by asset proccessor when it wants us to execute a job - void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, - AssetBuilderSDK::ProcessJobResponse& response); - - //! Returns the job related information used by the builder - static AssetBuilderSDK::JobDescriptor GetJobDescriptor(const AZStd::string& sourceFile, const AtlasBuilderInput& input); - - ////////////////////////////////////////////////////////////////////////// - //! AssetBuilderSDK::AssetBuilderCommandBus interface - void ShutDown() override; // if you get this you must fail all existing jobs and return. - ////////////////////////////////////////////////////////////////////////// - - private: - bool m_isShuttingDown = false; - - //! This is the main function that takes a set of inputs and attempts to pack them into an atlas of a given - //! size. Returns true if succesful, does not update out on failure. - static bool TryPack(const ImageDimensionData& images, - int targetWidth, - int targetHeight, - int padding, - size_t& amountFit, - AZStd::vector& out); - - //! Removes any overlap between slotList and the given item - static void TrimOverlap(AZStd::vector& slotList, AtlasCoordinates item); - - //! Uses the proper tightening method based on the input and returns the maximum number of items that were able to be fit - bool TryTightening(AtlasBuilderInput input, - const ImageDimensionData& images, - int smallestWidth, - int smallestHeight, - int targetArea, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out); - - //! Finds the tightest square fit achievable by expanding a square area until a valid fit is found - bool TryTighteningSquare(const ImageDimensionData& images, - int lowerBound, - int maxDimension, - int targetArea, - bool powerOfTwo, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out); - - //! Finds the tightest fit achievable by starting with the optimal thin solution and attempting to resize to be - //! a better shape - bool TryTighteningOptimal(const ImageDimensionData& images, - int smallestWidth, - int smallestHeight, - int maxDimension, - int targetArea, - bool powerOfTwo, - int padding, - int& resultWidth, - int& resultHeight, - size_t& amountFit, - AZStd::vector& out); - - //! Sorting logic for adding a slot to a sorted list in order to maintain increasing order - static void InsertInOrder(AZStd::vector& slotList, AtlasCoordinates item); - - //! Misc Logic For Estimating Target Shape - - //! Returns the width of the widest element - static int GetWidest(const ImageDimensionData& imageList); - - //! Returns the height of the tallest area - static int GetTallest(const ImageDimensionData& imageList); - }; - - //! Used for sorting ImageDimensions - static bool operator<(ImageDimension a, ImageDimension b); - - //! Used to expose the ImageDimension in a pair to AZStd::Sort - static bool operator<(IndexImageDimension a, IndexImageDimension b); - - //! Returns true if two coordinate sets overlap - static bool Collides(AtlasCoordinates a, AtlasCoordinates b); - - //! Returns true if item collides with any object in list - static bool Collides(AtlasCoordinates item, AZStd::vector list); - - //! Returns the portion of the second item that overlaps with the first - static AtlasCoordinates GetOverlap(AtlasCoordinates a, AtlasCoordinates b); - - //! Performs an operation that copies a pixel to the output - static void SetPixels(AZ::u8* dest, const AZ::u8* source, int destBytes); - - //! Checks if we can insert an image into a slot - static bool CanInsert(AtlasCoordinates slot, ImageDimension image, int padding, int farRight, int farBot); - - //! Adds the necessary padding to an Atlas Coordinate - static void AddPadding(AtlasCoordinates& slot, int padding, int farRight, int farBot); -} diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.cpp deleted file mode 100644 index f8b0a1651b..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ /dev/null @@ -1,1114 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" - -#include "BuilderSettingManager.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - namespace ImageProcess##PrivateName\ - {\ - bool DoesSupport(AZStd::string);\ - } -AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif //AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS - - const char* BuilderSettingManager::s_environmentVariableName = "ImageBuilderSettingManager"; - AZ::EnvironmentVariable BuilderSettingManager::s_globalInstance = nullptr; - AZStd::mutex BuilderSettingManager::s_instanceMutex; - const PlatformName BuilderSettingManager::s_defaultPlatform = AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM; - - AZ::Outcome, AZStd::string> GetPlatformNamesFromRC(AZStd::string& filePath) - { - QFile inputFile(filePath.c_str()); - - if (inputFile.exists() == false) - { - return AZ::Failure(AZStd::string::format("'%s' does not exist", filePath.c_str())); - } - - AZStd::vector all_platforms; - if (inputFile.open(QIODevice::ReadOnly)) - { - QTextStream in(&inputFile); - while (!in.atEnd()) - { - if (in.readLine() == "[_platform]") - { - QString name_line = in.readLine(); - if (name_line.contains("name=")) - { - QString name_value = name_line.split("=")[1]; - // Remove name alias after ',' - AZStd::string az_name_value = name_value.split(",")[0].toUtf8().constData(); - all_platforms.push_back(az_name_value); - } - } - } - inputFile.close(); - } - return AZ::Success(all_platforms); - } - - StringOutcome ParseKeyToData(QString settingKey, const QSettings& rcINI, PresetSettings& presetSettings) - { - // We may be parsing platform-specific settings denoted by a colon and a platform (ex. mintexturesize:ios=35). - // We always extract the actual setting name to determine the setting we are parsing. We must reference the key - // as a whole to properly index into the rcINI file content. - QString key = settingKey.split(":")[0]; - - // There is no standard way to map an enum to string-- - // Also, can't seem to make this static because it allocates something that the destructor doesn't catch. - const AZStd::map colorSpaceMap{ - { "linear" , ColorSpace::linear }, - { "sRGB" , ColorSpace::sRGB }, - { "auto" , ColorSpace::autoSelect } - }; - - const AZStd::map rgbWeightMap{ - { "uniform" , RGBWeight::uniform }, - { "luminance" , RGBWeight::luminance }, - { "ciexyz" , RGBWeight::ciexyz } - }; - - //cm_ftype: gaussian, cone, disc, cosine, cosine_power, ggx - const AZStd::map cubemapFilterTypeMap{ - { "cone" , CubemapFilterType::cone }, - { "gaussian" , CubemapFilterType::gaussian }, - { "ggx" , CubemapFilterType::ggx }, - { "cosine" , CubemapFilterType::cosine }, - { "cosine_power" , CubemapFilterType::cosine_power } - }; - - // To avoid abusing '#define', we use lambda instead. - auto INI_VALUE = [&rcINI, &settingKey]() { return rcINI.value(settingKey); }; - auto INI_VALUE_QSTRING = [&rcINI, &settingKey]() { return rcINI.value(settingKey).toString(); }; - - /************************************************************************/ - /* GENERAL PRESET SETTINGS */ - /************************************************************************/ - if (key == "rgbweights") - { - auto rgbWeightStr = INI_VALUE_QSTRING().toUtf8(); - auto rgbWeightIter = rgbWeightMap.find(rgbWeightStr); - if (rgbWeightIter != rgbWeightMap.end()) - { - presetSettings.m_rgbWeight = rgbWeightIter->second; - } - else - { - return AZ::Failure(AZStd::string("Unmapped rgbweights enum detected.")); - } - } - else if (key == "powof2") - { - presetSettings.m_isPowerOf2 = INI_VALUE().toBool(); - } - else if (key == "discardalpha") - { - presetSettings.m_discardAlpha = INI_VALUE().toBool(); - } - else if (key == "reduce") - { - int reduce = INI_VALUE().toInt(); - if (reduce > 0) - { - presetSettings.m_sizeReduceLevel = reduce; - } - } - else if (key == "ser") - { - presetSettings.m_suppressEngineReduce = INI_VALUE().toBool(); - } - else if (key == "colorchart") - { - presetSettings.m_isColorChart = INI_VALUE().toBool(); - } - else if (key == "highpass") - { - presetSettings.m_highPassMip = INI_VALUE().toInt(); - } - else if (key == "glossfromnormals") - { - presetSettings.m_glossFromNormals = INI_VALUE().toBool(); - } - else if (key == "glosslegacydist") - { - presetSettings.m_isLegacyGloss = INI_VALUE().toBool(); - } - else if (key == "swizzle") - { - presetSettings.m_swizzle = INI_VALUE_QSTRING().toUtf8().constData(); - } - else if (key == "mipnormalize") - { - presetSettings.m_isMipRenormalize = INI_VALUE().toBool(); - } - else if (key == "numstreamablemips") - { - presetSettings.m_numStreamableMips = INI_VALUE().toInt(); - } - else if (key == "colorspace") - { - // By default, RC.ini contains data written in non-standard INI format inherited from CryEngine. - // We need to parse in the value as string list. - // Example: - // - // [MyValues] - // colorspace=src,dst - // - QVariant paramValue = rcINI.value(key, QString()); - if (paramValue.type() != QVariant::StringList) - { - return AZ::Failure(AZStd::string("Expect ColorSpace parameter to be a string list!")); - } - QStringList stringValueList = paramValue.toStringList(); // The order of values for this key is... (SRC, DST) - - if (stringValueList.size() != 2) - { - return AZ::Failure(AZStd::string("Expect ColorSpace parameter list size to be 2!")); - } - - auto srcColorSpaceIter = colorSpaceMap.find(stringValueList[0]); - if (srcColorSpaceIter != colorSpaceMap.end()) - { - presetSettings.m_srcColorSpace = srcColorSpaceIter->second; - } - else - { - return AZ::Failure(AZStd::string("Unmapped ColorSpace enum detected.")); - } - - auto dstColorSpaceIter = colorSpaceMap.find(stringValueList[1]); - if (dstColorSpaceIter != colorSpaceMap.end()) - { - presetSettings.m_destColorSpace = dstColorSpaceIter->second; - } - else - { - return AZ::Failure(AZStd::string("Unmapped ColorSpace enum detected.")); - } - } - else if (key == "filemasks") - { - QVariant iniVariant = rcINI.value(settingKey); - QStringList stringValueList = iniVariant.toStringList(); - for (QString value : stringValueList) - { - //remove stars. For example: "*_ddna*" => "_ddna" - QString suffix = value.mid(1, value.length()-2); - QByteArray suffixByteArray = suffix.toUtf8(); - presetSettings.m_fileMasks.emplace_back(suffixByteArray.constData()); - } - } - else if (key == "pixelformat") - { - auto pixelFormatQBytes = INI_VALUE_QSTRING().toUtf8(); - const char* pixelFormatString = pixelFormatQBytes.constData(); - - EPixelFormat pixelFormatEnum = CPixelFormats::GetInstance().FindPixelFormatByLegacyName(pixelFormatString); - if (pixelFormatEnum == EPixelFormat::ePixelFormat_Unknown) - { - return AZ::Failure(AZStd::string::format("Unsupported ePixelFormat detected: %s", pixelFormatString)); - } - - presetSettings.m_pixelFormat = pixelFormatEnum; - presetSettings.m_pixelFormatName = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormatEnum)->szName; - } - else if (key == "pixelformatalpha") - { - auto pixelFormatQBytes = INI_VALUE_QSTRING().toUtf8(); - const char* pixelFormatString = pixelFormatQBytes.constData(); - - EPixelFormat pixelFormatEnum = CPixelFormats::GetInstance().FindPixelFormatByLegacyName(pixelFormatString); - if (pixelFormatEnum == EPixelFormat::ePixelFormat_Unknown) - { - return AZ::Failure(AZStd::string::format("Unsupported ePixelFormat detected: %s", pixelFormatString)); - } - - presetSettings.m_pixelFormatAlpha = pixelFormatEnum; - presetSettings.m_pixelFormatAlphaName = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormatEnum)->szName; - } - else if (key == "maxtexturesize") - { - bool isOk = false; - auto maxTextureSize = INI_VALUE().toUInt(&isOk); - if (isOk) - { - presetSettings.m_maxTextureSize = maxTextureSize; - } - else - { - return AZ::Failure(AZStd::string::format("Invalid number for key 'maxtexturesize' for [%s]", presetSettings.m_name.c_str())); - } - } - else if (key == "mintexturesize") - { - bool isOk = false; - auto minTextureSize = INI_VALUE().toUInt(&isOk); - if (isOk) - { - presetSettings.m_minTextureSize = minTextureSize; - } - else - { - return AZ::Failure(AZStd::string::format("Invalid number for key 'mintexturesize' for [%s]", presetSettings.m_name.c_str())); - } - } - /************************************************************************/ - /* CUBEMAP PRESET SETTINGS */ - /************************************************************************/ - else if (key == "cm") - { - if (presetSettings.m_cubemapSetting == nullptr && INI_VALUE().toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - } - else - { - return AZ::Failure(AZStd::string("Multiple CubeMap settings detected. Reduce to a single settings entry.")); - } - } - else if (key == "cm_ftype") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - } - } - - if (presetSettings.m_cubemapSetting) - { - auto filterTypeStr = INI_VALUE_QSTRING().toUtf8(); - auto filterTypeIter = cubemapFilterTypeMap.find(filterTypeStr); - if (filterTypeIter != cubemapFilterTypeMap.end()) - { - presetSettings.m_cubemapSetting->m_filter = filterTypeIter->second; - } - else - { - return AZ::Failure(AZStd::string("Unmapped cubemap filter type enum detected.")); - } - } - } - else if (key == "cm_fangle") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_angle = INI_VALUE().toFloat(); - } - } - else - { - presetSettings.m_cubemapSetting->m_angle = INI_VALUE().toFloat(); - } - } - else if (key == "cm_fmipangle") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_mipAngle = INI_VALUE().toFloat(); - } - } - else - { - presetSettings.m_cubemapSetting->m_mipAngle = INI_VALUE().toFloat(); - } - } - else if (key == "cm_fmipslope") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_mipSlope = INI_VALUE().toFloat(); - } - } - else - { - presetSettings.m_cubemapSetting->m_mipSlope = INI_VALUE().toFloat(); - } - } - else if (key == "cm_edgefixup") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_edgeFixup = INI_VALUE().toFloat(); - } - } - else - { - presetSettings.m_cubemapSetting->m_edgeFixup = INI_VALUE().toFloat(); - } - } - else if (key == "cm_diff") - { - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_generateDiff = INI_VALUE().toBool(); - } - } - else - { - presetSettings.m_cubemapSetting->m_generateDiff = INI_VALUE().toBool(); - } - } - else if (key == "cm_diffpreset") - { - QByteArray presetNameByteArray = INI_VALUE().toString().toUtf8(); - AZ::Uuid presetID = BuilderSettingManager::Instance()->GetPresetIdFromName(presetNameByteArray.constData()); - if (presetID.IsNull()) - { - return STRING_OUTCOME_ERROR(AZStd::string::format("Parsing error [cm_diffpreset]. Unable to find UUID for preset: %s", presetNameByteArray.constData())); - } - - if (presetSettings.m_cubemapSetting == nullptr) - { - if (rcINI.value("cm").toBool()) - { - presetSettings.m_cubemapSetting = AZStd::make_unique(); - presetSettings.m_cubemapSetting->m_diffuseGenPreset = presetID; - } - } - else - { - presetSettings.m_cubemapSetting->m_diffuseGenPreset = presetID; - } - } - /************************************************************************/ - /* MIPMAP PRESET SETTINGS */ - /************************************************************************/ - else if (key == "mipmaps") - { - // We convey whether 'mipmaps' is enabled/available by whether the pointer is valid or empty. - if (presetSettings.m_mipmapSetting == nullptr && INI_VALUE().toBool()) - { - presetSettings.m_mipmapSetting = AZStd::make_unique(); - } - } - else if (key == "mipgentype") - { - // We must handle parsing settings of missing/disabled parent settings ("mipmaps") - if (rcINI.value("mipmaps") == QVariant()) - { - return AZ::Failure(AZStd::string("'mipgentype' specified, but dependent 'mipmaps' setting is missing in rc.ini.")); - } - - // If we are missing the mipmap settings (possibly yet to be parsed)... - if (presetSettings.m_mipmapSetting == nullptr) - { - if (rcINI.value("mipmaps").toBool()) - { - presetSettings.m_mipmapSetting = AZStd::make_unique(); - } - else - { - return AZ::Failure(AZStd::string::format( - "Cannot assign 'mipgentype' because current Preset [%s] has 'mipmaps' disabled.", presetSettings.m_name.c_str())); - } - } - - presetSettings.m_mipmapSetting->m_type = MipGenType::blackmanHarris; - if ("average" == INI_VALUE_QSTRING().toUtf8()) - { - presetSettings.m_mipmapSetting->m_type = MipGenType::box; - } - } - else - { - QByteArray keyByteArray = key.toUtf8(); - return STRING_OUTCOME_WARNING(AZStd::string::format("Unsupported key parsed from RC.ini: %s", keyByteArray.constData())); - } - - return STRING_OUTCOME_SUCCESS; - } - - void LoadPresetAliasFromRC(QSettings& rcINI, AZStd::map & presetAliases) - { - rcINI.beginGroup("_presetAliases"); - - for (QString legacyPresetString : rcINI.childKeys()) - { - QString modernPresetString = rcINI.value(legacyPresetString).toString(); - - // We must store this intermediary data in order to convert to a c-string. - QByteArray legacyPresetUtf8 = legacyPresetString.toUtf8(); - QByteArray modernPresetUtf8 = modernPresetString.toUtf8(); - - PresetName legacyPresetName(legacyPresetUtf8.constData()); - PresetName modernPresetName(modernPresetUtf8.constData()); - - presetAliases.insert(AZStd::pair(legacyPresetName, modernPresetName)); - } - - rcINI.endGroup(); - } - - void BuilderSettingManager::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("BuildSettings", &BuilderSettingManager::m_builderSettings) - ->Field("PresetAliases", &BuilderSettingManager::m_presetAliases) - ->Field("DefaultPresetsByFileMask", &BuilderSettingManager::m_defaultPresetByFileMask) - ->Field("DefaultPreset", &BuilderSettingManager::m_defaultPreset) - ->Field("DefaultPresetAlpha", &BuilderSettingManager::m_defaultPresetAlpha) - ->Field("DefaultPresetNonePOT", &BuilderSettingManager::m_defaultPresetNonePOT); - } - } - - BuilderSettingManager* BuilderSettingManager::Instance() - { - AZStd::lock_guard lock(s_instanceMutex); - - if (!s_globalInstance) - { - s_globalInstance = AZ::Environment::FindVariable(s_environmentVariableName); - } - AZ_Assert(s_globalInstance, "BuilderSettingManager not created!"); - - return s_globalInstance.Get(); - } - - void BuilderSettingManager::CreateInstance() - { - AZStd::lock_guard lock(s_instanceMutex); - - if (s_globalInstance) - { - AZ_Assert(false, "BuilderSettingManager already created!"); - return; - } - - if (!s_globalInstance) - { - s_globalInstance = AZ::Environment::CreateVariable(s_environmentVariableName); - } - if (!s_globalInstance.Get()) - { - s_globalInstance.Set(aznew BuilderSettingManager()); - } - } - - void BuilderSettingManager::DestroyInstance() - { - AZStd::lock_guard lock(s_instanceMutex); - AZ_Assert(s_globalInstance, "Invalid call to DestroyInstance - no instance exists."); - AZ_Assert(s_globalInstance.Get(), "You can only call DestroyInstance if you have called CreateInstance."); - - delete s_globalInstance.Get(); - s_globalInstance.Reset(); - } - - const PresetSettings* BuilderSettingManager::GetPreset(const AZ::Uuid presetId, const PlatformName& platform) - { - AZStd::lock_guard lock(m_presetMapLock); - PlatformName platformName = platform; - if (platformName.empty()) - { - platformName = BuilderSettingManager::s_defaultPlatform; - } - - if (m_builderSettings.find(platformName) != m_builderSettings.end()) - { - const BuilderSettings& platformBuilderSetting = m_builderSettings[platformName]; - auto settingsIter = platformBuilderSetting.m_presets.find(presetId); - if (settingsIter != platformBuilderSetting.m_presets.end()) - { - return &settingsIter->second; - } - else - { - AZ_Error("Image Processing", false, "Cannot find preset settings on platform [%s] for preset id: %s", platformName.c_str(), presetId.ToString().c_str()); - } - } - else - { - AZ_Error("Image Processing", false, "Cannot find platform [%s]", platformName.c_str()); - } - - return nullptr; - } - - - const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) - { - if (m_builderSettings.find(platform) != m_builderSettings.end()) - { - return &m_builderSettings[platform]; - } - return nullptr; - } - - const PlatformNameList BuilderSettingManager::GetPlatformList() - { - PlatformNameList platforms; - - for(auto& builderSetting : m_builderSettings) - { - if (builderSetting.second.m_enablePlatform) - { - platforms.push_back(builderSetting.first); - } - } - - return platforms; - } - - const AZStd::map >& BuilderSettingManager::GetPresetFilterMap() - { - AZStd::lock_guard lock(m_presetMapLock); - return m_presetFilterMap; - } - - const AZ::Uuid BuilderSettingManager::GetPresetIdFromName(const PresetName& presetName) - { - AZStd::lock_guard lock(m_presetMapLock); - - // Each preset shares the same UUID across platforms, therefore, it's safe to pick a random - // platform to search for the preset UUID. We'll use PC, in this case. - const PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform; - if (m_builderSettings.find(defaultPlatform) != m_builderSettings.end()) - { - auto presets = m_builderSettings[defaultPlatform].m_presets; - - for (auto curIter : presets) - { - if (curIter.second.m_name == presetName) - { - return curIter.first; - } - } - } - - return AZ::Uuid::CreateNull(); - } - - const PresetName BuilderSettingManager::GetPresetNameFromId(const AZ::Uuid& presetId) - { - AZStd::lock_guard lock(m_presetMapLock); - const PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform; - if (m_builderSettings.find(defaultPlatform) != m_builderSettings.end()) - { - auto& presetMap = m_builderSettings[defaultPlatform].m_presets; - auto presetIter = presetMap.find(presetId); - if (presetIter != presetMap.end()) - { - return presetIter->second.m_name; - } - } - - return "Unknown"; - } - - void BuilderSettingManager::ClearSettings() - { - AZStd::lock_guard lock(m_presetMapLock); - m_presetFilterMap.clear(); - m_presetAliases.clear(); - m_builderSettings.clear(); - } - - StringOutcome BuilderSettingManager::LoadBuilderSettings() - { - StringOutcome outcome = STRING_OUTCOME_ERROR(""); - // Construct the project setting path that is used by the tool for loading setting file - const char* gameFolderPath = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameFolderPath, &AzToolsFramework::AssetSystemRequestBus::Events::GetAbsoluteDevGameFolderPath); - AZStd::string projectSettingPath = ""; - - if (gameFolderPath) - { - AzFramework::StringFunc::Path::Join(gameFolderPath, "Config/ImageBuilder/ImageBuilderPresets.settings", projectSettingPath); - outcome = LoadBuilderSettings(projectSettingPath); - } - - if (!outcome.IsSuccess()) - { - AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Failed to read project specific preset setting at [%s], will use default setting file.\n", projectSettingPath.c_str()); - // Construct the default setting path - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - - if (engineRoot) - { - AZStd::string defaultSettingPath = ""; - AzFramework::StringFunc::Path::Join(engineRoot, "Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings", defaultSettingPath); - outcome = LoadBuilderSettings(defaultSettingPath); - } - } - - return outcome; - } - - StringOutcome BuilderSettingManager::LoadBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context) - { - // Ensure filepath exists. - AZ::IO::FileIOBase* fileReader = AZ::IO::FileIOBase::GetInstance(); - if(false == fileReader->Exists(filepath.c_str())) - { - return AZ::Failure(AZStd::string::format("Build settings file not found: %s", filepath.c_str())); - } - - AZ::IO::HandleType settingsFileHandle; - m_builderSettingsFileVersion = 0; - if (fileReader->Open(filepath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary, settingsFileHandle) == AZ::IO::ResultCode::Success) - { - // Read the contents of the file and hash it. The first u32 of the result of this will be used as a version - // number. Any changes to the builder settings file will then cause all textures to be reconverted to pick - // up that change. - AZStd::string settingsFileBuffer; - AZ::u64 settingsFileSize = 0; - fileReader->Size(settingsFileHandle, settingsFileSize); - settingsFileBuffer.resize_no_construct(settingsFileSize); - fileReader->Read(settingsFileHandle, settingsFileBuffer.data(), settingsFileSize); - fileReader->Close(settingsFileHandle); - - AZ::Sha1 block; - AZ::u32 hashDigest[5]; - block.ProcessBytes(settingsFileBuffer.data(), settingsFileSize); - block.GetDigest(hashDigest); - m_builderSettingsFileVersion = hashDigest[0]; - } - - auto loadedSettingsPtr = AZStd::unique_ptr(AZ::Utils::LoadObjectFromFile(filepath, context)); - - // Ensure file is loaded. - if (!loadedSettingsPtr) - { - return AZ::Failure(AZStd::string::format("Failed to read from file: %s", filepath.c_str())); - } - - m_presetMapLock.lock(); - // Normally, we would perform a deep-copy from the loaded settings onto 'this' via assignment operator overload. However, we have deleted our - // assignment operator overloads, because we intend for this class to be a singleton. Instead, we will manually perform a deep-copy - // in this function since it's the only time we require something akin to assignment operation. - m_builderSettings = loadedSettingsPtr->m_builderSettings; - m_presetAliases = loadedSettingsPtr->m_presetAliases; - m_defaultPresetByFileMask = loadedSettingsPtr->m_defaultPresetByFileMask; - m_defaultPreset = loadedSettingsPtr->m_defaultPreset; - m_defaultPresetAlpha = loadedSettingsPtr->m_defaultPresetAlpha; - m_defaultPresetNonePOT = loadedSettingsPtr->m_defaultPresetNonePOT; - - m_presetFilterMap.clear(); - - //enable builder settings for enabled restricted platforms. These settings should be disabled by default in the setting file -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - for (auto& buildSetting : m_builderSettings)\ - {\ - if (ImageProcess##PrivateName::DoesSupport(buildSetting.first))\ - {\ - buildSetting.second.m_enablePlatform = true;\ - break;\ - }\ - } - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif //AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS - - //convert pixel format string to enum for each preset - for (auto& buildSetting : m_builderSettings) - { - for (auto& preset : buildSetting.second.m_presets) - { - preset.second.m_pixelFormat = CPixelFormats::GetInstance().FindPixelFormatByName(preset.second.m_pixelFormatName.c_str()); - preset.second.m_pixelFormatAlpha = CPixelFormats::GetInstance().FindPixelFormatByName(preset.second.m_pixelFormatAlphaName.c_str()); - } - } - m_presetMapLock.unlock(); - - RegenerateMappings(); - - return AZ::Success(AZStd::string()); - } - - StringOutcome BuilderSettingManager::WriteBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context) - { - if( false == AZ::Utils::SaveObjectToFile(filepath, AZ::DataStream::StreamType::ST_XML, this, context)) - { - return STRING_OUTCOME_ERROR(AZStd::string::format("Failed to write file: %s", filepath.c_str())); - } - return STRING_OUTCOME_SUCCESS; - } - - const PresetName BuilderSettingManager::TranslateLegacyPresetName(const PresetName& legacyName) - { - auto iterResult = m_presetAliases.find(legacyName); - - if (iterResult == m_presetAliases.end()) - { - return legacyName; - } - - return iterResult->second; - } - - StringOutcome BuilderSettingManager::LoadBuilderSettingsFromRC(AZStd::string& filePath) - { - //Clear previous settings first - ClearSettings(); - - // Find all the platforms - auto outcome = GetPlatformNamesFromRC(filePath); - AZ_ENSURE_STRING_OUTCOME(outcome); - PlatformNameVector all_platforms = outcome.TakeValue(); - - m_presetMapLock.lock(); - // Register all the platforms with empty settings. - for (const AZStd::string& platformName : all_platforms) - { - auto newEntry = AZStd::pair(platformName, BuilderSettings()); - m_builderSettings.insert(newEntry); - } - - // Open settings for parsing - QSettings set(filePath.c_str(), QSettings::IniFormat); - - // Load the preset alias mapping - LoadPresetAliasFromRC(set, m_presetAliases); - - QStringList childGroups = set.childGroups(); - QStringList exemptGroups; - exemptGroups.append("_platform"); - exemptGroups.append("_presetAliases"); - - // We must generate new preset settings and UUID's prior to parsing the rest of the data, because - // some preset settings make references to other presets within RC.ini. We must make sure all presets - // are identified, before making references to them via their UUID. - for (QString groupName : childGroups) - { - auto newPresetUuid = AZ::Uuid::CreateRandom(); - PresetSettings newPresetSetting; - newPresetSetting.m_name = groupName.toUtf8().constData(); - newPresetSetting.m_uuid = newPresetUuid; - for (const PlatformName& platform : all_platforms) - { - m_builderSettings[platform].m_presets.insert(AZStd::make_pair(newPresetUuid, newPresetSetting)); - } - } - m_presetMapLock.unlock(); - - // Apply preset settings from file to the existing presets (process each platform). - for(QString groupName : childGroups) - { - // Only process Presets from here on out. - if (exemptGroups.contains(groupName)) - { - continue; - } - - auto outcome2 = ProcessPreset(groupName, set, all_platforms); - AZ_ENSURE_STRING_OUTCOME(outcome2); - } - - RegenerateMappings(); - - // The original rc.ini doesn't have the information below. Included here for GetSuggestedPreset() to work properly. - m_defaultPresetByFileMask["_diff"] = GetPresetIdFromName("Albedo"); - m_defaultPresetByFileMask["_spec"] = GetPresetIdFromName("Reflectance"); - m_defaultPresetByFileMask["_refl"] = GetPresetIdFromName("Reflectance"); - m_defaultPresetByFileMask["_ddn"] = GetPresetIdFromName("Normals"); - m_defaultPresetByFileMask["_ddna"] = GetPresetIdFromName("NormalsWithSmoothness"); - m_defaultPresetByFileMask["_cch"] = GetPresetIdFromName("ColorChart"); - m_defaultPresetByFileMask["_cm"] = GetPresetIdFromName("EnvironmentProbeHDR"); - - m_defaultPreset = GetPresetIdFromName("Albedo"); - m_defaultPresetAlpha = GetPresetIdFromName("AlbedoWithGenericAlpha"); - m_defaultPresetNonePOT = GetPresetIdFromName("ReferenceImage"); - - return STRING_OUTCOME_SUCCESS; - } - - AZ::u32 BuilderSettingManager::BuilderSettingsVersion() const - { - return m_builderSettingsFileVersion; - } - - void BuilderSettingManager::RegenerateMappings() - { - AZStd::lock_guard lock(m_presetMapLock); - - AZStd::string noFilter = AZStd::string(); - - m_presetFilterMap.clear(); - - for (auto& builderSettingIter : m_builderSettings) - { - const BuilderSettings& builderSetting = builderSettingIter.second; - for (auto& presetIter : builderSetting.m_presets) - { - //Put into no filter preset list - m_presetFilterMap[noFilter].insert(presetIter.second.m_name); - - //Put into file mask preset list if any - for (const PlatformName& filemask : presetIter.second.m_fileMasks) - { - m_presetFilterMap[filemask].insert(presetIter.second.m_name); - } - } - } - } - - StringOutcome BuilderSettingManager::ProcessPreset(QString& preset, QSettings& rcINI, PlatformNameVector& all_platforms) - { - // Early-out check. We should have the preset available before processing. - QByteArray presetByteArray = preset.toUtf8(); - AZ::Uuid parsingPresetUuid = GetPresetIdFromName(presetByteArray.constData()); - if (parsingPresetUuid.IsNull()) - { - return STRING_OUTCOME_ERROR(AZStd::string::format("Unable to find UUID for preset: %s", presetByteArray.constData())); - } - - rcINI.beginGroup(preset); - QStringList groupKeys = rcINI.allKeys(); - - // Build a list for common & platform-specific settings - QStringList commonPresetSettingKeys; - QStringList platformSpecificPresetSettingKeys; - for (QString key : groupKeys) - { - if (key.contains(":")) - { - platformSpecificPresetSettingKeys.append(key); - } - else - { - commonPresetSettingKeys.append(key); - } - } - - // Parse the common settings (retain preset name & uuid) - PresetSettings commonPresetSettings; - commonPresetSettings.m_name = presetByteArray.constData(); - commonPresetSettings.m_uuid = parsingPresetUuid; - for (QString settingKey : commonPresetSettingKeys) - { - AZ_ENSURE_STRING_OUTCOME(ParseKeyToData(settingKey, rcINI, commonPresetSettings)); - } - - // When loading a preset, the UUID is the same per-preset, regardless of the target-platform. - for (AZStd::string& platformId : all_platforms) - { - // Begin platform-specific settings loading with a copy of common Preset settings. - PresetSettings currentPlatformPresetSetting = commonPresetSettings; - - // Obtain platform-specific settings - QString platformFilter = QString(":%1").arg(platformId.c_str()); // Example results-> ":ios", ":osx", ":es3" - QStringList currentPlatformSettings = platformSpecificPresetSettingKeys.filter(platformFilter); - - // Overwrite values for platform-specific settings... - for (QString platformSetting : currentPlatformSettings) - { - AZ_ENSURE_STRING_OUTCOME(ParseKeyToData(platformSetting, rcINI, currentPlatformPresetSetting)); - } - - // Assign the overridden platform preset settings to the BuilderSettingManager. - m_builderSettings[platformId].m_presets[parsingPresetUuid] = currentPlatformPresetSetting; - } - - rcINI.endGroup(); - return STRING_OUTCOME_SUCCESS; - } - - void BuilderSettingManager::MetafilePathFromImagePath(const AZStd::string& imagePath, AZStd::string& metafilePath) - { - // Determine if we have a meta file (legacy or modern). - AZ::IO::LocalFileIO fileIO; - - AZStd::string modernMetaFilepath = imagePath + TextureSettings::modernExtensionName; - if (fileIO.Exists(modernMetaFilepath.c_str())) - { - metafilePath = modernMetaFilepath; - return; - } - - AZStd::string legacyMetaFilepath = imagePath + TextureSettings::legacyExtensionName; - if (fileIO.Exists(legacyMetaFilepath.c_str())) - { - metafilePath = legacyMetaFilepath; - return; - } - - // We found neither. - metafilePath = AZStd::string(); - } - - AZStd::string GetFileMask(const AZStd::string& imageFilePath) - { - //get file name - AZStd::string fileName; - QString lowerFileName = imageFilePath.c_str(); - lowerFileName = lowerFileName.toLower(); - AzFramework::StringFunc::Path::GetFileName(lowerFileName.toUtf8().constData(), fileName); - - //get the substring from last '_' - size_t lastUnderScore = fileName.find_last_of('_'); - if (lastUnderScore != AZStd::string::npos) - { - return fileName.substr(lastUnderScore); - } - - return AZStd::string(); - } - - AZ::Uuid BuilderSettingManager::GetSuggestedPreset(const AZStd::string& imageFilePath, IImageObjectPtr imageFromFile) - { - //load the image to get its size for later use - IImageObjectPtr image = imageFromFile; - //if the input image is empty we will try to load it from the path - if (imageFromFile == nullptr) - { - image = IImageObjectPtr(LoadImageFromFile(imageFilePath)); - } - - if (image == nullptr) - { - AZ_Error("Image Processing", image, "Cannot load image file [%s]. Invalid image format or corrupt data. Note that \"Indexed Color\" is not currently supported for .tga files.", imageFilePath.c_str()); - return AZ::Uuid::CreateNull(); - } - - //get file mask of this image file - AZStd::string fileMask = GetFileMask(imageFilePath); - - AZ::Uuid outPreset = AZ::Uuid::CreateNull(); - - if ("_diff" == fileMask && image->GetAlphaContent() != EAlphaContent::eAlphaContent_Absent) - { - outPreset = m_defaultPresetAlpha; - } - else - { - //check default presets for some file masks - if (m_defaultPresetByFileMask.find(fileMask) != m_defaultPresetByFileMask.end()) - { - outPreset = m_defaultPresetByFileMask[fileMask]; - } - } - - //use the preset filter map to find - if (outPreset.IsNull() && !fileMask.empty()) - { - auto& presetFilterMap = GetPresetFilterMap(); - if (presetFilterMap.find(fileMask) != presetFilterMap.end()) - { - AZStd::string presetName = *(presetFilterMap.find(fileMask)->second.begin()); - outPreset = GetPresetIdFromName(presetName); - } - } - - const PresetSettings* presetInfo = nullptr; - - if (!outPreset.IsNull()) - { - presetInfo = GetPreset(outPreset); - - //special case for cubemap - if (presetInfo && presetInfo->m_cubemapSetting) - { - if (CubemapLayout::GetCubemapLayoutInfo(image) == nullptr) - { - outPreset = AZ::Uuid::CreateNull(); - } - } - } - - if (outPreset.IsNull()) - { - if (!image->HasPowerOfTwoSizes()) - { - // The resource compiler used the non power of 2 preset if the width or the height is not power of 2 - // even if it would have been possible to compress the image, so this behavior is matched here. - return m_defaultPresetNonePOT; - } - else if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent) - { - outPreset = m_defaultPreset; - } - else - { - outPreset = m_defaultPresetAlpha; - } - } - - //get the pixel format for selected preset - presetInfo = GetPreset(outPreset); - - if (presetInfo) - { - //valid whether image size work with pixel format - if (CPixelFormats::GetInstance().IsImageSizeValid(presetInfo->m_pixelFormat, - image->GetWidth(0), image->GetHeight(0), false)) - { - return outPreset; - } - } - - //uncompressed one which could be used for almost everything - return m_defaultPresetNonePOT; - } - - bool BuilderSettingManager::DoesSupportPlatform(const AZStd::string& platformId) - { - bool rv = m_builderSettings.find(platformId) != m_builderSettings.end(); - return rv; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.h deleted file mode 100644 index c6d03eae54..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettingManager.h +++ /dev/null @@ -1,192 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -class QSettings; -class QString; - -namespace AZ -{ - template class EnvironmentVariable; - class SerializeContext; -} - -namespace ImageProcessing -{ - class BuilderSettingManager - { - public: - AZ_TYPE_INFO(CBuilderSettingManager, "{DAA55241-64FA-4A9B-A37F-C0A36B36D536}"); - AZ_CLASS_ALLOCATOR(BuilderSettingManager, AZ::SystemAllocator, 0); - //load builder settings for all platform - //contain builder setting for all platforms - //this manager should be able to get texture setting for a platform - - - static BuilderSettingManager* Instance(); - // life cycle management: - static void CreateInstance(); - static void DestroyInstance(); - static void Reflect(AZ::ReflectContext* context); - - const PresetSettings* GetPreset(const AZ::Uuid presetId, const PlatformName& platform = ""); - - const BuilderSettings* GetBuilderSetting(const PlatformName& platform); - - /** - * Attempts to translate a legacy preset name into Open 3D Engine preset name. - * @param legacy preset name string - * @return A translated preset name. If no translation is available, returns the same value as input argument. - */ - const PresetName TranslateLegacyPresetName(const PresetName& legacyName); - - /** - * @return A list of platform supported - */ - const PlatformNameList GetPlatformList(); - - /** - * @return A map of preset settings based on their filemasks. - * @key filemask string, empty string means no filemask - * @value set of preset setting names supporting the specified filemask - */ - const AZStd::map>& GetPresetFilterMap(); - - /** - * Find preset id list based on the preset name. - * @param preset name string - * @return a map of preset ids whose name are specified by the input on different platforms - * @key platform name string - * @value uuid of the preset setting - */ - const AZ::Uuid GetPresetIdFromName(const PresetName& presetName); - - /** - * Find preset name based on the preset id. - * @param uuid of the preset setting - * @return preset name string - */ - const PresetName GetPresetNameFromId(const AZ::Uuid& presetId); - - /** - * Writes preset data to file using AZ::Serialization format. - * @param filepath string to the build settings xml - */ - StringOutcome WriteBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context = nullptr); - - /** - * Loads preset data from file using AZ::Serialization format. - * @param filepath string to the build settings xml - */ - StringOutcome LoadBuilderSettings(AZStd::string filepath, AZ::SerializeContext* context = nullptr); - - /** - * Overload function. Loads preset data from project setting file if any - * Otherwise, the function will load default setting file inside the gem - */ - StringOutcome LoadBuilderSettings(); - - /** - * Loads preset data from legacy format found in RC.ini. - * @param filepath string to RC.ini - */ - StringOutcome LoadBuilderSettingsFromRC(AZStd::string& filePath); - - /** - * Returns the first u32 generated from a hash of the builder settings - * file that can be used as a version to detect changes to the file. - */ - AZ::u32 BuilderSettingsVersion() const; - - /** - * Provides a full path to the adjacent metafile of a given texture/image file. - * @param Filepath string to the texture/image file. - * @param Output filepath string to the adjacent texture/image metafile. - * Will output whichever metafile is present, whether it is legacy or modern format. - * If both are present, modern format is returned. - * If none are present, an empty string is returned. - */ - void MetafilePathFromImagePath(const AZStd::string& imagePath, AZStd::string& metafilePath); - - /** - * Find a suitable preset a given image file. - * @param imageFilePath: Filepath string of the image file. The function may load the image from the path for better detection - * @param image: an optional image object which can be used for preset selection if there is no match based file mask. - * @return suggested preset uuid. - */ - AZ::Uuid GetSuggestedPreset(const AZStd::string& imageFilePath, IImageObjectPtr image = nullptr); - - bool DoesSupportPlatform(const AZStd::string& platformId); - - static const char* s_environmentVariableName; - static AZ::EnvironmentVariable s_globalInstance; - static AZStd::mutex s_instanceMutex; - static const PlatformName s_defaultPlatform; - - BuilderSettingManager(){} - - private: // functions - AZ_DISABLE_COPY_MOVE(BuilderSettingManager); - - StringOutcome ProcessPreset(QString& preset, QSettings& rcINI, PlatformNameVector& all_platforms); - - /** - * Clear Builder Settings and any cached maps/lists - */ - void ClearSettings(); - - /** - * Regenerate Builder Settings and any cached maps/lists - */ - void RegenerateMappings(); - - private: // variables - - //builder settings for each platform - AZStd::map m_builderSettings; - AZStd::map m_presetAliases; - - /** - * Cached list of presets mapped by their file masks. - * @Key file mask, use empty string to indicate all presets without filtering - * @Value set of preset names that matches the file mask - */ - AZStd::map > m_presetFilterMap; - - /** - * A mutex to protect when modifying any map in this manager - */ - AZStd::mutex m_presetMapLock; - - //default presets for certian file masks - AZStd::map m_defaultPresetByFileMask; - - //default preset for none power of two image - AZ::Uuid m_defaultPresetNonePOT; - - //default preset for power of two - AZ::Uuid m_defaultPreset; - - //default preset for power of two with alpha - AZ::Uuid m_defaultPresetAlpha; - - //generated from hashing the builder settings file - AZ::u32 m_builderSettingsFileVersion; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.cpp deleted file mode 100644 index 6f68ea7581..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ImageProcessing_precompiled.h" -#include -#include - -namespace ImageProcessing -{ - void BuilderSettings::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("GlossScale", &BuilderSettings::m_brdfGlossScale) - ->Field("GlossBias", &BuilderSettings::m_brdfGlossBias) - ->Field("Streaming", &BuilderSettings::m_enableStreaming) - ->Field("Enable", &BuilderSettings::m_enablePlatform) - ->Field("Presets", &BuilderSettings::m_presets); - } - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.h deleted file mode 100644 index 500b69f472..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/BuilderSettings.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - //builder setting for a platform - struct BuilderSettings - { - AZ_TYPE_INFO(BuilderSettings, "{4085AB56-934C-43A6-AF25-4443E1EEB71D}"); - AZ_CLASS_ALLOCATOR(BuilderSettings, AZ::SystemAllocator, 0); - static void Reflect(AZ::ReflectContext* context); - - //global settings - float m_brdfGlossScale = 16.0f; - float m_brdfGlossBias = 0.0f; - bool m_enableStreaming = true; - bool m_enablePlatform = true; - AZStd::map m_presets; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.cpp deleted file mode 100644 index 43f2a50535..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include - -namespace ImageProcessing -{ - - bool CubemapSettings::operator!=(const CubemapSettings& other) - { - return !(*this == other); - } - - bool CubemapSettings::operator==(const CubemapSettings& other) - { - return - m_angle == other.m_angle && - m_mipAngle == other.m_mipAngle && - m_mipSlope == other.m_mipSlope && - m_edgeFixup == other.m_edgeFixup && - m_generateDiff == other.m_generateDiff && - m_diffuseGenPreset == other.m_diffuseGenPreset; - } - - void CubemapSettings::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("Filter", &CubemapSettings::m_filter) - ->Field("Angle", &CubemapSettings::m_angle) - ->Field("MipAngle", &CubemapSettings::m_mipAngle) - ->Field("MipSlope", &CubemapSettings::m_mipSlope) - ->Field("EdgeFixup", &CubemapSettings::m_edgeFixup) - ->Field("GenerateDiff", &CubemapSettings::m_generateDiff) - ->Field("DiffuseProbePreset", &CubemapSettings::m_diffuseGenPreset); - } - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.h deleted file mode 100644 index edfdde8cbe..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/CubemapSettings.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include - -namespace ImageProcessing -{ - //! settings related to cubemap. Part of texture preset setting. only useful when cubemap enabled - struct CubemapSettings - { - AZ_TYPE_INFO(CubemapSettings, "{C6BDEB7B-8E05-4B2D-8F39-8F6275BC84E8}"); - AZ_CLASS_ALLOCATOR(CubemapSettings, AZ::SystemAllocator, 0); - bool operator!=(const CubemapSettings& other); - bool operator==(const CubemapSettings& other); - static void Reflect(AZ::ReflectContext* context); - - // "cm_ftype", cubemap angular filter type: gaussian, cone, disc, cosine, cosine_power, ggx - CubemapFilterType m_filter; - - // "cm_fangle", base filter angle for cubemap filtering(degrees), 0 - disabled - float m_angle; - - // "cm_fmipangle", initial mip filter angle for cubemap filtering(degrees), 0 - disabled - float m_mipAngle; - - // "cm_fmipslope", mip filter angle multiplier for cubemap filtering, 1 - default" - float m_mipSlope; - - // "cm_edgefixup", cubemap edge fix-up width, 0 - disabled - float m_edgeFixup; - - // "cm_diff", generate a diffuse illumination light-probe in addition - bool m_generateDiff; - - // "cm_diffpreset", the name of the preset to be used for the diffuse probe - AZ::Uuid m_diffuseGenPreset; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/ImageProcessingDefines.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/ImageProcessingDefines.h deleted file mode 100644 index c9fa860240..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/ImageProcessingDefines.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -/** -* Shorthand for checking a condition, and failing if false. -* Works with any function that returns AZ::Outcome<..., AZStd::string>. -* Unlike assert, it is not removed in release builds. -* Ensure all strings are passed with c_str(), as they are passed to AZStd::string::format(). -*/ -#define AZ_ENSURE_STRING_OUTCOME_CONDITION(cond, ...) if (!(cond)) { return AZ::Failure(AZStd::string::format(__VA_ARGS__)); } - -// Similar to above macro, but ensures on an AZ::Outcome. Not removed in release builds. -#define AZ_ENSURE_STRING_OUTCOME(outcome) if (!(outcome.IsSuccess())) { return AZ::Failure(outcome.GetError()); } - -namespace ImageProcessing -{ - //! Common return type for operations that can fail. - // Empty success string == Success. - // Populated success string == Warning. - // Populated error string == Failure. - using StringOutcome = AZ::Outcome; -#define STRING_OUTCOME_SUCCESS AZ::Success(AZStd::string()) -#define STRING_OUTCOME_WARNING(warning) AZ::Success(AZStd::string(warning)) -#define STRING_OUTCOME_ERROR(error) AZ::Failure(AZStd::string(error)) - - // Common typedefs (with dependent forward-declarations) - typedef AZStd::string PlatformName, PresetName, FileMask; - typedef AZStd::vector PlatformNameVector; - typedef AZStd::list PlatformNameList; - - //! min and max reduce level - static const unsigned int s_MinReduceLevel = 0; - static const unsigned int s_MaxReduceLevel = 5; - - static const int s_TotalSupportedImageExtensions = 8; - static const char* s_SupportedImageExtensions[s_TotalSupportedImageExtensions] = { - "*.tif", - "*.tiff", - "*.png", - "*.bmp", - "*.jpg", - "*.jpeg", - "*.tga", - "*.gif" - }; - - enum class RGBWeight : AZ::u32 - { - uniform, // uniform weights (1.0, 1.0, 1.0) (default) - luminance, // luminance-based weights (0.3086, 0.6094, 0.0820) - ciexyz // ciexyz-based weights (0.2126, 0.7152, 0.0722) - }; - - enum class ColorSpace : AZ::u32 - { - linear, - sRGB, - autoSelect, - }; - - enum class MipGenType : AZ::u32 - { - point, //Also called nearest neighbor - box, //Also called 'average'. When shrinking images it will average, and merge the pixels together. - triangle, //Also called linear or Bartlett window - quadratic, //Also called bilinear or Welch window - gaussian, //It remove high frequency noise in a highly controllable way. - blackmanHarris, - kaiserSinc //Good for foliage and tree assets exported from Speedtree. - }; - - enum class MipGenEvalType : AZ::u32 - { - sum, - max, - min - }; - - //cubemap angular filter type. Only two filter types were used in rc.ini - enum class CubemapFilterType : AZ::u32 - { - disc = 0, // same as CP_FILTER_TYPE_DISC in CubemapGen - cone = 1, // same as CP_FILTER_TYPE_CONE - cosine = 2, // same as CP_FILTER_TYPE_COSINE. only used for [EnvironmentProbeHDR_Irradiance] - gaussian = 3, // same as CP_FILTER_TYPE_ANGULAR_GAUSSIAN - cosine_power = 4, // same as CP_FILTER_TYPE_COSINE_POWER - ggx = 5 // same as CP_FILTER_TYPE_GGX. only used for [EnvironmentProbeHDR] - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.cpp deleted file mode 100644 index 0285404f50..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include -#include - -namespace ImageProcessing -{ - bool MipmapSettings::operator!=(const MipmapSettings& other) const - { - return !(*this == other); - } - - bool MipmapSettings::operator==(const MipmapSettings& other) const - { - return - m_type == other.m_type && - m_borderColor == other.m_borderColor && - m_normalize == other.m_normalize && - m_streamableMips == other.m_streamableMips; - } - - void MipmapSettings::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("MipGenType", &MipmapSettings::m_type) - ->Field("BorderColor", &MipmapSettings::m_borderColor) - ->Field("Normalize", &MipmapSettings::m_normalize) - ->Field("StreamableMips", &MipmapSettings::m_streamableMips); - - AZ::EditContext* editContext = serialize->GetEditContext(); - if (editContext) - { - editContext->Class("Mipmap Setting", "") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MipmapSettings::m_type, "Type", "") - ->EnumAttribute(MipGenType::point, "Point") - ->EnumAttribute(MipGenType::box, "Average") - ->EnumAttribute(MipGenType::triangle, "Linear") - ->EnumAttribute(MipGenType::quadratic, "Bilinear") - ->EnumAttribute(MipGenType::gaussian, "Gaussian") - ->EnumAttribute(MipGenType::blackmanHarris, "BlackmanHarris") - ->EnumAttribute(MipGenType::kaiserSinc, "KaiserSinc") - ->DataElement(AZ::Edit::UIHandlers::Color, &MipmapSettings::m_borderColor, "Color", "") - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &MipmapSettings::m_normalize, "Normalized", "") - ->DataElement(AZ::Edit::UIHandlers::SpinBox, &MipmapSettings::m_streamableMips, "Streamable Mips", "") - ->Attribute(AZ::Edit::Attributes::Min, 0) - ; - } - } - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.h deleted file mode 100644 index 4a2864d2b7..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/MipmapSettings.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - struct MipmapSettings - { - AZ_TYPE_INFO(MipmapSettings, "{9239618E-23A6-43C8-9B87-50528CBFA6FF}"); - AZ_CLASS_ALLOCATOR(MipmapSettings, AZ::SystemAllocator, 0); - bool operator!=(const MipmapSettings& other) const; - bool operator==(const MipmapSettings& other) const; - - static void Reflect(AZ::ReflectContext* context); - - MipGenType m_type = MipGenType::blackmanHarris; - - //Unused or duplicated properties. We may want to move same properties from perset setting to here. - AZ::Color m_borderColor; - bool m_normalize; - AZ::u32 m_streamableMips; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/PlatformSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/PlatformSettings.h deleted file mode 100644 index 5cfc7757b2..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/PlatformSettings.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include - -namespace ImageProcessing -{ - //! default settings for platform - struct PlatformSetting - { - AZ_TYPE_INFO(PlatformSetting, "{19EF828B-DDFF-4591-AD5A-946801FCC98E}"); - AZ_CLASS_ALLOCATOR(PlatformSetting, AZ::SystemAllocator, 0); - - //! Platform's name - PlatformName m_name; - - //! pixel formats supported for the platform - AZStd::list m_availableFormat; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.cpp deleted file mode 100644 index 8f904058d3..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include - -namespace ImageProcessing -{ - PresetSettings::PresetSettings() - : m_uuid(0) - , m_rgbWeight(RGBWeight::uniform) - , m_srcColorSpace(ColorSpace::sRGB) - , m_destColorSpace(ColorSpace::autoSelect) - , m_suppressEngineReduce(false) - , m_pixelFormat(ePixelFormat_R8G8B8A8) - , m_pixelFormatName("R8G8B8A8") - , m_pixelFormatAlpha(ePixelFormat_Unknown) - , m_pixelFormatAlphaName("") - , m_discardAlpha(false) - , m_maxTextureSize(0) - , m_minTextureSize(0) - , m_isPowerOf2(false) - , m_sizeReduceLevel(0) - , m_isColorChart(0) - , m_highPassMip(0) - , m_glossFromNormals(false) - , m_isMipRenormalize(false) - , m_numStreamableMips(100) - , m_isLegacyGloss(false) - { - - } - - PresetSettings::PresetSettings(const PresetSettings& other) - { - DeepCopyMembers(other); - } - - void PresetSettings::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("UUID", &PresetSettings::m_uuid) - ->Field("Name", &PresetSettings::m_name) - ->Field("Description", &PresetSettings::m_description) - ->Field("RGB_Weight", &PresetSettings::m_rgbWeight) - ->Field("SourceColor", &PresetSettings::m_srcColorSpace) - ->Field("DestColor", &PresetSettings::m_destColorSpace) - ->Field("FileMasks", &PresetSettings::m_fileMasks) - ->Field("SuppressEngineReduce", &PresetSettings::m_suppressEngineReduce) - ->Field("PixelFormat", &PresetSettings::m_pixelFormatName) - ->Field("PixelFormatAlpha", &PresetSettings::m_pixelFormatAlphaName) - ->Field("DiscardAlpha", &PresetSettings::m_discardAlpha) - ->Field("MaxTextureSize", &PresetSettings::m_maxTextureSize) - ->Field("MinTextureSize", &PresetSettings::m_minTextureSize) - ->Field("IsPowerOf2", &PresetSettings::m_isPowerOf2) - ->Field("SizeReduceLevel", &PresetSettings::m_sizeReduceLevel) - ->Field("IsColorChart", &PresetSettings::m_isColorChart) - ->Field("HighPassMip", &PresetSettings::m_highPassMip) - ->Field("GlossFromNormal", &PresetSettings::m_glossFromNormals) - ->Field("UseLegacyGloss", &PresetSettings::m_isLegacyGloss) - ->Field("MipRenormalize", &PresetSettings::m_isMipRenormalize) - ->Field("NumberStreamableMips", &PresetSettings::m_numStreamableMips) - ->Field("Swizzle", &PresetSettings::m_swizzle) - ->Field("CubemapSettings", &PresetSettings::m_cubemapSetting) - ->Field("MipMapSetting", &PresetSettings::m_mipmapSetting); - } - } - - PresetSettings& PresetSettings::operator= (const PresetSettings& other) - { - DeepCopyMembers(other); - return *this; - } - - bool PresetSettings::operator==(const PresetSettings& other) const - { - bool arePointersEqual = true; - - /////// - // MipMap Settings - ////// - // If both pointers are allocated... - if (m_mipmapSetting && other.m_mipmapSetting) - { - // If the allocated values are different... - if (*m_mipmapSetting != *other.m_mipmapSetting) - { - arePointersEqual = false; - } - } - // Otherwise, one or both pointers are un-allocated. - // If only one pointer is allocated (via unequivalency)... - else if (m_mipmapSetting != other.m_mipmapSetting) - { - arePointersEqual = false; - } - /////// - // CubeMap Settings - ////// - // If both pointers are allocated... - if (m_cubemapSetting && other.m_cubemapSetting) - { - // If the allocated values are different... - if (*m_cubemapSetting != *other.m_cubemapSetting) - { - arePointersEqual = false; - } - } - // Otherwise, one or both pointers are un-allocated. - // If only one pointer is allocated (via unequivalency)... - else if (m_cubemapSetting != other.m_cubemapSetting) - { - arePointersEqual = false; - } - return - arePointersEqual && - m_uuid == other.m_uuid && - m_name == other.m_name && - m_description == other.m_description && - m_rgbWeight == other.m_rgbWeight && - m_srcColorSpace == other.m_srcColorSpace && - m_destColorSpace == other.m_destColorSpace && - m_fileMasks == other.m_fileMasks && - m_suppressEngineReduce == other.m_suppressEngineReduce && - m_pixelFormat == other.m_pixelFormat && - m_pixelFormatName == other.m_pixelFormatName && - m_pixelFormatAlpha == other.m_pixelFormatAlpha && - m_pixelFormatAlphaName == other.m_pixelFormatAlphaName && - m_discardAlpha == other.m_discardAlpha && - m_minTextureSize == other.m_minTextureSize && - m_maxTextureSize == other.m_maxTextureSize && - m_isPowerOf2 == other.m_isPowerOf2 && - m_sizeReduceLevel == other.m_sizeReduceLevel && - m_isColorChart == other.m_isColorChart && - m_highPassMip == other.m_highPassMip && - m_glossFromNormals == other.m_glossFromNormals && - m_isLegacyGloss == other.m_isLegacyGloss && - m_swizzle == other.m_swizzle && - m_isMipRenormalize == other.m_isMipRenormalize && - m_numStreamableMips == other.m_numStreamableMips; - } - - void PresetSettings::DeepCopyMembers(const PresetSettings & other) - { - if (this != &other) - { - if(other.m_mipmapSetting) - { - m_mipmapSetting = AZStd::make_unique(*other.m_mipmapSetting); - } - - if(other.m_cubemapSetting) - { - m_cubemapSetting = AZStd::make_unique(*other.m_cubemapSetting); - } - - m_uuid = other.m_uuid; - m_name = other.m_name; - m_description = other.m_description; - m_rgbWeight = other.m_rgbWeight; - m_srcColorSpace = other.m_srcColorSpace; - m_destColorSpace = other.m_destColorSpace; - m_fileMasks = other.m_fileMasks; - m_suppressEngineReduce = other.m_suppressEngineReduce; - m_pixelFormat = other.m_pixelFormat; - m_pixelFormatAlpha = other.m_pixelFormatAlpha; - m_pixelFormatName = other.m_pixelFormatName; - m_pixelFormatAlphaName = other.m_pixelFormatAlphaName; - m_discardAlpha = other.m_discardAlpha; - m_minTextureSize = other.m_minTextureSize; - m_maxTextureSize = other.m_maxTextureSize; - m_isPowerOf2 = other.m_isPowerOf2; - m_sizeReduceLevel = other.m_sizeReduceLevel; - m_isColorChart = other.m_isColorChart; - m_highPassMip = other.m_highPassMip; - m_glossFromNormals = other.m_glossFromNormals; - m_isLegacyGloss = other.m_isLegacyGloss; - m_swizzle = other.m_swizzle; - m_isMipRenormalize = other.m_isMipRenormalize; - m_numStreamableMips = other.m_numStreamableMips; - } - } - - AZ::Vector3 PresetSettings::GetColorWeight() - { - switch (m_rgbWeight) - { - case RGBWeight::uniform: - return AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - case RGBWeight::ciexyz: - return AZ::Vector3(0.2126f, 0.7152f, 0.0722f); - case RGBWeight::luminance: - return AZ::Vector3(0.3086f, 0.6094f, 0.0820f); - default: - AZ_Assert(false, "color weight value need to be added to new rgbWeight enum"); - return AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - } - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.h deleted file mode 100644 index fa881e853b..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/PresetSettings.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - //settings for texture process preset - class PresetSettings - { - public: - AZ_TYPE_INFO(PresetSettings, "{935BCE3F-9E76-494E-9408-47C5937D7288}"); - AZ_CLASS_ALLOCATOR(PresetSettings, AZ::SystemAllocator, 0); - - PresetSettings(); - PresetSettings(const PresetSettings& other); - PresetSettings& operator= (const PresetSettings& other); - bool operator== (const PresetSettings& other) const; - static void Reflect(AZ::ReflectContext* context); - - //unique id for the preset - AZ::Uuid m_uuid; - - PresetName m_name; - - //a brief description for the usage of this Preset - AZStd::string m_description; - - //misc options - // "rgbweights". specify preset for weighting of R,G,B channels (used by compressor) - RGBWeight m_rgbWeight; - ColorSpace m_srcColorSpace; - ColorSpace m_destColorSpace; - - // file masks used for helping select default preset and option preset list in texture property dialog - AZStd::vector m_fileMasks; - - // "ser". Whether to enable supress reduce resolution (m_sizeReduceLevel) during loading, 0(default) - bool m_suppressEngineReduce; - - //pixel format - EPixelFormat m_pixelFormat; - AZStd::string m_pixelFormatName; - //pixel format for image which only contains alpha channel. this is for if we need to save alpha channel into a seperate image - EPixelFormat m_pixelFormatAlpha; - AZStd::string m_pixelFormatAlphaName; - bool m_discardAlpha; - - // Resolution related settings - - // "maxtexturesize", upper limit of the resolution of generated textures. It should be a power-of-2 number larger than 1 - // resulting texture will be downscaled if its width or height larger than this value - // 0 - no upper resolution limit (default) - unsigned int m_maxTextureSize; - - // "mintexturesize", lower limit of the resolution of generated textures.It should be a power-of-2 number larger than 1 - // resulting texture will be upscaled if its width or height smaller than this value - // 0 - no lower resolution limit (default) - unsigned int m_minTextureSize; - - bool m_isPowerOf2; - - //"reduce", 0=no size reduce /1=half resolution /2=quarter resolution, etc" - unsigned int m_sizeReduceLevel; - - //settings for cubemap generation. it's null if this preset is not for cubemap. - //"cm" equals 1 to enable cubemap in rc.ini - AZStd::unique_ptr m_cubemapSetting; - - //settings for mipmap generation. it's null if this preset disable mipmap. - AZStd::unique_ptr m_mipmapSetting; - - //some specific settings - // "colorchart". This is to indicate if need to extract color chart from the image and output the color chart data. - // This is very specific usage for cryEngine. Check ColorChart.cpp for better explaination. - bool m_isColorChart; - - //"highpass". Defines which mip level is subtracted when applying the high pass filter - //this is only used for terrain asset. we might remove it later since it can be done with source image directly - AZ::u32 m_highPassMip; - - //"glossfromnormals". Bake normal variance into smoothness stored in alpha channel - AZ::u32 m_glossFromNormals; - - //"mipnormalize". need normalize the rgb - bool m_isMipRenormalize; - - //function to get color's rgb weight in vec3 based on m_rgbWeight enum - //this is useful for squisher compression - AZ::Vector3 GetColorWeight(); - - //numstreamablemips - AZ::u32 m_numStreamableMips; - - //legacy options might be removed later - //"glosslegacydist". If the gloss map use legacy distribution. NW is still using legacy dist - bool m_isLegacyGloss; - - //"swizzle". need to be 4 character and each character need to be one of "rgba01" - AZStd::string m_swizzle; - - private: - void DeepCopyMembers(const PresetSettings& other); - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.cpp b/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.cpp deleted file mode 100644 index b465ec81f3..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -namespace ImageProcessing -{ - const char* TextureSettings::legacyExtensionName = ".exportsettings"; - const char* TextureSettings::modernExtensionName = ".imagesettings"; - - StringOutcome ParseLegacyTextureSettingString(AZStd::string& key, AZStd::string& value, TextureSettings& textureSettingOut) - { - // Parse only the settings we support for TextureSetting - if ("reduce" == key) // Example: reduce=0 - { - int reduce = AzFramework::StringFunc::ToInt(value.c_str()); - if (reduce >= 0) - { - textureSettingOut.m_sizeReduceLevel = reduce; - } - } - else if ("M" == key) // Example: M=50,50,0,50,50,50 - { - textureSettingOut.m_enableMipmap = true; - - AZStd::vector mipStringValues; - AzFramework::StringFunc::Tokenize(value.c_str(), mipStringValues, ','); - - for (size_t mipIndex = 0; mipIndex < mipStringValues.size(); ++mipIndex) - { - AZ::u32 mipValue = AzFramework::StringFunc::ToInt(mipStringValues[mipIndex].c_str()); - textureSettingOut.m_mipAlphaAdjust[mipIndex] = mipValue; - } - } - else if ("ser" == key) // Example: ser=1 - { - textureSettingOut.m_suppressEngineReduce = (value == "1"); - } - else if ("preset" == key) // Example: preset=NormalsWithSmoothness - { - AZ::Uuid presetUuid = BuilderSettingManager::Instance()->GetPresetIdFromName(value); - - // There's a chance the preset name still adheres to legacy preset naming convention (from CryEngine). - const PresetName translation = BuilderSettingManager::Instance()->TranslateLegacyPresetName(value); - AZ::Uuid translatedPresetUuid = BuilderSettingManager::Instance()->GetPresetIdFromName(translation); - - if (!presetUuid.IsNull()) - { - textureSettingOut.m_preset = presetUuid; - } - else if (!translatedPresetUuid.IsNull()) - { - textureSettingOut.m_preset = translatedPresetUuid; - } - else - { - AZ_Error("Image processing", false, "Can't find preset %s", value.c_str()); - } - } - else if ("mipgentype" == key) // Example: mipgentype=box - { - if ("box" == value || "average" == value) - { - textureSettingOut.m_mipGenType = MipGenType::box; - } - else if ("gauss" == value) - { - textureSettingOut.m_mipGenType = MipGenType::gaussian; - } - else if ("blackman-harris" == value) - { - textureSettingOut.m_mipGenType = MipGenType::blackmanHarris; - } - else if ("kaiser" == value) - { - textureSettingOut.m_mipGenType = MipGenType::kaiserSinc; - } - else if ("point" == value) - { - textureSettingOut.m_mipGenType = MipGenType::point; - } - else if ("quadric" == value) - { - textureSettingOut.m_mipGenType = MipGenType::quadratic; - } - else if ("triangle" == value) - { - textureSettingOut.m_mipGenType = MipGenType::triangle; - } - } - return STRING_OUTCOME_SUCCESS; - } - - TextureSettings::TextureSettings() - : m_preset(0) - , m_sizeReduceLevel(0) - , m_suppressEngineReduce(false) - , m_enableMipmap(true) - , m_maintainAlphaCoverage(false) - , m_mipGenEval(MipGenEvalType::sum) - , m_mipGenType(MipGenType::blackmanHarris) - { - const int defaultMipMapValue = 50; - - for (int i = 0; i < s_MaxMipMaps; ++i) - { - m_mipAlphaAdjust.push_back(defaultMipMapValue); - } - } - - void TextureSettings::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) - { - serialize->Class() - ->Version(1) - ->Field("PresetID", &TextureSettings::m_preset) - ->Field("SizeReduceLevel", &TextureSettings::m_sizeReduceLevel) - ->Field("EngineReduce", &TextureSettings::m_suppressEngineReduce) - ->Field("EnableMipmap", &TextureSettings::m_enableMipmap) - ->Field("MaintainAlphaCoverage", &TextureSettings::m_maintainAlphaCoverage) - ->Field("MipMapAlphaAdjustments", &TextureSettings::m_mipAlphaAdjust) - ->Field("MipMapGenEval", &TextureSettings::m_mipGenEval) - ->Field("MipMapGenType", &TextureSettings::m_mipGenType) - ->Field("PlatformSpecificOverrides", &TextureSettings::m_platfromOverrides) - ->Field("OverridingPlatform", &TextureSettings::m_overridingPlatform); - - AZ::EditContext* edit = serialize->GetEditContext(); - if (edit) - { - edit->Class("Texture Setting", "") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &TextureSettings::m_mipAlphaAdjust, "Alpha Test Bias", "Multiplies the mipmap's alpha with a scale value that is based on alpha coverage. \ - Set the mip 0 to mip 5 values to offset the alpha test values and ensure the mipmap's alpha coverage matches the original image. Specify a value from 0 to 100.") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) - ->ElementAttribute(AZ::Edit::UIHandlers::Handler, AZ::Edit::UIHandlers::Slider) - ->ElementAttribute(AZ::Edit::Attributes::Min, 0) - ->ElementAttribute(AZ::Edit::Attributes::Max, 100) - ->ElementAttribute(AZ::Edit::Attributes::Step, 1) - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &TextureSettings::m_mipGenType, "Filter Method", "") - ->EnumAttribute(MipGenType::point, "Point") - ->EnumAttribute(MipGenType::box, "Average") - ->EnumAttribute(MipGenType::triangle, "Linear") - ->EnumAttribute(MipGenType::quadratic, "Bilinear") - ->EnumAttribute(MipGenType::gaussian, "Gaussian") - ->EnumAttribute(MipGenType::blackmanHarris, "BlackmanHarris") - ->EnumAttribute(MipGenType::kaiserSinc, "KaiserSinc") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &TextureSettings::m_mipGenEval, "Pixel Sampling Type", "") - ->EnumAttribute(MipGenEvalType::max, "Max") - ->EnumAttribute(MipGenEvalType::min, "Min") - ->EnumAttribute(MipGenEvalType::sum, "Sum") - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &TextureSettings::m_maintainAlphaCoverage, "Maintain Alpha Coverage", "Select this option to manually adjust Alpha channel mipmaps.") - ; - } - } - - } - - bool TextureSettings::operator!=(const TextureSettings& other) const - { - return !(*this == other); - } - - bool TextureSettings::operator==(const TextureSettings& other) const - { - ///////////////////////////// - // Compare Alpha Adjust - ///////////////////////////// - bool matchingAlphaTestAdjust = true; - for (AZ::u8 curIndex = 0; curIndex < s_MaxMipMaps; ++curIndex) - { - if (m_mipAlphaAdjust[curIndex] != other.m_mipAlphaAdjust[curIndex]) - { - matchingAlphaTestAdjust = false; - break; - } - } - return - matchingAlphaTestAdjust && - m_preset == other.m_preset && - m_sizeReduceLevel == other.m_sizeReduceLevel && - m_suppressEngineReduce == other.m_suppressEngineReduce && - m_maintainAlphaCoverage == other.m_maintainAlphaCoverage && - m_mipGenEval == other.m_mipGenEval && - m_mipGenType == other.m_mipGenType; - } - - bool TextureSettings::Equals(const TextureSettings& other, AZ::SerializeContext* serializeContext) - { - ///////////////////////////// - // Compare Common Settings - ///////////////////////////// - if (*this != other) - { - return false; - } - - ///////////////////////////// - // Compare Overrides - ///////////////////////////// - const MultiplatformTextureSettings selfOverrides = GetMultiplatformTextureSetting(*this, serializeContext); - const MultiplatformTextureSettings otherOverrides = GetMultiplatformTextureSetting(other, serializeContext); - auto selfOverridesIter = selfOverrides.begin(); - auto otherOverridesIter = otherOverrides.begin(); - - while (selfOverridesIter != selfOverrides.end() && otherOverridesIter != otherOverrides.end()) - { - if (selfOverridesIter->second != otherOverridesIter->second) - { - return false; - } - otherOverridesIter++; - selfOverridesIter++; - } - - AZ_Assert(selfOverridesIter == selfOverrides.end() && otherOverridesIter == otherOverrides.end(), "Both iterators must be at the end by now.") - return true; - } - - float TextureSettings::ComputeMIPAlphaOffset(AZ::u32 mip) const - { - if (mip / 2 + 1 >= s_MaxMipMaps) - { - return 0; - } - - float fVal = static_cast(m_mipAlphaAdjust[s_MaxMipMaps - 1]); - if (mip / 2 + 1 < s_MaxMipMaps) - { - float fInterpolationSlider1 = static_cast(m_mipAlphaAdjust[mip / 2]); - float fInterpolationSlider2 = static_cast(m_mipAlphaAdjust[mip / 2 + 1]); - fVal = fInterpolationSlider1 + (fInterpolationSlider2 - fInterpolationSlider1) * (mip & 1) * 0.5f; - } - - return 0.5f - fVal / 100.0f; - } - - void TextureSettings::ApplyPreset(AZ::Uuid presetId) - { - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(presetId); - if (presetSetting != nullptr) - { - m_sizeReduceLevel = presetSetting->m_sizeReduceLevel; - m_suppressEngineReduce = presetSetting->m_suppressEngineReduce; - if (presetSetting->m_mipmapSetting) - { - m_mipGenType = presetSetting->m_mipmapSetting->m_type; - } - - m_preset = presetId; - } - else - { - AZ_Error("Image Processing", false, "Cannot set an invalid preset %s!", presetId.ToString().c_str()); - } - } - - StringOutcome TextureSettings::LoadTextureSetting(const AZStd::string& filepath, TextureSettings& textureSettingPtrOut, AZ::SerializeContext* serializeContext /*= nullptr*/) - { - auto loadedTextureSettingPtr = AZStd::unique_ptr(AZ::Utils::LoadObjectFromFile(filepath, serializeContext)); - - if (!loadedTextureSettingPtr) - { - return AZ::Failure(AZStd::string()); - } - - textureSettingPtrOut = *loadedTextureSettingPtr; - return AZ::Success(AZStd::string()); - } - - StringOutcome TextureSettings::WriteTextureSetting(const AZStd::string& filepath, TextureSettings& textureSetting, AZ::SerializeContext* serializeContext) - { - if(false == AZ::Utils::SaveObjectToFile(filepath, AZ::DataStream::StreamType::ST_XML, &textureSetting, serializeContext)) - { - return STRING_OUTCOME_ERROR("Failed to write to file: " + filepath); - } - - return STRING_OUTCOME_SUCCESS; - } - - StringOutcome TextureSettings::LoadLegacyTextureSetting(const AZStd::string& imagePath, const AZStd::string& contentString, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext) - { - AZStd::string trimmedContent = contentString; - AzFramework::StringFunc::TrimWhiteSpace(trimmedContent, true /* leading */, true /* trailing */); - if (trimmedContent.empty()) - { - return STRING_OUTCOME_ERROR("Empty legacy texture setting!"); - } - - AZStd::vector settings; - AZStd::vector overrideSettings; - - // Each setting begins with a forward-slash. - AzFramework::StringFunc::Tokenize(trimmedContent.c_str(), settings, " /"); // requires space character. - - // For each setting pair (field & value)... - for (AZStd::string& settingPair : settings) - { - // Split setting pair into key & value. - AZStd::string key, value; - { - AZStd::vector key_value; - AzFramework::StringFunc::Tokenize(settingPair.c_str(), key_value, '='); - if (key_value.size() == 2) - { - key = key_value[0]; - value = key_value[1]; - } - else - { - return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + settingPair); - } - } - - bool containsPlatformOverrides = !value.empty() && (value[0] == '"' && value[value.length() - 1] == '"'); - if (containsPlatformOverrides) - { - // Process platform-specific overrides on the next loop. - overrideSettings.push_back(&settingPair); - continue; - } - - // Parse the common settings. - ParseLegacyTextureSettingString(key, value, textureSettingOut); - } - - // Some setting file won't assign a proper preset for the image, need to assign a suggested one here - if (textureSettingOut.m_preset.IsNull()) - { - textureSettingOut.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imagePath); - } - - // Store a temporary settings of all platforms intended to have overrides within this preset. - // We will collate all overrides per-platform to generate PatchData at the end. - MultiplatformTextureSettings overrideCache; - - // For each platform-specific override setting pair - for (AZStd::string* overrideSettingPair : overrideSettings) - { - // Split setting pair into key & value. - AZStd::string key, value; - { - AZStd::vector key_value; - AzFramework::StringFunc::Tokenize(overrideSettingPair->c_str(), key_value, '='); - - if (key_value.size() == 2) - { - key = key_value[0]; - value = key_value[1]; - } - else - { - return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + *overrideSettingPair); - } - } - - // Chop the surrounding quotation marks. - AzFramework::StringFunc::LChop(value, 1); - AzFramework::StringFunc::RChop(value, 1); - - // Split the collection of platforms overrides into entries in a vector. - // Layout: { [platform0],[value0],[platform1],[value1],[platform2],[value2] } - AZStd::vector override_platform_value; - AzFramework::StringFunc::Tokenize(value.c_str(), override_platform_value, ",:"); - - if (override_platform_value.size() % 2 != 0) - { - return STRING_OUTCOME_ERROR("Invalid format found in legacy texture setting: " + value); - } - - for (int platformIdx = 0, valueIdx = 1; - valueIdx < override_platform_value.size(); - platformIdx += 2, valueIdx = platformIdx + 1) - { - PlatformName& overridePlatform = override_platform_value[platformIdx]; - AZStd::string& overrideValue = override_platform_value[valueIdx]; - - // Insert a copy of the base settings we've parsed from the legacy metafile. - overrideCache.insert(AZStd::pair(overridePlatform, textureSettingOut)); - - ParseLegacyTextureSettingString(key, overrideValue, overrideCache[overridePlatform]); - overrideCache[overridePlatform].m_overridingPlatform = overridePlatform; - overrideCache[overridePlatform].m_platfromOverrides.clear(); - } - } - - // Store the final result in a temp variable to do a whole-sale copy at the end. - TextureSettings finalResult = textureSettingOut; - - // Use the override cache to generate a DataPatch per-platform. - for (auto& overridePair : overrideCache) - { - // Every DataPatch is only a diff between a vanilla common-settings (with no platform-specific overrides) and the specified platform's override. - AZ::DataPatch platformOverridePatch; - platformOverridePatch.Create(&textureSettingOut, &overridePair.second,AZ::DataPatch::FlagsMap(), AZ::DataPatch::FlagsMap(), serializeContext); - finalResult.m_platfromOverrides.insert(AZStd::pair(overridePair.first, platformOverridePatch)); - } - - // Fully overwrite output variable. The only difference should be properly filled-out overrides. - textureSettingOut = finalResult; - - return STRING_OUTCOME_SUCCESS; - } - - StringOutcome TextureSettings::LoadLegacyTextureSettingFromFile(const AZStd::string& imagePath, const AZStd::string& filepath, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext) - { - AZStd::string fileContents; - - // Perform file I/O to read the contents of the metafile into the string above. - auto fileIoPtr = AZ::IO::FileIOBase::GetInstance(); - AZ::IO::HandleType fileHandle; - fileIoPtr->Open(filepath.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle); - AZ::u64 fileSize = 0; - AZ::u64 bytesRead = 0; - fileIoPtr->Size(fileHandle, fileSize); - char* fileString = new char[fileSize + 1]; - fileIoPtr->Read(fileHandle, fileString, fileSize, false, &bytesRead); - fileIoPtr->Close(fileHandle); - fileString[bytesRead] = 0; - fileContents = fileString; - delete[] fileString; - - - return LoadLegacyTextureSetting(imagePath, fileContents, textureSettingOut, serializeContext); - } - - MultiplatformTextureSettings TextureSettings::GenerateDefaultMultiplatformTextureSettings(const AZStd::string& imageFilepath) - { - MultiplatformTextureSettings settings; - PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList(); - AZ::Uuid suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath); - if (!suggestedPreset.IsNull()) - { - for (PlatformName& platform : platformsList) - { - TextureSettings textureSettings; - textureSettings.ApplyPreset(suggestedPreset); - settings.insert(AZStd::pair(platform, textureSettings)); - } - } - return settings; - } - - StringOutcome TextureSettings::GetPlatformSpecificTextureSetting(const PlatformName& platformName, const TextureSettings& baseTextureSettings, - TextureSettings& textureSettingsOut, AZ::SerializeContext* serializeContext) - { - // Obtain the DataPatch (if platform exists) - auto overrideIter = baseTextureSettings.m_platfromOverrides.find(platformName); - if (overrideIter == baseTextureSettings.m_platfromOverrides.end()) - { - return STRING_OUTCOME_ERROR(AZStd::string::format("TextureSettings preset [%s] does not have override for platform [%s]", - baseTextureSettings.m_preset.ToString().c_str(), platformName.c_str())); - } - AZ::DataPatch& platformOverride = const_cast(overrideIter->second); - - // Update settings instance with override values. - if (platformOverride.IsData()) - { - // Apply the AZ::DataPatch to obtain a platform-overridden version of the TextureSettings. - AZStd::unique_ptr platformSpecificTextureSettings(platformOverride.Apply(&baseTextureSettings, serializeContext)); - AZ_Assert(platformSpecificTextureSettings->m_mipAlphaAdjust.size() == s_MaxMipMaps, "Unexpected m_mipAlphaAdjust size."); - - // Adjust overrides data to imply 'platformSpecificTextureSettings' *IS* the override. - platformSpecificTextureSettings->m_platfromOverrides.clear(); - platformSpecificTextureSettings->m_overridingPlatform = platformName; - textureSettingsOut = *platformSpecificTextureSettings; - } - else - { - textureSettingsOut = baseTextureSettings; - } - - return STRING_OUTCOME_SUCCESS; - } - - const MultiplatformTextureSettings TextureSettings::GetMultiplatformTextureSetting(const TextureSettings& textureSettings, AZ::SerializeContext* serializeContext) - { - MultiplatformTextureSettings loadedSettingsReturn; - PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList(); - // Generate MultiplatformTextureSettings based on existing available overrides. - for (const PlatformName& curPlatformName : platformsList) - { - // Start with a copy of the base settings - TextureSettings curPlatformOverride = textureSettings; - if (!GetPlatformSpecificTextureSetting(curPlatformName, textureSettings, curPlatformOverride, serializeContext).IsSuccess()) - { - // We have failed to obtain an override. Maintain base settings to indicate zero overrides. - // We still want to designate these TextureSettings as an (empty) override. - curPlatformOverride.m_platfromOverrides.clear(); - curPlatformOverride.m_overridingPlatform = curPlatformName; - } - - // Add as an entry to the multiplatform texture settings - loadedSettingsReturn.insert(AZStd::pair(curPlatformName, curPlatformOverride)); - } - - // return a copy of the results - return loadedSettingsReturn; - } - - const MultiplatformTextureSettings TextureSettings::GetMultiplatformTextureSetting(const AZStd::string& imageFilepath, bool& canOverridePreset, AZ::SerializeContext* serializeContext) - { - TextureSettings loadedTextureSetting; - - // Attempt to get metadata filepath from image path. - AZStd::string legacyMetadataFilepath = imageFilepath + legacyExtensionName; - AZStd::string modernMetadataFilepath = imageFilepath + modernExtensionName; - bool hasLegacyMetafile = AZ::IO::SystemFile::Exists(legacyMetadataFilepath.c_str()); - bool hasModernMetafile = AZ::IO::SystemFile::Exists(modernMetadataFilepath.c_str()); - - // If the image has an accompanying metadata... - if(hasModernMetafile) - { - // Parse the metadata file. - if (!LoadTextureSetting(modernMetadataFilepath, loadedTextureSetting, serializeContext).IsSuccess()) - { - canOverridePreset = true; - return GenerateDefaultMultiplatformTextureSettings(imageFilepath); - } - } - else if (hasLegacyMetafile) - { - if (!LoadLegacyTextureSettingFromFile(imageFilepath, legacyMetadataFilepath, loadedTextureSetting, serializeContext).IsSuccess()) - { - canOverridePreset = true; - return GenerateDefaultMultiplatformTextureSettings(imageFilepath); - } - } - else - { - canOverridePreset = true; // RC could override settings if it was loaded from the image so this is set to - // true regardless of whether settings existed in the texture for compatibility. - // Try to load from image file if it has embedded setting file - AZStd::string embeddedString = LoadEmbeddedSettingFromFile(imageFilepath); - if (!LoadLegacyTextureSetting(imageFilepath, embeddedString, loadedTextureSetting, serializeContext).IsSuccess()) - { - // If the texture has neither of legacy/modern meta file nor embedded setting, generate data for a new metadata file. - return GenerateDefaultMultiplatformTextureSettings(imageFilepath); - } - } - - // Generate MultiplatformTextureSettings based on the loaded texture setting. - return GetMultiplatformTextureSetting(loadedTextureSetting, serializeContext); - } - - StringOutcome TextureSettings::ApplySettings(const TextureSettings& settings, const PlatformName& overridePlatform, AZ::SerializeContext* serializeContext) - { - if (overridePlatform.empty()) - { - *this = settings; - } - else - { - AZ::DataPatch newOverride; - if (false == newOverride.Create(this, &settings, AZ::DataPatch::FlagsMap(), AZ::DataPatch::FlagsMap(), serializeContext)) - { - return STRING_OUTCOME_ERROR("Failed to create TextureSettings platform override data. See AZ_Error log for details."); - } - - m_platfromOverrides[overridePlatform] = newOverride; - } - - return STRING_OUTCOME_SUCCESS; - } -} diff --git a/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.h b/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.h deleted file mode 100644 index 2ecc2c0a96..0000000000 --- a/Gems/ImageProcessing/Code/Source/BuilderSettings/TextureSettings.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include - -namespace ImageProcessing -{ - class TextureSettings; - typedef AZStd::map MultiplatformTextureSettings; - - class TextureSettings - { - public: - AZ_TYPE_INFO(TextureSettings, "{CC3ED018-7FF7-4233-AAD8-6D3115FD844A}"); - AZ_CLASS_ALLOCATOR(TextureSettings, AZ::SystemAllocator, 0); - - TextureSettings(); - float ComputeMIPAlphaOffset(AZ::u32 mip) const; - void ApplyPreset(AZ::Uuid presetId); - - /** - * Performs a comprehensive comparison between two TextureSettings instances. - * @param Reference to the settings which will be compared. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return True, is both instances are equivalent. - */ - bool Equals(const TextureSettings& other, AZ::SerializeContext* serializeContext = nullptr); - - /** - * Applies texture settings to the instance (including overrides). Common settings are applied, unless specific platform is specified. - * @param Reference to the settings which will be applied. - * @param Optional. Applies settings as a platform override if a platform is specified. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - StringOutcome ApplySettings(const TextureSettings& settings, const PlatformName& overridePlatform = PlatformName(), AZ::SerializeContext* serializeContext = nullptr); - - /** - * Gets platform-specific texture settings obtained from the base settings version of a pre-loaded TextureSettings instance. - * @param Name of platform to get the settings from. - * @param Base TextureSettings which we will get overrides from. - * @param Output TextureSettings which will contain the result of the function. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - static StringOutcome GetPlatformSpecificTextureSetting(const PlatformName& platformName, const TextureSettings& baseTextureSettings, TextureSettings& textureSettingsOut, AZ::SerializeContext* serializeContext = nullptr); - - static void Reflect(AZ::ReflectContext* context); - - - /** - * Loads base texture settings obtained from ".exportsettings" file (legacy setting) - * @param ImagePath absolute/relative path of the image file. - * @param FilePath absolute/relative path of the ".exportsettings" file. - * @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - static StringOutcome LoadLegacyTextureSettingFromFile(const AZStd::string& imagePath, const AZStd::string& filepath, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext = nullptr); - - /** - * Loads base texture settings obtained from a legacy setting string - * @param ImagePath absolute/relative path of the image file. - * @param Content string of the legacy setting to be read. - * @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - static StringOutcome LoadLegacyTextureSetting(const AZStd::string& imagePath, const AZStd::string& contentString, TextureSettings& textureSettingOut, AZ::SerializeContext* serializeContext = nullptr); - - /** - * Loads base texture settings obtained from ".imagesettings" file (modern setting) - * @param FilePath absolute/relative path of the ".imagesettings" file. - * @param Output TextureSettings which contain the result of the function, it may contains platform-specific overrides. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - static StringOutcome LoadTextureSetting(const AZStd::string& filepath, TextureSettings& textureSettingPtrOut, AZ::SerializeContext* serializeContext = nullptr); - - /** - * Writes base texture settings to a ".imagesettings" file (modern setting) - * @param FilePath absolute/relative path of the ".imagesettings" file. - * @param TextureSetting to be written on the disk, it may contains platform-specific overrides. - * @param Optional. Serialize context. Will use global context if none is provided. - * @return Status outcome result. - */ - static StringOutcome WriteTextureSetting(const AZStd::string& filepath, TextureSettings& textureSetting, AZ::SerializeContext* serializeContext = nullptr); - - // Generates a MultiplatformTextureSettings collection with default texture settings for all - static MultiplatformTextureSettings GenerateDefaultMultiplatformTextureSettings(const AZStd::string& imageFilepath); - - /** - * Generates a TextureSetting instance of a particular image file for each supported platform. - * @param filepath - A path to the texture file. - * @param canOverridePreset - Returns whether the preset can be overriden. Will return false if the preset was selecting from a settings file created by the user. - * @param serializeContext - Optional. Serialize context used for reflection/serialization - * @return - The collection of TextureSetting instances. If error occurs, a default MultiplatformTextureSettings is returned (see GenerateDefaultMultiplatformTextureSettings()). - */ - static const MultiplatformTextureSettings GetMultiplatformTextureSetting(const AZStd::string& filepath, bool& canOverridePreset, AZ::SerializeContext* serializeContext = nullptr); - - /** - * Generates a TextureSetting instance of a particular image file for each supported platform. - * @param textureSettings - A reference to an already-loaded texture settings. - * @param serializeContext - Optional. Serialize context used for reflection/serialization - * @return - The collection of TextureSetting instances. If error occurs, a default MultiplatformTextureSettings is returned (see GenerateDefaultMultiplatformTextureSettings()). - */ - static const MultiplatformTextureSettings GetMultiplatformTextureSetting(const TextureSettings& textureSettings, AZ::SerializeContext* serializeContext = nullptr); - - static const char* legacyExtensionName; - static const char* modernExtensionName; - static const size_t s_MaxMipMaps = 6; - - // uuid of selected preset for this texture - AZ::Uuid m_preset; - - // texture size reduce level. the value of this variable will override the same variable in PresetSettings - unsigned int m_sizeReduceLevel; - - // "ser". Whether to enable supress reduce resolution (m_sizeReduceLevel) during loading, 0(default) - // the value of this variable will override the same variable in PresetSettings - bool m_suppressEngineReduce; - - //enable generate mipmap or not - bool m_enableMipmap; - - //"mc". not used in rc.ini. experiemental - //maybe relate to http://the-witness.net/news/2010/09/computing-alpha-mipmaps/ - bool m_maintainAlphaCoverage; - - // "M", adjust mipalpha, 0..50=normal..100. associate with ComputeMIPAlphaOffset function - // only useful if m_maintainAlphaCoverage set to true. - // This data type MUST be an AZStd::vector, even though we treat is as a fixed array. This is due to a limitation - // during AZ::DataPatch serialization, where an element is allocated one by one while extending the container.. - AZStd::vector m_mipAlphaAdjust; - - MipGenEvalType m_mipGenEval; - - MipGenType m_mipGenType; - - private: - // Platform overrides in form of DataPatch. Each entry is a patch for a specified platform. - // This map is used to generate TextureSettings with overridden values. The map is empty if - // the instance is for platform-specific settings. - AZStd::map m_platfromOverrides; - - // The platform which these settings override. - // Blank if the instance is for common settings. - PlatformName m_overridingPlatform; - - // Comparison operators only compare the base settings, they do not compare overrides. - // For a comprehensive equality comparison, use Equals() function. - bool operator==(const TextureSettings& other) const; - bool operator!=(const TextureSettings& other) const; - - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.cpp b/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.cpp deleted file mode 100644 index efb9d85cab..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include - -#include - -namespace ImageProcessing -{ - struct CrySquisherCallbackUserData - { - IImageObjectPtr m_pImageObject; - AZ::u8* m_dstMem; - AZ::u32 m_dstOffset; - }; - - // callbacks for the CryTextureSquisher - void CrySquisherOutputCallback(const CryTextureSquisher::CompressorParameters& compress, const void* data, AZ::u32 size, AZ::u32 oy, AZ::u32 ox) - { - CrySquisherCallbackUserData* const pUserData = (CrySquisherCallbackUserData*)compress.userPtr; - - AZ::u32 stride = (compress.width + 3) >> 2; - AZ::u32 blocks = (compress.height + 3) >> 2; - memcpy(pUserData->m_dstMem + size * (stride * oy + ox), data, size); - pUserData->m_dstOffset = size * (stride * blocks); - } - - void CrySquisherInputCallback(const CryTextureSquisher::DecompressorParameters& decompress, void* data, AZ::u32 size, AZ::u32 oy, AZ::u32 ox) - { - CrySquisherCallbackUserData* const pUserData = (CrySquisherCallbackUserData*)decompress.userPtr; - AZ::u32 stride = (decompress.width + 3) >> 2; - AZ::u32 blocks = (decompress.height + 3) >> 2; - - //assert(CPixelFormats::GetPixelFormatInfo(pUserData->m_pImageObject->GetPixelFormat())->bCompressed); - - memcpy(data, pUserData->m_dstMem + size * (stride * oy + ox), size); - - pUserData->m_dstOffset = size * (stride * blocks); - } - - - CryTextureSquisher::ECodingPreset CTSquisher::GetCompressPreset(EPixelFormat compressFmt, EPixelFormat uncompressFmt) - { - CryTextureSquisher::ECodingPreset preset = CryTextureSquisher::eCompressorPreset_Num; - switch (compressFmt) - { - case ePixelFormat_BC1: - preset = CryTextureSquisher::eCompressorPreset_BC1U; - break; - case ePixelFormat_BC1a: - preset = CryTextureSquisher::eCompressorPreset_BC1Ua; - break; - case ePixelFormat_BC3: - preset = CryTextureSquisher::eCompressorPreset_BC3U; - break; - case ePixelFormat_BC3t: - preset = CryTextureSquisher::eCompressorPreset_BC3Ut; - break; - case ePixelFormat_BC4: - preset = (CPixelFormats::GetInstance().IsFormatSingleChannel(uncompressFmt) - ? CryTextureSquisher::eCompressorPreset_BC4Ua // a-channel - : CryTextureSquisher::eCompressorPreset_BC4U); // r-channel - break; - case ePixelFormat_BC4s: - preset = (CPixelFormats::GetInstance().IsFormatSingleChannel(uncompressFmt) - ? CryTextureSquisher::eCompressorPreset_BC4Sa // a-channel - : CryTextureSquisher::eCompressorPreset_BC4S); // r-channel - break; - case ePixelFormat_BC5: - preset = CryTextureSquisher::eCompressorPreset_BC5Un; - break; - case ePixelFormat_BC5s: - preset = CryTextureSquisher::eCompressorPreset_BC5Sn; - break; - case ePixelFormat_BC6UH: - preset = CryTextureSquisher::eCompressorPreset_BC6UH; - break; - case ePixelFormat_BC7: - preset = CryTextureSquisher::eCompressorPreset_BC7U; - break; - case ePixelFormat_BC7t: - preset = CryTextureSquisher::eCompressorPreset_BC7Ut; - break; - default: - AZ_Assert(false, "%s: Unexpected pixel format (in compressing an image). Inform an RC programmer.", __FUNCTION__); - } - - return preset; - } - - bool CTSquisher::IsCompressedPixelFormatSupported(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_BC1: - case ePixelFormat_BC1a: - case ePixelFormat_BC3: - case ePixelFormat_BC3t: - case ePixelFormat_BC4: - case ePixelFormat_BC4s: - case ePixelFormat_BC5: - case ePixelFormat_BC5s: - case ePixelFormat_BC6UH: - case ePixelFormat_BC7: - case ePixelFormat_BC7t: - return true; - default: - return false; - } - } - - bool CTSquisher::IsUncompressedPixelFormatSupported(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_R8: - case ePixelFormat_A8: - case ePixelFormat_R8G8B8A8: - case ePixelFormat_R8G8B8X8: - case ePixelFormat_R32F: - case ePixelFormat_R32G32B32A32F: - return true; - default: - return false; - } - } - - bool CTSquisher::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst) - { - return true; - } - - EPixelFormat CTSquisher::GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) - { - //special cases - if (compressedfmt == ePixelFormat_BC6UH || compressedfmt == ePixelFormat_BC5 || compressedfmt == ePixelFormat_BC5s) - { - return ePixelFormat_R32G32B32A32F; - } - - if (IsUncompressedPixelFormatSupported(uncompressedfmt)) - { - return uncompressedfmt; - } - - //for fmt dont support, convert to supported uncompressed formats: ePixelFormat_A8, ePixelFormat_R8, ePixelFormat_A8R8G8B8, - // ePixelFormat_X8R8G8B8, ePixelFormat_R32F, ePixelFormat_A32B32G32R32F - - switch (uncompressedfmt) - { - case ePixelFormat_R8G8: - case ePixelFormat_R16G16: - return ePixelFormat_R8G8B8X8; - case ePixelFormat_R16: - return ePixelFormat_R8; - case ePixelFormat_R16G16B16A16: - case ePixelFormat_B8G8R8A8: - return ePixelFormat_R8G8B8A8; - case ePixelFormat_R9G9B9E5: - case ePixelFormat_R32G32F: - case ePixelFormat_R16G16B16A16F: - case ePixelFormat_R16G16F: - return ePixelFormat_R32G32B32A32F; - case ePixelFormat_R16F: - return ePixelFormat_R32F; - default: - //this shouldn't happen. but we could handle it with uncompressed data anyway - if (CPixelFormats::GetInstance().IsPixelFormatWithoutAlpha(uncompressedfmt)) - { - return ePixelFormat_R8G8B8X8; - } - else - { - return ePixelFormat_R8G8B8A8; - } - } - } - - IImageObjectPtr CTSquisher::DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) - { - // Decompressing - // the output pixel format could only have one channel or four channels. need to find out more - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be compressed and dst format need to uncompressed. - if (!IsCompressedPixelFormatSupported(fmtSrc) || !IsUncompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //clear the dstImage to (0, 0, 0, 1) since some compression format only write to certain channels - dstImage->ClearColor(0, 0, 0, 1); - - //for each mipmap - const AZ::u32 mipCount = srcImage->GetMipCount(); - for (AZ::u32 dwMip = 0; dwMip < mipCount; ++dwMip) - { - const AZ::u32 dwLocalWidth = srcImage->GetWidth(dwMip); - const AZ::u32 dwLocalHeight = srcImage->GetHeight(dwMip); - - AZ::u8* pSrcMem; - AZ::u32 dwSrcPitch; - srcImage->GetImagePointer(dwMip, pSrcMem, dwSrcPitch); - - AZ::u8* pDstMem; - AZ::u32 dwDstPitch; - dstImage->GetImagePointer(dwMip, pDstMem, dwDstPitch); - - CrySquisherCallbackUserData userData; - userData.m_pImageObject = srcImage; - userData.m_dstOffset = 0; - userData.m_dstMem = pSrcMem; - - CryTextureSquisher::DecompressorParameters decompress; - - decompress.dstBuffer = pDstMem; - decompress.width = dwLocalWidth; - decompress.height = dwLocalHeight; - decompress.pitch = dwDstPitch; - - decompress.dstType = (CPixelFormats::GetInstance().IsFormatFloatingPoint(fmtDst, true) ? - CryTextureSquisher::eBufferType_ufloat : CryTextureSquisher::eBufferType_uint8); - - if (CPixelFormats::GetInstance().IsFormatSigned(fmtSrc)) - { - decompress.dstType = (decompress.dstType == CryTextureSquisher::eBufferType_ufloat ? - CryTextureSquisher::eBufferType_sfloat : CryTextureSquisher::eBufferType_sint8); - } - - decompress.userPtr = &userData; - decompress.userInputFunction = CrySquisherInputCallback; - decompress.preset = GetCompressPreset(fmtSrc, fmtDst); - - CryTextureSquisher::Decompress(decompress); - } - - // CTsquish operates on native normal vectors when floating-point - // buffers are used. Apply bias and scale when returning a normal-map. - if (fmtSrc == ePixelFormat_BC5 || fmtSrc == ePixelFormat_BC5s) - { - if (fmtDst == ePixelFormat_R32G32B32A32F) - { - //conver from [-1, 1] to [0, 1]. And set alpha to 1. - dstImage->ScaleAndBiasChannels(0, 100, - AZ::Vector4(0.5f, 0.5f, 0.5f, 0.0f), - AZ::Vector4(0.5f, 0.5f, 0.5f, 1.0f)); - } - } - - return dstImage; - } - - /////////////////////////////////////////////////////////////////////////////////// - IImageObjectPtr CTSquisher::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, - const CompressOption *compressOption) - { - // Compressing - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be uncompressed and dst format need to compressed. - if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //passing compress option - ICompressor::EQuality quality = ICompressor::eQuality_Normal; - AZ::Vector3 weights = AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - if (compressOption) - { - quality = compressOption->compressQuality; - weights = compressOption->rgbWeight; - } - - //do some clamp for float - if (fmtSrc == ePixelFormat_R32G32B32A32F) - { - const uint32 nMips = srcImage->GetMipCount(); - - // NOTES: - // - all incoming images are unsigned, even normal maps - // - all mipmaps of incoming images can contain out-of-range values from mipmap filtering - // - 3Dc/BC5 is synonymous with "is a normal map" because they are not tagged explicitly as such - if (fmtDst == ePixelFormat_BC5 || fmtDst == ePixelFormat_BC5s) - { - srcImage->ScaleAndBiasChannels(0, nMips, - AZ::Vector4(2.0f, 2.0f, 2.0f, 1.0f), - AZ::Vector4(-1.0f, -1.0f, -1.0f, 0.0f)); - srcImage->ClampChannels(0, nMips, - AZ::Vector4(-1.0f, -1.0f, -1.0f, -1.0f), - AZ::Vector4(1.0f, 1.0f, 1.0f, 1.0f)); - } - else if (fmtDst == ePixelFormat_BC6UH) - { - srcImage->ClampChannels(0, nMips, - AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f), - AZ::Vector4(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX)); - } - else - { - srcImage->ClampChannels(0, nMips, - AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f), - AZ::Vector4(1.0f, 1.0f, 1.0f, 1.0f)); - } - } - - const uint32 mipCount = dstImage->GetMipCount(); - for (uint32 dwMip = 0; dwMip < mipCount; ++dwMip) - { - uint32 dwLocalWidth = srcImage->GetWidth(dwMip); - uint32 dwLocalHeight = srcImage->GetHeight(dwMip); - - uint8* pSrcMem; - uint32 dwSrcPitch; - srcImage->GetImagePointer(dwMip, pSrcMem, dwSrcPitch); - - uint8* pDstMem; - uint32 dwDstPitch; - dstImage->GetImagePointer(dwMip, pDstMem, dwDstPitch); - - { - CrySquisherCallbackUserData userData; - userData.m_pImageObject = dstImage; - userData.m_dstOffset = 0; - userData.m_dstMem = pDstMem; - - CryTextureSquisher::CompressorParameters compress; - - compress.srcBuffer = pSrcMem; - compress.width = dwLocalWidth; - compress.height = dwLocalHeight; - compress.pitch = dwSrcPitch; - - compress.srcType = (CPixelFormats::GetInstance().IsFormatFloatingPoint(fmtSrc, true) ? - CryTextureSquisher::eBufferType_ufloat : CryTextureSquisher::eBufferType_uint8); - if (CPixelFormats::GetInstance().IsFormatSigned(fmtDst)) - { - compress.srcType = (compress.srcType == CryTextureSquisher::eBufferType_ufloat ? - CryTextureSquisher::eBufferType_sfloat : CryTextureSquisher::eBufferType_sint8); - } - - const AZ::Vector3 uniform = AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - - compress.weights[0] = weights.GetX(); - compress.weights[1] = weights.GetY(); - compress.weights[2] = weights.GetZ(); - - compress.perceptual = - (compress.weights[0] != uniform.GetX()) || - (compress.weights[1] != uniform.GetY()) || - (compress.weights[2] != uniform.GetZ()); - - compress.quality = - (quality == eQuality_Preview ? CryTextureSquisher::eQualityProfile_Low : - (quality == eQuality_Fast ? CryTextureSquisher::eQualityProfile_Low : - (quality == eQuality_Slow ? CryTextureSquisher::eQualityProfile_High : - CryTextureSquisher::eQualityProfile_Medium))); - - compress.userPtr = &userData; - compress.userOutputFunction = CrySquisherOutputCallback; - compress.preset = GetCompressPreset(fmtDst, fmtSrc); - - CryTextureSquisher::Compress(compress); - } - } // for: all mips - - return dstImage; - } - -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.h b/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.h deleted file mode 100644 index 6cb08ac295..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CTSquisher.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include - -namespace ImageProcessing -{ - //Cry Texture Squisher for all the BC compressions - class CTSquisher : public ICompressor - { - public: - static bool IsCompressedPixelFormatSupported(EPixelFormat fmt); - static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt); - static bool DoesSupportDecompress(EPixelFormat fmtDst); - - IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override; - IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override; - - EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override; - - - private: - static CryTextureSquisher::ECodingPreset GetCompressPreset(EPixelFormat compressFmt, EPixelFormat uncompressFmt); - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/Compressor.cpp b/Gems/ImageProcessing/Code/Source/Compressors/Compressor.cpp deleted file mode 100644 index fe151d8954..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/Compressor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include - -namespace ImageProcessing -{ - ICompressorPtr ICompressor::FindCompressor(EPixelFormat fmt, bool isCompressing) - { - if (CTSquisher::IsCompressedPixelFormatSupported(fmt)) - { - if (isCompressing || (!isCompressing && CTSquisher::DoesSupportDecompress(fmt))) - { - return ICompressorPtr(new CTSquisher()); - } - } - - // Both ETC2Compressor and PVRTCCompressor can process ETC formats - // According to Mobile team, Etc2Com is faster than PVRTexLib, so we check with ETC2Compressor before PVRTCCompressor - // Note: with the test I have done, I found out it cost similar time for both Etc2Com and PVRTexLib to compress - // a 2048x2048 test texture to EAC_R11 and EAC_RG11. It was around 7 minutes for EAC_R11 and 14 minutes for EAC_RG11 - if (ETC2Compressor::IsCompressedPixelFormatSupported(fmt)) - { - if (isCompressing || (!isCompressing && ETC2Compressor::DoesSupportDecompress(fmt))) - { - return ICompressorPtr(new ETC2Compressor()); - } - } - - if (PVRTCCompressor::IsCompressedPixelFormatSupported(fmt)) - { - if (isCompressing || (!isCompressing && PVRTCCompressor::DoesSupportDecompress(fmt))) - { - return ICompressorPtr(new PVRTCCompressor()); - } - } - - return nullptr; - } - - ICompressor::~ICompressor() - { - - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/Compressor.h b/Gems/ImageProcessing/Code/Source/Compressors/Compressor.h deleted file mode 100644 index 14fb6d2b9a..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/Compressor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include - -namespace ImageProcessing -{ - class ICompressor; - typedef AZStd::shared_ptr ICompressorPtr; - - //the interface base class for any compressors which can decompress/compress image with compressed pixel format - class ICompressor - { - public: - enum EQuality - { - eQuality_Preview, // for the 256x256 preview only - eQuality_Fast, - eQuality_Normal, - eQuality_Slow, - }; - - //some extra information required for different compressors. - //keep is a simple structure for now. - struct CompressOption - { - EQuality compressQuality = eQuality_Normal; - //required for CTSquisher - AZ::Vector3 rgbWeight = AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - }; - - public: - //compress the source image to desired compressed pixel format - virtual IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) = 0; - virtual IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) = 0; - virtual EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) = 0; - - //find compressor for specified compressed pixel format. isCompressing to indicate if it's for compressing or decompressing - static ICompressorPtr FindCompressor(EPixelFormat fmt, bool isCompressing); - - virtual ~ICompressor() = 0; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.cpp b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.cpp deleted file mode 100644 index b436e7bbc2..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -#include - -#include "ColorBlockRGBA4x4c.h" - -namespace ImageProcessing -{ - static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!"); - - void ColorBlockRGBA4x4c::setRGBA8(const void* imgBGRA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgBGRA8, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBA8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA8* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const uint8* const pSrc = ((const uint8*)imgBGRA8) + (pitch * (y + row)) + (x * sizeof(ColorRGBA8)); - - ColorRGBA8* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const uint8* const pSrc = ((const uint8*)imgBGRA8) + pitch * (y + by); - - ColorRGBA8* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - } - } - } - } - - void ColorBlockRGBA4x4c::getRGBA8(void* imgRGBA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgRGBA8, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBA8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA8* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - uint8* const pDst = ((uint8*)imgRGBA8) + (pitch * (y + row)) + (x * sizeof(ColorRGBA8)); - - const ColorRGBA8* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBA8) / sizeof(*pDst)]); - pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBA8) / sizeof(*pDst)]); - pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBA8) / sizeof(*pDst)]); - pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBA8) / sizeof(*pDst)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - uint8* const pDst = ((uint8*)imgRGBA8) + pitch * (y + by); - - const ColorRGBA8* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBA8) / sizeof(*pSrc)]); - } - } - } - } - - void ColorBlockRGBA4x4c::setA8(const void* imgA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgA8, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA8* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const uint8* const pSrc = ((const uint8*)imgA8) + (pitch * (y + row)) + (x * sizeof(uint8)); - - ColorRGBA8* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(0, 0, 0, pSrc[0]); - pDst[1].setRGBA(0, 0, 0, pSrc[1]); - pDst[2].setRGBA(0, 0, 0, pSrc[2]); - pDst[3].setRGBA(0, 0, 0, pSrc[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const uint8* const pSrc = ((const uint8*)imgA8) + pitch * (y + by); - - ColorRGBA8* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]); - } - } - } - } - - void ColorBlockRGBA4x4c::getA8(void* imgA8, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgA8, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA8* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - uint8* const pDst = ((uint8*)imgA8) + (pitch * (y + row)) + (x * sizeof(uint8)); - uint8 r, g, b; - - const ColorRGBA8* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(r, g, b, pDst[0]); - pSrc[1].getRGBA(r, g, b, pDst[1]); - pSrc[2].getRGBA(r, g, b, pDst[2]); - pSrc[3].getRGBA(r, g, b, pDst[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - uint8* const pDst = ((uint8*)imgA8) + pitch * (y + by); - uint8 r, g, b; - - const ColorRGBA8* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(r, g, b, pDst[x + bx]); - } - } - } - } - - bool ColorBlockRGBA4x4c::isSingleColorIgnoringAlpha() const - { - for (unsigned int i = 1; i < COLOR_COUNT; ++i) - { - if ((m_color[0].b != m_color[i].b) || - (m_color[0].g != m_color[i].g) || - (m_color[0].r != m_color[i].r)) - { - return false; - } - } - - return true; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.h b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.h deleted file mode 100644 index 06f0ac00ed..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - - -#include "ColorTypes.h" - -namespace ImageProcessing -{ - // Uncompressed 4x4 color block of 8bit integers. - struct ColorBlockRGBA4x4c - { - ColorBlockRGBA4x4c() - { - } - - void setRGBA8(const void* imgBGRA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getRGBA8(void* imgBGRA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - void setA8(const void* imgA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getA8(void* imgA8, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - bool isSingleColorIgnoringAlpha() const; - - const ColorRGBA8* colors() const - { - return m_color; - } - - ColorRGBA8* colors() - { - return m_color; - } - - ColorRGBA8 color(unsigned int i) const - { - return m_color[i]; - } - - ColorRGBA8& color(unsigned int i) - { - return m_color[i]; - } - - private: - static const unsigned int COLOR_COUNT = 4 * 4; - - ColorRGBA8 m_color[COLOR_COUNT]; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.cpp b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.cpp deleted file mode 100644 index 20db26100a..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -#include - -#include "ColorBlockRGBA4x4f.h" - -namespace ImageProcessing -{ - static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!"); - - void ColorBlockRGBA4x4f::setRGBAf(const void* imgRGBAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgRGBAf, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBAf), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorRGBAf* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const float* const pSrc = (const float*)(((const uint8*)imgRGBAf) + (pitch * (y + row)) + (x * sizeof(ColorRGBAf))); - - ColorRGBAf* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBAf) / sizeof(*pSrc)]); - pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBAf) / sizeof(*pSrc)]); - pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBAf) / sizeof(*pSrc)]); - pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBAf) / sizeof(*pSrc)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const float* const pSrc = (const float*)(((const uint8*)imgRGBAf) + pitch * (y + by)); - - ColorRGBAf* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBAf) / sizeof(*pSrc)]); - } - } - } - } - - void ColorBlockRGBA4x4f::getRGBAf(void* imgRGBAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgRGBAf, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBAf), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorRGBAf* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - float* const pDst = (float*)(((uint8*)imgRGBAf) + (pitch * (y + row)) + (x * sizeof(ColorRGBAf))); - - const ColorRGBAf* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBAf) / sizeof(*pDst)]); - pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBAf) / sizeof(*pDst)]); - pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBAf) / sizeof(*pDst)]); - pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBAf) / sizeof(*pDst)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - float* const pDst = (float*)(((uint8*)imgRGBAf) + pitch * (y + by)); - - const ColorRGBAf* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBAf) / sizeof(*pDst)]); - } - } - } - } - - void ColorBlockRGBA4x4f::setAf(const void* imgAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgAf, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(float), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorRGBAf* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const float* const pSrc = (const float*)(((const uint8*)imgAf) + (pitch * (y + row)) + (x * sizeof(float))); - - ColorRGBAf* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(0, 0, 0, pSrc[0]); - pDst[1].setRGBA(0, 0, 0, pSrc[1]); - pDst[2].setRGBA(0, 0, 0, pSrc[2]); - pDst[3].setRGBA(0, 0, 0, pSrc[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const float* const pSrc = (const float*)(((const uint8*)imgAf) + (pitch * (y + by))); - - ColorRGBAf* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]); - } - } - } - } - - void ColorBlockRGBA4x4f::getAf(void* imgAf, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgAf, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(float), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorRGBAf* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - float* const pDst = (float*)(((uint8*)imgAf) + (pitch * (y + row)) + (x * sizeof(float))); - float r, g, b; - - const ColorRGBAf* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(r, g, b, pDst[0]); - pSrc[1].getRGBA(r, g, b, pDst[1]); - pSrc[2].getRGBA(r, g, b, pDst[2]); - pSrc[3].getRGBA(r, g, b, pDst[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - float* const pDst = (float*)(((uint8*)imgAf) + pitch * (y + by)); - float r, g, b; - - const ColorRGBAf* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(r, g, b, pDst[x + bx]); - } - } - } - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.h b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.h deleted file mode 100644 index 0235dd18db..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include "ColorTypes.h" - -namespace ImageProcessing -{ - // Uncompressed 4x4 color block of single precision floating points. - struct ColorBlockRGBA4x4f - { - ColorBlockRGBA4x4f() - { - } - - void setRGBAf(const void* imgARGBf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getRGBAf(void* imgARGBf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - void setAf(const void* imgAf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getAf(void* imgAf, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - const ColorRGBAf* colors() const - { - return m_color; - } - - ColorRGBAf* colors() - { - return m_color; - } - - ColorRGBAf color(unsigned int i) const - { - return m_color[i]; - } - - ColorRGBAf& color(unsigned int i) - { - return m_color[i]; - } - - private: - static const unsigned int COLOR_COUNT = 4 * 4; - - ColorRGBAf m_color[COLOR_COUNT]; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.cpp b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.cpp deleted file mode 100644 index 9e95a23f17..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -#include - -#include "ColorBlockRGBA4x4s.h" - -namespace ImageProcessing -{ - static_assert(sizeof(int) == 4, "Expected size of int to be 4 bytes!"); - - void ColorBlockRGBA4x4s::setRGBA16(const void* imgBGRA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgBGRA16, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBA16), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA16* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const uint16* const pSrc = (const uint16*)(((const uint8*)imgBGRA16) + (pitch * (y + row)) + (x * sizeof(ColorRGBA16))); - - ColorRGBA16* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(&pSrc[0 * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - pDst[1].setRGBA(&pSrc[1 * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - pDst[2].setRGBA(&pSrc[2 * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - pDst[3].setRGBA(&pSrc[3 * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const uint16* const pSrc = (const uint16*)(((const uint8*)imgBGRA16) + pitch * (y + by)); - - ColorRGBA16* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(&pSrc[(x + bx) * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - } - } - } - } - - void ColorBlockRGBA4x4s::getRGBA16(void* imgBGRA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgBGRA16, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(ColorRGBA16), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA16* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - uint16* const pDst = (uint16*)(((uint8*)imgBGRA16) + (pitch * (y + row)) + (x * sizeof(ColorRGBA16))); - - const ColorRGBA16* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(&pDst[0 * sizeof(ColorRGBA16) / sizeof(*pDst)]); - pSrc[1].getRGBA(&pDst[1 * sizeof(ColorRGBA16) / sizeof(*pDst)]); - pSrc[2].getRGBA(&pDst[2 * sizeof(ColorRGBA16) / sizeof(*pDst)]); - pSrc[3].getRGBA(&pDst[3 * sizeof(ColorRGBA16) / sizeof(*pDst)]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - uint16* const pDst = (uint16*)(((uint8*)imgBGRA16) + pitch * (y + by)); - - const ColorRGBA16* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(&pDst[(x + bx) * sizeof(ColorRGBA16) / sizeof(*pSrc)]); - } - } - } - } - - void ColorBlockRGBA4x4s::setA16(const void* imgA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgA16, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA16* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - const uint16* const pSrc = (const uint16*)(((const uint8*)imgA16) + (pitch * (y + row)) + (x * sizeof(uint16))); - - ColorRGBA16* const pDst = &m_color[row << 2]; - - pDst[0].setRGBA(0, 0, 0, pSrc[0]); - pDst[1].setRGBA(0, 0, 0, pSrc[1]); - pDst[2].setRGBA(0, 0, 0, pSrc[2]); - pDst[3].setRGBA(0, 0, 0, pSrc[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - const uint16* const pSrc = (const uint16*)(((const uint8*)imgA16) + pitch * (y + by)); - - ColorRGBA16* pDst = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pDst[col].setRGBA(0, 0, 0, pSrc[x + bx]); - } - } - } - } - - void ColorBlockRGBA4x4s::getA16(void* imgA16, unsigned int const width, unsigned int const height, unsigned int const pitch, unsigned int x, unsigned int y) - { - AZ_Assert(imgA16, "%s: Unexpected image pointer", __FUNCTION__); - AZ_Assert((width & 3) == 0, "%s: Unexpected image width", __FUNCTION__); - AZ_Assert((height & 3) == 0, "%s: Unexpected image height", __FUNCTION__); - AZ_Assert(pitch >= width * sizeof(uint8), "%s: Unexpected image pitch", __FUNCTION__); - AZ_Assert(x < width, "%s: Unexpected pixel position x", __FUNCTION__); - AZ_Assert(y < height, "%s: Unexpected pixel position y", __FUNCTION__); - - const unsigned int bw = AZ::GetMin(width - x, 4U); - const unsigned int bh = AZ::GetMin(height - y, 4U); - - // note: it's allowed for source data to be not aligned to 4 byte boundary - // (so, we cannot cast source data pointer to ColorBGRA16* in code below) - - if ((bw == 4) && (bh == 4)) - { - for (unsigned int row = 0; row < 4; ++row) - { - uint16* const pDst = (uint16*)(((uint8*)imgA16) + (pitch * (y + row)) + (x * sizeof(uint16))); - uint16 r, g, b; - - const ColorRGBA16* const pSrc = &m_color[row << 2]; - - pSrc[0].getRGBA(r, g, b, pDst[0]); - pSrc[1].getRGBA(r, g, b, pDst[1]); - pSrc[2].getRGBA(r, g, b, pDst[2]); - pSrc[3].getRGBA(r, g, b, pDst[3]); - } - } - else - { - // Rare case: block is smaller than 4x4. - // Let's repeat pixels in this case. - // It will keep frequency of colors, except the case - // when width and/or height equals 3. But, this case - // is very rare because images usually are "power of 2" sized, and even - // if they are not, nobody will notice that the resulting encoding - // for such block is not ideal. - - static unsigned int remainder[] = - { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - for (unsigned int row = 0; row < 4; ++row) - { - const unsigned int by = remainder[(bh - 1) * 4 + row]; - uint16* const pDst = (uint16*)(((uint8*)imgA16) + pitch * (y + by)); - uint16 r, g, b; - - const ColorRGBA16* const pSrc = &m_color[row * 4]; - - for (unsigned int col = 0; col < 4; ++col) - { - const unsigned int bx = remainder[(bw - 1) * 4 + col]; - - pSrc[col].getRGBA(r, g, b, pDst[x + bx]); - } - } - } - } - - bool ColorBlockRGBA4x4s::isSingleColorIgnoringAlpha() const - { - for (unsigned int i = 1; i < COLOR_COUNT; ++i) - { - if ((m_color[0].b != m_color[i].b) || - (m_color[0].g != m_color[i].g) || - (m_color[0].r != m_color[i].r)) - { - return false; - } - } - - return true; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.h b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.h deleted file mode 100644 index 3c4b47cae7..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - - -#include "ColorTypes.h" - -namespace ImageProcessing -{ - // Uncompressed 4x4 color block of 16bit integers. - struct ColorBlockRGBA4x4s - { - ColorBlockRGBA4x4s() - { - } - - void setRGBA16(const void* imgRGBA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getRGBA16(void* imgRGBA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - void setA16(const void* imgA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - void getA16(void* imgA16, unsigned int width, unsigned int height, unsigned int pitch, unsigned int x, unsigned int y); - - bool isSingleColorIgnoringAlpha() const; - - const ColorRGBA16* colors() const - { - return m_color; - } - - ColorRGBA16* colors() - { - return m_color; - } - - ColorRGBA16 color(unsigned int i) const - { - return m_color[i]; - } - - ColorRGBA16& color(unsigned int i) - { - return m_color[i]; - } - - private: - static const unsigned int COLOR_COUNT = 4 * 4; - - ColorRGBA16 m_color[COLOR_COUNT]; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorTypes.h b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorTypes.h deleted file mode 100644 index 2d5c8eb1e3..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/ColorTypes.h +++ /dev/null @@ -1,228 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -namespace ImageProcessing -{ - // 32 bit 8888 RGBA color - struct ColorRGBA8 - { - ColorRGBA8() - { - } - - ColorRGBA8(const ColorRGBA8& a_c) - : u(a_c.u) - { - } - - ColorRGBA8(uint8 a_r, uint8 a_g, uint8 a_b, uint8 a_a) - : r(a_r) - , g(a_g) - , b(a_b) - , a(a_a) - { - } - - explicit ColorRGBA8(uint32 a_u) - : u(a_u) - { - } - - void setRGBA(uint8 a_r, uint8 a_g, uint8 a_b, uint8 a_a) - { - r = a_r; - g = a_g; - b = a_b; - a = a_a; - } - - void setRGBA(const uint8* a_pRGBA8) - { - r = a_pRGBA8[0]; - g = a_pRGBA8[1]; - b = a_pRGBA8[2]; - a = a_pRGBA8[3]; - } - - void getRGBA(uint8& a_r, uint8& a_g, uint8& a_b, uint8& a_a) const - { - a_r = r; - a_g = g; - a_b = b; - a_a = a; - } - - void getRGBA(uint8* a_pRGBA8) const - { - a_pRGBA8[0] = r; - a_pRGBA8[1] = g; - a_pRGBA8[2] = b; - a_pRGBA8[3] = a; - } - - union - { - struct - { - uint8 r; - uint8 g; - uint8 b; - uint8 a; - }; - uint32 u; - }; - }; - - // 64 bit 16161616 RGBA color - struct ColorRGBA16 - { - ColorRGBA16() - { - } - - ColorRGBA16(const ColorRGBA16& a_c) - : u(a_c.u) - { - } - - ColorRGBA16(uint16 a_r, uint16 a_g, uint16 a_b, uint16 a_a) - : r(a_r) - , g(a_g) - , b(a_b) - , a(a_a) - { - } - - explicit ColorRGBA16(AZ::u64 a_u) - : u(a_u) - { - } - - void setRGBA(uint16 a_r, uint16 a_g, uint16 a_b, uint16 a_a) - { - r = a_r; - g = a_g; - b = a_b; - a = a_a; - } - - void setRGBA(const uint16* a_pRGBA16) - { - r = a_pRGBA16[0]; - g = a_pRGBA16[1]; - b = a_pRGBA16[2]; - a = a_pRGBA16[3]; - } - - - void getRGBA(uint16& a_r, uint16& a_g, uint16& a_b, uint16& a_a) const - { - a_r = r; - a_g = g; - a_b = b; - a_a = a; - } - - void getRGBA(uint16* a_pRGBA16) const - { - a_pRGBA16[0] = r; - a_pRGBA16[1] = g; - a_pRGBA16[2] = b; - a_pRGBA16[3] = a; - } - - union - { - struct - { - uint16 r; - uint16 g; - uint16 b; - uint16 a; - }; - AZ::u64 u; - }; - }; - - // 128 bit (4 floats) RGBA color - struct ColorRGBAf - { - ColorRGBAf() - { - } - - ColorRGBAf(const ColorRGBAf& a_c) - : r(a_c.r) - , g(a_c.g) - , b(a_c.b) - , a(a_c.a) - { - } - - ColorRGBAf(float a_r, float a_g, float a_b, float a_a) - : r(a_r) - , g(a_g) - , b(a_b) - , a(a_a) - { - } - - void setRGBA(float a_r, float a_g, float a_b, float a_a) - { - r = a_r; - g = a_g; - b = a_b; - a = a_a; - } - - void setRGBA(const float* a_pRGBAf) - { - r = a_pRGBAf[0]; - g = a_pRGBAf[1]; - b = a_pRGBAf[2]; - a = a_pRGBAf[3]; - } - - void getRGBA(float& a_r, float& a_g, float& a_b, float& a_a) const - { - a_r = r; - a_g = g; - a_b = b; - a_a = a; - } - - void getRGBA(float* a_pRGBAf) const - { - a_pRGBAf[0] = r; - a_pRGBAf[1] = g; - a_pRGBAf[2] = b; - a_pRGBAf[3] = a; - } - - union - { - struct - { - float r; - float g; - float b; - float a; - }; - }; - }; - static_assert(sizeof(ColorRGBA8) == 4, "Expected size of ColorRGBA8 to be 4 bytes!"); - static_assert(sizeof(ColorRGBA16) == 8, "Expected size of ColorRGBA16 to be 4 bytes!"); - static_assert(sizeof(ColorRGBAf) == 16, "Expected size of ColorRGBAf to be 4 bytes!"); -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.cpp b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.cpp deleted file mode 100644 index 27bb11a35b..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.cpp +++ /dev/null @@ -1,657 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include -#include -#include "ColorBlockRGBA4x4c.h" -#include "ColorBlockRGBA4x4s.h" -#include "ColorBlockRGBA4x4f.h" -#include "CryTextureSquisher.h" - -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wnull-dereference" -# pragma clang diagnostic ignored "-Wsometimes-uninitialized" -# pragma clang diagnostic ignored "-Wshift-negative-value" -#endif - -#if AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL -#define __fastcall -#define _fastcall -#define __assume(x) -#endif - -#include - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// number of bytes per block per type -#define BLOCKSIZE_BC1 8 -#define BLOCKSIZE_BC2 16 -#define BLOCKSIZE_BC3 16 -#define BLOCKSIZE_BC4 8 -#define BLOCKSIZE_BC5 16 -#define BLOCKSIZE_BC6 16 -#define BLOCKSIZE_BC7 16 -#define BLOCKSIZE_CTX1 8 -#define BLOCKSIZE_LIMIT 16 - -#define PTROFFSET_R 0 -#define PTROFFSET_G 1 -#define PTROFFSET_B 2 -#define PTROFFSET_A 3 - -namespace ImageProcessing -{ - AZStd::mutex s_squishLock; - - -/* ------------------------------------------------------------------------------------------------------------- - * internal presets - */ - static struct ParameterMatrix - { - int flagsBaseline; - int flagsUniform; - int flagsPerceptual; - int flagsQuality[CryTextureSquisher::EQualityProfile::eQualityProfile_Num]; - - size_t offset; - bool alphaOnly; - } P2P[] = - { - // eCompressorPreset_BC1U, - { - squish::kBtc1 + squish::kExcludeAlphaFromPalette, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - // eCompressorPreset_BC2U, - { - squish::kBtc2, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - // eCompressorPreset_BC3U, - { - squish::kBtc3, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit }, - - 0, false - }, - // eCompressorPreset_BC4U, - { - squish::kBtc4, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_R, false - }, - // eCompressorPreset_BC5U, - { - squish::kBtc5, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_R, false - }, - // eCompressorPreset_BC6UH, - { - squish::kBtc6, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit }, - - 0, false - }, - // eCompressorPreset_BC7U, - { - squish::kBtc7, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - - // eCompressorPreset_BC4S, - { - squish::kBtc4 + squish::kSignedInternal, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_R, false - }, - // eCompressorPreset_BC5S, - { - squish::kBtc5 + squish::kSignedInternal, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_R, false - }, - - // eCompressorPreset_BC1Un, - { - squish::kBtc1 + squish::kExcludeAlphaFromPalette, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit }, - - 0, false - }, - // eCompressorPreset_BC2Un, - { - squish::kBtc2, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit }, - - 0, false - }, - // eCompressorPreset_BC3Un, - { - squish::kBtc3, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kNormalRangeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit }, - - 0, false - }, - // eCompressorPreset_BC4Un, - { - squish::kBtc4, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_B, false - }, - // eCompressorPreset_BC5Un, - { - squish::kBtc5, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit }, - - PTROFFSET_R, false - }, - // eCompressorPreset_BC6UHn, - { - squish::kBtc6, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit }, - - 0, false - }, - // eCompressorPreset_BC7Un, - { - squish::kBtc7, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - - // eCompressorPreset_BC4Sn, - { - squish::kBtc4 + squish::kSignedInternal, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_B, false - }, - // eCompressorPreset_BC5Sn, - { - squish::kBtc5 + squish::kSignedInternal, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit }, - - PTROFFSET_R, false - }, - - // eCompressorPreset_BC1Ua, - { - squish::kBtc1 + squish::kWeightColourByAlpha, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - // eCompressorPreset_BC2Ut, - { - squish::kBtc2 + squish::kWeightColourByAlpha, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - // eCompressorPreset_BC3Ut, - { - squish::kBtc3 + squish::kWeightColourByAlpha, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit }, - - 0, false - }, - // eCompressorPreset_BC4Ua, - { - squish::kBtc4, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_A, true - }, - // eCompressorPreset_BC7Ut - { - squish::kBtc7 + squish::kWeightColourByAlpha, - squish::kColourMetricUniform, - squish::kColourMetricPerceptual, - { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - - // eCompressorPreset_BC4Sa, - { - squish::kBtc4 + squish::kSignedInternal, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit }, - - PTROFFSET_A, true - }, - - // eCompressorPreset_BC7Ug - { - squish::kBtc7, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourClusterFit * 15, squish::kColourClusterFit * 15 }, - - 0, false - }, - - // eCompressorPreset_CTX1U - { - squish::kCtx1, - squish::kColourMetricUniform, - squish::kColourMetricUniform, - { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit }, - - 0, false - }, - // eCompressorPreset_CTX1Un - { - squish::kCtx1, - squish::kColourMetricUnit, - squish::kColourMetricUnit, - { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit }, - - 0, false - }, - }; - - /* ------------------------------------------------------------------------------------------------------------- - * compression functions - */ - void CryTextureSquisher::Compress(const CryTextureSquisher::CompressorParameters& compress) - { - const unsigned int w = compress.width; - const unsigned int h = compress.height; - const size_t offset = P2P[compress.preset].offset; - int flags = P2P[compress.preset].flagsBaseline + P2P[compress.preset].flagsQuality[compress.quality] + - (!compress.perceptual ? P2P[compress.preset].flagsUniform : P2P[compress.preset].flagsPerceptual); - const bool bAlphaOnly = P2P[compress.preset].alphaOnly; - - squish::sqio::dtp datatype; - switch (compress.srcType) - { - case eBufferType_sint8: - flags += squish::kSignedExternal; - case eBufferType_uint8: - datatype = squish::sqio::dtp::DT_U8; - break; - case eBufferType_sint16: - flags += squish::kSignedExternal; - case eBufferType_uint16: - datatype = squish::sqio::dtp::DT_U16; - break; - case eBufferType_sfloat: - flags += squish::kSignedExternal; - case eBufferType_ufloat: - datatype = squish::sqio::dtp::DT_F23; - break; - default: - __assume(0); - break; - } - - if (compress.perceptual && (flags & squish::kColourMetricPerceptual)) - { - flags |= squish::kColourMetricCustom; - } - - const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags); - - if (compress.perceptual && (flags & squish::kColourMetricPerceptual)) - { - s_squishLock.lock(); - } - if (compress.perceptual && (flags & squish::kColourMetricPerceptual)) - { - squish::SetWeights(sqio.flags, &compress.weights[0]); - } - - AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__); - - switch (compress.srcType) - { - // compress an unsigned 8bit texture -------------------------------------------------- - // compress a signed 8bit texture ----------------------------------------------------- - case eBufferType_uint8: - case eBufferType_sint8: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - ColorBlockRGBA4x4c srcBlock; - uint8 dstBlock[BLOCKSIZE_LIMIT]; - - uint8* const targetBlock = dstBlock; - const uint8* const sourceRgba = (const uint8*)srcBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (!bAlphaOnly) - { - srcBlock.setRGBA8(compress.srcBuffer, w, h, compress.pitch, x, y); - } - else - { - srcBlock.setA8(compress.srcBuffer, w, h, compress.pitch, x, y); - } - - sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags); - - if (compress.userOutputFunction) - { - compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2); - } - } - } - } - break; - // compress an unsigned 16bit texture ------------------------------------------------- - // compress a signed 16bit texture ---------------------------------------------------- - case eBufferType_uint16: - case eBufferType_sint16: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - ColorBlockRGBA4x4s srcBlock; - uint8 dstBlock[BLOCKSIZE_LIMIT]; - - uint8* const targetBlock = dstBlock; - const float* const sourceRgba = (const float*)srcBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (!bAlphaOnly) - { - srcBlock.setRGBA16(compress.srcBuffer, w, h, compress.pitch, x, y); - } - else - { - srcBlock.setA16(compress.srcBuffer, w, h, compress.pitch, x, y); - } - - sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags); - - if (compress.userOutputFunction) - { - compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2); - } - } - } - } - break; - // compress an unsigned floating point texture ---------------------------------------- - // compress a signed floating point texture ------------------------------------------- - case eBufferType_ufloat: - case eBufferType_sfloat: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - ColorBlockRGBA4x4f srcBlock; - uint8 dstBlock[BLOCKSIZE_LIMIT]; - - uint8* const targetBlock = dstBlock; - const float* const sourceRgba = (const float*)srcBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (!bAlphaOnly) - { - srcBlock.setRGBAf(compress.srcBuffer, w, h, compress.pitch, x, y); - } - else - { - srcBlock.setAf(compress.srcBuffer, w, h, compress.pitch, x, y); - } - - sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags); - - if (compress.userOutputFunction) - { - compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2); - } - } - } - } - break; - default: - AZ_Assert(false, "%s: Unexpected compress source type", __FUNCTION__); - break; - } - - if (compress.perceptual && (flags & squish::kColourMetricPerceptual)) - { - s_squishLock.unlock(); - } - } - - void CryTextureSquisher::Decompress(const DecompressorParameters& decompress) - { - const unsigned int w = decompress.width; - const unsigned int h = decompress.height; - const size_t offset = P2P[decompress.preset].offset; - int flags = P2P[decompress.preset].flagsBaseline + - P2P[decompress.preset].flagsUniform; - const bool bAlphaOnly = P2P[decompress.preset].alphaOnly; - - squish::sqio::dtp datatype; - switch (decompress.dstType) - { - case eBufferType_sint8: - flags += squish::kSignedExternal; - case eBufferType_uint8: - datatype = squish::sqio::dtp::DT_U8; - break; - case eBufferType_sint16: - flags += squish::kSignedExternal; - case eBufferType_uint16: - datatype = squish::sqio::dtp::DT_U16; - break; - case eBufferType_sfloat: - flags += squish::kSignedExternal; - case eBufferType_ufloat: - datatype = squish::sqio::dtp::DT_F23; - break; - default: - __assume(0); - break; - } - - const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags); - - AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__); - - switch (decompress.dstType) - { - // decompress an unsigned 8bit texture -------------------------------------------------- - // decompress a signed 8bit texture ----------------------------------------------------- - case eBufferType_uint8: - case eBufferType_sint8: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - uint8 srcBlock[BLOCKSIZE_LIMIT]; - ColorBlockRGBA4x4c dstBlock; - - uint8* const sourceBlock = srcBlock; - uint8* const targetRgba = (uint8*)dstBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (decompress.userInputFunction) - { - decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2); - } - - if (!bAlphaOnly) - { - dstBlock.setRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - - sqio.decoder(targetRgba, sourceBlock, sqio.flags); - - if (!bAlphaOnly) - { - dstBlock.getRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - else - { - dstBlock.getA8(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - } - } - } - break; - // decompress an unsigned 16bit texture ------------------------------------------------- - // decompress a signed 16bit texture ---------------------------------------------------- - case eBufferType_uint16: - case eBufferType_sint16: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - uint8 srcBlock[BLOCKSIZE_LIMIT]; - ColorBlockRGBA4x4s dstBlock; - - uint8* const sourceBlock = srcBlock; - uint16* const targetRgba = (uint16*)dstBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (decompress.userInputFunction) - { - decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2); - } - - if (!bAlphaOnly) - { - dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - - sqio.decoder(targetRgba, sourceBlock, sqio.flags); - - if (!bAlphaOnly) - { - dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - else - { - dstBlock.getA16(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - } - } - } - break; - // decompress an unsigned floating point texture ---------------------------------------- - // decompress a signed floating point texture ------------------------------------------- - case eBufferType_ufloat: - case eBufferType_sfloat: - { - for (unsigned int y = 0U; y < h; y += 4U) - { - uint8 srcBlock[BLOCKSIZE_LIMIT]; - ColorBlockRGBA4x4f dstBlock; - - uint8* const sourceBlock = srcBlock; - float* const targetRgba = (float*)dstBlock.colors() + offset; - - for (unsigned int x = 0U; x < w; x += 4U) - { - if (decompress.userInputFunction) - { - decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2); - } - - if (!bAlphaOnly) - { - dstBlock.setRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - sqio.decoder(targetRgba, sourceBlock, sqio.flags); - - if (!bAlphaOnly) - { - dstBlock.getRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - else - { - dstBlock.getAf(decompress.dstBuffer, w, h, decompress.pitch, x, y); - } - } - } - } - break; - default: - AZ_Assert(false, "%s: Unexpected compress destination type", __FUNCTION__); - break; - } - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.h b/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.h deleted file mode 100644 index 2aa7117d46..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/CryTextureSquisher/CryTextureSquisher.h +++ /dev/null @@ -1,132 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -namespace ImageProcessing -{ - class CryTextureSquisher - { - public: - enum EBufferType - { - eBufferType_uint8, // native support: BC1-5/7,CTX1 - eBufferType_sint8, // native support: BC4-5 - eBufferType_uint16, // native support: BC1-7,CTX1 - eBufferType_sint16, // native support: BC4-6 - eBufferType_ufloat, // native support: BC1-7,CTX1 - eBufferType_sfloat, // native support: BC4-6 - }; - - enum EQualityProfile - { - eQualityProfile_Low = 0,// as-fast-as-possible - eQualityProfile_Medium, // not so bad (nightly builds) - eQualityProfile_High, // relative good (weekly builds) - eQualityProfile_Best, // as-best-as-possible (final build for release) - - eQualityProfile_Num - }; - - enum ECodingPreset - { - eCompressorPreset_BC1U = 0, - eCompressorPreset_BC2U, - eCompressorPreset_BC3U, - eCompressorPreset_BC4U, // r-channel from RGBA - eCompressorPreset_BC5U, // rg-channels from RGBA - eCompressorPreset_BC6UH, - eCompressorPreset_BC7U, - - eCompressorPreset_BC4S, // r-channel from RGBA - eCompressorPreset_BC5S, // rg-channels from RGBA - - // normal vectors -> unit metric - eCompressorPreset_BC1Un, - eCompressorPreset_BC2Un, - eCompressorPreset_BC3Un, - eCompressorPreset_BC4Un, // z-channel from XYZD - eCompressorPreset_BC5Un, // xy-channels from XYZD, xyz must be a valid unit-vector - eCompressorPreset_BC6UHn, - eCompressorPreset_BC7Un, - - eCompressorPreset_BC4Sn, // z-channel from XYZD - eCompressorPreset_BC5Sn, // xy-channels from XYZD, xyz must be a valid unit-vector - - // transparency -> weighted alpha - eCompressorPreset_BC1Ua, - eCompressorPreset_BC2Ut, - eCompressorPreset_BC3Ut, - eCompressorPreset_BC4Ua, // a-channel from RGBA - eCompressorPreset_BC7Ut, - - eCompressorPreset_BC4Sa, // a-channel from RGBA - - // grey-scale -> 12+ bits of precision - eCompressorPreset_BC7Ug, - - // special ones - eCompressorPreset_CTX1U, // rg-channels from RGBA - eCompressorPreset_CTX1Un, // xy-channels from XYZD, xyz must be a valid unit-vector - - eCompressorPreset_Num - }; - - struct CompressorParameters - { - // source's parameters - EBufferType srcType; - const void* srcBuffer; - unsigned int width; - unsigned int height; - unsigned int pitch; - - // coding preset - ECodingPreset preset; - EQualityProfile quality; - - // either if "srgb==1" or if "rgbweights!=uniform" - bool perceptual; - float weights[4]; - - void* userPtr; - int userInt; - - void(*userOutputFunction)(const CompressorParameters& compress, const void* compressedData, unsigned int compressedSize, unsigned int oy, unsigned int ox); - }; - - struct DecompressorParameters - { - // destination's parameters - EBufferType dstType; - void* dstBuffer; - unsigned int width; - unsigned int height; - unsigned int pitch; - - // coding preset - ECodingPreset preset; - - void* userPtr; - int userInt; - - void(*userInputFunction)(const DecompressorParameters& decompress, void* compressedData, unsigned int compressedSize, unsigned int oy, unsigned int ox); - }; - - public: - static void Compress(const CompressorParameters& compress); - static void Decompress(const DecompressorParameters& decompress); - }; - -} //namespace ImageProcessing - diff --git a/Gems/ImageProcessing/Code/Source/Compressors/ETC2.cpp b/Gems/ImageProcessing/Code/Source/Compressors/ETC2.cpp deleted file mode 100644 index 3d43fe7dda..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/ETC2.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace ImageProcessing -{ - //limited to 1 thread because AP requires so. We may change to n when AP allocate n thread to a job in the furture - static const int MAX_COMP_JOBS = 1; - static const int MIN_COMP_JOBS = 1; - static const float ETC_LOW_EFFORT_LEVEL = 25.0f; - static const float ETC_MED_EFFORT_LEVEL = 40.0f; - static const float ETC_HIGH_EFFORT_LEVEL = 80.0f; - - //Grab the Etc2Comp specific pixel format enum - static Etc::Image::Format FindEtc2PixelFormat(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_EAC_RG11: - return Etc::Image::Format::RG11; - case ePixelFormat_EAC_R11: - return Etc::Image::Format::R11; - case ePixelFormat_ETC2: - return Etc::Image::Format::RGB8; - case ePixelFormat_ETC2a: - return Etc::Image::Format::RGBA8; - default: - return Etc::Image::Format::FORMATS; - } - } - - //Get the errmetric required for the compression - static Etc::ErrorMetric FindErrMetric(Etc::Image::Format fmt) - { - switch (fmt) - { - case Etc::Image::Format::RG11: - return Etc::ErrorMetric::NORMALXYZ; - case Etc::Image::Format::R11: - return Etc::ErrorMetric::NUMERIC; - case Etc::Image::Format::RGB8: - return Etc::ErrorMetric::RGBX; - case Etc::Image::Format::RGBA8: - return Etc::ErrorMetric::RGBA; - default: - return Etc::ErrorMetric::ERROR_METRICS; - } - - } - - //Convert to sRGB format - static Etc::Image::Format FindGammaEtc2PixelFormat(Etc::Image::Format fmt) - { - switch (fmt) - { - case Etc::Image::Format::RGB8: - return Etc::Image::Format::SRGB8; - case Etc::Image::Format::RGBA8: - return Etc::Image::Format::SRGBA8; - case Etc::Image::Format::RGB8A1: - return Etc::Image::Format::SRGB8A1; - default: - return Etc::Image::Format::FORMATS; - } - } - - bool ETC2Compressor::IsCompressedPixelFormatSupported(EPixelFormat fmt) - { - return (FindEtc2PixelFormat(fmt) != Etc::Image::Format::FORMATS); - } - - bool ETC2Compressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt) - { - //for uncompress format - if (fmt == ePixelFormat_R8G8B8A8) - { - return true; - } - return false; - } - - EPixelFormat ETC2Compressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt) - { - return ePixelFormat_R8G8B8A8; - } - - bool ETC2Compressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst) - { - return false; - } - - IImageObjectPtr ETC2Compressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, - const CompressOption *compressOption) - { - const size_t srcPixelSize = 4; - - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be uncompressed and dst format need to compressed. - if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //determinate compression quality - ICompressor::EQuality quality = ICompressor::eQuality_Normal; - //get setting from compression option - if (compressOption) - { - quality = compressOption->compressQuality; - } - - float qualityEffort = 0.0f; - switch (quality) - { - case eQuality_Preview: - case eQuality_Fast: - { - qualityEffort = ETC_LOW_EFFORT_LEVEL; - break; - } - case eQuality_Normal: - { - qualityEffort = ETC_MED_EFFORT_LEVEL; - break; - } - default: - { - qualityEffort = ETC_HIGH_EFFORT_LEVEL; - } - } - - Etc::Image::Format dstEtc2Format = FindEtc2PixelFormat(fmtDst); - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - dstEtc2Format = FindGammaEtc2PixelFormat(dstEtc2Format); - } - - //use to read pixel data from src image - IPixelOperationPtr pixelOp = CreatePixelOperation(fmtSrc); - //get count of bytes per pixel for images - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtSrc)->bitsPerBlock / 8; - - const AZ::u32 mipCount = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < mipCount; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Prepare source data - AZ::u8* srcMem; - AZ::u32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - const AZ::u32 pixelCount = srcImage->GetPixelCount(mip); - - Etc::ColorFloatRGBA* rgbaPixels = new Etc::ColorFloatRGBA[pixelCount]; - Etc::ColorFloatRGBA* rgbaPixelPtr = rgbaPixels; - float r, g, b, a; - for (AZ::u32 pixelIdx = 0; pixelIdx < pixelCount; pixelIdx++, srcMem += pixelBytes, rgbaPixelPtr++) - { - pixelOp->GetRGBA(srcMem, r, g, b, a); - rgbaPixelPtr->fA = a; - rgbaPixelPtr->fR = r; - rgbaPixelPtr->fG = g; - rgbaPixelPtr->fB = b; - } - - //Call into etc2Comp lib to compress. https://medium.com/@duhroach/building-a-blazing-fast-etc2-compressor-307f3e9aad99 - Etc::ErrorMetric errMetric = FindErrMetric(dstEtc2Format); - unsigned char* paucEncodingBits; - unsigned int uiEncodingBitsBytes; - unsigned int uiExtendedWidth; - unsigned int uiExtendedHeight; - int iEncodingTime_ms; - - Etc::Encode(reinterpret_cast(rgbaPixels), - width, height, - dstEtc2Format, - errMetric, - qualityEffort, - MIN_COMP_JOBS, - MAX_COMP_JOBS, - &paucEncodingBits, &uiEncodingBitsBytes, - &uiExtendedWidth, &uiExtendedHeight, - &iEncodingTime_ms); - - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - - memcpy(dstMem, paucEncodingBits, uiEncodingBitsBytes); - delete[] rgbaPixels; - } - - return dstImage; - } - - IImageObjectPtr ETC2Compressor::DecompressImage(IImageObjectPtr srcImage, [[maybe_unused]] EPixelFormat fmtDst) - { - //etc2Comp doesn't support decompression - //Since PVRTexLib support ETC formats too. It may take over the decompression. - return nullptr; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/ETC2.h b/Gems/ImageProcessing/Code/Source/Compressors/ETC2.h deleted file mode 100644 index d862bead68..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/ETC2.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - class ETC2Compressor : public ICompressor - { - public: - static bool IsCompressedPixelFormatSupported(EPixelFormat fmt); - static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt); - static bool DoesSupportDecompress(EPixelFormat fmtDst); - - IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override; - IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override; - - EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.cpp b/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.cpp deleted file mode 100644 index 64fee3b747..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include -#include -#include -#include -#include - -#if AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT -//_WINDLL_IMPORT need to be defined before including PVRTexLib header files to avoid linking error on windows. -#define _WINDLL_IMPORT -// NOMINMAX needs to be defined before including PVRTexLib header files (which include Windows.h) -// so that Windows.h doesn't define min/max. Otherwise, a compile error may arise in Uber builds -#ifndef NOMINMAX -#define NOMINMAX -#endif -#endif -#include -#include - - -namespace ImageProcessing -{ - // Note: PVRTexLib supports ASTC formats, ETC formats, PVRTC formats and BC formats - // We haven't tested the performace to compress BC formats compare to CTSquisher - // For PVRTC formats, we only added PVRTC 1 support for now - // The compression for ePVRTPF_EAC_R11 and ePVRTPF_EAC_RG11 are very slow. It takes 7 and 14 minutes for a 2048x2048 texture. - EPVRTPixelFormat FindPvrPixelFormat(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_ASTC_4x4: - return ePVRTPF_ASTC_4x4; - case ePixelFormat_ASTC_5x4: - return ePVRTPF_ASTC_5x4; - case ePixelFormat_ASTC_5x5: - return ePVRTPF_ASTC_5x5; - case ePixelFormat_ASTC_6x5: - return ePVRTPF_ASTC_6x5; - case ePixelFormat_ASTC_6x6: - return ePVRTPF_ASTC_6x6; - case ePixelFormat_ASTC_8x5: - return ePVRTPF_ASTC_8x5; - case ePixelFormat_ASTC_8x6: - return ePVRTPF_ASTC_8x6; - case ePixelFormat_ASTC_8x8: - return ePVRTPF_ASTC_8x8; - case ePixelFormat_ASTC_10x5: - return ePVRTPF_ASTC_10x5; - case ePixelFormat_ASTC_10x6: - return ePVRTPF_ASTC_10x6; - case ePixelFormat_ASTC_10x8: - return ePVRTPF_ASTC_10x8; - case ePixelFormat_ASTC_10x10: - return ePVRTPF_ASTC_10x10; - case ePixelFormat_ASTC_12x10: - return ePVRTPF_ASTC_12x10; - case ePixelFormat_ASTC_12x12: - return ePVRTPF_ASTC_12x12; - case ePixelFormat_PVRTC2: - return ePVRTPF_PVRTCI_2bpp_RGBA; - case ePixelFormat_PVRTC4: - return ePVRTPF_PVRTCI_4bpp_RGBA; - case ePixelFormat_EAC_R11: - return ePVRTPF_EAC_R11; - case ePixelFormat_EAC_RG11: - return ePVRTPF_EAC_RG11; - case ePixelFormat_ETC2: - return ePVRTPF_ETC2_RGB; - case ePixelFormat_ETC2a: - return ePVRTPF_ETC2_RGBA; - default: - return ePVRTPF_NumCompressedPFs; - } - } - - bool PVRTCCompressor::IsCompressedPixelFormatSupported(EPixelFormat fmt) - { - return (FindPvrPixelFormat(fmt) != ePVRTPF_NumCompressedPFs); - } - - bool PVRTCCompressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt) - { - //for uncompress format - if (fmt == ePixelFormat_R8G8B8A8) - { - return true; - } - return false; - } - - - EPixelFormat PVRTCCompressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt) - { - return ePixelFormat_R8G8B8A8; - } - - - bool PVRTCCompressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst) - { - return true; - } - - IImageObjectPtr PVRTCCompressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, - const CompressOption *compressOption) - { - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be uncompressed and dst format need to compressed. - if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //determinate compression quality - pvrtexture::ECompressorQuality internalQuality = pvrtexture::eETCFast; - ICompressor::EQuality quality = ICompressor::eQuality_Normal; - AZ::Vector3 uniformWeights = AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - AZ::Vector3 weights = uniformWeights; - bool isUniform = true; - //get setting from compression option - if (compressOption) - { - quality = compressOption->compressQuality; - weights = compressOption->rgbWeight; - isUniform = (weights == uniformWeights); - } - - if (IsETCFormat(fmtDst)) - { - if ((quality <= eQuality_Normal) && isUniform) - { - internalQuality = pvrtexture::eETCFast; - } - else if (quality <= eQuality_Normal) - { - internalQuality = pvrtexture::eETCNormal; - } - else if (isUniform) - { - internalQuality = pvrtexture::eETCSlow; - } - else - { - internalQuality = pvrtexture::eETCSlow; - } - } - else if (IsASTCFormat(fmtDst)) - { - if (quality == eQuality_Preview) - { - internalQuality = pvrtexture::eASTCVeryFast; - } - else if (quality == eQuality_Fast) - { - internalQuality = pvrtexture::eASTCFast; - } - else if (quality == eQuality_Normal) - { - internalQuality = pvrtexture::eASTCMedium; - } - else - { - internalQuality = pvrtexture::eASTCThorough; - } - } - else - { - if (quality == eQuality_Preview) - { - internalQuality = pvrtexture::ePVRTCFastest; - } - else if (quality == eQuality_Fast) - { - internalQuality = pvrtexture::ePVRTCFast; - } - else if (quality == eQuality_Normal) - { - internalQuality = pvrtexture::ePVRTCNormal; - } - else - { - internalQuality = pvrtexture::ePVRTCHigh; - } - } - - // setup color space - EPVRTColourSpace cspace = ePVRTCSpacelRGB; - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - cspace = ePVRTCSpacesRGB; - } - - //setup src texture for compression - const pvrtexture::PixelType srcPixelType('r', 'g', 'b', 'a', 8, 8, 8, 8); - const AZ::u32 dstMips = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < dstMips; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Prepare source data - AZ::u8* srcMem; - uint32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - - const pvrtexture::CPVRTextureHeader srcHeader( - srcPixelType.PixelTypeID, // AZ::u64 u64PixelFormat, - width, // uint32 u32Height=1, - height, // uint32 u32Width=1, - 1, // uint32 u32Depth=1, - 1, // uint32 u32NumMipMaps=1, - 1, // uint32 u32NumArrayMembers=1, - 1, // uint32 u32NumFaces=1, - cspace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB, - ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm, - false); // bool bPreMultiplied=false); - - pvrtexture::CPVRTexture compressTexture(srcHeader, srcMem); - - //compressing - bool isSuccess = false; -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - try -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - { - isSuccess = pvrtexture::Transcode( - compressTexture, - pvrtexture::PixelType(FindPvrPixelFormat(fmtDst)), - ePVRTVarTypeUnsignedByteNorm, - cspace, - internalQuality); - } -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - catch (...) - { - AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib"); - return nullptr; - } -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - - if (!isSuccess) - { - AZ_Error("Image Processing", false, "Failed to compress image with PVRTexLib. You may not have astcenc.exe for compressing ASTC formates"); - return nullptr; - } - - // Getting compressed data - const void* const compressedData = compressTexture.getDataPtr(); - if (!compressedData) - { - AZ_Error("Image Processing", false, "Failed to obtain compressed image data by using PVRTexLib"); - return nullptr; - } - - const AZ::u32 compressedDataSize = compressTexture.getDataSize(); - if (dstImage->GetMipBufSize(mip) != compressedDataSize) - { - AZ_Error("Image Processing", false, "Compressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - //save compressed data to dst image - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - memcpy(dstMem, compressedData, compressedDataSize); - } - - return dstImage; - } - - IImageObjectPtr PVRTCCompressor::DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) - { - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); //compressed - - if (!IsCompressedPixelFormatSupported(fmtSrc) || !IsUncompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - EPVRTColourSpace colorSpace = ePVRTCSpacelRGB; - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - colorSpace = ePVRTCSpacesRGB; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - const AZ::u32 mipCount = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < mipCount; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Preparing source compressed data - const pvrtexture::CPVRTextureHeader compressedHeader( - FindPvrPixelFormat(fmtSrc), // AZ::u64 u64PixelFormat, - width, // uint32 u32Height=1, - height, // uint32 u32Width=1, - 1, // uint32 u32Depth=1, - 1, // uint32 u32NumMipMaps=1, - 1, // uint32 u32NumArrayMembers=1, - 1, // uint32 u32NumFaces=1, - colorSpace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB, - ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm, - false); // bool bPreMultiplied=false); - - const AZ::u32 compressedDataSize = compressedHeader.getDataSize(); - if (srcImage->GetMipBufSize(mip) != compressedDataSize) - { - AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - AZ::u8* srcMem; - AZ::u32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - pvrtexture::CPVRTexture cTexture(compressedHeader, srcMem); - - // Decompress - bool bOk = false; -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - try - { -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - bOk = pvrtexture::Transcode( - cTexture, - pvrtexture::PVRStandard8PixelType, - ePVRTVarTypeUnsignedByteNorm, - colorSpace, - pvrtexture::ePVRTCHigh); - -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - } - catch (...) - { - AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib when decompressing"); - return nullptr; - } -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - - if (!bOk) - { - AZ_Error("Image Processing", false, "Failed to decompress an image by using PVRTexLib"); - return nullptr; - } - - // Getting decompressed data - const void* const pDecompressedData = cTexture.getDataPtr(); - if (!pDecompressedData) - { - AZ_Error("Image Processing", false, "Failed to obtain decompressed image data by using PVRTexLib"); - return nullptr; - } - - const AZ::u32 decompressedDataSize = cTexture.getDataSize(); - if (dstImage->GetMipBufSize(mip) != decompressedDataSize) - { - AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - //save decompressed image to dst image - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - memcpy(dstMem, pDecompressedData, decompressedDataSize); - } - - return dstImage; - } - -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.h b/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.h deleted file mode 100644 index 648990a819..0000000000 --- a/Gems/ImageProcessing/Code/Source/Compressors/PVRTC.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - class PVRTCCompressor : public ICompressor - { - public: - static bool IsCompressedPixelFormatSupported(EPixelFormat fmt); - static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt); - static bool DoesSupportDecompress(EPixelFormat fmtDst); - - IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption *compressOption) override; - IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) override; - - EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) override; - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/AlphaCoverage.cpp b/Gems/ImageProcessing/Code/Source/Converters/AlphaCoverage.cpp deleted file mode 100644 index 46444d8d87..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/AlphaCoverage.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////////// -//functions for maintaining alpha coverage. - -namespace ImageProcessing -{ - void CImageObject::TransferAlphaCoverage(const TextureSettings* textureSetting, const IImageObjectPtr srcImg) - { - EPixelFormat srcFmt = srcImg->GetPixelFormat(); - //both this image and src image need to be uncompressed - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat) - || !CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt)) - { - AZ_Assert(false, "Both source image and dest image need to be uncompressed"); - return; - } - - const float fAlphaRef = 0.5f; // Seems to give good overall results - const float fDesiredAlphaCoverage = srcImg->ComputeAlphaCoverage(0, fAlphaRef); - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - for (uint32 mip = 0; mip < GetMipCount(); mip++) - { - const float fAlphaOffset = textureSetting->ComputeMIPAlphaOffset(mip); - const float fAlphaScale = ComputeAlphaCoverageScaleFactor(mip, fDesiredAlphaCoverage, fAlphaRef); - - AZ::u8* pixelBuf = m_mips[mip]->m_pData; - const AZ::u32 pixelCount = GetPixelCount(mip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - float r, g, b, a; - pixelOp->GetRGBA(pixelBuf, r, g, b, a); - a = AZ::GetMin(a * fAlphaScale + fAlphaOffset, 1.0f); - pixelOp->SetRGBA(pixelBuf, r, g, b, a); - } - } - } - - float CImageObject::ComputeAlphaCoverageScaleFactor(AZ::u32 mip, float fDesiredCoverage, float fAlphaRef) const - { - float minAlphaRef = 0.0f; - float maxAlphaRef = 1.0f; - float midAlphaRef = 0.5f; - - // Find best alpha test reference value using a binary search - for (int i = 0; i < 10; i++) - { - const float currentCoverage = ComputeAlphaCoverage(mip, midAlphaRef); - - if (currentCoverage > fDesiredCoverage) - { - minAlphaRef = midAlphaRef; - } - else if (currentCoverage < fDesiredCoverage) - { - maxAlphaRef = midAlphaRef; - } - else - { - break; - } - - midAlphaRef = (minAlphaRef + maxAlphaRef) * 0.5f; - } - - return fAlphaRef / midAlphaRef; - } - - float CImageObject::ComputeAlphaCoverage(AZ::u32 mip, float fAlphaRef) const - { - //This function only works with uncompressed image - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)) - { - AZ_Assert(false, "This image need to be uncompressed"); - return 0; - } - - uint32 coverage = 0; - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - AZ::u8* pixelBuf = m_mips[mip]->m_pData; - const AZ::u32 pixelCount = GetPixelCount(mip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - float r, g, b, a; - pixelOp->GetRGBA(pixelBuf, r, g, b, a); - coverage += a > fAlphaRef; - } - - return (float)coverage / (float)(pixelCount); - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/ColorChart.cpp b/Gems/ImageProcessing/Code/Source/Converters/ColorChart.cpp deleted file mode 100644 index 63067a57b5..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/ColorChart.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include - -namespace ImageProcessing -{ - const int COLORCHART_IMAGE_WIDTH = 78; - const int COLORCHART_IMAGE_HEIGHT = 66; - - // color chart in cry engine is a special image data, with size 78x66, you may see in game screenshot which is defined by a rectangle - // area with a yellow-black dash line boarder - // Create color chart function is to read that block of image data and convert it to a color table then save it to another image - // with size 256x16. - - class C3dLutColorChart - { - public: - C3dLutColorChart() {} - ~C3dLutColorChart() {}; - - //generate default color chart data - void GenerateDefault(); - - //generate color chart data from input image - bool GenerateFromInput(IImageObjectPtr image); - - //ouput the color chart data to an image object - IImageObjectPtr GenerateChartImage(); - - protected: - //extract color chart data from specified location in an image - void ExtractFromImageAt(IImageObjectPtr pImg, AZ::u32 x, AZ::u32 y); - - //find color chart location in an image - static bool FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY); - - //if there is a color chart at specified location - static bool IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch); - - private: - enum EPrimaryShades - { - ePS_Red = 16, - ePS_Green = 16, - ePS_Blue = 16, - - ePS_NumColors = ePS_Red * ePS_Green * ePS_Blue - }; - - struct SColor - { - unsigned char r, g, b, _padding; - }; - - typedef AZStd::vector ColorMapping; - - ColorMapping m_mapping; - }; - - void C3dLutColorChart::GenerateDefault() - { - m_mapping.reserve(ePS_NumColors); - - for (int b = 0; b < ePS_Blue; ++b) - { - for (int g = 0; g < ePS_Green; ++g) - { - for (int r = 0; r < ePS_Red; ++r) - { - SColor col; - col.r = 255 * r / (ePS_Red); - col.g = 255 * g / (ePS_Green); - col.b = 255 * b / (ePS_Blue); - int l = 255 - (col.r * 3 + col.g * 6 + col.b) / 10; - col.r = col.g = col.b = (unsigned char)l; - m_mapping.push_back(col); - } - } - } - } - - //find color chart location in a image - bool C3dLutColorChart::FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY) - { - const AZ::u32 width = pImg->GetWidth(0); - const AZ::u32 height = pImg->GetHeight(0); - - //the origin image is too small to have a color chart - if (width < COLORCHART_IMAGE_WIDTH || height < COLORCHART_IMAGE_HEIGHT) - { - return false; - } - - AZ::u8* pData; - AZ::u32 pitch; - pImg->GetImagePointer(0, pData, pitch); - - //check all the posible start location on whether there might be a color chart - for (AZ::u32 y = 0; y <= height - COLORCHART_IMAGE_HEIGHT; ++y) - { - for (AZ::u32 x = 0; x <= width - COLORCHART_IMAGE_WIDTH; ++x) - { - if (IsColorChartAt(x, y, pData, pitch)) - { - outLocX = x; - outLocY = y; - return true; - } - } - } - - return false; - } - - bool C3dLutColorChart::GenerateFromInput(IImageObjectPtr image) - { - AZ::u32 outLocX, outLocY; - if (FindColorChart(image, outLocX, outLocY)) - { - ExtractFromImageAt(image, outLocX, outLocY); - return true; - } - return false; - } - - IImageObjectPtr C3dLutColorChart::GenerateChartImage() - { - const AZ::u32 mipCount = 1; - IImageObjectPtr image( IImageObject::CreateImage(ePS_Red * ePS_Blue, ePS_Green, 1, ePixelFormat_R8G8B8A8)); - - { - AZ::u8* pData; - AZ::u32 pitch; - image->GetImagePointer(0, pData, pitch); - - size_t nSlicePitch = (pitch / ePS_Blue); - AZ::u32 src = 0; - for (int b = 0; b < ePS_Blue; ++b) - { - for (int g = 0; g < ePS_Green; ++g) - { - - AZ::u8* p = pData + g * pitch + b * nSlicePitch; - for (int r = 0; r < ePS_Red; ++r) - { - const SColor& c = m_mapping[src]; - p[0] = c.r; - p[1] = c.g; - p[2] = c.b; - p[3] = 255; - ++src; - p += 4; - } - } - } - } - - return image; - } - - void C3dLutColorChart::ExtractFromImageAt(IImageObjectPtr image, AZ::u32 x, AZ::u32 y) - { - int ox = x + 1; - int oy = y + 1; - - AZ::u8* pData; - AZ::u32 pitch; - image->GetImagePointer(0, pData, pitch); - - m_mapping.reserve(ePS_NumColors); - - for (int b = 0; b < ePS_Blue; ++b) - { - int px = ox + ePS_Red * (b % 4); - int py = oy + ePS_Green * (b / 4); - - for (int g = 0; g < ePS_Green; ++g) - { - for (int r = 0; r < ePS_Red; ++r) - { - AZ::u8* p = pData + pitch * (py + g) + (px + r) * 4; - - SColor col; - col.r = p[0]; - col.g = p[1]; - col.b = p[2]; - m_mapping.push_back(col); - } - } - } - } - - //check if image data at location x and y could be a color chart - //based on if the boarder is dash lines with two pixel each segement - //the idea and implementation are both coming from CryEngine. - bool C3dLutColorChart::IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch) - { - struct Color - { - private: - int c[3]; - - public: - Color(AZ::u32 x, AZ::u32 y, void* pPixels, AZ::u32 pitch) - { - const uint8* p = (const uint8*)pPixels + pitch * y + x * 4; - c[0] = p[0]; - c[1] = p[1]; - c[2] = p[2]; - } - - bool isSimilar(const Color& a, int maxDiff) const - { - return - abs(a.c[0] - c[0]) <= maxDiff && - abs(a.c[1] - c[1]) <= maxDiff && - abs(a.c[2] - c[2]) <= maxDiff; - } - }; - - const Color colorRef[2] = - { - Color(x, y, pData, pitch), - Color(x + 2, y, pData, pitch) - }; - - // We require two colors of the border to be at least a bit different - if (colorRef[0].isSimilar(colorRef[1], 15)) - { - return false; - } - - static const int kMaxDiff = 3; - - int refIdx = 0; - //rectangle's top - for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + i, y, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + i + 1, y, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //left - for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x, y + i, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x, y + i + 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //right - for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i + 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //bottom - for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + i, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + i + 1, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - return true; - } - - - void ImageToProcess::CreateColorChart() - { - C3dLutColorChart colorChart; - - //get color chart data from source image. - if (!colorChart.GenerateFromInput(m_img)) - { - //if load from image failed then generate default color data - colorChart.GenerateDefault(); - } - - //save color chart data to an image and save as current - m_img = colorChart.GenerateChartImage(); - } -} diff --git a/Gems/ImageProcessing/Code/Source/Converters/ConvertPixelFormat.cpp b/Gems/ImageProcessing/Code/Source/Converters/ConvertPixelFormat.cpp deleted file mode 100644 index 9a49bf9b63..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/ConvertPixelFormat.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include - -#include -#include - -/////////////////////////////////////////////////////////////////////////////////// -//functions for maintaining alpha coverage. - -namespace ImageProcessing -{ - void ImageToProcess::ConvertFormat(EPixelFormat fmtDst) - { - //pixel format before convertion - EPixelFormat fmtSrc = Get()->GetPixelFormat(); - - //return directly if the image already has the desired pixel format - if (fmtDst == fmtSrc) - { - return; - } - - uint32 dwWidth, dwHeight, dwMips; - dwWidth = Get()->GetWidth(0); - dwHeight = Get()->GetHeight(0); - dwMips = Get()->GetMipCount(); - - //if the output image size doesn't work the desired pixel format. set to fallback format - const PixelFormatInfo* dstFmtInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtDst); - if (!CPixelFormats::GetInstance().IsImageSizeValid(fmtDst, dwWidth, dwHeight, true)) - { - AZ_Warning("Image Processing", false, "Output pixel format %d doesn't work with output image size %d x %d", - fmtDst, dwWidth, dwHeight); - - //fall back to safe texture format - if (dstFmtInfo->nChannels == 1) - { - fmtDst = dstFmtInfo->bHasAlpha ? ePixelFormat_A8 : ePixelFormat_R8; - } - else if (dstFmtInfo->nChannels == 2) - { - fmtDst = ePixelFormat_R8G8; - } - else - { - fmtDst = dstFmtInfo->bHasAlpha ? ePixelFormat_R8G8B8A8 : ePixelFormat_R8G8B8X8; - } - } - - //convert src image to uncompressed formats if it's compressed format - bool isSrcUncompressed = CPixelFormats::GetInstance().IsPixelFormatUncompressed(fmtSrc); - bool isDstUncompressed = CPixelFormats::GetInstance().IsPixelFormatUncompressed(fmtDst); - - if (isSrcUncompressed && isDstUncompressed) - {//both are uncompressed - ConvertFormatUncompressed(fmtDst); - } - else if (!isSrcUncompressed && !isDstUncompressed) - { //both are compressed - AZ_Assert(false, "unusual user case. but we can still handle it"); - } - else - { //one fmt is compressed format - //use the compressed format to find right compressor - EPixelFormat compressedFmt = isSrcUncompressed ? fmtDst : fmtSrc; - EPixelFormat uncompressedFmt = isSrcUncompressed ? fmtSrc : fmtDst; - ICompressorPtr compressor = ICompressor::FindCompressor(compressedFmt, isSrcUncompressed); - - if (compressor == nullptr) - { - //no avaible compressor for compressed format - AZ_Warning("Image Processing", false, "No avaliable compressor for pixel format %d", compressedFmt); - return; - } - - //check if the uncompressed fmt also supported by the compressor - EPixelFormat desiredUncompressedFmt = compressor->GetSuggestedUncompressedFormat(compressedFmt, uncompressedFmt); - if (desiredUncompressedFmt != uncompressedFmt) - { - //we need to do intermedia convertion to convert to the temperory format - ConvertFormat(desiredUncompressedFmt); - ConvertFormat(fmtDst); - } - else - { - IImageObjectPtr dstImage = nullptr; - if (isSrcUncompressed) - { - dstImage = compressor->CompressImage(Get(), fmtDst, &m_compressOption); - } - else - { - dstImage = compressor->DecompressImage(Get(), fmtDst); - } - - Set(dstImage); - } - - if (Get() == nullptr) - { - AZ_Error("Image Processing", false, "The selected compressor failed to compress this image"); - } - } - } - - void ImageToProcess::ConvertFormatUncompressed(EPixelFormat fmtTo) - { - IImageObjectPtr srcImage = m_img; - EPixelFormat srcFmt = srcImage->GetPixelFormat(); - EPixelFormat dstFmt = fmtTo; - - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt) - && CPixelFormats::GetInstance().IsPixelFormatUncompressed(dstFmt))) - { - AZ_Assert(false, "both source and dest images' pixel format need to be uncompressed"); - return; - } - - IImageObjectPtr dstImage(m_img->AllocateImage(fmtTo)); - - AZ_Assert(srcImage->GetPixelCount(0) == dstImage->GetPixelCount(0), "dest image has different size than source image"); - - //create pixel operation function for src and dst images - IPixelOperationPtr srcOp = CreatePixelOperation(srcFmt); - IPixelOperationPtr dstOp = CreatePixelOperation(dstFmt); - - //get count of bytes per pixel for both src and dst images - uint32 srcPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8; - uint32 dstPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->bitsPerBlock / 8; - - const uint32 dwMips = dstImage->GetMipCount(); - float r, g, b, a; - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* srcPixelBuf; - uint32 srcPitch; - srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch); - uint8* dstPixelBuf; - uint32 dstPitch; - dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch); - - const uint32 pixelCount = srcImage->GetPixelCount(dwMip); - - for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += srcPixelBytes, dstPixelBuf += dstPixelBytes) - { - srcOp->GetRGBA(srcPixelBuf, r, g, b, a); - dstOp->SetRGBA(dstPixelBuf, r, g, b, a); - } - } - - m_img = dstImage; - } - - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/Cubemap.cpp b/Gems/ImageProcessing/Code/Source/Converters/Cubemap.cpp deleted file mode 100644 index 71e629b553..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Cubemap.cpp +++ /dev/null @@ -1,620 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace ImageProcessing -{ - CubemapLayoutInfo CubemapLayout::s_layoutList[CubemapLayoutTypeCount]; - - template - inline bool IsPowerOfTwo(TInteger x) - { - return (x & (x - 1)) == 0; - } - - CubemapLayoutInfo::CubemapLayoutInfo() - : m_type(CubemapLayoutNone) - , m_rows(0) - , m_columns(0) - { - - } - - void CubemapLayoutInfo::SetFaceInfo(CubemapFace face, AZ::u8 row, AZ::u8 col, CubemapFaceDirection dir) - { - m_faceInfos[face].row = row; - m_faceInfos[face].column = col; - m_faceInfos[face].direction = dir; - } - - void CubemapLayout::InitCubemapLayoutInfos() - { - //CubemapLayoutHorizontal - //left , right, front, back, top, bottom; - //NOTE: this layout is widely used in game projects by Jan 2018 since other layouts weren't supported correctly - //but the faces in one has unusual directions compare to other format. - //The direction matters when using it as input for Cubemap generation filter. - //Left: rotated left 90 degree. Right: rotated right 90 degree - //Front: rotated 180 degree. Back: no rotation - //Top: rotate 180 degree. Bottom: no rotation - CubemapLayoutInfo *info = &s_layoutList[CubemapLayoutHorizontal]; - info->m_rows = 1; - info->m_columns = 6; - info->m_type = CubemapLayoutHorizontal; - info->SetFaceInfo(FaceLeft, 0, 0, CubemapFaceDirection::DirRotateLeft90); - info->SetFaceInfo(FaceRight, 0, 1, CubemapFaceDirection::DirRotateRight90); - info->SetFaceInfo(FaceFront, 0, 2, CubemapFaceDirection::DirRotate180); - info->SetFaceInfo(FaceBack, 0, 3, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceTop, 0, 4, CubemapFaceDirection::DirRotate180); - info->SetFaceInfo(FaceBottom, 0, 5, CubemapFaceDirection::DirNoRotation); - - //CubemapLayoutHorizontalCross - // top - // left front right back - // bottom - info = &s_layoutList[CubemapLayoutHorizontalCross]; - info->m_rows = 3; - info->m_columns = 4; - info->m_type = CubemapLayoutHorizontalCross; - info->SetFaceInfo(FaceLeft, 1, 0, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceRight, 1, 2, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceFront, 1, 1, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceBack, 1, 3, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceTop, 0, 1, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceBottom, 2, 1, CubemapFaceDirection::DirNoRotation); - - //CubemapLayoutVerticalCross - // top - // left front right - // bottom - // back - info = &s_layoutList[CubemapLayoutVerticalCross]; - info->m_rows = 4; - info->m_columns = 3; - info->m_type = CubemapLayoutVerticalCross; - info->SetFaceInfo(FaceLeft, 1, 0, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceRight, 1, 2, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceFront, 1, 1, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceBack, 3, 1, CubemapFaceDirection::DirRotate180); - info->SetFaceInfo(FaceTop, 0, 1, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceBottom, 2, 1, CubemapFaceDirection::DirNoRotation); - - //CubemapLayoutVertical - // left - // right - // front - // back - // top - // bottom - info = &s_layoutList[CubemapLayoutVertical]; - info->m_rows = 6; - info->m_columns = 1; - info->m_type = CubemapLayoutVertical; - info->SetFaceInfo(FaceLeft, 0, 0, CubemapFaceDirection::DirRotateLeft90); - info->SetFaceInfo(FaceRight, 1, 0, CubemapFaceDirection::DirRotateRight90); - info->SetFaceInfo(FaceFront, 2, 0, CubemapFaceDirection::DirRotate180); - info->SetFaceInfo(FaceBack, 3, 0, CubemapFaceDirection::DirNoRotation); - info->SetFaceInfo(FaceTop, 4, 0, CubemapFaceDirection::DirRotate180); - info->SetFaceInfo(FaceBottom, 5, 0, CubemapFaceDirection::DirNoRotation); - - //make sure all types were initialized - for (int i = 0; i < CubemapLayoutTypeCount; i++) - { - AZ_Assert(s_layoutList[i].m_type == i, "layout %d is not initialized", i); - } - } - - const float* GetTransformMatrix(CubemapFaceDirection dir, bool isInvert) - { - switch (dir) - { - case CubemapFaceDirection::DirNoRotation: - { - static const float mat[] = { 1, 0, 0, 1 }; - return mat; - } - case CubemapFaceDirection::DirRotateLeft90: - { - //thelta = 90 degree - //{cos, -sin, sin, cos} - if (isInvert) - { - return GetTransformMatrix(CubemapFaceDirection::DirRotateRight90, false); - } - static const float mat[] = { 0, -1, 1, 0 }; - return mat; - } - case CubemapFaceDirection::DirRotateRight90: - { - //thelta = -90 degree - if (isInvert) - { - return GetTransformMatrix(CubemapFaceDirection::DirRotateLeft90, false); - } - static const float mat[] = { 0, 1, -1, 0 }; - return mat; - } - case CubemapFaceDirection::DirRotate180: - { - //thelta = 180 degree - static const float mat[] = { -1, 0, 0, -1 }; - return mat; - } - case CubemapFaceDirection::DirMirrorHorizontal: - { - static const float mat[] = { 1, 0, 0, -1 }; - return mat; - } - default: - { - AZ_Assert(false, "unimplemented direction matrix"); - static const float mat[] = { 1, 0, 0, 1 }; - return mat; - } - } - } - - void TransformImage(CubemapFaceDirection srcDir, CubemapFaceDirection dstDir, const AZ::u8* srcImageBuf, - AZ::u8* dstImageBuf, AZ::u8 bytePerPixel, AZ::u32 rectSize) - { - //get final matrix to transform dst back to src - const float* m1 = GetTransformMatrix(dstDir, true); - const float* m2 = GetTransformMatrix(srcDir, false); - float mtx[4]; - mtx[0] = m1[0] * m2[0] + m1[1] * m2[2]; - mtx[1] = m1[0] * m2[1] + m1[1] * m2[3]; - mtx[2] = m1[2] * m2[0] + m1[3] * m2[2]; - mtx[3] = m1[2] * m2[1] + m1[3] * m2[3]; - - const float* noRotate = GetTransformMatrix(CubemapFaceDirection::DirNoRotation, false); - - if (memcmp(noRotate, mtx, 4 * sizeof(float)) == 0) - { - memcpy(dstImageBuf, srcImageBuf, rectSize*rectSize*bytePerPixel); - return; - } - - //for each pixel in dst image, find it's location in src and copy the data from there - float halfSize = rectSize / 2; - for (AZ::u32 row = 0; row < rectSize; row++) - { - for (AZ::u32 col = 0; col < rectSize; col++) - { - //coordinate in image center as origin and right as positive X, up as positive Y - float dstX = col + 0.5f - halfSize; - float dstY = halfSize - row - 0.5f; - float srcX = dstX * mtx[0] + dstY * mtx[1]; - float srcY = dstX * mtx[2] + dstY * mtx[3]; - AZ::u32 srcCol = srcX + halfSize; - AZ::u32 srcRow = halfSize - srcY; - - memcpy(&dstImageBuf[(row*rectSize + col)*bytePerPixel], - &srcImageBuf[(srcRow*rectSize + srcCol)*bytePerPixel], bytePerPixel); - } - } - } - - CubemapLayout::CubemapLayout() - : m_info(nullptr) - , m_image(nullptr) - , m_faceSize(256) - { - } - - CubemapLayout* CubemapLayout::CreateCubemapLayout(IImageObjectPtr image) - { - //only support uncompressed format. - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(image->GetPixelFormat())) - { - AZ_Assert(false, "CubemapLayout only support uncompressed image"); - return nullptr; - } - - CubemapLayout* layout = nullptr; - CubemapLayoutInfo* info = GetCubemapLayoutInfo(image); - if (info) - { - layout = new CubemapLayout(); - layout->m_info = GetCubemapLayoutInfo(image); - layout->m_image = image; - layout->m_faceSize = image->GetWidth(0)/layout->m_info->m_columns; - } - return layout; - } - - - CubemapLayoutInfo* CubemapLayout::GetCubemapLayoutInfo(CubemapLayoutType type) - { - if (type == CubemapLayoutNone) - { - return nullptr; - } - - //if it's never initialized - if (s_layoutList[0].m_type == CubemapLayoutNone) - { - InitCubemapLayoutInfos(); - } - - return &s_layoutList[type]; - } - - CubemapLayoutInfo* CubemapLayout::GetCubemapLayoutInfo(IImageObjectPtr image) - { - //if it's never initialized - if (s_layoutList[0].m_type == CubemapLayoutNone) - { - InitCubemapLayoutInfos(); - } - - if (image == nullptr) - { - return nullptr; - } - - uint32 width, height; - width = image->GetWidth(0); - height = image->GetHeight(0); - CubemapLayoutInfo* info = nullptr; - - for (int i = 0; i < CubemapLayoutTypeCount; i++) - { - if (width * s_layoutList[i].m_rows == height*s_layoutList[i].m_columns) - { - info = &s_layoutList[i]; - - //we require the face size need to be power of two - if (IsPowerOfTwo(width / info->m_columns)) - { - return info; - } - else - { - return nullptr; - } - } - } - return nullptr; - } - - //public functions to get faces information for associated image - AZ::u32 CubemapLayout::GetFaceSize() - { - return m_faceSize; - } - - CubemapLayoutInfo* CubemapLayout::GetLayoutInfo() - { - return m_info; - } - - CubemapFaceDirection CubemapLayout::GetFaceDirection(CubemapFace face) - { - return m_info->m_faceInfos[face].direction; - } - - void CubemapLayout::GetFaceData(CubemapFace face, void* outBuffer, AZ::u32& outSize) - { - //only valid for uncompressed - AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->GetPixelFormat())->bitsPerBlock / 8; - - AZ::u8* imageBuf; - AZ::u32 dwPitch; - m_image->GetImagePointer(0, imageBuf, dwPitch); - AZ::u8* dstBuf = (AZ::u8*)outBuffer; - - AZ::u32 startX = m_info->m_faceInfos[face].column * m_faceSize; - AZ::u32 startY = m_info->m_faceInfos[face].row * m_faceSize; - - //face size is same as rows for uncompressed format - for (AZ::u32 y = 0; y < m_faceSize; y++) - { - AZ::u32 scanlineSize = m_faceSize*sizePerPixel; - AZ::u8* srcBuf = &imageBuf[(startY + y) * dwPitch + startX*sizePerPixel]; - memcpy(dstBuf, srcBuf, scanlineSize); - dstBuf += scanlineSize; - } - - outSize = m_faceSize*m_faceSize*sizePerPixel; - - } - - void CubemapLayout::SetFaceData(CubemapFace face, void* dataBuffer, [[maybe_unused]] AZ::u32 dataSize) - { - //only valid for uncompressed - AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->GetPixelFormat())->bitsPerBlock / 8; - - AZ::u8* imageBuf; - AZ::u32 dwPitch; - m_image->GetImagePointer(0, imageBuf, dwPitch); - AZ::u8* srcBuf = (AZ::u8*)dataBuffer; - - AZ::u32 startX = m_info->m_faceInfos[face].column * m_faceSize; - AZ::u32 startY = m_info->m_faceInfos[face].row * m_faceSize; - - //face size is same as rows for uncompressed format - for (AZ::u32 y = 0; y < m_faceSize; y++) - { - AZ::u32 scanlineSize = m_faceSize*sizePerPixel; - AZ::u8* dstBuf = &imageBuf[(startY + y) * dwPitch + startX*sizePerPixel]; - memcpy(dstBuf, srcBuf, scanlineSize); - srcBuf += scanlineSize; - } - } - - void* CubemapLayout::GetFaceMemBuffer(AZ::u32 mip, CubemapFace face, AZ::u32& outPitch) - { - if (CubemapLayoutVertical != m_info->m_type) - { - AZ_Assert(false, "this should only be used for CubemapLayoutVertical which has continous memory for each face"); - return nullptr; - } - - AZ::u32 faceSize = m_faceSize >> mip; - AZ::u8* imageBuf; - m_image->GetImagePointer(mip, imageBuf, outPitch); - AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize; - - //use startY is same as rows from m_image since the pixel format is uncompressed - return &imageBuf[startY * outPitch]; - } - - void CubemapLayout::SetToFaceMemBuffer(AZ::u32 mip, CubemapFace face, void* dataBuffer) - { - if (CubemapLayoutVertical != m_info->m_type) - { - AZ_Assert(false, "this should only be used for CubemapLayoutVertical which has continuous memory for each face"); - return; - } - - AZ::u32 faceSize = m_faceSize >> mip; - AZ::u32 pitch; - AZ::u8* imageBuf; - m_image->GetImagePointer(mip, imageBuf, pitch); - AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize; - - //use startY is same as rows from m_image since the pixel format is uncompressed - memcpy(&imageBuf[startY * pitch], dataBuffer, faceSize*pitch); - } - - void CubemapLayout::GetRectForFace(AZ::u32 mip, CubemapFace face, QRect& outRect) - { - AZ::u32 faceSize = m_faceSize >> mip; - AZ::u32 startY = m_info->m_faceInfos[face].row * faceSize; - AZ::u32 startX = m_info->m_faceInfos[face].column * faceSize; - - outRect.setRect(startX, startY, faceSize, faceSize); - } - - bool ImageToProcess::ConvertCubemapLayout(CubemapLayoutType dstLayoutType) - { - const EPixelFormat srcPixelFormat = m_img->GetPixelFormat(); - - //it need to be uncompressed format - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcPixelFormat)) - { - AZ_Assert(false, "Please convert the image to uncompressed pixel format before calling ConvertCubemapLayout"); - return false; - } - - //check if it's valid cubemap size - CubemapLayoutInfo* layoutInfo = CubemapLayout::GetCubemapLayoutInfo(m_img); - if (layoutInfo == nullptr) - { - AZ_Error("Image Processing", false, "The original image doesn't have a valid size (layout) as cubemap"); - return false; - } - - //if the source is same as output layout, return directly - if (layoutInfo->m_type == dstLayoutType) - { - return true; - } - - CubemapLayoutInfo* dstLayoutInfo = CubemapLayout::GetCubemapLayoutInfo(dstLayoutType); - - //create cubemap layout for source image for later operation. - CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img); - AZ::u32 faceSize = srcCubemap->GetFaceSize(); - - //create new image with same pixel format and copy prperties from source image - IImageObjectPtr newImage(IImageObject::CreateImage(faceSize * dstLayoutInfo->m_columns, - faceSize*dstLayoutInfo->m_rows, 1, srcPixelFormat)); - CubemapLayout *dstCubemap = CubemapLayout::CreateCubemapLayout(newImage); - newImage->CopyPropertiesFrom(newImage); - - //copy data from src cube to dst cube for each face - //temp buf for copy over data - AZ::u32 sizePerPixel = CPixelFormats::GetInstance().GetPixelFormatInfo(srcPixelFormat)->bitsPerBlock/8; //only valid for uncompressed - AZ::u8 *buf = new AZ::u8[faceSize*faceSize*sizePerPixel]; - AZ::u8 *tempBuf = new AZ::u8[faceSize*faceSize*sizePerPixel]; - - for (AZ::u32 faceIdx = 0; faceIdx < FaceCount; faceIdx++) - { - AZ::u32 outSize = 0; - CubemapFace face = (CubemapFace)faceIdx; - srcCubemap->GetFaceData(face, buf, outSize); - CubemapFaceDirection srcDir = srcCubemap->GetFaceDirection(face); - CubemapFaceDirection dstDir = dstCubemap->GetFaceDirection(face); - if (srcDir == dstDir) - { - dstCubemap->SetFaceData(face, buf, outSize); - } - else - { - //transform the image - TransformImage(srcDir, dstDir, buf, tempBuf, sizePerPixel, faceSize); - dstCubemap->SetFaceData(face, tempBuf, outSize); - } - } - - //clean up - delete[] buf; - delete[] tempBuf; - delete srcCubemap; - delete dstCubemap; - - newImage->AddImageFlags(EIF_Cubemap); - m_img = newImage; - return true; - } - - bool ImageConvertProcess::FillCubemapMipmaps() - { - //this function only works with pixel format rgba32f - const EPixelFormat srcPixelFormat = m_image->Get()->GetPixelFormat(); - if (srcPixelFormat != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s only works with pixel format rgba32f", __FUNCTION__); - return false; - } - - //only if the src image has one mip - if (m_image->Get()->GetMipCount() != 1) - { - AZ_Assert(false, "%s called for a mipmapped image. ", __FUNCTION__); - return false; - } - - CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_image->Get()); - - uint32 outWidth; - uint32 outHeight; - uint32 outReduce = 0; - AZ::u32 srcFaceSize = srcCubemap->GetFaceSize(); - //get output face size - GetOutputExtent(srcFaceSize, srcFaceSize, outWidth, outHeight, outReduce, &m_textureSetting, &m_presetSetting); - AZ_Assert(outWidth == outHeight, "something wrong with GetOutputExtent function"); - - //get final cubemap image size - outWidth *= srcCubemap->GetLayoutInfo()->m_columns; - outHeight *= srcCubemap->GetLayoutInfo()->m_rows; - - //max mipmap count - uint32 maxMipCount; - if (m_presetSetting.m_mipmapSetting == nullptr || !m_textureSetting.m_enableMipmap) - { - maxMipCount = 1; - } - else - { - //calculate based on face size, and use final export format which may save some low level mip calculation - maxMipCount = CPixelFormats::GetInstance().ComputeMaxMipCount(m_presetSetting.m_pixelFormat, srcFaceSize, srcFaceSize); - - //the FilterImage function won't do well with rect size 1. avoiding cubemap with face size 1 - if (srcFaceSize >> maxMipCount == 1 && maxMipCount > 1) - { - maxMipCount -= 1; - } - } - - //create new new output image with proper face - IImageObjectPtr outImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, srcPixelFormat)); - outImage->CopyPropertiesFrom(m_image->Get()); - CubemapLayout *dstCubemap = CubemapLayout::CreateCubemapLayout(outImage); - AZ::u32 outFaceSize = dstCubemap->GetFaceSize(); - AZ::u32 dstMipCount = outImage->GetMipCount(); - - //filter the image for top mip first - for (int iSide = 0; iSide < 6; ++iSide) - { - QRect srcRect; - QRect dstRect; - - srcRect.setLeft(0); - srcRect.setRight(srcFaceSize); - srcRect.setTop(iSide * srcFaceSize); - srcRect.setBottom((iSide + 1) * srcFaceSize); - - dstRect.setLeft(0); - dstRect.setRight(outFaceSize); - dstRect.setTop(iSide * outFaceSize); - dstRect.setBottom((iSide + 1) * outFaceSize); - - FilterImage(m_textureSetting.m_mipGenType, m_textureSetting.m_mipGenEval, 0, 0, m_image->Get(), 0, - outImage, 0, &srcRect, &dstRect); - } - - - CCubeMapProcessor atiCubemanGen; - //ATI's cubemap generator to filter the image edges to avoid seam problem - // https://gpuopen.com/archive/gamescgi/cubemapgen/ - - //the thread support was done with windows thread function so it's removed for multi-dev platform support - atiCubemanGen.m_NumFilterThreads = 0; - - // input and output cubemap set to have save dimensions, - atiCubemanGen.Init(outFaceSize, outFaceSize, dstMipCount, 4); - - // Load the 6 faces of the input cubemap and copy them into the cubemap processor - void* pMem; - uint32 nPitch; - - for (int iFace = 0; iFace < 6; ++iFace) - { - pMem = dstCubemap->GetFaceMemBuffer(0, (CubemapFace)iFace, nPitch); - atiCubemanGen.SetInputFaceData( - iFace, // FaceIdx, - CP_VAL_FLOAT32, // SrcType, - 4, // SrcNumChannels, - nPitch, // SrcPitch, - pMem, // SrcDataPtr, - 1000000.0f, // MaxClamp, - 1.0f, // Degamma, - 1.0f); // Scale - } - - //Filter cubemap - atiCubemanGen.InitiateFiltering( - m_presetSetting.m_cubemapSetting->m_angle, //BaseFilterAngle, - m_presetSetting.m_cubemapSetting->m_mipAngle, //InitialMipAngle, - m_presetSetting.m_cubemapSetting->m_mipSlope, //MipAnglePerLevelScale, - (int)m_presetSetting.m_cubemapSetting->m_filter, //FilterType, CP_FILTER_TYPE_COSINE for diffuse cube - m_presetSetting.m_cubemapSetting->m_edgeFixup > 0? CP_FIXUP_PULL_LINEAR : CP_FIXUP_NONE, //FixupType, CP_FIXUP_PULL_LINEAR if FixupWidth> 0 - m_presetSetting.m_cubemapSetting->m_edgeFixup, //FixupWidth, - true, //bUseSolidAngle, - 16, //GlossScale, - 0, //GlossBias - 128); //SampleCountGGX - - // Download data into it - for (int iFace = 0; iFace < 6; ++iFace) - { - for (unsigned int dstMip = 0; dstMip < dstMipCount; ++dstMip) - { - pMem = dstCubemap->GetFaceMemBuffer(dstMip, (CubemapFace)iFace, nPitch); - atiCubemanGen.GetOutputFaceData(iFace, dstMip, CP_VAL_FLOAT32, 4, nPitch, pMem, 1.0f, 1.0f); - } - } - - delete srcCubemap; - delete dstCubemap; - - //set back to image - m_image->Set(outImage); - return true; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/Cubemap.h b/Gems/ImageProcessing/Code/Source/Converters/Cubemap.h deleted file mode 100644 index 76dd8d2c30..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Cubemap.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - // note: O3DE is right hand Z up coordinate - // please don't change the order of the enum since we are using it to match the face id defined in AMD's CubemapGen - // and they are using left hand Y up coordinate - enum CubemapFace - { - FaceLeft = 0, - FaceRight, - FaceFront, - FaceBack, - FaceTop, - FaceBottom, - FaceCount - }; - - //we are treating the orientation of faces in 4x3 layout as the original direction. - enum class CubemapFaceDirection - { - DirNoRotation = 0, - DirRotateLeft90, - DirRotateRight90, - DirRotate180, - DirMirrorHorizontal - }; - - //this class contains information to describe a cubemap layout - class CubemapLayoutInfo - { - public: - struct FaceInfo - { - AZ::u8 row; - AZ::u8 column; - CubemapFaceDirection direction; - }; - - //rows and columns of how cubemap's faces laid - AZ::u8 m_rows; - AZ::u8 m_columns; - - //the type of this layout info for - CubemapLayoutType m_type; - - //the index of row and column where all the faces located - FaceInfo m_faceInfos[FaceCount]; - - CubemapLayoutInfo(); - void SetFaceInfo(CubemapFace face, AZ::u8 row, AZ::u8 col, CubemapFaceDirection dir); - }; - - //class to help doing operations with faces for an image as cubemap - class CubemapLayout - { - public: - //create a cubemapLayout object for the image. It can be used later to get image information as a cubemap - static CubemapLayout* CreateCubemapLayout(IImageObjectPtr image); - - //get layout info for input layout type - static CubemapLayoutInfo* GetCubemapLayoutInfo(CubemapLayoutType type); - - //get layout info for input image based on its size - static CubemapLayoutInfo* GetCubemapLayoutInfo(IImageObjectPtr image); - - //public functions to get faces information for associated image - AZ::u32 GetFaceSize(); - - //get the rect where the face in the image - void GetRectForFace(AZ::u32 mip, CubemapFace face, QRect& outRect); - - CubemapLayoutInfo* GetLayoutInfo(); - - //set/get pixels' data from/to specific face. only works for mip 0 - void GetFaceData(CubemapFace face, void* outBuffer, AZ::u32& outSize); - void SetFaceData(CubemapFace face, void* dataBuffer, AZ::u32 dataSize); - - //get the face's direction - CubemapFaceDirection GetFaceDirection(CubemapFace face); - - //get memory for a face from Image data. only works for CubemapLayoutVertical since its memory for each face is continuous - void* GetFaceMemBuffer(AZ::u32 mip, CubemapFace face, AZ::u32& outPitch); - void SetToFaceMemBuffer(AZ::u32 mip, CubemapFace face, void* dataBuffer); - - private: - //information for all supported cubemap layouts - static CubemapLayoutInfo s_layoutList[CubemapLayoutTypeCount]; - - //the image associated for this CubemapLayout - IImageObjectPtr m_image; - //the layout information of m_image - CubemapLayoutInfo *m_info; - //the size of the cubemap's face (which is square and power of 2). - uint32 m_faceSize; - - //private constructor. User should always use CreateCubemapLayout create a layout for an image object - CubemapLayout(); - - //initialize information of all available cubemap layouts - static void InitCubemapLayoutInfos(); - }; - -}//end namspace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/FIR-Filter.cpp b/Gems/ImageProcessing/Code/Source/Converters/FIR-Filter.cpp deleted file mode 100644 index 8d1b8f2877..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/FIR-Filter.cpp +++ /dev/null @@ -1,1285 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -/* #################################################################################################################### - */ -#define mallocAligned(sze) _aligned_malloc(sze, 16) -#define freeAligned(ptr) _aligned_free(ptr) - -/* #################################################################################################################### - */ - -namespace ImageProcessing -{ - class Rect2D - { - public: - /* ================================================================================================================== - * Rect2D = ??? - */ - Rect2D() { } - Rect2D(const int x, const int y) { visual[0] = x; visual[1] = y; } - - private: - int visual[2]; - - public: - /* ================================================================================================================== - * Access operators - * M(i, j) == [row i][col j] - */ - inline int& operator () (int i) { return visual[i]; } - inline int operator () (int i) const { return visual[i]; } - - inline int& operator [] (int i) { return visual[i]; } - inline int operator [] (int i) const { return visual[i]; } - - /* ================================================================================================================== - * Logical operators - */ - inline bool operator == (const Rect2D& tht) - { - return (visual[0] == tht.visual[0]) && - (visual[1] == tht.visual[1]); - } - }; - - /* #################################################################################################################### - */ - template - class Plane2D - { - public: - /* ================================================================================================================== - * Plane2D = ??? - */ - Plane2D(const int x, const int y, const int p) { planes = p; allocatedC[0] = x; allocatedC[1] = y; used = allocatedC; aligned[0] = (allocatedC[0] + 15) & (~15); aligned[1] = allocatedC[1]; allocate(); } - Plane2D(const Rect2D& i, const int p) { planes = p; allocatedC = i; used = allocatedC; aligned[0] = (allocatedC[0] + 15) & (~15); aligned[1] = allocatedC[1]; allocate(); } - - ~Plane2D() { deallocate(); } - - /* ================================================================================================================== - * ??? = Plane2D - */ - inline operator Rect2D() const { return used; } - inline operator int () const { return planes; } - - inline operator DataType* () const { return buffers; } - inline operator DataType*** () const { return rows; } - inline operator const DataType* () const { return (const DataType*)buffers; } - inline operator const DataType*** () const { return (const DataType***)rows; } - - public: - inline void locate(Rect2D take) - { - taken = take; - - if ((taken[0] > aligned[0]) || - (taken[1] > abs(aligned[1]))) - { - abort(); - } - - /* align column#length */ - used[0] = (taken[0] + 15) & (~15); - used[1] = taken[1]; - - for (int p = 0; p < planes; p++) - { - /* we may need to replicate the row-unsigned __int64 over all rows only (y < 0) */ - const unsigned long int rowsize = (aligned[1] <= 0 ? 0 : aligned[0] * sizeof(DataType)); - int r; - char* buffer; - AZ_Assert((rowsize % 16) == 0, "%s: Unexpected row size!", __FUNCTION__); - - /* first block contains the row*-pointers */ - rows[p] = (DataType**)((char*)(rows + planes) + rowblocksize * p) + excess; - - /* "excess" empty pointers on negative offsets ----------------------------- */ - buffer = (char*)NULL; - AZ_Assert((reinterpret_cast(buffer) % 16) == 0, "%s: Unexpected buffer size!", __FUNCTION__); - - - for (r = -excess; r < 0; r++) - { - rows[p][r] = (DataType*)buffer; - } - - /* regular row-pointers ---------------------------------------------------- */ - buffer = (char*)buffers + (planesize * p); - AZ_Assert((reinterpret_cast(buffer) % 16) == 0, "%s: Unexpected buffer size!", __FUNCTION__); - - for (r = 0; r < abs(aligned[1]); r++, buffer += rowsize) - { - rows[p][r] = (DataType*)buffer; - } - - /* overhanging row-pointers show on the first valid row (loop) ------------- */ - buffer = (char*)buffers + (planesize * p); - AZ_Assert((reinterpret_cast(buffer) % 16) == 0, "%s: Unexpected buffer size!", __FUNCTION__); - - - for (r = abs(aligned[1]); r < abs(aligned[1]) + excess; r++, buffer += rowsize) - { - rows[p][r] = (DataType*)buffer; - } - } - } - - inline void clear() - { - memset(buffers, 0, planesize * planes); - } - - inline void delocate() - { - memset(buffers, 0, planesize * planes); - memset(rows, 0, sizeof(DataType * *) * planes + rowblocksize * planes); - } - - inline void relocate(Rect2D take) - { - delocate(); - locate(take); - } - - protected: - inline void allocate () - { - /* adjust rows */ - allocatedC[0] = allocatedC[0]; - allocatedC[1] = maximum(1, allocatedC[1]); - - /* if "(y < 0)", we allocate exactly 1 row and replicate it over "abs(y)" */ - planesize = sizeof(DataType) * aligned[0] * maximum(1, aligned[1]); - rowblocksize = sizeof(DataType*) * (abs(aligned[1]) + (2 * excess) + 16); - - /* all planes after each other: - * - * start -> plane0 -> plane1 -> ... - */ - buffers = (DataType* )AZ_OS_MALLOC(planesize * planes, 16); - /* all pointers after each other: - * - * start -> unsigned __int64 to planes -> unsigned __int64 to rows of planes - */ - rows = (DataType***)AZ_OS_MALLOC(sizeof(DataType * *) * planes + rowblocksize * planes, 16); - - /* ensure the blocks are aligned */ - AZ_Assert(((AZ::s64)buffers % 16) == 0, "%s: Expect blocks are aligned!", __FUNCTION__); - /* ensure the planes concat aligned */ - AZ_Assert((planesize % 16) == 0, "%s: Expect planes concat is aligned!", __FUNCTION__); - - locate(allocatedC); - } - - inline void deallocate() - { - AZ_OS_FREE(buffers); - AZ_OS_FREE(rows); - } - - Rect2D allocatedC, aligned; // real buffer sizes and its aligned counterpart - Rect2D taken, used; // actually taken sizes and its aligned counterpart - - int planes; - long int planesize, rowblocksize; - DataType* buffers; - DataType*** rows; - }; - - /* #################################################################################################################### \ - */ - #define filterTVariables(filterVxNNum, dtyp, wtyp, reps) \ - /* addition of c-pointers already takes care of datatype-sizes */ \ - const signed long int dy = /*parm->mirror ? -1 :*/ 1; \ - const unsigned int stridei = parm->incols * 1 * 1; \ - const unsigned int stridet = parm->subcols * 1 * 1; \ - const unsigned int strideo = parm->outcols * 1 * 1; \ - /* offset and shift calculations still require the unmodified values */ \ - const unsigned int strideiraw = parm->incols; \ - const unsigned int stridetraw = parm->subcols; \ - const unsigned int strideoraw = parm->outcols; \ - \ - class Plane2D tmp(tmpcols, tmprows, 4); \ - dtyp*** t = (dtyp***)tmp; \ - int srcPos, dstPos; \ - bool plusminush = false; const bool of = true; \ - bool plusminusv = false; const bool nc = false; \ - FilterWeights* fwh = calculateFilterWeights(parm->resample.colrem, parm->caged ? 0 : 0 - parm->region.subtop, parm->caged ? srccols : parm->subrows - parm->region.subtop, \ - parm->resample.colquo, 0, dstcols, reps, parm->resample.colblur, parm->resample.wf, parm->resample.operation != eWindowEvaluation_Sum, plusminush); \ - FilterWeights* fwv = calculateFilterWeights(parm->resample.rowrem, parm->caged ? 0 : 0 - parm->region.intop, parm->caged ? srcrows : parm->inrows - parm->region.intop, \ - parm->resample.rowquo, 0, dstrows, reps, parm->resample.rowblur, parm->resample.wf, parm->resample.operation != eWindowEvaluation_Sum, plusminusv); \ - - #define filterFTVariables(filterVxNNum) \ - filterTVariables(filterVxNNum, float, signed short, 1) - - /* #################################################################################################################### \ - */ - #define filterTCleanUp(filterVxNNum) \ - delete[] fwh; \ - delete[] fwv; - - /* #################################################################################################################### \ - */ - #define filterTInitLoop() - - /* ******************************************************************************************************************** \ - */ - #define filterTExitLoop() - - /* #################################################################################################################### \ - */ - #define filter4xNf(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip, init, next, fetch, store, exit, op, pm, hv, dtyp, atyp) \ - init(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip); \ - \ - dstPos = 0; do { \ - FilterWeights& fw = *(hv + dstPos); \ - const signed short* w = fw.weights; \ - \ - next(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip); \ - \ - atyp res0 = (op != eWindowEvaluation_Min ? 0 : 32768); \ - atyp res1 = (op != eWindowEvaluation_Min ? 0 : 32768); \ - atyp res2 = (op != eWindowEvaluation_Min ? 0 : 32768); \ - atyp res3 = (op != eWindowEvaluation_Min ? 0 : 32768); \ - \ - srcPos = fw.first; do { \ - /* get value */ \ - fetch(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip); \ - \ - /* build result using sign inverted weights [32767,-32768] */ \ - if constexpr (op == eWindowEvaluation_Sum) { \ - res0 -= ((atyp)_0 * *w); \ - res1 -= ((atyp)_1 * *w); \ - res2 -= ((atyp)_2 * *w); \ - res3 -= ((atyp)_3 * *w++); \ - } \ - else if constexpr (op == eWindowEvaluation_Max) { \ - res0 = maximum(res0, -(atyp)_0 * *w); \ - res1 = maximum(res1, -(atyp)_1 * *w); \ - res2 = maximum(res2, -(atyp)_2 * *w); \ - res3 = maximum(res3, -(atyp)_3 * *w++); \ - } \ - else if constexpr (op == eWindowEvaluation_Min) { \ - res0 = (atyp)32768.0 - maximum((atyp)32768.0 - res0, -(atyp)(1.0f - _0) * *w); \ - res1 = (atyp)32768.0 - maximum((atyp)32768.0 - res1, -(atyp)(1.0f - _1) * *w); \ - res2 = (atyp)32768.0 - maximum((atyp)32768.0 - res2, -(atyp)(1.0f - _2) * *w); \ - res3 = (atyp)32768.0 - maximum((atyp)32768.0 - res3, -(atyp)(1.0f - _3) * *w++); \ - } \ - } while (++srcPos < fw.last); \ - \ - /* dtyp _0 = ldexp((dtyp)res0, -15); */ \ - /* dtyp _1 = ldexp((dtyp)res1, -15); */ \ - /* dtyp _2 = ldexp((dtyp)res2, -15); */ \ - /* dtyp _3 = ldexp((dtyp)res3, -15); */ \ - \ - dtyp _0 = (dtyp)res0 * (dtyp)(1.0 / 32768.0); \ - dtyp _1 = (dtyp)res1 * (dtyp)(1.0 / 32768.0); \ - dtyp _2 = (dtyp)res2 * (dtyp)(1.0 / 32768.0); \ - dtyp _3 = (dtyp)res3 * (dtyp)(1.0 / 32768.0); \ - \ - /* put value */ \ - store(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip); \ - } while (++dstPos < (signed)dstSize); \ - \ - exit(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip); - - #define filterF4xNHor(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip, init, next, fetch, store, exit, op, pm) \ - filter4xNf(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip, init, next, fetch, store, exit, op, 0, fwh, float, float /*double*/) - - #define filterF4xNVer(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip, init, next, fetch, store, exit, op, pm) \ - filter4xNf(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip, init, next, fetch, store, exit, op, 0, fwv, float, float /*double*/) - - /* #################################################################################################################### \ - */ - #define resampleF4xNFromPlane(stride) \ - float _0, _1, _2, _3; \ - \ - _0 = (*i0)[ix], i0 += (stride) * dy; \ - _1 = (*i1)[ix], i1 += (stride) * dy; \ - _2 = (*i2)[ix], i2 += (stride) * dy; \ - _3 = (*i3)[ix], i3 += (stride) * dy; - - /* ******************************************************************************************************************** \ - */ - #define resampleF4xNFromStream(stride, instream) \ - float _0, _1, _2, _3; \ - \ - _0 = instream[0]; \ - _1 = instream[1]; \ - _2 = instream[2]; \ - _3 = instream[3], instream += (stride) * 4; - - /* ******************************************************************************************************************** \ - */ - #define resampleF4xNFromStreamSwapped(stride, instream) \ - float _0, _1, _2, _3; \ - \ - _3 = instream[0]; \ - _2 = instream[1]; \ - _1 = instream[2]; \ - _0 = instream[3], instream += (stride) * 4; - - /* #################################################################################################################### \ - */ - #define resampleF4xNToPlane(stride) \ - (*o0)[ox] = _0; \ - (*o1)[ox] = _1; \ - (*o2)[ox] = _2; \ - (*o3)[ox] = _3, ox += (1) * 1; - - /* ******************************************************************************************************************** \ - */ - #define resampleF4xNToStream(stride, outstream) \ - outstream[0] = _0; \ - outstream[1] = _1; \ - outstream[2] = _2; \ - outstream[3] = _3, outstream += (1) * 4; - - /* ******************************************************************************************************************** \ - */ - #define resampleF4xNToStreamSwapped(stride, outstream) \ - outstream[0] = _3; \ - outstream[1] = _2; \ - outstream[2] = _1; \ - outstream[3] = _0, outstream += (1) * 4; - - /* #################################################################################################################### \ - */ - #undef filterF4xNFromPlane - #define filterF4xNFromPlane(stride) \ - resampleF4xNFromPlane(stride) - - /* ******************************************************************************************************************** \ - */ - #undef filterF4xNFromStream - #define filterF4xNFromStream(stride, instream) \ - resampleF4xNFromStream(stride, instream) - - /* ******************************************************************************************************************** \ - */ - #undef filterF4xNFromStreamSwapped - #define filterF4xNFromStreamSwapped(stride, instream) \ - resampleF4xNFromStreamSwapped(stride, instream) - - /* #################################################################################################################### \ - */ - #undef filterF4xNToPlane - #define filterF4xNToPlane(stride) \ - resampleF4xNToPlane(stride) - - /* ******************************************************************************************************************** \ - */ - #undef filterF4xNToStream - #define filterF4xNToStream(stride, outstream) \ - resampleF4xNToStream(stride, outstream) - - /* ******************************************************************************************************************** \ - */ - #undef filterF4xNToStreamSwapped - #define filterF4xNToStreamSwapped(stride, outstream) \ - resampleF4xNToStreamSwapped(stride, outstream) - - /* #################################################################################################################### \ - */ - #define loopEnter(id, untill, advance) \ - unsigned int id; for (id = 0; id < untill; id += advance) { - #define loopLeave(id, untill, advance) \ - } - - /* #################################################################################################################### \ - */ - #define all4InitSwappablePlanePointers(left, top, row, rows, pp, swap, dtyp) \ - dtyp * pp##0, *pp##1, *pp##2, *pp##3; \ - \ - pp##0 = pp[0][/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)] + left; /* r */ \ - pp##1 = pp[1][/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)] + left; /* g */ \ - pp##2 = pp[2][/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)] + left; /* b */ \ - pp##3 = pp[3][/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)] + left; /* a */ - - #define allF4InitSwappablePlanePointers(left, top, row, rows, pp, swap) \ - all4InitSwappablePlanePointers(left, top, row, rows, pp, swap, float) - - /* #################################################################################################################### \ - */ - #define all4InitFixedPlanePointers(left, top, row, rows, pp, swap, dtyp) \ - dtyp * pp##0, *pp##1, *pp##2, *pp##3; \ - \ - pp##0 = pp[0][(row + top)] + left; /* r */ \ - pp##1 = pp[1][(row + top)] + left; /* g */ \ - pp##2 = pp[2][(row + top)] + left; /* b */ \ - pp##3 = pp[3][(row + top)] + left; /* a */ - - #define allF4InitFixedPlanePointers(left, top, row, rows, pp, swap) \ - all4InitFixedPlanePointers(left, top, row, rows, pp, swap, float) - - /* #################################################################################################################### \ - */ - #define all4InitSwappablePlaneReferences(left, offs, top, row, rows, pp, swap, dtyp) \ - unsigned long int pp##x = left + offs; \ - dtyp** pp##0; \ - dtyp** pp##1; \ - dtyp** pp##2; \ - dtyp** pp##3; \ - \ - pp##0 = pp[0] + (/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)); /* r */ \ - pp##1 = pp[1] + (/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)); /* g */ \ - pp##2 = pp[2] + (/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)); /* b */ \ - pp##3 = pp[3] + (/*parm->mirror ? (rows - 1) - (row + top) :*/ (row + top)); /* a */ - - #define allF4InitSwappablePlaneReferences(left, offs, top, row, rows, pp, swap) \ - all4InitSwappablePlaneReferences(left, offs, top, row, rows, pp, swap, float) - - /* #################################################################################################################### \ - */ - #define all4InitFixedPlaneReferences(left, row, rows, pp, ps, dtyp) \ - unsigned long int pp##x = left; \ - dtyp** pp##0; \ - dtyp** pp##1; \ - dtyp** pp##2; \ - dtyp** pp##3; \ - \ - pp##0 = ps[0] + (row); /* r */ \ - pp##1 = ps[1] + (row); /* g */ \ - pp##2 = ps[2] + (row); /* b */ \ - pp##3 = ps[3] + (row); /* a */ - - #define allF4InitFixedPlaneReferences(left, row, rows, pp, ps) \ - all4InitFixedPlaneReferences(left, row, rows, pp, ps, float) - - /* #################################################################################################################### \ - */ - #define allF4AdvanceSwappablePlaneReferences(row, rows, pp) \ - pp##0 += (rows - row) * dy; /* r */ \ - pp##1 += (rows - row) * dy; /* g */ \ - pp##2 += (rows - row) * dy; /* b */ \ - pp##3 += (rows - row) * dy; /* a */ - - /* #################################################################################################################### \ - */ - #define allF4AdvanceFixedPlaneReferences(row, rows, pp) \ - allF4AdvanceSwappablePlaneReferences(row, rows, pp) - - /* #################################################################################################################### \ - */ - #define allF4AdvanceStreamPointer(left, col, cols, sp) \ - sp += ((cols) - (left + col)) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvNMULStreamPointer(top, stride, sp) \ - sp -= ((stride) * (top)) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvPMULStreamPointer(top, stride, sp) \ - sp += ((stride) * (top)) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvSUBMStreamPointer(left, top, stride, sp) \ - sp -= (((stride) * (top)) - (left)) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvADDMStreamPointer(left, top, stride, sp) \ - sp += ((left) + ((stride) * (top))) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvPADDStreamPointer(offs, sp) \ - sp += (offs) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvSSUBStreamPointer(top, shift, offs, sp) \ - sp += (((top) << (shift)) - (offs)) * 4; - - /* ******************************************************************************************************************** \ - */ - #define allF4AdvNAMAStreamPointer(left, top, offs, stride, sp) \ - sp -= ((left) + (((top) + (offs)) * (stride))) * 4; - - /* ################################################################################################################### \ - */ - #undef comcpyFNum - #define comcpyFNum 1 - #undef orderedFNum - #define orderedFNum 1 - #undef orderedFShift - #define orderedFShift 0 - #undef interleavedFNum - #define interleavedFNum 1 - - /* #################################################################################################################### \ - */ - # define allTInitFixedOutPlaneReferences allF4InitFixedPlaneReferences - # define allTInitFixedInPlaneReferences allF4InitFixedPlaneReferences - # define allCInitSwappableInPlaneReferences /*allF4InitSwappablePlaneReferences*/ - # define allCInitSwappableOutPlaneReferences /*allF4InitSwappablePlaneReferences*/ - - # define allCAdvADDMInStreamPointer allF4AdvADDMStreamPointer - # define allCAdvPADDInStreamPointer allF4AdvPADDStreamPointer - # define allCAdvPMULInStreamPointer allF4AdvPMULStreamPointer - # define allCAdvNMULInStreamPointer allF4AdvNMULStreamPointer - # define allCAdvADDMOutStreamPointer allF4AdvADDMStreamPointer - # define allCAdvSSUBOutStreamPointer allF4AdvSSUBStreamPointer - - # define getCxNFromStreamSwapped /*filterF4xNFromStreamSwapped*/ - # define getCxNFromStream filterF4xNFromStream - # define getCxNFromPlane /*filterF4xNFromPlane*/ - # define getTxNFromPlane filterF4xNFromPlane - - # define filterHor filterF4xNHor - # define filterVer filterF4xNVer - - # define comcpyCCheckHiLo() /*orderedF4CheckHiLo*/ - # define comcpyCCoVar() /*orderedF4CoVar*/ - # define comcpyCHistogram() /*orderedF4Histogram*/ - - # define putCxNToStreamSwapped /*filterF4xNToStreamSwapped*/ - # define putCxNToStream filterF4xNToStream - # define putCxNToPlane /*filterF4xNToPlane*/ - # define putTxNToPlane filterF4xNToPlane - - # define orderedNum orderedFNum - # define orderedShift orderedFShift - - # define comcpyCMergeHiLo(orderedNum) /*comcpyFTMergeHiLo*/ - # define comcpyCCompleteCoVar(orderedNum) /*comcpyFTCompleteCoVar*/ - # define comcpyCCompleteHistogram(orderedNum) /*comcpyFTCompleteHistogram*/ - - # define hiloCVariables /*hiloFTVariables*/ - # define covarCVariables /*covarFTVariables*/ - # define histoCVariables /*histoFTVariables*/ - - # define filterCVariables filterFTVariables - - # define orderedTInitLoop() /*orderedTInitLoop*/ - # define hiloTInitLoop() /*hiloTInitLoop*/ - # define covarTInitLoop() /*covarTInitLoop*/ - # define histoTInitLoop() /*histoTInitLoop*/ - - # define orderedTExitLoop() /*orderedTExitLoop*/ - # define hiloTExitLoop() /*hiloTExitLoop*/ - # define covarTExitLoop() /*covarTExitLoop*/ - # define histoTExitLoop() /*histoTExitLoop*/ - - # define filterCCleanUp filterTCleanUp - - /* #################################################################################################################### \ - */ - - struct prcparm - { - /* configuration -------------------------------------------------------------------------------- */ - - /* dimensions of the source/destination image */ - int inrows, outrows, subrows; - int incols, outcols, subcols; - - /* region to process the stuff in */ - bool regional; - /* don't fetch data from outside the region */ - bool caged; - struct - { - /* offsets to the source/destination image-region */ - int intop, outtop, subtop; - int inleft, outleft, subleft; - - /* dimensions of the source/destination image-region */ - int inrows, outrows, subrows; - int incols, outcols, subcols; - } region; - - /* parameters ----------------------------------------------------------------------------------- */ - - /* parameters for resampling */ - struct - { - /* we don't give floating-point x/y-factor, it's not exact enough */ - unsigned int rowquo, rowrem; - unsigned int colquo, colrem; - - /* over/under-blurring (window minification/magnification) */ - float rowblur, colblur; - - /* the windowing-function for the filtering */ - IWindowFunction* wf; - - /* operation to perform the filter with */ - int operation; - } resample; - - /* private stuff -------------------------------------------------------------------------------- */ - - /* what really has do be done after choosing/recalculation */ - int dorows, docols; - }; - - static void CheckBoundaries(const void* i, void* o, struct prcparm* parm) - { - /* the parameter evaluation ----------------------------------------------- */ - const bool scaler = true; - - /* this is fairly straightforward */ - if (!parm->regional) - { - int rgrows = parm->inrows; - int rgcols = parm->incols; - - /* compare out-region against available out-size */ - if (o) - { - int dorows = parm->outrows; - int docols = parm->outcols; - - /* scale up */ - if (scaler) - { - dorows = dorows * parm->resample.rowrem / parm->resample.rowquo; - docols = docols * parm->resample.colrem / parm->resample.colquo; - } - - /* compare in scaled space */ - rgrows = maximum(rgrows, dorows); - rgcols = maximum(rgcols, docols); - - /* scale down */ - if (scaler) - { - rgrows = rgrows * parm->resample.rowquo / parm->resample.rowrem; - rgcols = rgcols * parm->resample.colquo / parm->resample.colrem; - } - } - - parm->dorows = rgrows; - parm->docols = rgcols; - } - /* this may need some adjustment */ - else - { - int rgrows = parm->region.inrows; - int rgcols = parm->region.incols; - - /* compare in/out-region against available out-size */ - if (o) - { - int dorows = parm->region.outrows; - int docols = parm->region.outcols; - - /* compare out-region against available in-size */ - if (dorows > parm->outrows - parm->region.outtop) - { - dorows = parm->outrows - parm->region.outtop; - } - if (docols > parm->outcols - parm->region.outleft) - { - docols = parm->outcols - parm->region.outleft; - } - - /* scale to in */ - if (scaler) - { - dorows = dorows * parm->resample.rowrem / parm->resample.rowquo; - docols = docols * parm->resample.colrem / parm->resample.colquo; - } - - /* compare in scaled space */ - rgrows = maximum(rgrows, dorows); - rgcols = maximum(rgcols, docols); - - /* compare in-region against available in-size */ - if (i) - { - if (rgrows > parm->inrows - parm->region.intop) - { - rgrows = parm->inrows - parm->region.intop; - } - if (rgcols > parm->incols - parm->region.inleft) - { - rgcols = parm->incols - parm->region.inleft; - } - } - - /* scale to out */ - if (scaler) - { - rgrows = rgrows * parm->resample.rowquo / parm->resample.rowrem; - rgcols = rgcols * parm->resample.colquo / parm->resample.colrem; - } - } - else - { - /* compare in-region against available in-size */ - if (i) - { - if (rgrows > parm->inrows - parm->region.intop) - { - rgrows = parm->inrows - parm->region.intop; - } - if (rgcols > parm->incols - parm->region.inleft) - { - rgcols = parm->incols - parm->region.inleft; - } - } - } - - parm->dorows = rgrows; - parm->docols = rgcols; - } - - AZ_Assert(parm->dorows > 0, "%s: Expect row count to be above zero!", __FUNCTION__); - AZ_Assert(parm->docols > 0, "%s: Expect column count to be above zero!", __FUNCTION__); - } - - /* #################################################################################################################### \ - * multi-threadable if needed - */ - static void RunAlgorithm(const float* i, float* o, struct prcparm* parm) - { - /* make these local, so no indirect access is needed */ - const unsigned int srcrows = parm->dorows * parm->resample.rowrem / parm->resample.rowquo; - const unsigned int srccols = parm->docols * parm->resample.colrem / parm->resample.colquo; - const unsigned int dstrows = parm->dorows; - const unsigned int dstcols = parm->docols; - const unsigned int cstZero = 0; - - /* temporary buffer region */ - parm->subrows = srccols; - parm->subcols = dstrows; - parm->region.subleft = 0; - parm->region.subtop = 0; - parm->region.subcols = parm->subcols; - parm->region.subrows = parm->subrows; - - if (!parm->caged) - { - int oleft; - int oright; - - /* check for out-of-region access rectangle */ - calculateFilterRange(srccols, oleft, oright, dstcols, 0, dstcols, parm->resample.colblur, parm->resample.wf); - - /* round down left, round up right */ - oleft = oleft & (~(orderedNum - 1)); - oright = (oright + (orderedNum - 1)) & (~(orderedNum - 1)); - - /* clamp to available image-rectangle */ - if ((oleft < (signed)parm->region.subtop) || - (oright > (signed)parm->subrows)) - { - oleft = maximum(oleft, -(signed)parm->region.inleft); - oright = minimum(oright, (signed)parm->incols); - } - - /* readjust temporary buffer region to include out-of-region accesses */ - parm->region.inleft += oleft; //rm->docols -= oleft; //rm->docols += (oright - srccols); - parm->region.subtop -= oleft; - parm->subrows -= oleft; - parm->subrows += (oright - srccols); - } - - const unsigned int tmprows = parm->subrows; - const unsigned int tmpcols = parm->subcols; - - /* -------------------------------------------------------------------------------------------- - * common resampling - */ - - /* init t */ - filterCVariables(orderedNum); - - filterTInitLoop(); - - /* -------------------------------------------------------------------------------------------- - * reading rows, writing cols (xy-flip) - * - * make srccol x inrow -> dstrow x srccol - * - * we are reading vertical, and writing horizontal - * in effect we can use fast parallel-reads, but need - * slow interleaved-writes - * as reads are slower (ask+receive) than writes (send) - * this should even be gracefully fast - */ - allCAdvADDMInStreamPointer(parm->region.inleft, parm->region.intop, parm->incols, i); - - #define filterRowInit(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - allTInitFixedOutPlaneReferences(cstZero, srcOffs, -, o, t); - - #define filterRowNext(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - /* every in/out-put may swap */ \ - allCInitSwappableInPlaneReferences(parm->region.inleft, srcOffs, parm->region.intop, fw.first, parm->inrows, i, false); \ - /* because the filter moves back and forth, we always have to reposition from 0 */ \ - allCAdvPMULInStreamPointer(srcSkip##raw, fw.first, i); - - #define filterRowFetch(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - /* vertical stride, horizontal fetch */ \ - getCxNFromStreamSwapped(srcSkip, i); \ - getCxNFromStream(srcSkip, i); \ - getCxNFromPlane(1); \ - \ - /*srcPos++;*/ - - #define filterRowStore(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - /* because the filter moves back and forth, we always have to reposition to 0 */ \ - allCAdvNMULInStreamPointer(srcSkip##raw, fw.last, i); \ - \ - /* horizontal stride, vertical store */ \ - putTxNToPlane(1); \ - \ - /*dstPos++;*/ - - #define filterRowExit(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - allCAdvPADDInStreamPointer(orderedNum, i); - - if (parm->resample.operation == eWindowEvaluation_Sum) - { - loopEnter(tmprow, tmprows, orderedNum); - - { - filterVer(tmprow, srcrows, stridei, - tmprow, dstrows, stridet, filterRowInit, filterRowNext, filterRowFetch, filterRowStore, filterRowExit, eWindowEvaluation_Sum, of); - } - - loopLeave(tmprow, tmprows, orderedNum); - } - else if (parm->resample.operation == eWindowEvaluation_Max) - { - loopEnter(tmprow, tmprows, orderedNum); - - { - filterVer(tmprow, srcrows, stridei, - tmprow, dstrows, stridet, filterRowInit, filterRowNext, filterRowFetch, filterRowStore, filterRowExit, eWindowEvaluation_Max, of); - } - - loopLeave(tmprow, tmprows, orderedNum); - } - else if (parm->resample.operation == eWindowEvaluation_Min) - { - loopEnter(tmprow, tmprows, orderedNum); - - { - filterVer(tmprow, srcrows, stridei, - tmprow, dstrows, stridet, filterRowInit, filterRowNext, filterRowFetch, filterRowStore, filterRowExit, eWindowEvaluation_Min, of); - } - - loopLeave(tmprow, tmprows, orderedNum); - } - - /* 1st resampling end - * -------------------------------------------------------------------------------------------- - */ - filterTExitLoop(); - - /* return collected min/max */ - hiloCVariables(orderedNum); - covarCVariables(orderedNum); - histoCVariables(orderedNum); - - /* --------------------------------------------------------------- */ - orderedTInitLoop(); - filterTInitLoop(); - - hiloTInitLoop(); - covarTInitLoop(); - histoTInitLoop(); - - /* -------------------------------------------------------------------------------------------- - * reading rows, writing cols (xy-flip) - * - * make dstrow x srccol -> outcol x dstrow - * - * we are reading vertical, and writing horizontal - * in effect we can use fast parallel-reads, but need - * slow interleaved-writes - * as reads are slower (ask+receive) than writes (send) - * this should even be gracefully fast - */ - allCAdvADDMOutStreamPointer(parm->region.outleft, parm->region.outtop, parm->outcols, o); - - #define filterColInit(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - allCInitSwappableOutPlaneReferences(parm->region.outleft, cstZero, parm->region.outtop, srcOffs, parm->outrows, o, false); - - #define filterColNext(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - /* every in/out-put may swap */ \ - allTInitFixedInPlaneReferences(srcOffs, parm->region.subtop + fw.first, -, i, t); - - #define filterColFetch(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - /* vertical stride, horizontal fetch */ \ - getTxNFromPlane(1); \ - \ - /*srcPos++;*/ - - #define filterColStore(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - comcpyCCheckHiLo(); \ - comcpyCCoVar(); \ - comcpyCHistogram(); \ - \ - /* horizontal stride, vertical store */ \ - putCxNToStreamSwapped(dstSkip, o); \ - putCxNToStream(dstSkip, o); \ - putCxNToPlane(1); \ - \ - /*dstPos++;*/ - - #define filterColExit(srcOffs, srcSize, srcSkip, dstOffs, dstSize, dstSkip) \ - allCAdvSSUBOutStreamPointer(dstSkip##raw, orderedShift, dstPos, o); - - if (parm->resample.operation == eWindowEvaluation_Sum) - { - loopEnter(dstrow, dstrows, orderedNum); - - { - filterHor(dstrow, srccols, stridet, - dstrow, dstcols, strideo, filterColInit, filterColNext, filterColFetch, filterColStore, filterColExit, eWindowEvaluation_Sum, of); - } - - loopLeave(dstrow, dstrows, orderedNum); - } - else if (parm->resample.operation == eWindowEvaluation_Max) - { - loopEnter(dstrow, dstrows, orderedNum); - - { - filterHor(dstrow, srccols, stridet, - dstrow, dstcols, strideo, filterColInit, filterColNext, filterColFetch, filterColStore, filterColExit, eWindowEvaluation_Max, of); - } - - loopLeave(dstrow, dstrows, orderedNum); - } - else if (parm->resample.operation == eWindowEvaluation_Min) - { - loopEnter(dstrow, dstrows, orderedNum); - - { - filterHor(dstrow, srccols, stridet, - dstrow, dstcols, strideo, filterColInit, filterColNext, filterColFetch, filterColStore, filterColExit, eWindowEvaluation_Min, of); - } - - loopLeave(dstrow, dstrows, orderedNum); - } - - /* 2nd resampling end - * -------------------------------------------------------------------------------------------- - */ - histoTExitLoop(); - covarTExitLoop(); - hiloTExitLoop(); - - filterTExitLoop(); - orderedTExitLoop(); - /* --------------------------------------------------------------- */ - - /* return collected min/max */ - comcpyCMergeHiLo(orderedNum); - comcpyCCompleteCoVar(orderedNum); - comcpyCCompleteHistogram(orderedNum); - - /* exit t */ - filterCCleanUp(orderedNum); - } - - // TODO: not working yet, debug and enable - //static void SplitAlgorithm(const void* i, void* o, struct prcparm* templ, int threads = 8) - //{ - // struct prcparm fraction[32]; - // int t, istart = 0, sstart = 0, ostart = 0; - // const bool scaler = true; - - // int theight = 0; - - // /* prepare data to be emitted to the threads */ - // for (t = 0; t < threads; t++) - // { - // fraction[t] = *templ; - - // /* adjust the processing-region according to the available threads */ - // { - //#undef split /* only prefix-threads need aligned transpose (for not trashing suffix-thread data) */ - //#define split(rows) !scaler \ - // ? ((rows * (t + 1)) / threads) & (~(t != threads - 1 ? 15 : 0)) \ - // : ((rows * (t + 1)) / threads) & (~0) - - // /* area covered */ - // const int inrows = (fraction[t].regional ? fraction[t].region.inrows : fraction[t].inrows); - // const int incols = (fraction[t].regional ? fraction[t].region.incols : fraction[t].incols); - // const int subrows = (fraction[t].regional ? fraction[t].region.subrows : fraction[t].subrows); - // const int subcols = (fraction[t].regional ? fraction[t].region.subcols : fraction[t].subcols); - // const int outrows = (fraction[t].regional ? fraction[t].region.outrows : fraction[t].outrows); - // const int outcols = (fraction[t].regional ? fraction[t].region.outcols : fraction[t].outcols); - - // /* splitting blocks */ - // const int istop = split(inrows), sstop = split(subrows), ostop = split(outrows); - // const int irows = istop - istart, srows = sstop - sstart, orows = ostop - ostart; - // const int icols = incols, scols = subcols, ocols = outcols; - - // AZ_Assert(irows > 0, "%s: Expect row count to be above zero!", __FUNCTION__); - // AZ_Assert(orows > 0, "%s: Expect row count to be above zero!", __FUNCTION__); - // AZ_Assert(icols > 0, "%s: Expect column count to be above zero!", __FUNCTION__); - // AZ_Assert(ocols > 0, "%s: Expect column count to be above zero!", __FUNCTION__); - - // /* now we are regional */ - // fraction[t].regional = true; - - // /* take previous regionality into account */ - // fraction[t].region.intop += istart; - // fraction[t].region.subtop += sstart; - // fraction[t].region.outtop += ostart; - // fraction[t].region.inrows = irows; - // fraction[t].region.subrows = srows; - // fraction[t].region.outrows = orows; - - // /* take previous regionality into account */ - // fraction[t].region.inleft += 0; - // fraction[t].region.subleft += 0; - // fraction[t].region.outleft += 0; - // fraction[t].region.incols = icols; - // fraction[t].region.subcols = scols; - // fraction[t].region.outcols = ocols; - - // /* advance block */ - // istart = istop; - // sstart = sstop; - // ostart = ostop; - - // /* check */ - // theight += irows; - // } - - // // the algorithm supports "i" and "o" pointing to the same memory - // CheckBoundaries((float*)i, (float*)o, &fraction[t]); - // RunAlgorithm((float*)i, (float*)o, &fraction[t]); - // } - - // AZ_Assert(theight >= (templ->regional ? templ->region.inrows : templ->inrows), "%s: Invalid height!", __FUNCTION__); - //} - - /* #################################################################################################################### \ - */ - void FilterImage(int filterIndex, int filterOp, float blurH, float blurV, const IImageObjectPtr srcImg, int srcMip, - IImageObjectPtr dstImg, int dstMip, QRect* srcRect, QRect* dstRect) - { - //only support ePixelFormat_R32G32B32A32F - if (srcImg->GetPixelFormat() != ePixelFormat_R32G32B32A32F || dstImg->GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "FilterImage only support both source and dest image objects have pixel format R32G32B32A32F"); - return; - } - - uint32 srcWidth, srcHeight; - uint8* pSrcMem; - uint32 dwSrcPitch; - - srcImg->GetImagePointer(srcMip, pSrcMem, dwSrcPitch); - - srcWidth = srcImg->GetWidth(srcMip); - srcHeight = srcImg->GetHeight(srcMip); - - uint32 dstWidth, dstHeight; - uint8* pDestMem; - uint32 dwDestPitch; - - dstImg->GetImagePointer(dstMip, pDestMem, dwDestPitch); - - dstWidth = dstImg->GetWidth(dstMip); - dstHeight = dstImg->GetHeight(dstMip); - - { - struct prcparm parm; - memset(&parm, 0, sizeof(parm)); - - parm.incols = srcWidth; - parm.inrows = srcHeight; - parm.outcols = dstWidth; - parm.outrows = dstHeight; - parm.regional = false; - parm.caged = false; - - if (srcRect || dstRect) - { - parm.regional = true; - parm.caged = true; - - parm.region.inleft = (!srcRect ? 0 : srcRect->left()); - parm.region.intop = (!srcRect ? 0 : srcRect->top()); - parm.region.incols = (!srcRect ? parm.incols : srcRect->right() - srcRect->left()); - parm.region.inrows = (!srcRect ? parm.inrows : srcRect->bottom() - srcRect->top()); - - parm.region.outleft = (!dstRect ? 0 : dstRect->left()); - parm.region.outtop = (!dstRect ? 0 : dstRect->top()); - parm.region.outcols = (!dstRect ? parm.outcols : dstRect->right() - dstRect->left()); - parm.region.outrows = (!dstRect ? parm.outrows : dstRect->bottom() - dstRect->top()); - - if (!srcRect) - { - parm.region.inleft = parm.region.outleft * srcHeight / dstHeight; - parm.region.intop = parm.region.outtop * srcWidth / dstWidth; - } - - if (!dstRect) - { - parm.region.outleft = parm.region.inleft * dstHeight / srcHeight; - parm.region.outtop = parm.region.intop * dstWidth / srcWidth; - } - } - - parm.resample.colquo = dstWidth; - parm.resample.colrem = srcWidth; - parm.resample.rowquo = dstHeight; - parm.resample.rowrem = srcHeight; - parm.resample.rowblur = blurH; - parm.resample.colblur = blurV; - parm.resample.operation = filterOp; - - switch (filterIndex) - { - // case eWindowFunction_COMBINER : parm.resample.wf = new CombinerWindowFunction(..., ...); break; - case eWindowFunction_Point: - parm.resample.wf = new PointWindowFunction(); - break; - case eWindowFunction_Box: - parm.resample.wf = new BoxWindowFunction(); - break; - case eWindowFunction_Triangle: - parm.resample.wf = new TriangleWindowFunction(); - break; - case eWindowFunction_Quadric: - parm.resample.wf = new QuadricWindowFunction(); - break; - case eWindowFunction_Cubic: - parm.resample.wf = new CubicWindowFunction(); - break; - case eWindowFunction_Hermite: - parm.resample.wf = new HermiteWindowFunction(); - break; - case eWindowFunction_Catrom: - parm.resample.wf = new CatromWindowFunction(); - break; - case eWindowFunction_Sine: - parm.resample.wf = new SineWindowFunction(); - break; - case eWindowFunction_Sinc: - parm.resample.wf = new SincWindowFunction(); - break; - case eWindowFunction_Bessel: - parm.resample.wf = new BesselWindowFunction(); - break; - case eWindowFunction_Lanczos: - parm.resample.wf = new LanczosWindowFunction(); - break; - case eWindowFunction_Gaussian: - parm.resample.wf = new GaussianWindowFunction(); - break; - case eWindowFunction_Normal: - parm.resample.wf = new NormalWindowFunction(); - break; - case eWindowFunction_Mitchell: - parm.resample.wf = new MitchellWindowFunction(); - break; - case eWindowFunction_Hann: - parm.resample.wf = new HannWindowFunction(); - break; - case eWindowFunction_BartlettHann: - parm.resample.wf = new BartlettHannWindowFunction(); - break; - case eWindowFunction_Hamming: - parm.resample.wf = new HammingWindowFunction(); - break; - case eWindowFunction_Blackman: - parm.resample.wf = new BlackmanWindowFunction(); - break; - case eWindowFunction_BlackmanHarris: - parm.resample.wf = new BlackmanHarrisWindowFunction(); - break; - case eWindowFunction_BlackmanNuttall: - parm.resample.wf = new BlackmanNuttallWindowFunction(); - break; - case eWindowFunction_Flattop: - parm.resample.wf = new FlatTopWindowFunction(); - break; - case eWindowFunction_Kaiser: - parm.resample.wf = new KaiserWindowFunction(); - break; - - case eWindowFunction_SigmaSix: - parm.resample.wf = new SigmaSixWindowFunction(); - break; - case eWindowFunction_KaiserSinc: - parm.resample.wf = new CombinerWindowFunction(new SincWindowFunction(), new KaiserWindowFunction()); - break; - - default: - abort(); - break; - } - - // TODO: not working yet, debug and enable - // SplitAlgorithm(pSrcMem, pDestMem, &parm); - - // the algorithm supports "pSrcMem" and "pDestMem" pointing to the same memory - CheckBoundaries((float*)pSrcMem, (float*)pDestMem, &parm); - RunAlgorithm((float*)pSrcMem, (float*)pDestMem, &parm); - - delete parm.resample.wf; - } - } - - int MipGenTypeToFilterIndex(MipGenType filterType) - { - switch (filterType) - { - case MipGenType::point: - return eWindowFunction_Point; - case MipGenType::box: - return eWindowFunction_Box; - case MipGenType::triangle: - return eWindowFunction_Triangle; - case MipGenType::quadratic: - return eWindowFunction_Bilinear; - case MipGenType::gaussian: - return eWindowFunction_Gaussian; - case MipGenType::blackmanHarris: - return eWindowFunction_BlackmanHarris; - case MipGenType::kaiserSinc: - return eWindowFunction_KaiserSinc; - default: - AZ_Assert(false, "unable find filter type for mipmap gen type %d", filterType); - return eWindowFunction_BlackmanHarris; - } - } - - /* #################################################################################################################### \ - */ - void FilterImage(MipGenType filterType, MipGenEvalType evalType, float blurH, float blurV, const IImageObjectPtr srcImg, int srcMip, - IImageObjectPtr dstImg, int dstMip, QRect* srcRect, QRect* dstRect) - { - int filterIndex = MipGenTypeToFilterIndex(filterType); - int filterOp = static_cast(evalType); - FilterImage(filterIndex, filterOp, blurH, blurV, srcImg, srcMip, dstImg, dstMip, srcRect, dstRect); - } - -} diff --git a/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.cpp b/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.cpp deleted file mode 100644 index d5d9d617c4..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -#include -#include "FIR-Weights.h" - -/* #################################################################################################################### - */ - -namespace ImageProcessing -{ - void calculateFilterRange(unsigned int srcFactor, int& srcFirst, int& srcLast, - unsigned int dstFactor, int dstFirst, int dstLast, - double blurFactor, class IWindowFunction* windowFunction) - { - double s, t, u, scaleFactor; /* scale factors */ - double srcRadius, srcCenter; /* window position and size */ - -#define s0 0 -#define s1 srcFactor -#define d0 0 -#define d1 dstFactor - - /* the mapping from discrete destination coordinates to continuous source coordinates: */ -#define MAP(b, scaleFactor, offset) ((b) + (offset)) / (scaleFactor) - - /* relation of dstFactor to srcFactor */ - s = (double)dstFactor / srcFactor; - t = d0 - s * (s0 - 0.5) - 0.5; - - /* compute offsets for MAP */ - u = d0 - s * (s0 - 0.5) - t; - - /* find scale of filter - * when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1 - */ - scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s); - - /* find support radius of scaled filter - * if the window's length is <= 0.5 then we've got point sampling. - */ - srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength()); - - /* sample the continuous filter, scaled by scaleFactor and - * positioned at continuous source coordinate srcCenter - */ - { - srcCenter = MAP(dstFirst + 0, s, u); - - /* find the source coordinate range of this positioned filter window */ - srcFirst = int(floor(srcCenter - srcRadius + 0.5)); - } - - { - srcCenter = MAP(dstLast - 1, s, u); - - /* find the source coordinate range of this positioned filter window */ - srcLast = int(floor(srcCenter + srcRadius + 0.5)); - } - } - - template<> - FilterWeights* calculateFilterWeights(unsigned int srcFactor, int srcFirst, int srcLast, - unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions, - double blurFactor, class IWindowFunction* windowFunction, - bool peaknorm, bool& plusminus) - - { -#define WEIGHTBITS 15 -#define WEIGHTONE (1 << WEIGHTBITS) /* filter weight of one */ - - double s, t, u, scaleFactor; /* scale factors */ - double srcRadius, srcCenter; /* window position and size */ - double sumfWeights, neg, pos, nrmWeights, fWeight; /* window position and size */ - int i, i0, i1; /* window position and size */ - int dstPosition; - signed short int n; - bool trimZeros = true, stillzero; - int lastnonzero, hWeight, highest; - signed int sumiWeights, iWeight; - signed short int* weightsPtr, *weightsMem; - FilterWeights* weightsObjs; - bool pm, pma = false; - - /* pre-calculate filter window solutions for all rows - */ - weightsObjs = new FilterWeights[dstLast - dstFirst]; - -#define s0 0 -#define s1 srcFactor -#define d0 0 -#define d1 dstFactor - - /* relation of dstFactor to srcFactor */ - s = (double)dstFactor / srcFactor; - t = d0 - s * (s0 - 0.5) - 0.5; - - /* compute offsets for MAP */ - u = d0 - s * (s0 - 0.5) - t; - - /* find scale of filter - * when minifying, scaleFactor = 1/s, but when magnifying, scaleFactor = 1 - */ - scaleFactor = (blurFactor == 0.0 ? 1.0 : (blurFactor > 0.0 ? (1.0 + blurFactor) : 1.0 / (1.0 - blurFactor))) * maximum(1., 1. / s); - - /* find support radius of scaled filter - * if the window's length is <= 0.5 then we've got point sampling. - */ - srcRadius = maximum(0.5, scaleFactor * windowFunction->getLength()); - - /* sample the continuous filter, scaled by ap->scaleFactor and - * positioned at continuous source coordinate srcCenter, for source coordinates in - * the range [0..len-1], writing the weights into wtab. - * Scale the weights so they sum up to WEIGHTONE, and trim leading and trailing - * zeros if trimZeros is true. - */ -#undef NORMALIZE_SUMMED_PEAK -#define NORMALIZE_MAXXED_PEAK - for (dstPosition = dstFirst, pm = false; dstPosition < dstLast; dstPosition++) - { - srcCenter = MAP(dstPosition, s, u); - - /* find the source coordinate range of this positioned filter window */ - i0 = int(floor(srcCenter - srcRadius + 0.5)); - i1 = int(floor(srcCenter + srcRadius + 0.5)); - - /* clip against the source-range */ - if (i0 < srcFirst) - { - i0 = srcFirst; - } - if (i1 > srcLast) - { - i1 = srcLast; - } - - /* this is possible if we hit the final line */ - if (i1 <= i0) - { - if (i1 >= srcLast) - { - i0 = i1 - 1; - } - else - { - i1 = i0 + 1; - } - } - - AZ_Assert(i0 >= srcFirst, "%s: Invalid source coordinate range!", __FUNCTION__); - AZ_Assert(i1 <= srcLast, "%s: Invalid source coordinate range!", __FUNCTION__); - AZ_Assert(i0 < i1, "%s: Invalid source coordinate range!", __FUNCTION__); - - /* find maximum peak to normalize the filter */ - for (sumfWeights = 0, pos = 0, neg = 0, i = i0; i < i1; i++) - { - /* evaluate the filter function: */ - fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor); - -#if defined(NORMALIZE_SUMMED_PEAK) - /* get positive and negative summed peaks */ - if (fWeight >= 0) - { - pos += fWeight; - } - else - { - neg += fWeight; - } -#elif defined(NORMALIZE_MAXXED_PEAK) - /* get positive and negative maximum peaks */ - minmax(fWeight, neg, pos); -#endif - - sumfWeights += fWeight; - } - - /* the range of source samples to buffer: */ - weightsMem = new signed short int[(i1 - i0) * abs(numRepetitions)]; - - /* set nrmWeights so that sumWeights of windowFunction() is approximately WEIGHTONE - * this needs to be adjusted because the maximum weight-coefficient - * is NOT allowed to leave [-32768,32767] - * a case like {+1.25,-0.25} does produce a sumWeights of 1.0 BUT - * produced a weight much too high (-40000) - */ -#if defined(NORMALIZE_SUMMED_PEAK) - sumfWeights = maximum(-neg, pos); -#elif defined(NORMALIZE_MAXXED_PEAK) - sumfWeights = maximum(sumfWeights, maximum(-neg, pos)); -#endif - - if (!peaknorm) - { - nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / sumfWeights); - } - else - { - nrmWeights = (sumfWeights == 0. ? WEIGHTONE : (-neg > pos ? WEIGHTONE - 1 : WEIGHTONE) / maximum(-neg, pos)); - } - - /* compute the discrete, sampled filter coefficients */ - stillzero = trimZeros; - for (sumiWeights = 0, hWeight = -WEIGHTONE, weightsPtr = weightsMem, i = i0; i < i1; i++) - { - /* evaluate the filter function: */ - fWeight = (*windowFunction)((i + 0.5 - srcCenter) / scaleFactor); - - /* normalize against the peak sumWeights, because the sums are not allowed to leave -32768/32767 */ - fWeight = fWeight * nrmWeights; - iWeight = int(round(fWeight)); - - /* find first nonzero */ - if (stillzero && (iWeight == 0)) - { - i0++; - } - else - { - AZ_Assert((-fWeight >= -32768.5) && (-fWeight <= 32767.5), "%s:The weight exceeded the maximum weight-coefficient.", __FUNCTION__); - - if (!peaknorm) - { - sumiWeights += iWeight; - } - else - { - sumiWeights = maximum(sumiWeights, iWeight); - } - -#define sgnextend(n, iWeight) (n & 1 ? (iWeight < 0 ? -1 : 0) : iWeight) - if (numRepetitions < 0) - { - /* add weight to table, interleaved sign */ - for (n = 0; n < -numRepetitions; n++) - { - *weightsPtr++ = sgnextend(n, -iWeight); - } - } - else - { - /* add weight to table */ - for (n = 0; n < numRepetitions; n++) - { - *weightsPtr++ = -iWeight; - } - } - - stillzero = false; - - /* find last nonzero */ - if (iWeight != 0) - { - lastnonzero = i; - } - - /* check for negative values */ - if (iWeight < 0) - { - pm = pma = true; - } - - /* find most influential value */ - if (iWeight >= hWeight) - { - highest = i; - hWeight = iWeight; - } - } - } - - if (sumiWeights == 0) - { - i0 = (i0 + i1) >> 1; - i1 = (i0 + 1); - - for (n = 0, weightsPtr = weightsMem; n < numRepetitions; n++) - { - *weightsPtr++ = -WEIGHTONE; - } - } - else - { - /* skip leading and trailing zeros */ - if (trimZeros) - { - /* set i0 and i1 to the nonzero support of the filter */ - i0 = i0; - i1 = i1 = lastnonzero + 1; - } - - if (sumiWeights != WEIGHTONE) - { - /* Fudge with the highest value */ - i = highest; - - /* fudge srcCenter sample */ - iWeight = WEIGHTONE - sumiWeights; - - for (n = 0, weightsPtr = weightsMem + (i - i0) * numRepetitions; n < numRepetitions; n++) - { - *weightsPtr++ -= iWeight; - } - } - } - - /* the new adjusted range of source samples to buffer: */ - weightsObjs[dstPosition].first = i0; - weightsObjs[dstPosition].last = i1; - weightsObjs[dstPosition].hasNegativeWeights = pm; - weightsObjs[dstPosition].weights = weightsMem; - } - - plusminus = pma; - return weightsObjs; - } -} diff --git a/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.h b/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.h deleted file mode 100644 index 0dee77aa1a..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/FIR-Weights.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include "FIR-Windows.h" - -namespace ImageProcessing -{ - /* #################################################################################################################### - */ - template - inline DataType abs (const DataType& ths) { return (ths < 0 ? -ths : ths); } - template - inline void minmax (const DataType& ths, DataType& mn, DataType& mx) { mn = (mn > ths ? ths : mn); mx = (mx < ths ? ths : mx); } - template - inline DataType minimum(const DataType& ths, const DataType& tht) { return (ths < tht ? ths : tht); } - template - inline DataType maximum(const DataType& ths, const DataType& tht) { return (ths > tht ? ths : tht); } - - /* #################################################################################################################### - */ - - template - class FilterWeights - { - public: - FilterWeights() - : weights(nullptr) - { - } - - ~FilterWeights() - { - delete[] weights; - } - - public: - // window-position - int first, last; - - // do we encounter positive as well as negative weights - bool hasNegativeWeights; - - /* weights, summing up to -(1 << 15), - * means weights are given negative - * that enables us to use signed short - * multiplication while occupying 0x8000 - */ - T* weights; - }; - - /* #################################################################################################################### - */ - - void calculateFilterRange (unsigned int srcFactor, int& srcFirst, int& srcLast, - unsigned int dstFactor, int dstFirst, int dstLast, - double blurFactor, class IWindowFunction* windowFunction); - - template - FilterWeights* calculateFilterWeights(unsigned int srcFactor, int srcFirst, int srcLast, - unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions, - double blurFactor, class IWindowFunction* windowFunction, - bool peaknorm, bool& plusminus); - - template<> - FilterWeights* calculateFilterWeights(unsigned int srcFactor, int srcFirst, int srcLast, - unsigned int dstFactor, int dstFirst, int dstLast, signed short int numRepetitions, - double blurFactor, class IWindowFunction* windowFunction, - bool peaknorm, bool& plusminus); - - -} //end namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/FIR-Windows.h b/Gems/ImageProcessing/Code/Source/Converters/FIR-Windows.h deleted file mode 100644 index b814d911d0..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/FIR-Windows.h +++ /dev/null @@ -1,1283 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : A collection of window functions with Finite Impulse Response FIR -// and some helper window functions with Infinite Impulse Response IIR - -#pragma once -#include -#include - -/* #################################################################################################################### - */ -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* pi */ -#endif - -//the original file was from cry's RC.exe with all the filters. We decided we would only use few of them for users -namespace ImageProcessing -{ - template - F cube(const F& op) { return op * op * op; } - - template - F square(F fOp) { return(fOp * fOp); } - - enum EWindowFunction - { - eWindowFunction_Combiner = 0, - - /*--------------- unit-area filters for unit-spaced samples ----------------*/ - eWindowFunction_Point = 1, - - eWindowFunction_Box = 2, // box, pulse, Fourier window, 1st order (constant) b-spline - eWindowFunction_Triangle = 3, // triangle, Bartlett window, 2nd order (linear) b-spline - eWindowFunction_Linear = eWindowFunction_Triangle, - eWindowFunction_Bartlett = eWindowFunction_Triangle, - - eWindowFunction_Quadric = 4, // 3rd order (quadratic) b-spline - eWindowFunction_Bilinear = eWindowFunction_Quadric, - eWindowFunction_Welch = eWindowFunction_Quadric, - eWindowFunction_Cubic = 5, // 4th order (cubic) b-spline - eWindowFunction_Hermite = 6, // 4th order (cubic hermite) b-spline - eWindowFunction_Catrom = 7, // Catmull-Rom spline, Overhauser spline - - eWindowFunction_Sine = 8, // IIR - eWindowFunction_Sinc = 9, // Sinc, perfect lowpass filter (infinite) - eWindowFunction_Bessel = 10, // Bessel (for circularly symm. 2-d filt, inf) - eWindowFunction_Lanczos = 11, // Lanczos filtering, windowed Sinc - - /*------------------ filters for non-unit spaced samples -------------------*/ - eWindowFunction_Gaussian = 12, // Gaussian (infinite) - eWindowFunction_Normal = 13, // Normal distribution (infinite) - - /*------------------------- parameterized filters --------------------------*/ - eWindowFunction_Mitchell = 14, // Mitchell & Netravali's two-param cubic - - /*--------------------------- window functions -----------------------------*/ - eWindowFunction_Hann = 15, // Hanning window - eWindowFunction_BartlettHann = 16, - eWindowFunction_Hamming = 17, // Hamming window - eWindowFunction_Blackman = 18, // Blackman window - eWindowFunction_BlackmanHarris = 19, - eWindowFunction_BlackmanNuttall = 20, - eWindowFunction_Flattop = 21, - - /*------------------------- parameterized windows --------------------------*/ - eWindowFunction_Kaiser = 22, // parameterized Kaiser window - - /*---------------------------- custom windows ------------------------------*/ - eWindowFunction_SigmaSix = 23, // two Normal distributions - eWindowFunction_KaiserSinc = 24, // Kaiser and Sinc - - eWindowFunction_Num = eWindowFunction_KaiserSinc + 1, - }; - - enum EWindowEvaluation - { - eWindowEvaluation_Sum, - eWindowEvaluation_Max, - eWindowEvaluation_Min, - }; - - /* #################################################################################################################### - */ - template - class IWindowFunction - { - public: - virtual ~IWindowFunction() {} - - virtual const char* getName() const = 0; - virtual T getLength() const = 0; - - virtual bool isCardinal() const = 0; - virtual bool isInfinite() const = 0; - virtual bool isUnitSpaced() const = 0; - virtual bool isCentered() const = 0; - - public: - virtual T operator () (T pos) const = 0; - }; - - /* #################################################################################################################### - * box, pulse, Fourier window, - * box function also know as rectangle function - * 1st order (constant) b-spline - */ - template - class BoxWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Box-window"; - } - virtual T getLength() const - { - return 0.5; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos <= 0.5) - { - return 1.0; - } - return 0.0; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * triangle, Bartlett window, - * triangle function also known as lambda function - * 2nd order (linear) b-spline - */ - template - class TriangleWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Triangle-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 1.0) - { - return 1.0 - pos; - } - return 0.0; - } - }; - - /* #################################################################################################################### - * 3rd order (quadratic) b-spline - */ - template - class QuadricWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Quadric-window"; - } - virtual T getLength() const - { - return 1.5; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 0.5) - { - return 0.75 - square(pos); - } - if (pos < 1.5) - { - return 0.50 * square(pos - 1.5); - } - return 0.0; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * 4th order (cubic) b-spline - */ - template - class CubicWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Cubic-window"; - } - virtual T getLength() const - { - return 2.0; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 1.0) - { - return 0.5 * cube(pos) - square(pos) + 2.0 / 3.0; - } - if (pos < 2.0) - { - return cube(2.0 - pos) / 6.0; - } - return 0.0; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Hermite filter - * f(x) = 2|x|^3 - 3|x|^2 + 1, -1 <= x <= 1 - */ - template - class HermiteWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Hermite-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 1.0) - { - return 2.0 * cube(pos) - 3.0 * square(pos) + 1.0; - } - return 0.0; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Catmull-Rom spline, Overhauser spline - */ - template - class CatromWindowFunction - : public IWindowFunction - { - public: - CatromWindowFunction() { } - - public: - virtual const char* getName() const - { - return "Catrom-window"; - } - virtual T getLength() const - { - return 2.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 1.0) - { - return 1.5 * cube(pos) - 2.5 * square(pos) + 1.0; - } - if (pos < 2.0) - { - return -0.5 * cube(pos) + 2.5 * square(pos) - 4.0 * pos + 2.0; - } - return 0.0; - } - }; - - /* #################################################################################################################### - */ - template - class SineWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Sine-window"; - } - virtual T getLength() const - { - return 0.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return sin(pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * sinc, perfect lowpass filter (infinite) - * - * Note: Some people say sinc(x) is sin(x)/x. Others say it's - * sin(PI*x)/(PI*x), a horizontal compression of the former which is - * zero at integer values. We use the latter, whose Fourier transform - * is a canonical rectangle function (edges at -1/2, +1/2, height 1). - */ - template - class SincWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Sinc-window"; - } - virtual T getLength() const - { - return 4.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos == 0.0) - { - return 1.0; - } - - return sin(M_PI * pos) / (M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Bessel (for circularly symm. 2-d filt, infinite) - * See Pratt "Digital Image Processing" p. 97 for Bessel functions - */ - template - class BesselWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Bessel-window"; - } - virtual T getLength() const - { - return 3.2383; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos == 0.0) - { - return M_PI / 4.0; - } - return AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER(M_PI * pos) / (2.0 * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Lanczos filter - */ - template - class LanczosWindowFunction - : public SincWindowFunction - { - public: - LanczosWindowFunction(T tap = 3.0) - { - this->tap = AZ::GetMax(3.0, tap); - } - - protected: - T tap; - - public: - virtual const char* getName() const - { - return "Lanczos-window"; - } - virtual T getLength() const - { - return tap; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < tap) - { - return ((SincWindowFunction) * this)(pos) * ((SincWindowFunction) * this)(pos / tap); - } - return 0.0; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Gaussian filter (infinite) - */ - template - class GaussianWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Gaussian-window"; - } - virtual T getLength() const - { - return 1.25; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return exp(-2.0 * square(pos)) * sqrt(2.0 / M_PI); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * normal distribution (infinite) - * Normal(x) = Gaussian(x/2)/2 - */ - template - class NormalWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Normal-window"; - } - virtual T getLength() const - { - return 2.5; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return exp(-square(pos) / 2.0) / sqrt(2.0 * M_PI); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - */ - template - class SigmaSixWindowFunction - : public IWindowFunction - { - public: - SigmaSixWindowFunction(T diameter = 1.0, T negative = 0.0) - { - // we aim for 6 * sigma = 99,99996% of all values - const T sigma = 1.0 / 3.0; - - s2 = sigma * sigma * 2.0; - d2 = s2 / (diameter * diameter); - d = diameter; - n = negative; - } - - protected: - T s2, d2, d, n; - - public: - virtual const char* getName() const - { - return "SigmaSix-window"; - } - virtual T getLength() const - { - return 1.44; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - T o = exp(-square(pos) / s2) - (1.0 - 0.9999996); - T i = exp(-square(pos) / d2) - (1.0 - 0.9999996); - return (pos >= d ? 0.0 : i) - o * n; - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Mitchell & Netravali's two-param cubic - * see Mitchell & Netravali, - * "Reconstruction Filters in Computer Graphics", SIGGRAPH 88 - */ - template - class MitchellWindowFunction - : public IWindowFunction - { - public: - MitchellWindowFunction(T b = 1.0 / 3.0, T c = 1.0 / 3.0) - { - p0 = (6. - 2. * b) / 6.; - p2 = (-18. + 12. * b + 6. * c) / 6.; - p3 = (12. - 9. * b - 6. * c) / 6.; - q0 = (8. * b + 24. * c) / 6.; - q1 = (-12. * b - 48. * c) / 6.; - q2 = (6. * b + 30. * c) / 6.; - q3 = (-b - 6. * c) / 6.; - } - - protected: - T p0, p2, p3, q0, q1, q2, q3; - - public: - virtual const char* getName() const - { - return "Mitchell-window"; - } - virtual T getLength() const - { - return 2.0; - } - - virtual bool isCardinal() const - { - return false; - } - virtual bool isInfinite() const - { - return false; - } - virtual bool isUnitSpaced() const - { - return false; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - if (pos < 0.0) - { - pos = -pos; - } - if (pos < 1.0) - { - return p3 * cube(pos) + p2 * square(pos) + p0; - } - if (pos < 2.0) - { - return q3 * cube(pos) + q2 * square(pos) + q1 * pos + q0; - } - return 0.0; - } - }; - - /* #################################################################################################################### - * Hanning window (infinite) - */ - template - class HannWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Hann-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.5 + 0.5 * cos(M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * BartlettHanning window (infinite) - */ - template - class BartlettHannWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Bartlett-Hann-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.62 + 0.48 * (1.0 - pos) + 0.38 * cos(M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Hamming window (infinite) - */ - template - class HammingWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Hamming-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.53836 + 0.46164 * cos(M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * Blackman window (infinite) - */ - template - class BlackmanWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Blackman-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.42659 - + 0.49656 * cos(M_PI * pos) - + 0.07685 * cos(2.0 * M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * BlackmanHarris window (infinite) - */ - template - class BlackmanHarrisWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Blackman-Harris-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.35875 - + 0.48829 * cos(M_PI * pos) - + 0.14128 * cos(2.0 * M_PI * pos) - + 0.01168 * cos(3.0 * M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * BlackmanNuttall window (infinite) - */ - template - class BlackmanNuttallWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Blackman-Nuttall-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.3635819 - + 0.4891775 * cos(M_PI * pos) - + 0.1365995 * cos(2.0 * M_PI * pos) - + 0.0106411 * cos(3.0 * M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * FlatTop window (infinite) - */ - template - class FlatTopWindowFunction - : public IWindowFunction - { - public: - virtual const char* getName() const - { - return "Flat-Top-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return 0.215578948 - + 0.416631580 * cos(M_PI * pos) - + 0.277263158 * cos(2.0 * M_PI * pos) - + 0.083578947 * cos(3.0 * M_PI * pos) - + 0.006947368 * cos(4.0 * M_PI * pos); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - * parameterized Kaiser window (infinite) - * from Oppenheim & Schafer, Hamming - */ - template - class KaiserWindowFunction - : public IWindowFunction - { - public: - KaiserWindowFunction(T a = 6.5) - { - /* typically 4a = a; - this->i0a = 1. / bessel_i0(a); - } - - protected: - T a, i0a; - - /* modified zeroth order Bessel function of the first kind. */ - static T bessel_i0(T x) - { - #define EPSILON 1e-7 - const T y = square(x) / 4.0; - - T sum = 1.0; - T t = y; - - for (int i = 2; t > EPSILON; i++) - { - sum += t; - t *= y / square(i); - } - - return sum; - - #undef EPSILON - } - - public: - virtual const char* getName() const - { - return "Kaiser-window"; - } - virtual T getLength() const - { - return 1.0; - } - - virtual bool isCardinal() const - { - return true; - } - virtual bool isInfinite() const - { - return true; - } - virtual bool isUnitSpaced() const - { - return true; - } - virtual bool isCentered() const - { - return true; - } - - public: - virtual T operator () (T pos) const - { - return i0a * bessel_i0(a * sqrt(1.0 - square(pos))); - } - }; - - /* #################################################################################################################### - */ - template - class CombinerWindowFunction - : public IWindowFunction - { - public: - CombinerWindowFunction(IWindowFunction* fu, IWindowFunction* wi) - { - shaper = fu; - restrictor = wi; - } - - protected: - IWindowFunction* shaper; - IWindowFunction* restrictor; - - public: - virtual const char* getName() const - { - return "Combiner of two window-generators"; - } - virtual T getLength() const - { - return shaper->getLength(); - } - - virtual bool isCardinal() const - { - return shaper->isCardinal() && restrictor->isCardinal(); - } - virtual bool isInfinite() const - { - return shaper->isInfinite() && restrictor->isInfinite(); - } - virtual bool isUnitSpaced() const - { - return shaper->isUnitSpaced() && restrictor->isUnitSpaced(); - } - virtual bool isCentered() const - { - return shaper->isCentered() && restrictor->isCentered(); - } - - public: - virtual T operator () (T pos) const - { - return (*shaper)(pos) * (*restrictor)(pos / shaper->getLength()); - } - }; - - /* -------------------------------------------------------------------------------------------------------------------- - */ - template - class PointWindowFunction - : public BoxWindowFunction - { - public: - PointWindowFunction() - : BoxWindowFunction() { } - - public: - virtual const char* getName() const - { - return "Point-window"; - } - virtual T getLength() const - { - return 0.0; - } - }; -} //end namespace ImageProcessing - diff --git a/Gems/ImageProcessing/Code/Source/Converters/Gamma.cpp b/Gems/ImageProcessing/Code/Source/Converters/Gamma.cpp deleted file mode 100644 index c30385c608..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Gamma.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -namespace ImageProcessing -{ - /////////////////////////////////////////////////////////////////////////////////// - // Lookup table for a function 'float fn(float x)'. - // Computed function values are stored in the table for x in [0.0; 1.0]. - // - // If passed x is less than xMin (xMin must be >= 0) or greater than 1.0, - // then the original function is called. - // Otherwise, a value from the table (linearly interpolated) - // is returned. - template - class FunctionLookupTable - { - public: - FunctionLookupTable(float(*fn)(float x), float xMin, float maxAllowedDifference) - : m_fn(fn) - , m_xMin(xMin) - , m_fMaxDiff(maxAllowedDifference) - { - } - - void Initialize() const - { - m_initialized = true; - AZ_Assert(m_xMin >= 0.0f, "wrong initial data for m_xMin"); - for (int i = 0; i <= TABLE_SIZE; ++i) - { - const float x = i / (float)TABLE_SIZE; - const float y = (*m_fn)(x); - m_table[i] = y; - } - } - - inline float compute(float x) const - { - if (x < m_xMin || x > 1) - { - return m_fn(x); - } - - const float f = x * TABLE_SIZE; - - const int i = int(f); - - if (!m_initialized) - { - Initialize(); - } - - if (i >= TABLE_SIZE) - { - return m_table[TABLE_SIZE]; - } - - const float alpha = f - i; - return (1 - alpha) * m_table[i] + alpha * m_table[i + 1]; - } - - public: - bool Test(const float maxDifferenceAllowed) const - { - if (int(-0.99f) != 0 || - int(+0.00f) != 0 || - int(+0.01f) != 0 || - int(+0.99f) != 0 || - int(+1.00f) != 1 || - int(+1.01f) != 1 || - int(+1.99f) != 1 || - int(+2.00f) != 2 || - int(+2.01f) != 2) - { - return false; - } - - if (m_xMin < 0) - { - return false; - } - - const int n = 1000000; - for (int i = 0; i <= n; ++i) - { - const float x = 1.1f * (i / (float)n); - const float resOriginal = m_fn(x); - const float resTable = compute(x); - const float difference = resOriginal - resTable; - - if (fabs(difference) > maxDifferenceAllowed) - { - return false; - } - } - return true; - } - - private: - float(*m_fn)(float x); - float m_xMin; - mutable float m_table[TABLE_SIZE + 1]; - mutable bool m_initialized = false; - float m_fMaxDiff = 0.0f; - }; - - - static float GammaToLinear(float x) - { - return (x <= 0.04045f) ? x / 12.92f : powf((x + 0.055f) / 1.055f, 2.4f); - } - - static float LinearToGamma(float x) - { - return (x <= 0.0031308f) ? x * 12.92f : 1.055f * powf(x, 1.0f / 2.4f) - 0.055f; - } - - static FunctionLookupTable<1024> s_lutGammaToLinear(GammaToLinear, 0.04045f, 0.00001f); - static FunctionLookupTable<1024> s_lutLinearToGamma(LinearToGamma, 0.05f, 0.00001f); - - /////////////////////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////////////////////// - bool ImageToProcess::GammaToLinearRGBA32F(bool bDeGamma) - { - // return immediately if there is no need to de-gamma image and the source is in the desired format - EPixelFormat srcFmt = m_img->GetPixelFormat(); - if (!bDeGamma && (srcFmt == ePixelFormat_R32G32B32A32F)) - { - return true; - } - - //convert to 32F first - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcFmt)) - { - AZ_Warning("Image Processing", false, "This is not common user case with compressed format input. But it may continue"); - ConvertFormat(ePixelFormat_R32G32B32A32F); - } - - IImageObjectPtr srcImage = m_img; - EPixelFormat dstFmt = ePixelFormat_R32G32B32A32F; - IImageObjectPtr dstImage(m_img->AllocateImage(dstFmt)); - - //create pixel operation function for src and dst images - IPixelOperationPtr srcOp = CreatePixelOperation(srcFmt); - IPixelOperationPtr dstOp = CreatePixelOperation(dstFmt); - - //get count of bytes per pixel for both src and dst images - uint32 srcPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8; - uint32 dstPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->bitsPerBlock / 8; - - const uint32 dwMips = dstImage->GetMipCount(); - float r, g, b, a; - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* srcPixelBuf; - uint32 srcPitch; - srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch); - uint8* dstPixelBuf; - uint32 dstPitch; - dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch); - - const uint32 pixelCount = srcImage->GetPixelCount(dwMip); - - for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += srcPixelBytes, dstPixelBuf += dstPixelBytes) - { - srcOp->GetRGBA(srcPixelBuf, r, g, b, a); - if (bDeGamma) - { - r = s_lutGammaToLinear.compute(r); - g = s_lutGammaToLinear.compute(g); - b = s_lutGammaToLinear.compute(b); - } - - dstOp->SetRGBA(dstPixelBuf, r, g, b, a); - } - } - - m_img = dstImage; - - if (bDeGamma) - { - m_img->RemoveImageFlags(EIF_SRGBRead); - } - return true; - } - - void ImageToProcess::LinearToGamma() - { - if (Get()->HasImageFlags(EIF_SRGBRead)) - { - AZ_Assert(false, "%s: input image is already SRGB", __FUNCTION__); - return; - } - - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_img->GetPixelFormat())) - { - AZ_Assert(false, "This is not common user case with compressed format input. But it may continue"); - ConvertFormat(ePixelFormat_R32G32B32A32F); - } - - EPixelFormat srcFmt = m_img->GetPixelFormat(); - IImageObjectPtr srcImage = m_img; - - IImageObjectPtr dstImage(m_img->AllocateImage(srcFmt)); - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(srcFmt); - - //get count of bytes per pixel for both src and dst images - uint32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(srcFmt)->bitsPerBlock / 8; - - const uint32 dwMips = srcImage->GetMipCount(); - float r, g, b, a; - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* srcPixelBuf; - uint32 srcPitch; - srcImage->GetImagePointer(dwMip, srcPixelBuf, srcPitch); - uint8* dstPixelBuf; - uint32 dstPitch; - dstImage->GetImagePointer(dwMip, dstPixelBuf, dstPitch); - - const uint32 pixelCount = srcImage->GetPixelCount(dwMip); - - for (uint32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes) - { - pixelOp->GetRGBA(srcPixelBuf, r, g, b, a); - r = s_lutLinearToGamma.compute(r); - g = s_lutLinearToGamma.compute(g); - b = s_lutLinearToGamma.compute(b); - pixelOp->SetRGBA(dstPixelBuf, r, g, b, a); - } - } - - m_img = dstImage; - Get()->AddImageFlags(EIF_SRGBRead); - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/HighPass.cpp b/Gems/ImageProcessing/Code/Source/Converters/HighPass.cpp deleted file mode 100644 index 7660d02016..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/HighPass.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - - // higher mip level is subtracted by lower mip level when applying the [cheap] high pass filter - void ImageToProcess::CreateHighPass(AZ::u32 dwMipDown) - { - //no need to convert if mip go down 0 - if (dwMipDown == 0) - { - return; - } - - const EPixelFormat ePixelFormat = m_img->GetPixelFormat(); - - if (ePixelFormat != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "You need convert the orginal image to ePixelFormat_R32G32B32A32F before call this function"); - return; - } - - - AZ::u32 dwWidth, dwHeight, dwMips; - dwWidth = m_img->GetWidth(0); - dwHeight = m_img->GetHeight(0); - dwMips = m_img->GetMipCount(); - - if (dwMipDown >= dwMips) - { - AZ_Warning("Image Processing", false, "CreateHighPass can't go down %i MIP levels for high pass as there are not\ - enough MIP levels available, going down by %i instead", dwMipDown, dwMips - 1); - dwMipDown = dwMips - 1; - } - - IImageObjectPtr newImage(IImageObject::CreateImage(dwWidth, dwHeight, dwMips, ePixelFormat)); - newImage->CopyPropertiesFrom(m_img); - - IPixelOperationPtr pixelOp = CreatePixelOperation(ePixelFormat); - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat)->bitsPerBlock / 8; - - AZ::u32 dstMips = newImage->GetMipCount(); - for (AZ::u32 dstMip = 0; dstMip < dwMipDown; ++dstMip) - { - // linear interpolation - FilterImage(MipGenType::triangle, MipGenEvalType::sum, 0.0f, 0.0f, m_img, dwMipDown, newImage, dstMip, NULL, NULL); - - const AZ::u32 pixelCountIn = m_img->GetWidth(dstMip) *m_img->GetHeight(dstMip); - const AZ::u32 pixelCountOut = newImage->GetWidth(dstMip) * newImage->GetHeight(dstMip); - - //substraction - AZ::u8* srcPixelBuf; - AZ::u32 srcPitch; - m_img->GetImagePointer(dstMip, srcPixelBuf, srcPitch); - AZ::u8* dstPixelBuf; - AZ::u32 dstPitch; - newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch); - const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes) - { - float r1, g1, b1, a1, r2, g2, b2, a2; - pixelOp->GetRGBA(srcPixelBuf, r1, g1, b1, a1); - pixelOp->GetRGBA(dstPixelBuf, r2, g2, b2, a2); - - r2 = AZ::GetClamp(r1 - r2 + 0.5f, 0.0f, 1.0f); - g2 = AZ::GetClamp(g1 - g2 + 0.5f, 0.0f, 1.0f); - b2 = AZ::GetClamp(b1 - b2 + 0.5f, 0.0f, 1.0f); - a2 = AZ::GetClamp(a1 - a2 + 0.5f, 0.0f, 1.0f); - pixelOp->SetRGBA(dstPixelBuf, r2, g2, b2, a2); - } - } - - // mips below the chosen highpass mip are grey - for (AZ::u32 dstMip = dwMipDown; dstMip < dstMips; ++dstMip) - { - AZ::u8* dstPixelBuf; - AZ::u32 dstPitch; - newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch); - const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, dstPixelBuf += pixelBytes) - { - pixelOp->SetRGBA(dstPixelBuf, 0.5f, 0.5f, 0.5f, 1.0f); - } - } - - m_img = newImage; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/Histogram.cpp b/Gems/ImageProcessing/Code/Source/Converters/Histogram.cpp deleted file mode 100644 index 23cd836891..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Histogram.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include - -#include - -/////////////////////////////////////////////////////////////////////////////////// - -namespace ImageProcessing -{ - float GetLuminance(const float& r, const float& g, const float& b) - { - return (r * 0.30f + g * 0.59f + b * 0.11f); - } - - bool ComputeLuminanceHistogram(IImageObjectPtr imageObject, Histogram<256>& histogram) - { - EPixelFormat pixelFormat = imageObject->GetPixelFormat(); - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(pixelFormat))) - { - AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__); - return false; - } - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(pixelFormat); - - //setup histogram bin - static const size_t binCount = 256; - Histogram::Bins bins; - Histogram::clearBins(bins); - - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat)->bitsPerBlock / 8; - - const AZ::u32 mipCount = imageObject->GetMipCount(); - float color[4]; - for (uint32 mip = 0; mip < mipCount; ++mip) - { - AZ::u8* pixelBuf; - AZ::u32 pitch; - imageObject->GetImagePointer(mip, pixelBuf, pitch); - const uint32 pixelCount = imageObject->GetPixelCount(mip); - - for (uint32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - - const float luminance = AZ::GetClamp(GetLuminance(color[0], color[1], color[2]), 0.0f, 1.0f); - const float f = luminance * binCount; - if (f <= 0) - { - ++bins[0]; - } - else - { - const int bin = int(f); - ++bins[(bin < binCount) ? bin : binCount - 1]; - } - } - } - - histogram.set(bins); - return true; - } -} // end namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/Histogram.h b/Gems/ImageProcessing/Code/Source/Converters/Histogram.h deleted file mode 100644 index 4f73f23a74..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Histogram.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -namespace ImageProcessing -{ - template - class Histogram - { - public: - typedef AZ::u64 Bins[BIN_COUNT]; - - public: - Histogram() - { - } - - static void clearBins(Bins& bins) - { - memset(&bins, 0, sizeof(bins)); - } - - void set(const Bins& bins) - { - m_bins[0] = bins[0]; - m_binsCumulative[0] = bins[0]; - double sum = 0.0f; - for (size_t i = 1; i < BIN_COUNT; ++i) - { - m_bins[i] = bins[i]; - m_binsCumulative[i] = m_binsCumulative[i - 1] + bins[i]; - sum += i * double(bins[i]); - } - - const AZ::u64 totalCount = getTotalSampleCount(); - m_meanBin = (totalCount <= 0) ? 0.0f : float(sum / totalCount); - } - - AZ::u64 getTotalSampleCount() const - { - return m_binsCumulative[BIN_COUNT - 1]; - } - - float getPercentage(size_t minBin, size_t maxBin) const - { - const AZ::u64 totalCount = getTotalSampleCount(); - - if ((totalCount <= 0) || (minBin > maxBin) || (maxBin < 0) || (minBin >= BIN_COUNT)) - { - return 0.0f; - } - - minBin = AZ::GetMax(minBin, size_t(0)); - maxBin = AZ::GetMin(maxBin, BIN_COUNT-1); - - const AZ::u64 count = m_binsCumulative[maxBin] - ((minBin <= 0) ? 0 : m_binsCumulative[minBin-1]); - - return float((double(count) * 100.0) / double(totalCount)); - } - - float getMeanBin() const - { - return m_meanBin; - } - - private: - Bins m_bins; - Bins m_binsCumulative; - float m_meanBin; - }; - - bool ComputeLuminanceHistogram(IImageObjectPtr imageObject, Histogram<256>& histogram); -} diff --git a/Gems/ImageProcessing/Code/Source/Converters/Normalize.cpp b/Gems/ImageProcessing/Code/Source/Converters/Normalize.cpp deleted file mode 100644 index bb41991385..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/Normalize.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -#include -#include - -namespace ImageProcessing -{ - template - static void AdjustScaleForQuantization(float fBaseValue, float fBaseLine, float& cScale, float& cMinColor, float& cMaxColor) - { - const int qOne = (1 << qBits) - 1; - const int qUpperBits = (8 - qBits); - const int qLowerBits = qBits - qUpperBits; - - const int v = int(floor(fBaseValue * qOne)); - - int v0 = v - (v != 0); - int v1 = v + 0; - int v2 = v + (v != qOne); - - v0 = (v0 << qUpperBits) | (v0 >> qLowerBits); - v1 = (v1 << qUpperBits) | (v1 >> qLowerBits); - v2 = (v2 << qUpperBits) | (v2 >> qLowerBits); - - const float f0 = v0 / 255.0f; - const float f1 = v1 / 255.0f; - const float f2 = v2 / 255.0f; - - float fBaseLock = -1; - - if (fabsf(f0 - fBaseValue) < fabsf(fBaseLock - fBaseValue)) - { - fBaseLock = f0; - } - if (fabsf(f1 - fBaseValue) < fabsf(fBaseLock - fBaseValue)) - { - fBaseLock = f1; - } - if (fabsf(f2 - fBaseValue) < fabsf(fBaseLock - fBaseValue)) - { - fBaseLock = f2; - } - - float lScale = (1.0f - fBaseLock) / (1.0f - fBaseLine); - float vScale = (1.0f - fBaseValue) / (1.0f - fBaseLine); - float sScale = lScale / vScale; - - float csScale = (cScale / sScale); - float csBias = cMinColor - (1.0f - sScale) * (cScale / sScale); - - if ((csBias > 0.0f) && ((csScale + csBias) < 1.0f)) - { - cMinColor = csBias; - cScale = csScale; - cMaxColor = csScale + csBias; - } - } - - /////////////////////////////////////////////////////////////////////////////////// - - void CImageObject::NormalizeImageRange(EColorNormalization eColorNorm, EAlphaNormalization eAlphaNorm, bool bMaintainBlack, int nExponentBits) - { - if (GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s: unsupported source format", __FUNCTION__); - return; - } - - uint32 dwWidth, dwHeight, dwMips; - GetExtent(dwWidth, dwHeight, dwMips); - - // find image's range, can be negative - float cMinColor[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; - float cMaxColor[4] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX }; - - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* pSrcMem; - uint32 dwSrcPitch; - GetImagePointer(dwMip, pSrcMem, dwSrcPitch); - - dwHeight = GetHeight(dwMip); - dwWidth = GetWidth(dwMip); - for (uint32 dwY = 0; dwY < dwHeight; ++dwY) - { - const float* pSrcPix = (float*)&pSrcMem[dwY * dwSrcPitch]; - for (uint32 dwX = 0; dwX < dwWidth; ++dwX) - { - cMinColor[0] = AZ::GetMin(cMinColor[0], pSrcPix[0]); - cMinColor[1] = AZ::GetMin(cMinColor[1], pSrcPix[1]); - cMinColor[2] = AZ::GetMin(cMinColor[2], pSrcPix[2]); - cMinColor[3] = AZ::GetMin(cMinColor[3], pSrcPix[3]); - - cMaxColor[0] = AZ::GetMax(cMaxColor[0], pSrcPix[0]); - cMaxColor[1] = AZ::GetMax(cMaxColor[1], pSrcPix[1]); - cMaxColor[2] = AZ::GetMax(cMaxColor[2], pSrcPix[2]); - cMaxColor[3] = AZ::GetMax(cMaxColor[3], pSrcPix[3]); - - pSrcPix += 4; - } - } - } - - if (bMaintainBlack) - { - cMinColor[0] = AZ::GetMin(0.f, cMinColor[0]); - cMinColor[1] = AZ::GetMin(0.f, cMinColor[1]); - cMinColor[2] = AZ::GetMin(0.f, cMinColor[2]); - cMinColor[3] = AZ::GetMin(0.f, cMinColor[3]); - } - - AZ_Assert(cMaxColor[0] >= cMinColor[0] && cMaxColor[1] >= cMinColor[1] && - cMaxColor[2] >= cMinColor[2] && cMaxColor[3] >= cMinColor[3], "bad color range"); - - // some graceful threshold to avoid extreme cases - if (cMaxColor[0] - cMinColor[0] < (3.f / 255)) - { - cMinColor[0] = AZ::GetMax(0.f, cMinColor[0] - (2.f / 255)); - cMaxColor[0] = AZ::GetMin(1.f, cMaxColor[0] + (2.f / 255)); - } - if (cMaxColor[1] - cMinColor[1] < (3.f / 255)) - { - cMinColor[1] = AZ::GetMax(0.f, cMinColor[1] - (2.f / 255)); - cMaxColor[1] = AZ::GetMin(1.f, cMaxColor[1] + (2.f / 255)); - } - if (cMaxColor[2] - cMinColor[2] < (3.f / 255)) - { - cMinColor[2] = AZ::GetMax(0.f, cMinColor[2] - (2.f / 255)); - cMaxColor[2] = AZ::GetMin(1.f, cMaxColor[2] + (2.f / 255)); - } - if (cMaxColor[3] - cMinColor[3] < (3.f / 255)) - { - cMinColor[3] = AZ::GetMax(0.f, cMinColor[3] - (2.f / 255)); - cMaxColor[3] = AZ::GetMin(1.f, cMaxColor[3] + (2.f / 255)); - } - - // calculate range to normalize to - const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f; - const float cUprValue = powf(2.0f, fMaxExponent); - - if (eColorNorm == eColorNormalization_PassThrough) - { - cMinColor[0] = cMinColor[1] = cMinColor[2] = 0.f; - cMaxColor[0] = cMaxColor[1] = cMaxColor[2] = 1.f; - } - - // don't touch alpha channel if not used - if (eAlphaNorm == eAlphaNormalization_SetToZero) - { - // Store the range explicitly into the structure for read-back. - // The formats which request range expansion don't support alpha. - cMinColor[3] = 0.f; - cMaxColor[3] = cUprValue; - } - else if (eAlphaNorm == eAlphaNormalization_PassThrough) - { - cMinColor[3] = 0.f; - cMaxColor[3] = 1.f; - } - - // get the origins of the color model's lattice for the range of values - // these values need to be encoded as precise as possible under quantization - AZ::Vector4 cBaseLines = AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f); - AZ::Vector4 cScale = AZ::Vector4(cMaxColor[0] - cMinColor[0], cMaxColor[1] - cMinColor[1], - cMaxColor[2] - cMinColor[2], cMaxColor[3] - cMinColor[3]); - -#if 0 - // NOTE: disabled for now, in the future we can turn this on to force availability - // of value to guarantee for example perfect grey-scales (using YFF) - switch (GetImageFlags() & EIF_Colormodel) - { - case EIF_Colormodel_RGB: - cBaseLines = Vec4(0.0f, 0.0f, 0.0f, 0.0f); - break; - case EIF_Colormodel_CIE: - cBaseLines = Vec4(0.0f, 1.f / 3, 1.f / 3, 0.0f); - break; - case EIF_Colormodel_IRB: - cBaseLines = Vec4(0.0f, 1.f / 2, 1.f / 2, 0.0f); - break; - case EIF_Colormodel_YCC: - case EIF_Colormodel_YFF: - cBaseLines = Vec4(1.f / 2, 0.0f, 1.f / 2, 0.0f); - break; - } - - Vec4 cBaseScale = cBaseLines; - cBaseLines = cBaseLines - cMinColor; - cBaseLines = cBaseLines / cScale; - - if ((cBaseLines.x > 0.0f) && (cBaseLines.x < 1.0f)) - { - AdjustScaleForQuantization<5>(cBaseLines.x, cBaseScale.x, cScale.x, cMinColor.x, cMaxColor.x); - } - if ((cBaseLines.y > 0.0f) && (cBaseLines.y < 1.0f)) - { - AdjustScaleForQuantization<6>(cBaseLines.y, cBaseScale.y, cScale.y, cMinColor.y, cMaxColor.y); - } - if ((cBaseLines.z > 0.0f) && (cBaseLines.z < 1.0f)) - { - AdjustScaleForQuantization<5>(cBaseLines.z, cBaseScale.z, cScale.z, cMinColor.z, cMaxColor.z); - } -#endif - - // normalize the image - AZ::Vector4 vMin = AZ::Vector4(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]); - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* pSrcMem; - uint32 dwSrcPitch; - GetImagePointer(dwMip, pSrcMem, dwSrcPitch); - - dwHeight = GetHeight(dwMip); - dwWidth = GetWidth(dwMip); - for (uint32 dwY = 0; dwY < dwHeight; ++dwY) - { - AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch]; - for (uint32 dwX = 0; dwX < dwWidth; ++dwX) - { - *pSrcPix = *pSrcPix - vMin; - *pSrcPix = *pSrcPix / cScale; - *pSrcPix = *pSrcPix * cUprValue; - - pSrcPix++; - } - } - } - - // set up a range - SetColorRange(AZ::Color(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]), - AZ::Color(cMaxColor[0], cMaxColor[1], cMaxColor[2], cMaxColor[3])); - - // set up a flag - AddImageFlags(EIF_RenormalizedTexture); - } - - void CImageObject::ExpandImageRange([[maybe_unused]] EColorNormalization eColorMode, EAlphaNormalization eAlphaMode, int nExponentBits) - { - AZ_Assert(!((eAlphaMode != eAlphaNormalization_SetToZero) && (nExponentBits != 0)), "%s: Unexpected alpha mode", __FUNCTION__); - - if (!HasImageFlags(EIF_RenormalizedTexture)) - { - return; - } - - if (GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__); - return; - } - - uint32 dwWidth, dwHeight, dwMips; - GetExtent(dwWidth, dwHeight, dwMips); - - // calculate range to normalize to - const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f; - float cUprValue = powf(2.0f, fMaxExponent); - - // find image's range, can be negative - AZ::Color cMinColor = AZ::Color(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX); - AZ::Color cMaxColor = AZ::Color(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX); - - GetColorRange(cMinColor, cMaxColor); - - // don't touch alpha channel if not used - if (eAlphaMode == eAlphaNormalization_SetToZero) - { - // Overwrite the range explicitly into the structure. - // The formats which request range expansion don't support alpha. - cUprValue = cMaxColor.GetA(); - - cMinColor.SetA(1.f); - cMaxColor.SetA(1.f); - } - - // expand the image - const AZ::Vector4 cScale = cMaxColor.GetAsVector4() - cMinColor.GetAsVector4(); - for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - uint8* pSrcMem; - uint32 dwSrcPitch; - GetImagePointer(dwMip, pSrcMem, dwSrcPitch); - - dwHeight = GetHeight(dwMip); - dwWidth = GetWidth(dwMip); - for (uint32 dwY = 0; dwY < dwHeight; ++dwY) - { - AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch]; - for (uint32 dwX = 0; dwX < dwWidth; ++dwX) - { - *pSrcPix = *pSrcPix / cUprValue; - *pSrcPix = *pSrcPix * cScale; - *pSrcPix = *pSrcPix + cMinColor.GetAsVector4(); - - pSrcPix++; - } - } - } - - // set up a range - SetColorRange(AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f)); - - // set up a flag - RemoveImageFlags(EIF_RenormalizedTexture); - } - - /////////////////////////////////////////////////////////////////////////////////// - - void CImageObject::NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount) - { - if (GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__); - return; - } - - uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount()); - for (uint32 mip = firstMip; mip < lastMip; ++mip) - { - const uint32 pixelCount = GetPixelCount(mip); - uint8* imageMem; - uint32 pitch; - GetImagePointer(mip, imageMem, pitch); - float* pPixels = (float*)imageMem; - - for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4) - { - AZ::Vector3 vNormal = AZ::Vector3(pPixels[0] * 2.0f - 1.0f, pPixels[1] * 2.0f - 1.0f, pPixels[2] * 2.0f - 1.0f); - - // TODO: every opposing vector addition produces the zero-vector for - // normals on the entire sphere, in that case the forward vector [0,0,1] - // isn't necessarily right and we should look at the adjacent normals - // for a direction - if (vNormal.IsZero()) - { - vNormal = AZ::Vector3(1.0f, 0.0f, 0.0f); - } - else - { - vNormal.NormalizeSafe(); - } - - pPixels[0] = vNormal.GetX() * 0.5f + 0.5f; - pPixels[1] = vNormal.GetY() * 0.5f + 0.5f; - pPixels[2] = vNormal.GetZ() * 0.5f + 0.5f; - } - } - } - - /////////////////////////////////////////////////////////////////////////////////// - void CImageObject::ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias) - { - if (GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__); - return; - } - - const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount()); - for (uint32 mip = firstMip; mip < lastMip; ++mip) - { - const uint32 pixelCount = GetPixelCount(mip); - uint8* imageMem; - uint32 pitch; - GetImagePointer(mip, imageMem, pitch); - float* pPixels = (float*)imageMem; - - for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4) - { - pPixels[0] = pPixels[0] * scale.GetX() + bias.GetX(); - pPixels[1] = pPixels[1] * scale.GetY() + bias.GetY(); - pPixels[2] = pPixels[2] * scale.GetZ() + bias.GetZ(); - pPixels[3] = pPixels[3] * scale.GetW() + bias.GetW(); - } - } - } - - /////////////////////////////////////////////////////////////////////////////////// - void CImageObject::ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max) - { - if (GetPixelFormat() != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__); - return; - } - - const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount()); - for (uint32 mip = firstMip; mip < lastMip; ++mip) - { - - const uint32 pixelCount = GetPixelCount(mip); - uint8* imageMem; - uint32 pitch; - GetImagePointer(mip, imageMem, pitch); - float* pPixels = (float*)imageMem; - - for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4) - { - pPixels[0] = AZ::GetClamp(pPixels[0], float(min.GetX()), float(max.GetX())); - pPixels[1] = AZ::GetClamp(pPixels[1], float(min.GetY()), float(max.GetY())); - pPixels[2] = AZ::GetClamp(pPixels[2], float(min.GetZ()), float(max.GetZ())); - pPixels[3] = AZ::GetClamp(pPixels[3], float(min.GetW()), float(max.GetW())); - } - } - } - -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.cpp b/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.cpp deleted file mode 100644 index 034dcdfda1..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include - -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////////// -//functions for maintaining alpha coverage. - -namespace ImageProcessing -{ - //convertion: all data type supported by pixel channel <=> float - float U8ToF32(uint8 in) - { - return in / 255.f; - } - - uint8 F32ToU8(float in) - { - return aznumeric_cast(round(AZ::GetClamp(in, 0.f, 1.f) * 255)); - } - - float U16ToF32(uint16 in) - { - return in / 65535.f; - } - - uint16 F32ToU16(float in) - { - return aznumeric_cast(round(AZ::GetClamp(in, 0.f, 1.f) * 65535.f)); - } - - float HalfToF32(SHalf in) - { - return in; - } - - SHalf F32ToHalf(float in) - { - return SHalf(in); - } - - //stucture for RGBE pixel format - struct RgbE - { - static const int RGB9E5_EXPONENT_BITS = 5; - static const int RGB9E5_MANTISSA_BITS = 9; - static const int RGB9E5_EXP_BIAS = 15; - static const int RGB9E5_MAX_VALID_BIASED_EXP = 31; - static const int MAX_RGB9E5_EXP = (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS); - static const int RGB9E5_MANTISSA_VALUES = (1 << RGB9E5_MANTISSA_BITS); - static const int MAX_RGB9E5_MANTISSA = (RGB9E5_MANTISSA_VALUES - 1); - - static float MAX_RGB9E5; - - unsigned int r : 9; - unsigned int g : 9; - unsigned int b : 9; - unsigned int e : 5; - - static int log2(float x) - { - int bitfield = *((int*)(&x)); - bitfield &= ~0x80000000; - - return ((bitfield >> 23) - 127); - } - - void GetRGBF(float& outR, float& outG, float& outB) const - { - int exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS; - float scale = powf(2.0f, aznumeric_cast(exponent)); - outR = r * scale; - outG = g * scale; - outB = b * scale; - } - - void SetRGBF(const float& inR, const float& inG, const float& inB) - { - float rf = AZStd::GetMax(0.0f, AZStd::GetMin(inR, MAX_RGB9E5)); - float gf = AZStd::GetMax(0.0f, AZStd::GetMin(inG, MAX_RGB9E5)); - float bf = AZStd::GetMax(0.0f, AZStd::GetMin(inB, MAX_RGB9E5)); - float mf = AZStd::GetMax(rf, AZStd::GetMax(gf, bf)); - - e = AZStd::GetMax(0, log2(mf) + (RGB9E5_EXP_BIAS + 1)); - - int exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS; - float scale = powf(2.0f, aznumeric_cast(exponent)); - - r = AZStd::GetMin(511, (int)floorf(rf / scale + 0.5f)); - g = AZStd::GetMin(511, (int)floorf(gf / scale + 0.5f)); - b = AZStd::GetMin(511, (int)floorf(bf / scale + 0.5f)); - } - }; - - float RgbE::MAX_RGB9E5 = (((float)MAX_RGB9E5_MANTISSA) / RGB9E5_MANTISSA_VALUES * (1 << MAX_RGB9E5_EXP)); - - //ePixelFormat_R8G8B8A8 - class PixelOperationR8G8B8A8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - r = U8ToF32(data[0]); - g = U8ToF32(data[1]); - b = U8ToF32(data[2]); - a = U8ToF32(data[3]); - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(r); - data[1] = F32ToU8(g); - data[2] = F32ToU8(b); - data[3] = F32ToU8(a); - } - }; - - //ePixelFormat_R8G8B8X8 - class PixelOperationR8G8B8X8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - r = U8ToF32(data[0]); - g = U8ToF32(data[1]); - b = U8ToF32(data[2]); - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, [[maybe_unused]] const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(r); - data[1] = F32ToU8(g); - data[2] = F32ToU8(b); - data[3] = 0xff; - } - }; - - //ePixelFormat_B8G8R8A8 - class PixelOperationB8G8R8A8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - r = U8ToF32(data[2]); - g = U8ToF32(data[1]); - b = U8ToF32(data[0]); - a = U8ToF32(data[3]); - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(b); - data[1] = F32ToU8(g); - data[2] = F32ToU8(r); - data[3] = F32ToU8(a); - } - }; - - //ePixelFormat_R8G8 - class PixelOperationR8G8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - r = U8ToF32(data[0]); - g = U8ToF32(data[1]); - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(r); - data[1] = F32ToU8(g); - } - }; - - //ePixelFormat_R8 - class PixelOperationR8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - r = U8ToF32(data[0]); - g = 0.f; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(r); - } - }; - - //ePixelFormat_A8 - class PixelOperationA8 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint8* data = buf; - a = U8ToF32(data[0]); - //save alpha information to rgb too. useful for preview. - r = a; - g = a; - b = a; - } - - void SetRGBA(uint8* buf, [[maybe_unused]] const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, const float& a) override - { - uint8* data = buf; - data[0] = F32ToU8(a); - } - }; - - //ePixelFormat_R16G16B16A16 - class PixelOperationR16G16B16A16 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint16* data = (uint16*)(buf); - r = U16ToF32(data[0]); - g = U16ToF32(data[1]); - b = U16ToF32(data[2]); - a = U16ToF32(data[3]); - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override - { - uint16* data = (uint16*)(buf); - data[0] = F32ToU16(r); - data[1] = F32ToU16(g); - data[2] = F32ToU16(b); - data[3] = F32ToU16(a); - } - }; - - //ePixelFormat_R16G16 - class PixelOperationR16G16 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint16* data = (uint16*)(buf); - r = U16ToF32(data[0]); - g = U16ToF32(data[1]); - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - uint16* data = (uint16*)(buf); - data[0] = F32ToU16(r); - data[1] = F32ToU16(g); - } - }; - - //ePixelFormat_R16 - class PixelOperationR16 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const uint16* data = (uint16*)(buf); - r = U16ToF32(data[0]); - g = 0.f; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - uint16* data = (uint16*)(buf); - data[0] = F32ToU16(r); - } - }; - - //ePixelFormat_R9G9B9E5 - class PixelOperationR9G9B9E5 : public IPixelOperation - { - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const RgbE* data = (RgbE*)(buf); - data->GetRGBF(r, g, b); - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, [[maybe_unused]] const float& a) override - { - RgbE* data = (RgbE*)(buf); - data->SetRGBF(r, g, b); - } - }; - - //ePixelFormat_R32G32B32A32F - class PixelOperationR32G32B32A32F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const float* data = (float*)(buf); - r = data[0]; - g = data[1]; - b = data[2]; - a = data[3]; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override - { - float* data = (float*)(buf); - data[0] = r; - data[1] = g; - data[2] = b; - data[3] = a; - } - }; - - //ePixelFormat_R32G32F - class PixelOperationR32G32F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const float* data = (float*)(buf); - r = data[0]; - g = data[1]; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - float* data = (float*)(buf); - data[0] = r; - data[1] = g; - } - }; - - //ePixelFormat_R32F - class PixelOperationR32F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const float* data = (float*)(buf); - r = data[0]; - g = 0.f; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - float* data = (float*)(buf); - data[0] = r; - } - }; - - //ePixelFormat_R16G16B16A16F - class PixelOperationR16G16B16A16F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const SHalf* data = (SHalf*)(buf); - r = data[0]; - g = data[1]; - b = data[2]; - a = data[3]; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) override - { - SHalf* data = (SHalf*)(buf); - data[0] = SHalf(r); - data[1] = SHalf(g); - data[2] = SHalf(b); - data[3] = SHalf(a); - } - }; - - //ePixelFormat_R16G16F - class PixelOperationR16G16F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const SHalf* data = (SHalf*)(buf); - r = data[0]; - g = data[1]; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - SHalf* data = (SHalf*)(buf); - data[0] = SHalf(r); - data[1] = SHalf(g); - } - }; - - //ePixelFormat_R16F - class PixelOperationR16F : public IPixelOperation - { - public: - void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) override - { - const SHalf* data = (SHalf*)(buf); - r = data[0]; - g = 0.f; - b = 0.f; - a = 1.f; - } - - void SetRGBA(uint8* buf, const float& r, [[maybe_unused]] const float& g, [[maybe_unused]] const float& b, [[maybe_unused]] const float& a) override - { - SHalf* data = (SHalf*)(buf); - data[0] = SHalf(r); - } - }; - - IPixelOperationPtr CreatePixelOperation(EPixelFormat pixelFmt) - { - switch (pixelFmt) - { - case ePixelFormat_R8G8B8A8: - return AZStd::make_shared(); - case ePixelFormat_R8G8B8X8: - return AZStd::make_shared(); - case ePixelFormat_B8G8R8A8: - return AZStd::make_shared(); - case ePixelFormat_R8G8: - return AZStd::make_shared(); - case ePixelFormat_R8: - return AZStd::make_shared(); - case ePixelFormat_A8: - return AZStd::make_shared(); - case ePixelFormat_R16G16B16A16: - return AZStd::make_shared(); - case ePixelFormat_R16G16: - return AZStd::make_shared(); - case ePixelFormat_R16: - return AZStd::make_shared(); - case ePixelFormat_R9G9B9E5: - return AZStd::make_shared(); - case ePixelFormat_R32G32B32A32F: - return AZStd::make_shared(); - case ePixelFormat_R32G32F: - return AZStd::make_shared(); - case ePixelFormat_R32F: - return AZStd::make_shared(); - case ePixelFormat_R16G16B16A16F: - return AZStd::make_shared(); - case ePixelFormat_R16G16F: - return AZStd::make_shared(); - case ePixelFormat_R16F: - return AZStd::make_shared(); - default: - AZ_Assert(false, "This function should be only called for uncompressed pixel format"); - break; - } - return nullptr; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.h b/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.h deleted file mode 100644 index 4ce8a20643..0000000000 --- a/Gems/ImageProcessing/Code/Source/Converters/PixelOperation.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - class IPixelOperation - { - public: - virtual ~IPixelOperation() {} - - virtual void GetRGBA(const uint8* buf, float& r, float& g, float& b, float& a) = 0; - virtual void SetRGBA(uint8* buf, const float& r, const float& g, const float& b, const float& a) = 0; - }; - - typedef AZStd::shared_ptr IPixelOperationPtr; - IPixelOperationPtr CreatePixelOperation(EPixelFormat pixelFmt); - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.cpp b/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.cpp deleted file mode 100644 index fb62bd258f..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - - bool EditorHelper::s_IsPixelFormatStringInited = false; - const char* EditorHelper::s_PixelFormatString[ImageProcessing::EPixelFormat::ePixelFormat_Count]; - - void EditorHelper::InitPixelFormatString() - { - if (!s_IsPixelFormatStringInited) - { - s_IsPixelFormatStringInited = true; - } - - CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - for (int format = 0; format < EPixelFormat::ePixelFormat_Count; format ++) - { - const PixelFormatInfo* info = pixelFormats.GetPixelFormatInfo((EPixelFormat)format); - s_PixelFormatString[(EPixelFormat)format] = ""; - if (info) - { - s_PixelFormatString[(EPixelFormat)format] = info->szName; - } - else - { - AZ_Error("Texture Editor", false, "Cannot find name of EPixelFormat %i", format); - } - } - } - - const AZStd::string EditorHelper::GetFileSizeString(AZ::u32 fileSizeInBytes) - { - AZStd::string fileSizeStr; - - static double kb = 1024.0f; - static double mb = kb * 1024.0; - static double gb = mb * 1024.0; - - static AZStd::string byteStr = "B"; - static AZStd::string kbStr = "KB"; - static AZStd::string mbStr = "MB"; - static AZStd::string gbStr = "GB"; - -#if AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX - kb = 1000.0; - mb = kb * 1000.0; - gb = mb * 1000.0; - - kbStr = "kB"; - mbStr = "mB"; - gbStr = "gB"; -#endif // AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX - - if (fileSizeInBytes < kb) - { - fileSizeStr = AZStd::string::format("%u%s", fileSizeInBytes, byteStr.c_str()); - } - else if (fileSizeInBytes < mb) - { - double size = fileSizeInBytes / kb; - fileSizeStr = AZStd::string::format("%.2f%s", size, kbStr.c_str()); - } - else if (fileSizeInBytes < gb) - { - double size = fileSizeInBytes / mb; - fileSizeStr = AZStd::string::format("%.2f%s", size, mbStr.c_str()); - } - else - { - double size = fileSizeInBytes / gb; - fileSizeStr = AZStd::string::format("%.2f%s", size, gbStr.c_str()); - } - return fileSizeStr; - } - - const AZStd::string EditorHelper::ToReadablePlatformString(const AZStd::string& platformRawStr) - { - AZStd::string readableString; - AZStd::string platformStrLowerCase = platformRawStr; - AZStd::to_lower(platformStrLowerCase.begin(), platformStrLowerCase.end()); - if (platformStrLowerCase == "pc") - { - readableString = "PC"; - } - else if (platformStrLowerCase == "es3") - { - readableString = "Android"; - } - else if (platformStrLowerCase == "osx_gl") - { - readableString = "macOS"; - } - else if (platformStrLowerCase == "provo") - { - readableString = "Provo"; - } - else if (platformStrLowerCase == "ios") - { - readableString = "iOS"; - } - else - { - return platformRawStr; - } - - return readableString; - } - - - EditorTextureSetting::EditorTextureSetting(const AZ::Uuid& sourceTextureId) - { - const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* fullDetails = AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry::GetSourceByUuid(sourceTextureId); - InitFromPath(fullDetails->GetFullPath()); - } - - EditorTextureSetting::EditorTextureSetting(const AZStd::string& texturePath) - { - InitFromPath(texturePath); - } - - void EditorTextureSetting::InitFromPath(const AZStd::string& texturePath) - { - m_fullPath = texturePath; - AzFramework::StringFunc::Path::GetFullFileName(texturePath.c_str(), m_textureName); - - m_img = IImageObjectPtr(LoadImageFromFile(m_fullPath)); - - if (m_img == nullptr) - { - AZ_Warning("Texture Editor", false, "%s is not a valid texture image.", texturePath.c_str()); - return; - } - - bool generatedDefaults = false; - m_settingsMap = TextureSettings::GetMultiplatformTextureSetting(m_fullPath, generatedDefaults); - - // Get the preset id from one platform. The preset id for each platform should always be same - AZ_Assert(m_settingsMap.size() > 0, "There is no platform information"); - AZ::Uuid presetId = m_settingsMap.begin()->second.m_preset; - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetId); - - if (!preset) - { - AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetId.ToString().c_str()); - presetId = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img); - - for (auto& settingIter : m_settingsMap) - { - settingIter.second.ApplyPreset(presetId); - } - } - } - - void EditorTextureSetting::SetIsOverrided() - { - for (auto& it : m_settingsMap) - { - m_overrideFromPreset = false; - TextureSettings& textureSetting = it.second; - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(textureSetting.m_preset); - if (presetSetting != nullptr) - { - if ((textureSetting.m_sizeReduceLevel != presetSetting->m_sizeReduceLevel) || - (textureSetting.m_suppressEngineReduce != presetSetting->m_suppressEngineReduce) || - (presetSetting->m_mipmapSetting != nullptr && textureSetting.m_mipGenType != presetSetting->m_mipmapSetting->m_type)) - { - m_overrideFromPreset = true; - } - } - else - { - AZ_Error("Texture Editor", false, "Texture Preset %s is not found!", textureSetting.m_preset.ToString().c_str()); - } - } - } - - void EditorTextureSetting::SetToPreset(const AZStd::string& presetName) - { - m_overrideFromPreset = false; - - AZ::Uuid presetId = BuilderSettingManager::Instance()->GetPresetIdFromName(presetName); - if (presetId.IsNull()) - { - AZ_Error("Texture Editor", false, "Texture Preset %s has no associated UUID.", presetName.c_str()); - return; - } - - for (auto& settingIter : m_settingsMap) - { - settingIter.second.ApplyPreset(presetId); - } - } - - //Get the texture setting on certain platform - TextureSettings& EditorTextureSetting::GetMultiplatformTextureSetting(const AZStd::string& platform) - { - AZ_Assert(m_settingsMap.size() > 0, "Texture Editor", "There is no texture settings for texture %s", m_fullPath.c_str()); - PlatformName platformName = platform; - if (platform.empty()) - { - platformName = BuilderSettingManager::s_defaultPlatform; - } - if (m_settingsMap.find(platformName) != m_settingsMap.end()) - { - return m_settingsMap[platformName]; - } - else - { - AZ_Error("Texture Editor", false, "Cannot find texture setting on platform %s", platformName.c_str()); - } - return m_settingsMap.begin()->second; - } - - bool EditorTextureSetting::GetFinalInfoForTextureOnPlatform(const AZStd::string& platform, AZ::u32 wantedReduce, ResolutionInfo& outResolutionInfo) - { - if (m_settingsMap.find(platform) == m_settingsMap.end()) - { - return false; - } - - // Copy current texture setting and set to desired reduce - TextureSettings textureSetting = m_settingsMap[platform]; - wantedReduce = AZStd::min(AZStd::max(s_MinReduceLevel, wantedReduce), s_MaxReduceLevel); - textureSetting.m_sizeReduceLevel = wantedReduce; - - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(textureSetting.m_preset, platform); - if (presetSetting) - { - EPixelFormat pixelFormat = presetSetting->m_pixelFormat; - CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - - AZ::u32 inputWidth = m_img->GetWidth(0); - AZ::u32 inputHeight = m_img->GetHeight(0); - - // Update input width and height if it's a cubemap - if (presetSetting->m_cubemapSetting != nullptr) - { - CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(m_img); - if (srcCubemap == nullptr) - { - return false; - } - inputWidth = srcCubemap->GetFaceSize(); - inputHeight = inputWidth; - outResolutionInfo.arrayCount = 6; - delete srcCubemap; - } - - GetOutputExtent(inputWidth, inputHeight, outResolutionInfo.width, outResolutionInfo.height, outResolutionInfo.reduce, &textureSetting, presetSetting); - - AZ::u32 mipMapCount = pixelFormats.ComputeMaxMipCount(pixelFormat, outResolutionInfo.width, outResolutionInfo.height); - outResolutionInfo.mipCount = presetSetting->m_mipmapSetting != nullptr && textureSetting.m_enableMipmap ? mipMapCount : 1; - - return true; - } - else - { - return false; - } - } - - bool EditorTextureSetting::RefreshMipSetting(bool enableMip) - { - bool enabled = true; - for (auto& it : m_settingsMap) - { - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(it.second.m_preset); - if (enableMip) - { - if (preset && preset->m_mipmapSetting) - { - it.second.m_enableMipmap = true; - it.second.m_mipGenType = preset->m_mipmapSetting->m_type; - } - else - { - it.second.m_enableMipmap = false; - enabled = false; - AZ_Error("Texture Editor", false, "Preset %s does not support mipmap!", preset->m_name.c_str()); - } - } - else - { - it.second.m_enableMipmap = false; - enabled = false; - } - } - return enabled; - } - - void EditorTextureSetting::PropagateCommonSettings() - { - if (m_settingsMap.size() <= 1) - { - //Only one setting available, no need to propagate - return; - } - - TextureSettings& texSetting = GetMultiplatformTextureSetting(); - for (auto& it = ++ m_settingsMap.begin(); it != m_settingsMap.end(); ++it) - { - const PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform; - if (it->first != defaultPlatform) - { - it->second.m_enableMipmap = texSetting.m_enableMipmap; - it->second.m_maintainAlphaCoverage = texSetting.m_maintainAlphaCoverage; - it->second.m_mipGenEval = texSetting.m_mipGenEval; - it->second.m_mipGenType = texSetting.m_mipGenType; - for (size_t i = 0; i < TextureSettings::s_MaxMipMaps; i++) - { - it->second.m_mipAlphaAdjust[i] = texSetting.m_mipAlphaAdjust[i]; - } - } - } - } - - AZStd::list EditorTextureSetting::GetResolutionInfo(AZStd::string platform, AZ::u32& minReduce, AZ::u32& maxReduce) - { - AZStd::list resolutionInfos; - // Set the min/max reduce to the global value range first - minReduce = s_MaxReduceLevel; - maxReduce = s_MinReduceLevel; - for (AZ::u32 i = s_MinReduceLevel; i <= s_MaxReduceLevel; i++) - { - ResolutionInfo resolutionInfo; - GetFinalInfoForTextureOnPlatform(platform, i, resolutionInfo); - // If actual reduce is lower than desired reduce, it reaches the limit and we can stop try lower resolution - if (i > resolutionInfo.reduce) - { - break; - } - // Finds out the final min/max reduce based on range in different platforms - minReduce = AZStd::min(resolutionInfo.reduce, minReduce); - maxReduce = AZStd::max(resolutionInfo.reduce, maxReduce); - resolutionInfos.push_back(resolutionInfo); - } - return resolutionInfos; - } - - AZStd::list EditorTextureSetting::GetResolutionInfoForMipmap(AZStd::string platform) - { - AZStd::list resolutionInfos; - unsigned int baseReduce = m_settingsMap[platform].m_sizeReduceLevel; - ResolutionInfo baseInfo; - GetFinalInfoForTextureOnPlatform(platform, baseReduce, baseInfo); - resolutionInfos.push_back(baseInfo); - for (AZ::u32 i = 1; i < baseInfo.mipCount; i++) - { - ResolutionInfo resolutionInfo = baseInfo; - resolutionInfo.width = AZStd::max(baseInfo.width >> i, 1); - resolutionInfo.height = AZStd::max(baseInfo.height >> i, 1); - resolutionInfo.reduce = baseInfo.reduce + i; - resolutionInfo.mipCount = 1; - resolutionInfos.push_back(resolutionInfo); - } - return resolutionInfos; - } - -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.h b/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.h deleted file mode 100644 index cbba723f06..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/EditorCommon.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -namespace ImageProcessingEditor -{ - class EditorHelper - { - public: - static const char* s_PixelFormatString[ImageProcessing::EPixelFormat::ePixelFormat_Count]; - static void InitPixelFormatString(); - static const AZStd::string GetFileSizeString(AZ::u32 fileSizeInBytes); - static const AZStd::string ToReadablePlatformString(const AZStd::string& platformRawStr); - - private: - static bool s_IsPixelFormatStringInited; - }; - - struct ResolutionInfo - { - AZ::u32 width = 0; - AZ::u32 height = 0; - AZ::u32 arrayCount = 1; - AZ::u32 reduce = 0; - AZ::u32 mipCount = 0; - }; - - struct EditorTextureSetting - { - AZStd::string m_textureName = ""; - AZStd::string m_fullPath = ""; - ImageProcessing::MultiplatformTextureSettings m_settingsMap; - bool m_overrideFromPreset = false; - bool m_modified = false; - ImageProcessing::IImageObjectPtr m_img; - - EditorTextureSetting(const AZ::Uuid& sourceTextureId); - EditorTextureSetting(const AZStd::string& texturePath); - ~EditorTextureSetting() = default; - - void InitFromPath(const AZStd::string& texturePath); - - void SetIsOverrided(); - - void SetToPreset(const AZStd::string& presetName); - - //Get the texture setting on certain platform - ImageProcessing::TextureSettings& GetMultiplatformTextureSetting(const AZStd::string& platform = ""); - - //Gets the final resolution/reduce/mip count for a texture on a certain platform - //@param wantedReduce indicates the reduce level that's preferred - //@return successfully get the value or not - bool GetFinalInfoForTextureOnPlatform(const AZStd::string& platform, AZ::u32 wantedReduce, ResolutionInfo& outResolutionInfo); - - //Refresh the mip setting when the mip map setting is enabled/disabled. - //@return whether the mipmap is enabled or not. - bool RefreshMipSetting(bool enableMip); - - //Propagate non platform specific settings from the first setting to all the settings stored in m_settingsMap - void PropagateCommonSettings(); - - //Returns a list of calculated final resolution info based on different base reduce levels - AZStd::list GetResolutionInfo(AZStd::string platform, AZ::u32& minReduce, AZ::u32& maxReduce); - - //Returns a list of calculated final resolution info based on different mipmap levels - AZStd::list GetResolutionInfoForMipmap(AZStd::string platform); - }; - - - class ImageProcessingEditorInteralNotifications - : public AZ::EBusTraits - { - public: - ////////////////////////////////////////////////////////////////////////// - // EBusTraits overrides - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - ///////////////////////////////////////////////////////////////////////// - - //! Used to inform the settings changed across widgets - virtual void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) = 0; - }; - - using EditorInternalNotificationBus = AZ::EBus; - -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.cpp b/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.cpp deleted file mode 100644 index c646d7adad..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "ImagePopup.h" -#include -#include -#include - -namespace ImageProcessingEditor -{ - ImagePopup::ImagePopup(QImage previewImage, QWidget* parent /*= nullptr*/) - : QDialog(parent, Qt::Dialog | Qt::FramelessWindowHint | Qt::Popup) - , m_ui(new Ui::ImagePopup) - { - m_ui->setupUi(this); - m_previewImage = previewImage; - - if (!m_previewImage.isNull()) - { - int height = previewImage.height(); - int width = previewImage.width(); - - this->resize(width, height); - m_ui->imageLabel->resize(width, height); - QPixmap pixmap = QPixmap::fromImage(previewImage); - m_ui->imageLabel->setPixmap(pixmap); - - this->setFocusPolicy(Qt::FocusPolicy::NoFocus); - this->setModal(false); - } - } - - ImagePopup::~ImagePopup() - { - - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.ui b/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.ui deleted file mode 100644 index 419812b686..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ImagePopup.ui +++ /dev/null @@ -1,43 +0,0 @@ - - - ImagePopup - - - Qt::WindowModal - - - - 0 - 0 - 400 - 300 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Form - - - - - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.cpp b/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.cpp deleted file mode 100644 index e0e70e30be..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "MipmapSettingWidget.h" -#include - -#include -#include -#include - -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - MipmapSettingWidget::MipmapSettingWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/) - : QWidget(parent) - , m_ui(new Ui::MipmapSettingWidget) - , m_textureSetting(&textureSetting) - { - m_ui->setupUi(this); - - - AZ::SerializeContext* serializeContext = nullptr; - EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); - AZ_Assert(serializeContext, "Serialization context not available"); - - m_ui->propertyEditor->SetAutoResizeLabels(true); - m_ui->propertyEditor->Setup(serializeContext, this, true, 250); - - m_ui->propertyEditor->ClearInstances(); - TextureSettings* instance = &m_textureSetting->GetMultiplatformTextureSetting(); - const AZ::Uuid& classId = AZ::SerializeTypeInfo::GetUuid(instance); - m_ui->propertyEditor->AddInstance(instance, classId); - m_ui->propertyEditor->InvalidateAll(); - m_ui->propertyEditor->ExpandAll(); - - RefreshUI(); - - EditorInternalNotificationBus::Handler::BusConnect(); - } - - MipmapSettingWidget::~MipmapSettingWidget() - { - EditorInternalNotificationBus::Handler::BusDisconnect(); - } - - void MipmapSettingWidget::RefreshUI() - { - TextureSettings& texSetting = m_textureSetting->GetMultiplatformTextureSetting(); - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(texSetting.m_preset); - if (preset == nullptr || preset->m_mipmapSetting == nullptr) - { - m_ui->enableCheckBox->setCheckState(Qt::CheckState::Unchecked); - m_ui->enableCheckBox->setEnabled(false); - m_ui->propertyEditor->hide(); - } - else - { - bool showMipMap = texSetting.m_enableMipmap; - m_ui->enableCheckBox->setEnabled(true); - m_ui->enableCheckBox->setCheckState(showMipMap ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - QObject::connect(m_ui->enableCheckBox, &QCheckBox::clicked, this, &MipmapSettingWidget::OnCheckBoxStateChanged); - if (showMipMap) - { - m_ui->propertyEditor->show(); - this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - } - else - { - m_ui->propertyEditor->hide(); - this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - } - } - m_ui->propertyEditor->InvalidateValues(); - } - - void MipmapSettingWidget::OnCheckBoxStateChanged(bool checked) - { - bool finalChecked = m_textureSetting->RefreshMipSetting(checked); - - if (finalChecked) - { - m_ui->propertyEditor->show(); - } - else - { - m_ui->propertyEditor->hide(); - } - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform); - } - - - void MipmapSettingWidget::AfterPropertyModified(AzToolsFramework::InstanceDataNode* /*pNode*/) - { - //Only the first texture setting reflected is changed, we need to propagate the change to every texture settings. - m_textureSetting->PropagateCommonSettings(); - m_ui->propertyEditor->InvalidateValues(); - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform); - } - - void MipmapSettingWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/) - { - if (needRefresh) - { - RefreshUI(); - } - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.h b/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.h deleted file mode 100644 index 813c09eb77..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -namespace Ui -{ - class MipmapSettingWidget; -} - -namespace ImageProcessingEditor -{ - class MipmapSettingWidget - : public QWidget - , public AzToolsFramework::IPropertyEditorNotify - , protected EditorInternalNotificationBus::Handler - { - Q_OBJECT - public: - AZ_CLASS_ALLOCATOR(MipmapSettingWidget, AZ::SystemAllocator, 0); - explicit MipmapSettingWidget(EditorTextureSetting& textureSetting, QWidget* parent = nullptr); - ~MipmapSettingWidget(); - - //IPropertyEditorNotify Interface - void BeforePropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} - void AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) override; - void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} - void SetPropertyEditingComplete([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} - void SealUndoStack() override {} - - public slots: - void OnCheckBoxStateChanged(bool checked); - - protected: - //////////////////////////////////////////////////////////////////////// - //EditorInternalNotificationBus - void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform); - //////////////////////////////////////////////////////////////////////// - - private: - void RefreshUI(); - QScopedPointer m_ui; - EditorTextureSetting* m_textureSetting; - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.ui b/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.ui deleted file mode 100644 index bdab04033c..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/MipmapSettingWidget.ui +++ /dev/null @@ -1,89 +0,0 @@ - - - MipmapSettingWidget - - - - 0 - 0 - 583 - 489 - - - - - 0 - 0 - - - - Form - - - - - - - - Mipmap Settings - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Enable - - - - - - - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 20 - 1 - - - - - - - - - AzToolsFramework::ReflectedPropertyEditor - QFrame -
AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx
- 1 -
-
- - -
diff --git a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.cpp b/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.cpp deleted file mode 100644 index e3fc2500c2..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "PresetInfoPopup.h" -#include -#include -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - // Help functions to convert enum to strings - static const char* RGBWeightToString(RGBWeight weight) - { - static const char* RGBWeightNames[] = { "uniform", "luminance", "ciexyz" }; - AZ_Assert(weight <= RGBWeight::ciexyz, "Invalid RGBWeight!"); - return RGBWeightNames[(int)weight]; - } - - static const char* ColorSpaceToString(ColorSpace colorSpace) - { - static const char* colorSpaceNames[] = { "linear", "sRGB", "auto" }; - AZ_Assert(colorSpace <= ColorSpace::autoSelect, "Invalid ColorSpace!"); - return colorSpaceNames[(int)colorSpace]; - } - - static const char* MipGenTypeToString(MipGenType mipGenType) - { - static const char* mipGenTypeNames[] = { "point", "average", "linear" , "bilinear" , "gaussian" , "blackmanHarris", "kaiserSinc" }; - AZ_Assert(mipGenType <= MipGenType::kaiserSinc, "Invalid MipGenType!"); - return mipGenTypeNames[(int)mipGenType]; - } - - static const char* CubemapFilterTypeToString(CubemapFilterType cubemapFilterType) - { - static const char* cubemapFilterTypeNames[] = { "disc", "cone", "cosine" , "gaussian" , "cosine power" , "ggx" }; - AZ_Assert(cubemapFilterType <= CubemapFilterType::ggx, "Invalid CubemapFilterType!"); - return cubemapFilterTypeNames[(int)cubemapFilterType]; - } - - PresetInfoPopup::PresetInfoPopup(const PresetSettings* presetSettings, QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent, Qt::Dialog | Qt::Popup) - , m_ui(new Ui::PresetInfoPopup) - { - m_ui->setupUi(this); - RefreshPresetInfoLabel(presetSettings); - } - - PresetInfoPopup::~PresetInfoPopup() - { - - } - void PresetInfoPopup::RefreshPresetInfoLabel(const PresetSettings* presetSettings) - { - - QString presetInfoText = ""; - if (!presetSettings) - { - presetInfoText = "Invalid Preset!"; - m_ui->infoLabel->setText(presetInfoText); - return; - } - - presetInfoText += QString("UUID: %1\n").arg(presetSettings->m_uuid.ToString().c_str()); - presetInfoText += QString("Name: %1\n").arg(presetSettings->m_name.c_str()); - presetInfoText += QString("RGB Weight: %1\n").arg(RGBWeightToString(presetSettings->m_rgbWeight)); - presetInfoText += QString("Source ColorSpace: %1\n").arg(ColorSpaceToString(presetSettings->m_srcColorSpace)); - presetInfoText += QString("Destination ColorSpace: %1\n").arg(ColorSpaceToString(presetSettings->m_destColorSpace)); - presetInfoText += QString("FileMasks: "); - int i = 0; - for (auto& mask : presetSettings->m_fileMasks) - { - presetInfoText += i > 0 ? ", " : ""; - presetInfoText += mask.c_str(); - i++; - } - presetInfoText += "\n"; - presetInfoText += QString("Suppress Engine Reduce: %1\n").arg(presetSettings->m_suppressEngineReduce ? "True" : "False"); - presetInfoText += QString("Discard Alpha: %1\n").arg(presetSettings->m_discardAlpha ? "True" : "False"); - presetInfoText += QString("Is Power Of 2: %1\n").arg(presetSettings->m_isPowerOf2 ? "True" : "False"); - presetInfoText += QString("Is Color Chart: %1\n").arg(presetSettings->m_isColorChart ? "True" : "False"); - presetInfoText += QString("High Pass Mip: %1\n").arg(presetSettings->m_highPassMip); - presetInfoText += QString("Gloss From Normal: %1\n").arg(presetSettings->m_glossFromNormals); - presetInfoText += QString("Use Legacy Gloss: %1\n").arg(presetSettings->m_isLegacyGloss ? "True" : "False"); - presetInfoText += QString("Mip Re-normalize: %1\n").arg(presetSettings->m_isMipRenormalize ? "True" : "False"); - presetInfoText += QString("Streamable Mips Number: %1\n").arg(presetSettings->m_numStreamableMips); - presetInfoText += QString("Swizzle: %1\n").arg(presetSettings->m_swizzle.c_str()); - if (presetSettings->m_cubemapSetting) - { - presetInfoText += QString("[Cubemap Settings]\n"); - presetInfoText += QString("Filter: %1\n").arg(CubemapFilterTypeToString(presetSettings->m_cubemapSetting->m_filter)); - presetInfoText += QString("Angle: %1\n").arg(presetSettings->m_cubemapSetting->m_angle); - presetInfoText += QString("Mip Angle: %1\n").arg(presetSettings->m_cubemapSetting->m_mipAngle); - presetInfoText += QString("Mip Slope: %1\n").arg(presetSettings->m_cubemapSetting->m_mipSlope); - presetInfoText += QString("Edge Fixup: %1\n").arg(presetSettings->m_cubemapSetting->m_edgeFixup); - presetInfoText += QString("Generate Diff: %1\n").arg(presetSettings->m_cubemapSetting->m_generateDiff ? "True" : "False"); - presetInfoText += QString("Diffuse Probe Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_diffuseGenPreset.ToString().c_str()); - } - - if (presetSettings->m_mipmapSetting) - { - presetInfoText += QString("[MipMapSetting]\n"); - presetInfoText += QString("Type: %1\n").arg(MipGenTypeToString(presetSettings->m_mipmapSetting->m_type)); - } - - m_ui->infoLabel->setText(presetInfoText); - } -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.h b/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.h deleted file mode 100644 index 64fa666d25..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -namespace ImageProcessing -{ - class PresetSettings; -} -namespace Ui -{ - class PresetInfoPopup; -} - -namespace ImageProcessingEditor -{ - class PresetInfoPopup - : public AzQtComponents::StyledDialog - { - Q_OBJECT - public: - AZ_CLASS_ALLOCATOR(PresetInfoPopup, AZ::SystemAllocator, 0); - explicit PresetInfoPopup(const ImageProcessing::PresetSettings* preset, QWidget* parent = nullptr); - ~PresetInfoPopup(); - void RefreshPresetInfoLabel(const ImageProcessing::PresetSettings* presetSettings); - private: - QScopedPointer m_ui; - - - - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.ui b/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.ui deleted file mode 100644 index fd52b34c8e..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/PresetInfoPopup.ui +++ /dev/null @@ -1,83 +0,0 @@ - - - PresetInfoPopup - - - Qt::NonModal - - - - 0 - 0 - 300 - 400 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Preset Info - - - false - - - false - - - - - - 10 - - - 10 - - - 10 - - - 10 - - - 10 - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.cpp b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.cpp deleted file mode 100644 index 73340a45a7..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "ResolutionSettingItemWidget.h" -#include -#include - -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - - ResolutionSettingItemWidget::ResolutionSettingItemWidget(ResoultionWidgetType type, QWidget* parent /*= nullptr*/) - : QWidget(parent) - , m_ui(new Ui::ResolutionSettingItemWidget) - { - m_ui->setupUi(this); - m_type = type; - - EditorInternalNotificationBus::Handler::BusConnect(); - } - - ResolutionSettingItemWidget::~ResolutionSettingItemWidget() - { - EditorInternalNotificationBus::Handler::BusDisconnect(); - } - - void ResolutionSettingItemWidget::Init(AZStd::string platform, EditorTextureSetting* editorTextureSetting) - { - m_platform = platform; - m_editorTextureSetting = editorTextureSetting; - m_textureSetting = &m_editorTextureSetting->m_settingsMap[m_platform]; - m_preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset, platform); - SetupResolutionInfo(); - RefreshUI(); - if (m_type == ResoultionWidgetType::TexturePropety) - { - m_ui->formatLabel->show(); - m_ui->formatComboBox->hide(); - } - else - { - m_ui->formatLabel->hide(); - m_ui->formatComboBox->show(); - QObject::connect(m_ui->formatComboBox, static_cast(&QComboBox::currentIndexChanged), this, &ResolutionSettingItemWidget::OnChangeFormat); - } - QObject::connect(m_ui->downResSpinBox, static_cast(&QSpinBox::valueChanged), this, &ResolutionSettingItemWidget::OnChangeDownRes); - - } - - void ResolutionSettingItemWidget::RefreshUI() - { - m_ui->platformLabel->setText(EditorHelper::ToReadablePlatformString(m_platform).c_str()); - - m_ui->downResSpinBox->setRange(m_minReduce, m_maxReduce); - int clampedReduce = AZStd::min(AZStd::max(m_textureSetting->m_sizeReduceLevel, s_MinReduceLevel), s_MaxReduceLevel); - auto it = m_resolutionInfos.begin(); - it = AZStd::next(it, clampedReduce); - m_ui->downResSpinBox->setValue(it->reduce); - - QString finalResolution; - - if (it->arrayCount > 1) - { - finalResolution = QString("%1 x %2 x %3").arg(QString::number(it->width), QString::number(it->height), QString::number(it->arrayCount)); - } - else - { - finalResolution = QString("%1 x %2").arg(QString::number(it->width), QString::number(it->height)); - } - - m_ui->sizeLabel->setText(finalResolution); - - QString finalFormat = GetFinalFormat(m_textureSetting->m_preset); - if (m_type == ResoultionWidgetType::TexturePropety) - { - m_ui->formatLabel->setText(finalFormat); - } - else - { - SetupFormatComboBox(); - m_ui->formatComboBox->setCurrentText(finalFormat); - } - } - - void ResolutionSettingItemWidget::SetupResolutionInfo() - { - m_resolutionInfos = m_editorTextureSetting->GetResolutionInfo(m_platform, m_minReduce, m_maxReduce); - } - - void ResolutionSettingItemWidget::OnChangeDownRes(int downRes) - { - if ((unsigned int)downRes >= m_minReduce && (unsigned int)downRes <= m_maxReduce) - { - m_textureSetting->m_sizeReduceLevel = downRes; - RefreshUI(); - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, m_platform); - } - } - - QString ResolutionSettingItemWidget::GetFinalFormat([[maybe_unused]] const AZ::Uuid& presetId) - { - if (m_preset && m_preset->m_pixelFormat >=0 && m_preset->m_pixelFormat < ePixelFormat_Count) - { - return EditorHelper::s_PixelFormatString[m_preset->m_pixelFormat]; - } - return QString(); - } - - - void ResolutionSettingItemWidget::SetupFormatComboBox() - { - m_ui->formatComboBox->clear(); - } - - void ResolutionSettingItemWidget::OnChangeFormat([[maybe_unused]] int index) - { - bool oldState = m_ui->formatComboBox->blockSignals(true); - m_ui->formatComboBox->blockSignals(oldState); - } - - void ResolutionSettingItemWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/) - { - if (needRefresh) - { - m_preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset, m_platform); - SetupResolutionInfo(); - RefreshUI(); - } - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.h b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.h deleted file mode 100644 index ef86ad716e..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -namespace ImageProcessing -{ - class PresetSettings; -} -namespace Ui -{ - class ResolutionSettingItemWidget; -} - -namespace ImageProcessingEditor -{ - enum class ResoultionWidgetType - { - TexturePipeline, //Fully editable - TexturePropety, //Only DownRes is editable - }; - - class ResolutionSettingItemWidget - : public QWidget - , EditorInternalNotificationBus::Handler - { - Q_OBJECT - public: - - AZ_CLASS_ALLOCATOR(ResolutionSettingItemWidget, AZ::SystemAllocator, 0); - explicit ResolutionSettingItemWidget(ResoultionWidgetType type, QWidget* parent = nullptr); - ~ResolutionSettingItemWidget(); - void Init(AZStd::string platform, EditorTextureSetting* editorTextureSetting); - - public slots: - - void OnChangeDownRes(int downRes); - void OnChangeFormat(int index); - - protected: - //////////////////////////////////////////////////////////////////////// - //EditorInternalNotificationBus - void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform); - //////////////////////////////////////////////////////////////////////// - - private: - - void SetupFormatComboBox(); - void SetupResolutionInfo(); - void RefreshUI(); - QString GetFinalFormat(const AZ::Uuid& presetId); - - QScopedPointer m_ui; - ResoultionWidgetType m_type; - AZStd::string m_platform; - ImageProcessing::TextureSettings* m_textureSetting; - EditorTextureSetting* m_editorTextureSetting; - const ImageProcessing::PresetSettings* m_preset; - //Cached list of calculated final resolution info based on different reduce levels - AZStd::list m_resolutionInfos; - //Final reduce level range - unsigned int m_maxReduce; - unsigned int m_minReduce; - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.ui b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.ui deleted file mode 100644 index 5e5055e382..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingItemWidget.ui +++ /dev/null @@ -1,205 +0,0 @@ - - - ResolutionSettingItemWidget - - - - 0 - 0 - 400 - 20 - - - - - 0 - 0 - - - - - 400 - 0 - - - - - 400 - 20 - - - - Form - - - Qt::LeftToRight - - - - 0 - - - QLayout::SetDefaultConstraint - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - - 60 - 0 - - - - Provo - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 50 - 0 - - - - - 50 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 0 - - - - TextLabel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 0 - - - - TextLabel - - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.cpp b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.cpp deleted file mode 100644 index 4fe8bdbb0b..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "ResolutionSettingWidget.h" -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - ResolutionSettingWidget::ResolutionSettingWidget(ResoultionWidgetType type, EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/) - : QWidget(parent) - , m_ui(new Ui::ResolutionSettingWidget) - , m_textureSetting(&textureSetting) - { - m_ui->setupUi(this); - m_type = type; - - //Put default platform in the first row - ResolutionSettingItemWidget* item = new ResolutionSettingItemWidget(ResoultionWidgetType::TexturePropety, this); - item->Init(BuilderSettingManager::s_defaultPlatform, m_textureSetting); - m_ui->listLayout->addWidget(item); - - //Add the other platforms in the list - for (auto& it : m_textureSetting->m_settingsMap) - { - AZStd::string platform = it.first; - if (platform != BuilderSettingManager::s_defaultPlatform) - { - ResolutionSettingItemWidget* item2 = new ResolutionSettingItemWidget(ResoultionWidgetType::TexturePropety, this); - item2->Init(platform, m_textureSetting); - m_ui->listLayout->addWidget(item2); - } - } - - // Tooltips - m_ui->downResLabel->setToolTip(QString("Adjust the resolution based on the target platform. \ - Use this setting to preserve the resolution of a source file even though it appears smaller in the game. \ - Select 0 to preserve the original size or 5 for the maximum reduction.")); - } - - ResolutionSettingWidget::~ResolutionSettingWidget() - { - - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.h b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.h deleted file mode 100644 index 1960130521..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -namespace Ui -{ - class ResolutionSettingWidget; -} - -namespace ImageProcessingEditor -{ - class ResolutionSettingWidget - : public QWidget - { - Q_OBJECT - public: - AZ_CLASS_ALLOCATOR(ResolutionSettingWidget, AZ::SystemAllocator, 0); - explicit ResolutionSettingWidget(ResoultionWidgetType type, EditorTextureSetting& texureSetting, QWidget* parent = nullptr); - ~ResolutionSettingWidget(); - - private: - QScopedPointer m_ui; - ResoultionWidgetType m_type; - EditorTextureSetting* m_textureSetting; - - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.ui b/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.ui deleted file mode 100644 index d8987a37eb..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/ResolutionSettingWidget.ui +++ /dev/null @@ -1,177 +0,0 @@ - - - ResolutionSettingWidget - - - - 0 - 0 - 550 - 300 - - - - - 0 - 0 - - - - - 0 - 0 - - - - Form - - - - - - 0 - - - - - 0 - - - QLayout::SetDefaultConstraint - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - - 60 - 0 - - - - Platform - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 50 - 0 - - - - DownRes - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - Size - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - Format - - - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.cpp b/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.cpp deleted file mode 100644 index da78295c80..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "TexturePresetSelectionWidget.h" -#include - -#include -#include -#include -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - TexturePresetSelectionWidget::TexturePresetSelectionWidget(EditorTextureSetting& textureSetting, QWidget* parent /*= nullptr*/) - : QWidget(parent) - , m_ui(new Ui::TexturePresetSelectionWidget) - , m_textureSetting(&textureSetting) - { - m_ui->setupUi(this); - - // Add presets into combo box - m_presetList.clear(); - auto& presetFilterMap = BuilderSettingManager::Instance()->GetPresetFilterMap(); - - AZStd::set noFilterPresetList; - - // Check if there is any filtered preset list first - for(auto& presetFilter : presetFilterMap) - { - if (presetFilter.first.empty()) - { - noFilterPresetList = presetFilter.second; - } - else if (IsMatchingWithFileMask(m_textureSetting->m_textureName, presetFilter.first)) - { - for(const AZStd::string& presetName : presetFilter.second) - { - m_presetList.insert(presetName); - } - } - } - // If no filtered preset list available or should list all presets, use non-filter list - if (m_presetList.size() == 0 || m_listAllPresets) - { - m_presetList = noFilterPresetList; - } - - foreach (const AZStd::string& presetName, m_presetList) - { - m_ui->presetComboBox->addItem(QString(presetName.c_str())); - } - - // Set current preset - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); - - if (presetSetting) - { - m_ui->presetComboBox->setCurrentText(presetSetting->m_name.c_str()); - QObject::connect(m_ui->presetComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TexturePresetSelectionWidget::OnChangePreset); - - // Suppress engine reduction checkbox - m_ui->serCheckBox->setCheckState(m_textureSetting->GetMultiplatformTextureSetting().m_suppressEngineReduce ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - - SetCheckBoxReadOnly(m_ui->serCheckBox, presetSetting->m_suppressEngineReduce); - QObject::connect(m_ui->serCheckBox, &QCheckBox::clicked, this, &TexturePresetSelectionWidget::OnCheckBoxStateChanged); - - // Set convention label - SetPresetConvention(presetSetting); - } - - // Reset btn - QObject::connect(m_ui->resetBtn, &QPushButton::clicked, this, &TexturePresetSelectionWidget::OnRestButton); - - // PresetInfo btn - QObject::connect(m_ui->infoBtn, &QPushButton::clicked, this, &TexturePresetSelectionWidget::OnPresetInfoButton); - - // Tooltips - m_ui->activeFileConventionLabel->setToolTip(QString("Displays the supported naming convention for the selected preset.")); - m_ui->presetComboBox->setToolTip(QString("Choose a preset to update the preview and other properties.")); - m_ui->resetBtn->setToolTip(QString("Reset values to current preset defaults.")); - m_ui->serCheckBox->setToolTip(QString("Preserves the original size. Use this setting for textures that include text.")); - m_ui->infoBtn->setToolTip(QString("Show detail properties of the current preset")); - - EditorInternalNotificationBus::Handler::BusConnect(); - } - - TexturePresetSelectionWidget::~TexturePresetSelectionWidget() - { - EditorInternalNotificationBus::Handler::BusDisconnect(); - } - - void TexturePresetSelectionWidget::OnCheckBoxStateChanged(bool checked) - { - for (auto& it : m_textureSetting->m_settingsMap) - { - it.second.m_suppressEngineReduce = checked; - } - m_textureSetting->SetIsOverrided(); - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, false, BuilderSettingManager::s_defaultPlatform); - } - - void TexturePresetSelectionWidget::OnRestButton() - { - m_textureSetting->SetToPreset(AZStd::string(m_ui->presetComboBox->currentText().toUtf8().data())); - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform); - } - - void TexturePresetSelectionWidget::OnChangePreset(int index) - { - QString text = m_ui->presetComboBox->itemText(index); - m_textureSetting->SetToPreset(AZStd::string(text.toUtf8().data())); - EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform); - } - - void ImageProcessingEditor::TexturePresetSelectionWidget::OnPresetInfoButton() - { - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); - m_presetPopup.reset(new PresetInfoPopup(presetSetting, this)); - m_presetPopup->installEventFilter(this); - m_presetPopup->show(); - } - - void TexturePresetSelectionWidget::OnEditorSettingsChanged(bool needRefresh, const AZStd::string& /*platform*/) - { - if (needRefresh) - { - bool oldState = m_ui->serCheckBox->blockSignals(true); - m_ui->serCheckBox->setChecked(m_textureSetting->GetMultiplatformTextureSetting().m_suppressEngineReduce); - // If the preset's SER is true, texture setting should not override - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); - if (presetSetting) - { - SetCheckBoxReadOnly(m_ui->serCheckBox, presetSetting->m_suppressEngineReduce); - SetPresetConvention(presetSetting); - // If there is preset info dialog open, update the text - if (m_presetPopup && m_presetPopup->isVisible()) - { - m_presetPopup->RefreshPresetInfoLabel(presetSetting); - } - } - m_ui->serCheckBox->blockSignals(oldState); - } - } - - bool TexturePresetSelectionWidget::IsMatchingWithFileMask(const AZStd::string& filename, const AZStd::string& fileMask) - { - if (fileMask.empty()) - { - // Will not match with empty string - return false; - } - else - { - // Extract the file name and compare if it ends with file mask or not - AZStd::string filenameNoExt; - AzFramework::StringFunc::Path::GetFileName(filename.c_str(), filenameNoExt); - return filenameNoExt.length() >= fileMask.length() && filenameNoExt.compare(filenameNoExt.length() - fileMask.length(), fileMask.length(), fileMask) == 0; - } - } - - void ImageProcessingEditor::TexturePresetSelectionWidget::SetPresetConvention(const PresetSettings* presetSettings) - { - AZStd::string conventionText = ""; - if (presetSettings) - { - int i = 0; - for (const PlatformName& filemask : presetSettings->m_fileMasks) - { - conventionText += i > 0 ? " " + filemask : filemask; - i++; - } - } - m_ui->conventionLabel->setText(QString(conventionText.c_str())); - } - - void ImageProcessingEditor::TexturePresetSelectionWidget::SetCheckBoxReadOnly(QCheckBox* checkBox, bool readOnly) - { - checkBox->setAttribute(Qt::WA_TransparentForMouseEvents, readOnly); - checkBox->setFocusPolicy(readOnly ? Qt::NoFocus : Qt::StrongFocus); - checkBox->setEnabled(!readOnly); - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.h b/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.h deleted file mode 100644 index c490fdbf1f..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#include -#endif - -class QCheckBox; -namespace Ui -{ - class TexturePresetSelectionWidget; -} - -namespace ImageProcessingEditor -{ - class TexturePresetSelectionWidget - : public QWidget - , protected EditorInternalNotificationBus::Handler - { - Q_OBJECT - public: - AZ_CLASS_ALLOCATOR(TexturePresetSelectionWidget, AZ::SystemAllocator, 0); - explicit TexturePresetSelectionWidget(EditorTextureSetting& texureSetting, QWidget* parent = nullptr); - ~TexturePresetSelectionWidget(); - - public slots: - void OnCheckBoxStateChanged(bool checked); - void OnRestButton(); - void OnChangePreset(int index); - void OnPresetInfoButton(); - - protected: - //////////////////////////////////////////////////////////////////////// - //EditorInternalNotificationBus - void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform); - //////////////////////////////////////////////////////////////////////// - - private: - QScopedPointer m_ui; - AZStd::set m_presetList; - EditorTextureSetting* m_textureSetting; - QScopedPointer m_presetPopup; - bool IsMatchingWithFileMask(const AZStd::string& filename, const AZStd::string& fileMask); - void SetPresetConvention(const ImageProcessing::PresetSettings* presetSettings); - void SetCheckBoxReadOnly(QCheckBox* checkBox, bool readOnly); - - bool m_listAllPresets = true; - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.ui b/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.ui deleted file mode 100644 index 73a7741dde..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePresetSelectionWidget.ui +++ /dev/null @@ -1,91 +0,0 @@ - - - TexturePresetSelectionWidget - - - - 0 - 0 - 624 - 118 - - - - Form - - - - - - - - - - - - - Active file conventions - - - - - - - Texture presets - - - - - - - - - - Active preset - - - - - - - - - - - :/Reset.png - - - - - - - - Suppress spec reduction - - - - - - - - - - - :/info.png - - - - - 16 - 16 - - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.cpp b/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.cpp deleted file mode 100644 index 8a1cd3b650..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.cpp +++ /dev/null @@ -1,639 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "TexturePreviewWidget.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ImageProcessingEditor -{ - using namespace ImageProcessing; - - TexturePreviewWidget::TexturePreviewWidget(EditorTextureSetting& texureSetting, QWidget* parent /*= nullptr*/) - : QWidget(parent) - , m_ui(new Ui::TexturePreviewWidget) - , m_textureSetting(&texureSetting) - { - m_ui->setupUi(this); - - m_platform = BuilderSettingManager::s_defaultPlatform; - // For now, only provide preview for default platform - m_previewConverter = AZStd::make_unique(m_textureSetting->m_fullPath, &m_textureSetting->GetMultiplatformTextureSetting()); - - m_updateTimer = new QTimer(this); - connect(m_updateTimer, &QTimer::timeout, this, &TexturePreviewWidget::UpdatePreview); - m_updateTimer->setSingleShot(false); - - m_ui->infoLayer->setAttribute(Qt::WA_NoSystemBackground); - m_ui->mipLevelLabel->setAttribute(Qt::WA_NoSystemBackground); - m_ui->imageSizeLabel->setAttribute(Qt::WA_NoSystemBackground); - m_ui->fileSizeLabel->setAttribute(Qt::WA_NoSystemBackground); - - // Setup preview mode combo box - static const QString previewModeString[] = { "RGB", - "R", - "G", - "B", - "Alpha", - "RGBA" }; - - for (int i = 0; i < (int)PreviewMode::Count; i ++) - { - m_ui->previewComboBox->addItem(previewModeString[i]); - } - - QSize size = m_ui->imageLabel->size(); - m_imageLabelSize = aznumeric_cast(size.width()); - - SetUpResolutionInfo(); - RefreshUI(true); - - QObject::connect(m_ui->previewCheckBox, &QCheckBox::clicked, this, &TexturePreviewWidget::OnTiledChanged); - QObject::connect(m_ui->nextMipBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnNextMip); - QObject::connect(m_ui->prevMipBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnPrevMip); - QObject::connect(m_ui->previewComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TexturePreviewWidget::OnChangePreviewMode); - - // Set up Refresh button - m_alwaysRefreshAction = new QAction("Always refresh preview", this); - m_alwaysRefreshAction->setCheckable(true); - m_alwaysRefreshAction->setChecked(m_alwaysRefreshPreview); - QObject::connect(m_alwaysRefreshAction, &QAction::triggered, this, &TexturePreviewWidget::OnAlwaysRefresh); - - m_refreshPerClickAction = new QAction("Press to refresh preview", this); - m_refreshPerClickAction->setCheckable(true); - m_refreshPerClickAction->setChecked(!m_alwaysRefreshPreview); - QObject::connect(m_refreshPerClickAction, &QAction::triggered, this, &TexturePreviewWidget::OnRefreshPerClick); - - QMenu* menu = new QMenu(this); - menu->addAction(m_alwaysRefreshAction); - menu->addAction(m_refreshPerClickAction); - - m_ui->refreshBtn->setMenu(menu); - AzQtComponents::PushButton::applySmallIconStyle(m_ui->refreshBtn); - - QObject::connect(m_ui->refreshBtn, &QPushButton::clicked, this, &TexturePreviewWidget::OnRefreshClicked); - m_alwaysRefreshIcon.addFile(QStringLiteral(":/refresh.png"), QSize(), QIcon::Normal, QIcon::On); - m_refreshPerClickIcon.addFile(QStringLiteral(":/refresh-active.png"), QSize(), QIcon::Normal, QIcon::On); - m_ui->refreshBtn->setIcon(m_alwaysRefreshIcon); - - m_ui->busyLabel->SetBusyIconSize(16); - SetImageLabelText(QString(), false); - - // Tooltips - m_ui->previewComboBox->setToolTip(QString("Preview the texture in different channels.")); - m_ui->previewCheckBox->setToolTip(QString("Show or hide a 2x2 tiling of the texture.")); - m_ui->hotkeyLabel->setToolTip(QString("Preview different texture states with keyboard shortcuts.")); - m_ui->refreshBtn->setToolTip(QString("Provide different ways to refresh the preview. Click on the button to refresh manually.")); - - EditorInternalNotificationBus::Handler::BusConnect(); - } - - TexturePreviewWidget::~TexturePreviewWidget() - { - EditorInternalNotificationBus::Handler::BusDisconnect(); - } - - void TexturePreviewWidget::resizeEvent(QResizeEvent *event) - { - QWidget::resizeEvent(event); - - QSize size = m_ui->mainWidget->size(); - m_ui->infoLayer->resize(size); - - QSize imageSize = m_ui->imageLabel->size(); - QPoint center = m_ui->mainWidget->rect().center(); - m_ui->imageLabel->move(center - QPoint(imageSize.width() / 2, imageSize.height() / 2)); - QSize busyLabelSize = m_ui->busyLabel->size(); - m_ui->busyLabel->move(center - QPoint(busyLabelSize.width() + m_ui->imageLabel->sizeHint().width() / 2, busyLabelSize.width() / 2)); - } - - void TexturePreviewWidget::SetUpResolutionInfo() - { - m_resolutionInfos = m_textureSetting->GetResolutionInfoForMipmap(m_platform); - m_mipCount = (unsigned int)m_resolutionInfos.size(); - if (m_currentMipIndex > (int)m_mipCount) - { - m_currentMipIndex = 0; - } - } - - void TexturePreviewWidget::OnEditorSettingsChanged([[maybe_unused]] bool needRefresh, const AZStd::string& platform) - { - // Only update the preview if there is any change in current platform - if (platform == m_platform) - { - SetUpResolutionInfo(); - RefreshUI(true); - } - } - - void TexturePreviewWidget::RefreshUI(bool fullRefresh) - { - m_ui->mipLevelLabel->setText(QString("Mip %1").arg(QString::number(m_currentMipIndex))); - m_ui->previewCheckBox->setCheckState(m_previewTiled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - - bool hasNextMip = m_currentMipIndex < (int)m_mipCount - 1; - m_ui->nextMipBtn->setVisible(hasNextMip); - - bool hasPrevMip = m_currentMipIndex > 0; - m_ui->prevMipBtn->setVisible(hasPrevMip); - - RefreshWarning(); - - if (m_currentMipIndex < m_resolutionInfos.size()) - { - auto it = AZStd::next(m_resolutionInfos.begin(), m_currentMipIndex); - QString finalResolution; - if (it->arrayCount > 1) - { - finalResolution = QString("Image Size: %1 x %2 x %3").arg(QString::number(it->width), QString::number(it->height), QString::number(it->arrayCount)); - } - else - { - finalResolution = QString("Image Size: %1 x %2").arg(QString::number(it->width), QString::number(it->height)); - } - m_ui->imageSizeLabel->setText(finalResolution); - - CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->GetMultiplatformTextureSetting().m_preset); - if (preset) - { - uint32 size = pixelFormats.EvaluateImageDataSize(preset->m_pixelFormat, it->width, it->height) * it->arrayCount; - AZStd::string fileSizeString = EditorHelper::GetFileSizeString(size); - QString finalFileSize = QString("File Size: %1").arg(fileSizeString.c_str()); - m_ui->fileSizeLabel->setText(finalFileSize); - } - - if (m_alwaysRefreshPreview) - { - RefreshPreviewImage(fullRefresh ? RefreshMode::Convert : RefreshMode::Mip); - } - - } - else - { - AZ_Error("Texture Setting", false, "Cannot find mip reduce level for mip %d", m_currentMipIndex); - } - } - - void TexturePreviewWidget::OnNextMip() - { - if (m_currentMipIndex >= (int)m_mipCount - 1) - { - return; - } - m_currentMipIndex ++; - RefreshUI(false); - } - - - void TexturePreviewWidget::OnPrevMip() - { - if (m_currentMipIndex <= 0) - { - return; - } - - m_currentMipIndex--; - RefreshUI(false); - } - - void TexturePreviewWidget::UpdatePreview() - { - if (!m_previewConverter->IsDone()) - { - float progress = m_previewConverter->GetProgress(); - SetImageLabelText(QString("Converting for preview...Progress %1%").arg(QString::number(progress * 100, 'f', 2))); - return; - } - - m_updateTimer->stop(); - m_previewImageRaw = m_previewConverter->GetOutputImage(); - - GenerateMipmap(m_currentMipIndex); - GenerateChannelImage(m_previewMode); - PaintPreviewImage(); - } - - void TexturePreviewWidget::OnAlwaysRefresh() - { - m_alwaysRefreshPreview = true; - m_alwaysRefreshAction->setChecked(true); - m_refreshPerClickAction->setChecked(false); - - m_ui->refreshBtn->setIcon(m_alwaysRefreshIcon); - } - - void TexturePreviewWidget::OnRefreshPerClick() - { - m_alwaysRefreshPreview = false; - m_alwaysRefreshAction->setChecked(false); - m_refreshPerClickAction->setChecked(true); - - m_ui->refreshBtn->setIcon(m_refreshPerClickIcon); - } - - void TexturePreviewWidget::OnRefreshClicked() - { - RefreshPreviewImage(RefreshMode::Convert); - } - - void TexturePreviewWidget::GenerateMipmap(int mip) - { - // Clear all cached preview images - for (int i = 0; i < (int)PreviewMode::Count; i++) - { - m_previewImages[i] = QImage(); - } - - if (m_previewImageRaw && (AZ::u32)mip < m_previewImageRaw->GetMipCount() ) - { - uint8* imageBuf; - uint32 pitch; - m_previewImageRaw->GetImagePointer(mip, imageBuf, pitch); - const uint32 width = m_previewImageRaw->GetWidth(mip); - const uint32 height = m_previewImageRaw->GetHeight(mip); - m_previewImages[PreviewMode::RGBA] = QImage(imageBuf, width, height, pitch, QImage::Format_RGBA8888); - } - else - { - AZ_Error("Texture Editor", false, "Cannot generate mip preview from an invalid image."); - } - - } - - void TexturePreviewWidget::GenerateChannelImage(PreviewMode channel) - { - // If there is no preview image generated, ignore this function - if (m_previewImages[PreviewMode::RGBA].isNull()) - { - AZ_Error("Texture Editor", false, "Cannot generate channel image from an invalid image."); - return; - } - - if (m_previewImages[channel].isNull()) - { - // Copy the RGBA image before changing the color - QImage previewImg = m_previewImages[PreviewMode::RGBA].copy(); - for (int x = 0; x < previewImg.width(); x++) - { - for (int y = 0; y < previewImg.height(); y++) - { - QRgb pixel = previewImg.pixel(x, y); - int r = qRed(pixel); - int g = qGreen(pixel); - int b = qBlue(pixel); - int a = qAlpha(pixel); - - switch (channel) - { - case ImageProcessingEditor::RGB: - pixel = qRgba(r, g, b, 255); - break; - case ImageProcessingEditor::RRR: - pixel = qRgba(r, r, r, 255); - break; - case ImageProcessingEditor::GGG: - pixel = qRgba(g, g, g, 255); - break; - case ImageProcessingEditor::BBB: - pixel = qRgba(b, b, b, 255); - break; - case ImageProcessingEditor::Alpha: - pixel = qRgba(a, a, a, 255); - break; - default: - break; - } - - previewImg.setPixel(x, y, pixel); - } - } - // Cache the image in current preview mode - m_previewImages[channel] = previewImg; - } - } - - void TexturePreviewWidget::RefreshPreviewImage(RefreshMode mode) - { - // Ignore any none-conversion refresh request when the image is being converted - if (m_updateTimer->isActive() && mode != RefreshMode::Convert) - { - return; - } - - switch (mode) - { - case RefreshMode::Convert: - { - // Start conversion in a AZ::Job - m_previewConverter->StartConvert(); - // Start the timer to trigger the update function - m_updateTimer->start(s_updateInterval); - SetImageLabelText(QString("Converting for preview...Progress 0.01%")); - } - break; - case RefreshMode::Mip: - { - GenerateMipmap(m_currentMipIndex); - GenerateChannelImage(m_previewMode); - PaintPreviewImage(); - } - break; - case RefreshMode::Channel: - { - GenerateChannelImage(m_previewMode); - PaintPreviewImage(); - } - break; - default: - PaintPreviewImage(); - break; - } - } - - void TexturePreviewWidget::PaintPreviewImage() - { - if (m_previewImages[m_previewMode].isNull()) - { - SetImageLabelText(QString("Conversion failed, please check console for more information."), false); - return; - } - SetImageLabelText(QString(), false); - - // Paint the image on to the image label - QPixmap pixMap = QPixmap::fromImage(m_previewImages[m_previewMode]); - QSize size = m_ui->imageLabel->size(); - QPixmap finalPix = pixMap.copy(); - finalPix.fill(Qt::transparent); - finalPix = finalPix.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - QPainter painter(&finalPix); - painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); - QRect rect = finalPix.rect(); - if (m_previewTiled) - { - pixMap = pixMap.scaled(size / 2, Qt::KeepAspectRatio, Qt::SmoothTransformation); - painter.drawTiledPixmap(rect, pixMap); - } - else - { - painter.drawPixmap(rect, pixMap); - } - // Recenter the image label - float aspectRatio = static_cast(finalPix.width()) / static_cast(finalPix.height()); - QSize preferredSize; - if (aspectRatio >= 1.0f) - { - preferredSize = QSize(aznumeric_cast(m_imageLabelSize), aznumeric_cast(m_imageLabelSize / aspectRatio)); - } - else - { - preferredSize = QSize(aznumeric_cast(m_imageLabelSize * aspectRatio), aznumeric_cast(m_imageLabelSize)); - } - - m_ui->imageLabel->resize(preferredSize); - m_ui->imageLabel->setPixmap(finalPix); - - QPoint center = m_ui->mainWidget->rect().center(); - m_ui->imageLabel->move(center - QPoint(preferredSize.width() / 2, preferredSize.height() / 2)); - - } - - void TexturePreviewWidget::SetImageLabelText(const QString& text, bool busyStatus /*= true*/) - { - // Since setting pixmap will change the label size - // Need to set back to initial size and recenter before displaying text - m_ui->imageLabel->resize(QSize(aznumeric_cast(m_imageLabelSize), aznumeric_cast(m_imageLabelSize))); - QPoint center = m_ui->mainWidget->rect().center(); - m_ui->imageLabel->move(center - QPoint(aznumeric_cast(m_imageLabelSize / 2), aznumeric_cast(m_imageLabelSize / 2))); - m_ui->imageLabel->setText(text); - - // Set busy label status and position to align with the text - m_ui->busyLabel->SetIsBusy(busyStatus); - QSize size = m_ui->busyLabel->size(); - m_ui->busyLabel->move(center - QPoint(size.width() + m_ui->imageLabel->sizeHint().width() / 2, size.width() / 2)); - m_ui->busyLabel->setVisible(busyStatus); - } - - void TexturePreviewWidget::RefreshWarning() - { - int imageWidth = m_textureSetting->m_img->GetWidth(0); - int imageHeight = m_textureSetting->m_img->GetHeight(0); - AZStd::list stretchedPlatform; - - for (auto& iter: m_textureSetting->m_settingsMap) - { - PlatformName platform = iter.first; - const PresetSettings* presetSettings = BuilderSettingManager::Instance()->GetPreset(iter.second.m_preset, platform); - if (presetSettings) - { - EPixelFormat dstFmt = presetSettings->m_pixelFormat; - if (!CPixelFormats::GetInstance().IsImageSizeValid(dstFmt, imageWidth, imageHeight, false)) - { - stretchedPlatform.push_back(EditorHelper::ToReadablePlatformString(platform).c_str()); - } - } - } - - if (stretchedPlatform.size() > 0) - { - QString warningText = QString("The output image will be stretched on Platform:"); - int i = 0; - for (AZStd::string platform: stretchedPlatform) - { - warningText += i > 0 ? ", " : " "; - warningText += platform.c_str(); - i ++; - } - m_ui->warningLabel->setText(warningText); - m_ui->warningLabel->setVisible(true); - m_ui->warningIcon->setVisible(true); - } - else - { - m_ui->warningLabel->setVisible(false); - m_ui->warningIcon->setVisible(false); - } - } - - void TexturePreviewWidget::OnChangePreviewMode(int index) - { - if (index < (int)PreviewMode::Count) - { - m_previewMode = (PreviewMode)index; - - RefreshPreviewImage(RefreshMode::Channel); - } - } - - void TexturePreviewWidget::OnTiledChanged(bool checked) - { - m_previewTiled = checked; - RefreshPreviewImage(RefreshMode::Repaint); - } - - bool TexturePreviewWidget::OnQtEvent(QEvent * event) - { - if (event->type() == QEvent::KeyPress) - { - const QKeyEvent* ke = static_cast(event); - if (ke->isAutoRepeat()) - { - return false; //ignore repeat key event - } - - if (ke->key() == Qt::Key_Space) - { - if (!m_updateTimer->isActive()) // Only popup when image is not converting - { - m_previewPopup.reset(new ImagePopup(m_previewImages[m_previewMode], this)); - m_previewPopup->installEventFilter(this); - m_previewPopup->show(); - event->accept(); - return true; - } - } - else if (ke->key() == Qt::Key_Alt) - { - m_previewMode = PreviewMode::Alpha; - RefreshPreviewImage(RefreshMode::Channel); - event->accept(); - return true; - } - else if (ke->key() == Qt::Key_Shift) - { - m_previewMode = PreviewMode::RGBA; - RefreshPreviewImage(RefreshMode::Channel); - event->accept(); - return true; - } - } - else if (event->type() == QEvent::KeyRelease) - { - const QKeyEvent* ke = static_cast(event); - if (ke->isAutoRepeat()) - { - return false; //ignore repeat key event - } - if (ke->key() == Qt::Key_Space) - { - if (m_previewPopup) - { - m_previewPopup->hide(); - } - event->accept(); - return true; - } - else if (ke->key() == Qt::Key_Alt) - { - m_previewMode = (PreviewMode)m_ui->previewComboBox->currentIndex(); - RefreshPreviewImage(RefreshMode::Channel); - event->accept(); - return true; - } - else if (ke->key() == Qt::Key_Shift) - { - m_previewMode = (PreviewMode)m_ui->previewComboBox->currentIndex(); - RefreshPreviewImage(RefreshMode::Channel); - event->accept(); - return true; - } - } - else if (event->type() == QEvent::ApplicationStateChange) - { - const QApplicationStateChangeEvent* appEvent = static_cast(event); - AZ_Warning("Texture Editor", false, "app status change %d", appEvent->applicationState()); - if (appEvent->applicationState() != Qt::ApplicationState::ApplicationActive) - { - PreviewMode currPreviewMode = (PreviewMode)m_ui->previewComboBox->currentIndex(); - if (m_previewMode != currPreviewMode) - { - m_previewMode = currPreviewMode; - RefreshPreviewImage(RefreshMode::Channel); - event->accept(); - return true; - } - } - } - else if (event->type() == QEvent::ShortcutOverride) - { - // since we respond to the following things, let Qt know so that shortcuts don't override us - - QKeyEvent* kev = static_cast(event); - int key = kev->key() | kev->modifiers(); - switch (key) - { - case Qt::Key_Space: - case Qt::Key_Alt: - case Qt::Key_Shift: - event->accept(); - return true; - break; - - default: - break; - } - } - return false; - } - - bool TexturePreviewWidget::eventFilter(QObject* obj, QEvent* event) - { - if (event->type() == QEvent::KeyRelease) - { - const QKeyEvent* ke = static_cast(event); - if (ke->key() == Qt::Key_Space && !ke->isAutoRepeat()) - { - if (m_previewPopup) - { - m_previewPopup->hide(); - } - return true; - } - } - else if (event->type() == QEvent::ApplicationStateChange) - { - const QApplicationStateChangeEvent* appEvent = static_cast(event); - if (appEvent->applicationState() != Qt::ApplicationState::ApplicationActive) - { - if (m_previewPopup) - { - m_previewPopup->hide(); - } - } - return true; - } - - return QWidget::eventFilter(obj, event); - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.h b/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.h deleted file mode 100644 index 84ef09d366..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#include -#include - -#include -#endif - -namespace Ui -{ - class TexturePreviewWidget; -} - -namespace ImageProcessingEditor -{ - enum PreviewMode - { - RGB = 0, - RRR, - GGG, - BBB, - Alpha, - RGBA, - Count - }; - - enum class RefreshMode - { - Convert, // Convert the whole image from beginning, takes longest time - Mip, // Generate a new mip from from converted image - Channel, // Generate a new channel image from converted image - Repaint, - }; - - class TexturePreviewWidget - : public QWidget - , protected EditorInternalNotificationBus::Handler - { - Q_OBJECT - public: - AZ_CLASS_ALLOCATOR(TexturePreviewWidget, AZ::SystemAllocator, 0); - explicit TexturePreviewWidget(EditorTextureSetting& texureSetting, QWidget* parent = 0); - ~TexturePreviewWidget(); - bool OnQtEvent(QEvent* event); - - public slots: - void OnTiledChanged(bool checked); - void OnPrevMip(); - void OnNextMip(); - void OnChangePreviewMode(int index); - void UpdatePreview(); - void OnAlwaysRefresh(); - void OnRefreshPerClick(); - void OnRefreshClicked(); - - protected: - //////////////////////////////////////////////////////////////////////// - //EditorInternalNotificationBus - void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform); - //////////////////////////////////////////////////////////////////////// - void resizeEvent(QResizeEvent *event) override; - bool eventFilter(QObject* obj, QEvent* event) override; - - private: - void SetUpResolutionInfo(); - void RefreshUI(bool fullRefresh = false); - void RefreshPreviewImage(RefreshMode mode); - void GenerateMipmap(int mip); - void GenerateChannelImage(PreviewMode channel); - void PaintPreviewImage(); - void SetImageLabelText(const QString& text, bool busyStatus = true); - void RefreshWarning(); - - AZStd::list m_resolutionInfos; - QScopedPointer m_ui; - EditorTextureSetting* m_textureSetting; - int m_currentMipIndex = 0; - bool m_previewTiled = false; - float m_imageLabelSize = 0; - AZStd::string m_platform; - unsigned int m_mipCount = 1; - - /////////////////////////////////////////// - // Preview window - PreviewMode m_previewMode = PreviewMode::RGB; - QScopedPointer m_previewPopup; - AZStd::unique_ptr m_previewConverter; - ImageProcessing::IImageObjectPtr m_previewImageRaw; - QImage m_previewImages[PreviewMode::Count]; - QTimer* m_updateTimer; - static const int s_updateInterval = 200; - //////////////////////////////////////////// - - //////////////////////////////////////////// - // Refresh button - bool m_alwaysRefreshPreview = true; - QAction* m_alwaysRefreshAction = nullptr; - QAction* m_refreshPerClickAction = nullptr; - QIcon m_refreshPerClickIcon; - QIcon m_alwaysRefreshIcon; - //////////////////////////////////////////// - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.ui b/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.ui deleted file mode 100644 index 5f42fc8fd9..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePreviewWidget.ui +++ /dev/null @@ -1,371 +0,0 @@ - - - TexturePreviewWidget - - - - 0 - 0 - 672 - 579 - - - - Form - - - - - - - - - - - Preview tiled - - - - - - - - 0 - 0 - - - - Shift: RGBA | Alt:Alpha | Space: Full-size - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - 0 - 500 - - - - - - 0 - 0 - 171 - 185 - - - - - 0 - 0 - - - - Qt::RightToLeft - - - - - - - - - - - - - - - - 0 - 0 - - - - - 16 - 16 - - - - - 26 - 25 - - - - - - - :/warning.png - - - - - - - - - Qt::Vertical - - - - 115 - 32 - - - - - - - - - - - - - - :/Forward.png - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - ... - - - - :/Backward.png - - - - - - - - - - Qt::Vertical - - - - 115 - 32 - - - - - - - - - - - - Mip 1 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Image size: 2048 x 2048 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - File Size: 4,096 KB - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - true - - - - - - - - - - 24 - 24 - - - - false - - - false - - - QToolButton::MenuButtonPopup - - - Qt::ToolButtonIconOnly - - - false - - - - - - - - - - - 0 - 0 - 400 - 400 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 2048 - 2048 - - - - image - - - true - - - Qt::AlignCenter - - - - - - 510 - 80 - 30 - 30 - - - - - 0 - 0 - - - - - 10 - 10 - - - - - 0 - 0 - - - - - 24 - 24 - - - - imageLabel - infoLayer - busyLabel - - - - - - - AzQtComponents::StyledBusyLabel - QWidget -
AzQtComponents/Components/StyledBusyLabel.h
- 1 -
-
- - - - -
diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.cpp b/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.cpp deleted file mode 100644 index 90044a18c0..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include "TexturePropertyEditor.h" -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -namespace ImageProcessingEditor -{ - TexturePropertyEditor::TexturePropertyEditor(const AZ::Uuid& sourceTextureId, QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowTitleHint) - , m_ui(new Ui::TexturePropertyEditor) - , m_textureSetting(sourceTextureId) - , m_validImage(true) - { - if (m_textureSetting.m_img == nullptr) - { - m_validImage = false; - return; - } - - m_ui->setupUi(this); - - //Initialize all the format string here - EditorHelper::InitPixelFormatString(); - - //TexturePreviewWidget will be the widget to preview mipmaps - m_previewWidget.reset(aznew TexturePreviewWidget(m_textureSetting, this)); - m_ui->mainLayout->layout()->addWidget(m_previewWidget.data()); - - //TexturePresetSelectionWidget will be the widget to select the preset for the texture - m_presetSelectionWidget.reset(aznew TexturePresetSelectionWidget(m_textureSetting, this)); - m_ui->mainLayout->layout()->addWidget(m_presetSelectionWidget.data()); - - //ResolutionSettingWidget will be the table section to display mipmap resolution for each platform - m_resolutionSettingWidget.reset(aznew ResolutionSettingWidget(ResoultionWidgetType::TexturePropety, m_textureSetting, this)); - m_ui->mainLayout->layout()->addWidget(m_resolutionSettingWidget.data()); - - //MipmapSettingWidget will be simple ReflectedProperty editor to reflect mipmap settings section - m_mipmapSettingWidget.reset(aznew MipmapSettingWidget(m_textureSetting, this)); - m_ui->mainLayout->layout()->addWidget(m_mipmapSettingWidget.data()); - - // Disable horizontal scroll - m_ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - QObject::connect(m_ui->saveBtn, &QPushButton::clicked, this, &TexturePropertyEditor::OnSave); - QObject::connect(m_ui->helpBtn, &QPushButton::clicked, this, &TexturePropertyEditor::OnHelp); - QObject::connect(m_ui->cancelBtn, &QPushButton::clicked, this, &QDialog::reject); - - EditorInternalNotificationBus::Handler::BusConnect(); - - // When checkbox and combobox is focused, they will intercept the space shortcut, need to disable focus on them first - // to get space shortcut pass through - QList checkBoxWidgets = QObject::findChildren(); - for (QCheckBox* widget: checkBoxWidgets) - { - widget->setFocusPolicy(Qt::NoFocus); - } - QList comboBoxWidgets = QObject::findChildren(); - for (QComboBox* widget : comboBoxWidgets) - { - widget->setFocusPolicy(Qt::NoFocus); - } - this->setFocusPolicy(Qt::StrongFocus); - - } - - TexturePropertyEditor::~TexturePropertyEditor() - { - EditorInternalNotificationBus::Handler::BusDisconnect(); - } - - bool TexturePropertyEditor::HasValidImage() - { - return m_validImage; - } - - void TexturePropertyEditor::OnEditorSettingsChanged([[maybe_unused]] bool needRefresh, const AZStd::string& /*platform*/) - { - m_textureSetting.m_modified = true; - } - - void TexturePropertyEditor::OnSave() - { - if (!m_validImage) - { - return; - } - - bool sourceControlActive = false; - AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive); - AZStd::string outputPath = m_textureSetting.m_fullPath + ImageProcessing::TextureSettings::modernExtensionName; - - if (sourceControlActive) - { - using ApplicationBus = AzToolsFramework::ToolsApplicationRequestBus; - bool checkoutResult = false; - ApplicationBus::BroadcastResult(checkoutResult, &ApplicationBus::Events::RequestEditForFileBlocking, outputPath.c_str(), "Checking out .imagesetting file", []([[maybe_unused]] int& current, [[maybe_unused]] int& max) {}); - - if (checkoutResult) - { - SaveTextureSetting(outputPath); - } - else - { - AZ_Error("Texture Editor", false, "Cannot checkout file '%s' from source control.", outputPath.c_str()); - } - } - else - { - const bool fileExisted = AZ::IO::FileIOBase::GetInstance()->Exists(outputPath.c_str()); - const bool fileReadOnly = AZ::IO::FileIOBase::GetInstance()->IsReadOnly(outputPath.c_str()); - - if (!fileExisted || !fileReadOnly) - { - SaveTextureSetting(outputPath); - } - } - } - - void TexturePropertyEditor::SaveTextureSetting(AZStd::string outputPath) - { - if (!m_validImage) - { - return; - } - - ImageProcessing::TextureSettings& baseSetting = m_textureSetting.GetMultiplatformTextureSetting(); - for (auto& it : m_textureSetting.m_settingsMap) - { - baseSetting.ApplySettings(it.second, it.first); - } - - ImageProcessing::StringOutcome outcome = ImageProcessing::TextureSettings::WriteTextureSetting(outputPath, baseSetting); - - if (outcome.IsSuccess()) - { - // Since setting is successfully saved, we can safely delete the legacy setting now - DeleteLegacySetting(); - } - else - { - AZ_Error("Texture Editor", false, "Cannot save texture settings!"); - } - } - - void TexturePropertyEditor::DeleteLegacySetting() - { - AZStd::string legacyFile = m_textureSetting.m_fullPath + ImageProcessing::TextureSettings::legacyExtensionName; - const bool fileExisted = AZ::IO::FileIOBase::GetInstance()->Exists(legacyFile.c_str()); - if (fileExisted) - { - bool sourceControlActive = false; - AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive); - - if (sourceControlActive) - { - AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestDelete, legacyFile.c_str(), - [](bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - //Deletes the file locally if it's not tracked by source control - if (!success && !info.IsManaged()) - { - AZ::IO::FileIOBase::GetInstance()->Remove(info.m_filePath.c_str()); - } - }); - } - else - { - AZ::IO::FileIOBase::GetInstance()->Remove(legacyFile.c_str()); - } - } - } - - - void TexturePropertyEditor::OnHelp() - { - QString webLink = tr("https://docs.aws.amazon.com/console/lumberyard/texturepipeline"); - QDesktopServices::openUrl(QUrl(webLink)); - } - - - bool TexturePropertyEditor::event(QEvent* event) - { - bool needsBlocking = false; - if (m_previewWidget) - { - needsBlocking = m_previewWidget->OnQtEvent(event); - } - return needsBlocking ? true : QWidget::event(event); - } - -}//namespace ImageProcessingEditor -#include diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.h b/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.h deleted file mode 100644 index 77261d820a..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#endif - -namespace Ui -{ - class TexturePropertyEditor; -} - -namespace ImageProcessingEditor -{ - class TexturePropertyEditor - : public AzQtComponents::StyledDialog - , protected EditorInternalNotificationBus::Handler - { - Q_OBJECT - public: - - AZ_CLASS_ALLOCATOR(TexturePropertyEditor, AZ::SystemAllocator, 0); - explicit TexturePropertyEditor(const AZ::Uuid& sourceTextureId, QWidget* parent = nullptr); - ~TexturePropertyEditor(); - - bool HasValidImage(); - - protected: - void OnSave(); - void OnHelp(); - - //////////////////////////////////////////////////////////////////////// - //EditorInternalNotificationBus - void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform); - //////////////////////////////////////////////////////////////////////// - - bool event(QEvent* event) override; - - private: - QScopedPointer m_ui; - QScopedPointer m_previewWidget; - QScopedPointer m_presetSelectionWidget; - QScopedPointer m_resolutionSettingWidget; - QScopedPointer m_mipmapSettingWidget; - - EditorTextureSetting m_textureSetting; - bool m_validImage = true; - - void SaveTextureSetting(AZStd::string outputPath); - void DeleteLegacySetting(); - - }; -} //namespace ImageProcessingEditor - diff --git a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.ui b/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.ui deleted file mode 100644 index 33a7fd3376..0000000000 --- a/Gems/ImageProcessing/Code/Source/Editor/TexturePropertyEditor.ui +++ /dev/null @@ -1,120 +0,0 @@ - - - TexturePropertyEditor - - - - 0 - 0 - 580 - 1100 - - - - - 580 - 800 - - - - - 580 - 1200 - - - - Texture Settings Editor - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 560 - 1049 - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - ? - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - Apply - - - - - - - Close - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderBaseType.h b/Gems/ImageProcessing/Code/Source/ImageBuilderBaseType.h deleted file mode 100644 index 962cd81668..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderBaseType.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License").All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file.Do not -* remove or modify any license notices.This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once -#include - -typedef AZ::s8 int8; -typedef AZ::s8 sint8; -typedef AZ::u8 uint8; - -typedef AZ::s16 int16; -typedef AZ::s16 sint16; -typedef AZ::u16 uint16; - -typedef AZ::s32 int32; -typedef AZ::s32 sint32; -typedef AZ::u32 uint32; - -typedef float f32; -typedef double f64; diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp deleted file mode 100644 index 8c0dc0ff56..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -namespace ImageProcessing -{ - BuilderPluginComponent::BuilderPluginComponent() - { - // AZ Components should only initialize their members to null and empty in constructor - // after construction, they may be deserialized from file. - } - - BuilderPluginComponent::~BuilderPluginComponent() - { - } - - void BuilderPluginComponent::Init() - { - } - - void BuilderPluginComponent::Activate() - { - // create and initialize BuilderSettingManager once since it's will be used for image conversion - BuilderSettingManager::CreateInstance(); - - auto outcome = ImageProcessing::BuilderSettingManager::Instance()->LoadBuilderSettings(); - AZ_Error("Image Processing", outcome.IsSuccess(), "Failed to load default preset settings!"); - - // Activate is where you'd perform registration with other objects and systems. - // Since we want to register our builder, we do that here: - AssetBuilderSDK::AssetBuilderDesc builderDescriptor; - builderDescriptor.m_name = "Image Worker Builder"; - builderDescriptor.m_version = 2; - builderDescriptor.m_analysisFingerprint = AZStd::string::format("%d", ImageProcessing::BuilderSettingManager::Instance()->BuilderSettingsVersion()); - - for (int i = 0; i < s_TotalSupportedImageExtensions; i++) - { - builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(s_SupportedImageExtensions[i], AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - } - - //add ".dds" here separately since we only apply copy operation for this type of file. and there won't be export option for dds files. - builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.dds", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - builderDescriptor.m_busId = azrtti_typeid(); - builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - m_imageBuilder.BusConnect(builderDescriptor.m_busId); - ImageProcessingRequestBus::Handler::BusConnect(); - AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); - } - - void BuilderPluginComponent::Deactivate() - { - ImageProcessingRequestBus::Handler::BusDisconnect(); - m_imageBuilder.BusDisconnect(); - BuilderSettingManager::DestroyInstance(); - CPixelFormats::DestroyInstance(); - } - - void BuilderPluginComponent::Reflect(AZ::ReflectContext* context) - { - // components also get Reflect called automatically - // this is your opportunity to perform static reflection or type registration of any types you want the serializer to know about - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })) - ; - } - - BuilderSettingManager::Reflect(context); - BuilderSettings::Reflect(context); - PresetSettings::Reflect(context); - CubemapSettings::Reflect(context); - MipmapSettings::Reflect(context); - TextureSettings::Reflect(context); - } - - void BuilderPluginComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e)); - } - - void BuilderPluginComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e)); - } - - IImageObjectPtr BuilderPluginComponent::LoadImage(const AZStd::string& filePath) - { - return IImageObjectPtr(LoadImageFromFile(filePath)); - } - - IImageObjectPtr BuilderPluginComponent::LoadImagePreview(const AZStd::string& filePath) - { - IImageObjectPtr image(LoadImageFromFile(filePath)); - if (image) - { - ImageToProcess imageToProcess(image); - imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); - return imageToProcess.Get(); - } - return image; - } - - void ImageBuilderWorker::ShutDown() - { - // it is important to note that this will be called on a different thread than your process job thread - m_isShuttingDown = true; - } - - // this happens early on in the file scanning pass - // this function should consistently always create the same jobs, and should do no checking whether the job is up to date or not - just be consistent. - void ImageBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) - { - if (m_isShuttingDown) - { - response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; - return; - } - - // Get the extension of the file - AZStd::string ext; - AzFramework::StringFunc::Path::GetExtension(request.m_sourceFile.c_str(), ext, false); - AZStd::to_upper(ext.begin(), ext.end()); - - // We process the same file for all platforms - for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms) - { - if (ImageProcessing::BuilderSettingManager::Instance()->DoesSupportPlatform(platformInfo.m_identifier)) - { - AssetBuilderSDK::JobDescriptor descriptor; - descriptor.m_jobKey = ext + " Compile"; - descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); - descriptor.m_critical = false; - descriptor.m_additionalFingerprintInfo = AZStd::string::format("%d", ImageProcessing::BuilderSettingManager::Instance()->BuilderSettingsVersion()); - response.m_createJobOutputs.push_back(descriptor); - } - } - - response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; - return; - } - - // later on, this function will be called for jobs that actually need doing. - // the request will contain the CreateJobResponse you constructed earlier, including any keys and values you placed into the hash table - void ImageBuilderWorker::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) - { - // Before we begin, let's make sure we are not meant to abort. - AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId); - - AZStd::vector productFilepaths; - bool imageProcessingSuccessful = false; - bool needConversion = true; - - //if the original file is a dds file then skip conversion - if (AzFramework::StringFunc::Path::IsExtension(request.m_fullPath.c_str(), "dds", false)) - { - productFilepaths.push_back(request.m_fullPath); - imageProcessingSuccessful = true; - needConversion = false; - } - - // Do conversion and get exported file's path - if (needConversion) - { - AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Performing image conversion: %s\n", request.m_fullPath.c_str()); - ImageConvertProcess* process = CreateImageConvertProcess(request.m_fullPath, request.m_tempDirPath, - request.m_jobDescription.GetPlatformIdentifier()); - - if (process != nullptr) - { - //the process can be stopped if the job is cancelled or the worker is shutting down - while (!process->IsFinished() && !m_isShuttingDown && !jobCancelListener.IsCancelled()) - { - process->UpdateProcess(); - } - - //get process result - imageProcessingSuccessful = process->IsSucceed(); - process->GetAppendOutputFilePaths(productFilepaths); - - delete process; - } - else - { - imageProcessingSuccessful = false; - } - } - - if (imageProcessingSuccessful) - { - AZ::Outcome result = PopulateProducts(request, productFilepaths, response.m_outputProducts); - if (result.IsSuccess()) - { - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - } - else - { - AZ_Error(AssetBuilderSDK::ErrorWindow, false, result.GetError().c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; - } - } - else - { - if (m_isShuttingDown) - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled; - } - else if (jobCancelListener.IsCancelled()) - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled was requested for job %s.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled; - } - else - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Unexpected error during processing job %s.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; - } - } - } - - AZ::Outcome ImageBuilderWorker::PopulateProducts(const AssetBuilderSDK::ProcessJobRequest& request, const AZStd::vector& productFilepaths, AZStd::vector& jobProducts) - { - AssetBuilderSDK::JobProduct* rgbBaseJobProduct = nullptr; - AssetBuilderSDK::JobProduct* diffBaseJobProduct = nullptr; - AssetBuilderSDK::JobProduct* baseJobProduct = nullptr; - AssetBuilderSDK::JobProduct* alphaBaseJobProduct = nullptr; - // Report the image-import result (filepath to one or many '.dds') - - // This reserve is critically important to prevent resizing the vector and invalidating the pointers we need to save off - jobProducts.reserve(productFilepaths.size()); - - for (const auto& product : productFilepaths) - { - AssetBuilderSDK::JobProduct jobProduct(product); - jobProduct.m_dependenciesHandled = true; // Dependencies are handled down below. The base products will have dependencies, lod products won't - jobProducts.push_back(jobProduct); - - AZ::u32 lodLevel = AssetBuilderSDK::GetSubID_LOD(jobProduct.m_productSubID); - - if(jobProduct.m_productSubID == 0) - { - rgbBaseJobProduct = &jobProducts.back(); - } - else if((jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_DIFF) && lodLevel == 0) - { - diffBaseJobProduct = &jobProducts.back(); - } - else if((jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_ALPHA) && lodLevel == 0) - { - alphaBaseJobProduct = &jobProducts.back(); - } - } - - //We can have a diff and/or a rgb base. The rgb base always takes precedence when present - baseJobProduct = rgbBaseJobProduct; - - if(!baseJobProduct) - { - baseJobProduct = diffBaseJobProduct; - } - - for (AssetBuilderSDK::JobProduct& jobProduct : jobProducts) - { - AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, jobProduct.m_productSubID), 0); - - AZ::u32 lodLevel = AssetBuilderSDK::GetSubID_LOD(jobProduct.m_productSubID); - bool isAlpha = jobProduct.m_productSubID & AssetBuilderSDK::SUBID_FLAG_ALPHA; - - if (lodLevel > 0) - { - if (isAlpha) - { - if (alphaBaseJobProduct) - { - // add all alpha mips to the base alpha texture as product dependency - alphaBaseJobProduct->m_dependencies.push_back(productDependency); - } - else - { - return AZ::Failure(AZStd::string::format("Unable to add (%s) file as a product dependency of the base alpha texture file. Base alpha texture file is missing from the products list.\n", jobProduct.m_productFileName.c_str())); - } - } - else - { - if (baseJobProduct) - { - // add all rgb mips to the base rgb texture as product dependency - baseJobProduct->m_dependencies.push_back(productDependency); - } - else - { - return AZ::Failure(AZStd::string::format("Unable to add (%s) file as a product dependency of the base rgb texture file. Base rgb texture file is missing from the products list.\n", jobProduct.m_productFileName.c_str())); - } - } - } - } - - // Diffuse (_diff) is required by the base (typically for cubemaps) - if (rgbBaseJobProduct && diffBaseJobProduct) - { - AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, diffBaseJobProduct->m_productSubID), 0); - rgbBaseJobProduct->m_dependencies.push_back(productDependency); - } - - if (alphaBaseJobProduct && baseJobProduct) - { - // Add the alphaBaseTexture as a product dependency for baseTexture - AssetBuilderSDK::ProductDependency productDependency(AZ::Data::AssetId(request.m_sourceFileUUID, alphaBaseJobProduct->m_productSubID), 0); - baseJobProduct->m_dependencies.push_back(productDependency); - } - - return AZ::Success(); - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h deleted file mode 100644 index 212081ec92..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - //! Builder to process images - class ImageBuilderWorker - : public AssetBuilderSDK::AssetBuilderCommandBus::Handler - { - public: - AZ_RTTI(ImageBuilderWorker, "{525422DE-05B3-4095-966F-90CD7657A7E1}"); - - ImageBuilderWorker() = default; - ~ImageBuilderWorker() = default; - - //! Asset Builder Callback Functions - void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response); - void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response); - - ////////////////////////////////////////////////////////////////////////// - //!AssetBuilderSDK::AssetBuilderCommandBus interface - void ShutDown() override; // if you get this you must fail all existing jobs and return. - ////////////////////////////////////////////////////////////////////////// - - //! Populates the jobProduct vector with all the entries including their product dependencies - AZ::Outcome PopulateProducts(const AssetBuilderSDK::ProcessJobRequest& request, const AZStd::vector& productFilepaths, AZStd::vector& jobProducts); - - private: - bool m_isShuttingDown = false; - }; - - //! BuilderPluginComponent is to handle the lifecycle of ImageBuilder module. - class BuilderPluginComponent - : public AZ::Component - , protected ImageProcessingRequestBus::Handler - { - public: - AZ_COMPONENT(BuilderPluginComponent, "{2F12E1BE-D8F6-47A4-AC3E-6C5527C55840}") - static void Reflect(AZ::ReflectContext* context); - - BuilderPluginComponent(); // avoid initialization here. - ~BuilderPluginComponent() override; // free memory an uninitialize yourself. - - ////////////////////////////////////////////////////////////////////////// - // AZ::Component - void Init() override; // create objects, allocate memory and initialize yourself without reaching out to the outside world - void Activate() override; // reach out to the outside world and connect up to what you need to, register things, etc. - void Deactivate() override; // unregister things, disconnect from the outside world - - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - ////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // ImageProcessingRequestBus interface implementation - IImageObjectPtr LoadImage(const AZStd::string& filePath) override; - IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override; - //////////////////////////////////////////////////////////////////////// - - private: - ImageBuilderWorker m_imageBuilder; - }; -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings b/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings deleted file mode 100644 index 7e16a3c98f..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings +++ /dev/null @@ -1,8051 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gems/ImageProcessing/Code/Source/ImageLoader/BTImageLoader.cpp b/Gems/ImageProcessing/Code/Source/ImageLoader/BTImageLoader.cpp deleted file mode 100644 index b06ceccddc..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageLoader/BTImageLoader.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" - -#include "ImageLoaders.h" - -#include -#include - -#include - -namespace -{ - //--------------------------------------------------------------------------- - // Load and save the VTP Binary Terrain (BT) format, documented here: - // http://vterrain.org/Implementation/Formats/BT.html - - // This structure represents a binary layout in the file. To direct load & save it, we need to remove all structure memory padding -#pragma pack(push,1) - struct BtHeader - { - char headerTag[7]; // Should be "binterr" - char headerTagVersion[3]; // Should be "1.3" - AZ::s32 columns; // # of columns in the heightfield - AZ::s32 rows; // # of rows in the heightfield - AZ::s16 bytesPerPoint; // bytes per height value, either 2 for signed ints or 4 for floats - AZ::s16 isFloatingPointData; // 1 if height values are floats, 0 for 16-bit signed ints - AZ::s16 horizUnits; // 0 if degrees, 1 if meters, 2 if international feet, 3 if US survey feet - AZ::s16 utmZone; // UTM projection zone 1 to 60 or -1 to -60 (see https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system ) - AZ::s16 datum; // Datum value (6001 to 6094), see http://www.epsg.org/ - double leftExtent; // left coordinate projection of the file - double rightExtent; // right coordinate projection of the file - double bottomExtent; // bottom coordinate projection of the file - double topExtent; // top coordinate projection of the file - AZ::s16 externalProjection; // 1 if projection is in an external .prj file, 0 if it's contained in the header - float scale; // vertical units in meters. 0.0 should be treated as 1.0 - char unused[190]; - }; -#pragma pack(pop) - - AZStd::vector LoadFile(const AZStd::string& fileName) - { - AZ::IO::FileIOBase* fileReader = AZ::IO::FileIOBase::GetInstance(); - - if (!fileReader) - { - return {}; - } - - // an engine compatible file reader has been attached, so use that. - AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; - AZ::u64 fileSize = 0; - - if (!fileReader->Open(fileName.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary, fileHandle)) - { - return {}; - } - - if ((!fileReader->Size(fileHandle, fileSize)) || (fileSize == 0)) - { - fileReader->Close(fileHandle); - return {}; - } - - AZStd::vector fileBuf(fileSize); - - if (!fileReader->Read(fileHandle, fileBuf.data(), fileSize, true)) - { - fileReader->Close(fileHandle); - return {}; - } - - fileReader->Close(fileHandle); - - return fileBuf; - } - - bool IsHeaderValid(const BtHeader* header, std::size_t fileSize) - { - bool validData = true; - - // Do some quick error-checking on the header to make sure it meets our expectations - - // Does the header have the right header tag? (binterr1.0 - binterr1.3) - validData = validData && (memcmp(header->headerTag, "binterr", sizeof(header->headerTag)) == 0); - validData = validData && (header->headerTagVersion[0] == '1') && (header->headerTagVersion[1] == '.') && (header->headerTagVersion[2] >= '0') && (header->headerTagVersion[2] <= '3'); - - // Will the grid fit into a reasonable image size? - validData = validData && (header->columns >= 0) && (header->columns < 65536); - validData = validData && (header->rows >= 0) && (header->rows < 65536); - - // Do we either have 32-bit floats or 16-bit ints? - validData = validData && (((header->isFloatingPointData == 1) && (header->bytesPerPoint == 4)) || ((header->isFloatingPointData == 0) && (header->bytesPerPoint == 2))); - - // Is the remaining data exactly the size needed to fill our image? - AZ::s32 total = header->columns * header->rows * header->bytesPerPoint; - validData = validData && ((fileSize - sizeof(BtHeader)) == total); - - return validData; - } -} - -namespace ImageProcessing -{ - bool BTLoader::IsExtensionSupported(const char* extension) - { - return strcmp(extension, "bt") == 0; - } - - /* - Most of the logic here was taken from ImageBT.cpp. Please make sure - any changes are kept in sync :) - */ - IImageObject* BTLoader::LoadImageFromBT(const AZStd::string& fileName) - { - auto fileData = LoadFile(fileName); - - if (fileData.size() < sizeof(BtHeader)) - { - return nullptr; - } - - auto header = reinterpret_cast(fileData.data()); - - if (!header || !IsHeaderValid(header, fileData.size())) - { - return nullptr; - } - - if (header->scale == 0.0f) - { - header->scale = 1.0f; - } - - // The BT format defines the data as stored in column-first order, from bottom to top. - // However, some BT files store the data in row-first order, from top to bottom. - // There isn't anything that clearly specifies which type of file it is. If you load it the wrong way, - // the data will look like a bunch of wavy stripes. - // The only difference I've found in test files is datum values above 8000, which appears to be an invalid value for datum - // (it should be 6001-6904 according to the BT definition) - constexpr AZ::s32 invalidDatumValueDenotingColumnFirstData = 8000; - bool isColumnFirstData = (header->datum >= invalidDatumValueDenotingColumnFirstData) ? true : false; - AZ::s32 imageWidth = 0; - AZ::s32 imageHeight = 0; - - if (isColumnFirstData) - { - imageWidth = header->rows; - imageHeight = header->columns; - } - else - { - imageWidth = header->columns; - imageHeight = header->rows; - } - - IImageObject* image = IImageObject::CreateImage(imageWidth, imageHeight, 1, EPixelFormat::ePixelFormat_R32F); - - AZ::u8* p = nullptr; - AZ::u32 dwPitch = 0; - image->GetImagePointer(0, p, dwPitch); - - auto dst = reinterpret_cast(p); - auto maxPixel = std::numeric_limits::lowest(); - auto minPixel = std::numeric_limits::max(); - auto terrainData = reinterpret_cast(header + 1); - - // Read in the pixel data - if (header->isFloatingPointData) - { - for (AZ::s32 y = 0; y < imageHeight; ++y) - { - for (AZ::s32 x = 0; x < imageWidth; ++x) - { - float height = *reinterpret_cast(terrainData); - terrainData += sizeof(float); - - // Scale based on what our header defines - float setVal = dst[(y * imageWidth) + x] = height * header->scale; - maxPixel = AZStd::max(maxPixel, setVal); - minPixel = AZStd::min(minPixel, setVal); - } - } - } - else - { - for (AZ::s32 y = 0; y < imageHeight; ++y) - { - for (AZ::s32 x = 0; x < imageWidth; ++x) - { - float height = static_cast(*reinterpret_cast(terrainData)); - terrainData += sizeof(AZ::s16); - - // Scale based on what our header defines - float setVal = dst[(y * imageWidth) + x] = height * header->scale; - maxPixel = AZStd::max(maxPixel, setVal); - minPixel = AZStd::min(minPixel, setVal); - } - } - } - - // Scale our range down to 0 - 1 - auto diff = maxPixel - minPixel; - if (AZ::GetAbs(diff) < std::numeric_limits::epsilon()) - { - diff = 1.0f; - } - - auto imagePixels = imageWidth * imageHeight; - for (AZ::s32 i = 0; i < imagePixels; ++i) - { - dst[i] = (dst[i] - minPixel) / diff; - } - - return image; - } -} diff --git a/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.cpp b/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.cpp deleted file mode 100644 index ac6b1d34d5..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include - -namespace ImageProcessing -{ - IImageObject* LoadImageFromFile(const AZStd::string& filename) - { - QFileInfo fileInfo(filename.c_str()); - QString ext = fileInfo.suffix(); - - if (TIFFLoader::IsExtensionSupported(ext.toUtf8())) - { - return TIFFLoader::LoadImageFromTIFF(filename); - } - else if (BTLoader::IsExtensionSupported(ext.toUtf8())) - { - return BTLoader::LoadImageFromBT(filename); - } - else if (QtImageLoader::IsExtensionSupported(ext.toUtf8())) - { - return QtImageLoader::LoadImageFromFile(filename); - } - - AZ_Warning("ImageProcessing", false, "No proper image loader to load file: %s", filename.c_str()); - return nullptr; - } - - bool IsExtensionSupported(const char* extension) - { - if (TIFFLoader::IsExtensionSupported(extension)) - { - return true; - } - else if (BTLoader::IsExtensionSupported(extension)) - { - return true; - } - else if (QtImageLoader::IsExtensionSupported(extension)) - { - return true; - } - return false; - } - - const AZStd::string LoadEmbeddedSettingFromFile(const AZStd::string& filename) - { - QFileInfo fileInfo(filename.c_str()); - QString ext = fileInfo.suffix(); - - if (TIFFLoader::IsExtensionSupported(ext.toUtf8())) - { - return TIFFLoader::LoadSettingFromTIFF(filename); - } - return ""; - } - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.h b/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.h deleted file mode 100644 index ae460b3552..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageLoader/ImageLoaders.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace ImageProcessing -{ - class IImageObject; - - IImageObject* LoadImageFromFile(const AZStd::string& filename); - bool IsExtensionSupported(const char* extension); - const AZStd::string LoadEmbeddedSettingFromFile(const AZStd::string& filename); - - // Tiff loader. The loader support uncompressed tiff with with 1~4 channels and 8bit and 16bit uint or 16bits and 32bits float per channel - // QImage also support tiff (tiff plugin), but it only supports 8bits uint - namespace TIFFLoader - { - bool IsExtensionSupported(const char* extension); - // Load a tiff file to an image object. - IImageObject* LoadImageFromTIFF(const AZStd::string& filename); - // Load embedded .exportsettings string from tiff which was exported by deprecated feature of CryTif plugin. - const AZStd::string LoadSettingFromTIFF(const AZStd::string& filename); - };// namespace ImageTIFF - - namespace BTLoader - { - bool IsExtensionSupported(const char* extension); - // Load a BT file to an image object. - IImageObject* LoadImageFromBT(const AZStd::string& fileName); - }// namespace BTLoader - - // Image loader through Qt's QImage with image formats supported native and through plugins - namespace QtImageLoader - { - bool IsExtensionSupported(const char* extension); - // Load image file which supported by QtImage to an image object - IImageObject* LoadImageFromFile(const AZStd::string& filename); - };// namespace QtImageLoader - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageLoader/QtImageLoader.cpp b/Gems/ImageProcessing/Code/Source/ImageLoader/QtImageLoader.cpp deleted file mode 100644 index dd5dd62b73..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageLoader/QtImageLoader.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ImageProcessing_precompiled.h" - -#include -#include - -#include -#include - -/////////////////////////////////////////////////////////////////////////////////// - -namespace ImageProcessing -{ - namespace QtImageLoader - { - IImageObject* LoadImageFromFile(const AZStd::string& filename) - { - //try to open the image - QImage qimage(filename.c_str()); - if (qimage.isNull()) - { - return NULL; - } - - //convert to format which compatiable our pixel format - if (qimage.format() != QImage::Format_RGBA8888) - { - qimage = qimage.convertToFormat(QImage::Format_RGBA8888); - } - - //create a new image object - IImageObject *pImage = IImageObject::CreateImage(qimage.width(), qimage.height(), 1, - ePixelFormat_R8G8B8A8); - - //get a pointer to the image objects pixel data - uint8* pDst; - uint32 dwPitch; - pImage->GetImagePointer(0, pDst, dwPitch); - - //copy the qImage into the image object - for (uint32 dwY = 0; dwY < (uint32)qimage.height(); ++dwY) - { - uint8* dstLine = &pDst[dwPitch * dwY]; - uchar* srcLine = qimage.scanLine(dwY); - memcpy(dstLine, srcLine, dwPitch); - } - return pImage; - } - - bool IsExtensionSupported(const char* extension) - { - QList imgFormats = QImageReader::supportedImageFormats(); - - for (int i = 0; i < imgFormats.size(); ++i) - { - if (QString::fromUtf8(imgFormats[i]).toLower() == QString(extension).toLower()) - { - return true; - } - } - - return false; - } - }//namespace QtImageLoader -} //namespace ImageProcessing - diff --git a/Gems/ImageProcessing/Code/Source/ImageLoader/TIFFLoader.cpp b/Gems/ImageProcessing/Code/Source/ImageLoader/TIFFLoader.cpp deleted file mode 100644 index 6c2881423d..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageLoader/TIFFLoader.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" - -#include -#include -#include -#include - -#include -#include - -#include - -#include // TIFF library - -namespace ImageProcessing -{ - namespace TIFFLoader - { - class TiffFileRead - { - public: - TiffFileRead(const AZStd::string& filename) - : m_tif(nullptr) - { - m_tif = TIFFOpen(filename.c_str(), "r");; - } - - ~TiffFileRead() - { - if (m_tif != nullptr) - { - TIFFClose(m_tif); - } - } - - TIFF *GetTiff() - { - return m_tif; - } - - private: - TIFF *m_tif; - }; - - bool IsExtensionSupported(const char* extension) - { - QString ext = QString(extension).toLower(); - // This is the list of file extensions supported by this loader - return ext == "tif" || ext == "tiff"; - } - - struct TiffData - { - AZ::u32 m_channels = 0; - AZ::u32 m_photometric = 0; - AZ::u32 m_bitsPerPixel = 0; - AZ::u16 m_format = 0; - - AZ::u32 m_width = 0; - AZ::u32 m_height = 0; - - AZ::u32 m_tileWidth = 0; - AZ::u32 m_tileHeight = 0; - bool m_isTiled = false; - AZ::u32 m_bufSize = 0; - - bool m_isGeoTiff = false; - float m_pixelValueScale = 1.0f; - - EPixelFormat m_pixelFormat = EPixelFormat::ePixelFormat_Unknown; - }; - - static void Process8BitTiff(AZ::u8* dst, const AZ::u8* src, AZ::u32 destIdx, AZ::u32 srcIdx, const TiffData& data, AZ::u8& dstMult) - { - if (data.m_channels == 1) - { - if (data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 3] = 0xFF; - - dstMult = 4; - } - } - else if (data.m_channels == 2) - { - if (data.m_photometric == PHOTOMETRIC_SEPARATED) - { - // convert CMY to RGB (PHOTOMETRIC_SEPARATED refers to inks in TIFF, the value is inverted) - dst[destIdx] = aznumeric_cast(0xFF - src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(0xFF - src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = 0x00; - dst[destIdx + 3] = 0xFF; - - dstMult = 4; - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - - dstMult = 2; - } - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx + 2] * data.m_pixelValueScale); - dst[destIdx + 3] = (data.m_channels == 3) ? 0xFF : aznumeric_cast(src[srcIdx + 3] * data.m_pixelValueScale); - - dstMult = 4; - } - } - - static void Process16BitHDRTiff(AZ::s16* dst, const AZ::s16* src, AZ::u32 destIdx, AZ::u32 srcIdx, const TiffData& data, AZ::u8& dstMult) - { - if (data.m_channels == 1) - { - if (data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 3] = 1; - - dstMult = 4; - } - } - else if (data.m_channels == 2) - { - if (data.m_photometric == PHOTOMETRIC_SEPARATED) - { - //but convert CMY to RGB (PHOTOMETRIC_SEPARATED refers to inks in TIFF, the value is inverted) - dst[destIdx] = uint16(1.0f - src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = uint16(1.0f - src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = 0; - dst[destIdx + 3] = 1; - - dstMult = 4; - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - - dstMult = 2; - } - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx + 2] * data.m_pixelValueScale); - dst[destIdx + 3] = (data.m_channels == 3) ? 1 : aznumeric_cast(src[srcIdx + 3] * data.m_pixelValueScale); - - dstMult = 4; - } - } - - static void Process16BitTiff(AZ::u16* dst, const AZ::u16* src, AZ::u32 destIdx, AZ::u32 srcIdx, const TiffData& data, AZ::u8& dstMult) - { - if (data.m_channels == 1) - { - if (data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 3] = 0xFFFF; - - dstMult = 4; - } - } - else if (data.m_channels == 2) - { - if (data.m_photometric == PHOTOMETRIC_SEPARATED) - { - //convert CMY to RGB (PHOTOMETRIC_SEPARATED refers to inks in TIFF, the value is inverted) - dst[destIdx] = 0xFFFF - aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = 0xFFFF - aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = 0x0000; - dst[destIdx + 3] = 0xFFFF; - - dstMult = 4; - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - - dstMult = 2; - } - } - else - { - dst[destIdx] = aznumeric_cast(src[srcIdx] * data.m_pixelValueScale); - dst[destIdx + 1] = aznumeric_cast(src[srcIdx + 1] * data.m_pixelValueScale); - dst[destIdx + 2] = aznumeric_cast(src[srcIdx + 2] * data.m_pixelValueScale); - dst[destIdx + 3] = (data.m_channels == 3) ? 0xFFFF : aznumeric_cast(src[srcIdx + 3] * data.m_pixelValueScale); - - dstMult = 4; - } - } - - static void Process32BitHDRTiff(float* dst, const float* src, AZ::u32 destIdx, AZ::u32 srcIdx, const TiffData& data, AZ::u8& dstMult) - { - auto getScaledOrClamped = [&data](auto val) - { - // GeoTiff doesn't clamp because negative values are legitimate when the data represents height values below sea level. - return data.m_isGeoTiff ? (val * data.m_pixelValueScale) : AZ::GetMax(val, 0.0f); - }; - - if (data.m_channels == 1) - { - if (data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - // clamp negative values - const float v = getScaledOrClamped(src[srcIdx]); - dst[destIdx] = v; - } - else - { - // clamp negative values - const float v = getScaledOrClamped(src[srcIdx]); - dst[destIdx] = v; - dst[destIdx + 1] = v; - dst[destIdx + 2] = v; - dst[destIdx + 3] = 1.0f; - - dstMult = 4; - } - } - else if (data.m_channels == 2) - { - if (data.m_photometric == PHOTOMETRIC_SEPARATED) - { - //convert CMY to RGB (PHOTOMETRIC_SEPARATED refers to inks in TIFF, the value is inverted) - dst[destIdx] = 1.0f - getScaledOrClamped(src[srcIdx]); - dst[destIdx + 1] = 1.0f - getScaledOrClamped(src[srcIdx + 1]); - dst[destIdx + 2] = 0.0f; - dst[destIdx + 3] = 1.0f; - - dstMult = 4; - } - else - { - dst[destIdx] = src[srcIdx] * data.m_pixelValueScale; - dst[destIdx + 1] = src[srcIdx + 1] * data.m_pixelValueScale; - - dstMult = 2; - } - } - else - { - // clamp negative values; don't swap red and blue -> RGB(A) - dst[destIdx] = getScaledOrClamped(src[srcIdx]); - dst[destIdx + 1] = getScaledOrClamped(src[srcIdx + 1]); - dst[destIdx + 2] = getScaledOrClamped(src[srcIdx + 2]); - dst[destIdx + 3] = (data.m_channels == 3) ? 1.0f : getScaledOrClamped(src[srcIdx + 3]) * data.m_pixelValueScale; - - dstMult = 4; - } - } - - static TiffData GetTiffData(TIFF* tif) - { - TiffData data; - - TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &data.m_channels); - TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &data.m_photometric); - TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &data.m_bitsPerPixel); - TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &data.m_format); - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &data.m_width); - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &data.m_height); - TIFFGetField(tif, TIFFTAG_TILEWIDTH, &data.m_tileWidth); - TIFFGetField(tif, TIFFTAG_TILELENGTH, &data.m_tileHeight); - - // Check to see if this is a tiled TIFF (vs a scanline-based TIFF) - if ((data.m_tileWidth > 0) && (data.m_tileHeight > 0)) - { - // Tiled TIFF, so our buffer needs to be tile-sized - data.m_isTiled = true; - data.m_bufSize = TIFFTileSize(tif); - } - else - { - // Scanline TIFF, so our buffer needs to be scanline-sized. - data.m_bufSize = TIFFScanlineSize(tif); - - // Treat scanlines like a tile of 1 x width size. - data.m_tileHeight = 1; - data.m_tileWidth = data.m_width; - } - - // Defined in GeoTIFF format - http://web.archive.org/web/20160403164508/http://www.remotesensing.org/geotiff/spec/geotiffhome.html - // Used to get the X, Y, Z scales from a GeoTIFF file - constexpr auto GEOTIFF_MODELPIXELSCALE_TAG = 33550; - - // Check to see if it's a GeoTIFF, and if so, whether or not it has the ZScale parameter. - AZ::u32 tagCount = 0; - double* pixelScales = nullptr; - if (TIFFGetField(tif, GEOTIFF_MODELPIXELSCALE_TAG, &tagCount, &pixelScales) == 1) - { - data.m_isGeoTiff = true; - - // if there's an xyz scale, and the Z scale isn't 0, let's use it. - if ((tagCount == 3) && (pixelScales != nullptr) && (pixelScales[2] != 0.0f)) - { - data.m_pixelValueScale = static_cast(pixelScales[2]); - } - } - - // Retrieve the pixel format of the image - switch (data.m_bitsPerPixel) - { - case 8: - { - data.m_pixelFormat = ePixelFormat_R8G8B8X8; - - if (data.m_channels == 1 && data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - data.m_pixelFormat = ePixelFormat_R8; - } - else if (data.m_channels == 4) - { - data.m_pixelFormat = ePixelFormat_R8G8B8A8; - } - - break; - } - - case 16: - { - if (data.m_format == SAMPLEFORMAT_IEEEFP) - { - data.m_pixelFormat = ePixelFormat_R16G16B16A16F; - - if (data.m_channels == 1 && data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - data.m_pixelFormat = ePixelFormat_R16F; - } - } - else - { - data.m_pixelFormat = ePixelFormat_R16G16B16A16; - - if (data.m_channels == 1 && data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - data.m_pixelFormat = ePixelFormat_R16; - } - } - - break; - } - - case 32: - { - if (data.m_format == SAMPLEFORMAT_IEEEFP) - { - data.m_pixelFormat = ePixelFormat_R32G32B32A32F; - - if (data.m_channels == 1 && data.m_photometric != PHOTOMETRIC_MINISBLACK) - { - data.m_pixelFormat = ePixelFormat_R32F; - } - } - - break; - } - - default: - break; - } - - return data; - } - - static IImageObject* LoadTIFF(TIFF* tif) - { - TiffData data = GetTiffData(tif); - AZStd::unique_ptr destImageObject; - destImageObject.reset(IImageObject::CreateImage(data.m_width, data.m_height, - 1, data.m_pixelFormat)); - - uint8* dst; - uint32 pitch; - destImageObject->GetImagePointer(0, dst, pitch); - - AZStd::vector buf(data.m_bufSize); - - AZ::u8 dstMult = 1; - - // Loop across the image height, one tile at a time - for (AZ::u32 imageY = 0; imageY < data.m_height; imageY += data.m_tileHeight) - { - // If we aren't actually tiled, we'll need to read a scanline here - if (!data.m_isTiled) - { - if (TIFFReadScanline(tif, buf.data(), imageY) == -1) - { - AZ_Error("LoadTIFF", false, "Error reading scanline."); - return nullptr; - } - } - - // Loop across the image width, one tile at a time - for (AZ::u32 imageX = 0; imageX < data.m_width; imageX += data.m_tileWidth) - { - // If we *are* tiled, read in a new tile here - if (data.m_isTiled) - { - if (TIFFReadTile(tif, buf.data(), imageX, imageY, 0, 0) == -1) - { - AZ_Error("LoadTIFF", false, "Error reading tile."); - return nullptr; - } - } - - // For each pixel in the tile buffer, read it in and convert. - for (AZ::u32 tileY = 0; tileY < data.m_tileHeight; ++tileY) - { - for (AZ::u32 tileX = 0; tileX < data.m_tileWidth; ++tileX) - { - AZ::u32 srcIdx = ((tileY * data.m_tileWidth) + tileX) * data.m_channels; - AZ::u32 destIdx = (((imageY + tileY) * data.m_width) + (imageX + tileX)) * dstMult; - - switch (data.m_bitsPerPixel) - { - case 8: - Process8BitTiff(dst, buf.data(), destIdx, srcIdx, data, dstMult); - break; - - case 16: - { - switch (data.m_format) - { - case SAMPLEFORMAT_INT: - case SAMPLEFORMAT_IEEEFP: - Process16BitHDRTiff(reinterpret_cast(dst), reinterpret_cast(buf.data()), - destIdx, srcIdx, data, dstMult); - - break; - - default: - Process16BitTiff(reinterpret_cast(dst), reinterpret_cast(buf.data()), - destIdx, srcIdx, data, dstMult); - - break; - } - - break; - } - - case 32: - if (data.m_format == SAMPLEFORMAT_IEEEFP) - { - Process32BitHDRTiff(reinterpret_cast(dst), reinterpret_cast(buf.data()), - destIdx, srcIdx, data, dstMult); - } - else - { - AZ_Error("LoadTIFF", false, "Unknown / unsupported format."); - return nullptr; - } - - break; - - default: - AZ_Error("LoadTIFF", false, "Unknown / unsupported format."); - return nullptr; - } - - } - } - } - } - - return destImageObject.release(); - } - - IImageObject* LoadImageFromTIFF(const AZStd::string& filename) - { - TiffFileRead tiffRead(filename); - TIFF* tif = tiffRead.GetTiff(); - - IImageObject* destImageObject = nullptr; - - if (!tif) - { - AZ_Warning("Image Processing", false, "%s: Open tiff failed (%s)", __FUNCTION__, filename.c_str()); - return destImageObject; - } - - uint32 bitsPerChannel = 0; - uint32 channels = 0; - uint32 format = 0; - TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &channels); - TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerChannel); - TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &format); - - if (channels != 1 && channels != 2 && channels != 3 && channels != 4) - { - AZ_Warning("Image Processing", false, "Unsupported TIFF pixel format (channel count: %d)", channels); - return destImageObject; - } - - uint32 width = 0; - uint32 height = 0; - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); - if (width <= 0 || height <= 0) - { - AZ_Error("Image Processing", false, "%s failed (empty image)", __FUNCTION__); - return destImageObject; - } - - destImageObject = LoadTIFF(tif); - - if (destImageObject == nullptr) - { - AZ_Error("Image Processing", false, "Failed to read TIFF pixels"); - } - - return destImageObject; - } - - const AZStd::string LoadSettingFromTIFF(const AZStd::string& filename) - { - AZStd::string setting = ""; - - TiffFileRead tiffRead(filename); - TIFF* tif = tiffRead.GetTiff(); - - if (tif == nullptr) - { - return setting; - } - - // get image metadata - const unsigned char* buffer = nullptr; - unsigned int bufferLength = 0; - - if (!TIFFGetField(tif, TIFFTAG_PHOTOSHOP, &bufferLength, &buffer)) // 34377 IPTC TAG - { - return setting; - } - - const unsigned char* const bufferEnd = buffer + bufferLength; - - // detailed structure here: - // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037504 - while (buffer < bufferEnd) - { - const unsigned char* const bufferStart = buffer; - - // sanity check - if (buffer[0] != '8' || buffer[1] != 'B' || buffer[2] != 'I' || buffer[3] != 'M') - { - AZ_Warning("Image Processing", false, "Invalid Photoshop TIFF file [%s]!", filename.c_str()); - return setting; - } - buffer += 4; - - // get image resource id - const unsigned short resourceId = (((unsigned short)buffer[0]) << 8) | (unsigned short)buffer[1]; - buffer += 2; - - // get size of pascal string - const unsigned int nameSize = (unsigned int)buffer[0]; - ++buffer; - - // get pascal string - AZStd::string szName(buffer, buffer + nameSize); - buffer += nameSize; - - // align 2 bytes - if ((buffer - bufferStart) & 1) - { - ++buffer; - } - - // get size of resource data - const unsigned int resDataSize = - (((unsigned int)buffer[0]) << 24) | - (((unsigned int)buffer[1]) << 16) | - (((unsigned int)buffer[2]) << 8) | - (unsigned int)buffer[3]; - buffer += 4; - - // IPTC-NAA record. Contains the [File Info...] information. Old RC use this section to store the setting string. - if (resourceId == 0x0404) - { - const unsigned char* const iptcBufferStart = buffer; - - // Old RC uses IPTC ApplicationRecord tags SpecialInstructions to store the setting string - // IPTC Details: https://iptc.org/std/photometadata/specification/mapping/iptc-pmd-newsmlg2.html - unsigned int iptcPos = 0; - while (iptcPos + 5 < resDataSize) - { - int marker = iptcBufferStart[iptcPos++]; - int recordNumber = iptcBufferStart[iptcPos++]; - int dataSetNumber = iptcBufferStart[iptcPos++]; - int fieldLength = (iptcBufferStart[iptcPos++] << 8); - fieldLength += iptcBufferStart[iptcPos++]; - - // Ignore fields other than SpecialInstructions - if (marker != 0x1C || recordNumber != 0x02 || dataSetNumber != 0x28 ) - { - iptcPos += fieldLength; - continue; - } - - //save the setting string before close file - setting = AZStd::string(iptcBufferStart + iptcPos, iptcBufferStart + iptcPos + fieldLength); - return setting; - } - } - - buffer += resDataSize; - - // align 2 bytes - if ((buffer - bufferStart) & 1) - { - ++buffer; - } - } - - return setting; - } - - }// namespace ImageTIFF - -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageProcessingModule.cpp b/Gems/ImageProcessing/Code/Source/ImageProcessingModule.cpp deleted file mode 100644 index 9cd28b39fe..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageProcessingModule.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" -#include -#include "ImageProcessingSystemComponent.h" -#include "ImageBuilderComponent.h" -#include "AtlasBuilder/AtlasBuilderComponent.h" - -namespace ImageProcessing -{ - class ImageProcessingModule - : public AZ::Module - { - public: - AZ_RTTI(ImageProcessingModule, "{A5392495-DD0E-4719-948A-B98DBAE88197}", AZ::Module); - - ImageProcessingModule() - : AZ::Module() - { - // Push results of the components' ::CreateDescriptor() into m_descriptors here. - m_descriptors.insert(m_descriptors.end(), { - ImageProcessingSystemComponent::CreateDescriptor(), //system component for editor - BuilderPluginComponent::CreateDescriptor(), //builder component for AP - TextureAtlasBuilder::AtlasBuilderComponent::CreateDescriptor(), //builder component for texture atlas - }); - } - - /** - * Add required SystemComponents to the SystemEntity. - */ - AZ::ComponentTypeList GetRequiredSystemComponents() const override - { - return AZ::ComponentTypeList{ - azrtti_typeid(), - }; - } - }; -} - -// 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_ImageProcessing, ImageProcessing::ImageProcessingModule) diff --git a/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.cpp b/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.cpp deleted file mode 100644 index 6629dc592a..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "ImageProcessingSystemComponent.h" -#include -#include - -namespace ImageProcessing -{ - void ImageProcessingSystemComponent::Reflect(AZ::ReflectContext* context) - { - if (auto serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0) - ; - } - } - - void ImageProcessingSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC("ImageBuilderService", 0x43c4be37)); - } - - void ImageProcessingSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC("ImageBuilderService", 0x43c4be37)); - } - - void ImageProcessingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - (void)required; - } - - void ImageProcessingSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) - { - (void)dependent; - } - - void ImageProcessingSystemComponent::Init() - { - - } - - void ImageProcessingSystemComponent::Activate() - { - // Call to allocate BuilderSettingManager - BuilderSettingManager::CreateInstance(); - - ImageProcessingEditor::ImageProcessingEditorRequestBus::Handler::BusConnect(); - AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); - AzToolsFramework::AssetBrowser::AssetBrowserTexturePreviewRequestsBus::Handler::BusConnect(); - ImageProcessingRequestBus::Handler::BusConnect(); - } - - void ImageProcessingSystemComponent::Deactivate() - { - ImageProcessingRequestBus::Handler::BusDisconnect(); - ImageProcessingEditor::ImageProcessingEditorRequestBus::Handler::BusDisconnect(); - AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); - AzToolsFramework::AssetBrowser::AssetBrowserTexturePreviewRequestsBus::Handler::BusDisconnect(); - - // Deallocate BuilderSettingManager - BuilderSettingManager::DestroyInstance(); - CPixelFormats::DestroyInstance(); - } - - void ImageProcessingSystemComponent::OpenSourceTextureFile(const AZ::Uuid& textureSourceID) - { - if (textureSourceID.IsNull()) - { - QMessageBox::warning(QApplication::activeWindow(), "Warning", - "Texture source does not have a unique ID. This can occur if the source asset has not yet been processed by the Asset Processor.", - QMessageBox::Ok); - } - else - { - ImageProcessingEditor::TexturePropertyEditor editor(textureSourceID, QApplication::activeWindow()); - if (!editor.HasValidImage()) - { - QMessageBox::warning(QApplication::activeWindow(), "Warning", "Invalid texture file", QMessageBox::Ok); - return; - } - editor.exec(); - } - } - - IImageObjectPtr ImageProcessingSystemComponent::LoadImage(const AZStd::string& filePath) - { - return IImageObjectPtr(LoadImageFromFile(filePath)); - } - - IImageObjectPtr ImageProcessingSystemComponent::LoadImagePreview(const AZStd::string& filePath) - { - IImageObjectPtr image(LoadImageFromFile(filePath)); - if (image) - { - ImageToProcess imageToProcess(image); - imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); - return imageToProcess.Get(); - } - return image; - } - - void ImageProcessingSystemComponent::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) - { - if (HandlesSource(fullSourceFileName)) - { - openers.push_back( - { - "Image_Processing_Editor", - "Edit Image Settings...", - QIcon(), - [&](const char* fullSourceFileNameInCallback, const AZ::Uuid& sourceUUID) - { - AZ_UNUSED(fullSourceFileNameInCallback); - - if (!LoadTextureSettings()) - { - return; - } - - ImageProcessingEditor::ImageProcessingEditorRequestBus::Broadcast(&ImageProcessingEditor::ImageProcessingEditorRequests::OpenSourceTextureFile, sourceUUID); - } - }); - } - } - - bool ImageProcessingSystemComponent::HandlesSource(AZStd::string_view fileName) const - { - for (int i = 0; i < s_TotalSupportedImageExtensions; i ++ ) - { - if (AZStd::wildcard_match(s_SupportedImageExtensions[i], fileName.data())) - { - return true; - } - } - - return false; - } - - bool ImageProcessingSystemComponent::GetProductTexturePreview(const char* fullProductFileName, QImage& previewImage, AZStd::string& productInfo, AZStd::string& productAlphaInfo) - { - return ImagePreview::GetProductTexturePreview(fullProductFileName, previewImage, productInfo, productAlphaInfo); - } - - bool ImageProcessingSystemComponent::LoadTextureSettings() - { - if (m_textureSettingsLoaded) - { - return true; - } - - // Load the preset settings before opening the editor - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(); - if (outcome.IsSuccess()) - { - m_textureSettingsLoaded = true; - return true; - } - - AZ_Error("Image Processing", false, "Failed to load default preset settings!"); - return false; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.h b/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.h deleted file mode 100644 index 3d6f03b295..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageProcessingSystemComponent.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace ImageProcessing -{ - class ImageProcessingSystemComponent - : public AZ::Component - , protected ImageProcessingRequestBus::Handler - , protected ImageProcessingEditor::ImageProcessingEditorRequestBus::Handler - , protected AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler - , protected AzToolsFramework::AssetBrowser::AssetBrowserTexturePreviewRequestsBus::Handler - { - public: - AZ_COMPONENT(ImageProcessingSystemComponent, "{13B1EB88-316F-4D44-B59C-886F023A5A58}"); - - 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: - //////////////////////////////////////////////////////////////////////// - // ImageProcessingEditorRequestBus interface implementation - void OpenSourceTextureFile(const AZ::Uuid& textureSourceID) override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // ImageProcessingRequestBus interface implementation - IImageObjectPtr LoadImage(const AZStd::string& filePath) override; - IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Init() override; - void Activate() override; - void Deactivate() override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationsBus::Handler - void AddSourceFileOpeners(const char* fullSourceFileName, const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AzToolsFramework::AssetBrowser::AssetBrowserTexturePreviewRequestsBus::Handler - bool GetProductTexturePreview(const char* fullProductFileName, QImage& previewImage, AZStd::string& productInfo, AZStd::string& productAlphaInfo) override; - //////////////////////////////////////////////////////////////////////// - - private: - bool HandlesSource(AZStd::string_view fileName) const; - - bool LoadTextureSettings(); - - bool m_textureSettingsLoaded = false; - }; -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.cpp b/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.cpp deleted file mode 100644 index cb97685105..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" diff --git a/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.h b/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.h deleted file mode 100644 index 2972414a1f..0000000000 --- a/Gems/ImageProcessing/Code/Source/ImageProcessing_precompiled.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -///////////////////////////////////////////////////////////////////////////// -// Qt -///////////////////////////////////////////////////////////////////////////// -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////// -// AZCore -///////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////// -//Type definitions -///////////////////////////////////////////////////////////////////////////// -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Android.h b/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Android.h deleted file mode 100644 index ab7622478b..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Android.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#define AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER j1 -#define AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM "pc" -#define AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS 0 -#define AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT 0 -#define AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL 0 -#define AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH 1 -#define AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX 0 diff --git a/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Platform.h b/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Platform.h deleted file mode 100644 index db38b9f980..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Android/ImageProcessing_Traits_Platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android.cmake b/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android_files.cmake b/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android_files.cmake deleted file mode 100644 index fd81e56d8d..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Android/platform_android_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ImageProcessing_Traits_Platform.h - ImageProcessing_Traits_Android.h -) diff --git a/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Linux.h b/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Linux.h deleted file mode 100644 index f1186391ad..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Linux.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#define AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER j1 -#define AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM "pc" -#define AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS 0 -#define AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT 0 -#define AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL 1 -#define AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH 0 -#define AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX 0 diff --git a/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Platform.h b/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Platform.h deleted file mode 100644 index 4131e01743..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Linux/ImageProcessing_Traits_Platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux.cmake b/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux_files.cmake b/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux_files.cmake deleted file mode 100644 index 5f1d5dfd84..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Linux/platform_linux_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ImageProcessing_Traits_Platform.h - ImageProcessing_Traits_Linux.h -) diff --git a/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Mac.h b/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Mac.h deleted file mode 100644 index b2e35a528d..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Mac.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#define AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER j1 -#define AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM "osx_gl" -#define AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS 1 -#define AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT 0 -#define AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL 1 -#define AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH 0 -#define AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX 1 diff --git a/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Platform.h b/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Platform.h deleted file mode 100644 index bc9d313e91..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Mac/ImageProcessing_Traits_Platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac.cmake b/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# diff --git a/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac_files.cmake b/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac_files.cmake deleted file mode 100644 index a25ce357a8..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Mac/platform_mac_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ImageProcessing_Traits_Platform.h - ImageProcessing_Traits_Mac.h -) diff --git a/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Platform.h b/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Platform.h deleted file mode 100644 index d2a32135c3..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Windows.h b/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Windows.h deleted file mode 100644 index 0410a31986..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Windows/ImageProcessing_Traits_Windows.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#define AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER _j1 -#define AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM "pc" -#define AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS 0 -#define AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT 1 -#define AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL 0 -#define AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH 0 -#define AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX 0 diff --git a/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows.cmake b/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows_files.cmake b/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows_files.cmake deleted file mode 100644 index eabc30e929..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/Windows/platform_windows_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ImageProcessing_Traits_Platform.h - ImageProcessing_Traits_Windows.h -) diff --git a/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_Platform.h b/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_Platform.h deleted file mode 100644 index 4ecfd207ca..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_Platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#include diff --git a/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_iOS.h b/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_iOS.h deleted file mode 100644 index 55b1be4d77..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/iOS/ImageProcessing_Traits_iOS.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once - -#define AZ_TRAIT_IMAGEPROCESSING_BESSEL_FUNCTION_FIRST_ORDER j1 -#define AZ_TRAIT_IMAGEPROCESSING_DEFAULT_PLATFORM "osx_gl" -#define AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS 1 -#define AZ_TRAIT_IMAGEPROCESSING_PVRTEXLIB_USE_WINDLL_IMPORT 0 -#define AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL 1 -#define AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH 1 -#define AZ_TRAIT_IMAGEPROCESSING_USE_BASE10_BYTE_PREFIX 1 diff --git a/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios.cmake b/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios_files.cmake b/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios_files.cmake deleted file mode 100644 index 12d59f3933..0000000000 --- a/Gems/ImageProcessing/Code/Source/Platform/iOS/platform_ios_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ImageProcessing_Traits_Platform.h - ImageProcessing_Traits_iOS.h -) diff --git a/Gems/ImageProcessing/Code/Source/Processing/DDSHeader.h b/Gems/ImageProcessing/Code/Source/Processing/DDSHeader.h deleted file mode 100644 index 9fd0827e21..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/DDSHeader.h +++ /dev/null @@ -1,230 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once -#include -#include -#include - -//! The following defines and constants are extracted from ImageExtensionHelper.h -//! Please make sure they are always synced with ImageExtensionHelper.h - -#define IMAGE_BUIDER_MAKEFOURCC(ch0, ch1, ch2, ch3) \ - ((AZ::u32)(AZ::u8)(ch0) | ((AZ::u32)(AZ::u8)(ch1) << 8) | \ - ((AZ::u32)(AZ::u8)(ch2) << 16) | ((AZ::u32)(AZ::u8)(ch3) << 24)) - -// This header defines constants and structures that are useful when parsing -// DDS files. DDS files were originally designed to use several structures -// and constants that are native to DirectDraw and are defined in ddraw.h, -// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar -// (compatible) constants and structures so that one can use DDS files -// without needing to include ddraw.h. - - -//Needed to write out DDS files on Mac -#if AZ_TRAIT_IMAGEPROCESSING_DEFINE_DIRECT3D_CONSTANTS -#define DDPF_ALPHAPIXELS 0x00000001 // Texture contains alpha data -#define DDPF_ALPHA 0x00000002 // For alpha channel only uncompressed data -#define DDPF_FOURCC 0x00000004 // Texture contains compressed RGB data -#define DDPF_RGB 0x00000040 // Texture contains uncompressed RGB data -#define DDPF_YUV 0x00000200 // For YUV uncompressed data -#define DDPF_LUMINANCE 0x00020000 // For single channel color uncompressed data - -#define DDSCAPS_COMPLEX 0x00000008 // Must be used on any file that contains more than one surface -#define DDSCAPS_MIPMAP 0x00400000 // Should be used for a mipmap -#define DDSCAPS_TEXTURE 0x00001000 // Required -#endif - -#define DDS_FOURCC 0x00000004 // DDPF_FOURCC -#define DDS_RGB 0x00000040 // DDPF_RGB -#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE -#define DDS_SIGNED 0x00080000 // DDPF_SIGNED -#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS -#define DDS_LUMINANCEA 0x00020001 // DDS_LUMINANCE | DDPF_ALPHAPIXELS -#define DDS_A 0x00000001 // DDPF_ALPHAPIXELS -#define DDS_A_ONLY 0x00000002 // DDPF_ALPHA - -#define DDS_FOURCC_A16B16G16R16 0x00000024 // FOURCC A16B16G16R16 -#define DDS_FOURCC_V16U16 0x00000040 // FOURCC V16U16 -#define DDS_FOURCC_Q16W16V16U16 0x0000006E // FOURCC Q16W16V16U16 -#define DDS_FOURCC_R16F 0x0000006F // FOURCC R16F -#define DDS_FOURCC_G16R16F 0x00000070 // FOURCC G16R16F -#define DDS_FOURCC_A16B16G16R16F 0x00000071 // FOURCC A16B16G16R16F -#define DDS_FOURCC_R32F 0x00000072 // FOURCC R32F -#define DDS_FOURCC_G32R32F 0x00000073 // FOURCC G32R32F -#define DDS_FOURCC_A32B32G32R32F 0x00000074 // FOURCC A32B32G32R32F - -#define DDSD_CAPS 0x00000001l // default -#define DDSD_PIXELFORMAT 0x00001000l -#define DDSD_WIDTH 0x00000004l -#define DDSD_HEIGHT 0x00000002l -#define DDSD_LINEARSIZE 0x00080000l - -#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT -#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT -#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH -#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH -#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE - -#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE -#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP -#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX - -#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX -#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX -#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY -#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY -#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ -#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ - -#define DDS_CUBEMAP_ALLFACES (DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX | \ - DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY | \ - DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ) - -#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME - -#define DDS_RESF1_NORMALMAP 0x01000000 -#define DDS_RESF1_DSDT 0x02000000 - - -namespace ImageProcessing -{ - const static AZ::u32 FOURCC_DX10 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', '1', '0'); - const static AZ::u32 FOURCC_DDS = IMAGE_BUIDER_MAKEFOURCC('D', 'D', 'S', ' '); - const static AZ::u32 FOURCC_FYRC = IMAGE_BUIDER_MAKEFOURCC('F', 'Y', 'R', 'C'); - - //The values of each elements in this enum should be same as ITexture ETEX_TileMode enum. - enum DDS_TileMode : AZ::u8 - { - eTM_None = 0, - eTM_LinearPadded, - eTM_Optimal, - }; - - struct DDS_PIXELFORMAT - { - AZ::u32 dwSize; - AZ::u32 dwFlags; - AZ::u32 dwFourCC; - AZ::u32 dwRGBBitCount; - AZ::u32 dwRBitMask; - AZ::u32 dwGBitMask; - AZ::u32 dwBBitMask; - AZ::u32 dwABitMask; - - const bool operator == (const DDS_PIXELFORMAT& fmt) const - { - return dwFourCC == fmt.dwFourCC && - dwFlags == fmt.dwFlags && - dwRGBBitCount == fmt.dwRGBBitCount && - dwRBitMask == fmt.dwRBitMask && - dwGBitMask == fmt.dwGBitMask && - dwBBitMask == fmt.dwBBitMask && - dwABitMask == fmt.dwABitMask && - dwSize == fmt.dwSize; - } - - }; - - struct DDS_HEADER_DXT10 - { - // we're unable to use native enums, so we use AZ::u32 instead. - AZ::u32 /*DXGI_FORMAT*/ dxgiFormat; - AZ::u32 /*D3D10_RESOURCE_DIMENSION*/ resourceDimension; - AZ::u32 miscFlag; - AZ::u32 arraySize; - AZ::u32 reserved; - }; - - struct DDS_HEADER - { - AZ::u32 dwSize; - AZ::u32 dwHeaderFlags; - AZ::u32 dwHeight; - AZ::u32 dwWidth; - AZ::u32 dwPitchOrLinearSize; - AZ::u32 dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags - AZ::u32 dwMipMapCount; - AZ::u32 dwAlphaBitDepth; - AZ::u32 dwReserved1; // Crytek image flags - float fAvgBrightness; // Average top mip brightness. Could be f16/half - float cMinColor[4]; - float cMaxColor[4]; - DDS_PIXELFORMAT ddspf; - AZ::u32 dwSurfaceFlags; - AZ::u32 dwCubemapFlags; - AZ::u8 bNumPersistentMips; - AZ::u8 tileMode; //DDS_TileMode - AZ::u8 bReserved2[6]; - AZ::u32 dwTextureStage; - - - inline const bool IsValid() const { return sizeof(*this) == dwSize; } - inline const bool IsDX10Ext() const { return ddspf.dwFourCC == FOURCC_DX10; } - inline const AZ::u32 GetMipCount() const { return AZStd::GetMax(1u, (AZ::u32)dwMipMapCount); } - - inline const size_t GetFullHeaderSize() const - { - if (IsDX10Ext()) - { - return sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); - } - - return sizeof(DDS_HEADER); - } - }; - - // standard description of file header - struct DDS_FILE_DESC - { - AZ::u32 dwMagic; - DDS_HEADER header; - - inline const bool IsValid() const { return dwMagic == FOURCC_DDS && header.IsValid(); } - inline const size_t GetFullHeaderSize() const { return sizeof(dwMagic) + header.GetFullHeaderSize(); } - }; - - // chunk identifier - const static AZ::u32 FOURCC_CExt = IMAGE_BUIDER_MAKEFOURCC('C', 'E', 'x', 't'); // Crytek extension start - const static AZ::u32 FOURCC_CEnd = IMAGE_BUIDER_MAKEFOURCC('C', 'E', 'n', 'd'); // Crytek extension end - const static AZ::u32 FOURCC_AttC = IMAGE_BUIDER_MAKEFOURCC('A', 't', 't', 'C'); // Chunk Attached Channel - - //Fourcc for pixel formats which aren't supported by dx10, such as astc formats, etc formats, pvrtc formats - //They are used for dwFourCC of dds header's DDS_PIXELFORMAT to identify non-dx10 pixel formats - const static AZ::u32 FOURCC_EAC_R11 = IMAGE_BUIDER_MAKEFOURCC('E', 'A', 'R', ' '); - const static AZ::u32 FOURCC_EAC_RG11 = IMAGE_BUIDER_MAKEFOURCC('E', 'A', 'R', 'G'); - const static AZ::u32 FOURCC_ETC2 = IMAGE_BUIDER_MAKEFOURCC('E', 'T', '2', ' '); - const static AZ::u32 FOURCC_ETC2A = IMAGE_BUIDER_MAKEFOURCC('E', 'T', '2', 'A'); - const static AZ::u32 FOURCC_PVRTC2 = IMAGE_BUIDER_MAKEFOURCC('P', 'V', 'R', '2'); - const static AZ::u32 FOURCC_PVRTC4 = IMAGE_BUIDER_MAKEFOURCC('P', 'V', 'R', '4'); - const static AZ::u32 FOURCC_ASTC_4x4 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '4', '4'); - const static AZ::u32 FOURCC_ASTC_5x4 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '5', '4'); - const static AZ::u32 FOURCC_ASTC_5x5 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '5', '5'); - const static AZ::u32 FOURCC_ASTC_6x5 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '6', '5'); - const static AZ::u32 FOURCC_ASTC_6x6 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '6', '6'); - const static AZ::u32 FOURCC_ASTC_8x5 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '8', '5'); - const static AZ::u32 FOURCC_ASTC_8x6 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '8', '6'); - const static AZ::u32 FOURCC_ASTC_10x5 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'A', '5'); - const static AZ::u32 FOURCC_ASTC_10x6 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'A', '6'); - const static AZ::u32 FOURCC_ASTC_8x8 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '8', '8'); - const static AZ::u32 FOURCC_ASTC_10x8 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'A', '8'); - const static AZ::u32 FOURCC_ASTC_10x10 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'A', 'A'); - const static AZ::u32 FOURCC_ASTC_12x10 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'C', 'A'); - const static AZ::u32 FOURCC_ASTC_12x12 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'C', 'C'); - - //legacy formats names. they are only used for load rc.exe's dds formats - const static AZ::u32 FOURCC_DXT1 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '1'); - const static AZ::u32 FOURCC_DXT3 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '3'); - const static AZ::u32 FOURCC_DXT5 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '5'); - const static AZ::u32 FOURCC_3DCP = IMAGE_BUIDER_MAKEFOURCC('A', 'T', 'I', '1'); - const static AZ::u32 FOURCC_3DC = IMAGE_BUIDER_MAKEFOURCC('A', 'T', 'I', '2'); -} diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.cpp b/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.cpp deleted file mode 100644 index b5fc329a03..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.cpp +++ /dev/null @@ -1,1014 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -//qt has convenience functions to handle file -#include -#include - -//for texture splitting -//mininum number of low level mips will be saved in the base file. -#define MinPersistantMips 3 -//mininum texture size to be splitted. A texture will only be split when the size is larger than this number -#define MinSizeToSplit 1<<5 - -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) - #if defined(TOOLS_SUPPORT_JASPER) - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageProcess, Jasper) - #endif - #if defined(TOOLS_SUPPORT_PROVO) - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageProcess, Provo) - #endif - #if defined(TOOLS_SUPPORT_SALEM) - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageProcess, Salem) - #endif -#endif - -namespace ImageProcessing -{ - - IImageObjectPtr ImageConvertProcess::GetOutputImage() - { - if (m_image) - { - return m_image->Get(); - } - return nullptr; - } - - IImageObjectPtr ImageConvertProcess::GetOutputAlphaImage() - { - return m_alphaImage; - } - - IImageObjectPtr ImageConvertProcess::GetOutputDiffCubemap() - { - return m_diffCubemapImage; - } - - void ImageConvertProcess::GetAppendOutputFilePaths(AZStd::vector& outPaths) - { - for (const auto& path : m_productFilepaths) - { - outPaths.push_back(path); - } - } - - ImageConvertProcess::ImageConvertProcess(const IImageObjectPtr inputImage, const TextureSettings& textureSetting, - const PresetSettings& presetSetting, bool isPreview, bool isStreaming, bool canOverridePreset, - const AZStd::string& outputPath, const AZStd::string& platformId) : - m_inputImage(inputImage), - m_textureSetting(textureSetting), - m_presetSetting(presetSetting), - m_canOverridePreset(canOverridePreset), - m_image(nullptr), - m_isPreview(isPreview), - m_outputPath(outputPath), - m_progressStep(0), - m_isFinished(false), - m_isSucceed(false), - m_processTime(0), - m_isStreaming(isStreaming), - m_platformId(platformId) - { - } - - ImageConvertProcess::~ImageConvertProcess() - { - delete m_image; - } - - bool ImageConvertProcess::IsConvertToCubemap() - { - return m_presetSetting.m_cubemapSetting != nullptr; - } - - void ImageConvertProcess::UpdateProcess() - { - if (m_isFinished) - { - return; - } - - switch (m_progressStep) - { - case StepValidateInput: - //validate - if (!ValidateInput()) - { - m_isSucceed = false; - break; - } - - //set start time - m_startTime = AZStd::GetTimeUTCMilliSecond(); - - //identify the alpha content of input image if gloss from normal wasn't set - m_alphaContent = m_inputImage->GetAlphaContent(); - - //create image for process - m_image = new ImageToProcess(IImageObjectPtr(m_inputImage->Clone())); - - break; - case StepGenerateColorChart: - //GenerateColorChart. - if (m_presetSetting.m_isColorChart) - { - m_image->CreateColorChart(); - } - break; - case StepConvertToLinear: - //convert to linear space and the output image pixel format should be rgba32f - ConvertToLinear(); - break; - case StepSwizzle: - //convert texture format. - if (m_presetSetting.m_swizzle.size() >= 4) - { - m_image->Get()->Swizzle(m_presetSetting.m_swizzle.substr(0, 4).c_str()); - m_alphaContent = m_image->Get()->GetAlphaContent(); - } - - //convert gloss map (alhpa channel) from legacy distribution to new one - if (m_presetSetting.m_isLegacyGloss) - { - m_image->Get()->ConvertLegacyGloss(); - } - break; - case StepOverridePreset: - if (m_canOverridePreset) - { - // Set the pixel format to BC3 if the source contains greyscale alpha and BC1 if it does not. - if (m_presetSetting.m_pixelFormat == ePixelFormat_BC1 - || m_presetSetting.m_pixelFormat == ePixelFormat_BC1a - || m_presetSetting.m_pixelFormat == ePixelFormat_BC3) - { - if (m_alphaContent == EAlphaContent::eAlphaContent_Greyscale) - { - m_presetSetting.m_pixelFormat = ePixelFormat_BC3; - } - else if (m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlack - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyWhite) - { - m_presetSetting.m_pixelFormat = ePixelFormat_BC1a; - } - else - { - m_presetSetting.m_pixelFormat = ePixelFormat_BC1; - } - } - } - break; - case StepCubemapLayout: - //convert cubemap image's layout to vertical strip used in game. - if (IsConvertToCubemap()) - { - if (!m_image->ConvertCubemapLayout(CubemapLayoutVertical)) - { - m_image->Set(nullptr); - } - } - break; - case StepPreNormalize: - //normalize base image before mipmap generation if glossfromnormals is enabled and require normalize - if (m_presetSetting.m_isMipRenormalize && m_presetSetting.m_glossFromNormals) - { - // Normalize the base mip map. This has to be done explicitly because we need to disable mip renormalization to - // preserve the normal length when deriving the normal variance - m_image->Get()->NormalizeVectors(0, 1); - } - break; - case StepDiffCubemap: - //create diffuse cubemap. We need to have better way to handle one input multiple export settings later. - CreateDiffuseCubemap(); - break; - case StepMipmap: - //generate mipmaps - if (IsConvertToCubemap()) - { - FillCubemapMipmaps(); - } - else - { - FillMipmaps(); - } - //add image flag - if (m_presetSetting.m_suppressEngineReduce || m_textureSetting.m_suppressEngineReduce) - { - m_image->Get()->AddImageFlags(EIF_SupressEngineReduce); - } - break; - case StepGlossFromNormal: - //get gloss from normal for all mipmaps and save to alpha channel - if (m_presetSetting.m_glossFromNormals) - { - bool hasAlpha = (m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlack - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite - || m_alphaContent == EAlphaContent::eAlphaContent_Greyscale); - - m_image->Get()->GlossFromNormals(hasAlpha); - //set alpha content so it won't be ignored later. - m_alphaContent = EAlphaContent::eAlphaContent_Greyscale; - } - break; - case StepPostNormalize: - //normalize all the other mipmaps - if (!IsConvertToCubemap() && m_presetSetting.m_isMipRenormalize) - { - if (m_presetSetting.m_glossFromNormals) - { - //normalize other mips except first mip - m_image->Get()->NormalizeVectors(1, 100); - } - else - { - //normalize all mips - m_image->Get()->NormalizeVectors(0, 100); - } - - m_image->Get()->AddImageFlags(EIF_RenormalizedTexture); - } - break; - case StepCreateHighPass: - if (m_presetSetting.m_highPassMip > 0) - { - m_image->CreateHighPass(m_presetSetting.m_highPassMip); - } - break; - case StepConvertOutputColorSpace: - //comvert image from linear space to desired output color space - ConvertToOuputColorSpace(); - break; - case StepAlphaImage: - //save alpha channel to separate image if it's needed - CreateAlphaImage(); - break; - case StepConvertPixelFormat: - //convert pixel format - ConvertPixelformat(); - break; - case StepSaveToFile: - //save to file - if (!m_isPreview) - { - m_isSucceed = SaveOutput(); - } - else - { - m_isSucceed = true; - } - break; - } - - m_progressStep++; - - if (m_image == nullptr || m_image->Get() == nullptr || m_progressStep >= StepAll) - { - m_isFinished = true; - AZStd::sys_time_t endTime = AZStd::GetTimeUTCMilliSecond(); - m_processTime = aznumeric_cast((endTime - m_startTime) / 1000); - } - - //output conversion log - if (m_isSucceed && m_isFinished) - { - const uint32 sizeTotal = m_image->Get()->GetTextureMemory(); - if (m_isPreview) - { - AZ_TracePrintf("Image Processing", "Image ( %d bytes) converted in %f seconds\n", sizeTotal, m_processTime); - } - else - { - AZ_TracePrintf("Image Processing", "Image converted and saved to %s ( %d bytes) with %f seconds\n", m_outputPath.c_str(), - sizeTotal, m_processTime); - } - } - } - - void ImageConvertProcess::ProcessAll() - { - while (!m_isFinished) - { - UpdateProcess(); - } - } - - float ImageConvertProcess::GetProgress() - { - return m_progressStep / (float)StepAll; - } - - bool ImageConvertProcess::IsFinished() - { - return m_isFinished; - } - - bool ImageConvertProcess::IsSucceed() - { - return m_isSucceed; - } - - //function to get desired output image extent - void GetOutputExtent(AZ::u32 inputWidth, AZ::u32 inputHeight, AZ::u32& outWidth, AZ::u32& outHeight, AZ::u32& outReduce, - const TextureSettings* textureSettings, const PresetSettings* presetSettings) - { - outWidth = inputWidth; - outHeight = inputHeight; - outReduce = 0; - - if (textureSettings == nullptr || presetSettings == nullptr) - { - return; - } - - //don't do any reduce for color chart - if (presetSettings->m_isColorChart) - { - return; - } - - //get suitable size for dest pixel format - CPixelFormats::GetInstance().GetSuitableImageSize(presetSettings->m_pixelFormat, inputWidth, inputHeight, - outWidth, outHeight); - - //desired reduce level. 1 means reduce one level - uint sizeReduceLevel = textureSettings->m_sizeReduceLevel; - - outReduce = 0; - - //reduce to not exceed max texture size - if (presetSettings->m_maxTextureSize > 0) - { - while (outWidth > presetSettings->m_maxTextureSize || outHeight > presetSettings->m_maxTextureSize) - { - outWidth >>= 1; - outHeight >>= 1; - outReduce++; - } - } - - //if it requires to reduce more and the result size will still larger than min texture size, then reduce - while (outReduce < sizeReduceLevel && - (outWidth >= presetSettings->m_minTextureSize * 2 && outHeight >= presetSettings->m_minTextureSize * 2)) - { - outWidth >>= 1; - outHeight >>= 1; - outReduce++; - } - } - - bool ImageConvertProcess::ConvertToLinear() - { - //de-gamma only if the input is sRGB. this will convert other uncompressed format to RGBA32F - return m_image->GammaToLinearRGBA32F(m_presetSetting.m_srcColorSpace == ColorSpace::sRGB); - } - - //mipmap generation - bool ImageConvertProcess::FillMipmaps() - { - //this function only works with pixel format rgba32f - const EPixelFormat srcPixelFormat = m_image->Get()->GetPixelFormat(); - if (srcPixelFormat != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "%s only works with pixel format rgba32f", __FUNCTION__); - return false; - } - - //only if the src image has one mip - if (m_image->Get()->GetMipCount() != 1) - { - AZ_Assert(false, "%s called for a mipmapped image. ", __FUNCTION__); - return false; - } - - //get output image size - uint32 outWidth; - uint32 outHeight; - uint32 outReduce = 0; - GetOutputExtent(m_image->Get()->GetWidth(0), m_image->Get()->GetHeight(0), outWidth, outHeight, outReduce, &m_textureSetting, - &m_presetSetting); - - //max mipmap count - uint32 mipCount = UINT32_MAX; - if (m_presetSetting.m_mipmapSetting == nullptr || !m_textureSetting.m_enableMipmap) - { - mipCount = 1; - } - - //create new new output image with proper side - IImageObjectPtr outImage(IImageObject::CreateImage(outWidth, outHeight, mipCount, ePixelFormat_R32G32B32A32F)); - - //filter setting for mip map generation - float blurH = 0; - float blurV = 0; - - //fill mipmap data for uncompressed output image - for (uint32 mip = 0; mip < outImage->GetMipCount(); mip++) - { - FilterImage(m_textureSetting.m_mipGenType, m_textureSetting.m_mipGenEval, blurH, blurV, m_image->Get(), 0, outImage, mip, nullptr, nullptr); - } - - //transfer alpha coverage - if (m_textureSetting.m_maintainAlphaCoverage) - { - outImage->TransferAlphaCoverage(&m_textureSetting, m_image->Get()); - } - - //set back to image - m_image->Set(outImage); - return true; - } - - void ImageConvertProcess::CreateAlphaImage() - { - //if alpha content doesn't have alpha or we need to discard alpha, skip - //we won't create alpha image for cubemap too - if (m_alphaContent == EAlphaContent::eAlphaContent_Absent - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyWhite - || m_presetSetting.m_discardAlpha || IsConvertToCubemap()) - { - return; - } - - //Ensure that the PixelFormatAlpha is set otherwise no need to create m_alphaImage - if (m_presetSetting.m_pixelFormatAlpha == ePixelFormat_Unknown) - { - return; - } - - //now create alpha image - ImageToProcess alphaImage(m_image->Get()); - alphaImage.ConvertFormat(ePixelFormat_A8); - - - if(CPixelFormats::GetInstance().IsFormatSingleChannel(m_presetSetting.m_pixelFormatAlpha)) - { - alphaImage.ConvertFormat(m_presetSetting.m_pixelFormatAlpha); - } - else - { - //For PVRTC compression we need to clear out the alpha to get accurate rgb compression. - if (IsPVRTCFormat(m_presetSetting.m_pixelFormat) || IsASTCFormat(m_presetSetting.m_pixelFormat)) - { - alphaImage.ConvertFormat(ePixelFormat_R8G8B8A8); - alphaImage.Get()->Swizzle("rgb1"); - alphaImage.ConvertFormat(m_presetSetting.m_pixelFormatAlpha); - } - else - { - AZ_Assert(false, "Did you apply the correct pixel format for PixelFormatAlpha?"); - } - } - - //get final result and save it to member variable for later use - m_alphaImage = alphaImage.Get(); - - m_image->Get()->AddImageFlags(EIF_AttachedAlpha); - } - - //pixel format convertions - bool ImageConvertProcess::ConvertPixelformat() - { - - //For PVRTC compression we need to clear out the alpha to get accurate rgb compression. - if(m_alphaImage && (IsPVRTCFormat(m_presetSetting.m_pixelFormat) || IsASTCFormat(m_presetSetting.m_pixelFormat))) - { - m_image->Get()->Swizzle("rgb1"); - } - - - //set up compress option - ICompressor::EQuality quality; - if (m_isPreview) - { - quality = ICompressor::eQuality_Preview; - } - else - { - quality = ICompressor::eQuality_Normal; - } - m_image->GetCompressOption().compressQuality = quality; - m_image->GetCompressOption().rgbWeight = m_presetSetting.GetColorWeight(); - m_image->ConvertFormat(m_presetSetting.m_pixelFormat); - return true; - } - - //convert color space from linear to sRGB space if it's neccessary - bool ImageConvertProcess::ConvertToOuputColorSpace() - { - if (m_presetSetting.m_destColorSpace == ColorSpace::sRGB) - { - m_image->LinearToGamma(); - } - else if (m_presetSetting.m_destColorSpace == ColorSpace::autoSelect) - { - //convert to sRGB color space if it's dark image (converting bright images decreases image quality) - bool bThresholded = false; - { - Histogram<256> histogram; - if (ComputeLuminanceHistogram(m_image->Get(), histogram)) - { - const size_t medianBinIndex = 116; - float percentage = histogram.getPercentage(medianBinIndex, 255); - - // The image has significant amount of dark pixels, it's good to use sRGB - bThresholded = (percentage < 50.0f); - } - } - - if (bThresholded) - { - bool convertToSRGB = true; - - // if the image is BC1 compressable, additionally estimate the conversion error - // to only convert if it doesn't introduce error - if (CPixelFormats::GetInstance().IsImageSizeValid(ePixelFormat_BC1, m_image->Get()->GetWidth(0), - m_image->Get()->GetHeight(0), false)) - { - //get image in RGB space - ImageToProcess imageProcess(m_image->Get()); - imageProcess.LinearToGamma(); - - ICompressor::CompressOption option; - option.compressQuality = ICompressor::eQuality_Preview; - option.rgbWeight = m_presetSetting.GetColorWeight(); - - float errorLinearBC1; - float errorSrgbBC1; - GetBC1CompressionErrors(m_image->Get(), errorLinearBC1, errorSrgbBC1, option); - - // Don't convert if it would lower the image quality when saved as sRGB according to GetDXT1GammaCompressionError() - if (errorSrgbBC1 >= errorLinearBC1) - { - convertToSRGB = false; - } - } - - // our final conclusion: if the texture had a significant percentage of dark pixels and, - // if applicable, it was BC1 compressable and gamma compression wouldn't introduce error, - // then we convert it to sRGB - if (convertToSRGB) - { - m_image->LinearToGamma(); - } - } - } - return true; - } - - bool ImageConvertProcess::ValidateInput() - { - //valid the input image and output settings here. - uint32 dwWidth, dwHeight; - dwWidth = m_inputImage->GetWidth(0); - dwHeight = m_inputImage->GetHeight(0); - - EPixelFormat dstFmt = m_presetSetting.m_pixelFormat; - - //check if whether input image can be a cubemap - if (m_presetSetting.m_cubemapSetting) - { - if (CubemapLayout::GetCubemapLayoutInfo(m_inputImage) == nullptr) - { - AZ_Error("Image Processing", false, "Invalid image size %dx%d using as cubemap. Requires power of two with 6x1, 1x6, 4x3 or 3x4 layouts", dwWidth, dwHeight); - return false; - } - } - else if (!CPixelFormats::GetInstance().IsImageSizeValid(dstFmt, dwWidth, dwHeight, false)) - { - AZ_Warning("Image Processing", false, "Image size will be scaled for pixel format %s", CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName); - } - -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - if (ImageProcess##PrivateName::DoesSupport(m_platformId))\ - {\ - if(!ImageProcess##PrivateName::IsPixelFormatSupported(m_presetSetting.m_pixelFormat))\ - {\ - AZ_Error("Image Processing", false, "Unsupported pixel format %s for %s",\ - CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName, m_platformId.c_str());\ - return false;\ - }\ - } - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif //AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS - - return true; - } - - bool ImageConvertProcess::SaveOutput() - { - //if the path wasn't specified, skip - if (m_outputPath.empty()) - { - AZ_Error("Image Processing", false, "No output path provided for saving"); - return false; - } - - //set all mips as presistent mips by default. it will be modified if the image is splitted later - m_image->Get()->SetNumPersistentMips(m_image->Get()->GetMipCount()); - - //split - if (m_isStreaming && m_presetSetting.m_numStreamableMips > 0) - { - IImageObjectPtr curImage = m_image->Get(); - - if (curImage->GetMipCount() > MinPersistantMips && (curImage->GetWidth(0) > MinSizeToSplit || - curImage->GetWidth(0) > MinSizeToSplit)) - { - //calculate final persistance mip count - AZ::u32 persistantMips = MinPersistantMips; - if (m_presetSetting.m_numStreamableMips < curImage->GetMipCount() - MinPersistantMips) - { - persistantMips = curImage->GetMipCount() - m_presetSetting.m_numStreamableMips; - } - curImage->SetNumPersistentMips(persistantMips); - curImage->AddImageFlags(EIF_Splitted); - - //add flags for alpha image too, assuming alpha image has same size as origin - if (m_alphaImage) - { - m_alphaImage->SetNumPersistentMips(persistantMips); - m_alphaImage->AddImageFlags(EIF_Splitted); - } - } - } - -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - if (ImageProcess##PrivateName::DoesSupport(m_platformId))\ - {\ - ImageProcess##PrivateName::PrepareImageForExport(m_image->Get());\ - ImageProcess##PrivateName::PrepareImageForExport(m_alphaImage);\ - } - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif //AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS - - AZStd::vector outputFilePaths; - if (!m_image->Get()->SaveImage(m_outputPath.c_str(), m_alphaImage, outputFilePaths)) - { - AZ_Error("Image Processing", false, "Save image to %s failed", m_outputPath.c_str()); - return false; - } - - for (auto& path : outputFilePaths) - { - m_productFilepaths.push_back(path); - } - return true; - } - - ImageConvertProcess* CreateImageConvertProcess(const AZStd::string& imageFilePath, const AZStd::string& exportDir - , const PlatformName& platformName, AZ::SerializeContext* context) - { - AZStd::string metafilePath; - BuilderSettingManager::Instance()->MetafilePathFromImagePath(imageFilePath, metafilePath); - TextureSettings textureSettings; - - MultiplatformTextureSettings multiTextureSetting; - bool canOverridePreset = false; - - multiTextureSetting = TextureSettings::GetMultiplatformTextureSetting(imageFilePath, canOverridePreset, context); - if (multiTextureSetting.empty()) - { - AZ_Error("Image Processing", false, "Could not determine export settings for image file [%s] due to previous error(s). Skipping export...", imageFilePath.c_str()); - return nullptr; - } - - if (multiTextureSetting.find(platformName) != multiTextureSetting.end()) - { - textureSettings = multiTextureSetting[platformName]; - } - else - { - PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform; - if (multiTextureSetting.find(defaultPlatform) != multiTextureSetting.end()) - { - textureSettings = multiTextureSetting[defaultPlatform]; - } - else - { - textureSettings = (*multiTextureSetting.begin()).second; - } - } - - //load image. Do it earlier so GetSuggestedPreset function could use the information of file to choose better preset - IImageObjectPtr srcImage(LoadImageFromFile(imageFilePath)); - if (srcImage == nullptr) - { - AZ_Error("Image Processing", false, "Load image file %s failed", imageFilePath.c_str()); - return nullptr; - } - - //if get textureSetting failed, use the default texture setting, and find suitable preset for this file - //in very rare user case, an old texture setting file may not have a preset. We fix it over here too. - if (textureSettings.m_preset.IsNull()) - { - textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath, srcImage); - } - - //get preset - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(textureSettings.m_preset, platformName); - - if (preset == nullptr) - { - AZStd::string uuidStr; - textureSettings.m_preset.ToString(uuidStr); - AZ_Assert(false, "%s cannot find image preset with ID %s.", imageFilePath.c_str(), uuidStr.c_str()); - return nullptr; - } - - //generate export file name - QDir dir(exportDir.c_str()); - if (!dir.exists()) - { - dir.mkpath("."); - } - AZStd::string fileName, outputPath; - AzFramework::StringFunc::Path::GetFileName(imageFilePath.c_str(), fileName); - fileName += ".dds"; - AzFramework::StringFunc::Path::Join(exportDir.c_str(), fileName.c_str(), outputPath, true, true); - - //if it need streaming - bool isStreaming = BuilderSettingManager::Instance()->GetBuilderSetting(platformName)->m_enableStreaming; - - //create convert process - ImageConvertProcess* process = new ImageConvertProcess(srcImage, textureSettings, *preset, false, isStreaming, - canOverridePreset, outputPath, platformName); - - return process; - } - - void ImageConvertProcess::CreateDiffuseCubemap() - { - //only need to convert if the diffuseGenPreset in cubemap setting is set - if (m_presetSetting.m_cubemapSetting == nullptr || m_presetSetting.m_cubemapSetting->m_diffuseGenPreset.IsNull()) - { - return; - } - - //need to create another ImageConvertProcess - //prepare preset setting and texture setting - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset( - m_presetSetting.m_cubemapSetting->m_diffuseGenPreset, m_platformId); - - TextureSettings textureSettings = m_textureSetting; - m_textureSetting.m_preset = m_presetSetting.m_cubemapSetting->m_diffuseGenPreset; - - if (preset == nullptr) - { - AZ_Error("Image Processing", false,"Couldn't find preset for diffuse cubemap generation"); - return; - } - - //generate export file name. add "_diff" in the end of file name - AZStd::string fileName, folderName, outProductPath; - AzFramework::StringFunc::Path::GetFileName(m_outputPath.c_str(), fileName); - AzFramework::StringFunc::Path::GetFullPath(m_outputPath.c_str(), folderName); - fileName += "_diff.dds"; - AzFramework::StringFunc::Path::Join(folderName.c_str(), fileName.c_str(), outProductPath, true, true); - - //create convert process - //we might be able to use current image result for the input to save some performance. But it's more safe to use input image - bool canOverridePreset = false; - ImageConvertProcess* process = new ImageConvertProcess(m_inputImage, textureSettings, *preset, - false, m_isStreaming, canOverridePreset, outProductPath, m_platformId); - if (process) - { - process->ProcessAll(); - if (process->IsSucceed()) - { - process->GetAppendOutputFilePaths(m_productFilepaths); - m_diffCubemapImage = process->m_image->Get(); - } - else - { - AZ_Error("Image Processing", false, "Convert diffuse cubemap failed"); - } - delete process; - } - else - { - AZ_Error("Image Processing", false, "Create convert process for diffuse cubemap failed"); - } - } - - bool ConvertImageFile(const AZStd::string& imageFilePath, const AZStd::string& exportDir, - AZStd::vector& outPaths, const PlatformName& platformName, AZ::SerializeContext* context) - { - bool result = false; - ImageConvertProcess* process = CreateImageConvertProcess(imageFilePath, exportDir, platformName, context); - if (process) - { - process->ProcessAll(); - result = process->IsSucceed(); - if (result) - { - process->GetAppendOutputFilePaths(outPaths); - } - delete process; - } - return result; - } - - IImageObjectPtr MergeOutputImageForPreview(IImageObjectPtr image, IImageObjectPtr alphaImage) - { - if (!image) - { - return IImageObjectPtr(); - } - - ImageToProcess imageToProcess(image); - imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); - IImageObjectPtr previewImage = imageToProcess.Get(); - - // If there is separate Alpha image, combine it with output - if (alphaImage) - { - // Create pixel operation function for rgb and alpha images - IPixelOperationPtr imageOp = CreatePixelOperation(ePixelFormat_R8G8B8A8); - IPixelOperationPtr alphaOp = CreatePixelOperation(ePixelFormat_A8); - - // Convert the alpha image to A8 first - ImageToProcess imageToProcess2(alphaImage); - imageToProcess2.ConvertFormat(ePixelFormat_A8); - IImageObjectPtr previewImageAlpha = imageToProcess2.Get(); - - const uint32 imageMips = previewImage->GetMipCount(); - const uint32 alphaMips = previewImageAlpha->GetMipCount(); - - // Get count of bytes per pixel for both rgb and alpha images - uint32 imagePixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat_R8G8B8A8)->bitsPerBlock / 8; - uint32 alphaPixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat_A8)->bitsPerBlock / 8; - - AZ_Assert(imageMips <= alphaMips, "Mip level of alpha image is less than origin image!"); - - // For each mip level, set the alpha value to the image - for (uint32 mipLevel = 0; mipLevel < imageMips; ++mipLevel) - { - const uint32 pixelCount = previewImage->GetPixelCount(mipLevel); - const uint32 alphaPixelCount = previewImageAlpha->GetPixelCount(mipLevel); - - AZ_Assert(pixelCount == alphaPixelCount, "Pixel count for image and alpha image at mip level %d is not equal!", mipLevel); - - uint8* imageBuf; - uint32 pitch; - previewImage->GetImagePointer(mipLevel, imageBuf, pitch); - - uint8* alphaBuf; - uint32 alphaPitch; - previewImageAlpha->GetImagePointer(mipLevel, alphaBuf, alphaPitch); - - float rAlpha, gAlpha, bAlpha, aAlpha, rImage, gImage, bImage, aImage; - - for (uint32 i = 0; i < pixelCount; ++i, imageBuf += imagePixelBytes, alphaBuf += alphaPixelBytes) - { - alphaOp->GetRGBA(alphaBuf, rAlpha, gAlpha, bAlpha, aAlpha); - imageOp->GetRGBA(imageBuf, rImage, gImage, bImage, aImage); - imageOp->SetRGBA(imageBuf, rImage, gImage, bImage, aAlpha); - } - } - } - - return previewImage; - } - - // This function will convert compressed image to RGBA32. - // Also if the image is in sRGB space will convert it to Linear space. - IImageObjectPtr GetUncompressedLinearImage(IImageObjectPtr ddsImage) - { - if (ddsImage) - { - ImageToProcess processImage(ddsImage); - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(ddsImage->GetPixelFormat())) - { - processImage.ConvertFormat(ePixelFormat_R32G32B32A32F); - } - if (ddsImage->HasImageFlags(EIF_SRGBRead)) - { - processImage.GammaToLinearRGBA32F(true); - } - return processImage.Get(); - } - return nullptr; - } - - float GetErrorBetweenImages(IImageObjectPtr inputImage1, IImageObjectPtr inputImage2) - { - // First make sure images are in uncompressed format and linear space - // Convert them if necessary - IImageObjectPtr image1 = GetUncompressedLinearImage(inputImage1); - IImageObjectPtr image2 = GetUncompressedLinearImage(inputImage2); - - const float errorValue = FLT_MAX; - - if (!image1 || !image2) - { - AZ_Warning("Image Processing", false, "Invalid images passed into %s function", __FUNCTION__); - return errorValue; - } - - // Two images should share same size - if (image1->GetWidth(0) != image2->GetWidth(0) || image1->GetHeight(0) != image2->GetHeight(0)) - { - AZ_Warning("Image Processing", false, "%s function only can get error between two images with same size", __FUNCTION__); - return errorValue; - } - - //create pixel operation function - IPixelOperationPtr pixelOp1 = CreatePixelOperation(image1->GetPixelFormat()); - IPixelOperationPtr pixelOp2 = CreatePixelOperation(image2->GetPixelFormat()); - - //get count of bytes per pixel - AZ::u32 pixelBytes1 = CPixelFormats::GetInstance().GetPixelFormatInfo(image1->GetPixelFormat())->bitsPerBlock / 8; - AZ::u32 pixelBytes2 = CPixelFormats::GetInstance().GetPixelFormatInfo(image2->GetPixelFormat())->bitsPerBlock / 8; - - float color1[4]; - float color2[4]; - AZ::u8* mem1; - AZ::u8* mem2; - uint32 pitch1, pitch2; - - float sumDeltaSqLinear = 0; - - //only process the highest mip - image1->GetImagePointer(0, mem1, pitch1); - image2->GetImagePointer(0, mem2, pitch2); - - const uint32 pixelCount = image1->GetPixelCount(0); - - for (uint32 i = 0; i < pixelCount; ++i) - { - pixelOp1->GetRGBA(mem1, color1[0], color1[1], color1[2], color1[3]); - pixelOp2->GetRGBA(mem2, color2[0], color2[1], color2[2], color2[3]); - - sumDeltaSqLinear += (color1[0] - color2[0]) * (color1[0] - color2[0]) - + (color1[1] - color2[1]) * (color1[1] - color2[1]) - + (color1[2] - color2[2]) * (color1[2] - color2[2]); - - mem1 += pixelBytes1; - mem2 += pixelBytes2; - } - - return sumDeltaSqLinear / pixelCount; - } - - void GetBC1CompressionErrors(IImageObjectPtr originImage, float& errorLinear, float& errorSrgb, - ICompressor::CompressOption option) - { - errorLinear = 0; - errorSrgb = 0; - - if (originImage->HasImageFlags(EIF_SRGBRead)) - { - AZ_Assert(false, "The input origin image of %s function need be in linear color space", __FUNCTION__); - return; - } - - //compress and decompress in linear space - ImageToProcess processLinear(originImage); - processLinear.SetCompressOption(option); - processLinear.ConvertFormat(ePixelFormat_BC1); - processLinear.ConvertFormat(ePixelFormat_R32G32B32A32F); - - errorLinear = GetErrorBetweenImages(originImage, processLinear.Get()); - - //compress and descompress in srgb space, then convert back to linear space to compare to original image - ImageToProcess processSrgb(originImage); - processSrgb.SetCompressOption(option); - processSrgb.LinearToGamma(); - processSrgb.ConvertFormat(ePixelFormat_BC1); - processSrgb.ConvertFormat(ePixelFormat_R32G32B32A32F); - processSrgb.GammaToLinearRGBA32F(true); - - errorSrgb = GetErrorBetweenImages(originImage, processSrgb.Get()); - } - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.h b/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.h deleted file mode 100644 index 01cd422672..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageConvert.h +++ /dev/null @@ -1,182 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include -#include - -namespace ImageProcessing -{ - class IImageObject; - class ImageToProcess; - - //Convert image file with its image export setting and save to specified folder. - //this function can be useful for a cancelable job - class ImageConvertProcess* CreateImageConvertProcess(const AZStd::string& imageFilePath, - const AZStd::string& exportDir, const PlatformName& platformName, AZ::SerializeContext* context = nullptr); - - //Convert image file with its image export setting and save to specified folder. it will return when the whole conversion is done. - //Could be used for command mode or test - bool ConvertImageFile(const AZStd::string& imageFilePath, const AZStd::string& exportDir, AZStd::vector& outPaths, - const PlatformName& platformName = "", AZ::SerializeContext* context = nullptr); - - //image filter function - void FilterImage(MipGenType genType, MipGenEvalType evalType, float blurH, float blurV, const IImageObjectPtr srcImg, int srcMip, - IImageObjectPtr dstImg, int dstMip, QRect* srcRect, QRect* dstRect); - - //get compression error for an image converting to certain format - void GetBC1CompressionErrors(IImageObjectPtr originImage, float& errorLinear, float& errorSrgb, - ICompressor::CompressOption option); - - float GetErrorBetweenImages(IImageObjectPtr inputImage1, IImageObjectPtr inputImage2); - - //Combine image with alpha image if any and output as RGBA8 - IImageObjectPtr MergeOutputImageForPreview(IImageObjectPtr image, IImageObjectPtr alphaImage); - - //get output image size and mip count based on the texture setting and preset setting - - //other helper functions - //Get desired output image size based on the texture settings - void GetOutputExtent(AZ::u32 inputWidth, AZ::u32 inputHeight, AZ::u32& outWidth, AZ::u32& outHeight, AZ::u32& outReduce, - const TextureSettings* textureSettings, const PresetSettings* presetSettings); - - class ImageConvertProcess - { - public: - //constructor - ImageConvertProcess(const IImageObjectPtr inputImage, const TextureSettings& textureSetting, - const PresetSettings& presetSetting, bool isPreview, bool isStreaming, bool canOverridePreset, - const AZStd::string& outputPath, const AZStd::string& platformId); - ~ImageConvertProcess(); - - //doing image conversion, this function need to be called repeatly until the process is done - //it could used for a working thread which may need to cancel a process - void UpdateProcess(); - - //doing all conversion in one step. This function will call UpdateProcess in a while loop until it's done. - void ProcessAll(); - - //for multi-thread - //get percentage of image convertion progress - float GetProgress(); - bool IsFinished(); - bool IsSucceed(); - - //get output images - IImageObjectPtr GetOutputImage(); - IImageObjectPtr GetOutputAlphaImage(); - IImageObjectPtr GetOutputDiffCubemap(); - - //get output file paths and append the paths to the outPaths vector. - void GetAppendOutputFilePaths(AZStd::vector& outPaths); - - private: - enum ConvertStep - { - StepValidateInput = 0, - StepGenerateColorChart, - StepConvertToLinear, - StepSwizzle, - StepOverridePreset, - StepCubemapLayout, - StepPreNormalize, - StepDiffCubemap, - StepMipmap, - StepGlossFromNormal, - StepPostNormalize, - StepCreateHighPass, - StepConvertOutputColorSpace, - StepAlphaImage, - StepConvertPixelFormat, - StepSaveToFile, - StepAll - }; - - //input image and settings - const IImageObjectPtr m_inputImage; - TextureSettings m_textureSetting; - PresetSettings m_presetSetting; - bool m_canOverridePreset; - bool m_isPreview; - AZStd::string m_outputPath; - AZStd::string m_platformId; - - //some global settings from builder setting - bool m_isStreaming; - - //for alpha - //to indicate the current alpha chanenl content - EAlphaContent m_alphaContent; - //An image object to hold alpha channel in a seperate image - IImageObjectPtr m_alphaImage; - - //for cubemap - //An image object to save output result of diffuse cubemap conversion - IImageObjectPtr m_diffCubemapImage; - - //image for processing - ImageToProcess *m_image; - - //progress - uint32 m_progressStep; - bool m_isFinished; - bool m_isSucceed; - - //all the output products' paths - AZStd::vector m_productFilepaths; - - //for get processing time - AZStd::sys_time_t m_startTime; - double m_processTime; //in seconds - - private: - //validate the input image and settings - bool ValidateInput(); - - //mipmap generation - bool FillMipmaps(); - - //mipmap generation for cubemap - bool FillCubemapMipmaps(); - - //special case: create diffuse cubemap - void CreateDiffuseCubemap(); - - //convert color space to linear with pixel format rgba32f - bool ConvertToLinear(); - - //convert to output color space before compression - bool ConvertToOuputColorSpace(); - - //create alpha image if it's needed - void CreateAlphaImage(); - - //pixel format convertion/compression - bool ConvertPixelformat(); - - //save output image to a file - bool SaveOutput(); - - //if it's converting for cubemap - bool IsConvertToCubemap(); - }; - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.cpp b/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.cpp deleted file mode 100644 index cab3918a05..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - IImageObjectPtr ImageConvertOutput::GetOutputImage(OutputImageType type) const - { - if (type < OutputImageType::Count) - { - return m_outputImage[static_cast(type)]; - } - else - { - return IImageObjectPtr(); - } - } - - void ImageConvertOutput::SetOutputImage(IImageObjectPtr image, OutputImageType type) - { - if (type < OutputImageType::Count) - { - m_outputImage[static_cast(type)] = image; - } - else - { - AZ_Error("ImageProcess", false, "Cannot set output image to %d", type); - } - } - - void ImageConvertOutput::SetReady(bool ready) - { - m_outputReady = ready; - } - - bool ImageConvertOutput::IsReady() const - { - return m_outputReady; - } - - float ImageConvertOutput::GetProgress() const - { - return m_progress; - } - - void ImageConvertOutput::SetProgress(float progress) - { - m_progress = progress; - } - - void ImageConvertOutput::Reset() - { - for (int i = 0; i < static_cast(OutputImageType::Count); i ++ ) - { - m_outputImage[i] = nullptr; - } - m_outputReady = false; - m_progress = 0.0f; - } - - ImageConvertJob::ImageConvertJob(IImageObjectPtr image, const TextureSettings* textureSetting, - const PresetSettings* preset, bool isPreview, const AZStd::string& platformId, - ImageConvertOutput* output, bool autoDelete /*= true*/, AZ::JobContext* jobContext /*= nullptr*/) - : AZ::Job(autoDelete, jobContext) - , m_isPreview(isPreview) - , m_isCancelled(false) - , m_output(output) - { - AZ_Assert(m_output, "Needs to have an output destination for image conversion!"); - if (image && textureSetting && preset) - { - bool isStreaming = BuilderSettingManager::Instance()->GetBuilderSetting(platformId)->m_enableStreaming; - bool canOverridePreset = false; - m_process = AZStd::make_unique(image, *textureSetting, *preset, isPreview, isStreaming, canOverridePreset, "", platformId); - } - } - - void ImageConvertJob::Process() - { - if (!m_process) - { - AZ_Error("Image Processing", false, "Cannot start processing, invalid setting or image!"); - m_output->SetReady(true); - m_output->SetProgress(1.0f); - return; - } - m_output->SetReady(false); - while (!m_process->IsFinished() && !IsJobCancelled()) - { - m_process->UpdateProcess(); - if (m_isPreview) - { - m_output->SetProgress(m_process->GetProgress() / static_cast(m_previewProcessStep)); - } - else - { - m_output->SetProgress(m_process->GetProgress()); - } - } - - IImageObjectPtr outputImage = m_process->GetOutputImage(); - IImageObjectPtr outputImageAlpha = m_process->GetOutputAlphaImage(); - - m_output->SetOutputImage(outputImage, ImageConvertOutput::Base); - m_output->SetOutputImage(outputImageAlpha, ImageConvertOutput::Alpha); - - if (m_isPreview && !IsJobCancelled()) - { - // For preview, combine image output with alpha if any - m_output->SetProgress(1.0f / static_cast(m_previewProcessStep)); - IImageObjectPtr combinedImage = MergeOutputImageForPreview(outputImage, outputImageAlpha); - m_output->SetOutputImage(combinedImage, ImageConvertOutput::Preview); - } - - m_output->SetReady(true); - m_output->SetProgress(1.0f); - } - - void ImageConvertJob::Cancel() - { - m_isCancelled = true; - } - - bool ImageConvertJob::IsJobCancelled() - { - return m_isCancelled || IsCancelled(); - } - - - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.h b/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.h deleted file mode 100644 index fb3f26af50..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageConvertJob.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ImageProcessing -{ - class ImageConvertProcess; - - class ImageConvertOutput - { - public: - enum OutputImageType - { - Base = 0, // Might contains alpha or not - Alpha, // Separate alpha image - Preview, // Combine base image with alpha if any, format RGBA8 - Count - }; - - IImageObjectPtr GetOutputImage(OutputImageType type) const; - void SetOutputImage(IImageObjectPtr image, OutputImageType type); - void SetReady(bool ready); - bool IsReady() const; - float GetProgress() const; - void SetProgress(float progress); - void Reset(); - - private: - IImageObjectPtr m_outputImage[OutputImageType::Count]; - bool m_outputReady = false; - float m_progress = 0.0f; - }; - - class ImageConvertJob - : public AZ::Job - { - public: - AZ_CLASS_ALLOCATOR(ImageConvertJob, AZ::ThreadPoolAllocator, 0) - - ImageConvertJob(IImageObjectPtr image, const TextureSettings* textureSetting, const PresetSettings* preset - , bool isPreview, const AZStd::string& platformId, ImageConvertOutput* output, bool autoDelete = true - , AZ::JobContext* jobContext = nullptr); - - void Process() override; - // Cancel the job itself - void Cancel(); - // Whether the job is being cancelled or the whole job group is being cancelled - bool IsJobCancelled(); - - private: - static const int m_previewProcessStep = 2; - - AZStd::unique_ptr m_process; - bool m_isPreview; - AZStd::atomic_bool m_isCancelled; - ImageConvertOutput* m_output; - }; -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageFlags.h b/Gems/ImageProcessing/Code/Source/Processing/ImageFlags.h deleted file mode 100644 index 2f09fbb588..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageFlags.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -//! The following constants are extracted from ImageExtensionHelper.h -//! Please make sure they are always synced with the same constants defined in ImageExtensionHelper.h - -namespace ImageProcessing -{ - // flags to propagate from the RC to the engine through GetImageFlags() - // 32bit bitmask, numbers should not change as engine relies on them - const static AZ::u32 EIF_Cubemap = 0x1; - const static AZ::u32 EIF_Volumetexture = 0x2; - const static AZ::u32 EIF_Decal = 0x4; // this is usually set through the preset - const static AZ::u32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color - const static AZ::u32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture - const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use - const static AZ::u32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel - const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear) - const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized with r_TexResolution - const static AZ::u32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range - const static AZ::u32 EIF_CafeNative = 0x20000; // info for the engine: native Cafe texture format - const static AZ::u32 EIF_RestrictedPlatformONative = 0x40000; // native tiled texture for restrict platform O - const static AZ::u32 EIF_Tiled = 0x80000; // info for the engine: texture has been tiled for the platform - const static AZ::u32 EIF_RestrictedPlatformDNative = 0x100000; // native tiled texture for restrict platform D - const static AZ::u32 EIF_Splitted = 0x200000; // info for the engine: this texture is splitted - const static AZ::u32 EIF_Colormodel = 0x7000000; // info for the engine: bitmask: colormodel used in the texture - const static AZ::u32 EIF_Colormodel_RGB = 0x0000000; // info for the engine: colormodel is RGB (default) - const static AZ::u32 EIF_Colormodel_CIE = 0x1000000; // info for the engine: colormodel is CIE (used for terrain) - const static AZ::u32 EIF_Colormodel_YCC = 0x2000000; // info for the engine: colormodel is Y'CbCr (used for reflectance) - const static AZ::u32 EIF_Colormodel_YFF = 0x3000000; // info for the engine: colormodel is Y'FbFr (used for reflectance) - const static AZ::u32 EIF_Colormodel_IRB = 0x4000000; // info for the engine: colormodel is IRB (used for reflectance) -} diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.cpp b/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.cpp deleted file mode 100644 index 7a6b1e3002..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.cpp +++ /dev/null @@ -1,1417 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -// Indicates a 2D texture is a cube-map texture. -#define DDS_RESOURCE_MISC_TEXTURECUBE 0x4 - -namespace ImageProcessing -{ - - IImageObject* IImageObject::CreateImage(AZ::u32 width, AZ::u32 height, - AZ::u32 maxMipCount, EPixelFormat pixelFormat) - { - return aznew CImageObject(width, height, maxMipCount, pixelFormat); - } - - CImageObject::CImageObject(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat) - : m_pixelFormat(pixelFormat) - , m_colMinARGB(0.0f, 0.0f, 0.0f, 0.0f) - , m_colMaxARGB(1.0f, 1.0f, 1.0f, 1.0f) - , m_averageBrightness(0.63f) - , m_imageFlags(0) - , m_numPersistentMips(0) - { - ResetImage(width, height, maxMipCount, pixelFormat); - } - - EPixelFormat CImageObject::GetPixelFormat() const - { - return m_pixelFormat; - } - - AZ::u32 CImageObject::GetPixelCount(AZ::u32 mip) const - { - AZ_Assert(mip < (AZ::u32)m_mips.size() && m_mips[mip], "Mip doesn't exist: %d", mip); - - return m_mips[mip]->m_width * m_mips[mip]->m_height; - } - - AZ::u32 CImageObject::GetWidth(AZ::u32 mip) const - { - AZ_Assert(mip < (AZ::u32)m_mips.size() && m_mips[mip], "Mip doesn't exist: %d", mip); - - return m_mips[mip]->m_width; - } - - AZ::u32 CImageObject::GetHeight(AZ::u32 mip) const - { - AZ_Assert(mip < (AZ::u32)m_mips.size() && m_mips[mip], "Mip doesn't exist: %d", mip); - - return m_mips[mip]->m_height; - } - - AZ::u32 CImageObject::GetMipCount() const - { - return (AZ::u32)m_mips.size(); - } - - void CImageObject::ResetImage(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat) - { - //check input - AZ_Assert(width > 0 && height > 0, "image width and height need to larger than 0. width: %d, height: %d", width, height); - AZ_Assert(maxMipCount > 0, "image mipmap count need to larger than 0. maxMipCount: %d", maxMipCount); - - //clean up mipmaps - for (AZ::u32 mip = 0; mip < AZ::u32(m_mips.size()); ++mip) - { - delete m_mips[mip]; - } - - m_pixelFormat = pixelFormat; - m_colMinARGB = AZ::Color(0.0f, 0.0f, 0.0f, 0.0f); - m_colMaxARGB = AZ::Color(1.0f, 1.0f, 1.0f, 1.0f); - m_averageBrightness = 0.0f; - m_imageFlags = 0; - m_numPersistentMips = 0; - m_mips.clear(); - - const PixelFormatInfo* const pFmt = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat); - AZ_Assert(pFmt, "can't find pixe format info for %d", m_pixelFormat); - - const AZ::u32 mipCount = AZStd::min(maxMipCount, - CPixelFormats::GetInstance().ComputeMaxMipCount(m_pixelFormat, width, height)); - - m_mips.reserve(mipCount); - - for (AZ::u32 mip = 0; mip < mipCount; ++mip) - { - MipLevel* const pEntry = aznew MipLevel; - - AZ::u32 localWidth = width >> mip; - AZ::u32 localHeight = height >> mip; - if (localWidth < 1) - { - localWidth = 1; - } - if (localHeight < 1) - { - localHeight = 1; - } - - pEntry->m_width = localWidth; - pEntry->m_height = localHeight; - - if (pFmt->bCompressed) - { - const AZ::u32 blocksInRow = (pEntry->m_width + (pFmt->blockWidth - 1)) / pFmt->blockWidth; - pEntry->m_pitch = (blocksInRow * pFmt->bitsPerBlock) / 8; - pEntry->m_rowCount = (localHeight + (pFmt->blockHeight - 1)) / pFmt->blockHeight; - } - else - { - pEntry->m_pitch = (pEntry->m_width * pFmt->bitsPerBlock) / 8; - pEntry->m_rowCount = localHeight; - } - - pEntry->Alloc(); - - m_mips.push_back(pEntry); - } - } - - bool CImageObject::CompareImage(const IImageObjectPtr otherImage) const - { - CImageObject* other = static_cast(otherImage.get()); - if (other == nullptr) - { - return false; - } - - if (m_pixelFormat == other->m_pixelFormat - && m_colMinARGB == other->m_colMinARGB - && m_colMaxARGB == other->m_colMaxARGB - && m_averageBrightness == other->m_averageBrightness - && m_imageFlags == other->m_imageFlags - && m_numPersistentMips == other->m_numPersistentMips - && m_mips.size() == other->m_mips.size()) - { - for (int mip = 0; mip < m_mips.size(); mip++) - { - if (!(*m_mips[mip] == *other->m_mips[mip])) - { - return false; - } - } - return true; - } - return false; - } - - uint CImageObject::GetTextureMemory() const - { - int totalSize = 0; - for (int mip = 0; mip < m_mips.size(); mip++) - { - totalSize += CPixelFormats::GetInstance().EvaluateImageDataSize(m_pixelFormat, - m_mips[mip]->m_width, m_mips[mip]->m_height); - } - - return totalSize; - } - - EAlphaContent CImageObject::GetAlphaContent() const - { - if (CPixelFormats::GetInstance().IsPixelFormatWithoutAlpha(m_pixelFormat)) - { - return EAlphaContent::eAlphaContent_Absent; - } - - //if it's compressed format, return indeterminate. if user really want to know the content, they may convert the format to ARGB8 first - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)) - { - AZ_Assert(false, "the function only works right with uncompressed formats. convert to uncompressed format if you get accurate result"); - return EAlphaContent::eAlphaContent_Indeterminate; - } - - //go though alpha channel of first mip - //create pixel operation function to access pixel data - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel for images - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - // counts of blacks and white - uint nBlacks = 0; - uint nWhites = 0; - - float r, g, b, a; - AZ::u8* pixelBuf; - AZ::u32 pitch; - GetImagePointer(0, pixelBuf, pitch); - - const AZ::u32 pixelCount = GetPixelCount(0); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, r, g, b, a); - if (a == 0.0f) - { - ++nBlacks; - } - else if (a == 1.0f) - { - ++nWhites; - } - else - { - return EAlphaContent::eAlphaContent_Greyscale; - } - } - - if (nBlacks == 0) - { - return EAlphaContent::eAlphaContent_OnlyWhite; - } - - if (nWhites == 0) - { - return EAlphaContent::eAlphaContent_OnlyBlack; - } - - return EAlphaContent::eAlphaContent_OnlyBlackAndWhite; - } - - // clone this image-object's contents - IImageObject* CImageObject::Clone() const - { - const EPixelFormat srcPixelformat = GetPixelFormat(); - - IImageObject* pRet = AllocateImage(); - - AZ::u32 dwMips = pRet->GetMipCount(); - for (AZ::u32 dwMip = 0; dwMip < dwMips; ++dwMip) - { - //AZ::u32 dwLocalWidth = GetWidth(dwMip); // we get error on NVidia with this (assumes input is 4x4 as well) - AZ::u32 dwLocalHeight = GetHeight(dwMip); - - AZ::u32 dwLines = dwLocalHeight; - - if (CPixelFormats::GetInstance().IsPixelFormatUncompressed(srcPixelformat)) - { - dwLines = m_mips[dwMip]->m_rowCount; - } - - AZ::u8* pMem; - AZ::u32 dwPitch; - GetImagePointer(dwMip, pMem, dwPitch); - - AZ::u8* pDstMem; - AZ::u32 dwDstPitch; - pRet->GetImagePointer(dwMip, pDstMem, dwDstPitch); - - for (AZ::u32 dwY = 0; dwY < dwLines; ++dwY) - { - memcpy(&pDstMem[dwDstPitch * dwY], &pMem[dwPitch * dwY], AZStd::min(dwPitch, dwDstPitch)); - } - } - return pRet; - } - - void CImageObject::ClearColor(float r, float g, float b, float a) - { - //if it's compressed format, return directly - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)) - { - AZ_Assert(false, "The %s function only works with uncompressed formats", __FUNCTION__); - return; - } - //create pixel operation function to access pixel data - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel for images - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - AZ::u8* pixelBuf; - AZ::u32 pitch; - - AZ::u32 mips = GetMipCount(); - for (AZ::u32 mip = 0; mip < mips; ++mip) - { - GetImagePointer(mip, pixelBuf, pitch); - const AZ::u32 pixelCount = GetPixelCount(mip); - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->SetRGBA(pixelBuf, r, g, b, a); - } - } - } - - // allocate an empty image with the same properties as the given image and the requested format - IImageObject* CImageObject::AllocateImage(EPixelFormat pixelFormat) const - { - AZ::u32 width = GetWidth(0); - AZ::u32 height = GetHeight(0); - - if (!CPixelFormats::GetInstance().IsImageSizeValid(pixelFormat, width, height, false)) - { - AZ_Assert(false, "Cann't allocate image with format: %d", pixelFormat); - return nullptr; - } - - CImageObject* pRet = aznew CImageObject(width, height, GetMipCount(), pixelFormat); - pRet->CopyPropertiesFrom(this); - return pRet; - } - - IImageObject* CImageObject::AllocateImage() const - { - return AllocateImage(m_pixelFormat); - } - - CImageObject::~CImageObject() - { - for (size_t i = 0; i < m_mips.size(); ++i) - { - delete m_mips[i]; - } - m_mips.clear(); - } - - //note: there are some unreasonable parts of the save files formats for cry textures. We might need to rethink about - // it for new renderer - bool CImageObject::SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const - { - AZ::IO::SystemFile file; - file.Open(filename, AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream fileSaveStream(&file, true); - if (!fileSaveStream.IsOpen()) - { - - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename); - return false; - } - - if (alphaImage) - { - AZ_Assert(HasImageFlags(EIF_AttachedAlpha), "attached alpha image flag wasn't set"); - AZ_Assert(!alphaImage->HasImageFlags(EIF_AttachedAlpha), "alpha image shouldn't have attached alpha image flag"); - - // inherit cubemap and decal image flags to attached alpha image - alphaImage->AddImageFlags(GetImageFlags() & (EIF_Cubemap - | EIF_Decal | EIF_Splitted)); - alphaImage->SetNumPersistentMips(m_numPersistentMips); - } - - bool bOk = SaveImage(fileSaveStream); - bool hasSplitFlag = HasImageFlags(EIF_Splitted); - - //append alpha image data in the end if there is no split - if (bOk && alphaImage && !hasSplitFlag) - { - //4 bytes extension tag, 4 bytes attached alpha tag, then 4 bytes of chunk size - fileSaveStream.Write(sizeof(FOURCC_CExt), &FOURCC_CExt); // marker for the start of Crytek Extended data - fileSaveStream.Write(sizeof(FOURCC_AttC), &FOURCC_AttC); // Attached Channel chunk - - AZ::u32 size = 0; - AZ::u32 sizeBytes = sizeof(size); - fileSaveStream.Write(sizeBytes, &size); //size of attached chunk - - //save alpha image and get the size - AZ::IO::SizeType startPos = fileSaveStream.GetCurPos(); - bOk = alphaImage->SaveImage(fileSaveStream); - AZ::IO::SizeType endPos = fileSaveStream.GetCurPos(); - size = aznumeric_cast(endPos - startPos); - - //move back to beginning of chunk and write chunk size then move back to end - fileSaveStream.Seek(startPos - sizeBytes, AZ::IO::GenericStream::ST_SEEK_BEGIN); - fileSaveStream.Write(sizeBytes, &size); - fileSaveStream.Seek(endPos, AZ::IO::GenericStream::ST_SEEK_BEGIN); - - // marker for the end of Crytek Extended data - fileSaveStream.Write(sizeof(FOURCC_CEnd), &FOURCC_CEnd); - } - - if (!bOk) - { - AZ::IO::SystemFile::Delete(filename); - return false; - } - - // It's important to maintain the product output sequence. Asset Database/Browser will use the first product to determine the source type! - outFilePaths.push_back(filename); - - // save stand alone products - if (hasSplitFlag) - { - // alpha - if (alphaImage) - { - AZStd::string alphaFile = AZStd::string::format("%s.a", filename); - - AZ::IO::SystemFile outAlphaFile; - outAlphaFile.Open(alphaFile.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream alphaFileSaveStream(&outAlphaFile, true); - - if (alphaFileSaveStream.IsOpen()) - { - alphaImage->SaveImage(alphaFileSaveStream); - outFilePaths.push_back(alphaFile); - } - else - { - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, alphaFile.c_str()); - } - } - - // mips - AZ::u32 numStreamable = GetMipCount() - m_numPersistentMips; - for (AZ::u32 mip = 0; mip < numStreamable; mip++) - { - AZ::u32 nameIdx = numStreamable - mip; - AZStd::string mipFileName = AZStd::string::format("%s.%d", filename, nameIdx); - SaveMipToFile(mip, mipFileName); - outFilePaths.push_back(mipFileName); - if (alphaImage) - { - AZStd::string mipAlphaFileName = mipFileName + "a"; - alphaImage->SaveMipToFile(mip, mipAlphaFileName); - outFilePaths.push_back(mipAlphaFileName); - } - } - } - - return bOk; - } - - bool CImageObject::SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const - { - AZ::IO::SystemFile saveFile; - saveFile.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream saveFileStream(&saveFile, true); - - if (!saveFileStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename.c_str()); - return false; - } - - saveFileStream.Write(GetMipBufSize(mip), m_mips[mip]->m_pData); - return true; - } - - IImageObject* CreateImageFromHeader(DDS_HEADER& header, DDS_HEADER_DXT10& exthead) - { - EPixelFormat eFormat = ePixelFormat_Unknown; - AZ::u32 dwWidth, dwMips, dwHeight; - AZ::u32 imageFlags = header.dwReserved1; - AZ::Color colMinARGB, colMaxARGB; - - dwWidth = header.dwWidth; - dwHeight = header.dwHeight; - dwMips = 1; - if (header.dwHeaderFlags & DDS_HEADER_FLAGS_MIPMAP) - { - dwMips = header.dwMipMapCount; - } - if ((header.dwSurfaceFlags & DDS_SURFACE_FLAGS_CUBEMAP) && (header.dwCubemapFlags & DDS_CUBEMAP_ALLFACES)) - { - AZ_Assert(header.dwReserved1&EIF_Cubemap, "Image flag should have cubemap flag"); - dwHeight *= 6; - } - - colMinARGB = AZ::Color(header.cMinColor[0], header.cMinColor[1], header.cMinColor[2], header.cMinColor[3]); - colMaxARGB = AZ::Color(header.cMaxColor[0], header.cMaxColor[1], header.cMaxColor[2], header.cMaxColor[3]); - - //get pixel format - { - // DX10 formats - if (header.ddspf.dwFourCC == FOURCC_DX10) - { - AZ::u32 dxgiFormat = exthead.dxgiFormat; - - //remove the SRGB from dxgi format and add sRGB to image flag - if (dxgiFormat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC1_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC1_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC2_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC2_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC3_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC3_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC7_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC7_UNORM; - } - - //add rgb flag if the dxgiformat was changed (which means it was sRGB format) above - if (dxgiFormat != exthead.dxgiFormat) - { - AZ_Assert(imageFlags&EIF_SRGBRead, "Image flags should have SRGBRead flag"); - imageFlags |= EIF_SRGBRead; - } - - //check all the pixel formats and find matching one - if (dxgiFormat != DXGI_FORMAT_UNKNOWN) - { - int i = 0; - for (i; id3d10Format == dxgiFormat) - { - eFormat = (EPixelFormat)i; - break; - } - } - if (i == ePixelFormat_Count) - { - AZ_Error("Image Processing", false, "Unhandled d3d10 format: %d", dxgiFormat); - return nullptr; - } - } - } - else - { - //for non-dx10 formats, use fourCC to find out its pixel formats - //go through all pixel formats and find a match with the fourcc - for (AZ::u32 formatIdx = 0; formatIdx < ePixelFormat_Count; formatIdx++) - { - const PixelFormatInfo *info = CPixelFormats::GetInstance().GetPixelFormatInfo((EPixelFormat)formatIdx); - if (header.ddspf.dwFourCC == info->fourCC) - { - eFormat = (EPixelFormat)formatIdx; - break; - } - } - - //legacy formats. This section is only used for load dds files converted by RC.exe - //our save to dds file function won't use any of these fourcc - if (eFormat == ePixelFormat_Unknown) - { - if (header.ddspf.dwFourCC == FOURCC_DXT1) - { - eFormat = ePixelFormat_BC1; - } - else if (header.ddspf.dwFourCC == FOURCC_DXT5) - { - eFormat = ePixelFormat_BC3; - } - else if (header.ddspf.dwFourCC == FOURCC_3DCP) - { - eFormat = ePixelFormat_BC4; - } - else if (header.ddspf.dwFourCC == FOURCC_3DC) - { - eFormat = ePixelFormat_BC5; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R32F) - { - eFormat = ePixelFormat_R32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G32R32F) - { - eFormat = ePixelFormat_R32G32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A32B32G32R32F) - { - eFormat = ePixelFormat_R32G32B32A32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R16F) - { - eFormat = ePixelFormat_R16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G16R16F) - { - eFormat = ePixelFormat_R16G16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16F) - { - eFormat = ePixelFormat_R16G16B16A16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16) - { - eFormat = ePixelFormat_R16G16B16A16; - } - else if ((header.ddspf.dwFlags == DDS_RGBA || header.ddspf.dwFlags == DDS_RGB) - && header.ddspf.dwRGBBitCount == 32) - { - if (header.ddspf.dwRBitMask == 0x00ff0000) - { - eFormat = ePixelFormat_B8G8R8A8; - } - else - { - eFormat = ePixelFormat_R8G8B8A8; - } - } - else if (header.ddspf.dwFlags == DDS_LUMINANCEA && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_R8G8; - } - else if (header.ddspf.dwFlags == DDS_LUMINANCE && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_A8; - } - else if ((header.ddspf.dwFlags == DDS_A || header.ddspf.dwFlags == DDS_A_ONLY || header.ddspf.dwFlags == (DDS_A | DDS_A_ONLY)) && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_A8; - } - } - } - } - - if (eFormat == ePixelFormat_Unknown) - { - AZ_Error("Image Processing", false, "Unhandled dds pixel format fourCC: %d, flags: %d", - header.ddspf.dwFourCC, header.ddspf.dwFlags); - return nullptr; - } - - IImageObject* newImage = IImageObject::CreateImage(dwWidth, dwHeight, dwMips, eFormat); - - if (dwMips != newImage->GetMipCount()) - { - AZ_Error("Image Processing", false, "Mipcount from image data doesn't match image size and pixelformat"); - delete newImage; - return nullptr; - } - - //set properties - newImage->SetImageFlags(imageFlags); - newImage->SetAverageBrightness(header.fAvgBrightness); - newImage->SetColorRange(colMinARGB, colMaxARGB); - newImage->SetNumPersistentMips(header.bNumPersistentMips); - - return newImage; - } - - float CImageObject::CalculateAverageBrightness() const - { - //if it's compressed format, return a default value - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)) - { - return 0.5f; - } - - // Accumulate pixel colors of the top mip - double avgOverall[3] = { 0.0, 0.0, 0.0 }; - - //create pixel operation function to access pixel data - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel for images - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - //only calculate mip 0 - AZ::u32 mip = 0; - float color[4]; - AZ::u8* pixelBuf; - AZ::u32 pitch; - GetImagePointer(mip, pixelBuf, pitch); - const AZ::u32 pixelCount = GetPixelCount(mip); - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - avgOverall[0] += color[0]; - avgOverall[1] += color[1]; - avgOverall[2] += color[2]; - } - - const double avg = (avgOverall[0] + avgOverall[1] + avgOverall[2]) / (3 * pixelCount); - - return (float)avg; - } - - bool CImageObject::BuildSurfaceHeader(DDS_HEADER& header) const - { - AZ::u32 dwWidth, dwMips, dwHeight; - GetExtent(dwWidth, dwHeight, dwMips); - - if (dwMips <= 0) - { - AZ_Error("Image Processing", false, "%s: dwMips is %u", __FUNCTION__, (unsigned)dwMips); - return false; - } - - const EPixelFormat format = GetPixelFormat(); - if ((format < 0) || (format >= ePixelFormat_Count)) - { - AZ_Error("Image Processing", false, "%s: Bad format %d", __FUNCTION__, (int)format); - return false; - } - - const PixelFormatInfo* const pPixelFormatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(format); - - memset(&header, 0, sizeof(DDS_HEADER)); - - header.dwSize = sizeof(DDS_HEADER); - header.dwHeaderFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT; - header.dwWidth = dwWidth; - header.dwHeight = dwHeight; - - if (HasImageFlags(EIF_Cubemap)) - { - header.dwSurfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP; - header.dwCubemapFlags |= DDS_CUBEMAP_ALLFACES; - //save face size instead of image size. - header.dwHeight /= 6; - } - - header.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); - header.ddspf.dwFlags = DDS_FOURCC; - - header.ddspf.dwFourCC = pPixelFormatInfo->fourCC; - - header.dwSurfaceFlags |= DDS_SURFACE_FLAGS_TEXTURE; - - if (dwMips > 1) - { - header.dwHeaderFlags |= DDS_HEADER_FLAGS_MIPMAP; - header.dwMipMapCount = dwMips; - header.dwSurfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP; - } - - // non standardized way to expose some features in the header (same information is in attached chunk but then - // streaming would need to find this spot in the file) - // if this is causing problems we need to change it - header.dwTextureStage = FOURCC_FYRC; - header.dwReserved1 = GetImageFlags(); - header.bNumPersistentMips = (AZ::u8)GetNumPersistentMips(); - - //tile mode for some platform native texture - if (HasImageFlags(EIF_RestrictedPlatformDNative)) - { - header.tileMode = eTM_LinearPadded; - } - else if (HasImageFlags(EIF_RestrictedPlatformONative)) - { - header.tileMode = eTM_Optimal; - } - - // setting up min and max colors - for (int i = 0; i < 4; i ++) - { - header.cMinColor[i] = m_colMinARGB.GetElement(i); - header.cMaxColor[i] = m_colMaxARGB.GetElement(i); - } - - // set avg brightness - header.fAvgBrightness = GetAverageBrightness(); - - return true; - } - - bool CImageObject::BuildSurfaceExtendedHeader(DDS_HEADER_DXT10& exthead) const - { - const EPixelFormat format = GetPixelFormat(); - - const PixelFormatInfo* const pPixelFormatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(format); - - DXGI_FORMAT dxgiformat = pPixelFormatInfo->d3d10Format; - - // check if we hit a format which can't be stored into a DX10 DDS-file (fe. L8) - if (dxgiformat == DXGI_FORMAT_UNKNOWN) - { - AZ_Error("Image Processing", false, "%s: Format can not be stored in a DDS-file %d", __FUNCTION__, dxgiformat); - return false; - } - - //the dxgi format are different for linear space or gamma space - if (HasImageFlags(EIF_SRGBRead)) - { - switch (dxgiformat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - dxgiformat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - break; - case DXGI_FORMAT_BC1_UNORM: - dxgiformat = DXGI_FORMAT_BC1_UNORM_SRGB; - break; - case DXGI_FORMAT_BC2_UNORM: - dxgiformat = DXGI_FORMAT_BC2_UNORM_SRGB; - break; - case DXGI_FORMAT_BC3_UNORM: - dxgiformat = DXGI_FORMAT_BC3_UNORM_SRGB; - break; - case DXGI_FORMAT_BC7_UNORM: - dxgiformat = DXGI_FORMAT_BC7_UNORM_SRGB; - break; - default: - break; - } - } - else - { - switch (dxgiformat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - dxgiformat = DXGI_FORMAT_R8G8B8A8_UNORM; - break; - case DXGI_FORMAT_BC1_UNORM_SRGB: - dxgiformat = DXGI_FORMAT_BC1_UNORM; - break; - case DXGI_FORMAT_BC2_UNORM_SRGB: - dxgiformat = DXGI_FORMAT_BC2_UNORM; - break; - case DXGI_FORMAT_BC3_UNORM_SRGB: - dxgiformat = DXGI_FORMAT_BC3_UNORM; - break; - case DXGI_FORMAT_BC7_UNORM_SRGB: - dxgiformat = DXGI_FORMAT_BC7_UNORM; - break; - default: - break; - } - } - - memset(&exthead, 0, sizeof(exthead)); - - exthead.dxgiFormat = dxgiformat; - exthead.resourceDimension = 3; //texture2d. not used - - if (HasImageFlags(EIF_Volumetexture)) - { - AZ_Assert(false, "There isn't any support for volume texture"); - } - else if (HasImageFlags(EIF_Cubemap)) - { - exthead.miscFlag = DDS_RESOURCE_MISC_TEXTURECUBE; - exthead.arraySize = 6; - } - else - { - exthead.miscFlag = 0; - exthead.arraySize = 1; - } - - return true; - } - - bool CImageObject::SaveImage(AZ::IO::SystemFileStream &saveFileStream) const - { - DDS_FILE_DESC desc; - DDS_HEADER_DXT10 exthead; - - desc.dwMagic = FOURCC_DDS; - - if (!BuildSurfaceHeader(desc.header)) - { - return false; - } - - if (desc.header.IsDX10Ext() && !BuildSurfaceExtendedHeader(exthead)) - { - return false; - } - - saveFileStream.Write(sizeof(desc), &desc); - - if (desc.header.IsDX10Ext()) - { - saveFileStream.Write(sizeof(exthead), &exthead); - } - - AZ::u32 faces = 1; - - //for cubemap. export each face and its mipmap - if (HasImageFlags(EIF_Cubemap)) - { - faces = 6; - } - - AZ::u32 mipStart = 0; - if (HasImageFlags(EIF_Splitted)) - { - if (m_numPersistentMips < m_mips.size()) - { - mipStart = (AZ::u32)m_mips.size() - m_numPersistentMips; - } - else - { - AZ_Assert(false, "numPersistentMips wasn't setup correctly"); - } - } - - for (AZ::u32 face = 0; face < faces; face++) - { - for (AZ::u32 mip = mipStart; mip < m_mips.size(); ++mip) - { - const MipLevel& level = *m_mips[mip]; - AZ::u32 faceBufSize = level.m_pitch*level.m_rowCount / faces; - saveFileStream.Write(faceBufSize, level.m_pData + faceBufSize*face); - } - } - return true; - } - - void CImageObject::GetExtent(AZ::u32& width, AZ::u32& height, AZ::u32& mipCount) const - { - mipCount = (AZ::u32)m_mips.size(); - - width = m_mips[0]->m_width; - height = m_mips[0]->m_height; - } - - AZ::u32 CImageObject::GetMipDataSize(const AZ::u32 mip) const - { - AZ_Assert(mip < m_mips.size(), "mip %d doesn't exist", mip); - - return m_mips[mip]->GetSize(); - } - - void CImageObject::GetImagePointer(const AZ::u32 mip, AZ::u8*& pMem, AZ::u32& pitch) const - { - AZ_Assert(mip < (AZ::u32)m_mips.size() && m_mips[mip], "requested mip doesn't exist"); - - pMem = m_mips[mip]->m_pData; - pitch = m_mips[mip]->m_pitch; - } - - AZ::u32 CImageObject::GetMipBufSize(AZ::u32 mip) const - { - AZ_Assert(mip < (AZ::u32)m_mips.size() && m_mips[mip], "requested mip doesn't exist"); - - return m_mips[mip]->m_rowCount * m_mips[mip]->m_pitch; - } - - - void CImageObject::SetMipData(AZ::u32 mip, AZ::u8* mipBuf, AZ::u32 bufSize, AZ::u32 pitch) - { - if (mip >= m_mips.size()) - { - return; - } - m_mips[mip]->m_pData = mipBuf; - m_mips[mip]->m_pitch = pitch; - m_mips[mip]->m_rowCount = bufSize/pitch; - AZ_Assert(bufSize == m_mips[mip]->m_rowCount * pitch, "Bad pitch size"); - } - - // ARGB - void CImageObject::GetColorRange(AZ::Color& minColor, AZ::Color& maxColor) const - { - minColor = m_colMinARGB; - maxColor = m_colMaxARGB; - } - - // ARGB - void CImageObject::SetColorRange(const AZ::Color& minColor, const AZ::Color& maxColor) - { - m_colMinARGB = minColor; - m_colMaxARGB = maxColor; - } - - float CImageObject::GetAverageBrightness() const - { - return m_averageBrightness; - } - - void CImageObject::SetAverageBrightness(const float avgBrightness) - { - m_averageBrightness = avgBrightness; - } - - AZ::u32 CImageObject::GetImageFlags() const - { - return m_imageFlags; - } - - void CImageObject::SetImageFlags(const AZ::u32 imageFlags) - { - m_imageFlags = imageFlags; - } - - void CImageObject::AddImageFlags(const AZ::u32 imageFlags) - { - m_imageFlags |= imageFlags; - } - - void CImageObject::RemoveImageFlags(const AZ::u32 imageFlags) - { - m_imageFlags &= ~imageFlags; - } - - bool CImageObject::HasImageFlags(const AZ::u32 imageFlags) const - { - return (m_imageFlags & imageFlags) != 0; - } - - AZ::u32 CImageObject::GetNumPersistentMips() const - { - return m_numPersistentMips; - } - - void CImageObject::SetNumPersistentMips(AZ::u32 nMips) - { - m_numPersistentMips = nMips; - } - - bool CImageObject::HasPowerOfTwoSizes() const - { - AZ::u32 w, h, mips; - GetExtent(w, h, mips); - return ((w&(w - 1)) == 0) && ((h&(h - 1)) == 0); - } - - // use when you convert an image to another one - void CImageObject::CopyPropertiesFrom(const IImageObjectPtr src) - { - const CImageObject *imageObj = static_cast(src.get()); - CopyPropertiesFrom(imageObj); - } - - void CImageObject::CopyPropertiesFrom(const CImageObject* src) - { - m_colMinARGB = src->m_colMinARGB; - m_colMaxARGB = src->m_colMaxARGB; - m_averageBrightness = src->m_averageBrightness; - m_imageFlags = src->GetImageFlags(); - } - - void CImageObject::Swizzle(const char channels[4]) - { - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))) - { - AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__); - return; - } - - const AZ::u8 channelCnt = 4; - - enum Channel_Id - { - ChannelR = 0, - ChannelG, - ChannelB, - ChannelA, - ChannelVal0, - ChannelVal1, - ChannelTypeCount - }; - - float values[ChannelTypeCount]; - values[ChannelVal0] = 0.f; - values[ChannelVal1] = 1.f; - - AZ::u8 channelIndics[channelCnt]; - for (AZ::u8 idx = 0; idx < channelCnt; idx++) - { - switch (channels[idx]) - { - case 'a': - channelIndics[idx] = ChannelA; - break; - case 'r': - channelIndics[idx] = ChannelR; - break; - case 'g': - channelIndics[idx] = ChannelG; - break; - case 'b': - channelIndics[idx] = ChannelB; - break; - case '0': - channelIndics[idx] = ChannelVal0; - break; - case '1': - channelIndics[idx] = ChannelVal1; - break; - default: - AZ_Assert(false, "%s function only works with channel name \"rgba01\"", __FUNCTION__); - return; - } - } - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel - uint32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - const uint32 mips = (uint32)m_mips.size(); - for (uint32 mip = 0; mip < mips; ++mip) - { - uint8* pixelBuf = m_mips[mip]->m_pData; - const uint32 pixelCount = GetPixelCount(mip); - - for (uint32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, values[ChannelR], values[ChannelG], values[ChannelB], values[ChannelA]); - pixelOp->SetRGBA(pixelBuf, values[channelIndics[0]], values[channelIndics[1]], - values[channelIndics[2]], values[channelIndics[3]]); - } - } - } - - void CImageObject::GlossFromNormals(bool hasAuthoredGloss) - { - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))) - { - AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__); - return; - } - - // Derive new roughness from normal variance to preserve the bumpiness of normal map mips and to reduce specular aliasing. - // The derived roughness is combined with the artist authored roughness stored in the alpha channel of the normal map. - // The algorithm is based on the Frequency Domain Normal Mapping implementation presented by Neubelt and Pettineo at Siggraph 2013. - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - const AZ::u32 mips = (AZ::u32)m_mips.size(); - float color[4]; - for (AZ::u32 mip = 0; mip < mips; ++mip) - { - AZ::u8* pixelBuf = m_mips[mip]->m_pData; - const AZ::u32 pixelCount = GetPixelCount(mip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - - // Get length of the averaged normal - AZ::Vector3 normal(color[0] * 2.0f - 1.0f, color[1] * 2.0f - 1.0f, color[2] * 2.0f - 1.0f); - - float len = AZ::GetMax(normal.GetLength(), 1.0f / (1 << 15)); - - float authoredSmoothness = hasAuthoredGloss ? color[3] : 1.0f; - float finalSmoothness = authoredSmoothness; - - if (len < 1.0f) - { - // Convert from smoothness to roughness (needs to match shader code) - float authoredRoughness = (1.0f - authoredSmoothness) * (1.0f - authoredSmoothness); - - // Derive new roughness based on normal variance - float kappa = (3.0f * len - len * len * len) / (1.0f - len * len); - float variance = 1.0f / (2.0f * kappa); - float finalRoughness = AZ::GetMin(sqrtf(authoredRoughness * authoredRoughness + variance), 1.0f); - - // Convert roughness back to smoothness - finalSmoothness = 1.0f - sqrtf(finalRoughness); - } - - pixelOp->SetRGBA(pixelBuf, color[0], color[1], color[2], finalSmoothness); - - } - } - } - - void CImageObject::ConvertLegacyGloss() - { - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))) - { - AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__); - return; - } - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - const AZ::u32 mips = (AZ::u32)m_mips.size(); - float color[4]; - for (AZ::u32 mip = 0; mip < mips; ++mip) - { - AZ::u8* pixelBuf = m_mips[mip]->m_pData; - const AZ::u32 pixelCount = GetPixelCount(mip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - // Convert from (1 - s * 0.7)^6 to (1 - s)^2 - color[3] = 1 - pow(1.0f - color[3] * 0.7f, 3.0f); - pixelOp->SetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - } - } - } - - IImageObject* LoadImageFromDdsFile(const AZStd::string& filename) - { - AZ::IO::SystemFile file; - file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream fileLoadStream(&file, true); - if (!fileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open file %s", __FUNCTION__, filename.c_str()); - return nullptr; - } - - AZStd::string ext = ""; - AzFramework::StringFunc::Path::GetExtension(filename.c_str(), ext, false); - bool isAlphaImage = (ext == "a"); - - IImageObject* imageObj = LoadImageFromDdsFile(fileLoadStream); - - //load mips from seperated files if it's splitted - if (imageObj && imageObj->HasImageFlags(EIF_Splitted)) - { - AZStd::string baseName; - if (isAlphaImage) - { - baseName = filename.substr(0, filename.size() - 2); - } - else - { - baseName = filename; - } - - AZ::u32 externalMipCount = 0; - if (imageObj->GetNumPersistentMips() < imageObj->GetMipCount()) - { - externalMipCount = imageObj->GetMipCount() - imageObj->GetNumPersistentMips(); - } - //load other mips from files with number extensions - for (AZ::u32 mipIdx = 1; mipIdx <= externalMipCount; mipIdx++) - { - AZ::u32 mip = externalMipCount - mipIdx; - AZStd::string mipFileName = AZStd::string::format("%s.%d%s", baseName.c_str(), mipIdx, isAlphaImage?"a":""); - - AZ::IO::SystemFile mipFile; - mipFile.Open(mipFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream mipFileLoadStream(&mipFile, true); - - if (!mipFileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open mip file %s", __FUNCTION__, mipFileName.c_str()); - break; - } - - AZ::u32 pitch; - AZ::u8* mem; - imageObj->GetImagePointer(mip, mem, pitch); - AZ::u32 bufSize = imageObj->GetMipBufSize(mip); - mipFileLoadStream.Read(bufSize, mem); - } - } - - return imageObj; - } - - IImageObject* LoadImageFromDdsFile(AZ::IO::SystemFileStream& fileLoadStream) - { - if (fileLoadStream.GetLength() - fileLoadStream.GetCurPos() < sizeof(DDS_FILE_DESC)) - { - AZ_Error("Image Processing", false, "%s: Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - DDS_FILE_DESC desc; - DDS_HEADER_DXT10 exthead; - - AZ::IO::SizeType startPos = fileLoadStream.GetCurPos(); - fileLoadStream.Read(sizeof(desc.dwMagic), &desc.dwMagic); - - if (desc.dwMagic != FOURCC_DDS) - { - desc.dwMagic = FOURCC_DDS; - //the old cry .a file doesn't have "DDS " in the beginning of the file. - //so reset to previous position - fileLoadStream.Seek(startPos, AZ::IO::GenericStream::ST_SEEK_BEGIN); - } - - fileLoadStream.Read(sizeof(desc.header), &desc.header); - - if (!desc.IsValid()) - { - AZ_Error("Image Processing", false, "%s: Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - if (desc.header.IsDX10Ext()) - { - fileLoadStream.Read(sizeof(exthead), &exthead); - } - - IImageObject* outImage = CreateImageFromHeader(desc.header, exthead); - - if (outImage == nullptr) - { - return nullptr; - } - - //load mip data - AZ::u32 mipStart = 0; - //There are at least three lowest mips are in the file if it was splitted. This is to load splitted dds file exported by legacy rc.exe - int numPersistentMips = outImage->GetNumPersistentMips(); - if (numPersistentMips == 0 && outImage->HasImageFlags(EIF_Splitted)) - { - outImage->SetNumPersistentMips(3); - } - - if (outImage->HasImageFlags(EIF_Splitted) - && outImage->GetMipCount() > outImage->GetNumPersistentMips()) - { - mipStart = outImage->GetMipCount() - outImage->GetNumPersistentMips(); - } - - AZ::u32 faces = 1; - if (outImage->HasImageFlags(EIF_Cubemap)) - { - faces = 6; - } - - for (AZ::u32 face = 0; face < faces; face++) - { - for (AZ::u32 mip = mipStart; mip < outImage->GetMipCount(); ++mip) - { - AZ::u32 pitch; - AZ::u8* mem; - outImage->GetImagePointer(mip, mem, pitch); - AZ::u32 faceBufSize = outImage->GetMipBufSize(mip) / faces; - fileLoadStream.Read(faceBufSize, mem + faceBufSize*face); - } - } - - return outImage; - } - - IImageObject* LoadAttachedImageFromDdsFile(const AZStd::string& filename, IImageObjectPtr originImage) - { - if (originImage == nullptr) - { - return nullptr; - } - - AZ_Assert(originImage->HasImageFlags(EIF_AttachedAlpha), - "this function should only be called for origin image loaded from same file with attached alpha flag"); - - AZ::IO::SystemFile file; - file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream fileLoadStream(&file, true); - if (!fileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open file %s", __FUNCTION__, filename.c_str()); - return nullptr; - } - - DDS_FILE_DESC desc; - DDS_HEADER_DXT10 exthead; - - fileLoadStream.Read(sizeof(desc), &desc); - if (desc.dwMagic != FOURCC_DDS) - { - AZ_Error("Image Processing", false, "%s:Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - if (desc.header.IsDX10Ext()) - { - fileLoadStream.Read(sizeof(exthead), &exthead); - } - - //skip size for originImage's mip data - for (AZ::u32 mip = 0; mip < originImage->GetMipCount(); ++mip) - { - AZ::u32 bufSize = originImage->GetMipBufSize(mip); - fileLoadStream.Seek(bufSize, AZ::IO::GenericStream::ST_SEEK_CUR); - } - - IImageObject* alphaImage = nullptr; - - AZ::u32 marker = 0; - fileLoadStream.Read(4, &marker); - if (marker == FOURCC_CExt) // marker for the start of Crytek Extended data - { - fileLoadStream.Read(4, &marker); - if (FOURCC_AttC == marker) // Attached Channel chunk - { - AZ::u32 size = 0; - fileLoadStream.Read(4, &size); - - alphaImage = LoadImageFromDdsFile(fileLoadStream); - fileLoadStream.Read(4, &marker); - } - - if (FOURCC_CEnd == marker ) // marker for the end of Crytek Extended data - { - fileLoadStream.Read(4, &marker); - } - } - - return alphaImage; - } - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.h b/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.h deleted file mode 100644 index e6f40dac2e..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageObjectImpl.h +++ /dev/null @@ -1,199 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include - -namespace ImageProcessing -{ - // ImageObject allows the abstraction of different kinds of - // images generated during conversion - class CImageObject: public IImageObject - { - public: - AZ_CLASS_ALLOCATOR(CImageObject, AZ::SystemAllocator, 0); - - public: - // Constructors - CImageObject(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat); - ~CImageObject(); - - //virtual functions from IImageObject - IImageObject* AllocateImage(EPixelFormat pixelFormat) const override; - IImageObject* AllocateImage() const override; - IImageObject* Clone() const override; - EPixelFormat GetPixelFormat() const override; - AZ::u32 GetPixelCount(AZ::u32 mip) const override; - AZ::u32 GetWidth(AZ::u32 mip) const override; - AZ::u32 GetHeight(AZ::u32 mip) const override; - AZ::u32 GetMipCount() const override; - bool IsCubemap() const override - { - return false; - }; - - void GetImagePointer(AZ::u32 mip, AZ::u8*& pMem, AZ::u32& pitch) const override; - AZ::u32 GetMipBufSize(AZ::u32 mip) const override; - void SetMipData(AZ::u32 mip, AZ::u8* mipBuf, AZ::u32 bufSize, AZ::u32 pitch) override; - - AZ::u32 GetImageFlags() const override; - void SetImageFlags(AZ::u32 imageFlags) override; - void AddImageFlags(AZ::u32 imageFlags) override; - void RemoveImageFlags(AZ::u32 imageFlags) override; - bool HasImageFlags(AZ::u32 imageFlags) const override; - - //image data operations and calculations - void ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias) override; - void ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max) override; - - void TransferAlphaCoverage(const TextureSettings* textureSetting, const IImageObjectPtr srcImg) override; - float ComputeAlphaCoverageScaleFactor(AZ::u32 mip, float fDesiredCoverage, float fAlphaRef) const override; - float ComputeAlphaCoverage(AZ::u32 firstMip, float fAlphaRef) const override; - - bool CompareImage(const IImageObjectPtr otherImage) const override; - - bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const override; - bool SaveImage(AZ::IO::SystemFileStream& out) const override; - bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const override; - - uint GetTextureMemory() const override; - - EAlphaContent GetAlphaContent() const override; - - void NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount) override; - - void CopyPropertiesFrom(const IImageObjectPtr src) override; - - void Swizzle(const char channels[4]) override; - - void GetColorRange(AZ::Color& minColor, AZ::Color& maxColor) const override; - void SetColorRange(const AZ::Color& minColor, const AZ::Color& maxColor) override; - float GetAverageBrightness() const override; - void SetAverageBrightness(float avgBrightness) override; - AZ::u32 GetNumPersistentMips() const override; - void SetNumPersistentMips(AZ::u32 nMips) override; - - void GlossFromNormals(bool hasAuthoredGloss) override; - void ConvertLegacyGloss() override; - void ClearColor(float r, float g, float b, float a) override; - //end virtual functions from IImageObject - - private: - - enum EColorNormalization - { - eColorNormalization_Normalize, - eColorNormalization_PassThrough, - }; - - enum EAlphaNormalization - { - eAlphaNormalization_SetToZero, - eAlphaNormalization_Normalize, - eAlphaNormalization_PassThrough, - }; - - private: - class MipLevel - { - public: - AZ_CLASS_ALLOCATOR(MipLevel, AZ::SystemAllocator, 0); - - AZ::u32 m_width; - AZ::u32 m_height; - AZ::u32 m_rowCount; // for compressed textures m_rowCount is usually less than m_height - AZ::u32 m_pitch; // row size in bytes - AZ::u8* m_pData; - - public: - MipLevel() - : m_width(0) - , m_height(0) - , m_rowCount(0) - , m_pitch(0) - , m_pData(0) - { - } - - ~MipLevel() - { - delete[] m_pData; - m_pData = 0; - } - - void Alloc() - { - AZ_Assert(m_pData == 0, "Mip data must be empty before Allocation!"); - m_pData = new AZ::u8[m_pitch * m_rowCount]; - } - - AZ::u32 GetSize() const - { - AZ_Assert(m_pitch, "Pitch must be greater than zero!"); - return m_pitch * m_rowCount; - } - - bool operator==(const MipLevel& other) - { - if (m_width == other.m_width && m_height == other.m_height - && m_rowCount == other.m_rowCount && m_pitch == other.m_pitch) - { - return (memcmp(m_pData, other.m_pData, m_pitch * m_rowCount) == 0); - } - return false; - } - }; - - private: - EPixelFormat m_pixelFormat; - std::vector m_mips; // stores *pointers* to avoid reallocations when elements are erase()'d - - AZ::Color m_colMinARGB; // ARGB will be added the properties of the DDS file - AZ::Color m_colMaxARGB; // ARGB will be added the properties of the DDS file - float m_averageBrightness; // will be added to the properties of the DDS file - AZ::u32 m_imageFlags; // combined from CImageExtensionHelper::EIF_Cubemap,... - AZ::u32 m_numPersistentMips; // number of mipmaps won't be splitted - - public: - //reset this image object to specified format and size - void ResetImage(AZ::u32 width, AZ::u32 height, AZ::u32 maxMipCount, EPixelFormat pixelFormat); - - //get mip count and the origin (top mip) size - void GetExtent(AZ::u32& width, AZ::u32& height, AZ::u32& mipCount) const; - - AZ::u32 GetMipDataSize(AZ::u32 mip) const; - - //! calculates the average brightness for a texture - float CalculateAverageBrightness() const; - - bool HasPowerOfTwoSizes() const override; - - void CopyPropertiesFrom(const CImageObject* src); - - // Computes the dynamically used range for the texture and expands it to use the - // full range [0,2^(2^ExponentBits-1)] for better quality. - void NormalizeImageRange(EColorNormalization eColorNorm, EAlphaNormalization eAlphaNorm, bool bMaintainBlack = false, int nExponentBits = 0); - // Brings normalized ranges back to it's original range. - void ExpandImageRange(EColorNormalization eColorNorm, EAlphaNormalization eAlphaNorm, int nExponentBits = 0); - - private: - //build image file header from this image object - bool BuildSurfaceHeader(DDS_HEADER& header) const; - bool BuildSurfaceExtendedHeader(DDS_HEADER_DXT10& exthead) const; - }; - -} // namespace ImageProcessing - - diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.cpp b/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.cpp deleted file mode 100644 index 09085540a9..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - - -namespace ImageProcessing -{ - - ImagePreview::ImagePreview(const AZStd::string& inputImageFile, TextureSettings* textureSetting) - : m_imageFileName(inputImageFile) - , m_textureSetting(textureSetting) - , m_presetSetting(nullptr) - , m_inputImage(nullptr) - { - InitializeJobSettings(); - } - - void ImagePreview::StartConvert() - { - // If there is ongoing job, cancel it - Cancel(); - m_output.Reset(); - if (m_inputImage == nullptr) - { - // Load input image - m_inputImage = IImageObjectPtr(LoadImageFromFile(m_imageFileName)); - } - // Get preset if the setting in texture is changed - if (m_presetSetting == nullptr || m_presetSetting->m_uuid != m_textureSetting->m_preset) - { - m_presetSetting = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset); - } - const bool isPreview = true; - const bool autoDelete = false; - PlatformName defaultPlatform = BuilderSettingManager::s_defaultPlatform; - - m_convertJob = AZStd::make_unique(m_inputImage, m_textureSetting, m_presetSetting, - isPreview, defaultPlatform, &m_output, autoDelete, m_jobContext.get()); - m_convertJob->SetDependent(&m_doneJob); - m_convertJob->Start(); - } - - bool ImagePreview::IsDone() - { - return m_output.IsReady(); - } - - float ImagePreview::GetProgress() - { - if (!m_output.IsReady()) - { - return m_output.GetProgress(); - } - return 1.0f; - } - - void ImagePreview::Cancel() - { - if (m_convertJob) - { - m_convertJob->Cancel(); - // Block until job completes - m_doneJob.StartAndWaitForCompletion(); - - AZ_Assert(m_output.IsReady(), "Conversion job is not done yet!"); - } - m_convertJob.release(); - m_doneJob.Reset(true); - } - - IImageObjectPtr ImagePreview::GetOutputImage() - { - return m_output.GetOutputImage(ImageConvertOutput::Preview); - } - - ImagePreview::~ImagePreview() - { - Cancel(); - // Maintain the releasing order - m_jobManager.release(); - m_jobContext.release(); - m_jobCancelGroup.release(); - } - - void ImagePreview::InitializeJobSettings() - { - AZ::JobManagerDesc desc; - AZ::JobManagerThreadDesc threadDesc; - desc.m_workerThreads.push_back(threadDesc); - // Check to ensure these have not already been initialized. - AZ_Error("Image Processing", !m_jobManager && !m_jobCancelGroup && !m_jobContext, "ImagePreview::InitializeJobSettings is being called again after it has already been initialized"); - m_jobManager = AZStd::make_unique(desc); - m_jobCancelGroup = AZStd::make_unique(); - m_jobContext = AZStd::make_unique(*m_jobManager, *m_jobCancelGroup); - - new (&m_doneJob) AZ::JobCompletion(m_jobContext.get()); //re-initialize with the job context - } - - - void GetImageInfoString(IImageObjectPtr image, bool isAlpha, AZStd::string& output) - { - if (!image) - { - return; - } - - CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - EPixelFormat format = image->GetPixelFormat(); - const PixelFormatInfo* info = pixelFormats.GetPixelFormatInfo(format); - if (info) - { - output += AZStd::string::format("Format: %s\r\n", info->szName); - } - - AZ::u32 mipCount = image->GetMipCount(); - output += AZStd::string::format("Mip Count: %d\r\n", mipCount); - - AZ::u32 memSize = image->GetTextureMemory(); - AZStd::string memSizeString = ImageProcessingEditor::EditorHelper::GetFileSizeString(memSize); - output += AZStd::string::format("Memory Size: %s\r\n", memSizeString.c_str()); - - if (!isAlpha) - { - if (image->HasImageFlags(EIF_SRGBRead)) - { - output += "Color Space: sRGB\r\n"; - } - else - { - output += "Color Space: Linear\r\n"; - } - - if (image->HasImageFlags(EIF_Cubemap)) - { - output += "Cubemap\r\n"; - } - } - - AZ::u32 imageFlag = image->GetImageFlags(); - output += AZStd::string::format("Image Flag: 0x%08x\r\n", imageFlag); - } - - bool ImagePreview::GetProductTexturePreview(const char* fullProductFileName, QImage& previewImage, AZStd::string& productInfo, AZStd::string& productAlphaInfo) - { - if (!AzFramework::StringFunc::Path::IsExtension(fullProductFileName, "dds", false)) - { - return false; - } - - IImageObjectPtr originImage = IImageObjectPtr(LoadImageFromDdsFile(fullProductFileName)); - IImageObjectPtr alphaImage; - - if (originImage && originImage->HasImageFlags(EIF_AttachedAlpha)) - { - if (originImage->HasImageFlags(EIF_Splitted)) - { - AZStd::string alphaFileName = AZStd::string::format("%s.a", fullProductFileName); - alphaImage = IImageObjectPtr(LoadImageFromDdsFile(alphaFileName)); - - } - else - { - alphaImage = IImageObjectPtr(LoadAttachedImageFromDdsFile(fullProductFileName, originImage)); - } - } - - GetImageInfoString(originImage, false, productInfo); - GetImageInfoString(alphaImage, true, productAlphaInfo); - - IImageObjectPtr combinedImage = MergeOutputImageForPreview(originImage, alphaImage); - if (combinedImage) - { - AZ::u8* imageBuf; - AZ::u32 pitch; - combinedImage->GetImagePointer(0, imageBuf, pitch); - const AZ::u32 width = originImage->GetWidth(0); - const AZ::u32 height = originImage->GetHeight(0); - QImage result = QImage(imageBuf, width, height, pitch, QImage::Format_RGBA8888); - previewImage = result.copy(); // Return a deep copy here - return true; - } - - return false; - } - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.h b/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.h deleted file mode 100644 index 25be5ed37c..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImagePreview.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include - -namespace ImageProcessing -{ - // The reason to have image preview class, we should keep the source image loaded once, - // we could restart conversion and cancel the old conversion at anytime when setting changed - class ImagePreview - { - public: - ImagePreview(const AZStd::string& inputImageFile, TextureSettings* textureSetting); - ~ImagePreview(); - - void InitializeJobSettings(); - void StartConvert(); - bool IsDone(); - float GetProgress(); - void Cancel(); - IImageObjectPtr GetOutputImage(); - - // Output preview image for Asset Browser - static bool GetProductTexturePreview(const char* fullProductFileName, QImage& previewImage, AZStd::string& productInfo, AZStd::string& productAlphaInfo); - - private: - AZStd::string m_imageFileName; - IImageObjectPtr m_inputImage; - const TextureSettings* m_textureSetting; - const PresetSettings* m_presetSetting; - - IImageObjectPtr m_outputImage; - IImageObjectPtr m_outputAlphaImage; - - ImageConvertOutput m_output; - - AZStd::unique_ptr m_jobManager; - AZStd::unique_ptr m_jobCancelGroup; - AZStd::unique_ptr m_jobContext; - AZStd::unique_ptr m_convertJob; - AZ::JobCompletion m_doneJob; - }; - - // Get basic image info as string - void GetImageInfoString(IImageObjectPtr image, bool isAlpha, AZStd::string& output); - -}// namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/ImageToProcess.h b/Gems/ImageProcessing/Code/Source/Processing/ImageToProcess.h deleted file mode 100644 index 080fd602e8..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/ImageToProcess.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include -#include -#include - -namespace ImageProcessing -{ - - //cubemap layouts - enum CubemapLayoutType - { - CubemapLayoutHorizontal = 0, //6x1 strip. with rotations. - CubemapLayoutHorizontalCross, //4x3. - CubemapLayoutVerticalCross, //3x4 - CubemapLayoutVertical, //1x6 strip. new output format. it's better because the memory is continuous for each face - CubemapLayoutTypeCount, - CubemapLayoutNone = CubemapLayoutTypeCount - }; - - class ImageToProcess - { - private: - IImageObjectPtr m_img; - ICompressor::CompressOption m_compressOption; - - private: - ImageToProcess(const ImageToProcess&); - - public: - ImageToProcess(IImageObjectPtr img) - { - m_img = img; - } - - ~ImageToProcess() - { - } - - void Set(IImageObjectPtr img) - { - m_img = img; - } - - IImageObjectPtr Get() const - { - return m_img; - } - - ICompressor::CompressOption& GetCompressOption() - { - return m_compressOption; - } - - void SetCompressOption(const ICompressor::CompressOption& compressOption) - { - m_compressOption = compressOption; - } - - public: - // --------------------------------------------------------------------------------- - //! can be used to compress, requires a preset - void ConvertFormat(EPixelFormat fmtTo); - void ConvertFormatUncompressed(EPixelFormat fmtTo); - - // --------------------------------------------------------------------------------- - // Arguments: - // bDeGamma - apply de-gamma correction - bool GammaToLinearRGBA32F(bool bDeGamma); - void LinearToGamma(); - - // --------------------------------------------------------------------------------- - // Resizers for A32B32G32R32F - - // Prerequisites: image width is even, ARGB32F only, no mips. - void DownscaleTwiceHorizontally(); - - // Prerequisites: height is even, ARGB32F only, no mips. - void DownscaleTwiceVertically(); - - // Prerequisites: width is pow of 2, ARGB32F only, no mips. - void UpscalePow2TwiceHorizontally(); - - // Prerequisites: height is pow of 2, ARGB32F only, no mips. - void UpscalePow2TwiceVertically(); - - // --------------------------------------------------------------------------------- - // Tools for A32B32G32R32F - - // input needs to be in range 0..1 - void AddNormalMap(const IImageObject* pAddBump); - - void CreateHighPass(uint32 dwMipDown); - - void CreateColorChart(); - - //convert various original cubemap layouts to new layout - bool ConvertCubemapLayout(CubemapLayoutType newLayout); - - }; -}// namespace ImageProcessing - diff --git a/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.cpp b/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.cpp deleted file mode 100644 index 3bfa371dc0..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include - -namespace ImageProcessing -{ - CPixelFormats* CPixelFormats::s_instance = nullptr; - - CPixelFormats& CPixelFormats::GetInstance() - { - if (s_instance == nullptr) - { - s_instance = new CPixelFormats(); - } - - return *s_instance; - } - - void CPixelFormats::DestroyInstance() - { - delete s_instance; - s_instance = nullptr; - } - - PixelFormatInfo::PixelFormatInfo( - int a_bitsPerPixel, - int a_Channels, - bool a_Alpha, - const char* a_szAlpha, - uint32 a_minWidth, - uint32 a_minHeight, - int a_blockWidth, - int a_blockHeight, - int a_bitsPerBlock, - bool a_bSquarePow2, - DXGI_FORMAT a_d3d10Format, - AZ::u32 a_fourCC, - ESampleType a_eSampleType, - const char* a_szName, - const char* a_szDescription, - bool a_bCompressed, - bool a_bSelectable) - : nChannels(a_Channels) - , bHasAlpha(a_Alpha) - , minWidth(a_minWidth) - , minHeight(a_minHeight) - , blockWidth(a_blockWidth) - , blockHeight(a_blockHeight) - , bitsPerBlock(a_bitsPerBlock) - , bSquarePow2(a_bSquarePow2) - , szAlpha(a_szAlpha) - , d3d10Format(a_d3d10Format) - , fourCC(a_fourCC) - , eSampleType(a_eSampleType) - , szName(a_szName) - , szLegacyName(a_szName) - , szDescription(a_szDescription) - , bCompressed(a_bCompressed) - , bSelectable(a_bSelectable) - { - //validate pixel format - //a_bitsPerPixel could be 0 if it's ACTC format since the actual bits per-pixel could be 6.4, 5.12 etc. - if (a_bitsPerPixel) - { - AZ_Assert(a_bitsPerPixel * blockWidth * blockHeight == bitsPerBlock, "PixelFormatInfo: Wrong block setting"); - } - - AZ_Assert(szName, "szName can't be nullptr"); - AZ_Assert(nChannels > 0 && nChannels <= 4, "unreasonable channel count %d", nChannels); - AZ_Assert(a_szDescription, "szDescription can't be nullptr"); - AZ_Assert(blockWidth > 0 && blockHeight > 0, "blcok size need to be larger than 0: %d x %d", blockWidth, blockHeight); - AZ_Assert(minWidth > 0 && minHeight > 0, "piexel required mininum image size need to be larger than 0: %d x %d", minWidth, minHeight); - if (!bCompressed) - { - AZ_Assert(blockWidth == 1 && blockHeight == 1, "Uncompressed format shouldn't have block which size > 1"); - } - } - - CPixelFormats::CPixelFormats() - { - InitPixelFormats(); - - m_removedLegacyFormats["DXT1"] = ePixelFormat_BC1; - m_removedLegacyFormats["DXT1a"] = ePixelFormat_BC1a; - m_removedLegacyFormats["DXT3"] = ePixelFormat_BC3; - m_removedLegacyFormats["DXT3t"] = ePixelFormat_BC3t; - m_removedLegacyFormats["DXT5"] = ePixelFormat_BC3; - m_removedLegacyFormats["DXT5t"] = ePixelFormat_BC3t; - m_removedLegacyFormats["3DCp"] = ePixelFormat_BC4; - m_removedLegacyFormats["3DC"] = ePixelFormat_BC5; - } - - void CPixelFormats::InitPixelFormat(EPixelFormat format, const PixelFormatInfo& formatInfo) - { - AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format); - - if (m_pixelFormatInfo[format].szName && m_pixelFormatNameMap.find(formatInfo.szName) != m_pixelFormatNameMap.end()) - { - // double initialization - AZ_Assert(false, "Pixel format already exist: %s", m_pixelFormatInfo[format].szName); - } - m_pixelFormatNameMap[formatInfo.szName] = format; - m_pixelFormatInfo[format] = formatInfo; - } - - void CPixelFormats::InitPixelFormats() - { - // Unsigned Formats - // Data in an unsigned format must be positive. Unsigned formats use combinations of - // (R)ed, (G)reen, (B)lue, (A)lpha, (L)uminance - InitPixelFormat(ePixelFormat_R8G8B8A8, PixelFormatInfo(32, 4, true, "8", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R8G8B8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8B8A8", "32-bit RGBA pixel format with alpha, using 8 bits per channel", false, true)); - InitPixelFormat(ePixelFormat_R8G8B8X8, PixelFormatInfo(32, 4, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R8G8B8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8B8X8", "32-bit RGB pixel format, where 8 bits are reserved for each color", false, true)); - InitPixelFormat(ePixelFormat_R8G8, PixelFormatInfo(16, 2, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R8G8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8", "16-bit red/green, using 8 bits per channel", false, false)); - InitPixelFormat(ePixelFormat_R8, PixelFormatInfo( 8, 1, false, "0", 1, 1, 1, 1, 8, false, DXGI_FORMAT_R8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8", "8-bit red only", false, false)); - InitPixelFormat(ePixelFormat_A8, PixelFormatInfo( 8, 1, true, "8", 1, 1, 1, 1, 8, false, DXGI_FORMAT_A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "A8", "8-bit alpha only", false, true)); - InitPixelFormat(ePixelFormat_R16G16B16A16, PixelFormatInfo(64, 4, true, "16", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R16G16B16A16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16G16B16A16", "64-bit ARGB pixel format with alpha, using 16 bits per channel", false, false)); - InitPixelFormat(ePixelFormat_R16G16, PixelFormatInfo(32, 2, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R16G16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16G16", "32-bit red/green, using 16 bits per channel", false, false)); - InitPixelFormat(ePixelFormat_R16, PixelFormatInfo(16, 1, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16", "16-bit red only", false, false)); - - // Custom FourCC Formats - // Data in these FourCC formats is custom compressed data and only decodable by certain hardware. - InitPixelFormat(ePixelFormat_ASTC_4x4, PixelFormatInfo(0, 4, true, "?", 16, 16, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_4x4, ESampleType::eSampleType_Compressed, "ASTC_4x4", "ASTC 4x4 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_5x4, PixelFormatInfo(0, 4, true, "?", 16, 16, 5, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_5x4, ESampleType::eSampleType_Compressed, "ASTC_5x4", "ASTC 5x4 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_5x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 5, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_5x5, ESampleType::eSampleType_Compressed, "ASTC_5x5", "ASTC 5x5 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_6x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 6, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_6x5, ESampleType::eSampleType_Compressed, "ASTC_6x5", "ASTC 6x5 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_6x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 6, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_6x6, ESampleType::eSampleType_Compressed, "ASTC_6x6", "ASTC 6x6 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_8x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x5, ESampleType::eSampleType_Compressed, "ASTC_8x5", "ASTC 8x5 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_8x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x6, ESampleType::eSampleType_Compressed, "ASTC_8x6", "ASTC 8x6 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_8x8, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 8, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x8, ESampleType::eSampleType_Compressed, "ASTC_8x8", "ASTC 8x8 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_10x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x5, ESampleType::eSampleType_Compressed, "ASTC_10x5", "ASTC 10x5 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_10x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x6, ESampleType::eSampleType_Compressed, "ASTC_10x6", "ASTC 10x6 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_10x8, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 8, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x8, ESampleType::eSampleType_Compressed, "ASTC_10x8", "ASTC 10x8 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_10x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x10, ESampleType::eSampleType_Compressed, "ASTC_10x10", "ASTC 10x10 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_12x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x10, ESampleType::eSampleType_Compressed, "ASTC_12x10", "ASTC 12x10 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ASTC_12x12, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 12, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x12, ESampleType::eSampleType_Compressed, "ASTC_12x12", "ASTC 12x12 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_PVRTC2, PixelFormatInfo(2, 4, true, "2", 16, 16, 8, 4, 64, true, DXGI_FORMAT_UNKNOWN, FOURCC_PVRTC2, ESampleType::eSampleType_Compressed, "PVRTC2", "POWERVR 2 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_PVRTC4, PixelFormatInfo(4, 4, true, "2", 8, 8, 4, 4, 64, true, DXGI_FORMAT_UNKNOWN, FOURCC_PVRTC4, ESampleType::eSampleType_Compressed, "PVRTC4", "POWERVR 4 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_EAC_R11, PixelFormatInfo(4, 1, true, "4", 4, 4, 4, 4, 64, false, DXGI_FORMAT_UNKNOWN, FOURCC_EAC_R11, ESampleType::eSampleType_Compressed, "EAC_R11", "EAC 4 bpp single channel texture format", true, false)); - InitPixelFormat(ePixelFormat_EAC_RG11, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_EAC_RG11, ESampleType::eSampleType_Compressed, "EAC_RG11", "EAC 8 bpp dual channel texture format", true, false)); - InitPixelFormat(ePixelFormat_ETC2, PixelFormatInfo(4, 3, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_UNKNOWN, FOURCC_ETC2, ESampleType::eSampleType_Compressed, "ETC2", "ETC2 RGB 4 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ETC2a, PixelFormatInfo(8, 4, true, "4", 4, 4, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ETC2A, ESampleType::eSampleType_Compressed, "ETC2a", "ETC2 RGBA 8 bpp compressed texture format", true, false)); - - // Standardized Compressed DXGI Formats (DX10+) - // Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API. - InitPixelFormat(ePixelFormat_BC1, PixelFormatInfo(4, 3, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC1_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC1", "BC1 compressed texture format", true, true)); - InitPixelFormat(ePixelFormat_BC1a, PixelFormatInfo(4, 4, true, "1", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC1_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC1a", "BC1a compressed texture format with transparency", true, true)); - InitPixelFormat(ePixelFormat_BC3, PixelFormatInfo(8, 4, true, "3of8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC3_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC3", "BC3 compressed texture format", true, true)); - InitPixelFormat(ePixelFormat_BC3t, PixelFormatInfo(8, 4, true, "3of8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC3_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC3t", "BC3t compressed texture format with transparency", true, true)); - InitPixelFormat(ePixelFormat_BC4, PixelFormatInfo(4, 1, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC4_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC4", "BC4 compressed texture format for single channel maps. 3DCp", true, true)); - InitPixelFormat(ePixelFormat_BC4s, PixelFormatInfo(4, 1, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC4_SNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC4s", "BC4 compressed texture format for signed single channel maps", true, true)); - InitPixelFormat(ePixelFormat_BC5, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC5_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC5", "BC5 compressed texture format for two channel maps or normalmaps. 3DC", true, true)); - InitPixelFormat(ePixelFormat_BC5s, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC5_SNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC5s", "BC5 compressed texture format for signed two channel maps or normalmaps", true, true)); - InitPixelFormat(ePixelFormat_BC6UH, PixelFormatInfo(8, 3, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC6H_UF16, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC6UH", "BC6 compressed texture format, unsigned half", true, true)); - InitPixelFormat(ePixelFormat_BC7, PixelFormatInfo(8, 4, true, "8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC7_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC7", "BC7 compressed texture format", true, true)); - InitPixelFormat(ePixelFormat_BC7t, PixelFormatInfo(8, 4, true, "8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC7_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC7t", "BC7t compressed texture format with transparency", true, true)); - - // Float formats - // Data in a Float format is floating point data. - InitPixelFormat(ePixelFormat_R9G9B9E5, PixelFormatInfo(32, 3, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, FOURCC_DX10, ESampleType::eSampleType_Compressed, "R9G9B9E5", "32-bit RGB pixel format with shared exponent", false, true)); - InitPixelFormat(ePixelFormat_R32G32B32A32F, PixelFormatInfo(128, 4, true, "23", 1, 1, 1, 1, 128, false, DXGI_FORMAT_R32G32B32A32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32G32B32A32F", "four float channels", false, false)); - InitPixelFormat(ePixelFormat_R32G32F, PixelFormatInfo(64, 2, false, "0", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R32G32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32G32F", "two float channels", false, false)); // FIXME: This should be eTF_R32G32F, but CryTek did not add that enum to ITexture.h yet - InitPixelFormat(ePixelFormat_R32F, PixelFormatInfo(32, 1, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32F", "one float channel", false, false)); - InitPixelFormat(ePixelFormat_R16G16B16A16F, PixelFormatInfo(64, 4, true, "10", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R16G16B16A16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16G16B16A16F", "four half channels", false, false)); - InitPixelFormat(ePixelFormat_R16G16F, PixelFormatInfo(32, 2, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R16G16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16G16F", "two half channel", false, false)); - InitPixelFormat(ePixelFormat_R16F, PixelFormatInfo(16, 1, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16F", "one half channel", false, false)); - - //legacy BGRA8 - InitPixelFormat(ePixelFormat_B8G8R8A8, PixelFormatInfo(32, 4, true, "8", 1, 1, 1, 1, 32, false, DXGI_FORMAT_B8G8R8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "B8G8R8A8", "32-bit BGRA pixel format with alpha, using 8 bits per channel", false, true)); - - InitPixelFormat(ePixelFormat_R32, PixelFormatInfo(32, 1, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_FORCE_UINT, FOURCC_DX10, ESampleType::eSampleType_Uint32, "R32", "32-bit red only", false, false)); - - //Set legacy name it can be used for convertion - m_pixelFormatInfo[ePixelFormat_R8G8B8A8].szLegacyName = "A8R8G8B8"; - m_pixelFormatInfo[ePixelFormat_R8G8B8X8].szLegacyName = "X8R8G8B8"; - m_pixelFormatInfo[ePixelFormat_R8G8].szLegacyName = "G8R8"; - m_pixelFormatInfo[ePixelFormat_R16G16B16A16].szLegacyName = "A16B16G16R16"; - m_pixelFormatInfo[ePixelFormat_R16G16].szLegacyName = "G16R16"; - m_pixelFormatInfo[ePixelFormat_R32G32B32A32F].szLegacyName = "A32B32G32R32F"; - m_pixelFormatInfo[ePixelFormat_R32G32F].szLegacyName = "G32R32F"; - m_pixelFormatInfo[ePixelFormat_R16G16B16A16F].szLegacyName = "A16B16G16R16F"; - m_pixelFormatInfo[ePixelFormat_R16G16F].szLegacyName = "G16R16F"; - - //validate all pixel formats are proper initialized - for (int i = 0; i < ePixelFormat_Count; ++i) - { - if (m_pixelFormatInfo[i].szName == 0) - { - // Uninitialized entry. Should never happen. But, if it happened: make sure that entries from - // the EPixelFormat enum and InitPixelFormat() calls match. - AZ_Assert(false, "InitPixelFormats error: not all pixel formats have an implementation."); - } - } - } - - - EPixelFormat CPixelFormats::FindPixelFormatByName(const char* name) - { - if (m_pixelFormatNameMap.find(name) != m_pixelFormatNameMap.end()) - { - return m_pixelFormatNameMap[name]; - } - return ePixelFormat_Unknown; - } - - EPixelFormat CPixelFormats::FindPixelFormatByLegacyName(const char* name) - { - if (m_removedLegacyFormats.find(name) != m_removedLegacyFormats.end()) - { - return m_removedLegacyFormats[name]; - } - - for (int i = 0; i < ePixelFormat_Count; ++i) - { - if (azstricmp(m_pixelFormatInfo[i].szLegacyName, name) == 0) - { - return (EPixelFormat)i; - } - } - return ePixelFormat_Unknown; - } - - const PixelFormatInfo* CPixelFormats::GetPixelFormatInfo(EPixelFormat format) - { - AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format); - return &m_pixelFormatInfo[format]; - } - - bool CPixelFormats::IsPixelFormatUncompressed(EPixelFormat format) - { - AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format); - return !m_pixelFormatInfo[format].bCompressed; - } - - bool CPixelFormats::IsPixelFormatWithoutAlpha(EPixelFormat format) - { - AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format); - return !m_pixelFormatInfo[format].bHasAlpha; - } - - uint32 CPixelFormats::ComputeMaxMipCount(EPixelFormat format, uint32 width, uint32 height) - { - const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format); - - AZ_Assert(pFormatInfo != nullptr, "ComputeMaxMipCount: unsupport pixel format %d", format); - - uint32 tmpWidth = width; - uint32 tmpHeight = height; - - bool bIgnoreBlockSize = CanImageSizeIgnoreBlockSize(format); - - uint32 mipCountW = 0; - while ((tmpWidth >= pFormatInfo->minWidth) && (bIgnoreBlockSize || (tmpWidth % pFormatInfo->blockWidth == 0))) - { - ++mipCountW; - tmpWidth >>= 1; - } - - uint32 mipCountH = 0; - while ((tmpHeight >= pFormatInfo->minHeight) && (bIgnoreBlockSize || (tmpHeight % pFormatInfo->blockHeight == 0))) - { - ++mipCountH; - tmpHeight >>= 1; - } - - //for compressed image, use minmum mip out of W and H because any size below won't be compressed properly - //for non-compressed image. use maximum mip count. for example the lowest two mips of 128x64 would be 2x1 and 1x1 - const uint32 mipCount = (pFormatInfo->bCompressed) - ? AZStd::min(mipCountW, mipCountH) - : AZStd::max(mipCountW, mipCountH); - - // In some cases, user may call this function for image size which is qualified for this pixel format, - // the mipCount could be 0 for those cases. Round it to 1 if it happend. - return AZStd::max((uint32)1, mipCount); - } - - bool CPixelFormats::CanImageSizeIgnoreBlockSize(EPixelFormat format) - { - // ASTC is a kind of block compression but it doesn't need the image size to be interger mutiples of block size. - // reference: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt - //"For images which are not an integer multiple of the block size, additional texels are added to the edges - // with maximum X and Y.These texels may be any color, as they will not be accessed." - bool bIgnoreBlockSize = IsASTCFormat(format); - - return bIgnoreBlockSize; - } - - bool CPixelFormats::IsImageSizeValid(EPixelFormat format, uint32 imageWidth, uint32 imageHeight, [[maybe_unused]] bool logWarning) - { - const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format); - AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format); - - //if the format requires image to be sqaure and power of 2 - if (pFormatInfo->bSquarePow2 && ((imageWidth != imageHeight) || (imageWidth & (imageWidth - 1)) != 0)) - { - AZ_Warning("ImageBuilder", !logWarning, "Image size need to be square and power of 2 for pixel format %s", - pFormatInfo->szName); - return false; - } - - // minimum size required by the pixel format - if (imageWidth < pFormatInfo->minWidth || imageHeight < pFormatInfo->minHeight) - { - AZ_Warning("ImageBuilder", !logWarning, "The image size (%dx%d) is smaller than minimum size (%dx%d) for pixel format %s", - imageWidth, imageHeight, pFormatInfo->minWidth, pFormatInfo->minHeight, pFormatInfo->szName); - return false; - } - - //check image size againest block size - if (!CanImageSizeIgnoreBlockSize(format)) - { - if (imageWidth % pFormatInfo->blockWidth != 0 || imageHeight % pFormatInfo->blockHeight != 0) - { - AZ_Warning("ImageBuilder", !logWarning, "Image size (%dx%d) need to be integer multiplier of compression block size (%dx%d) for pixel format %s", - imageWidth, imageHeight, pFormatInfo->minWidth, pFormatInfo->minHeight, pFormatInfo->szName); - return false; - } - } - - return true; - } - - AZ::u32 NextPowOf2(AZ::u32 value) - { - value--; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value++; - return value; - } - - void CPixelFormats::GetSuitableImageSize(EPixelFormat format, AZ::u32 imageWidth, AZ::u32 imageHeight, - AZ::u32& outWidth, AZ::u32& outHeight) - { - const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format); - AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format); - - outWidth = imageWidth; - outHeight = imageHeight; - - // minimum size required by the pixel format - if (outWidth < pFormatInfo->minWidth) - { - outWidth = pFormatInfo->minWidth; - } - if (outHeight < pFormatInfo->minHeight) - { - outHeight = pFormatInfo->minHeight; - } - - if (pFormatInfo->bSquarePow2 && ((outWidth != outHeight) || (outWidth & (outWidth - 1)) != 0)) - { - AZ::u32 sideSide = AZ::GetMax(outWidth, outHeight); - outWidth = NextPowOf2(sideSide); - outHeight = outWidth; - } - - //check image size againest block size - //if the format requires square and power of 2. we can skip this step - if (!CanImageSizeIgnoreBlockSize(format) && !pFormatInfo->bSquarePow2) - { - if (outWidth % pFormatInfo->blockWidth != 0) - { - outWidth = ((outWidth + pFormatInfo->blockWidth -1) / pFormatInfo->blockWidth) * pFormatInfo->blockWidth; - } - if (outHeight % pFormatInfo->blockHeight != 0) - { - outHeight = ((outHeight + pFormatInfo->blockHeight - 1) / pFormatInfo->blockHeight) * pFormatInfo->blockHeight; - } - } - - } - - uint32 CPixelFormats::EvaluateImageDataSize(EPixelFormat format, uint32 imageWidth, uint32 imageHeight) - { - const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format); - AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format); - - //the image should pass IsImageSizeValid test to be eavluated correctly - if (!IsImageSizeValid(format, imageWidth, imageHeight, false)) - { - return 0; - } - - // get number of blocks (ceiling round up for block count) and multiply with bits per block. Divided by 8 to get - // final byte size - return (((imageWidth + pFormatInfo->blockWidth -1) / pFormatInfo->blockWidth) * - ((imageHeight + pFormatInfo->blockHeight - 1) / pFormatInfo->blockHeight) * pFormatInfo->bitsPerBlock) / 8; - } - - bool CPixelFormats::IsFormatSingleChannel(EPixelFormat fmt) - { - return (m_pixelFormatInfo[fmt].nChannels == 1); - } - - bool CPixelFormats::IsFormatSigned(EPixelFormat fmt) - { - // all these formats contain signed data, the FP-formats contain scale & biased unsigned data - return (fmt == ePixelFormat_BC4s || fmt == ePixelFormat_BC5s /*|| fmt == ePixelFormat_BC6SH*/); - } - - bool CPixelFormats::IsFormatFloatingPoint(EPixelFormat fmt, bool bFullPrecision) - { - // all these formats contain floating point data - if (!bFullPrecision) - { - return ((fmt == ePixelFormat_R16F || fmt == ePixelFormat_R16G16F || - fmt == ePixelFormat_R16G16B16A16F) || (fmt == ePixelFormat_BC6UH || fmt == ePixelFormat_R9G9B9E5)); - } - else - { - return ((fmt == ePixelFormat_R32F || fmt == ePixelFormat_R32G32F || fmt == ePixelFormat_R32G32B32A32F)); - } - } -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.h b/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.h deleted file mode 100644 index aee61d1a9f..0000000000 --- a/Gems/ImageProcessing/Code/Source/Processing/PixelFormatInfo.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include // DX10+ formats. DXGI_FORMAT - -#include - -#include -#include - -namespace ImageProcessing -{ - //The original implementation was from cryhalf's CryConvertFloatToHalf and CryConvertHalfToFloat function - struct SHalf - { - explicit SHalf(float floatValue) - { - AZ::u32 Result; - - AZ::u32 intValue = ((AZ::u32*)(&floatValue))[0]; - AZ::u32 Sign = (intValue & 0x80000000U) >> 16U; - intValue = intValue & 0x7FFFFFFFU; - - if (intValue > 0x47FFEFFFU) - { - // The number is too large to be represented as a half. Saturate to infinity. - Result = 0x7FFFU; - } - else - { - if (intValue < 0x38800000U) - { - // The number is too small to be represented as a normalized half. - // Convert it to a denormalized value. - AZ::u32 Shift = 113U - (intValue >> 23U); - intValue = (0x800000U | (intValue & 0x7FFFFFU)) >> Shift; - } - else - { - // Rebias the exponent to represent the value as a normalized half. - intValue += 0xC8000000U; - } - - Result = ((intValue + 0x0FFFU + ((intValue >> 13U) & 1U)) >> 13U) & 0x7FFFU; - } - h = (Result | Sign); - } - - operator float() const - { - AZ::u32 Mantissa; - AZ::u32 Exponent; - AZ::u32 Result; - - Mantissa = h & 0x03FF; - - if ((h & 0x7C00) != 0) // The value is normalized - { - Exponent = ((h >> 10) & 0x1F); - } - else if (Mantissa != 0) // The value is denormalized - { - // Normalize the value in the resulting float - Exponent = 1; - - do - { - Exponent--; - Mantissa <<= 1; - } while ((Mantissa & 0x0400) == 0); - - Mantissa &= 0x03FF; - } - else // The value is zero - { - Exponent = -112; - } - - Result = ((h & 0x8000) << 16) | // Sign - ((Exponent + 112) << 23) | // Exponent - (Mantissa << 13); // Mantissa - - return *(float*)&Result; - } - - private: - AZ::u16 h; - }; - - enum class ESampleType - { - eSampleType_Uint8, - eSampleType_Uint16, - eSampleType_Uint32, - eSampleType_Half, - eSampleType_Float, - eSampleType_Compressed, - }; - - struct PixelFormatInfo - { - - int nChannels; // channel count per pixel - bool bHasAlpha; // has alpha channel or not - const char* szAlpha; // a string of bits of alpha channel used to show brief of the pixel format - uint32 minWidth; // minimum width required for image using this pixel format - uint32 minHeight; // minimum height required for image using this pixel format - int blockWidth; // width of the block for block based compressing - int blockHeight; // Height of the block for block based compressing - int bitsPerBlock; // bits per pixel before uncompressed - bool bSquarePow2; // whether the pixel format requires image size be square and power of 2. - DXGI_FORMAT d3d10Format; // the mapping d3d10 pixel format - ESampleType eSampleType; // the data type used to present pixel - const char* szLegacyName; // name used for cryEngine - const char* szName; // name for showing in editors - const char* szDescription; // description for showing in editors - bool bCompressed; // if it's a compressed format - bool bSelectable; // shows up in the list of usable destination pixel formats in the dialog window - AZ::u32 fourCC; // fourCC to identify a none d3d10 format - - PixelFormatInfo() - : szAlpha(0) - , bitsPerBlock(-1) - , d3d10Format(DXGI_FORMAT_UNKNOWN) - , szName(0) - , szDescription(0) - , fourCC(0) - { - } - - PixelFormatInfo( - int a_bitsPerPixel, - int a_Channels, - bool a_Alpha, - const char* a_szAlpha, - uint32 a_minWidth, - uint32 a_minHeight, - int a_blockWidth, - int a_blockHeight, - int a_bitsPerBlock, - bool a_bSquarePow2, - DXGI_FORMAT a_d3d10Format, - AZ::u32 a_fourCC, - ESampleType a_eSampleType, - const char* a_szName, - const char* a_szDescription, - bool a_bCompressed, - bool a_bSelectable); - }; - - class CPixelFormats - { - public: - //singleton - static CPixelFormats& GetInstance(); - static void DestroyInstance(); - - const PixelFormatInfo* GetPixelFormatInfo(EPixelFormat format); - - bool IsPixelFormatWithoutAlpha(EPixelFormat format); - bool IsPixelFormatUncompressed(EPixelFormat format); - - //functions seems only used for BC compressions. need re-evaluate later - bool IsFormatSingleChannel(EPixelFormat fmt); - bool IsFormatSigned(EPixelFormat fmt); - bool IsFormatFloatingPoint(EPixelFormat fmt, bool bFullPrecision); - - //find the pixel format for name used by Cry's RC.ini - //returns ePixelFormat_Unknown if the name was not found in registed format list - EPixelFormat FindPixelFormatByLegacyName(const char* name); - - //find pixel format by its name - EPixelFormat FindPixelFormatByName(const char* name); - - //returns maximum lod levels for image which has certain pixel format, width and height. - uint32 ComputeMaxMipCount(EPixelFormat format, uint32 imageWidth, uint32 imageHeight); - - //check if the input image size work with the pixel format. Some compression formats have requirements with the input image size. - bool IsImageSizeValid(EPixelFormat format, uint32 imageWidth, uint32 imageHeight, bool logWarning); - - //get suitable new size for an image with certain width, height and pixel format - void GetSuitableImageSize(EPixelFormat format, AZ::u32 imageWidth, AZ::u32 imageHeight, - AZ::u32& outWidth, AZ::u32& outHeight); - - //check if the image size of the specified pixel format need to be integer mutiple of block size - bool CanImageSizeIgnoreBlockSize(EPixelFormat format); - - //eavluate image data size. it doesn't include mips - uint32 EvaluateImageDataSize(EPixelFormat format, uint32 imageWidth, uint32 imageHeight); - - private: - CPixelFormats(); - void InitPixelFormats(); - void InitPixelFormat(EPixelFormat format, const PixelFormatInfo& formatInfo); - - private: - static CPixelFormats *s_instance; - - PixelFormatInfo m_pixelFormatInfo[ePixelFormat_Count]; - - //pixel format name to pixel format enum - AZStd::map m_pixelFormatNameMap; - - // some formats from cryEngine were removed. using this name-pixelFormat mapping to look for new format - AZStd::map m_removedLegacyFormats; - }; - - template - bool IsPowerOfTwo(TInteger x); - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/Code/Tests/AtlasBuilderTest.cpp b/Gems/ImageProcessing/Code/Tests/AtlasBuilderTest.cpp deleted file mode 100644 index 61462475a7..0000000000 --- a/Gems/ImageProcessing/Code/Tests/AtlasBuilderTest.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ImageProcessing_precompiled.h" -#include "Source/AtlasBuilder/AtlasBuilderWorker.h" -#include "Source/ImageBuilderComponent.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include - -using namespace TextureAtlasBuilder; -using namespace ImageProcessing; - -#if defined(AZ_PLATFORM_APPLE_OSX) -# define AZ_ROOT_TEST_FOLDER "./" -#else -# define AZ_ROOT_TEST_FOLDER "" -#endif - -namespace UnitTest -{ - class AtlasBuilderTest - : public ::testing::Test - , public AzToolsFramework::AssetSystemRequestBus::Handler - { - protected: - void SetUp() override - { - AZ::AllocatorInstance::Create(); - - m_app.reset(aznew AZ::ComponentApplication()); - AZ::ComponentApplication::Descriptor desc; - desc.m_useExistingAllocator = true; - m_app->Create(desc); - - BuilderSettingManager::CreateInstance(); - - m_context = AZStd::make_unique(); - BuilderPluginComponent::Reflect(m_context.get()); - - //load qt plugins for some image file formats support - int argc = 0; - char** argv = nullptr; - m_coreApplication.reset(new QCoreApplication(argc, argv)); - - m_engineRoot.reset(new AZStd::string(AZ::Test::GetEngineRootPath())); - - // Startup default local FileIO (hits OSAllocator) if not already setup. - if (AZ::IO::FileIOBase::GetInstance() == nullptr) - { - AZ::IO::FileIOBase::SetInstance(aznew AZ::IO::LocalFileIO()); - } - - AzToolsFramework::AssetSystemRequestBus::Handler::BusConnect(); - } - - void TearDown() override - { - AzToolsFramework::AssetSystemRequestBus::Handler::BusDisconnect(); - - delete AZ::IO::FileIOBase::GetInstance(); - AZ::IO::FileIOBase::SetInstance(nullptr); - - m_app->Destroy(); - m_app = nullptr; - - m_context.release(); - BuilderSettingManager::DestroyInstance(); - CPixelFormats::DestroyInstance(); - - m_engineRoot.reset(); - m_coreApplication.reset(); - - AZ::AllocatorInstance::Destroy(); - } - - AZStd::string GetFullPath(AZStd::string_view fileName) - { - const AZStd::string testsFolder = *m_engineRoot + "/Gems/ImageProcessing/Code/Tests/"; - return AZStd::string::format("%s%.*s", testsFolder.c_str(), aznumeric_cast(fileName.size()), fileName.data()); - } - - AZStd::unique_ptr m_context; - AZStd::unique_ptr m_app; - AZStd::unique_ptr m_coreApplication; // required by engine root and IsExtensionSupported - AZStd::unique_ptr m_engineRoot; - - public: - AssetBuilderSDK::ProcessJobRequest CreateTestJobRequest( - const AZStd::string& testFileName, - const AZStd::string& watchFolder, - const AZStd::string& tempDirPath, - [[maybe_unused]] bool critical, - QString platform, - AZ::s64 jobId = 0) - { - AZStd::string fullPath; - AzFramework::StringFunc::Path::Join( - watchFolder.c_str(), testFileName.c_str(), fullPath, true, true); - - bool valid = true; - AtlasBuilderInput testInput = AtlasBuilderInput::ReadFromFile(fullPath, watchFolder, valid); - - AssetBuilderSDK::ProcessJobRequest request; - request.m_sourceFile = testFileName; - request.m_fullPath = fullPath; - request.m_tempDirPath = tempDirPath; - request.m_jobId = jobId; - request.m_platformInfo.m_identifier = platform.toUtf8().constData(); - request.m_jobDescription = AtlasBuilderWorker::GetJobDescriptor(testFileName, testInput); - - return request; - } - - AZStd::string GetTestFolderPath() - { - return AZ_ROOT_TEST_FOLDER; - } - - ////////////////////////////////////////////////////////////////////////// - // AssetSystemRequestBus - bool GetAbsoluteAssetDatabaseLocation([[maybe_unused]] AZStd::string& result) override { return false; }; - const char* GetAbsoluteDevGameFolderPath() override { return ""; }; - const char* GetAbsoluteDevRootFolderPath() override { return ""; }; - bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& outputPath) override { return false; }; - bool GetFullSourcePathFromRelativeProductPath([[maybe_unused]] const AZStd::string& relPath, [[maybe_unused]] AZStd::string& fullPath) override { return false; }; - bool GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetType& assetType, [[maybe_unused]] const AZStd::string& platformName, [[maybe_unused]] AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] AZStd::string& rootFilePath) override { return false; }; - bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override - { - assetInfo.m_relativePath = sourcePath; - watchFolder = GetFullPath("TestAssets"); - return true; - }; - bool GetSourceInfoBySourceUUID([[maybe_unused]] const AZ::Uuid& sourceUuid, [[maybe_unused]] AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] AZStd::string& watchFolder) override { return false; }; - bool GetScanFolders([[maybe_unused]] AZStd::vector& scanFolders) override { return false; }; - bool GetAssetSafeFolders([[maybe_unused]] AZStd::vector& assetSafeFolders) override { return false; }; - bool IsAssetPlatformEnabled([[maybe_unused]] const char* platform) override { return false; }; - int GetPendingAssetsForPlatform([[maybe_unused]] const char* platform) override { return -1; }; - bool GetAssetsProducedBySourceUUID([[maybe_unused]] const AZ::Uuid& sourceUuid, [[maybe_unused]] AZStd::vector& productsAssetInfo) override { return false; }; - }; - - TEST_F(AtlasBuilderTest, ProcessJob_ProcessValidTextureAtlas_OutputProductDependencies) - { - AZStd::string builderSetting(*m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"); - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(builderSetting, m_context.get()); - - // create the test job - AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest( - "TextureAtlasTest.texatlas", GetFullPath("TestAssets"), GetTestFolderPath(), false, BuilderSettingManager::s_defaultPlatform.c_str(), 1); - - AssetBuilderSDK::ProcessJobResponse response; - - AtlasBuilderWorker testBuilder; - testBuilder.ProcessJob(request, response); - - ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success); - - // texture atlas builder only has two output products - ASSERT_EQ(response.m_outputProducts.size(), 2); - - // textureatlasidx depends on dds its paired with, but not the other way around - AZ::Data::AssetId ddsProductAssetId(request.m_sourceFileUUID, response.m_outputProducts[static_cast(Product::DdsProduct)].m_productSubID); - AZStd::vector textureatlasidxProductDependencies = response.m_outputProducts[static_cast(Product::TexatlasidxProduct)].m_dependencies; - ASSERT_EQ(textureatlasidxProductDependencies.size(), 1); - ASSERT_EQ(textureatlasidxProductDependencies[0].m_dependencyId, ddsProductAssetId); - - AZStd::vector ddsProductDependencies = response.m_outputProducts[static_cast(Product::DdsProduct)].m_dependencies; - ASSERT_EQ(ddsProductDependencies.size(), 0); - } -} diff --git a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp b/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp deleted file mode 100644 index 0eaa4df4c6..0000000000 --- a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp +++ /dev/null @@ -1,1540 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -//Enable generate image files for result of some tests. -//This is slow and only useful for debugging. This should be disabled for unit test -//#define DEBUG_OUTPUT_IMAGES - -//There are some test functions in this test which are DISABLED. They were mainly for programming tests. -//It's only recommended to enable them for programming test purpose. - -#include -#include -#include "../Source/ImageBuilderComponent.h" - -using namespace ImageProcessing; - -namespace UnitTest -{ - -class ImageProcessingTest - : public ScopedAllocatorSetupFixture - // Only used to provide the serialize context - , public AZ::ComponentApplicationBus::Handler -{ -protected: - AZStd::unique_ptr m_coreApplication; // required by engine root and IsExtensionSupported - AZStd::unique_ptr m_context; - AZStd::string m_engineRoot; - - void SetUp() override - { - BuilderSettingManager::CreateInstance(); - - //prepare reflection - m_context = AZStd::make_unique(); - BuilderPluginComponent::Reflect(m_context.get()); - AZ::DataPatch::Reflect(m_context.get()); - - // Startup default local FileIO (hits OSAllocator) if not already setup. - if (AZ::IO::FileIOBase::GetInstance() == nullptr) - { - AZ::IO::FileIOBase::SetInstance(aznew AZ::IO::LocalFileIO()); - } - - // Adding this handler to allow utility functions access the serialize context - AZ::ComponentApplicationBus::Handler::BusConnect(); - AZ::Interface::Register(this); - - //load qt plugins for some image file formats support - int argc = 0; - char** argv = nullptr; - m_coreApplication.reset(new QCoreApplication(argc, argv)); - m_engineRoot = AZ::Test::GetEngineRootPath(); - - InitialImageFilenames(); - - ImageProcessingEditor::EditorHelper::InitPixelFormatString(); - } - - - void TearDown() override - { - delete AZ::IO::FileIOBase::GetInstance(); - AZ::IO::FileIOBase::SetInstance(nullptr); - - m_context.reset(); - BuilderSettingManager::DestroyInstance(); - CPixelFormats::DestroyInstance(); - - AZ::Interface::Unregister(this); - AZ::ComponentApplicationBus::Handler::BusDisconnect(); - - m_coreApplication.reset(); - } - - // ComponentApplicationMessages overrides... - AZ::ComponentApplication* GetApplication() override { return nullptr; } - void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } - void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } - void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } - void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } - bool AddEntity(AZ::Entity*) override { return false; } - bool RemoveEntity(AZ::Entity*) override { return false; } - bool DeleteEntity(const AZ::EntityId&) override { return false; } - AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } - AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } - AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } - const char* GetEngineRoot() const override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } - AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } - void EnumerateEntities(const EntityCallback& /*callback*/) override {} - void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} - // The only one function we need to implement. - AZ::SerializeContext* GetSerializeContext() override - { - return m_context.get(); - } - - //enum names for Images with specific identification - enum ImageFeature - { - Image_20X16_RGBA8_Png = 0, - Image_32X32_16bit_F_Tif, - Image_32X32_32bit_F_Tif, - Image_200X200_RGB8_Jpg, - Image_512X288_RGB8_Tga, - Image_1024X1024_RGB8_Tif, - Image_UpperCase_Tga, - Image_512x512_Normal_Tga, - Image_128x128_Transparent_Tga, - Image_237x177_RGB_Jpg, - Image_GreyScale_Png, - Image_BlackWhite_Png, - Image_TerrainHeightmap_Bt - }; - - //image file names for testing - AZStd::map m_imagFileNameMap; - - //intialial image file names for testing - void InitialImageFilenames() - { - const AZStd::string fileFolder = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/"; - - m_imagFileNameMap[Image_20X16_RGBA8_Png] = fileFolder + AZStd::string("20x16_32bit.png"); - m_imagFileNameMap[Image_32X32_16bit_F_Tif] = fileFolder + AZStd::string("32x32_16bit_f.tif"); - m_imagFileNameMap[Image_32X32_32bit_F_Tif] = fileFolder + AZStd::string("32x32_32bit_f.tif"); - m_imagFileNameMap[Image_200X200_RGB8_Jpg] = fileFolder + AZStd::string("200x200_24bit.jpg"); - m_imagFileNameMap[Image_512X288_RGB8_Tga] = fileFolder + AZStd::string("512x288_24bit.tga"); - m_imagFileNameMap[Image_1024X1024_RGB8_Tif] = fileFolder + AZStd::string("1024x1024_24bit.tif"); - m_imagFileNameMap[Image_UpperCase_Tga] = fileFolder + AZStd::string("uppercase.TGA"); - m_imagFileNameMap[Image_512x512_Normal_Tga] = fileFolder + AZStd::string("512x512_RGB_N.tga"); - m_imagFileNameMap[Image_128x128_Transparent_Tga] = fileFolder + AZStd::string("128x128_RGBA8.tga"); - m_imagFileNameMap[Image_237x177_RGB_Jpg] = fileFolder + AZStd::string("237x177_RGB.jpg"); - m_imagFileNameMap[Image_GreyScale_Png] = fileFolder + AZStd::string("greyscale.png"); - m_imagFileNameMap[Image_BlackWhite_Png] = fileFolder + AZStd::string("BlackWhite.png"); - m_imagFileNameMap[Image_TerrainHeightmap_Bt] = fileFolder + AZStd::string("TerrainHeightmap.bt"); - } - -public: - //helper function to save an image object to a file through QtImage - static void SaveImageToFile(const IImageObjectPtr imageObject, const AZStd::string imageName, AZ::u32 maxMipCnt = 100) - { -#ifndef DEBUG_OUTPUT_IMAGES - return; -#endif - if (imageObject == nullptr) - { - return; - } - - //create the directory if it's not exist - const AZStd::string outputDir = AZ::Test::GetEngineRootPath() + "/Gems/ImageProcessing/Code/Tests/TestAssets/Output/"; - QDir dir(outputDir.c_str()); - if (!dir.exists()) - { - dir.mkpath("."); - } - - //save origin file pixel format so we could use it to generate name later - EPixelFormat originPixelFormat = imageObject->GetPixelFormat(); - - //convert to RGBA8 before can be exported. - ImageToProcess imageToProcess(imageObject); - imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); - - IImageObjectPtr finalImage = imageToProcess.Get(); - - //for each mipmap - for (uint32 mip = 0; mip < finalImage->GetMipCount() && mip < maxMipCnt; mip++) - { - uint8* imageBuf; - uint32 pitch; - finalImage->GetImagePointer(mip, imageBuf, pitch); - uint32 width = finalImage->GetWidth(mip); - uint32 height = finalImage->GetHeight(mip); - - //generate file name - char filePath[2048]; - azsprintf(filePath, "%s%s_%s_mip%d_%dx%d.png", outputDir.c_str(), imageName.c_str() - , CPixelFormats::GetInstance().GetPixelFormatInfo(originPixelFormat)->szName - , mip, width, height); - - QImage qimage(imageBuf, width, height, pitch, QImage::Format_RGBA8888); - qimage.save(filePath); - } - } - - static bool GetComparisonResult(IImageObjectPtr image1, IImageObjectPtr image2, QString& output) - { - bool isImageLoaded = true; - bool isDifferent = false; - - if (image1 == nullptr) - { - isImageLoaded = false; - output += ",Image 1 does not exist. "; - } - - if (image2 == nullptr) - { - isImageLoaded = false; - output += ",Image 2 does not exist. "; - } - - if (!isImageLoaded) - { - return (!image1 && !image2) ? false: true; - } - - // Mip - int mip1 = image1->GetMipCount(); - int mip2 = image2->GetMipCount(); - int mipDiff = abs(mip1 - mip2); - - isDifferent |= mipDiff != 0; - - // Format - EPixelFormat format1 = image1->GetPixelFormat(); - EPixelFormat format2 = image2->GetPixelFormat(); - - isDifferent |= (format1 != format2); - - // Flag - AZ::u32 flag1 = image1->GetImageFlags(); - AZ::u32 flag2 = image2->GetImageFlags(); - - isDifferent |= (flag1 != flag2); - - // Size - int memSize1 = image1->GetTextureMemory(); - int memSize2 = image2->GetTextureMemory(); - int memDiff = abs(memSize1 - memSize2); - - isDifferent |= memDiff != 0; - - // Error - float error = GetErrorBetweenImages(image1, image2); - - static float EPSILON = 0.000001f; - isDifferent |= abs(error) >= EPSILON; - - output += QString(",%1/%2,%3,%4/%5,%6/%7,").arg(QString::number(mip1,'f',1), QString::number(mip2,'f',1), QString::number(mipDiff), - QString(ImageProcessingEditor::EditorHelper::s_PixelFormatString[format1]), - QString(ImageProcessingEditor::EditorHelper::s_PixelFormatString[format2]), - QString::number(flag1, 16), QString::number(flag2, 16)); - - output += QString("%1/%2,%3,%4").arg(QString(ImageProcessingEditor::EditorHelper::GetFileSizeString(memSize1).c_str()), - QString(ImageProcessingEditor::EditorHelper::GetFileSizeString(memSize2).c_str()), - QString(ImageProcessingEditor::EditorHelper::GetFileSizeString(memDiff).c_str()), - QString::number(error, 'f', 8)); - - - return isDifferent; - } - - - static bool CompareDDSImage(const QString& imagePath1, const QString& imagePath2, QString& output) - { - IImageObjectPtr image1, alphaImage1, image2, alphaImage2; - - - image1 = IImageObjectPtr(LoadImageFromDdsFile(imagePath1.toUtf8().constData())); - if (image1 && image1->HasImageFlags(EIF_AttachedAlpha)) - { - if (image1->HasImageFlags(EIF_Splitted)) - { - alphaImage1 = IImageObjectPtr(LoadImageFromDdsFile(QString(imagePath1 + ".a").toUtf8().constData())); - } - else - { - alphaImage1 = IImageObjectPtr(LoadAttachedImageFromDdsFile(imagePath1.toUtf8().constData(), image1)); - } - } - - image2 = IImageObjectPtr(LoadImageFromDdsFile(imagePath2.toUtf8().constData())); - if (image2 && image2->HasImageFlags(EIF_AttachedAlpha)) - { - if (image2->HasImageFlags(EIF_Splitted)) - { - alphaImage2 = IImageObjectPtr(LoadImageFromDdsFile(QString(imagePath2 + ".a").toUtf8().constData())); - } - else - { - alphaImage2 = IImageObjectPtr(LoadAttachedImageFromDdsFile(imagePath2.toUtf8().constData(), image2)); - } - } - - if (!image1 && !image2) - { - output += "Cannot load both image file! "; - return false; - } - bool isDifferent = false; - - isDifferent = GetComparisonResult(image1, image2, output); - - - QFileInfo fi(imagePath1); - AZStd::string imageName = fi.baseName().toUtf8().constData(); - SaveImageToFile(image1, imageName + "_new"); - SaveImageToFile(image2, imageName + "_old"); - - if (alphaImage1 || alphaImage2) - { - isDifferent |= GetComparisonResult(alphaImage1, alphaImage2, output); - } - - return isDifferent; - } -}; - -// test CPixelFormats related functions -TEST_F(ImageProcessingTest, TestPixelFormats) -{ - CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - - //verify names which was used for legacy rc.ini - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC7t") == ePixelFormat_BC7t); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("ETC2A") == ePixelFormat_ETC2a); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("PVRTC4") == ePixelFormat_PVRTC4); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC1") == ePixelFormat_BC1); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("ETC2") == ePixelFormat_ETC2); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC1a") == ePixelFormat_BC1a); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC3") == ePixelFormat_BC3); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC7") == ePixelFormat_BC7); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC5s") == ePixelFormat_BC5s); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("EAC_RG11") == ePixelFormat_EAC_RG11); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC4") == ePixelFormat_BC4); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("EAC_R11") == ePixelFormat_EAC_R11); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("A8R8G8B8") == ePixelFormat_R8G8B8A8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC6UH") == ePixelFormat_BC6UH); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("R9G9B9E5") == ePixelFormat_R9G9B9E5); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("X8R8G8B8") == ePixelFormat_R8G8B8X8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("A16B16G16R16F") == ePixelFormat_R16G16B16A16F); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G8R8") == ePixelFormat_R8G8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G16R16") == ePixelFormat_R16G16); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G16R16F") == ePixelFormat_R16G16F); - - //some legacy format need to be mapping to new format. - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("DXT1") == ePixelFormat_BC1); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("DXT5") == ePixelFormat_BC3); - - //calculate mipmap count. no cubemap support at this moment - - //for all the non-compressed textures, if there minimum required texture size is 1x1 - for (uint32 i = 0; i < ePixelFormat_Count; i++) - { - EPixelFormat pixelFormat = (EPixelFormat)i; - if (pixelFormats.IsPixelFormatUncompressed(pixelFormat)) - { - //square, power of 2 sizes for uncompressed format which minimum required size is 1x1 - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 128, 128) == 8); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 64, 64) == 7); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 4, 4) == 3); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 2, 2) == 2); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 1, 1) == 1); - - //non-square, power of 2 sizes for uncompressed format which minimum required size is 1x1 - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 128, 64) == 8); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 128, 32) == 8); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 32, 2) == 6); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 2, 1) == 2); - - //Non power of 2 sizes for uncompressed format which minimum required size is 1x1 - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 128, 64) == 8); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 128, 32) == 8); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 32, 2) == 6); - ASSERT_TRUE(pixelFormats.ComputeMaxMipCount(pixelFormat, 2, 1) == 2); - } - } - - //check function IsImageSizeValid && EvaluateImageDataSize function - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 2, 1, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 4, 4, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 16, 16, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 16, 32, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 34, 34, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 256, 256, false) == true); - - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 2, 1, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 16, 16, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 16, 32, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 34, 34, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 256, 256, false) == true); - - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_ASTC_4x4, 2, 1, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_ASTC_4x4, 16, 16, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_ASTC_4x4, 16, 32, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_ASTC_4x4, 34, 34, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_ASTC_4x4, 256, 256, false) == true); - - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_A8, 2, 1, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_A8, 16, 16, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_A8, 16, 32, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_A8, 34, 34, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_A8, 256, 256, false) == true); -} - -// test image file loading -TEST_F(ImageProcessingTest, TestImageLoaders) -{ - //file extention support for different loader - ASSERT_TRUE(IsExtensionSupported("jpg") == true); - ASSERT_TRUE(IsExtensionSupported("JPG") == true); - ASSERT_TRUE(IsExtensionSupported(".JPG") == false); - ASSERT_TRUE(IsExtensionSupported("tga") == true); - ASSERT_TRUE(IsExtensionSupported("TGA") == true); - ASSERT_TRUE(IsExtensionSupported("tif") == true); - ASSERT_TRUE(IsExtensionSupported("tiff") == true); - ASSERT_TRUE(IsExtensionSupported("bt") == true); - - IImageObjectPtr img; - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_1024X1024_RGB8_Tif])); - - ASSERT_TRUE(img != nullptr); - ASSERT_TRUE(img->GetWidth(0) == 1024); - ASSERT_TRUE(img->GetHeight(0) == 1024); - ASSERT_TRUE(img->GetMipCount() == 1); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R8G8B8X8); - - //load png - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_20X16_RGBA8_Png])); - ASSERT_TRUE(img != nullptr); - ASSERT_TRUE(img->GetWidth(0) == 20); - ASSERT_TRUE(img->GetHeight(0) == 16); - ASSERT_TRUE(img->GetMipCount() == 1); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R8G8B8A8); - - //load jpg - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_200X200_RGB8_Jpg])); - ASSERT_TRUE(img->GetWidth(0) == 200); - ASSERT_TRUE(img->GetHeight(0) == 200); - ASSERT_TRUE(img->GetMipCount() == 1); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R8G8B8A8); - - //tga - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_512X288_RGB8_Tga])); - ASSERT_TRUE(img->GetWidth(0) == 512); - ASSERT_TRUE(img->GetHeight(0) == 288); - ASSERT_TRUE(img->GetMipCount() == 1); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R8G8B8A8); - - //image with upper case extension - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_UpperCase_Tga])); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R8G8B8A8); - - //16bits float tif - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_32X32_16bit_F_Tif])); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R16G16B16A16F); - - //32bits float tif - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_32X32_32bit_F_Tif])); - ASSERT_TRUE(img->GetPixelFormat() == ePixelFormat_R32G32B32A32F); - - //BT - img = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[Image_TerrainHeightmap_Bt])); - ASSERT_TRUE(img != nullptr); - EXPECT_EQ(img->GetWidth(0), 128); - EXPECT_EQ(img->GetHeight(0), 128); - EXPECT_EQ(img->GetMipCount(), 1); - EXPECT_EQ(img->GetPixelFormat(), ePixelFormat_R32F); -} - -TEST_F(ImageProcessingTest, PresetSettingCopyAssignmentOperatorOverload_WithDynamicallyAllocatedSettings_ReturnsTwoSeparateAllocations) -{ - PresetSettings presetSetting; - presetSetting.m_mipmapSetting = AZStd::unique_ptr(new MipmapSettings()); - presetSetting.m_cubemapSetting = AZStd::unique_ptr(new CubemapSettings()); - - // Explicit invoke assignment operator by splitting the operation into two lines. - PresetSettings otherPresetSetting; - otherPresetSetting = presetSetting; - - EXPECT_NE(otherPresetSetting.m_cubemapSetting, presetSetting.m_cubemapSetting); - EXPECT_NE(otherPresetSetting.m_mipmapSetting, presetSetting.m_mipmapSetting); -} - -TEST_F(ImageProcessingTest, PresetSettingCopyConstructor_WithDynamicallyAllocatedSettings_ReturnsTwoSeparateAllocations) -{ - PresetSettings presetSetting; - presetSetting.m_mipmapSetting = AZStd::unique_ptr(new MipmapSettings()); - presetSetting.m_cubemapSetting = AZStd::unique_ptr(new CubemapSettings()); - - PresetSettings otherPresetSetting(presetSetting); - - EXPECT_NE(otherPresetSetting.m_cubemapSetting, presetSetting.m_cubemapSetting); - EXPECT_NE(otherPresetSetting.m_mipmapSetting, presetSetting.m_mipmapSetting); -} - -TEST_F(ImageProcessingTest, PresetSettingEqualityOperatorOverload_WithIdenticalSettings_ReturnsEquivalent) -{ - PresetSettings presetSetting; - PresetSettings otherPresetSetting(presetSetting); - - EXPECT_TRUE(otherPresetSetting == presetSetting); -} - -TEST_F(ImageProcessingTest, PresetSettingEqualityOperatorOverload_WithDifferingDynamicallyAllocatedSettings_ReturnsUnequivalent) -{ - PresetSettings presetSetting; - presetSetting.m_mipmapSetting = AZStd::unique_ptr(new MipmapSettings()); - presetSetting.m_mipmapSetting->m_type = MipGenType::gaussian; - - PresetSettings otherPresetSetting(presetSetting); - otherPresetSetting.m_mipmapSetting = AZStd::unique_ptr(new MipmapSettings()); - otherPresetSetting.m_mipmapSetting->m_type = MipGenType::blackmanHarris; - - EXPECT_FALSE(otherPresetSetting == presetSetting); - -} - -//this test is to test image data won't be lost between uncompressed formats (for low to high precision or same precision) -TEST_F(ImageProcessingTest, TestConvertFormatUncompressed) -{ - //source image - IImageObjectPtr srcImage(LoadImageFromFile(m_imagFileNameMap[Image_200X200_RGB8_Jpg])); - ImageToProcess imageToProcess(srcImage); - - //image pointers to hold precessed images for comparison - IImageObjectPtr dstImage1, dstImage2, dstImage3, dstImage4, dstImage5; - - //compare four channels pixel formats - //we will convert to target format then convert back to RGBX8 so they can compare to easy other - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8A8); - dstImage1 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16G16B16A16); - ASSERT_FALSE(srcImage->CompareImage(imageToProcess.Get())); //this is different than source image - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8A8); - dstImage2 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16G16B16A16F); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8A8); - dstImage3 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R32G32B32A32F); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8A8); - dstImage4 = imageToProcess.Get(); - - ASSERT_TRUE(dstImage2->CompareImage(dstImage1)); - ASSERT_TRUE(dstImage3->CompareImage(dstImage1)); - ASSERT_TRUE(dstImage4->CompareImage(dstImage1)); - - // three channels formats - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage1 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R9G9B9E5); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage2 = imageToProcess.Get(); - - ASSERT_TRUE(dstImage2->CompareImage(dstImage1)); - - //convert image to all one channel formats then convert them back to RGBX8 for comparison - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage1 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage2 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16F); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage3 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R32F); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage4 = imageToProcess.Get(); - - ASSERT_TRUE(dstImage2->CompareImage(dstImage1)); - ASSERT_TRUE(dstImage3->CompareImage(dstImage1)); - ASSERT_TRUE(dstImage4->CompareImage(dstImage1)); - - //convert image to all two channels formats then convert them back to RGBX8 for comparison - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage1 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16G16); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage2 = imageToProcess.Get(); - - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R16G16F); - imageToProcess.ConvertFormatUncompressed(ePixelFormat_R8G8B8X8); - dstImage3 = imageToProcess.Get(); - - ASSERT_TRUE(dstImage2->CompareImage(dstImage1)); - ASSERT_TRUE(dstImage3->CompareImage(dstImage1)); -} - -TEST_F(ImageProcessingTest, DISABLED_TestConvertPVRTC) -{ - //load builder presets - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - AZStd::vector outPaths; - AZStd::string inputFile = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/normalSmoothness_ddna.tif"; - const AZStd::string outputFolder = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/temp/"; - ImageConvertProcess* process = CreateImageConvertProcess(inputFile, outputFolder, "ios", m_context.get()); - if (process != nullptr) - { - //the process can be stopped if the job is cancelled or the worker is shutting down - int step = 0; - while (!process->IsFinished()) - { - process->UpdateProcess(); - step++; - } - - //get process result - ASSERT_TRUE(process->IsSucceed()); - - SaveImageToFile(process->GetOutputImage(), "rgb", 10); - SaveImageToFile(process->GetOutputAlphaImage(), "alpha", 10); - - process->GetAppendOutputFilePaths(outPaths); - delete process; - } - - //ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, "ios", m_context.get())); - -} - -TEST_F(ImageProcessingTest, DISABLED_TestConvertFormat) -{ - EPixelFormat pixelFormat; - IImageObjectPtr srcImage; - - //images to be tested - static const int imageCount = 5; - ImageFeature images[imageCount] = { - Image_20X16_RGBA8_Png, - Image_32X32_16bit_F_Tif, - Image_32X32_32bit_F_Tif , - Image_512x512_Normal_Tga , - Image_128x128_Transparent_Tga }; - - for (int imageIdx = 0; imageIdx < imageCount; imageIdx++) - { - //get image's name and it will be used for output file name - QFileInfo fi(m_imagFileNameMap[images[imageIdx]].c_str()); - AZStd::string imageName = fi.baseName().toUtf8().constData(); - - srcImage = IImageObjectPtr(LoadImageFromFile(m_imagFileNameMap[images[imageIdx]])); - ImageToProcess imageToProcess(srcImage); - - //test ConvertFormat functions againest all the pixel formats - for (pixelFormat = ePixelFormat_R8G8B8A8; pixelFormat < ePixelFormat_Unknown;) - { - imageToProcess.Set(srcImage); - imageToProcess.ConvertFormat(pixelFormat); - - ASSERT_TRUE(imageToProcess.Get()); - - //if the format is compressed and there is no compressor for it, it won't be converted to the expected format - if (ICompressor::FindCompressor(pixelFormat, true) == nullptr - && !CPixelFormats::GetInstance().IsPixelFormatUncompressed(pixelFormat)) - { - ASSERT_TRUE(imageToProcess.Get()->GetPixelFormat() != pixelFormat); - } - else - { - //validate the size and it may not working for some uncompressed format - if (!CPixelFormats::GetInstance().IsImageSizeValid( - pixelFormat, srcImage->GetWidth(0), srcImage->GetHeight(0), false)) - { - ASSERT_TRUE(imageToProcess.Get()->GetPixelFormat() != pixelFormat); - } - else - { - ASSERT_TRUE(imageToProcess.Get()->GetPixelFormat() == pixelFormat); - - //save the image to a file so we can check the visual result - SaveImageToFile(imageToProcess.Get(), imageName, 1); - - //convert back to an uncompressed format and expect it will be successful - imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); - ASSERT_TRUE(imageToProcess.Get()->GetPixelFormat() == ePixelFormat_R8G8B8A8); - - } - } - - //next pixel format - pixelFormat = EPixelFormat(pixelFormat + 1); - } - } -} - -TEST_F(ImageProcessingTest, DISABLED_TestImageFilter) -{ - AZStd::string testImageFile = m_imagFileNameMap[Image_1024X1024_RGB8_Tif]; - IImageObjectPtr srcImage, dstImage; - - QFileInfo fi(testImageFile.c_str()); - AZStd::string imageName = fi.baseName().toUtf8().constData(); - - //load src image and convert it to RGBA32F - srcImage = IImageObjectPtr(LoadImageFromFile(testImageFile)); - ImageToProcess imageToProcess(srcImage); - imageToProcess.ConvertFormat(ePixelFormat_R32G32B32A32F); - srcImage = imageToProcess.Get(); - - //create dst image with same size and mipmaps - dstImage = IImageObjectPtr( - IImageObject::CreateImage(srcImage->GetWidth(0), srcImage->GetHeight(0), 3, - ePixelFormat_R32G32B32A32F)); - - //for each filters - const std::array, 7> allFilters = - { - { - {MipGenType::point, "point"}, - {MipGenType::box, "box" }, - { MipGenType::triangle, "triangle" }, - { MipGenType::quadratic, "Quadratic" }, - { MipGenType::blackmanHarris, "blackmanHarris" }, - { MipGenType::kaiserSinc, "kaiserSinc" } - } - }; - - for (std::pair filter : allFilters) - { - for (uint mip = 0; mip < dstImage->GetMipCount(); mip++) - { - FilterImage(filter.first, MipGenEvalType::sum, - 0, 0, imageToProcess.Get(), 0, dstImage, mip, nullptr, nullptr); - } - SaveImageToFile(dstImage, imageName + "_" + filter.second); - } -} - -TEST_F(ImageProcessingTest, TestColorSpaceConversion) -{ - IImageObjectPtr srcImage(LoadImageFromFile(m_imagFileNameMap[Image_GreyScale_Png])); - - ImageToProcess imageToProcess(srcImage); - imageToProcess.GammaToLinearRGBA32F(true); - SaveImageToFile(imageToProcess.Get(), "GammaTolinear_DeGamma", 1); - imageToProcess.LinearToGamma(); - SaveImageToFile(imageToProcess.Get(), "LinearToGamma_DeGamma", 1); -} - -//This function can be used to modify some value in the builder setting and keep all presets uuid then save back to setting file -//It will only change the file if the file was checked out -TEST_F(ImageProcessingTest, DISABLED_ModifyBuilderSetting) -{ - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - QFileInfo fileInfo(buiderSetting.c_str()); - if (fileInfo.isWritable()) - { - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - BuilderSettingManager::Instance()->WriteBuilderSettings(buiderSetting, m_context.get()); - } -} - -TEST_F(ImageProcessingTest, VerifyRestrictedPlatform) -{ - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - PlatformNameList platforms = BuilderSettingManager::Instance()->GetPlatformList(); - -#ifndef AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS - ASSERT_TRUE(platforms.size() == 4); -#endif //AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -} - -TEST_F(ImageProcessingTest, DISABLED_TestCubemap) -{ - //load builder presets - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - const AZStd::string outputFolder = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/temp/"; - AZStd::string inputFile; - AZStd::vector outPaths; - - inputFile = m_engineRoot + "/Assets/Engine/EngineAssets/Shading/defaultProbe_cm.tif"; - - IImageObjectPtr srcImage(LoadImageFromFile(inputFile)); - ImageToProcess imageToProcess(srcImage); - imageToProcess.ConvertCubemapLayout(CubemapLayoutVertical); - SaveImageToFile(imageToProcess.Get(), "Vertical", 100); - imageToProcess.ConvertCubemapLayout(CubemapLayoutHorizontalCross); - SaveImageToFile(imageToProcess.Get(), "HorizontalCross", 100); - imageToProcess.ConvertCubemapLayout(CubemapLayoutVerticalCross); - SaveImageToFile(imageToProcess.Get(), "VerticalCross", 100); - imageToProcess.ConvertCubemapLayout(CubemapLayoutHorizontal); - SaveImageToFile(imageToProcess.Get(), "VerticalHorizontal", 100); - - ImageConvertProcess* process = CreateImageConvertProcess(inputFile, outputFolder, "pc"); - - if (process != nullptr) - { - int step = 0; - while (!process->IsFinished()) - { - process->UpdateProcess(); - step++; - char name[100]; - azsprintf(name, "cubemap_%d", step); - //SaveImageToFile(process->GetOutputImage(), name, 1); - } - - //get process result - ASSERT_TRUE(process->IsSucceed()); - - SaveImageToFile(process->GetOutputImage(), "cubemap", 100); - SaveImageToFile(process->GetOutputDiffCubemap(), "diffCubemap", 100); - SaveImageToFile(process->GetOutputAlphaImage(), "alpha", 1); - process->GetAppendOutputFilePaths(outPaths); - - delete process; - } -} - -//test image conversion for builder -TEST_F(ImageProcessingTest, DISABLED_TestBuilderImageConvertor) -{ - AZStd::string oldCacheFolder = "E:/Javelin_old_tex_cache/textures"; - AZStd::string srcFolder = "E:/Javelin_NWLYDev/dev/Assets/Textures"; - - //load builder presets - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - const AZStd::string outputFolder = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/temp/"; - AZStd::string inputFile; - AZStd::vector outPaths; - - inputFile = srcFolder + "/terrain/cry/detail/grass_with_stones_displ.tif"; - inputFile = m_imagFileNameMap[Image_128x128_Transparent_Tga]; - AZStd::string oldFile = oldCacheFolder + "/terrain/cry/detail/grass_with_stones_displ.dds"; - ImageConvertProcess* process = CreateImageConvertProcess(inputFile, outputFolder, "pc", m_context.get()); - - if (process != nullptr) - { - //the process can be stopped if the job is cancelled or the worker is shutting down - int step = 0; - while (!process->IsFinished() ) - { - process->UpdateProcess(); - step++; - } - - //get process result - ASSERT_TRUE(process->IsSucceed()); - - SaveImageToFile(process->GetOutputImage(), "rgb", 10); - SaveImageToFile(process->GetOutputAlphaImage(), "alpha", 10); - - process->GetAppendOutputFilePaths(outPaths); - - QString output; - //CompareDDSImage(outPaths[0].c_str(), oldFile.c_str(), output); - delete process; - } - - - -/* //test cases for different presets - //ddna - inputFile = "../AutomatedTesting/Objects/ParticleAssets/ShowRoom/showroom_pipe_blue_001_m_ddna.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - //cubemap - inputFile = "../AutomatedTesting/Levels/Samples/Camera_Sample/Cubemaps/noon_cm.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - //albedo - inputFile = "../AutomatedTesting/Objects/ParticleAssets/ShowRoom/showroom_steel_brushed_001_diff.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - inputFile = "../AutomatedTesting/materials/pbs_reference/light_leather_diff.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - inputFile = "../Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - //ui ReferenceImage auto preset - inputFile = "../Bems/UiBasics/Assets/UI/Textures/Prefab/textinput_normal.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - //albedo with generic alpha auto preset - inputFile = "../AutomatedTesting/textures/GettingStartedTextures/LY_Logo_Beaver.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); - //color chart - inputFile = "../Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_low_cch.tif"; - ASSERT_TRUE(ConvertImageFile(inputFile, outputFolder, outPaths, m_context.get())); -*/ -} - - -//test image loading function for output dds files -TEST_F(ImageProcessingTest, DISABLED_TestLoadDdsImage) -{ - IImageObjectPtr originImage, alphaImage; - AZStd::string inputFolder = m_engineRoot + "/Cache/AutomatedTesting/pc/automatedtesting/engineassets/texturemsg/"; - AZStd::string inputFile; - - inputFile = "E:/Javelin_NWLYDev/dev/Cache/Assets/pc/assets/textures/blend_maps/moss/jav_moss_ddn.dds"; - - IImageObjectPtr newImage = IImageObjectPtr(LoadImageFromDdsFile(inputFile)); - if (newImage->HasImageFlags(EIF_AttachedAlpha)) - { - if (newImage->HasImageFlags(EIF_Splitted)) - { - alphaImage = IImageObjectPtr(LoadImageFromDdsFile(inputFile+".a")); - - } - else - { - alphaImage = IImageObjectPtr(LoadAttachedImageFromDdsFile(inputFile, newImage)); - } - } - - SaveImageToFile(newImage, "jav_moss_ddn", 10); -} - -TEST_F(ImageProcessingTest, DISABLED_CompareOutputImage) -{ - AZStd::string curretTextureFolder = m_engineRoot + "/TestAssets/TextureAssets/assets_new/textures"; - AZStd::string oldTextureFolder = m_engineRoot + "/TestAssets/TextureAssets/assets_old/textures"; - bool outputOnlyDifferent = false; - QDirIterator it(curretTextureFolder.c_str(), QStringList() << "*.dds", QDir::Files, QDirIterator::Subdirectories); - QFile f("../texture_comparison_output.csv"); - f.open(QIODevice::ReadWrite | QIODevice::Truncate); - // Write a header for csv file - f.write("Texture Name, Path, Mip new/old, MipDiff, Format new/old, Flag new/old, MemSize new/old, MemDiff, Error, AlphaMip new/old, AlphaMipDiff, AlphaFormat new/old, AlphaFlag new/old, AlphaMemSize new/old, AlphaMemDiff, AlphaError\r\n"); - int i = 0; - while (it.hasNext()) - { - i++; - it.next(); - - QString fileName = it.fileName(); - QString newFilePath = it.filePath(); - QString sharedPath = QString(newFilePath).remove(curretTextureFolder.c_str()); - QString oldFilePath = QString(oldTextureFolder.c_str()) + sharedPath; - QString output; - if (QFile::exists(oldFilePath)) - { - bool isDifferent = CompareDDSImage(newFilePath, oldFilePath, output); - if (outputOnlyDifferent && !isDifferent) - { - continue; - } - else - { - f.write(fileName.toUtf8().constData()); - f.write(","); - f.write(sharedPath.toUtf8().constData()); - f.write(output.toUtf8().constData()); - } - } - else - { - f.write(fileName.toUtf8().constData()); - f.write(","); - f.write(sharedPath.toUtf8().constData()); - output += ",No old file for comparison!"; - f.write(output.toUtf8().constData()); - } - f.write("\r\n"); - } - f.close(); -} - - -TEST_F(ImageProcessingTest, EditorTextureSettingTest) -{ - AZStd::string buiderSetting = m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - auto TestFunc = [](const AZStd::string& textureFilepath, bool isCubemap) { - - ImageProcessingEditor::EditorTextureSetting setting(textureFilepath); - const TextureSettings& textSettings = setting.m_settingsMap["pc"]; - auto& presetId = textSettings.m_preset; - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetId); - AZ::u32 arrayCount = 1; - AZ::u32 originalWidth = setting.m_img->GetWidth(0); - AZ::u32 originalHeight = setting.m_img->GetHeight(0); - - if (isCubemap) - { - ASSERT_TRUE(preset->m_cubemapSetting != nullptr); - CubemapLayout *srcCubemap = CubemapLayout::CreateCubemapLayout(setting.m_img); - ASSERT_TRUE(srcCubemap != nullptr); - - originalWidth = srcCubemap->GetFaceSize(); - originalHeight = srcCubemap->GetFaceSize(); - arrayCount = 6; - - delete srcCubemap; - } - - // Test GetFinalInfoForTextureOnPlatform function - { - for (AZ::u32 reduce = 0; reduce < 15; reduce++) - { - ImageProcessingEditor::ResolutionInfo info; - if (setting.GetFinalInfoForTextureOnPlatform("pc", reduce, info)) - { - ASSERT_TRUE(info.reduce <= reduce); - ASSERT_TRUE(info.arrayCount == arrayCount); - ASSERT_TRUE(info.width == AZStd::max(originalWidth >> info.reduce, 1)); - ASSERT_TRUE(info.height == AZStd::max(originalHeight >> info.reduce, 1)); - if (preset->m_maxTextureSize > 0) - { - ASSERT_TRUE(info.width <= preset->m_maxTextureSize); - ASSERT_TRUE(info.height <= preset->m_maxTextureSize); - } - if (preset->m_minTextureSize > 0) - { - ASSERT_TRUE(info.width >= preset->m_minTextureSize); - ASSERT_TRUE(info.height >= preset->m_minTextureSize); - } - } - } - } - - // Test GetResolutionInfo function - { - AZ::u32 minReduce, maxReduce; - auto resolutions = setting.GetResolutionInfo("pc", minReduce, maxReduce); - ASSERT_TRUE(resolutions.size() > 0); - ASSERT_TRUE(resolutions.size() == maxReduce - minReduce + 1); - for (auto& info : resolutions) - { - ASSERT_TRUE(info.reduce >= minReduce); - ASSERT_TRUE(info.reduce <= maxReduce); - ASSERT_TRUE(info.arrayCount == arrayCount); - ASSERT_TRUE(info.width == AZStd::max(originalWidth >> info.reduce, 1)); - ASSERT_TRUE(info.height == AZStd::max(originalHeight >> info.reduce, 1)); - ASSERT_TRUE(info.width >= 1); - ASSERT_TRUE(info.height >= 1); - } - } - - // Test GetResolutionInfo function - { - auto resolutions = setting.GetResolutionInfoForMipmap("pc"); - for (auto& info : resolutions) - { - ASSERT_TRUE(info.arrayCount == arrayCount); - ASSERT_TRUE(info.width == AZStd::max(originalWidth >> info.reduce, 1)); - ASSERT_TRUE(info.height == AZStd::max(originalHeight >> info.reduce, 1)); - ASSERT_TRUE(info.width >= 1); - ASSERT_TRUE(info.height >= 1); - } - setting.m_settingsMap["pc"].m_sizeReduceLevel += 1; - auto reducedResolutions = setting.GetResolutionInfoForMipmap("pc"); - ASSERT_TRUE(resolutions.size() >= reducedResolutions.size()); - } - }; - - // For cubemap texture - AZStd::string textureFilePath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/noon_cm.tif"; - TestFunc(textureFilePath, true); - - // For albedo texture - textureFilePath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif"; - TestFunc(textureFilePath, false); -} - -class ImageProcessingSerializationTest - : public ScopedAllocatorSetupFixture -{ -protected: - AZStd::unique_ptr m_context; - AZStd::string m_engineRoot; - - void SetUp() override - { - BuilderSettingManager::CreateInstance(); - - m_context = AZStd::make_unique(); - BuilderPluginComponent::Reflect(m_context.get()); - AZ::DataPatch::Reflect(m_context.get()); - - // Startup default local FileIO (hits OSAllocator) if not already setup. - if (AZ::IO::FileIOBase::GetInstance() == nullptr) - { - AZ::IO::FileIOBase::SetInstance(aznew AZ::IO::LocalFileIO()); - } - { - int argc = 0; - char** argv = nullptr; - QCoreApplication app(argc, argv); - m_engineRoot = AZ::Test::GetEngineRootPath(); - } - } - - void TearDown() override - { - delete AZ::IO::FileIOBase::GetInstance(); - AZ::IO::FileIOBase::SetInstance(nullptr); - - m_context.reset(); - BuilderSettingManager::DestroyInstance(); - CPixelFormats::DestroyInstance(); - } -}; - -TEST_F(ImageProcessingSerializationTest, DISABLED_LoadBuilderSettingsFromRC_SerializingLegacyDataIn_InvalidFiles) -{ - AZStd::string filepath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/rc.ini_Missing"; - ASSERT_FALSE(BuilderSettingManager::Instance()->LoadBuilderSettingsFromRC(filepath).IsSuccess()); - - filepath = m_engineRoot + "/Code/Tools/RC/Config/rc/rc.ini"; - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettingsFromRC(filepath); - ASSERT_TRUE(outcome.IsSuccess()); - - AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; - - // Load legacy texture settings from file that not exists - TextureSettings legacyTextureSetting; - AZStd::string notExistingFile = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/NotExistingFile"; - auto legacyLoadOutcome = TextureSettings::LoadLegacyTextureSettingFromFile("", notExistingFile, legacyTextureSetting, m_context.get()); - EXPECT_FALSE(legacyLoadOutcome.IsSuccess()); - - // Load legacy texture settings from file whose format is wrong - - // Wrong override data - AZStd::string wrongFormatFile = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/invalid.exportsettings"; - AZStd::string wrongFormatContent = "/autooptimizefile=0 /preset=Diffuse_highQ /reduce=\"es3:0,randomdata,ios:3,osx_gl:0,pc:4\" /ser=0"; - if (AZ::IO::FileIOBase::GetInstance()->Open(wrongFormatFile.c_str(), AZ::IO::OpenMode::ModeWrite, fileHandle)) - { - AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, wrongFormatContent.c_str(), wrongFormatContent.size()); - AZ::IO::FileIOBase::GetInstance()->Close(fileHandle); - } - else - { - EXPECT_TRUE(false); - } - legacyLoadOutcome = TextureSettings::LoadLegacyTextureSettingFromFile("", wrongFormatFile, legacyTextureSetting, m_context.get()); - EXPECT_FALSE(legacyLoadOutcome.IsSuccess()); - - // Wrong format data - wrongFormatContent = "//// ,&*&#$@#/preset=Diffuse_highQ / //reduce=0 /ser=0"; - if (AZ::IO::FileIOBase::GetInstance()->Open(wrongFormatFile.c_str(), AZ::IO::OpenMode::ModeWrite, fileHandle)) - { - AZ::IO::FileIOBase::GetInstance()->Write(fileHandle, wrongFormatContent.c_str(), wrongFormatContent.size()); - AZ::IO::FileIOBase::GetInstance()->Close(fileHandle); - } - legacyLoadOutcome = TextureSettings::LoadLegacyTextureSettingFromFile("", wrongFormatFile, legacyTextureSetting, m_context.get()); - EXPECT_FALSE(legacyLoadOutcome.IsSuccess()); - - AZ::IO::FileIOBase::GetInstance()->Remove(wrongFormatFile.c_str()); -} - - -TEST_F(ImageProcessingSerializationTest, TextureSettingReflect_SerializingLegacyDataIn_EmbeddedSetting) -{ - AZStd::string buiderSetting(m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"); - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - // Load legacy texture settings - TextureSettings legacyTextureSetting; - AZStd::string textureFilepath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/Lenstexture_dirtyglass.tif"; - AZStd::string textureSetting = LoadEmbeddedSettingFromFile(textureFilepath); - EXPECT_FALSE(textureSetting.empty()); - - auto legacyLoadOutcome = TextureSettings::LoadLegacyTextureSetting(textureFilepath, textureSetting, legacyTextureSetting, m_context.get()); - // Ensure we loaded and parsed the texture settings correctly. - EXPECT_TRUE(legacyLoadOutcome.IsSuccess()); - EXPECT_EQ(legacyTextureSetting.m_preset, BuilderSettingManager::Instance()->GetPresetIdFromName("LensOptics")); -} - -TEST_F(ImageProcessingSerializationTest, TextureSettingReflect_SerializingLegacyDataIn_CommonAndPlatformSpecificSettingsAreSerializedCorrectly) -{ - AZStd::string buiderSetting(m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"); - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - // Load legacy texture settings - TextureSettings legacyTextureSetting; - AZStd::string textureFilepath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif"; - auto legacyLoadOutcome = TextureSettings::LoadLegacyTextureSettingFromFile(textureFilepath, - textureFilepath + TextureSettings::legacyExtensionName, legacyTextureSetting, m_context.get()); - - // Ensure we loaded and parsed the texture settings correctly. - EXPECT_TRUE(legacyLoadOutcome.IsSuccess()); - EXPECT_EQ(legacyTextureSetting.m_mipGenType, MipGenType::kaiserSinc); - EXPECT_EQ(legacyTextureSetting.m_preset, BuilderSettingManager::Instance()->GetPresetIdFromName("Albedo")); - EXPECT_EQ(legacyTextureSetting.m_mipAlphaAdjust[0], 62); - EXPECT_EQ(legacyTextureSetting.m_suppressEngineReduce, false); - - // Ensure overrides are properly parsed as well. - { - TextureSettings iosTextureSettings; - auto iosOutcome = TextureSettings::GetPlatformSpecificTextureSetting("ios", legacyTextureSetting, iosTextureSettings, m_context.get()); - EXPECT_TRUE(iosOutcome.IsSuccess()); - EXPECT_EQ(iosTextureSettings.m_sizeReduceLevel, 3); - } -} - -TEST_F(ImageProcessingSerializationTest, TextureSettingReflect_SerializingModernDataOutThenIn_PreSerializedAndPostSerializedDataIsEquivalent) -{ - AZStd::string buiderSetting(m_engineRoot + "/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings"); - auto outcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buiderSetting, m_context.get()); - - // Load legacy texture settings - TextureSettings legacyTextureSetting; - AZStd::string textureFilepath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif"; - auto legacyLoadOutcome = TextureSettings::LoadLegacyTextureSettingFromFile(textureFilepath, - textureFilepath+TextureSettings::legacyExtensionName, legacyTextureSetting, m_context.get()); - - // Let's make modifications to the loaded texture setting - // Modification1: Set reduce level for common settings. - // Modification2: Set reduce level for iOS-override settings. - legacyTextureSetting.m_sizeReduceLevel = 1337; - TextureSettings iosOverride = legacyTextureSetting; - iosOverride.m_sizeReduceLevel = 0xDAD; - legacyTextureSetting.ApplySettings(iosOverride, "ios", m_context.get()); - - // Write the modified texture settings to file, using AZ::Serialization. - AZStd::string modernMetafilePath = textureFilepath + TextureSettings::modernExtensionName; - auto writeOutcome = TextureSettings::WriteTextureSetting(modernMetafilePath, legacyTextureSetting, m_context.get()); - EXPECT_TRUE(writeOutcome.IsSuccess()); - - // Load the modified settings back to memory, using AZ::Serialization - TextureSettings modernTextureSetting; - auto modernLoadOutcome = TextureSettings::LoadTextureSetting(modernMetafilePath, modernTextureSetting, m_context.get()); - - // Ensure what we just serialized-in is identical to what we serialized-out. - // The comparison operator also compares overrides. - EXPECT_TRUE(modernLoadOutcome.IsSuccess()); - EXPECT_TRUE(modernTextureSetting.Equals(legacyTextureSetting, m_context.get())); - - // Remove the temp file that was written out. - AZ::IO::FileIOBase::GetInstance()->Remove(modernMetafilePath.c_str()); -} - -TEST_F(ImageProcessingSerializationTest, TextureSettingReflect_SerializingModernDataInAndOut_WritesAndParsesFileAccurately) -{ - AZStd::string filepath = "test.xml"; - - // Fill-in structure with test data - TextureSettings fakeTextureSettings; - fakeTextureSettings.m_preset = AZ::Uuid::CreateRandom(); - fakeTextureSettings.m_sizeReduceLevel = 0; - fakeTextureSettings.m_suppressEngineReduce = true; - fakeTextureSettings.m_enableMipmap = false; - fakeTextureSettings.m_maintainAlphaCoverage = true; - fakeTextureSettings.m_mipAlphaAdjust = { 0xDEAD, 0xBADBEEF, 0xBADC0DE, 0xFEEFEE, 0xBADF00D, 0xC0FFEE }; - fakeTextureSettings.m_mipGenEval = MipGenEvalType::max; - fakeTextureSettings.m_mipGenType = MipGenType::quadratic; - - // Write test data to file - auto writeOutcome = TextureSettings::WriteTextureSetting(filepath, fakeTextureSettings, m_context.get()); - EXPECT_TRUE(writeOutcome.IsSuccess()); - - // Parse test data to file - TextureSettings parsedFakeTextureSettings; - auto readOutcome = TextureSettings::LoadTextureSetting(filepath, parsedFakeTextureSettings, m_context.get()); - EXPECT_TRUE(readOutcome.IsSuccess()); - EXPECT_TRUE(parsedFakeTextureSettings.Equals(fakeTextureSettings, m_context.get())); - - // Delete temp data - AZ::IO::FileIOBase::GetInstance()->Remove(filepath.c_str()); -} - -TEST_F(ImageProcessingSerializationTest, DISABLED_BuilderSettingsReflect_SerializingDataInAndOut_WritesAndParsesFileAccurately) -{ - AZStd::string buildSettingsFilepath = m_engineRoot + "/Gems/ImageProcessing/Code/Tests/TestAssets/tempPresets.settings"; - AZStd::string rcFilePath = m_engineRoot + "/Code/Tools/RC/Config/rc/rc.ini"; - - auto loadOutcome = BuilderSettingManager::Instance()->LoadBuilderSettingsFromRC(rcFilePath); - ASSERT_TRUE(loadOutcome.IsSuccess()); - - //Save the preset loaded from rc.ini for later comparison - AZ::Uuid oldPresetSettingsUuid = BuilderSettingManager::Instance()->GetPresetIdFromName("NormalsFromDisplacement"); - const PresetSettings oldPresetSetting = *BuilderSettingManager::Instance()->GetPreset(oldPresetSettingsUuid, "pc"); - - //Save builder settings to new file format - auto writeOutcome = BuilderSettingManager::Instance()->WriteBuilderSettings(buildSettingsFilepath, m_context.get()); - ASSERT_TRUE(writeOutcome.IsSuccess()); - - //Re-load Builder Settings - auto reloadOutcome = BuilderSettingManager::Instance()->LoadBuilderSettings(buildSettingsFilepath, m_context.get()); - ASSERT_TRUE(reloadOutcome.IsSuccess()); - - //Find the same preset - AZ::Uuid newPresetSettingsUuid = BuilderSettingManager::Instance()->GetPresetIdFromName("NormalsFromDisplacement"); - const PresetSettings newPresetSetting = *BuilderSettingManager::Instance()->GetPreset(newPresetSettingsUuid, "pc"); - - // Delete temp data - AZ::IO::FileIOBase::GetInstance()->Remove(buildSettingsFilepath.c_str()); - - //make sure the preset loaded from RC.ini is same as the preset loaded from builder setting - ASSERT_EQ(oldPresetSetting, newPresetSetting); -} - -class ProductDependencyTest - : public AllocatorsTestFixture -{ -public: - void SetUp() override - { - AllocatorsTestFixture::SetUp(); - m_data = AZStd::make_unique(); - m_data->m_request.m_sourceFileUUID = AZ::Uuid::CreateRandom(); - m_data->m_rgbBaseFilePath = AZStd::string("Foo/test.dds"); - m_data->m_alphaBaseFilePath = AZStd::string("Foo/test.dds.a"); - m_data->m_diffBaseFilePath = "Foo/test_diff.dds"; - - for (int idx = 1; idx < NumOfMips; idx++) - { - m_data->m_rgbMipsFilePath.push_back(AZStd::string::format("Foo/test.dds.%d", idx)); - m_data->m_alphaMipsFilePath.push_back(AZStd::string::format("Foo/test.dds.%da", idx)); - } - } - - void TearDown() override - { - m_data.reset(); - AllocatorsTestFixture::TearDown(); - } - - - bool ValidateResult(const AZStd::vector& productFilePaths, const AZStd::unordered_map& productDependencyMap) - { - AZStd::vector jobProducts; - m_data->m_imageBuilderWorker.PopulateProducts(m_data->m_request, productFilePaths, jobProducts); - - EXPECT_EQ(productFilePaths.size(), jobProducts.size()); - - for (const AssetBuilderSDK::JobProduct& jobProduct : jobProducts) - { - auto found = productDependencyMap.find(jobProduct.m_productFileName); - if (found != productDependencyMap.end()) - { - EXPECT_EQ(jobProduct.m_dependencies.size(), found->second); - - if (jobProduct.m_dependencies.size() != found->second) - { - return false; - } - } - } - - return true; - } -protected: - - struct StaticData - { - AssetBuilderSDK::ProcessJobRequest m_request; - AZStd::string m_rgbBaseFilePath; - AZStd::vector m_rgbMipsFilePath; - AZStd::string m_alphaBaseFilePath; - AZStd::vector m_alphaMipsFilePath; - AZStd::string m_diffBaseFilePath; - ImageProcessing::ImageBuilderWorker m_imageBuilderWorker; - }; - - AZStd::unique_ptr m_data; - static const int NumOfMips = 5; -}; - -TEST_F(ProductDependencyTest, ProductDependencyBaseRGBFile_Emit_None) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = 0; - productDependencyMap[m_data->m_alphaBaseFilePath] = 0; - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependencyBaseRGBFileAndMips_Emit_All) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = m_data->m_rgbMipsFilePath.size(); - productDependencyMap[m_data->m_alphaBaseFilePath] = 0; - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependencyBaseRGBFileAndBaseAlpha_Emit_ALL) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - productFilePaths.push_back(m_data->m_alphaBaseFilePath); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = 1; // one for the alphaBaseFile - productDependencyMap[m_data->m_alphaBaseFilePath] = 0; - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependencyBaseRGBFile_Emit_ALL) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - productFilePaths.push_back(m_data->m_alphaBaseFilePath); - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - productFilePaths.insert(productFilePaths.end(), m_data->m_alphaMipsFilePath.begin(), m_data->m_alphaMipsFilePath.end()); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = m_data->m_rgbMipsFilePath.size() + 1; // adding one for the alphaBaseFile - productDependencyMap[m_data->m_alphaBaseFilePath] = m_data->m_alphaMipsFilePath.size(); - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependency_Rgb_Diff_EmitALL) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - productFilePaths.push_back(m_data->m_diffBaseFilePath); - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = m_data->m_rgbMipsFilePath.size() + 1; // adding one for the diffBaseFile - productDependencyMap[m_data->m_alphaBaseFilePath] = 0; - productDependencyMap[m_data->m_diffBaseFilePath] = 0; - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependency_Diff_Alpha_EmitALL) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_diffBaseFilePath); - productFilePaths.push_back(m_data->m_alphaBaseFilePath); - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - productFilePaths.insert(productFilePaths.end(), m_data->m_alphaMipsFilePath.begin(), m_data->m_alphaMipsFilePath.end()); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = 0; - productDependencyMap[m_data->m_alphaBaseFilePath] = m_data->m_alphaMipsFilePath.size(); - productDependencyMap[m_data->m_diffBaseFilePath] = m_data->m_rgbMipsFilePath.size() + 1; // adding one for the alphaBaseFile - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependency_Rgb_Diff_Alpha_EmitALL) -{ - AZStd::vector productFilePaths; - productFilePaths.push_back(m_data->m_rgbBaseFilePath); - productFilePaths.push_back(m_data->m_diffBaseFilePath); - productFilePaths.push_back(m_data->m_alphaBaseFilePath); - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - productFilePaths.insert(productFilePaths.end(), m_data->m_alphaMipsFilePath.begin(), m_data->m_alphaMipsFilePath.end()); - - AZStd::unordered_map productDependencyMap; - - productDependencyMap[m_data->m_rgbBaseFilePath] = m_data->m_rgbMipsFilePath.size() + 2; // adding one for the alphaBaseFile and one for diffBaseFile - productDependencyMap[m_data->m_alphaBaseFilePath] = m_data->m_alphaMipsFilePath.size(); - productDependencyMap[m_data->m_diffBaseFilePath] = 0; - EXPECT_TRUE(ValidateResult(productFilePaths, productDependencyMap)); -} - -TEST_F(ProductDependencyTest, ProductDependencyBaseRGBMissing_Error_OK) -{ - AZStd::vector productFilePaths; - productFilePaths.insert(productFilePaths.end(), m_data->m_rgbMipsFilePath.begin(), m_data->m_rgbMipsFilePath.end()); - AZStd::vector jobProducts; - AZ::Outcome result = m_data->m_imageBuilderWorker.PopulateProducts(m_data->m_request, productFilePaths, jobProducts); - - EXPECT_FALSE(result.IsSuccess()); -} - -TEST_F(ProductDependencyTest, ProductDependencyBaseAlphaMissing_Error_OK) -{ - AZStd::vector productFilePaths; - productFilePaths.insert(productFilePaths.end(), m_data->m_alphaMipsFilePath.begin(), m_data->m_alphaMipsFilePath.end()); - AZStd::vector jobProducts; - AZ::Outcome result = m_data->m_imageBuilderWorker.PopulateProducts(m_data->m_request, productFilePaths, jobProducts); - - EXPECT_FALSE(result.IsSuccess()); -} - -} - -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif deleted file mode 100644 index 0a03a3f231..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:db3450a2e68b0ac5d88e82ed01c897ed4ea60a502bf1f44760c6f63ce4970816 -size 3157396 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings b/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings deleted file mode 100644 index 0417122033..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /bumptype=none /M=62,18,32,83,50,50 /preset=Diffuse_highQ /mipgentype=kaiser /reduce="es3:0,ios:3,osx_gl:0,pc:4,provo:1" /ser=0 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/128x128_RGBA8.tga b/Gems/ImageProcessing/Code/Tests/TestAssets/128x128_RGBA8.tga deleted file mode 100644 index b94d39d838..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/128x128_RGBA8.tga +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:116cd9a554235a0a2bf1b2ebbc7fdc38f50aafad7910cad01a7373bbfda3f562 -size 65580 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/200x200_24bit.jpg b/Gems/ImageProcessing/Code/Tests/TestAssets/200x200_24bit.jpg deleted file mode 100644 index d682456d63..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/200x200_24bit.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:588e3bca4304823fdf795fd96a640d3b1e31cc8e82dc1cb1835071aa96f2eb22 -size 34658 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/20x16_32bit.png b/Gems/ImageProcessing/Code/Tests/TestAssets/20x16_32bit.png deleted file mode 100644 index a7f48148f1..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/20x16_32bit.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd5106eebb6cf264fdac5f3568977fc8f944df4a4d4de6b0e9f35b3a001a3001 -size 206 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/237x177_RGB.jpg b/Gems/ImageProcessing/Code/Tests/TestAssets/237x177_RGB.jpg deleted file mode 100644 index 637ce7a86a..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/237x177_RGB.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af31ad61e58d030ef5406685fbccf67f83054fd81cf840aa308e513940f68645 -size 22767 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_16bit_f.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_16bit_f.tif deleted file mode 100644 index cfe2389ab5..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_16bit_f.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dfa0e2bbe4691b2fc98e8456298fc05d771cf2b30c61bba992b340abd2bacd91 -size 23944 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_32bit_f.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_32bit_f.tif deleted file mode 100644 index 7fb71acf75..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/32x32_32bit_f.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fee58c41e2306ad03870b517963f353f9be30378fbbe61e596007f4c3ac4b2cd -size 30088 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/512x288_24bit.tga b/Gems/ImageProcessing/Code/Tests/TestAssets/512x288_24bit.tga deleted file mode 100644 index 7f2daece10..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/512x288_24bit.tga +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f0098e9308e50755484b9bc7205422a54106c593d5d36073bbdbd822c9d459d -size 366890 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/512x512_RGB_N.tga b/Gems/ImageProcessing/Code/Tests/TestAssets/512x512_RGB_N.tga deleted file mode 100644 index d47f00912a..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/512x512_RGB_N.tga +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:646a9a9035cc3f4dfd57babc0055710d2f5bb8aee0a792f2b65d69b4fd6a94b3 -size 786450 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/BlackWhite.png b/Gems/ImageProcessing/Code/Tests/TestAssets/BlackWhite.png deleted file mode 100644 index dfe856790a..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/BlackWhite.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:969c6597a6346c5ff8ae24b4ae143bacbeed2944dd139ddef9b440483dbe4c02 -size 8866921 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/Lenstexture_dirtyglass.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/Lenstexture_dirtyglass.tif deleted file mode 100644 index 090991ec7a..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/Lenstexture_dirtyglass.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:265ae231486dc6d5d61aa2416b0010ea743722f7238660faeed9edacd46e8a6b -size 6303186 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TerrainHeightmap.bt b/Gems/ImageProcessing/Code/Tests/TestAssets/TerrainHeightmap.bt deleted file mode 100644 index d79577ea18..0000000000 Binary files a/Gems/ImageProcessing/Code/Tests/TestAssets/TerrainHeightmap.bt and /dev/null differ diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest.texatlas b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest.texatlas deleted file mode 100644 index 5cd9287208..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest.texatlas +++ /dev/null @@ -1,50 +0,0 @@ -TextureAtlasTest/button.tif -TextureAtlasTest/buttonPressed.tif -TextureAtlasTest/buttonSlider.tif -TextureAtlasTest/checkbox_spritesheet.tif -TextureAtlasTest/checkered3.tif -TextureAtlasTest/Circle_Shadow.tif -TextureAtlasTest/CircleFrame.tif -TextureAtlasTest/CircleGradient.png -TextureAtlasTest/CircleMask.tif -TextureAtlasTest/empty_icon.tif -TextureAtlasTest/fixed_image.tif -TextureAtlasTest/flipbook_walking.tif -TextureAtlasTest/mask.tif -TextureAtlasTest/outline.tif -TextureAtlasTest/outlineRounded.tif -TextureAtlasTest/panelBkgd.tif -TextureAtlasTest/ParticleGlow.tif -TextureAtlasTest/pattern02.tif -TextureAtlasTest/pattern02_big.tif -TextureAtlasTest/pattern02vertical.tif -TextureAtlasTest/pattern02vertical_big.tif -TextureAtlasTest/pattern03.tif -TextureAtlasTest/pattern03_big.tif -TextureAtlasTest/scroll_box_icon_1.tif -TextureAtlasTest/scroll_box_icon_2.tif -TextureAtlasTest/scroll_box_icon_3.tif -TextureAtlasTest/scroll_box_icon_4.tif -TextureAtlasTest/scroll_box_icon_5.tif -TextureAtlasTest/scroll_box_icon_6.tif -TextureAtlasTest/scroll_box_icon_7.tif -TextureAtlasTest/scroll_box_icon_8.tif -TextureAtlasTest/scroll_box_icon_9.tif -TextureAtlasTest/scroll_box_icon_10.tif -TextureAtlasTest/scroll_box_map.tif -TextureAtlasTest/selected.tif -TextureAtlasTest/shadowInside2.tif -TextureAtlasTest/shadowInsideSquare.tif -TextureAtlasTest/imagesequence/flipbook_walking_00.png -TextureAtlasTest/imagesequence/flipbook_walking_01.png -TextureAtlasTest/imagesequence/flipbook_walking_02.png -TextureAtlasTest/imagesequence/flipbook_walking_03.png -TextureAtlasTest/imagesequence/flipbook_walking_04.png -TextureAtlasTest/imagesequence/flipbook_walking_05.png -TextureAtlasTest/imagesequence/flipbook_walking_06.png -TextureAtlasTest/imagesequence/flipbook_walking_07.png -TextureAtlasTest/imagesequence/flipbook_walking_08.png -TextureAtlasTest/imagesequence/flipbook_walking_09.png -TextureAtlasTest/imagesequence/flipbook_walking_10.png -TextureAtlasTest/imagesequence/flipbook_walking_11.png - diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleFrame.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleFrame.tif deleted file mode 100644 index 392119bd62..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleFrame.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:839defde93893bced650c3aae365da2492ed5d3a36833f0d23b842a64459a73a -size 1069744 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleGradient.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleGradient.png deleted file mode 100644 index ab4a88134e..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleGradient.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9a1ada36ae4b3ef01744ab9041f6b822470c2c7595934a05d9eae8dbf4312e90 -size 38112 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleMask.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleMask.tif deleted file mode 100644 index fd29516609..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/CircleMask.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8474b897fe02f70ed8d0e5c47cae8c816c832a7a5739b8c32317737fd275774f -size 1069752 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/Circle_Shadow.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/Circle_Shadow.tif deleted file mode 100644 index a9e9885ee0..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/Circle_Shadow.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:65145dca27e8ddf865019947659956bae3cec4ff069bc0ff6dc4d87379fbd6fe -size 1070868 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/ParticleGlow.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/ParticleGlow.tif deleted file mode 100644 index 50fd39d881..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/ParticleGlow.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4633d813a6111cfe518853737897925b60616ad73f99fc47a4342c5fd2d5134b -size 267526 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/button.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/button.tif deleted file mode 100644 index d43f5383ec..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/button.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c5e07103351b9c8a05056c00abc44370c39cfb9480f5e99d1612ae9ad45cfc5 -size 37780 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonPressed.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonPressed.tif deleted file mode 100644 index eec732a736..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonPressed.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c10511cc5898f3edd24c24099d3dc569ebe9f014af01a523b708d74523209189 -size 37804 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonSlider.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonSlider.tif deleted file mode 100644 index 59fdd32998..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/buttonSlider.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:75a0174a65eb945fdb579816968c42de002ec6210f75add6d4c2829bd1cb8c5a -size 37980 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkbox_spritesheet.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkbox_spritesheet.tif deleted file mode 100644 index 6e2b74b486..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkbox_spritesheet.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40a03c12c1a0123a1fcfaa3f44d343d4318917a9b5851748c74accaa33efda56 -size 17765 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkered3.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkered3.tif deleted file mode 100644 index c1530d4b81..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/checkered3.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6546cc22a1030d2207cd98f8b9afa18abccd24e8b603770c8af6f2c08a769ff0 -size 22360 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/empty_icon.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/empty_icon.tif deleted file mode 100644 index 34a317e80e..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/empty_icon.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23a048ecd54699e9f243f33e9d73b8d8611100357da3f7bcb56a5e1fed08b463 -size 362 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/fixed_image.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/fixed_image.tif deleted file mode 100644 index e1c6d3ad0e..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/fixed_image.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cced003316fae3dec3244be8967b7e28a9168d6184362bd0eb65828ac8a0b53b -size 25642 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/flipbook_walking.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/flipbook_walking.tif deleted file mode 100644 index 9a0f604003..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/flipbook_walking.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91e7ffe470fddde4459e54eb889b2074dc26e8a1c705238c70672b5b3563098a -size 2303404 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_00.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_00.png deleted file mode 100644 index 770d3c724f..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_00.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:356ad2eaf78f24ff44f9a136fa22a17f7114052fff3061b417a48ae6b2767ab0 -size 8742 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_01.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_01.png deleted file mode 100644 index f0624bcdf6..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_01.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5eab5cb57ba50dc1d08abb610599ae6cd8e486dfb8bef1492e01a372ad5b31f -size 7979 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_02.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_02.png deleted file mode 100644 index 36e2450e1b..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_02.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:969a99c99f596f36a51893b14f2f70976809bc7a2ffb1794d0ebca0d5ad20604 -size 7575 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_03.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_03.png deleted file mode 100644 index e18a46d1d6..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_03.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73a6871305f9ee31ae35d78634cd88bb13d4da5273fce11ae5f353460d43e3c9 -size 5923 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_04.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_04.png deleted file mode 100644 index e6235daabd..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_04.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b28de207784be22c7f501e6ada59e9f9174446f43dba9929633627429e8e0ce3 -size 7076 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_05.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_05.png deleted file mode 100644 index 65f5792ac9..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_05.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b74237f5e285dd4eab6d1936b639aa1b87f285e5473b3514f9c1713eef39813 -size 8163 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_06.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_06.png deleted file mode 100644 index 61e547151f..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_06.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad6946b610769ba6d2ccc4269cfae24c5e4f30964fd499442108f8bf17c2e8cd -size 8846 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_07.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_07.png deleted file mode 100644 index d3e1aa0ef6..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_07.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dddff30e20fc4e2f36bedaaca14606d44c9085e8c73841f339ed0a9bc08f26bd -size 7927 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_08.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_08.png deleted file mode 100644 index bdf29b4777..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_08.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d52afab812c6fc8e9c0916c71dc2ea8d957f4326ff9a0ce71658aae06f9d07e5 -size 7459 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_09.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_09.png deleted file mode 100644 index 26fd687534..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_09.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1dad7ebe7690cc9318838dd63bfcace0fad67e14f8f1916dca2fb6ebd267a26c -size 6123 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_10.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_10.png deleted file mode 100644 index dae9568f47..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_10.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a91f9d4be1e432e7b4fa998722ecea178e38ae63ca9f521bb04e5ce2e5159e0f -size 7619 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_11.png b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_11.png deleted file mode 100644 index 60f52297c5..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/imagesequence/flipbook_walking_11.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2979e15676720eb2b81d792880360f8ea26e17322253800b4432f84541d7da7b -size 8245 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/mask.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/mask.tif deleted file mode 100644 index 5e3cd778b4..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/mask.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:764d622d9c589f89f164f4a23d0b66270c25d34c2ecb687640c4ea3e2da55035 -size 36812 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outline.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outline.tif deleted file mode 100644 index 79bdc27a73..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outline.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e502b7ad23409df89c713c9ce43e1df159d4a634f35fec220a7cf8b5e6c2807f -size 56428 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outlineRounded.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outlineRounded.tif deleted file mode 100644 index e48f6108e7..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/outlineRounded.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb9616528ac43a6c46c8f3b4802cbc7cea51ccc0f86dbc5d156fe0806f34edf0 -size 66024 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/panelBkgd.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/panelBkgd.tif deleted file mode 100644 index b9ad540ce0..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/panelBkgd.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5abfb3bfd5eb8044ec3fde65c65d515a43179c87734b1813dc71c07050841b9f -size 27704 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02.tif deleted file mode 100644 index c9895b73b3..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:739955d9e61a89f732316876e1d1ae0503a6296f946324d7d0305b71e12c9f9e -size 23776 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02_big.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02_big.tif deleted file mode 100644 index 50b056d4ef..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02_big.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed7bdcd8572fda83219564e8a92cc6f3d4d15e40e8c5950bf1412f74a799edd9 -size 24824 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical.tif deleted file mode 100644 index f8f2fd578c..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:290a417825baaed85811bcc29d91fd0ba436463dadc1648f669c5042234f96c1 -size 23948 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical_big.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical_big.tif deleted file mode 100644 index afebca233e..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern02vertical_big.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:005b9d7623d9ea1e4a470f6fee67f1eb5f38d7a1ad4e357e0036ce81850c6d5f -size 26032 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03.tif deleted file mode 100644 index 7a13c37c36..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6730661ad80d0d9b94c2c05b9cb321e5e5646a99b267d1680cf8fa9b8d62fb42 -size 23792 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03_big.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03_big.tif deleted file mode 100644 index 0098f2ce53..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/pattern03_big.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2ba16a432f64432c6de9b52703faa1dc413c880e284c8719b3e56c737af6d4a0 -size 26720 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_1.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_1.tif deleted file mode 100644 index a21d2aaaa3..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_1.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0426d9b043f9033967a31a3392b80651871af1d4e60eada2d17e445c19105e32 -size 284432 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_10.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_10.tif deleted file mode 100644 index 54ea437920..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_10.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4eef390a93715bd46f196dc0c7ca311300ae7aca33b8163555b6429e91450497 -size 283492 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_2.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_2.tif deleted file mode 100644 index 9f7ba47daa..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_2.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3d0845d8cc9c75a51ad2c812e6c72ca8147bae2ce12a7ea80e07f579bead937 -size 284884 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_3.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_3.tif deleted file mode 100644 index 4dc54a1950..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_3.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ee3d82984650486f6d2cf4488b60b1723f143134fdb763e390a7fc7c52ace18 -size 284872 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_4.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_4.tif deleted file mode 100644 index 54433305f8..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_4.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:becdab2a389207a942895017511cf453fe059c275dce25c1f5efd41ef13c9d38 -size 285396 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_5.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_5.tif deleted file mode 100644 index 5eae045870..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_5.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:da0222316fcabd92da0908d1750122296e11f7b3e2669e4cbfed3e8c15f08cb0 -size 285076 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_6.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_6.tif deleted file mode 100644 index 54611d8187..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_6.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3d0414c7d73a2ec33a50225af455819abb41f8d35077d3b3ec6bff8cabc3ff6b -size 283664 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_7.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_7.tif deleted file mode 100644 index 2da7dba224..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_7.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:05490310ee718b472efe4b8272077a88e2edf2992c253f46930c9ff1eb52a1e2 -size 283072 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_8.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_8.tif deleted file mode 100644 index 7115f20b1d..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_8.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba9fb34b4769374304e50d54cd34d1b971a5ec975cdae60ac33aa672c738e245 -size 283216 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_9.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_9.tif deleted file mode 100644 index c4f9f70332..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_icon_9.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0d96c5874954efba8c1c164fe5395a3a73647c09c887fe41d74d3a0f7b109ea8 -size 283488 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_map.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_map.tif deleted file mode 100644 index 8235c16cfc..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/scroll_box_map.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98b4c4ee5937d1211a4cf9deca85291bbe1419753cd80d97726839aaacd37699 -size 1597872 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/selected.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/selected.tif deleted file mode 100644 index 6d97b05566..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/selected.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fae0b4d2b33ec478d440fdfdb495a36a3980254087291ffdb5557abd66ffbb6e -size 37124 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInside2.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInside2.tif deleted file mode 100644 index ed0a235b5c..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInside2.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ea15986ef41dafe27f642ca91cccbc89e58247bee6b3f8e7e95bf7e5748c29d4 -size 36848 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInsideSquare.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInsideSquare.tif deleted file mode 100644 index 26c13cf93b..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/TextureAtlasTest/shadowInsideSquare.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:095c764409002b30048579c50c552e63b1578acc473a0bce4a646fdc0748df64 -size 37312 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/greyscale.png b/Gems/ImageProcessing/Code/Tests/TestAssets/greyscale.png deleted file mode 100644 index 6df643605a..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/greyscale.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c0bcbed46bceef7e0686b9b42027d28d98f637c9f7d0d1370eb9911921ba531 -size 1518 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/noon_cm.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/noon_cm.tif deleted file mode 100644 index 5c3c4c7a6f..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/noon_cm.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:461580d9bdd4919b72d1703284f53667378d7345ea57f4c52272ef17603a91c1 -size 3148003 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/normalSmoothness_ddna.tif b/Gems/ImageProcessing/Code/Tests/TestAssets/normalSmoothness_ddna.tif deleted file mode 100644 index 4fb9dce719..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/normalSmoothness_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd619f19b99ea234c44c79a39413faa18e85a4817a57674c27ebf050edad5515 -size 3776022 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/red.png b/Gems/ImageProcessing/Code/Tests/TestAssets/red.png deleted file mode 100644 index 800faddee4..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/red.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:37d146db3de179add861ee86d2316ef1dd413cdb0b02448b3b95bf0023f44bae -size 613 diff --git a/Gems/ImageProcessing/Code/Tests/TestAssets/uppercase.TGA b/Gems/ImageProcessing/Code/Tests/TestAssets/uppercase.TGA deleted file mode 100644 index d3808cdbce..0000000000 --- a/Gems/ImageProcessing/Code/Tests/TestAssets/uppercase.TGA +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a6b6c1bf24dd39159e38c880071abad7b7315c8667192ff2495501dd0b1dec9c -size 85419 diff --git a/Gems/ImageProcessing/Code/imageprocessing_files.cmake b/Gems/ImageProcessing/Code/imageprocessing_files.cmake deleted file mode 100644 index 98aa870b46..0000000000 --- a/Gems/ImageProcessing/Code/imageprocessing_files.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ../Assets/Editor/Resources.qrc - ../Assets/Editor/Backward.png - ../Assets/Editor/Forward.png - ../Assets/Editor/reset.png - Source/ImageProcessingModule.cpp -) diff --git a/Gems/ImageProcessing/Code/imageprocessing_headers_files.cmake b/Gems/ImageProcessing/Code/imageprocessing_headers_files.cmake deleted file mode 100644 index 5714be5dfb..0000000000 --- a/Gems/ImageProcessing/Code/imageprocessing_headers_files.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES -) diff --git a/Gems/ImageProcessing/Code/imageprocessing_static_files.cmake b/Gems/ImageProcessing/Code/imageprocessing_static_files.cmake deleted file mode 100644 index 07bf2ad375..0000000000 --- a/Gems/ImageProcessing/Code/imageprocessing_static_files.cmake +++ /dev/null @@ -1,133 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - Source/ImageProcessing_precompiled.cpp - Source/ImageProcessing_precompiled.h - Source/Compressors/CryTextureSquisher/CryTextureSquisher.cpp - Source/Compressors/CryTextureSquisher/CryTextureSquisher.h - Include/ImageProcessing/ImageProcessingBus.h - Include/ImageProcessing/ImageProcessingEditorBus.h - Include/ImageProcessing/PixelFormats.h - Include/ImageProcessing/ImageObject.h - Source/ImageProcessingSystemComponent.cpp - Source/ImageProcessingSystemComponent.h - Source/ImageBuilderComponent.cpp - Source/ImageBuilderComponent.h - Source/ImageBuilderBaseType.h - Source/BuilderSettings/MipmapSettings.h - Source/BuilderSettings/MipmapSettings.cpp - Source/BuilderSettings/CubemapSettings.h - Source/BuilderSettings/CubemapSettings.cpp - Source/BuilderSettings/PresetSettings.h - Source/BuilderSettings/PresetSettings.cpp - Source/BuilderSettings/TextureSettings.h - Source/BuilderSettings/TextureSettings.cpp - Source/BuilderSettings/BuilderSettings.cpp - Source/BuilderSettings/BuilderSettings.h - Source/BuilderSettings/BuilderSettingManager.cpp - Source/BuilderSettings/BuilderSettingManager.h - Source/BuilderSettings/ImageProcessingDefines.h - Source/BuilderSettings/PlatformSettings.h - Source/Processing/ImageObjectImpl.h - Source/Processing/ImageObjectImpl.cpp - Source/Processing/PixelFormatInfo.h - Source/Processing/PixelFormatInfo.cpp - Source/Processing/ImageConvert.h - Source/Processing/ImageConvert.cpp - Source/Processing/ImageConvertJob.h - Source/Processing/ImageConvertJob.cpp - Source/Processing/ImagePreview.h - Source/Processing/ImagePreview.cpp - Source/Processing/ImageToProcess.h - Source/Processing/ImageFlags.h - Source/Processing/DDSHeader.h - Source/ImageLoader/ImageLoaders.h - Source/ImageLoader/ImageLoaders.cpp - Source/ImageLoader/QtImageLoader.cpp - Source/ImageLoader/TIFFLoader.cpp - Source/ImageLoader/BTImageLoader.cpp - Source/Editor/EditorCommon.h - Source/Editor/EditorCommon.cpp - Source/Editor/TexturePropertyEditor.cpp - Source/Editor/TexturePropertyEditor.h - Source/Editor/TexturePropertyEditor.ui - Source/Editor/MipmapSettingWidget.cpp - Source/Editor/MipmapSettingWidget.h - Source/Editor/MipmapSettingWidget.ui - Source/Editor/ResolutionSettingWidget.cpp - Source/Editor/ResolutionSettingWidget.h - Source/Editor/ResolutionSettingWidget.ui - Source/Editor/ResolutionSettingItemWidget.cpp - Source/Editor/ResolutionSettingItemWidget.h - Source/Editor/ResolutionSettingItemWidget.ui - Source/Editor/TexturePresetSelectionWidget.cpp - Source/Editor/TexturePresetSelectionWidget.h - Source/Editor/TexturePresetSelectionWidget.ui - Source/Editor/TexturePreviewWidget.cpp - Source/Editor/TexturePreviewWidget.h - Source/Editor/TexturePreviewWidget.ui - Source/Editor/ImagePopup.cpp - Source/Editor/ImagePopup.h - Source/Editor/ImagePopup.ui - Source/Editor/PresetInfoPopup.cpp - Source/Editor/PresetInfoPopup.h - Source/Editor/PresetInfoPopup.ui - Source/Converters/Gamma.cpp - Source/Converters/FIR-Filter.cpp - Source/Converters/FIR-Windows.h - Source/Converters/FIR-Weights.h - Source/Converters/FIR-Weights.cpp - Source/Converters/AlphaCoverage.cpp - Source/Converters/PixelOperation.h - Source/Converters/PixelOperation.cpp - Source/Converters/Normalize.cpp - Source/Converters/ConvertPixelFormat.cpp - Source/Converters/Cubemap.h - Source/Converters/Cubemap.cpp - Source/Converters/ColorChart.cpp - Source/Converters/HighPass.cpp - Source/Converters/Histogram.cpp - Source/Converters/Histogram.h - ../External/CubeMapGen/CBBoxInt32.cpp - ../External/CubeMapGen/CBBoxInt32.h - ../External/CubeMapGen/CCubeMapProcessor.cpp - ../External/CubeMapGen/CCubeMapProcessor.h - ../External/CubeMapGen/CImageSurface.cpp - ../External/CubeMapGen/CImageSurface.h - ../External/CubeMapGen/VectorMacros.h - Source/Compressors/Compressor.h - Source/Compressors/Compressor.cpp - Source/Compressors/CTSquisher.h - Source/Compressors/CTSquisher.cpp - Source/Compressors/PVRTC.cpp - Source/Compressors/PVRTC.h - Source/Compressors/ETC2.cpp - Source/Compressors/ETC2.h - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.cpp - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.cpp - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.cpp - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.h - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.h - Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.h - Source/Compressors/CryTextureSquisher/ColorTypes.h - Source/AtlasBuilder/AtlasBuilderComponent.h - Source/AtlasBuilder/AtlasBuilderComponent.cpp - Source/AtlasBuilder/AtlasBuilderWorker.h - Source/AtlasBuilder/AtlasBuilderWorker.cpp -) - -set(SKIP_UNITY_BUILD_INCLUSION_FILES - Source/Compressors/PVRTC.cpp - Source/Compressors/PVRTC.h -) - - diff --git a/Gems/ImageProcessing/Code/imageprocessing_tests_files.cmake b/Gems/ImageProcessing/Code/imageprocessing_tests_files.cmake deleted file mode 100644 index 290f00104a..0000000000 --- a/Gems/ImageProcessing/Code/imageprocessing_tests_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - Tests/ImageProcessing_Test.cpp - Tests/AtlasBuilderTest.cpp -) diff --git a/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.cpp b/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.cpp deleted file mode 100644 index 5e80267f56..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.cpp +++ /dev/null @@ -1,129 +0,0 @@ - -//============================================================================= -//CBBoxInt32 -// 3D bounding box with int32 coordinates -// -//============================================================================= -// (C) 2005 ATI Research, Inc., All rights reserved. -//============================================================================= -// modifications by Crytek GmbH -// modifications by Amazon - -#include - -#include "CBBoxInt32.h" - -#define CP_MIN_INT32 0x80000000 -#define CP_MAX_INT32 0x7fffffff -#define CP_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define CP_MAX(a, b) (((a) > (b)) ? (a) : (b)) - - -namespace ImageProcessing -{ - //-------------------------------------------------------------------------------------- - // CBBoxInt32 - //-------------------------------------------------------------------------------------- - CBBoxInt32::CBBoxInt32(void) - { - Clear(); - } - - - //-------------------------------------------------------------------------------------- - // Text to see if CBBoxInt32 is empty or not - //-------------------------------------------------------------------------------------- - bool CBBoxInt32::Empty(void) - { - if ((m_minCoord[0] > m_maxCoord[0]) || - (m_minCoord[1] > m_maxCoord[1]) || - (m_minCoord[2] > m_maxCoord[2])) - { - return true; - } - else - { - return false; - } - } - - - //-------------------------------------------------------------------------------------- - // Clear bounding box extents - //-------------------------------------------------------------------------------------- - void CBBoxInt32::Clear(void) - { - m_minCoord[0] = CP_MAX_INT32; - m_minCoord[1] = CP_MAX_INT32; - m_minCoord[2] = CP_MAX_INT32; - m_maxCoord[0] = CP_MIN_INT32; - m_maxCoord[1] = CP_MIN_INT32; - m_maxCoord[2] = CP_MIN_INT32; - } - - - //-------------------------------------------------------------------------------------- - // Augment bounding box extents by specifying point to include in bounding box - //-------------------------------------------------------------------------------------- - void CBBoxInt32::Augment(int32 aX, int32 aY, int32 aZ) - { - m_minCoord[0] = CP_MIN(m_minCoord[0], aX); - m_minCoord[1] = CP_MIN(m_minCoord[1], aY); - m_minCoord[2] = CP_MIN(m_minCoord[2], aZ); - m_maxCoord[0] = CP_MAX(m_maxCoord[0], aX); - m_maxCoord[1] = CP_MAX(m_maxCoord[1], aY); - m_maxCoord[2] = CP_MAX(m_maxCoord[2], aZ); - } - - - //-------------------------------------------------------------------------------------- - // Augment bounding box extents by specifying x coordinate to include in bounding box - //-------------------------------------------------------------------------------------- - void CBBoxInt32::AugmentX(int32 aX) - { - m_minCoord[0] = CP_MIN(m_minCoord[0], aX); - m_maxCoord[0] = CP_MAX(m_maxCoord[0], aX); - } - - - //-------------------------------------------------------------------------------------- - // Augment bounding box extents by specifying x coordinate to include in bounding box - //-------------------------------------------------------------------------------------- - void CBBoxInt32::AugmentY(int32 aY) - { - m_minCoord[1] = CP_MIN(m_minCoord[1], aY); - m_maxCoord[1] = CP_MAX(m_maxCoord[1], aY); - } - - - //-------------------------------------------------------------------------------------- - // Augment bounding box extents by specifying x coordinate to include in bounding box - //-------------------------------------------------------------------------------------- - void CBBoxInt32::AugmentZ(int32 aZ) - { - m_minCoord[2] = CP_MIN(m_minCoord[2], aZ); - m_maxCoord[2] = CP_MAX(m_maxCoord[2], aZ); - } - - - //-------------------------------------------------------------------------------------- - // Clamp minimum values in bbox to be no larger than aX, aY, aZ - //-------------------------------------------------------------------------------------- - void CBBoxInt32::ClampMin(int32 aX, int32 aY, int32 aZ) - { - m_minCoord[0] = CP_MAX(m_minCoord[0], aX); - m_minCoord[1] = CP_MAX(m_minCoord[1], aY); - m_minCoord[2] = CP_MAX(m_minCoord[2], aZ); - } - - - //-------------------------------------------------------------------------------------- - // Clamp maximum values in bbox to be no larger than aX, aY, aZ - //-------------------------------------------------------------------------------------- - void CBBoxInt32::ClampMax(int32 aX, int32 aY, int32 aZ) - { - m_maxCoord[0] = CP_MIN(m_maxCoord[0], aX); - m_maxCoord[1] = CP_MIN(m_maxCoord[1], aY); - m_maxCoord[2] = CP_MIN(m_maxCoord[2], aZ); - } -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.h b/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.h deleted file mode 100644 index a6bbe0c327..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/CBBoxInt32.h +++ /dev/null @@ -1,32 +0,0 @@ -//============================================================================= -//CBBoxInt32 -// 3D bounding box with int32 coordinates -// -//============================================================================= -// (C) 2005 ATI Research, Inc., All rights reserved. -//============================================================================= -// modifications by Crytek GmbH -// modifications by Amazon - -#pragma once - -namespace ImageProcessing -{ - //bounding box class with coords specified as int32 - class CBBoxInt32 - { - public: - int32 m_minCoord[3]; //upper left back corner - int32 m_maxCoord[3]; //lower right front corner - - CBBoxInt32(); - bool Empty(void); - void Clear(void); - void Augment(int32 a_X, int32 a_Y, int32 a_Z); - void AugmentX(int32 a_X); - void AugmentY(int32 a_Y); - void AugmentZ(int32 a_Z); - void ClampMin(int32 a_X, int32 a_Y, int32 a_Z); - void ClampMax(int32 a_X, int32 a_Y, int32 a_Z); - }; -} //namespace ImageProcessing diff --git a/Gems/ImageProcessing/External/CubeMapGen/CCubeMapProcessor.cpp b/Gems/ImageProcessing/External/CubeMapGen/CCubeMapProcessor.cpp deleted file mode 100644 index 794e860f28..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/CCubeMapProcessor.cpp +++ /dev/null @@ -1,2237 +0,0 @@ -//============================================================================= -// (C) 2005 ATI Research, Inc., All rights reserved. -//============================================================================= -// modifications by Crytek GmbH -// modifications by Amazon - -#include -#include "CCubeMapProcessor.h" - -#include - -#define CP_PI 3.14159265358979323846 - - -namespace ImageProcessing -{ - - //------------------------------------------------------------------------------ - // D3D cube map face specification - // mapping from 3D x,y,z cube map lookup coordinates - // to 2D within face u,v coordinates - // - // --------------------> U direction - // | (within-face texture space) - // | _____ - // | | | - // | | +Y | - // | _____|_____|_____ _____ - // | | | | | | - // | | -X | +Z | +X | -Z | - // | |_____|_____|_____|_____| - // | | | - // | | -Y | - // | |_____| - // | - // v V direction - // (within-face texture space) - //------------------------------------------------------------------------------ - - //Information about neighbors and how texture coorrdinates change across faces - // in ORDER of left, right, top, bottom (e.g. edges corresponding to u=0, - // u=1, v=0, v=1 in the 2D coordinate system of the particular face. - //Note this currently assumes the D3D cube face ordering and orientation - CPCubeMapNeighbor sg_CubeNgh[6][4] = - { - //XPOS face - {{CP_FACE_Z_POS, CP_EDGE_RIGHT }, - {CP_FACE_Z_NEG, CP_EDGE_LEFT }, - {CP_FACE_Y_POS, CP_EDGE_RIGHT }, - {CP_FACE_Y_NEG, CP_EDGE_RIGHT }}, - //XNEG face - {{CP_FACE_Z_NEG, CP_EDGE_RIGHT }, - {CP_FACE_Z_POS, CP_EDGE_LEFT }, - {CP_FACE_Y_POS, CP_EDGE_LEFT }, - {CP_FACE_Y_NEG, CP_EDGE_LEFT }}, - //YPOS face - {{CP_FACE_X_NEG, CP_EDGE_TOP }, - {CP_FACE_X_POS, CP_EDGE_TOP }, - {CP_FACE_Z_NEG, CP_EDGE_TOP }, - {CP_FACE_Z_POS, CP_EDGE_TOP }}, - //YNEG face - {{CP_FACE_X_NEG, CP_EDGE_BOTTOM}, - {CP_FACE_X_POS, CP_EDGE_BOTTOM}, - {CP_FACE_Z_POS, CP_EDGE_BOTTOM}, - {CP_FACE_Z_NEG, CP_EDGE_BOTTOM}}, - //ZPOS face - {{CP_FACE_X_NEG, CP_EDGE_RIGHT }, - {CP_FACE_X_POS, CP_EDGE_LEFT }, - {CP_FACE_Y_POS, CP_EDGE_BOTTOM }, - {CP_FACE_Y_NEG, CP_EDGE_TOP }}, - //ZNEG face - {{CP_FACE_X_POS, CP_EDGE_RIGHT }, - {CP_FACE_X_NEG, CP_EDGE_LEFT }, - {CP_FACE_Y_POS, CP_EDGE_TOP }, - {CP_FACE_Y_NEG, CP_EDGE_BOTTOM }} - }; - - - //3x2 matrices that map cube map indexing vectors in 3d - // (after face selection and divide through by the - // _ABSOLUTE VALUE_ of the max coord) - // into NVC space - //Note this currently assumes the D3D cube face ordering and orientation - #define CP_UDIR 0 - #define CP_VDIR 1 - #define CP_FACEAXIS 2 - - float sgFace2DMapping[6][3][3] = { - //XPOS face - {{ 0, 0, -1}, //u towards negative Z - { 0, -1, 0}, //v towards negative Y - {1, 0, 0}}, //pos X axis - //XNEG face - {{0, 0, 1}, //u towards positive Z - {0, -1, 0}, //v towards negative Y - {-1, 0, 0}}, //neg X axis - //YPOS face - {{1, 0, 0}, //u towards positive X - {0, 0, 1}, //v towards positive Z - {0, 1 , 0}}, //pos Y axis - //YNEG face - {{1, 0, 0}, //u towards positive X - {0, 0 , -1}, //v towards negative Z - {0, -1 , 0}}, //neg Y axis - //ZPOS face - {{1, 0, 0}, //u towards positive X - {0, -1, 0}, //v towards negative Y - {0, 0, 1}}, //pos Z axis - //ZNEG face - {{-1, 0, 0}, //u towards negative X - {0, -1, 0}, //v towards negative Y - {0, 0, -1}}, //neg Z axis - }; - - - //The 12 edges of the cubemap, (entries are used to index into the neighbor table) - // this table is used to average over the edges. - int32 sg_CubeEdgeList[12][2] = { - {CP_FACE_X_POS, CP_EDGE_LEFT}, - {CP_FACE_X_POS, CP_EDGE_RIGHT}, - {CP_FACE_X_POS, CP_EDGE_TOP}, - {CP_FACE_X_POS, CP_EDGE_BOTTOM}, - - {CP_FACE_X_NEG, CP_EDGE_LEFT}, - {CP_FACE_X_NEG, CP_EDGE_RIGHT}, - {CP_FACE_X_NEG, CP_EDGE_TOP}, - {CP_FACE_X_NEG, CP_EDGE_BOTTOM}, - - {CP_FACE_Z_POS, CP_EDGE_TOP}, - {CP_FACE_Z_POS, CP_EDGE_BOTTOM}, - {CP_FACE_Z_NEG, CP_EDGE_TOP}, - {CP_FACE_Z_NEG, CP_EDGE_BOTTOM} - }; - - - //Information about which of the 8 cube corners are correspond to the - // the 4 corners in each cube face - // the order is upper left, upper right, lower left, lower right - int32 sg_CubeCornerList[6][4] = { - { CP_CORNER_PPP, CP_CORNER_PPN, CP_CORNER_PNP, CP_CORNER_PNN }, // XPOS face - { CP_CORNER_NPN, CP_CORNER_NPP, CP_CORNER_NNN, CP_CORNER_NNP }, // XNEG face - { CP_CORNER_NPN, CP_CORNER_PPN, CP_CORNER_NPP, CP_CORNER_PPP }, // YPOS face - { CP_CORNER_NNP, CP_CORNER_PNP, CP_CORNER_NNN, CP_CORNER_PNN }, // YNEG face - { CP_CORNER_NPP, CP_CORNER_PPP, CP_CORNER_NNP, CP_CORNER_PNP }, // ZPOS face - { CP_CORNER_PPN, CP_CORNER_NPN, CP_CORNER_PNN, CP_CORNER_NNN } // ZNEG face - }; - - - //-------------------------------------------------------------------------------------- - // Convert cubemap face texel coordinates and face idx to 3D vector - // note the U and V coords are integer coords and range from 0 to size-1 - // this routine can be used to generate a normalizer cube map - //-------------------------------------------------------------------------------------- - void TexelCoordToVect(int32 a_FaceIdx, float a_U, float a_V, int32 a_Size, float *a_XYZ) - { - float nvcU, nvcV; - float tempVec[3]; - - //scale up to [-1, 1] range (inclusive) - nvcU = (2.0f * ((float)a_U + 0.5f) / a_Size ) - 1.0f; - nvcV = (2.0f * ((float)a_V + 0.5f) / a_Size ) - 1.0f; - - //generate x,y,z vector (xform 2d NVC coord to 3D vector) - //U contribution - VM_SCALE3(a_XYZ, sgFace2DMapping[a_FaceIdx][CP_UDIR], nvcU); - //V contribution - VM_SCALE3(tempVec, sgFace2DMapping[a_FaceIdx][CP_VDIR], nvcV); - VM_ADD3(a_XYZ, tempVec, a_XYZ); - //add face axis - VM_ADD3(a_XYZ, sgFace2DMapping[a_FaceIdx][CP_FACEAXIS], a_XYZ); - - //normalize vector - VM_NORM3(a_XYZ, a_XYZ); - } - - - //-------------------------------------------------------------------------------------- - // Convert 3D vector to cubemap face texel coordinates and face idx - // note the U and V coords are integer coords and range from 0 to size-1 - // this routine can be used to generate a normalizer cube map - // - // returns face IDX and texel coords - //-------------------------------------------------------------------------------------- - void VectToTexelCoord(float *a_XYZ, int32 a_Size, int32 *a_FaceIdx, int32 *a_U, int32 *a_V ) - { - float nvcU, nvcV; - float absXYZ[3]; - float maxCoord; - float onFaceXYZ[3]; - int32 faceIdx; - int32 u, v; - - //absolute value 3 - VM_ABS3(absXYZ, a_XYZ); - - if( (absXYZ[0] >= absXYZ[1]) && (absXYZ[0] >= absXYZ[2]) ) - { - maxCoord = absXYZ[0]; - - if(a_XYZ[0] >= 0) //face = XPOS - { - faceIdx = CP_FACE_X_POS; - } - else - { - faceIdx = CP_FACE_X_NEG; - } - } - else if ( (absXYZ[1] >= absXYZ[0]) && (absXYZ[1] >= absXYZ[2]) ) - { - maxCoord = absXYZ[1]; - - if(a_XYZ[1] >= 0) //face = XPOS - { - faceIdx = CP_FACE_Y_POS; - } - else - { - faceIdx = CP_FACE_Y_NEG; - } - } - else // if( (absXYZ[2] > absXYZ[0]) && (absXYZ[2] > absXYZ[1]) ) - { - maxCoord = absXYZ[2]; - - if(a_XYZ[2] >= 0) //face = XPOS - { - faceIdx = CP_FACE_Z_POS; - } - else - { - faceIdx = CP_FACE_Z_NEG; - } - } - - //divide through by max coord so face vector lies on cube face - VM_SCALE3(onFaceXYZ, a_XYZ, 1.0f/maxCoord); - nvcU = VM_DOTPROD3(sgFace2DMapping[ faceIdx ][CP_UDIR], onFaceXYZ ); - nvcV = VM_DOTPROD3(sgFace2DMapping[ faceIdx ][CP_VDIR], onFaceXYZ ); - - u = (int32)floor( a_Size * 0.5f * (nvcU + 1.0f) ); - v = (int32)floor( a_Size * 0.5f * (nvcV + 1.0f) ); - - *a_FaceIdx = faceIdx; - *a_U = u; - *a_V = v; - } - - - //-------------------------------------------------------------------------------------- - // gets texel ptr in a cube map given a direction vector, and an array of - // CImageSurfaces that represent the cube faces. - // - //-------------------------------------------------------------------------------------- - CP_ITYPE *GetCubeMapTexelPtr(float *a_XYZ, CImageSurface *a_Surface) - { - int32 u, v, faceIdx; - - //get face idx and u, v texel coordinate in face - VectToTexelCoord(a_XYZ, a_Surface[0].m_Width, &faceIdx, &u, &v ); - - u = VM_MIN(u, a_Surface[0].m_Width - 1); - v = VM_MIN(v, a_Surface[0].m_Width - 1); - - return( a_Surface[faceIdx].GetSurfaceTexelPtr(u, v) ); - } - - - //-------------------------------------------------------------------------------------- - // Compute solid angle of given texel in cubemap face for weighting taps in the - // kernel by the area they project to on the unit sphere. - // - // Note that this code uses an approximation to the solid angle, by treating the - // two triangles that make up the quad comprising the texel as planar. If more - // accuracy is required, the solid angle per triangle lying on the sphere can be - // computed using the sum of the interior angles - PI. - // - //-------------------------------------------------------------------------------------- - float TexelCoordSolidAngle(int32 a_FaceIdx, float a_U, float a_V, int32 a_Size) - { - float cornerVect[4][3]; - double cornerVect64[4][3]; - - float halfTexelStep = 0.5f; //note u, and v are in texel coords (where each texel is one unit) - double edgeVect0[3]; - double edgeVect1[3]; - double xProdVect[3]; - double texelArea; - - //compute 4 corner vectors of texel - TexelCoordToVect(a_FaceIdx, a_U - halfTexelStep, a_V - halfTexelStep, a_Size, cornerVect[0] ); - TexelCoordToVect(a_FaceIdx, a_U - halfTexelStep, a_V + halfTexelStep, a_Size, cornerVect[1] ); - TexelCoordToVect(a_FaceIdx, a_U + halfTexelStep, a_V - halfTexelStep, a_Size, cornerVect[2] ); - TexelCoordToVect(a_FaceIdx, a_U + halfTexelStep, a_V + halfTexelStep, a_Size, cornerVect[3] ); - - VM_NORM3_UNTYPED(cornerVect64[0], cornerVect[0] ); - VM_NORM3_UNTYPED(cornerVect64[1], cornerVect[1] ); - VM_NORM3_UNTYPED(cornerVect64[2], cornerVect[2] ); - VM_NORM3_UNTYPED(cornerVect64[3], cornerVect[3] ); - - //area of triangle defined by corners 0, 1, and 2 - VM_SUB3_UNTYPED(edgeVect0, cornerVect64[1], cornerVect64[0] ); - VM_SUB3_UNTYPED(edgeVect1, cornerVect64[2], cornerVect64[0] ); - VM_XPROD3_UNTYPED(xProdVect, edgeVect0, edgeVect1 ); - texelArea = 0.5f * sqrt( VM_DOTPROD3_UNTYPED(xProdVect, xProdVect ) ); - - //area of triangle defined by corners 1, 2, and 3 - VM_SUB3_UNTYPED(edgeVect0, cornerVect64[2], cornerVect64[1] ); - VM_SUB3_UNTYPED(edgeVect1, cornerVect64[3], cornerVect64[1] ); - VM_XPROD3_UNTYPED(xProdVect, edgeVect0, edgeVect1 ); - texelArea += 0.5f * sqrt( VM_DOTPROD3_UNTYPED(xProdVect, xProdVect ) ); - - return texelArea; - } - - - - //-------------------------------------------------------------------------------------- - //Builds a normalizer cubemap - // - // Takes in a cube face size, and an array of 6 surfaces to write the cube faces into - // - // Note that this normalizer cube map stores the vectors in unbiased -1 to 1 range. - // if _bx2 style scaled and biased vectors are needed, uncomment the SCALE and BIAS - // below - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::BuildNormalizerCubemap(int32 a_Size, CImageSurface *a_Surface ) - { - int32 iCubeFace, u, v; - - //iterate over cube faces - for(iCubeFace=0; iCubeFace<6; iCubeFace++) - { - a_Surface[iCubeFace].Clear(); - a_Surface[iCubeFace].Init(a_Size, a_Size, 3); - - //fast texture walk, build normalizer cube map - CP_ITYPE *texelPtr = a_Surface[iCubeFace].m_ImgData; - - for(v=0; v < a_Surface[iCubeFace].m_Height; v++) - { - for(u=0; u < a_Surface[iCubeFace].m_Width; u++) - { - TexelCoordToVect(iCubeFace, (float)u, (float)v, a_Size, texelPtr); - - //VM_SCALE3(texelPtr, texelPtr, 0.5f); - //VM_BIAS3(texelPtr, texelPtr, 0.5f); - - texelPtr += a_Surface[iCubeFace].m_NumChannels; - } - } - } - } - - - //-------------------------------------------------------------------------------------- - //Builds a normalizer cubemap, with the texels solid angle stored in the fourth component - // - //Takes in a cube face size, and an array of 6 surfaces to write the cube faces into - // - //Note that this normalizer cube map stores the vectors in unbiased -1 to 1 range. - // if _bx2 style scaled and biased vectors are needed, uncomment the SCALE and BIAS - // below - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::BuildNormalizerSolidAngleCubemap(int32 a_Size, CImageSurface *a_Surface ) - { - //iterate over cube faces - for(int32 iCubeFace=0; iCubeFace<6; iCubeFace++) - { - a_Surface[iCubeFace].Clear(); - a_Surface[iCubeFace].Init(a_Size, a_Size, 4); //First three channels for norm cube, and last channel for solid angle - } - - //iterate over cube faces - for(int32 iCubeFace=0; iCubeFace<6; iCubeFace++) - { - const int32 height = a_Surface[iCubeFace].m_Height; - const int32 width = a_Surface[iCubeFace].m_Width; - - for(int32 v=0; v 0) - { - neighborFace = sg_CubeNgh[faceIdx][i].m_Face; - neighborEdge = sg_CubeNgh[faceIdx][i].m_Edge; - - //For certain types of edge abutments, the bleedOverBBoxMin, and bleedOverBBoxMax need to - // be flipped: the cases are - // if a left edge mates with a left or bottom edge on the neighbor - // if a top edge mates with a top or right edge on the neighbor - // if a right edge mates with a right or top edge on the neighbor - // if a bottom edge mates with a bottom or left edge on the neighbor - //Seeing as the edges are enumerated as follows - // left =0 - // right =1 - // top =2 - // bottom =3 - // - // so if the edge enums are the same, or the sum of the enums == 3, - // the bbox needs to be flipped - if( (i == neighborEdge) || ((i+neighborEdge) == 3) ) - { - bleedOverBBoxMin[i] = (a_SrcSize-1) - bleedOverBBoxMin[i]; - bleedOverBBoxMax[i] = (a_SrcSize-1) - bleedOverBBoxMax[i]; - } - - - //The way the bounding box is extended onto the neighboring face - // depends on which edge of neighboring face abuts with this one - switch(sg_CubeNgh[faceIdx][i].m_Edge) - { - case CP_EDGE_LEFT: - a_FilterExtents[neighborFace].Augment(0, bleedOverBBoxMin[i], 0); - a_FilterExtents[neighborFace].Augment(bleedOverAmount[i], bleedOverBBoxMax[i], 0); - break; - case CP_EDGE_RIGHT: - a_FilterExtents[neighborFace].Augment( (a_SrcSize-1), bleedOverBBoxMin[i], 0); - a_FilterExtents[neighborFace].Augment( (a_SrcSize-1) - bleedOverAmount[i], bleedOverBBoxMax[i], 0); - break; - case CP_EDGE_TOP: - a_FilterExtents[neighborFace].Augment(bleedOverBBoxMin[i], 0, 0); - a_FilterExtents[neighborFace].Augment(bleedOverBBoxMax[i], bleedOverAmount[i], 0); - break; - case CP_EDGE_BOTTOM: - a_FilterExtents[neighborFace].Augment(bleedOverBBoxMin[i], (a_SrcSize-1), 0); - a_FilterExtents[neighborFace].Augment(bleedOverBBoxMax[i], (a_SrcSize-1) - bleedOverAmount[i], 0); - break; - } - - //clamp filter extents in non-center tap faces to remain within surface - a_FilterExtents[neighborFace].ClampMin(0, 0, 0); - a_FilterExtents[neighborFace].ClampMax(a_SrcSize-1, a_SrcSize-1, 0); - } - - //If the bleed over amount bleeds past the adjacent face onto the opposite face - // from the center tap face, then process the opposite face entirely for now. - //Note that the cases in which this happens, what usually happens is that - // more than one edge bleeds onto the opposite face, and the bounding box - // encompasses the entire cube map face. - if(bleedOverAmount[i] > a_SrcSize) - { - uint32 oppositeFaceIdx; - - //determine opposite face - switch(faceIdx) - { - case CP_FACE_X_POS: - oppositeFaceIdx = CP_FACE_X_NEG; - break; - case CP_FACE_X_NEG: - oppositeFaceIdx = CP_FACE_X_POS; - break; - case CP_FACE_Y_POS: - oppositeFaceIdx = CP_FACE_Y_NEG; - break; - case CP_FACE_Y_NEG: - oppositeFaceIdx = CP_FACE_Y_POS; - break; - case CP_FACE_Z_POS: - oppositeFaceIdx = CP_FACE_Z_NEG; - break; - default: // CP_FACE_Z_NEG: - oppositeFaceIdx = CP_FACE_Z_POS; - break; - } - - //just encompass entire face for now - a_FilterExtents[oppositeFaceIdx].Augment(0, 0, 0); - a_FilterExtents[oppositeFaceIdx].Augment((a_SrcSize-1), (a_SrcSize-1), 0); - } - } - - minV=minV; - } - - - //-------------------------------------------------------------------------------------- - //ProcessFilterExtents - // Process bounding box in each cube face - // - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::ProcessFilterExtents(float *a_CenterTapDir, float a_DotProdThresh, - CBBoxInt32 *a_FilterExtents, CImageSurface *a_NormCubeMap, CImageSurface *a_SrcCubeMap, - CP_ITYPE *a_DstVal, uint32 a_FilterType, bool a_bUseSolidAngleWeighting, float a_SpecularPower) - { - //accumulators are 64-bit floats in order to have the precision needed - // over a summation of a large number of pixels - double dstAccumFace[6][4]; - double weightAccumFace[6]; - - const int32 nSrcChannels = a_SrcCubeMap[0].m_NumChannels; - - //norm cube map and srcCubeMap have same face width - const int32 faceWidth = a_NormCubeMap[0].m_Width; - - //amount to add to pointer to move to next scanline in images - const int32 normCubePitch = faceWidth * a_NormCubeMap[0].m_NumChannels; - const int32 srcCubePitch = faceWidth * a_SrcCubeMap[0].m_NumChannels; - - //iterate over cubefaces - for(int32 iFaceIdx=0; iFaceIdx<6; iFaceIdx++ ) - { - //dest accum - for(int32 k=0; k= a_DotProdThresh ) - { - CP_ITYPE weight; - - //for now just weight all taps equally, but ideally - // weight should be proportional to the solid angle of the tap - if(a_bUseSolidAngleWeighting == true) - { //solid angle stored in 4th channel of normalizer/solid angle cube map - weight = *(texelVect+3); - } - else - { //all taps equally weighted - weight = 1.0f; - } - - switch(a_FilterType) - { - case CP_FILTER_TYPE_COSINE_POWER: - { - if(tapDotProd > 0.0f) - { - weight *= pow(tapDotProd, a_SpecularPower) * tapDotProd; - } - else - { - weight = 0; - } - } - break; - case CP_FILTER_TYPE_CONE: - case CP_FILTER_TYPE_ANGULAR_GAUSSIAN: - { - //weights are in same lookup table for both of these filter types - weight *= m_FilterLUT[(int32)(tapDotProd * (m_NumFilterLUTEntries - 1))]; - } - break; - case CP_FILTER_TYPE_COSINE: - { - if(tapDotProd > 0.0f) - { - weight *= tapDotProd; - } - else - { - weight = 0.0f; - } - } - break; - case CP_FILTER_TYPE_DISC: - default: - break; - } - - //iterate over channels - for(int32 k=0; k>= 1; - - m_NumMipLevels++; - - //terminate if mip chain becomes too small - if(mipLevelSize == 0) - { - return; - } - } - } - - - //-------------------------------------------------------------------------------------- - //Copy and convert cube map face data from an external image/surface into this object - // - // a_FaceIdx = a value 0 to 5 speciying which face to copy into (one of the CP_FACE_? ) - // a_Level = mip level to copy into - // a_SrcType = data type of image being copyed from (one of the CP_TYPE_? types) - // a_SrcNumChannels = number of channels of the image being copied from (usually 1 to 4) - // a_SrcPitch = number of bytes per row of the source image being copied from - // a_SrcDataPtr = pointer to the image data to copy from - // a_Degamma = original gamma level of input image to undo by degamma - // a_Scale = scale to apply to pixel values after degamma (in linear space) - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::SetInputFaceData(int32 a_FaceIdx, int32 a_SrcType, int32 a_SrcNumChannels, - int32 a_SrcPitch, void *a_SrcDataPtr, float a_MaxClamp, float a_Degamma, float a_Scale) - { - //since input is being modified, terminate any active filtering threads - TerminateActiveThreads(); - - m_InputSurface[a_FaceIdx].SetImageDataClampDegammaScale( a_SrcType, a_SrcNumChannels, a_SrcPitch, - a_SrcDataPtr, a_MaxClamp, a_Degamma, a_Scale ); - } - - - //-------------------------------------------------------------------------------------- - //Copy and convert cube map face data from this object into an external image/surface - // - // a_FaceIdx = a value 0 to 5 speciying which face to copy into (one of the CP_FACE_? ) - // a_Level = mip level to copy into - // a_DstType = data type of image to copy to (one of the CP_TYPE_? types) - // a_DstNumChannels = number of channels of the image to copy to (usually 1 to 4) - // a_DstPitch = number of bytes per row of the dest image to copy to - // a_DstDataPtr = pointer to the image data to copy to - // a_Scale = scale to apply to pixel values (in linear space) before gamma for output - // a_Gamma = gamma level to apply to pixels after scaling - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::GetInputFaceData(int32 a_FaceIdx, int32 a_DstType, int32 a_DstNumChannels, - int32 a_DstPitch, void *a_DstDataPtr, float a_Scale, float a_Gamma) - { - m_InputSurface[a_FaceIdx].GetImageDataScaleGamma( a_DstType, a_DstNumChannels, a_DstPitch, - a_DstDataPtr, a_Scale, a_Gamma ); - } - - - //-------------------------------------------------------------------------------------- - //ChannelSwapInputFaceData - // swizzle data in first 4 channels for input faces - // - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::ChannelSwapInputFaceData(int32 a_Channel0Src, int32 a_Channel1Src, - int32 a_Channel2Src, int32 a_Channel3Src ) - { - int32 iFace, u, v, k; - int32 size; - CP_ITYPE texelData[4]; - int32 channelSrcArray[4]; - - //since input is being modified, terminate any active filtering threads - TerminateActiveThreads(); - - size = m_InputSize; - - channelSrcArray[0] = a_Channel0Src; - channelSrcArray[1] = a_Channel1Src; - channelSrcArray[2] = a_Channel2Src; - channelSrcArray[3] = a_Channel3Src; - - //Iterate over faces for input images - for(iFace=0; iFace<6; iFace++) - { - for(v=0; v> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - - return float(bits) * 2.3283064365386963e-10; // float(bits) * 2^-32 - } - - inline void HammersleySequence(uint32 sampleIndex, uint32 sampleCount, float* vXi) - { - vXi[0] = float(sampleIndex) / float(sampleCount); - vXi[1] = RadicalInverse2(sampleIndex); - } - - void ImportanceSampleGGX(float* vXi, float roughness, float* vNormal, float* vOut) - { - float phi = 2 * CP_PI * vXi[0]; - float cosTheta = sqrtf((1 - vXi[1]) / ( 1 + (roughness * roughness - 1) * vXi[1])); - float sinTheta = sqrtf(1 - cosTheta * cosTheta); - - float vH[3]; - vH[0] = sinTheta * cosf(phi); - vH[1] = sinTheta * sinf(phi); - vH[2] = cosTheta; - - float vUpVectorX[3] = {1, 0, 0}; - float vUpVectorZ[3] = {0, 0, 1}; - float vTangentX[3]; - float vTangentY[3]; - float vTempVec[3]; - - // Build local frame - VM_XPROD3(vTempVec, fabs(vNormal[2]) < 0.999f ? vUpVectorZ : vUpVectorX, vNormal); - VM_NORM3(vTangentX, vTempVec); - VM_XPROD3(vTangentY, vNormal, vTangentX); - - // Convert from tangent to world space - vOut[0] = vTangentX[0] * vH[0] + vTangentY[0] * vH[1] + vNormal[0] * vH[2]; - vOut[1] = vTangentX[1] * vH[0] + vTangentY[1] * vH[1] + vNormal[1] * vH[2]; - vOut[2] = vTangentX[2] * vH[0] + vTangentY[2] * vH[1] + vNormal[2] * vH[2]; - } - - - void CCubeMapProcessor::FilterCubeSurfacesGGX(CImageSurface *a_SrcCubeMap, CImageSurface *a_DstCubeMap, int32 a_SampleCount, float a_Roughness, - int32 a_FaceIdxStart, int32 a_FaceIdxEnd, int32 a_ThreadIdx) - { - const uint32 numChannels = VM_MIN(m_NumChannels, 4); - const int32 dstSize = a_DstCubeMap[0].m_Width; - - //thread progress - m_ThreadProgress[a_ThreadIdx].m_StartFace = a_FaceIdxStart; - m_ThreadProgress[a_ThreadIdx].m_EndFace = a_FaceIdxEnd; - - //process required faces - for(int32 iCubeFace = a_FaceIdxStart; iCubeFace <= a_FaceIdxEnd && !m_shutdownWorkerThreadSignal; iCubeFace++) - { - //iterate over dst cube map face texel - for(int32 v = 0; v < dstSize && !m_shutdownWorkerThreadSignal; v++) - { - CP_ITYPE *texelPtr = a_DstCubeMap[iCubeFace].m_ImgData + v * a_DstCubeMap[iCubeFace].m_NumChannels * dstSize; - - m_ThreadProgress[a_ThreadIdx].m_CurrentFace = iCubeFace; - m_ThreadProgress[a_ThreadIdx].m_CurrentRow = v; - - for (int32 u = 0; u < dstSize && !m_shutdownWorkerThreadSignal; u++) - { - float color[4] = { 0 }; - float totalWeight = 0; - float vH[3]; - float vL[3]; - - // Assume normal and view vector to be vCenterTapDir - float vCenterTapDir[3]; - TexelCoordToVect(iCubeFace, (float)u, (float)v, dstSize, vCenterTapDir); - - for (uint32 i = 0; i < (uint32)a_SampleCount && !m_shutdownWorkerThreadSignal; i++) - { - float vXi[2]; - HammersleySequence(i, a_SampleCount, vXi); - ImportanceSampleGGX(vXi, a_Roughness, vCenterTapDir, vH); - - float fVdotH = VM_DOTPROD3(vCenterTapDir, vH); - vL[0] = 2 * fVdotH * vH[0] - vCenterTapDir[0]; - vL[1] = 2 * fVdotH * vH[1] - vCenterTapDir[1]; - vL[2] = 2 * fVdotH * vH[2] - vCenterTapDir[2]; - - float fNdotL = VM_DOTPROD3(vCenterTapDir, vL); - if (fNdotL > 0) - { - CP_ITYPE *sourceTexel = GetCubeMapTexelPtr(vL, a_SrcCubeMap); - for (uint32 k = 0; k < numChannels; k++) - { - color[k] += sourceTexel[k] * fNdotL; - } - - totalWeight += fNdotL; - } - } - - for (uint32 k = 0; k < numChannels; k++) - { - texelPtr[k] = color[k] / totalWeight; - } - - texelPtr += a_DstCubeMap[iCubeFace].m_NumChannels; - } - } - } - } - - - void CCubeMapProcessor::FilterCubeMapMipChain(float a_BaseFilterAngle, float a_InitialMipAngle, float a_MipAnglePerLevelScale, - int32 a_FilterType, int32 a_FixupType, int32 a_FixupWidth, bool a_bUseSolidAngle, float a_GlossScale, float a_GlossBias, - int32 a_SampleCountGGX) - { - int32 i; - float coneAngle; - - if(a_FilterType == CP_FILTER_TYPE_COSINE_POWER || a_FilterType == CP_FILTER_TYPE_GGX) - { - // Don't filter top mipmap - a_BaseFilterAngle = 0; - } - - //Build filter lookup tables based on the source miplevel size - PrecomputeFilterLookupTables(a_FilterType, m_InputSurface[0].m_Width, a_BaseFilterAngle); - - //initialize thread progress - m_ThreadProgress[0].m_CurrentMipLevel = 0; - m_ThreadProgress[0].m_CurrentRow = 0; - m_ThreadProgress[0].m_CurrentFace = 0; - - //Filter the top mip level (initial filtering used for diffuse or blurred specular lighting ) - FilterCubeSurfaces(m_InputSurface, m_OutputSurface[0], a_BaseFilterAngle, a_FilterType, a_bUseSolidAngle, - 0, //start at face 0 - 5, //end at face 5 - 0); //thread 0 is processing - - m_ThreadProgress[0].m_CurrentMipLevel = 1; - m_ThreadProgress[0].m_CurrentRow = 0; - m_ThreadProgress[0].m_CurrentFace = 0; - - - FixupCubeEdges(m_OutputSurface[0], a_FixupType, a_FixupWidth); - - //Cone angle start (for generating subsequent mip levels) - coneAngle = a_InitialMipAngle; - - //generate subsequent mip levels - for(i=0; i<(m_NumMipLevels-1) && !m_shutdownWorkerThreadSignal; i++) - { - m_ThreadProgress[0].m_CurrentMipLevel = i+1; - m_ThreadProgress[0].m_CurrentRow = 0; - m_ThreadProgress[0].m_CurrentFace = 0; - - CImageSurface* srcCubeImage = m_OutputSurface[i]; - - if (a_FilterType == CP_FILTER_TYPE_GGX) - { - uint32 numUsableMips = m_NumMipLevels - 2; // Lowest used mip is 4x4 - float smoothness = VM_MAX(1.0f - (float)(i + 1) / (float)(numUsableMips - 1), 0.0f); - - // Convert smoothness to roughness (needs to match shader code) - float roughness = (1.0f - smoothness) * (1.0f - smoothness); - - FilterCubeSurfacesGGX(srcCubeImage, m_OutputSurface[i+1], a_SampleCountGGX, roughness, - 0, //start at face 0 - 5, //end at face 5 - 0 //thread 0 is processing - ); - } - else - { - float specPow = 1.0f; - - if(a_FilterType == CP_FILTER_TYPE_COSINE_POWER) - { - uint32 numMipsForGloss = m_NumMipLevels - 2; // Lowest used mip is 4x4 - float gloss = VM_MAX(1.0f - (float)(i + 1) / (float)(numMipsForGloss - 1), 0.0f); - - // Compute specular power (this must match shader code) - specPow = pow(2.0f, a_GlossScale * gloss + a_GlossBias); - - // Blinn to Phong approximation: (R.E)^p == (N.H)^(4*p) - specPow /= 4.0f; - - coneAngle = ComputeBaseFilterAngle(specPow); - srcCubeImage = m_InputSurface; - } - - //Build filter lookup tables based on the source miplevel size - PrecomputeFilterLookupTables(a_FilterType, srcCubeImage->m_Width, coneAngle); - - //filter cube surfaces - FilterCubeSurfaces(srcCubeImage, m_OutputSurface[i+1], coneAngle, a_FilterType, a_bUseSolidAngle, - 0, //start at face 0 - 5, //end at face 5 - 0, //thread 0 is processing - specPow); - } - - m_ThreadProgress[0].m_CurrentMipLevel = i+2; - m_ThreadProgress[0].m_CurrentRow = 0; - m_ThreadProgress[0].m_CurrentFace = 0; - - FixupCubeEdges(m_OutputSurface[i+1], a_FixupType, a_FixupWidth); - - coneAngle = coneAngle * a_MipAnglePerLevelScale; - } - - m_Status = CP_STATUS_FILTER_COMPLETED; - } - - - //-------------------------------------------------------------------------------------- - //Builds the following lookup tables prior to filtering: - // -normalizer cube map - // -tap weight lookup table - // - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::PrecomputeFilterLookupTables(uint32 a_FilterType, int32 a_SrcCubeMapWidth, float a_FilterConeAngle) - { - float srcTexelAngle; - int32 iCubeFace; - - //angle about center tap that defines filter cone - float filterAngle; - - //min angle a src texel can cover (in degrees) - srcTexelAngle = (180.0f / (float)CP_PI) * atan2f(1.0f, (float)a_SrcCubeMapWidth); - - //filter angle is 1/2 the cone angle - filterAngle = a_FilterConeAngle / 2.0f; - - //ensure filter angle is larger than a texel - if(filterAngle < srcTexelAngle) - { - filterAngle = srcTexelAngle; - } - - //ensure filter cone is always smaller than the hemisphere - if(filterAngle > 90.0f) - { - filterAngle = 90.0f; - } - - //build lookup table for tap weights based on angle between current tap and center tap - BuildAngleWeightLUT(a_SrcCubeMapWidth * 2, a_FilterType, filterAngle); - - //clear pre-existing normalizer cube map - for(iCubeFace=0; iCubeFace<6; iCubeFace++) - { - m_NormCubeMap[iCubeFace].Clear(); - } - - //Normalized vectors per cubeface and per-texel solid angle - BuildNormalizerSolidAngleCubemap(a_SrcCubeMapWidth, m_NormCubeMap); - - } - - //-------------------------------------------------------------------------------------- - //The key to the speed of these filtering routines is to quickly define a per-face - // bounding box of pixels which enclose all the taps in the filter kernel efficiently. - // Later these pixels are selectively processed based on their dot products to see if - // they reside within the filtering cone. - // - //This is done by computing the smallest per-texel angle to get a conservative estimate - // of the number of texels needed to be covered in width and height order to filter the - // region. the bounding box for the center taps face is defined first, and if the - // filtereing region bleeds onto the other faces, bounding boxes for the other faces are - // defined next - //-------------------------------------------------------------------------------------- - void CCubeMapProcessor::FilterCubeSurfaces(CImageSurface *a_SrcCubeMap, CImageSurface *a_DstCubeMap, - float a_FilterConeAngle, int32 a_FilterType, bool a_bUseSolidAngle, int32 a_FaceIdxStart, - int32 a_FaceIdxEnd, int32 a_ThreadIdx, float a_SpecularPower) - { - const int32 srcSize = a_SrcCubeMap[0].m_Width; - const int32 dstSize = a_DstCubeMap[0].m_Width; - - //min angle a src texel can cover (in degrees) - const float srcTexelAngle = (180.0f / (float)CP_PI) * atan2f(1.0f, (float)srcSize); - - //angle about center tap to define filter cone - float filterAngle; - - //filter angle is 1/2 the cone angle - filterAngle = a_FilterConeAngle / 2.0f; - - //ensure filter angle is larger than a texel - if(filterAngle < srcTexelAngle) - { - filterAngle = srcTexelAngle; - } - - //ensure filter cone is always smaller than the hemisphere - if(filterAngle > 90.0f) - { - filterAngle = 90.0f; - } - - //the maximum number of texels in 1D the filter cone angle will cover - // used to determine bounding box size for filter extents - //ensure conservative region always covers at least one texel - const int32 filterSize = AZ::GetMax((int32)ceil(filterAngle / srcTexelAngle), 1); - - //dotProdThresh threshold based on cone angle to determine whether or not taps - // reside within the cone angle - const float dotProdThresh = cosf( ((float)CP_PI / 180.0f) * filterAngle ); - - //thread progress - m_ThreadProgress[a_ThreadIdx].m_StartFace = a_FaceIdxStart; - m_ThreadProgress[a_ThreadIdx].m_EndFace = a_FaceIdxEnd; - - //process required faces - for(int32 iCubeFace = a_FaceIdxStart; iCubeFace <= a_FaceIdxEnd && !m_shutdownWorkerThreadSignal; iCubeFace++) - { - //iterate over dst cube map face texel - for(int32 v = 0; v < dstSize && !m_shutdownWorkerThreadSignal; v++) - { - CP_ITYPE *texelPtr = a_DstCubeMap[iCubeFace].m_ImgData + v * a_DstCubeMap[iCubeFace].m_NumChannels * dstSize; - - m_ThreadProgress[a_ThreadIdx].m_CurrentFace = iCubeFace; - m_ThreadProgress[a_ThreadIdx].m_CurrentRow = v; - - for(int32 u=0; u 0.0f) - { - totalMipComputation = pow(m_InputSize * m_BaseFilterAngle , 2.0f) * (m_OutputSize * m_OutputSize); - } - else - { - totalMipComputation = pow(m_InputSize * 0.01f , 2.0f) * (m_OutputSize * m_OutputSize); - } - - progressMipComputation = 0.0f; - if(a_FilterProgress->m_CurrentMipLevel > 0) - { - progressMipComputation = totalMipComputation; - } - - //filtering angle for this miplevel - filterAngle = m_InitialMipAngle; - dstSize = m_OutputSize; - - //computation for entire base mip level (if current level is base level) - if(a_FilterProgress->m_CurrentMipLevel == 0) - { - currentMipComputation = totalMipComputation; - currentMipSize = dstSize; - } - - //compuatation to generate subsequent mip levels - for(i=1; i 180) - { - filterAngle = 180; - } - - //note src size is dstSize*2 since miplevels are generated from the subsequent level - computation = pow(dstSize * 2 * filterAngle, 2.0f) * (dstSize * dstSize); - - totalMipComputation += computation; - - //accumulate computation for completed mip levels - if(a_FilterProgress->m_CurrentMipLevel > i) - { - progressMipComputation = totalMipComputation; - } - - //computation for entire current mip level - if(a_FilterProgress->m_CurrentMipLevel == i) - { - currentMipComputation = computation; - currentMipSize = dstSize; - } - } - - //fraction of compuation time processing the entire current mip level will take - currentMipComputation /= totalMipComputation; - progressMipComputation /= totalMipComputation; - - progressFaceComputation = currentMipComputation * - (float)(a_FilterProgress->m_CurrentFace - a_FilterProgress->m_StartFace) / - (float)(1 + a_FilterProgress->m_EndFace - a_FilterProgress->m_StartFace); - - currentFaceComputation = currentMipComputation * - 1.0f / - (1 + a_FilterProgress->m_EndFace - a_FilterProgress->m_StartFace); - - progressRowComputation = currentFaceComputation * - ((float)a_FilterProgress->m_CurrentRow / (float)currentMipSize); - - //progress completed - a_FilterProgress->m_FractionCompleted = - progressMipComputation + - progressFaceComputation + - progressRowComputation; - - - if( a_FilterProgress->m_CurrentFace < 0) - { - a_FilterProgress->m_CurrentFace = 0; - } - - if( a_FilterProgress->m_CurrentMipLevel < 0) - { - a_FilterProgress->m_CurrentMipLevel = 0; - } - - if( a_FilterProgress->m_CurrentRow < 0) - { - a_FilterProgress->m_CurrentRow = 0; - } - - } - - - //-------------------------------------------------------------------------------------- - // Return string describing the current status of the cubemap processing threads - // - //-------------------------------------------------------------------------------------- - WCHAR *CCubeMapProcessor::GetFilterProgressString(void) - { - WCHAR threadProgressString[CP_MAX_FILTER_THREADS][CP_MAX_PROGRESS_STRING]; - int32 i; - - for(i=0; i -#include -#include -#include - -#include "VectorMacros.h" -#include "CBBoxInt32.h" -#include "CImageSurface.h" - -//has routines for saving .rgbe files -#define CG_RGBE_SUPPORT - - -#ifndef WCHAR -#define WCHAR wchar_t -#endif //WCHAR - - -//used to index cube faces -#define CP_FACE_X_POS 0 -#define CP_FACE_X_NEG 1 -#define CP_FACE_Y_POS 2 -#define CP_FACE_Y_NEG 3 -#define CP_FACE_Z_POS 4 -#define CP_FACE_Z_NEG 5 - - -//used to index image edges -// NOTE.. the actual number corresponding to the edge is important -// do not change these, or the code will break -// -// CP_EDGE_LEFT is u = 0 -// CP_EDGE_RIGHT is u = width-1 -// CP_EDGE_TOP is v = 0 -// CP_EDGE_BOTTOM is v = height-1 -#define CP_EDGE_LEFT 0 -#define CP_EDGE_RIGHT 1 -#define CP_EDGE_TOP 2 -#define CP_EDGE_BOTTOM 3 - -//corners of CUBE map (P or N specifys if it corresponds to the -// positive or negative direction each of X, Y, and Z -#define CP_CORNER_NNN 0 -#define CP_CORNER_NNP 1 -#define CP_CORNER_NPN 2 -#define CP_CORNER_NPP 3 -#define CP_CORNER_PNN 4 -#define CP_CORNER_PNP 5 -#define CP_CORNER_PPN 6 -#define CP_CORNER_PPP 7 - -//data types processed by cube map processor -// note that UNORM data types use the full range -// of the unsigned integer to represent the range [0, 1] inclusive -// the float16 datatype is stored as D3Ds S10E5 representation -#define CP_VAL_UNORM8 0 -#define CP_VAL_UNORM8_BGRA 1 -#define CP_VAL_UNORM16 10 -#define CP_VAL_FLOAT16 20 -#define CP_VAL_FLOAT32 30 - - -//return codes for thread execution -// warning STILL_ACTIVE maps to 259, so the number 259 is reserved in this case -// and should only be used for STILL_ACTIVE -#define CP_THREAD_COMPLETED 0 -#define CP_THREAD_TERMINATED 15 -#define CP_THREAD_STILL_ACTIVE STILL_ACTIVE - -#define CP_MAX_PROGRESS_STRING 1024 - -// Type of data used internally by cube map processor -// just in case for any reason more preecision is needed, -// this type can be changed down the road -#define CP_ITYPE float - -// Filter type -#define CP_FILTER_TYPE_DISC 0 -#define CP_FILTER_TYPE_CONE 1 -#define CP_FILTER_TYPE_COSINE 2 -#define CP_FILTER_TYPE_ANGULAR_GAUSSIAN 3 -#define CP_FILTER_TYPE_COSINE_POWER 4 -#define CP_FILTER_TYPE_GGX 5 - - -// Edge fixup type (how to perform smoothing near edge region) -#define CP_FIXUP_NONE 0 -#define CP_FIXUP_PULL_LINEAR 1 -#define CP_FIXUP_PULL_HERMITE 2 -#define CP_FIXUP_AVERAGE_LINEAR 3 -#define CP_FIXUP_AVERAGE_HERMITE 4 - - -// Max potential cubemap size is limited to 65k (2^16 texels) on a side -#define CP_MAX_MIPLEVELS 16 - -//maximum number of threads running for cubemap processor is 2 -#define CP_MAX_FILTER_THREADS 2 - -//initial number of filtering threads for cubemap processor -#define CP_INITIAL_NUM_FILTER_THREADS 1 - - -//current status of cubemap processor -#define CP_STATUS_READY 0 -#define CP_STATUS_PROCESSING 1 -#define CP_STATUS_FILTER_TERMINATED 2 -#define CP_STATUS_FILTER_COMPLETED 3 - - -#define CP_SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#define CP_SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } - -namespace ImageProcessing -{ - - - //information about cube maps neighboring face after traversing - // across an edge - struct CPCubeMapNeighbor - { - uint8 m_Face; //index of neighboring face - uint8 m_Edge; //edge in neighboring face that abuts this face - }; - - - //-------------------------------------------------------------------------------------------------- - //structure used to store current progress of the filtering - //-------------------------------------------------------------------------------------------------- - struct SFilterProgress - { - //status of current cube map processing - int32 m_CurrentFace; - int32 m_CurrentRow; - int32 m_CurrentMipLevel; - - int32 m_StartFace; - int32 m_EndFace; - - float m_FractionCompleted; //Approximate fraction of work completed for this thread - }; - - - //-------------------------------------------------------------------------------------------------- - //structure used to pass filtering parameters for Thread 0 - //-------------------------------------------------------------------------------------------------- - struct SThreadOptionsThread0 - { - class CCubeMapProcessor *m_cmProc; - float m_BaseFilterAngle; - float m_InitialMipAngle; - float m_MipAnglePerLevelScale; - float m_GlossScale; - float m_GlossBias; - int32 m_FilterType; - int32 m_FixupType; - int32 m_FixupWidth; - int32 m_SampleCountGGX; - bool m_bUseSolidAngle; - }; - - - //-------------------------------------------------------------------------------------------------- - //structure used to pass filtering parameters to the process for Thread 1 (if used) - //-------------------------------------------------------------------------------------------------- - struct SThreadOptionsThread1 - { - class CCubeMapProcessor *m_cmProc; - CImageSurface *m_SrcCubeMap; - CImageSurface *m_DstCubeMap; - float m_FilterConeAngle; - int32 m_FilterType; - bool m_bUseSolidAngle; - int32 m_FaceIdxStart; - int32 m_FaceIdxEnd; - int32 m_ThreadIdx; - }; - - - //-------------------------------------------------------------------------------------------------- - //Class to filter, perform edge fixup, and build a mip chain for a cubemap - //-------------------------------------------------------------------------------------------------- - class CCubeMapProcessor - { - public: - - //cubemap processor status - int32 m_Status; - - //information about threads actively processing the cubemap - int32 m_NumFilterThreads; - bool m_bThreadInitialized[CP_MAX_FILTER_THREADS]; - - AZStd::thread m_ThreadHandle[CP_MAX_FILTER_THREADS]; - - AZ::u32 m_ThreadID[CP_MAX_FILTER_THREADS]; - SFilterProgress m_ThreadProgress[CP_MAX_FILTER_THREADS]; - WCHAR m_ProgressString[CP_MAX_PROGRESS_STRING]; - - //filtering parameters last used for filtering - float m_BaseFilterAngle; - float m_InitialMipAngle; - float m_MipAnglePerLevelScale; - - int32 m_InputSize; //input cubemap size (e.g. face width and height of topmost mip level) - int32 m_OutputSize; //output cubemap size (e.g. face width and height of topmost mip level) - int32 m_NumMipLevels; //number of output mip levels - int32 m_NumChannels; //number of channels in cube map processor - - CP_ITYPE *m_FilterLUT; //filter weight lookup table (scale dot product 0-1 range to index into it) - int32 m_NumFilterLUTEntries; //number of filter lookup table entries - - CImageSurface m_NormCubeMap[6]; //normalizer cube map and solid angle lookup table - - CImageSurface m_InputSurface[6]; //input faces for topmost mip level - - CImageSurface m_OutputSurface[CP_MAX_MIPLEVELS][6]; //output faces for all mip levels - - private: - //========================================================================================================== - //BuildNormalizerCubemap(int32 a_Size, CImageSurface *a_Surface ); - // Builds a normalizer cubemap of size a_Size. This routine deallocates the CImageSurfaces passed - // into the the function and reallocates them with the correct size and 3 channels to store the - // normalized vector for each texel. - // - // a_Size [in] size of normalizer cubemap - // a_Surface [out] Pointer to array of 6 CImageSurfaces where normalizer cube faces will be stored - // - //========================================================================================================== - void BuildNormalizerCubemap(int32 a_Size, CImageSurface *a_Surface); - - //========================================================================================================== - //void BuildNormalizerSolidAngleCubemap(int32 a_Size, CImageSurface *a_Surface ); - // Builds a normalizer|solid angle cubemap of size a_Size. This routine deallocates the CImageSurfaces - // passed into the the function and reallocates them with the correct size and 4 channels to store the - // normalized vector, and solid angle for each texel. - // - // a_Size [in] - // a_Surface [out] Pointer to array of 6 CImageSurfaces where normalizer cube faces will be stored - // - //========================================================================================================== - void BuildNormalizerSolidAngleCubemap(int32 a_Size, CImageSurface *a_Surface); - - //========================================================================================================== - //Clears filter extent bounding boxes for each face of the cubemap - // - // a_FilterExtents [in] Array of 6 bounding boxes (corresponding to the 6 cubemap faces) to clear - //========================================================================================================== - void ClearFilterExtents(CBBoxInt32 *a_FilterExtents); - - //========================================================================================================== - //void DetermineFilterExtents(float *a_CenterTapDir, int32 a_SrcSize, int32 a_BBoxSize, - // CBBoxInt32 *a_FilterExtents); - // - //Determines bounding boxes for each cube face for a single kernels angular extent - // a_CenterTapDir [in] Vector of 3 float32s specifying the center tap direction - // a_SrcSize [in] Source cubemap size (for the miplevel used as input to the filtering) - // a_BBoxSize [in] Maximum length in texels of the bbox extent derived from the filtering - // cone angle - // a_FilterExtents [out] Array of 6 bounding boxes (corresponding to the 6 cubemap faces) to clear - //========================================================================================================== - void DetermineFilterExtents(float *a_CenterTapDir, int32 a_SrcSize, int32 a_BBoxSize, CBBoxInt32 *a_FilterExtents); - - //========================================================================================================== - //void ProcessFilterExtents(float *a_CenterTapDir, float a_DotProdThresh, CBBoxInt32 *a_FilterExtents, - // CImageSurface *a_NormCubeMap, CImageSurface *a_SrcCubeMap, CP_ITYPE *a_DstVal, uint32 a_FilterType, - // bool a_bUseSolidAngle ); - // - //Processes all the texels within the bounding boxes in order to accumulate all the weighted taps to - // compute a single fitered texel value. - // - //a_CenterTapDir [in] Center tap directions - //a_DotProdThresh [in] Threshhold on dot product between center tap and - //a_FilterExtents [in] array of 6 bounding boxes describing rough filter extents for each face - //a_NormCubeMap [in] normalizer|solid angle cubemap - //a_SrcCubeMap [in] array of 6 faces comprising the miplevel of the source cubemap the filter is - // generated from - //a_DstVal [out] resulting filtered texel color - //a_FilterType [in] filter type: Choose one of the following options: CP_FILTER_TYPE_DISC, - // CP_FILTER_TYPE_CONE, CP_FILTER_TYPE_COSINE, CP_FILTER_TYPE_ANGULAR_GAUSSIAN - //a_bUseSolidAngle [in] Set this to true in order to incorporate the solid angle subtended - // each texel in the filter kernel in the filtering. - // - //========================================================================================================== - void ProcessFilterExtents(float *a_CenterTapDir, float a_DotProdThresh, CBBoxInt32 *a_FilterExtents, - CImageSurface *a_NormCubeMap, CImageSurface *a_SrcCubeMap, CP_ITYPE *a_DstVal, uint32 a_FilterType, - bool a_bUseSolidAngle, float a_SpecularPower); - - //========================================================================================================== - //void FixupCubeEdges(CImageSurface *a_CubeMap, int32 a_FixupType, int32 a_FixupWidth); - // - //Apply edge fixup to a cubemap mip level. - // - //a_CubeMap [in/out] Array of 6 images comprising cubemap miplevel to apply edge fixup to. - //a_FixupType [in] Specifies the technique used for edge fixup. Choose one of the following, - // CP_FIXUP_NONE, CP_FIXUP_PULL_LINEAR, CP_FIXUP_PULL_HERMITE, CP_FIXUP_AVERAGE_LINEAR, - // CP_FIXUP_AVERAGE_HERMITE - //a_FixupWidth [in] Fixup width in texels - // - //========================================================================================================== - void FixupCubeEdges(CImageSurface *a_CubeMap, int32 a_FixupType, int32 a_FixupWidth); - - //========================================================================================================== - //void BuildAngleWeightLUT(int32 a_NumFilterLUTEntries, int32 a_FilterType, float a_FilterAngle); - // - // Builds filter weight lookup table in order to quickly evaluate the weight of a particular texel - // for the Cone and Angular Gaussian fiter types. This lookup table is quickly indexed using the - // same dot product between the center tap and current texel that is used to determine whether a - // texel is inside or outside the filtering kernel. - // - //a_NumFilterLUTEntries [in] Number of entries in filter weight lookup table - //a_FilterType [in] Filter type - //a_FilterAngle [in] Filtering half cone angle - //========================================================================================================== - void BuildAngleWeightLUT(int32 a_NumFilterLUTEntries, int32 a_FilterType, float a_FilterAngle); - - //========================================================================================================== - //void PrecomputeFilterLookupTables(uint32 a_FilterType, int32 a_SrcCubeMapWidth, float a_FilterConeAngle); - // - // Builds the following lookup tables prior to filtering: - // -normalizer cube map - // -filter weight lookup table - // - //a_FilterType [in] Filter type - //a_SrcCubeMapWidth [in] source cubemap size - //a_FilterConeAngle [in] Filtering half cone angle - //========================================================================================================== - void PrecomputeFilterLookupTables(uint32 a_FilterType, int32 a_SrcCubeMapWidth, float a_FilterConeAngle); - - //========================================================================================================== - //void EstimateFilterThreadProgress(SFilterProgress *a_FilterProgress); - // - // Estimates percentage complete for a filtering thread for the current tap that is being filtered - // - //a_FilterProgress [in/out] Information about the filtereing thread's current position, and range of faces - // that it will process. - //========================================================================================================== - void EstimateFilterThreadProgress(SFilterProgress *a_FilterProgress); - - public: - //========================================================================================================== - //note that these functions are only public so that they can be called from within the global scope - // from the thread starting point functions. These should not be called by any other functions external - // to the class. - //========================================================================================================== - void FilterCubeMapMipChain(float a_BaseFilterAngle, float a_InitialMipAngle, float a_MipAnglePerLevelScale, - int32 a_FilterType, int32 a_FixupType, int32 a_FixupWidth, bool a_bUseSolidAngle, float a_GlossScale, float a_GlossBias, - int32 a_SampleCountGGX); - void FilterCubeSurfaces(CImageSurface *a_SrcCubeMap, CImageSurface *a_DstCubeMap, float a_FilterConeAngle, - int32 a_FilterType, bool a_bUseSolidAngle, int32 a_FaceIdxStart, int32 a_FaceIdxEnd, int32 aThreadIdx, - float a_SpecularPower = 1.0f); - void FilterCubeSurfacesGGX(CImageSurface *a_SrcCubeMap, CImageSurface *a_DstCubeMap, int32 a_SampleCount, float a_Roughness, - int32 a_FaceIdxStart, int32 a_FaceIdxEnd, int32 aThreadIdx); - - public: - CCubeMapProcessor(void); - ~CCubeMapProcessor(); - - //========================================================================================================== - // void Init(int32 a_InputSize, int32 a_OutputSize, int32 a_NumMipLevels, int32 a_NumChannels); - // - // Initializes cube map processor class - // - // a_InputSize [in] Size of the input cubemap - // a_OutputSize [in] Size of the input cubemap - // a_NumMipLevels [in] Number of miplevels in the output cubemap - // a_NumChannels [in] Number of color channels (internally) in the input and output cubemap - //========================================================================================================== - void Init(int32 a_InputSize, int32 a_OutputSize, int32 a_NumMipLevels, int32 a_NumChannels); - - - //========================================================================================================== - // void GetInputFaceData(int32 a_FaceIdx, int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, - // void *a_DstDataPtr, float a_Scale, float a_Gamma); - // - // Copies image data from the input cube map into a destination image. These routine describe the output - // image layout using a pitch and a pointer so that the image can be copied from a subrect of a locked - // D3D surface easily. Note that when reading out the image data, the intensity scale is applied first, - // and then degamma. - // - // a_FaceIdx [in] Index (0-5) of the input cubemap cube face to read the image data from. - // a_DstType [in] Data type for the image data being copied out the input cube map. - // choose one of the following: CP_VAL_UNORM8, CP_VAL_UNORM8_BGRA, CP_VAL_UNORM16 - // CP_VAL_FLOAT16, CP_VAL_FLOAT32. - // a_DstNumChannels [in] Number of channels in the destination image. - // a_DstPitch [in] Pitch in bytes of the destination image. - // a_DstDataPtr [in] Pointer to the top-left pixel in the destination image. - // a_Scale [in] Scale factor to apply to intensities. - // a_Gamma [in] Degamma to apply to intensities. - // - //========================================================================================================== - void GetInputFaceData(int32 a_FaceIdx, int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, - void *a_DstDataPtr, float a_Scale, float a_Gamma); - - - //========================================================================================================== - // void SetInputFaceData(int32 a_FaceIdx, int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, - // void *a_SrcDataPtr, float a_MaxClamp, float a_Scale, float a_Gamma ); - // - // Copies image data from a source image into one of the faces in the input cubemap in the cubemap. - // processor. These routines describe the output image layout using a pitch and a pointer so that the image - // can be copied from a subrect of a locked D3D surface easily. Note that the clamping is applied first, - // followed by the scale and then gamma. - // - // a_FaceIdx [in] Index (0-5) of the input cubemap cube face to write the image data into - // a_SrcType [in] Data type for the image data being copied into the cube map processor. - // choose one of the following: CP_VAL_UNORM8, CP_VAL_UNORM8_BGRA, CP_VAL_UNORM16 - // CP_VAL_FLOAT16, CP_VAL_FLOAT32. - // a_SrcNumChannels [in] Number of channels in the source image. - // a_SrcPitch [in] Pitch in bytes of the source image. - // a_SrcDataPtr [in] Pointer to the top-left pixel in the source image. - // a_MaxClamp [in] Max value to clamp the input intensity values to. - // a_Degamma [in] Degamma to apply to input intensities. - // a_Scale [in] Scale factor to apply to input intensities. - // - //========================================================================================================== - void SetInputFaceData(int32 a_FaceIdx, int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, - void *a_SrcDataPtr, float a_MaxClamp, float a_Degamma, float a_Scale); - - - //========================================================================================================== - // void GetOutputFaceData(int32 a_FaceIdx, int32 a_Level, int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, - // void *a_DstDataPtr, float a_Scale, float a_Gamma ); - // - // a_FaceIdx [in] Index (0-5) of the output cubemap cube face to read the image data from. - // a_Level [in] Miplevel of the output cubemap to read from - // a_DstType [in] Data type for the image data being copied out the input cube map. - // choose one of the following: CP_VAL_UNORM8, CP_VAL_UNORM8_BGRA, CP_VAL_UNORM16 - // CP_VAL_FLOAT16, CP_VAL_FLOAT32 - // a_DstNumChannels [in] Number of channels in the destination image. - // a_DstPitch [in] Pitch in bytes of the destination image. - // a_DstDataPtr [in] Pointer to the top-left pixel in the destination image. - // a_Scale [in] Scale factor to apply to intensities. - // a_Gamma [in] Degamma to apply to intensities. - // - //========================================================================================================== - void GetOutputFaceData(int32 a_FaceIdx, int32 a_Level, int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, - void *a_DstDataPtr, float a_Scale, float a_Gamma); - - - //========================================================================================================== - //void InitiateFiltering(float a_BaseFilterAngle, float a_InitialMipAngle, float a_MipAnglePerLevelScale, - // int32 a_FilterType, int32 a_FixupType, int32 a_FixupWidth, bool a_bUseSolidAngle ); - // - // Starts filtering the cubemap. - // If the number of filter threads is zero, the function does not return until the filtering is complete - // If the number of filter threads is non-zero, a filtering thread (or multiple threads) are started and - // the function returns immediately, with the threads running in the background. - // - // The cube map filtereing is specified using a number of parameters: - // Filtering per miplevel is specified using 2D cone angle (in degrees) that - // indicates the region of the hemisphere to filter over for each tap. - // - // Note that the top mip level is also a filtered version of the original input images - // as well in order to create mip chains for diffuse environment illumination. - // The cone angle for the top level is specified by a_BaseAngle. This can be used to - // generate mipchains used to store the results of preintegration across the hemisphere. - // - // The angle for the subsequent levels of the mip chain are specified by their parents - // filtering angle and a per-level scale and bias - // newAngle = oldAngle * a_MipAnglePerLevelScale; - // - // a_BaseFilterAngle [in] Base filter angle - // a_InitialMipAngle [in] Mip angle used to generate the next level of the mip chain from the base level - // a_MipAnglePerLevelScale [in] Scale factor to iteratively apply to the filtering angle to filter subsequent - // mip-levels. - // a_FilterType [in] Specifies the filtering type for angular extent filtering. Choose one of the - // following options: CP_FILTER_TYPE_DISC, CP_FILTER_TYPE_CONE, - // CP_FILTER_TYPE_COSINE, CP_FILTER_TYPE_ANGULAR_GAUSSIAN - // a_FixupType [in] Specifies the technique used for edge fixup. Choose one of the following, - // CP_FIXUP_NONE, CP_FIXUP_PULL_LINEAR, CP_FIXUP_PULL_HERMITE, - // CP_FIXUP_AVERAGE_LINEAR, CP_FIXUP_AVERAGE_HERMITE - // a_FixupWidth [in] Width in texels of the fixup region. - // a_bUseSolidAngle [in] Set this to true in order to incorporate the solid angle subtended - // each texel in the filter kernel in the filtering. - //========================================================================================================== - void InitiateFiltering(float a_BaseFilterAngle, float a_InitialMipAngle, float a_MipAnglePerLevelScale, - int32 a_FilterType, int32 a_FixupType, int32 a_FixupWidth, bool a_bUseSolidAngle, - float a_GlossScale, float a_GlossBias, int32 a_SampleCountGGX); - - //========================================================================================================== - // void WriteMipLevelIntoAlpha(void) - // - // Encodes the miplevel in the alpha channel of the output cubemap. - // The miplevel is encoded as (miplevel * 16.0f / 255.0f) so that the miplevel has an exact encoding in an - // 8-bit or 16-bit UNORM representation. - // - //========================================================================================================== - void WriteMipLevelIntoAlpha(void); - - - //========================================================================================================== - // Horizontally flips all the faces in the input cubemap - // - //========================================================================================================== - void FlipInputCubemapFaces(void); - - //========================================================================================================== - // Horizontally flips all the faces in the output cubemap - // - //========================================================================================================== - void FlipOutputCubemapFaces(void); - - - //========================================================================================================== - // Allows for in-place color channel swapping of the input cubemap. This routine can be useful for - // converting RGBA format data to BGRA format data. - // - // a_Channel0Src [in] Index of the color channel used as the source for the new channel 0 - // a_Channel1Src [in] Index of the color channel used as the source for the new channel 1 - // a_Channel2Src [in] Index of the color channel used as the source for the new channel 0 - // a_Channel3Src [in] Index of the color channel used as the source for the new channel 1 - // - //========================================================================================================== - void ChannelSwapInputFaceData(int32 a_Channel0Src, int32 a_Channel1Src, int32 a_Channel2Src, int32 a_Channel3Src); - - - //========================================================================================================== - // Allows for in-place color channel swapping of the output cubemap. This routine can be useful for - // converting RGBA format data to BGRA format data. - // - // a_Channel0Src [in] Index of the color channel used as the source for the new channel 0 - // a_Channel1Src [in] Index of the color channel used as the source for the new channel 1 - // a_Channel2Src [in] Index of the color channel used as the source for the new channel 0 - // a_Channel3Src [in] Index of the color channel used as the source for the new channel 1 - //========================================================================================================== - void ChannelSwapOutputFaceData(int32 a_Channel0Src, int32 a_Channel1Src, int32 a_Channel2Src, int32 a_Channel3Src); - - - //========================================================================================================== - // Resets the current cubemap processor, and deallocates the input and output cubemaps. - // - // This function is automatically called by destructor. - //========================================================================================================== - void Clear(void); - - - //========================================================================================================== - // Terminates any active filtering threads. This stops the filtering of the current cubemap. - // - //========================================================================================================== - void TerminateActiveThreads(void); - - - //========================================================================================================== - // Gets the current filtering progress string - // - //========================================================================================================== - WCHAR *GetFilterProgressString(void); - - - //========================================================================================================== - // Checks to see if either of the filtering threads is active - // - //========================================================================================================== - bool IsFilterThreadActive(uint32 a_ThreadIdx); - - //========================================================================================================== - // Gets the current status of the cubemap processing threads. The possible return values and their - // associated meanings are: - // - // CP_STATUS_READY: The cubemap processor is currently ready to change settings, and to load a - // new input cubemap. - // CP_STATUS_PROCESSING: The cubemap processor is currently filtering a cubemap - // CP_STATUS_FILTER_TERMINATED: The cubemap processor was terminated before the filtering was completed. - // CP_STATUS_FILTER_COMPLETED: The cubemap processor fully completed filtering the cubemap. - // - //========================================================================================================== - int32 GetStatus(void); - - - //========================================================================================================== - // This signifies to the cubemap processor that you have acknowledged a - // CP_STATUS_FILTER_TERMINATED or CP_STATUS_FILTER_COMPLETED status code, and would like to - // reset the cubemap processor to CP_STATUS_READY. - //========================================================================================================== - void RefreshStatus(void); - - AZStd::atomic_bool m_shutdownWorkerThreadSignal; ///< Signals the worker threads to stop. - }; - -} // namespace ImageProcessing diff --git a/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.cpp b/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.cpp deleted file mode 100644 index 62daa2b4d7..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -//-------------------------------------------------------------------------------------- -//CImageSurface -// Class for storing, manipulating, and copying image data to and from D3D Surfaces -// -//-------------------------------------------------------------------------------------- -// (C) 2005 ATI Research, Inc., All rights reserved. -//-------------------------------------------------------------------------------------- -// modifications by Crytek GmbH -// modifications by Amazon - -#include - -#include "CImageSurface.h" - - -namespace ImageProcessing -{ - //-------------------------------------------------------------------------------------- - // convert D3D 16 bit float to standard 32 bit float - // Format: - // - // 1 sign bit in MSB, (s) - // 5 bits of biased exponent, (e) - // 10 bits of fraction, (f), with an additional hidden bit - // A float16 value, v, made from the format above takes the following meaning: - // - // (a) if e == 31 and f != 0, then v is NaN regardless of s - // (b) if e == 31 and f == 0, then v = (-1)^s * infinity (signed infinity) - // (c) if 0 < e < 31, then v = (-1)^s * 2^(e-15) * (1.f) - // (d) if e == 0 and f != 0, then v = (-1)^s * 2^(e-14) * (0.f) (denormalized numbers) - // (e) if e == 0 and f == 0, then v = (-1)^s *0 (signed zero) - // - //-------------------------------------------------------------------------------------- - float CPf16Tof32(uint16 aVal) - { - uint32 signVal = (aVal >> 15); //sign bit in MSB - uint32 exponent = ((aVal >> 10) & 0x01f); //next 5 bits after signbit - uint32 mantissa = (aVal & 0x03ff); //lower 10 bits - uint32 rawFloat32Data; //raw binary float data - - //convert s10e5 5-bit exponent to IEEE754 s23e8 8-bit exponent - if (exponent == 31) - { // infinity or Nan depending on mantissa - exponent = 255; - } - else if (exponent == 0) - { // denormalized floats mantissa is treated as = 0.f - exponent = 0; - } - else - { //change 15base exponent to 127base exponent - //normalized floats mantissa is treated as = 1.f - exponent += (127 - 15); - } - - //convert 10-bit mantissa to 23-bit mantissa - mantissa <<= (23 - 10); - - //assemble s23e8 number using logical operations - rawFloat32Data = (signVal << 31) | (exponent << 23) | mantissa; - - //treat raw data as a 32 bit float - return *((float *)&rawFloat32Data); - } - - - //-------------------------------------------------------------------------------------- - // convert standard 32 bit float to D3D 16 bit float - // - // 16-bit float format: - // - // 1 sign bit in MSB, (s) - // 5 bits of biased exponent, (e) - // 10 bits of fraction, (f), with an additional hidden bit - // A float16 value, v, made from the format above takes the following meaning: - // - // (a) if e == 31 and f != 0, then v is NaN regardless of s - // (b) if e == 31 and f == 0, then v = (-1)s*infinity (signed infinity) - // (c) if 0 < e < 31, then v = (-1)s*2(e-15)*(1.f) - // (d) if e == 0 and f != 0, then v = (-1)s*2(e-14)*(0.f) (denormalized numbers) - // (e) if e == 0 and f == 0, then v = (-1)s*0 (signed zero) - //-------------------------------------------------------------------------------------- - uint16 CPf32Tof16(float aVal) - { - uint32 rawf32Data = *((uint32 *)&aVal); //raw binary float data - - uint32 signVal = (rawf32Data >> 31); //sign bit in MSB - uint32 exponent = ((rawf32Data >> 23) & 0xff); //next 8 bits after signbit - uint32 mantissa = (rawf32Data & 0x7fffff); //mantissa = lower 23 bits - - uint16 rawf16Data; - - //convert IEEE754 s23e8 8-bit exponent to s10e5 5-bit exponent - if (exponent == 255) - {//special case 32 bit float is inf or NaN, use mantissa as is - exponent = 31; - } - else if (exponent < ((127 - 15) - 10)) - {//special case, if 32-bit float exponent is out of 16-bit float range, then set 16-bit float to 0 - exponent = 0; - mantissa = 0; - } - else if (exponent >= (127 + (31 - 15))) - { // max 15based exponent for s10e5 is 31 - // force s10e5 number to represent infinity by setting mantissa to 0 - // and exponent to 31 - exponent = 31; - mantissa = 0; - } - else if (exponent <= (127 - 15)) - { //convert normalized s23e8 float to denormalized s10e5 float - - //add implicit 1.0 to mantissa to convert from 1.f to use as a 0.f mantissa - mantissa |= (1 << 23); - - //shift over mantissa number of bits equal to exponent underflow - mantissa = mantissa >> (1 + ((127 - 15) - exponent)); - - //zero exponent to treat value as a denormalized number - exponent = 0; - } - else - { //change 127base exponent to 15base exponent - // no underflow or overflow of exponent - //normalized floats mantissa is treated as= 1.f, so - // no denormalization or exponent derived shifts to the mantissa - exponent -= (127 - 15); - } - - //convert 23-bit mantissa to 10-bit mantissa - mantissa >>= (23 - 10); - - //assemble s10e5 number using logical operations - rawf16Data = (signVal << 15) | (exponent << 10) | mantissa; - - //return re-assembled raw data as a 32 bit float - return rawf16Data; - } - - - //-------------------------------------------------------------------------------------- - //size of data types in bytes - //-------------------------------------------------------------------------------------- - int32 CPTypeSizeOf(int32 a_Type) - { - switch (a_Type) - { - case CP_VAL_UNORM8: - case CP_VAL_UNORM8_BGRA: - return 1; - break; - case CP_VAL_UNORM16: - return 2; - break; - case CP_VAL_FLOAT16: - return 2; - break; - case CP_VAL_FLOAT32: - return 4; - break; - default: - return 1; - break; - } - } - - - //-------------------------------------------------------------------------------------- - //get value of data pointed to by a_Ptr given type information - //-------------------------------------------------------------------------------------- - CP_ITYPE CPTypeGetVal(int32 a_Type, void *a_Ptr) - { - switch (a_Type) - { - case CP_VAL_UNORM8: - case CP_VAL_UNORM8_BGRA: - return (1.0f / 255.0f) * *((uint8 *)a_Ptr); - break; - case CP_VAL_UNORM16: - return (1.0f / 65535.0f) * *((uint16 *)a_Ptr); - break; - case CP_VAL_FLOAT16: - return CPf16Tof32(*((uint16 *)a_Ptr)); - break; - case CP_VAL_FLOAT32: - return *((float *)a_Ptr); - break; - default: - return 0; - break; - } - } - - - //-------------------------------------------------------------------------------------- - //Given a CP_ITYPE value as input, convert it to the given type specified by a_Type - // and write the value to a_Ptr - //-------------------------------------------------------------------------------------- - void CPTypeSetVal(CP_ITYPE a_Val, int32 a_Type, void *a_Ptr) - { - CP_ITYPE clampVal; //clamp value to 0-1 range to output UNORM types - - switch (a_Type) - { - case CP_VAL_UNORM8: - case CP_VAL_UNORM8_BGRA: - clampVal = VM_MIN(VM_MAX(a_Val, 0.0f), 1.0f); - *((uint8 *)a_Ptr) = (uint8)(clampVal * 255.0f); - break; - case CP_VAL_UNORM16: - clampVal = VM_MIN(VM_MAX(a_Val, 0.0f), 1.0f); - *((uint16 *)a_Ptr) = (uint16)(clampVal * 65535.0f); - break; - case CP_VAL_FLOAT16: - *((uint16 *)a_Ptr) = CPf32Tof16(a_Val); - break; - case CP_VAL_FLOAT32: - *((float *)a_Ptr) = a_Val; - break; - default: - break; - } - } - - - //-------------------------------------------------------------------------------------- - //Error handling for imagesurface class - // Pop up dialog box, and terminate application - //-------------------------------------------------------------------------------------- - void CImageSurface::FatalError([[maybe_unused]] const WCHAR *a_Msg) - { - AZ_Error("Image Processing", false, "CImageSurface Error: %s", a_Msg); - } - - - //-------------------------------------------------------------------------------------- - // Image surface - //-------------------------------------------------------------------------------------- - CImageSurface::CImageSurface(void) - { - m_Width = 0; //cubemap face width - m_Height = 0; //cubemap face height - m_NumChannels = 0; //number of channels - m_ImgData = NULL; - - } - - - //-------------------------------------------------------------------------------------- - // Clear - //-------------------------------------------------------------------------------------- - void CImageSurface::Clear(void) - { - m_Width = 0; //cubemap face width - m_Height = 0; //cubemap face height - m_NumChannels = 0; //number of channels - SAFE_DELETE_ARRAY(m_ImgData); //safe delete old image data - } - - - //-------------------------------------------------------------------------------------- - // Initialize surface and associated memory - //-------------------------------------------------------------------------------------- - void CImageSurface::Init(int32 a_Width, int32 a_Height, int32 a_NumChannels) - { - m_Width = a_Width; //cubemap face width - m_Height = a_Height; //cubemap face height - m_NumChannels = a_NumChannels; //number of channels - - SAFE_DELETE_ARRAY(m_ImgData); //safe delete old image data - - m_ImgData = new(std::nothrow) CP_ITYPE[m_Width * m_Height * m_NumChannels]; //assume tight data packing - if (!m_ImgData) - { - FatalError(L"Unable to allocate data for image in CImageSurface::Init."); - } - } - - - //-------------------------------------------------------------------------------------- - //copy and convert data from external buffer into this surface - // - // note that srcPitch == the source pitch in bytes - //-------------------------------------------------------------------------------------- - void CImageSurface::SetImageData(int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, void *a_SrcDataPtr) - { - int32 i, j, k; - - CP_ITYPE *dstDataWalk = m_ImgData; - uint8 *srcDataWalk = (uint8 *)a_SrcDataPtr; - - int32 srcValueSize = CPTypeSizeOf(a_SrcType); - int32 srcTexelStep = srcValueSize * a_SrcNumChannels; - int32 numChannelsSet = VM_MIN(a_SrcNumChannels, m_NumChannels); - int32 srcChannelSelect; - - //loop over rows - for (j = 0; j < m_Height; j++) - { - //pointer arithmetic to offset pointer by pitch in bytes - srcDataWalk = ((uint8 *)a_SrcDataPtr + (j * a_SrcPitch)); - - //loop over texels within row - for (i = 0; i < m_Width; i++) - { - srcChannelSelect = 0; - - //loop over channels within texel - for (k = 0; k < numChannelsSet; k++) - { - if (a_SrcType == CP_VAL_UNORM8_BGRA) //swap channels 0, and 2 if in BGRA format - { - switch (k) - { - case 0: - *(dstDataWalk + 2) = CPTypeGetVal(a_SrcType, srcDataWalk + srcChannelSelect); - break; - case 2: - *(dstDataWalk + 0) = CPTypeGetVal(a_SrcType, srcDataWalk + srcChannelSelect); - break; - default: - *(dstDataWalk + k) = CPTypeGetVal(a_SrcType, srcDataWalk + srcChannelSelect); - break; - } - } - else - { - *(dstDataWalk + k) = CPTypeGetVal(a_SrcType, srcDataWalk + srcChannelSelect); - } - - srcChannelSelect += srcValueSize; - } - - dstDataWalk += m_NumChannels; - srcDataWalk += srcTexelStep; - } - } - } - - - //-------------------------------------------------------------------------------------- - // Copy and convert data from external buffer into this surface set image data degamma - // and scale - // - //-------------------------------------------------------------------------------------- - void CImageSurface::SetImageDataClampDegammaScale(int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, - void *a_SrcDataPtr, float a_MaxClamp, float a_Gamma, float a_Scale) - { - int32 i, j, k; - - CP_ITYPE *dstDataWalk = m_ImgData; - uint8 *srcDataWalk = (uint8 *)a_SrcDataPtr; - - int32 srcValueSize = CPTypeSizeOf(a_SrcType); - int32 srcTexelStep = srcValueSize * a_SrcNumChannels; - int32 numChannelsSet = VM_MIN(a_SrcNumChannels, m_NumChannels); - int32 srcChannelSelect; - - //loop over rows - for (j = 0; j < m_Height; j++) - { - //pointer arithmetic to offset pointer by pitch in bytes - srcDataWalk = ((uint8 *)a_SrcDataPtr + (j * a_SrcPitch)); - - //loop over texels within row - for (i = 0; i < m_Width; i++) - { - srcChannelSelect = 0; - - //loop over channels within texel - for (k = 0; k < numChannelsSet; k++) - { - CP_ITYPE texelVal; - - //get texel value from external buffer - texelVal = CPTypeGetVal(a_SrcType, srcDataWalk + srcChannelSelect); - - //clamp texelVal using max value only - // (using texelVal as the min clamping arguement means no minimum clamping) - VM_CLAMP(texelVal, texelVal, texelVal, a_MaxClamp); - - if (k < 3) //only apply gamma and scale to RGB channels - { - //degamma texel val, by raising to the power gamma - texelVal = pow(texelVal, a_Gamma); - - //scale texel val in linear space (after degamma) - texelVal *= a_Scale; - } - - //write data - if ((a_SrcType == CP_VAL_UNORM8_BGRA) && (k == 0)) - { - *(dstDataWalk + 2) = texelVal; - } - else if ((a_SrcType == CP_VAL_UNORM8_BGRA) && (k == 2)) - { - *(dstDataWalk + 0) = texelVal; - } - else - { - *(dstDataWalk + k) = texelVal; - } - - srcChannelSelect += srcValueSize; - } - - dstDataWalk += m_NumChannels; - srcDataWalk += srcTexelStep; - } - } - } - - - //-------------------------------------------------------------------------------------- - //copy data from this image surface into an external buffer - // - //-------------------------------------------------------------------------------------- - void CImageSurface::GetImageData(int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, void *a_DstDataPtr) - { - int32 i, j, k; - - CP_ITYPE *srcDataWalk = m_ImgData; - uint8 *dstDataWalk = (uint8 *)a_DstDataPtr; - - int32 dstValueSize = CPTypeSizeOf(a_DstType); - int32 dstTexelStep = dstValueSize * a_DstNumChannels; - - int32 numChannelsSet = VM_MIN(a_DstNumChannels, m_NumChannels); - int32 dstChannelSelect; - - //loop over rows - for (j = 0; j < m_Height; j++) - { - //pointer arithmetic to offset pointer by pitch in bytes - dstDataWalk = ((uint8 *)a_DstDataPtr + (j * a_DstPitch)); - - //loop over texels within row - for (i = 0; i < m_Width; i++) - { - dstChannelSelect = 0; - - //loop over channels within texel - for (k = 0; k < numChannelsSet; k++) - { - //write data - if ((a_DstType == CP_VAL_UNORM8_BGRA) && (k == 0)) - { - CPTypeSetVal(*(srcDataWalk + 2), a_DstType, dstDataWalk + dstChannelSelect); - } - else if ((a_DstType == CP_VAL_UNORM8_BGRA) && (k == 2)) - { - CPTypeSetVal(*(srcDataWalk + 0), a_DstType, dstDataWalk + dstChannelSelect); - } - else - { - CPTypeSetVal(*(srcDataWalk + k), a_DstType, dstDataWalk + dstChannelSelect); - } - - dstChannelSelect += dstValueSize; - } - - srcDataWalk += m_NumChannels; - dstDataWalk += dstTexelStep; - } - } - } - - - //-------------------------------------------------------------------------------------- - // Scale and then apply gamma to image data, then copy image data into an external buffer - // note: only apply scale and gamma to RGB channels (e.g. first 3 channels) - // - //-------------------------------------------------------------------------------------- - void CImageSurface::GetImageDataScaleGamma(int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, - void *a_DstDataPtr, float a_Scale, float a_Gamma) - { - int32 i, j, k; - - CP_ITYPE *srcDataWalk = m_ImgData; - uint8 *dstDataWalk = (uint8 *)a_DstDataPtr; - - int32 dstValueSize = CPTypeSizeOf(a_DstType); - int32 dstTexelStep = dstValueSize * a_DstNumChannels; - - int32 numChannelsSet = VM_MIN(a_DstNumChannels, m_NumChannels); - int32 dstChannelSelect; - - //loop over rows - for (j = 0; j < m_Height; j++) - { - //pointer arithmetic to offset pointer by pitch in bytes - dstDataWalk = ((uint8 *)a_DstDataPtr + (j * a_DstPitch)); - - //loop over texels within row - for (i = 0; i < m_Width; i++) - { - dstChannelSelect = 0; - - //loop over channels within texel - for (k = 0; k < numChannelsSet; k++) - { - CP_ITYPE texelVal; - - texelVal = *(srcDataWalk + k); - - if (k < 3) //only apply gamma and scale to RGB channels - { - //scale texel val - texelVal *= a_Scale; - - //apply gamma to texel val by raising the texelVal to the power of (1/gamma) - texelVal = pow(texelVal, 1.0f / a_Gamma); - } - - //write out texture value - if ((a_DstType == CP_VAL_UNORM8_BGRA) && (k == 0)) - { - CPTypeSetVal(texelVal, a_DstType, dstDataWalk + (dstValueSize * 2)); - } - else if ((a_DstType == CP_VAL_UNORM8_BGRA) && (k == 2)) - { - CPTypeSetVal(texelVal, a_DstType, dstDataWalk + (dstValueSize * 0)); - } - else - { - CPTypeSetVal(texelVal, a_DstType, dstDataWalk + dstChannelSelect); - } - - - dstChannelSelect += dstValueSize; - } - - srcDataWalk += m_NumChannels; - dstDataWalk += dstTexelStep; - } - } - } - - - //-------------------------------------------------------------------------------------- - //Set image channel a_ChannelIdx to a_ClearColor for all pixels. - // - //-------------------------------------------------------------------------------------- - void CImageSurface::ClearChannelConst(int32 a_ChannelIdx, CP_ITYPE a_ClearColor) - { - int32 u, v; - CP_ITYPE *texelPtr; - - //if channel does not exist, do not attempt to clear the channel - if (a_ChannelIdx > (m_NumChannels - 1)) - { - return; - } - - for (v = 0; v < m_Height; v++) - { - for (u = 0; u < m_Width; u++) - { - texelPtr = GetSurfaceTexelPtr(u, v); - - *(texelPtr + a_ChannelIdx) = a_ClearColor; - } - } - } - - - //-------------------------------------------------------------------------------------- - //Gets texel ptr in a surface given u and v coordinates, - // - //-------------------------------------------------------------------------------------- - CP_ITYPE *CImageSurface::GetSurfaceTexelPtr(int32 u, int32 v) - { - return(m_ImgData + (((m_Width * v) + u) * m_NumChannels)); - } - - - //-------------------------------------------------------------------------------------- - //flips surface image in place horizontally - // - //-------------------------------------------------------------------------------------- - void CImageSurface::InPlaceHorizonalFlip(void) - { - int32 u, v, k; - CP_ITYPE *texelPtrTop, *texelPtrBottom; - - //iterate over V - for (v = 0; v < (m_Height / 2); v++) - { - for (u = 0; u < m_Height; u++) - { - texelPtrTop = GetSurfaceTexelPtr(u, v); - texelPtrBottom = GetSurfaceTexelPtr(u, (m_Height - 1) - v); - - //iterate over channels - for (k = 0; k < m_NumChannels; k++) - { - CP_ITYPE tmpTexelVal; - - tmpTexelVal = *(texelPtrTop + k); - *(texelPtrTop + k) = *(texelPtrBottom + k); - *(texelPtrBottom + k) = tmpTexelVal; - - } - } - } - } - - - //-------------------------------------------------------------------------------------- - //flips surface image in place vertically - // - //-------------------------------------------------------------------------------------- - void CImageSurface::InPlaceVerticalFlip(void) - { - int32 u, v, k; - CP_ITYPE *texelPtrLeft, *texelPtrRight; - - for (u = 0; u < (m_Width / 2); u++) - { - for (v = 0; v < m_Height; v++) - { - texelPtrLeft = GetSurfaceTexelPtr(u, v); - texelPtrRight = GetSurfaceTexelPtr((m_Width - 1) - u, v); - - //iterate over channels - for (k = 0; k < m_NumChannels; k++) - { - CP_ITYPE tmpTexelVal; - - tmpTexelVal = *(texelPtrLeft + k); - *(texelPtrLeft + k) = *(texelPtrRight + k); - *(texelPtrRight + k) = tmpTexelVal; - } - } - } - } - - - //-------------------------------------------------------------------------------------- - //flip image around line defined by u = v (effectively swaps the u and v axises) - //-------------------------------------------------------------------------------------- - void CImageSurface::InPlaceDiagonalUVFlip(void) - { - int32 u, v, k; - CP_ITYPE *texelPtrLeft, *texelPtrRight; - - if (m_Width != m_Height) - { //only flip image if square - return; - } - - for (v = 0; v < m_Height; v++) - { - for (u = 0; u < v; u++) //only iterate over lower left triangle - { - texelPtrLeft = GetSurfaceTexelPtr(u, v); - texelPtrRight = GetSurfaceTexelPtr(v, u); - - //iterate over channels - for (k = 0; k < m_NumChannels; k++) - { - CP_ITYPE tmpTexelVal; - - tmpTexelVal = *(texelPtrLeft + k); - *(texelPtrLeft + k) = *(texelPtrRight + k); - *(texelPtrRight + k) = tmpTexelVal; - } - } - } - } - - //-------------------------------------------------------------------------------------- - // destructor, free all memory used - //-------------------------------------------------------------------------------------- - CImageSurface::~CImageSurface() - { - SAFE_DELETE_ARRAY(m_ImgData); - } -} // namespace ImageProcessing - - - diff --git a/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.h b/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.h deleted file mode 100644 index abd8cc5b50..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/CImageSurface.h +++ /dev/null @@ -1,94 +0,0 @@ -//-------------------------------------------------------------------------------------- -//CImageSurface -// Class for storing, manipulating, and copying image data to and from D3D Surfaces -// -//-------------------------------------------------------------------------------------- -// (C) 2005 ATI Research, Inc., All rights reserved. -//-------------------------------------------------------------------------------------- -// modifications by Crytek GmbH -// modifications by Amazon - -#pragma once - -#include -#include - -#include "VectorMacros.h" - - -#ifndef WCHAR -#define WCHAR wchar_t -#endif //WCHAR - -#ifndef SAFE_DELETE -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#endif - -#ifndef SAFE_DELETE_ARRAY -#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } -#endif - - -//Data types processed by cube map processor -// note that UNORM data types use the full range -// of the unsigned integer to represent the range [0, 1] inclusive -// the float16 datatype is stored as D3Ds S10E5 representation -#define CP_VAL_UNORM8 0 -#define CP_VAL_UNORM8_BGRA 1 -#define CP_VAL_UNORM16 10 -#define CP_VAL_FLOAT16 20 -#define CP_VAL_FLOAT32 30 - - -// Type of data used internally by CSurfaceImage -#define CP_ITYPE float - -namespace ImageProcessing -{ - //2D images used to store cube faces for processing, note that this class is - // meant to facilitate the copying of data to and from D3D surfaces hence the name ImageSurface - class CImageSurface - { - public: - int32 m_Width; //image width - int32 m_Height; //image height - int32 m_NumChannels; //number of channels - CP_ITYPE *m_ImgData; //cubemap image data - - private: - //fatal error - void FatalError(const WCHAR *a_Msg); - - public: - CImageSurface(void); - void Clear(void); - void Init(int32 a_Width, int32 a_Height, int32 a_NumChannels); - - //copy data from external buffer into this CImageSurface - void SetImageData(int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, void *a_SrcDataPtr); - - // copy image data from an external buffer and scale and degamma the data - void SetImageDataClampDegammaScale(int32 a_SrcType, int32 a_SrcNumChannels, int32 a_SrcPitch, void *a_SrcDataPtr, - float a_MaxClamp, float a_Degamma, float a_Scale); - - //copy data from this CImageSurface into an external buffer - void GetImageData(int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, void *a_DstDataPtr); - - //copy image data from an external buffer and scale and gamma the data - void GetImageDataScaleGamma(int32 a_DstType, int32 a_DstNumChannels, int32 a_DstPitch, void *a_DstDataPtr, - float a_Scale, float a_Gamma); - - //clear one of the channels in the CSurfaceImage to a particular color - void ClearChannelConst(int32 a_ChannelIdx, CP_ITYPE a_ClearColor); - - //various image operations that can be performed on the CImageSurface - void InPlaceVerticalFlip(void); - void InPlaceHorizonalFlip(void); - void InPlaceDiagonalUVFlip(void); - - CP_ITYPE *GetSurfaceTexelPtr(int32 a_U, int32 a_V); - ~CImageSurface(); - }; - -} // namespace ImageProcessing - diff --git a/Gems/ImageProcessing/External/CubeMapGen/ReadMe_CubeGen.doc b/Gems/ImageProcessing/External/CubeMapGen/ReadMe_CubeGen.doc deleted file mode 100644 index 56ad1c16b9..0000000000 Binary files a/Gems/ImageProcessing/External/CubeMapGen/ReadMe_CubeGen.doc and /dev/null differ diff --git a/Gems/ImageProcessing/External/CubeMapGen/VectorMacros.h b/Gems/ImageProcessing/External/CubeMapGen/VectorMacros.h deleted file mode 100644 index b752d0b3c1..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/VectorMacros.h +++ /dev/null @@ -1,176 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -//-------------------------------------------------------------------------------------- -// VectorMacros.h -// -// Fast operations on vectors, stored as arrays of floats -// -//-------------------------------------------------------------------------------------- -// (C) 2001-2005 ATI Research, Inc. All rights reserved. -//-------------------------------------------------------------------------------------- -// modifications by Crytek GmbH - -//disable warning about doubles being converted down to float -#pragma warning (disable : 4244 ) - -#define VM_LARGE_FLOAT 3.7e37f - -#define VM_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define VM_MAX(a, b) (((a) > (b)) ? (a) : (b)) - -//clamping macros -#define VM_CLAMP(d, s, mn, mx){(d) = ((s)<(mx))?( ((s)>(mn))?(s):(mn) ):(mx); } - -#define VM_CLAMP2_UNTYPED(d, s, mn, mx) {VM_CLAMP(d[0], s[0], mn, mx); VM_CLAMP(d[1], s[1], mn, mx);} -#define VM_CLAMP2(d, s, mn, mx) VM_CLAMP2_UNTYPED(((float *)(d)), ((float *)(s)), (float)(mn), (float)(mx)) - -#define VM_CLAMP3_UNTYPED(d, s, mn, mx) {VM_CLAMP(d[0], s[0], mn, mx); VM_CLAMP(d[1], s[1], mn, mx); VM_CLAMP(d[2], s[2], mn, mx);} -#define VM_CLAMP3(d, s, mn, mx) VM_CLAMP3_UNTYPED(((float *)(d)), ((float *)(s)), (float)(mn), (float)(mx)) - -#define VM_CLAMP4_UNTYPED(d, s, mn, mx) {VM_CLAMP(d[0], s[0], mn, mx); VM_CLAMP(d[1], s[1], mn, mx); VM_CLAMP(d[2], s[2], mn, mx); VM_CLAMP(d[3], s[3], mn, mx);} -#define VM_CLAMP4(d, s, mn, mx) VM_CLAMP4_UNTYPED(((float *)(d)), ((float *)(s)), (float)(mn), (float)(mx)) - - -//set vectors -#define VM_SET2_UNTYPED(d, f) { d[0]=f; d[1]=f;} -#define VM_SET2(d, f) VM_SET2_UNTYPED(((float *)(d)), ((float)(f))) - -#define VM_SET3_UNTYPED(d, f) { d[0]=f; d[1]=f; d[2]=f; } -#define VM_SET3(d, f) VM_SET3_UNTYPED(((float *)(d)), ((float)(f))) - -#define VM_SET4_UNTYPED(d, f) { d[0]=f; d[1]=f; d[2]=f; d[3]=f; } -#define VM_SET4(d, f) VM_SET4_UNTYPED(((float *)(d)), ((float)(f))) - - -//copy vectors -#define VM_COPY2_UNTYPED(d, s) { d[0]=s[0]; d[1]=s[1];} -#define VM_COPY2(d, s) VM_COPY2_UNTYPED(((float *)(d)), ((float *)(s))) - -#define VM_COPY3_UNTYPED(d, s) { d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; } -#define VM_COPY3(d, s) VM_COPY3_UNTYPED(((float *)(d)), ((float *)(s))) - -#define VM_COPY4_UNTYPED(d, s) { d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; d[3]=s[3]; } -#define VM_COPY4(d, s) VM_COPY4_UNTYPED(((float *)(d)), ((float *)(s))) - - -//add two vectors -#define VM_ADD2_UNTYPED(d, sa, sb) { d[0]=sa[0]+sb[0]; d[1]=sa[1]+sb[1]; } -#define VM_ADD2(d, sa, sb) VM_ADD3_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - -#define VM_ADD3_UNTYPED(d, sa, sb) { d[0]=sa[0]+sb[0]; d[1]=sa[1]+sb[1]; d[2]=sa[2]+sb[2]; } -#define VM_ADD3(d, sa, sb) VM_ADD3_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - -#define VM_ADD4_UNTYPED(d, sa, sb) { d[0]=sa[0]+sb[0]; d[1]=sa[1]+sb[1]; d[2]=sa[2]+sb[2]; d[3]=sa[3]+sb[3]; } -#define VM_ADD4(d, sa, sb) VM_ADD4_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - - -//subtract two vectors -#define VM_SUB2_UNTYPED(d, sa, sb) { d[0]=sa[0]-sb[0]; d[1]=sa[1]-sb[1]; } -#define VM_SUB2(d, sa, sb) VM_SUB2_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - -#define VM_SUB3_UNTYPED(d, sa, sb) { d[0]=sa[0]-sb[0]; d[1]=sa[1]-sb[1]; d[2]=sa[2]-sb[2]; } -#define VM_SUB3(d, sa, sb) VM_SUB3_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - -#define VM_SUB4_UNTYPED(d, sa, sb) { d[0]=sa[0]-sb[0]; d[1]=sa[1]-sb[1]; d[2]=sa[2]-sb[2]; d[3]=sa[3]-sb[3]; } -#define VM_SUB4(d, sa, sb) VM_SUB4_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - - -//multiply all elements of a vector by a scalar -#define VM_SCALE2_UNTYPED(d, s, f) {d[0]=s[0]*f; d[1]=s[1]*f; } -#define VM_SCALE2(d, s, f) VM_SCALE2_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f)) ) - -#define VM_SCALE3_UNTYPED(d, s, f) {d[0]=s[0]*f; d[1]=s[1]*f; d[2]=s[2]*f; } -#define VM_SCALE3(d, s, f) VM_SCALE3_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f)) ) - -#define VM_SCALE4_UNTYPED(d, s, f) {d[0]=s[0]*f; d[1]=s[1]*f; d[2]=s[2]*f; d[3]=s[3]*f; } -#define VM_SCALE4(d, s, f) VM_SCALE4_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f)) ) - - -//add a scalar to all elements of a vector -#define VM_BIAS2_UNTYPED(d, s, f) { d[0]=s[0]+f; d[1]=s[1]+f; } -#define VM_BIAS2(d, s, f) VM_BIAS2_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f))) - -#define VM_BIAS3_UNTYPED(d, s, f) { d[0]=s[0]+f; d[1]=s[1]+f; d[2]=s[2]+f; } -#define VM_BIAS3(d, s, f) VM_BIAS3_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f))) - -#define VM_BIAS4_UNTYPED(d, s, f) { d[0]=s[0]+f; d[1]=s[1]+f; d[2]=s[2]+f; d[3]=s[3]+f; } -#define VM_BIAS4(d, s, f) VM_BIAS4_UNTYPED(((float *)(d)), ((float *)(s)), ((float)(f))) - - -//3D cross product -#define VM_XPROD3_UNTYPED(d, sa, sb) { d[0]=sa[1]*sb[2]-sa[2]*sb[1]; d[1]=sa[2]*sb[0]-sa[0]*sb[2]; d[2]=sa[0]*sb[1]-sa[1]*sb[0]; } -#define VM_XPROD3(d, sa, sb) VM_XPROD3_UNTYPED(((float *)(d)), ((float *)(sa)), ((float *)(sb))) - - -//dot products -#define VM_DOTPROD2_UNTYPED(sa, sb) (sa[0]*sb[0]+ sa[1]*sb[1]) -#define VM_DOTPROD2(sa, sb) VM_DOTPROD2_UNTYPED(((float *)(sa)), ((float *)(sb))) - -#define VM_DOTPROD3_UNTYPED(sa, sb) (sa[0]*sb[0]+ sa[1]*sb[1]+ sa[2]*sb[2]) -#define VM_DOTPROD3(sa, sb) VM_DOTPROD3_UNTYPED(((float *)(sa)), ((float *)(sb))) - -#define VM_DOTPROD4_UNTYPED(sa, sb) (sa[0]*sb[0]+ sa[1]*sb[1]+ sa[2]*sb[2] + sa[3]*sb[3]) -#define VM_DOTPROD4(sa, sb) VM_DOTPROD4_UNTYPED(((float *)(sa)), ((float *)(sb))) - - -//dp3 then and add 4th component from second arguement -#define VM_DOTPROD3ADD_UNTYPED(pt, pl) (pt[0]*pl[0]+ pt[1]*pl[1]+ pt[2]*pl[2] + pl[3]) -#define VM_DOTPROD3ADD(pt, pl) VM_DOTPROD3ADD_UNTYPED(((float *)(pt)), ((float *)(pl))) - - -//normalize vectors -#define VM_NORM3_UNTYPED(d, s) {double __idsq; __idsq=1.0/sqrt(VM_DOTPROD3_UNTYPED(s,s)); d[0]=s[0]*__idsq; d[1]=s[1]*__idsq; d[2]=s[2]*__idsq; } -#define VM_NORM3_UNTYPED_F32(d, s) {float __idsq; __idsq=1.0/sqrt(VM_DOTPROD3_UNTYPED(s,s)); d[0]=s[0]*__idsq; d[1]=s[1]*__idsq; d[2]=s[2]*__idsq; } -#define VM_NORM3(d, s) VM_NORM3_UNTYPED_F32(((float *)(d)), ((float *)(s))) - -#define VM_NORM4_UNTYPED(d, s) {double __idsq; __idsq=1.0/sqrt(VM_DOTPROD4_UNTYPED(s,s)); d[0]=s[0]*__idsq; d[1]=s[1]*__idsq; d[2]=s[2]*__idsq; d[3]=s[3]*__idsq; } -#define VM_NORM4_UNTYPED_F32(d, s) {float __idsq; __idsq=1.0/sqrt(VM_DOTPROD4_UNTYPED(s,s)); d[0]=s[0]*__idsq; d[1]=s[1]*__idsq; d[2]=s[2]*__idsq; d[3]=s[3]*__idsq; } -#define VM_NORM4(d, s) VM_NORM4_UNTYPED_F32(((float *)(d)), ((float *)(s))) - - -//safely normalize vectors, deal with 0 length case -#define VM_SAFENORM3_UNTYPED(d, s) {float __idsq, __dp; __dp = VM_DOTPROD3_UNTYPED(s,s); \ - __idsq=( (__dp > 0.0f)?(1.0/sqrt(__dp)):0.0f ) ; d[0]=s[0]*__idsq; d[1]=s[1]*__idsq; d[2]=s[2]*__idsq; } -#define VM_SAFENORM3(d, s) VM_NORM3_UNTYPED_F32(((float *)(d)), ((float *)(s))) - - - -//absolute value -#define VM_ABS2_UNTYPED(d, s) { d[0] = fabs(s[0]); d[1] = fabs(s[1]); } -#define VM_ABS2(d, s) VM_ABS2_UNTYPED(((float *)(d)), ((float *)(s)) ) - -#define VM_ABS3_UNTYPED(d, s) { d[0] = fabs(s[0]); d[1] = fabs(s[1]); d[2] = fabs(s[2]); } -#define VM_ABS3(d, s) VM_ABS3_UNTYPED(((float *)(d)), ((float *)(s)) ) - -#define VM_ABS4_UNTYPED(d, s) { d[0] = fabs(s[0]); d[1] = fabs(s[1]); d[2] = fabs(s[2]); d[3] = fabs(s[3]); } -#define VM_ABS4(d, s) VM_ABS4_UNTYPED(((float *)(d)), ((float *)(s)) ) - - -//projection of a vector onto another vector (assumes vector v is normalized) -// computes d, which is the parallel component of s onto vector v -#define VM_PROJ3_UNTYPED(d, s, v) { double __dp; __dp = VM_DOTPROD3_UNTYPED(s, v); VM_SCALE3_UNTYPED(d, s, __dp); } -#define VM_PROJ3(d, s, v) VM_PROJ3_UNTYPED(((float *)(d)), ((float *)(s)), ((float *)(v)) ) -#define VM_PROJ3_F64(d, s, v) VM_PROJ3_UNTYPED(((double *)(d)), ((double *)(s)), ((double *)(v)) ) - - -//compute component of a vector perpendicular to another vector -// d is perpendicular component of s onto vector v -// this macro first computes the parallel projection, then subtracts off from the original vector -// to obtain the perpendicular component -#define VM_PERP3_UNTYPED(d, s, v) {double __proj[3]; VM_PROJ3_UNTYPED(__proj, s, v); VM_SUB3_UNTYPED(d, s, __proj); } -#define VM_PERP3(d, s, v) VM_PERP3_UNTYPED(((float *)(d)), ((float *)(s)), ((float *)(v)) ) -#define VM_PERP3_F64(d, s, v) VM_PERP3_UNTYPED(((double *)(d)), ((double *)(s)), ((double *)(v)) ) - - diff --git a/Gems/ImageProcessing/External/CubeMapGen/license.txt b/Gems/ImageProcessing/External/CubeMapGen/license.txt deleted file mode 100644 index aa663d5ba7..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/license.txt +++ /dev/null @@ -1,19 +0,0 @@ -Modified BSD License (2009): - -Copyright (c) 2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export laws, including but not limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. Sections 730 through 774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations under those regulations, please refer to the U.S. Bureau of Industry and Security’s website at http://www.bis.doc.gov/. - - - diff --git a/Gems/ImageProcessing/External/CubeMapGen/readme.txt b/Gems/ImageProcessing/External/CubeMapGen/readme.txt deleted file mode 100644 index 8026674cc4..0000000000 --- a/Gems/ImageProcessing/External/CubeMapGen/readme.txt +++ /dev/null @@ -1,5 +0,0 @@ -Cropped version of CubeMapGen-1.4-Source.zip - -More detail and download access: -https://gpuopen.com/archive/gamescgi/cubemapgen/ - diff --git a/Gems/ImageProcessing/gem.json b/Gems/ImageProcessing/gem.json deleted file mode 100644 index f211bad1e3..0000000000 --- a/Gems/ImageProcessing/gem.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "gem_name": "ImageProcessing", - "GemFormatVersion": 4, - "Uuid": "eeffbd9211cf4ce0b5cc73696b427cbe", - "Name": "ImageProcessing", - "DisplayName": "Image Processing", - "Version": "0.1.0", - "Summary": "Contains ImageBuilder for Asset Processor processing image files and UI for texture property editing", - "Tags": ["Image Builder", "Texture Property Editor"], - "IconPath": "preview.png", - "IsRequired": false, - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } - ], - "Dependencies": [ - { - "Uuid": "5a149b6b3c964064bd4970f0e92f72e2", - "VersionConstraints": [ - "~>0.1" - ], - "_comment": "Texture Atlas" - } - ] -} diff --git a/Gems/ImageProcessing/preview.png b/Gems/ImageProcessing/preview.png deleted file mode 100644 index 2f1ed47754..0000000000 --- a/Gems/ImageProcessing/preview.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa -size 41127 diff --git a/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp b/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp index 70d84dee6f..20ec7627bd 100644 --- a/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp @@ -72,25 +72,8 @@ namespace LmbrCentral return; } - ISystem* crySystem = GetISystem(); - if (!crySystem) - { - return; - } - - IRenderer* renderer = crySystem->GetIRenderer(); - if (!renderer) - { - return; - } - - IRenderAuxGeom* auxGeom = renderer->GetIRenderAuxGeom(); - if (!auxGeom) - { - return; - } - - float x = 10; + // ToDo: Remove class or update to work with Atom? LYN-3672 + /*float x = 10; float y = 15; ColorF color(1, 1, 1); constexpr bool center = false; @@ -161,7 +144,7 @@ namespace LmbrCentral StatusToString(asset.GetStatus()).c_str(), activeAssetLoadTime.count()); } - } + }*/ } void AssetSystemDebugComponent::AssetStatusUpdate(AZ::Data::AssetId id, AZ::Data::AssetData::AssetStatus status) diff --git a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp index f50526c67f..636aa72013 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp @@ -471,7 +471,7 @@ namespace CopyDependencyBuilder [[maybe_unused]] const AZStd::string& watchFolderPath) const { // Check the existing schema info stored in the asset database - // https://jira.agscollab.com/browse/LY-99056 + // LY-99056 return SchemaMatchResult::NoMatchFound; } @@ -526,7 +526,7 @@ namespace CopyDependencyBuilder { case SchemaMatchResult::MatchFound: // Update the LastUsedSchema info stored in the asset database - // https://jira.agscollab.com/browse/LY-99056 + // LY-99056 AZ_Printf("XmlBuilderWorker", "Schema file %s found for source %s.", schemaFilePath.c_str(), sourceFilePath.c_str()); return matchResult; case SchemaMatchResult::NoMatchFound: diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 10b3c3a317..d23ce13bfe 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -63,8 +63,6 @@ #include "Unhandled/UI/FontAssetTypeInfo.h" #include "Unhandled/UI/UICanvasAssetTypeInfo.h" -#include - // Asset types #include #include diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp index df5c65e07c..cd21b1e855 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp @@ -12,7 +12,7 @@ #include "LmbrCentral_precompiled.h" #include "EditorBaseShapeComponent.h" - +#include #include #include @@ -214,8 +214,7 @@ namespace LmbrCentral { if (changeReason == ShapeChangeReasons::ShapeChanged) { - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } } } // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp index e1951de498..144713c8ec 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp @@ -378,9 +378,7 @@ namespace LmbrCentral { SplineComponentNotificationBus::Event( GetEntityId(), &SplineComponentNotificationBus::Events::OnSplineChanged); - - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } AZ::SplinePtr EditorSplineComponent::GetSpline() diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 925f7512da..2514485519 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -304,6 +304,10 @@ public: void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(Entity*) override { } + void SignalEntityDeactivated(Entity*) override { } bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } @@ -329,6 +333,7 @@ public: m_serializeContext = aznew SerializeContext(true, true); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); m_sliceDescriptor = SliceComponent::CreateDescriptor(); m_mockAssetDescriptor = MockAssetRefComponent::CreateDescriptor(); @@ -358,6 +363,7 @@ public: void TearDown() override { m_catalog->DisableCatalog(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); Data::AssetManager::Destroy(); diff --git a/Gems/LyShine/Code/Editor/UiEditorEntityContext.cpp b/Gems/LyShine/Code/Editor/UiEditorEntityContext.cpp index 3be0b3cddf..d4de0b59c8 100644 --- a/Gems/LyShine/Code/Editor/UiEditorEntityContext.cpp +++ b/Gems/LyShine/Code/Editor/UiEditorEntityContext.cpp @@ -943,7 +943,7 @@ void UiEditorEntityContext::InitializeEntities(const AzFramework::EntityList& en // Because we automatically add the EditorOnlyEntityComponent if it doesn't exist, we can encounter a situation // where an entity has duplicate EditorOnlyEntityComponents if an old canvas is resaved and an old slice it uses - // is also resaved. See https://jira.agscollab.com/browse/LY-90580 + // is also resaved. See LY-90580 // In the main editor this is handled by disabling the duplicate components, but the UI Editor doesn't use that // method (the world editor allows the user to manually add incompatible components and then disable and enable // them in the entity, the UI Editor still works how the world editor used to - it doesn't allow users to add diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index 3ea451b7c5..bc6a27dac4 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -166,11 +166,6 @@ CLyShine::CLyShine(ISystem* system) UiAnimationSystem::StaticInitialize(); - if (m_system->GetIRenderer()) - { - m_system->GetIRenderer()->AddRenderDebugListener(this); - } - AzFramework::InputChannelEventListener::Connect(); AzFramework::InputTextEventListener::Connect(); UiCursorBus::Handler::BusConnect(); @@ -254,11 +249,6 @@ CLyShine::~CLyShine() AzFramework::InputTextEventListener::Disconnect(); AzFramework::InputChannelEventListener::Disconnect(); - if (m_system->GetIRenderer()) - { - m_system->GetIRenderer()->RemoveRenderDebugListener(this); - } - UiCanvasComponent::Shutdown(); // must be done after UiCanvasComponent::Shutdown diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.cpp b/Gems/LyShine/Code/Source/UiCanvasManager.cpp index 958dba0ab8..e09a6d0efd 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasManager.cpp @@ -815,7 +815,10 @@ bool UiCanvasManager::HandleInputEventForInWorldCanvases(const AzFramework::Inpu // First we need to construct a ray from the either the center of the screen or the mouse position. // This requires knowledge of the camera // for initial testing we will just use a ray in the center of the viewport - const CCamera& cam = GetISystem()->GetIRenderer()->GetCamera(); + + // ToDo: Re-implement by getting the camera from Atom. LYN-3680 + return false; + const CCamera cam; // construct a ray from the camera position in the view direction of the camera const float rayLength = 5000.0f; diff --git a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp index cb33ccac98..1bd2bd10be 100644 --- a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp +++ b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp @@ -98,7 +98,7 @@ namespace LyShineExamples { // if there is no texture we will just use a white texture // TODO: Get a default atom texture here when possible - //texture = gEnv->pRenderer->EF_GetTextureByID(gEnv->pRenderer->GetWhiteTextureId()); + //texture = ???->EF_GetTextureByID(???->GetWhiteTextureId()); } if (m_isRenderCacheDirty) diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp index ba30c3de39..ca1e73fc65 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimScreenFaderNode.cpp @@ -348,34 +348,6 @@ bool CAnimScreenFaderNode::GetParamInfoFromType(const CAnimParamType& paramId, S //----------------------------------------------------------------------------- void CAnimScreenFaderNode::Render() { - if (!m_bActive) - { - return; - } - - if (gEnv->pRenderer) - { - size_t const paramCount = m_tracks.size(); - for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex) - { - CScreenFaderTrack* pTrack = static_cast(GetTrackForParameter(AnimParamType::ScreenFader, paramIndex)); - - if (!pTrack) - { - continue; - } - - int textureId = -1; - if (pTrack->IsTextureVisible()) - { - textureId = (pTrack->GetActiveTexture() != 0) ? pTrack->GetActiveTexture()->GetTextureID() : -1; - } - - gEnv->pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); - gEnv->pRenderer->Draw2dImage(0, 0, m_screenWidth, m_screenHeight, textureId, 0.0f, 1.0f, 1.0f, 0.0f, 0.f, - pTrack->GetDrawColor().x, pTrack->GetDrawColor().y, pTrack->GetDrawColor().z, pTrack->GetDrawColor().w, 0.f); - } - } } bool CAnimScreenFaderNode::IsAnyTextureVisible() const diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp index f68ddb2b49..8ee2c68cc4 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp @@ -993,9 +993,6 @@ void CMovieSystem::ShowPlayedSequencesDebug() continue; } - const char* fullname = playingSequence.sequence->GetName(); - gEnv->pRenderer->Draw2dLabel(1.0f, y, 1.3f, green, false, "Sequence %s : %f (x %f)", fullname, playingSequence.currentTime, playingSequence.currentSpeed); - y += 16.0f; for (int i = 0; i < playingSequence.sequence->GetNodeCount(); ++i) @@ -1017,8 +1014,6 @@ void CMovieSystem::ShowPlayedSequencesDebug() { names.push_back(name); } - - gEnv->pRenderer->Draw2dLabel((21.0f + 100.0f * i), ((i % 2) ? (y + 8.0f) : y), 1.0f, alreadyThere ? white : purple, false, "%s", name); } y += 32.0f; diff --git a/Gems/Maestro/Code/Source/Cinematics/ScreenFaderTrack.cpp b/Gems/Maestro/Code/Source/Cinematics/ScreenFaderTrack.cpp index 8b2e615c26..3465b137b1 100644 --- a/Gems/Maestro/Code/Source/Cinematics/ScreenFaderTrack.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/ScreenFaderTrack.cpp @@ -113,12 +113,6 @@ void CScreenFaderTrack::PreloadTextures() GetKey(nKeyIndex, &key); if (!key.m_strTexture.empty()) { - ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(key.m_strTexture.c_str(), FT_DONT_STREAM | FT_STATE_CLAMP); - if (pTexture) - { - pTexture->SetClamp(true); - m_preloadedTextures.push_back(pTexture); - } } else { diff --git a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp index e300607fd7..cd0dfb02b3 100644 --- a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp +++ b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp @@ -122,7 +122,7 @@ namespace Maestro /////////////////////////////////////////////////////////////////////////////////////////////// void MaestroSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& startupParams) { - if (!startupParams.bSkipMovie && !startupParams.bShaderCacheGen) + if (!startupParams.bSkipMovie) { // OnCrySystemInitialized should only ever be called once, and we should be the only one initializing gEnv->pMovieSystem AZ_Assert(!m_movieSystemEventListener && gEnv && !gEnv->pMovieSystem, "MaestroSystemComponent::OnCrySystemInitialized - movie system was alread initialized."); diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h b/Gems/Multiplayer/Code/Include/IConnectionData.h similarity index 87% rename from Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h rename to Gems/Multiplayer/Code/Include/IConnectionData.h index a7ceffd289..dcc2c940ef 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h +++ b/Gems/Multiplayer/Code/Include/IConnectionData.h @@ -12,11 +12,13 @@ #pragma once -#include -#include +#include +#include namespace Multiplayer { + class EntityReplicationManager; + enum class ConnectionDataType { ClientToServer, @@ -42,8 +44,8 @@ namespace Multiplayer virtual EntityReplicationManager& GetReplicationManager() = 0; //! Creates and manages sending updates to the remote endpoint. - //! @param serverGameTimeMs current server game time in milliseconds - virtual void Update(AZ::TimeMs serverGameTimeMs) = 0; + //! @param hostTimeMs current server game time in milliseconds + virtual void Update(AZ::TimeMs hostTimeMs) = 0; //! Returns whether update messages can be sent to the connection. //! @return true if update messages can be sent diff --git a/Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h b/Gems/Multiplayer/Code/Include/IEntityDomain.h similarity index 97% rename from Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h rename to Gems/Multiplayer/Code/Include/IEntityDomain.h index 56ec24618d..6571797d05 100644 --- a/Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h +++ b/Gems/Multiplayer/Code/Include/IEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Include/IMultiplayer.h b/Gems/Multiplayer/Code/Include/IMultiplayer.h index 47d0d5a05e..039b86b2a6 100644 --- a/Gems/Multiplayer/Code/Include/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/IMultiplayer.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AzNetworking @@ -56,7 +57,7 @@ namespace Multiplayer //! Gets the type of Agent this IMultiplayer impl represents //! @return The type of agents represented - virtual MultiplayerAgentType GetAgentType() = 0; + virtual MultiplayerAgentType GetAgentType() const = 0; //! Sets the type of this Multiplayer connection and calls any related callback //! @param state The state of this connection @@ -78,6 +79,14 @@ namespace Multiplayer //! @param readyForEntityUpdates Ready for entity updates or not virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0; + //! Returns the current server time in milliseconds. + //! This can be one of three possible values: + //! 1. On the host outside of rewind scope, this will return the latest application elapsed time in ms. + //! 2. On the host within rewind scope, this will return the rewound time in ms. + //! 3. On the client, this will return the most recently replicated server time in ms. + //! @return the current server time in milliseconds + virtual AZ::TimeMs GetCurrentHostTimeMs() const = 0; + //! Returns the gem name associated with the provided component index. //! @param netComponentId the componentId to return the gem name of //! @return the name of the gem that contains the requested component diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/IMultiplayerComponentInput.h b/Gems/Multiplayer/Code/Include/IMultiplayerComponentInput.h similarity index 100% rename from Gems/Multiplayer/Code/Source/NetworkInput/IMultiplayerComponentInput.h rename to Gems/Multiplayer/Code/Include/IMultiplayerComponentInput.h diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/INetworkEntityManager.h similarity index 99% rename from Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h rename to Gems/Multiplayer/Code/Include/INetworkEntityManager.h index 891a4606ea..d9b611ece0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/INetworkEntityManager.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/INetworkTime.h similarity index 50% rename from Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h rename to Gems/Multiplayer/Code/Include/INetworkTime.h index 703fba5fb5..5346a0e0d0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h +++ b/Gems/Multiplayer/Code/Include/INetworkTime.h @@ -14,13 +14,10 @@ #include #include +#include namespace Multiplayer { - //! This is a strong typedef for representing the number of application frames since application start. - AZ_TYPE_SAFE_INTEGRAL(ApplicationFrameId, uint32_t); - static constexpr ApplicationFrameId InvalidApplicationFrameId = ApplicationFrameId{0xFFFFFFFF}; - //! @class INetworkTime //! @brief This is an AZ::Interface<> for managing multiplayer specific time related operations. class INetworkTime @@ -31,30 +28,24 @@ namespace Multiplayer INetworkTime() = default; virtual ~INetworkTime() = default; - //! Converts from an ApplicationFrameId to a corresponding TimeMs. - //! @param frameId the ApplicationFrameId to convert to a TimeMs - //! @return the TimeMs that corresponds to the provided ApplicationFrameId - virtual AZ::TimeMs ConvertFrameIdToTimeMs(ApplicationFrameId frameId) const = 0; - - //! Converts from a TimeMs to an ApplicationFrameId. - //! @param timeMs the TimeMs to convert to an ApplicationFrameId - //! @return the ApplicationFrameId that corresponds to the provided TimeMs - virtual ApplicationFrameId ConvertTimeMsToFrameId(AZ::TimeMs timeMs) const = 0; + //! Returns true if the host timeMs and frameId has been temporarily altered. + //! @return true if the host timeMs and frameId has been altered, false otherwise + virtual bool IsTimeRewound() const = 0; - //! Returns true if the application frameId has been temporarily altered. - //! @return true if the application frameId has been altered, false otherwise - virtual bool IsApplicationFrameIdRewound() const = 0; + //! Retrieves the hosts current frameId (may be rewound on the server during backward reconciliation). + //! @return the hosts current frameId + virtual HostFrameId GetHostFrameId() const = 0; - //! Retrieves the applications current frameId (may be rewound on the server during backward reconciliation). - //! @return the applications current frameId - virtual ApplicationFrameId GetApplicationFrameId() const = 0; + //! Retrieves the unaltered hosts current frameId. + //! @return the hosts current frameId, unaltered by any scoped time instance + virtual HostFrameId GetUnalteredHostFrameId() const = 0; - //! Retrieves the unaltered applications current frameId. - //! @return the applications current frameId, unaltered by any scoped time instance - virtual ApplicationFrameId GetUnalteredApplicationFrameId() const = 0; + //! Increments the hosts current frameId. + virtual void IncrementHostFrameId() = 0; - //! Increments the applications current frameId. - virtual void IncrementApplicationFrameId() = 0; + //! Retrieves the hosts current timeMs (may be rewound on the server during backward reconciliation). + //! @return the hosts current timeMs + virtual AZ::TimeMs GetHostTimeMs() const = 0; //! Synchronizes rewindable entity state for the current application time. virtual void SyncRewindableEntityState() = 0; @@ -66,14 +57,15 @@ namespace Multiplayer //! Get the controlling connection that may be currently altering global game time. //! Note this abstraction is required at a relatively high level to allow for 'don't rewind the shooter' semantics - //! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered applicationFrameId - //! @return the ApplicationFrameId taking into account the provided rewinding connectionId - virtual ApplicationFrameId GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0; + //! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered hostFrameId + //! @return the HostFrameId taking into account the provided rewinding connectionId + virtual HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0; - //! Alters the current ApplicationFrameId and binds that alteration to the provided ConnectionId. - //! @param frameId the new ApplicationFrameId to use + //! Alters the current HostFrameId and binds that alteration to the provided ConnectionId. + //! @param frameId the new HostFrameId to use + //! @param timeMs the new HostTimeMs to use //! @param rewindConnectionId the rewinding ConnectionId - virtual void AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) = 0; + virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0; AZ_DISABLE_COPY_MOVE(INetworkTime); }; @@ -93,22 +85,22 @@ namespace Multiplayer class ScopedAlterTime final { public: - inline ScopedAlterTime(ApplicationFrameId frameId, AzNetworking::ConnectionId connectionId) + inline ScopedAlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId connectionId) { INetworkTime* time = AZ::Interface::Get(); - m_previousApplicationFrameId = time->GetApplicationFrameId(); + m_previousHostFrameId = time->GetHostFrameId(); + m_previousHostTimeMs = time->GetHostTimeMs(); m_previousRewindConnectionId = time->GetRewindingConnectionId(); - time->AlterApplicationFrameId(frameId, connectionId); + time->AlterTime(frameId, timeMs, connectionId); } inline ~ScopedAlterTime() { INetworkTime* time = AZ::Interface::Get(); - time->AlterApplicationFrameId(m_previousApplicationFrameId, m_previousRewindConnectionId); + time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId); } private: - ApplicationFrameId m_previousApplicationFrameId = InvalidApplicationFrameId; + HostFrameId m_previousHostFrameId = InvalidHostFrameId; + AZ::TimeMs m_previousHostTimeMs = AZ::TimeMs{ 0 }; AzNetworking::ConnectionId m_previousRewindConnectionId = AzNetworking::InvalidConnectionId; }; } - -AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ApplicationFrameId); diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h b/Gems/Multiplayer/Code/Include/IReplicationWindow.h similarity index 96% rename from Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h rename to Gems/Multiplayer/Code/Include/IReplicationWindow.h index 27c14f8049..eb34a2f87d 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h +++ b/Gems/Multiplayer/Code/Include/IReplicationWindow.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp index b9f47814b4..7672997ad5 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp @@ -14,6 +14,12 @@ namespace Multiplayer { + MultiplayerStats::Metric::Metric() + { + AZStd::uninitialized_fill_n(m_callHistory.data(), RingbufferSamples, 0); + AZStd::uninitialized_fill_n(m_byteHistory.data(), RingbufferSamples, 0); + } + void MultiplayerStats::ReserveComponentStats(NetComponentId netComponentId, uint16_t propertyCount, uint16_t rpcCount) { const uint16_t netComponentIndex = aznumeric_cast(netComponentId); @@ -71,6 +77,29 @@ namespace Multiplayer { m_totalHistoryTimeMs = metricFrameTimeMs * static_cast(RingbufferSamples); m_recordMetricIndex = ++m_recordMetricIndex % RingbufferSamples; + for (ComponentStats& componentStats : m_componentStats) + { + for (Metric& metric : componentStats.m_propertyUpdatesSent) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_propertyUpdatesRecv) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_rpcsSent) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_rpcsRecv) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + } } static void CombineMetrics(MultiplayerStats::Metric& outArg1, const MultiplayerStats::Metric& arg2) diff --git a/Gems/Multiplayer/Code/Include/MultiplayerStats.h b/Gems/Multiplayer/Code/Include/MultiplayerStats.h index fcbd741bb9..dc266a14bf 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerStats.h +++ b/Gems/Multiplayer/Code/Include/MultiplayerStats.h @@ -37,6 +37,7 @@ namespace Multiplayer using MetricRingbuffer = AZStd::array; struct Metric { + Metric(); uint64_t m_totalCalls = 0; uint64_t m_totalBytes = 0; MetricRingbuffer m_callHistory; diff --git a/Gems/Multiplayer/Code/Include/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/MultiplayerTypes.h index 5c690958b5..1bee9867e3 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/MultiplayerTypes.h @@ -36,6 +36,12 @@ namespace Multiplayer AZ_TYPE_SAFE_INTEGRAL(PropertyIndex, uint16_t); AZ_TYPE_SAFE_INTEGRAL(RpcIndex, uint16_t); + AZ_TYPE_SAFE_INTEGRAL(ClientInputId, uint16_t); + + //! This is a strong typedef for representing the number of application frames since application start. + AZ_TYPE_SAFE_INTEGRAL(HostFrameId, uint32_t); + static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ 0xFFFFFFFF }; + using LongNetworkString = AZ::CVarFixedString; using ReliabilityType = AzNetworking::ReliabilityType; @@ -122,3 +128,5 @@ AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::NetEntityId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::NetComponentId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::PropertyIndex); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::RpcIndex); +AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ClientInputId); +AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostFrameId); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.h similarity index 99% rename from Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h rename to Gems/Multiplayer/Code/Include/NetworkEntityHandle.h index 0f84ed4477..9b8546ef2c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h +++ b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.h @@ -138,4 +138,4 @@ namespace Multiplayer }; } -#include "Source/NetworkEntity/NetworkEntityHandle.inl" +#include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.inl b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.inl similarity index 100% rename from Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.inl rename to Gems/Multiplayer/Code/Include/NetworkEntityHandle.inl diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja index 57375b39f2..2bae618d94 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja @@ -1,6 +1,6 @@ #include #include -#include +#include {% for Component in dataFiles %} {% set ComponentDerived = Component.attrib['OverrideComponent']|booleanTrue %} {% set ControllerDerived = Component.attrib['OverrideController']|booleanTrue %} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index fb7de56bb1..d211b933c5 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -170,12 +170,12 @@ AZ::Event<{{ Property.attrib['Type'] }}> {% set PropertyName = UpperFirst(Property.attrib['Name']) %} {{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} {% if IsOverride %} -void Handle{{ PropertyName }}({{ ', '.join(paramDefines) }}) override {} +void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) override {} {% else %} //! {{ PropertyName }} Handler //! {{ Property.attrib['Description'] }} //! HandleOn {{ HandleOn }} -virtual void Handle{{ PropertyName }}({{ ', '.join(paramDefines) }}) = 0; +virtual void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) = 0; {% endif %} {% endmacro %} {# diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 14a68cddf1..faaa009e34 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -221,11 +221,11 @@ AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] } #include #include #include -#include +#include +#include #include #include #include -#include #include #include {% call(Include) AutoComponentMacros.ParseIncludes(Component) %} @@ -435,7 +435,7 @@ namespace {{ Component.attrib['Namespace'] }} //! MultiplayerComponent interface //! @{ NetComponentId GetNetComponentId() const override; - bool HandleRpcMessage(Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override; + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override; bool SerializeStateDeltaMessage(Multiplayer::ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) override; void NotifyStateDeltaChanges(Multiplayer::ReplicationRecord& replicationRecord) override; bool HasController() const override; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index fb802541ce..6e54ec3d58 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -336,7 +336,7 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); } {% if Property.attrib['IsReliable']|booleanTrue %} {# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #} @@ -350,7 +350,7 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); } {% else %} Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); @@ -1251,7 +1251,12 @@ namespace {{ Component.attrib['Namespace'] }} #pragma warning(push) #pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels - bool {{ ComponentBaseName }}::HandleRpcMessage([[maybe_unused]] Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& message) + bool {{ ComponentBaseName }}::HandleRpcMessage + ( + [[maybe_unused]] AzNetworking::IConnection* invokingConnection, + [[maybe_unused]] Multiplayer::NetEntityRole remoteRole, + Multiplayer::NetworkEntityRpcMessage& message + ) { const {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure rpcType = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure>(message.GetRpcIndex()); switch (rpcType) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index 4eaf7ff0fb..44edcaf505 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -12,15 +12,16 @@ + - + - + - - + + @@ -30,6 +31,6 @@ - +
diff --git a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml index 5de466899c..daf55c3d92 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml @@ -3,6 +3,7 @@ + @@ -35,6 +36,7 @@ + diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 24986148c4..90b590d99d 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -13,9 +13,41 @@ #include #include #include +#include +#include +#include +#include +#include namespace Multiplayer { + AZ_CVAR(AZ::TimeMs, cl_InputRateMs, AZ::TimeMs{ 33 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Rate at which to sample and process client inputs"); + AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay"); +#ifndef _RELEASE + AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat"); +#endif + + AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs"); + AZ_CVAR(double, sv_MaxBankTimeWindowSec, 0.2, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum bank time we allow before we start rejecting autonomous proxy move inputs due to anticheat kicking in"); + AZ_CVAR(double, sv_BankTimeDecay, 0.025, nullptr, AZ::ConsoleFunctorFlags::Null, "Amount to decay bank time by, in case of more permanent shifts in client latency"); + AZ_CVAR(AZ::TimeMs, sv_MinCorrectionTimeMs, AZ::TimeMs{ 100 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time to wait between sending out corrections in order to avoid flooding corrections on high-latency connections"); + AZ_CVAR(AZ::TimeMs, sv_InputUpdateTimeMs, AZ::TimeMs{ 5 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time between component updates"); + + // Debug helper functions + AZStd::string GetInputString(NetworkInput& input) + { + AzNetworking::StringifySerializer serializer(',', false); + input.Serialize(serializer); + return serializer.GetString(); + } + + AZStd::string GetCorrectionDataString(NetBindComponent* netBindComponent) + { + AzNetworking::StringifySerializer serializer(',', false); + netBindComponent->SerializeEntityCorrection(serializer); + return serializer.GetString(); + } + void LocalPredictionPlayerInputComponent::LocalPredictionPlayerInputComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -27,30 +59,544 @@ namespace Multiplayer LocalPredictionPlayerInputComponentBase::Reflect(context); } + void LocalPredictionPlayerInputComponent::OnInit() + { + ; + } + + void LocalPredictionPlayerInputComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + + void LocalPredictionPlayerInputComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + + LocalPredictionPlayerInputComponentController::LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent) + : LocalPredictionPlayerInputComponentControllerBase(parent) + , m_autonomousUpdateEvent([this]() { UpdateAutonomous(m_autonomousUpdateEvent.TimeInQueueMs()); }, AZ::Name("AutonomousUpdate Event")) + , m_updateBankedTimeEvent([this]() { UpdateBankedTime(m_updateBankedTimeEvent.TimeInQueueMs()); }, AZ::Name("BankTimeUpdate Event")) + , m_migrateStartHandler([this](ClientInputId migratedInputId) { OnMigrateStart(migratedInputId); }) + , m_migrateEndHandler([this]() { OnMigrateEnd(); }) + { + if (GetNetEntityRole() == NetEntityRole::Autonomous) + { + m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true); + parent.GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler); + parent.GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler); + } + } + + void LocalPredictionPlayerInputComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + if (entityIsMigrating == EntityIsMigrating::True) + { + m_allowMigrateClientInput = true; + m_serverMigrateFrameId = AZ::Interface::Get()->GetHostFrameId(); + } + } + + void LocalPredictionPlayerInputComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + void LocalPredictionPlayerInputComponentController::HandleSendClientInput ( - [[maybe_unused]] const Multiplayer::NetworkInputVector& inputArray, - [[maybe_unused]] const uint32_t& stateHash, + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputArray& inputArray, + const AZ::HashValue32& stateHash, [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState ) { - ; + // After receiving the first input from the client, start the update event to check for slow hacking + if (!m_updateBankedTimeEvent.IsScheduled()) + { + m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true); + } + + if (invokingConnection == nullptr) + { + // Discard any input messages that were locally dispatched or sent by disconnected clients + return; + } + + const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs(); + const double clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + m_lastInputReceivedTimeMs = currentTimeMs; + + // Keep track of last inputs received, also allows us to update frame ids + m_lastInputReceived = inputArray; + + // Figure out which index from the input array we want + // we start at the oldest input that has not been processed + int32_t inputArrayIndex = -1; + for (int32_t i = NetworkInputArray::MaxElements - 1; i >= 0; --i) + { + // Find an input that is newer than the last one we processed + if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId()) + { + inputArrayIndex = i; + break; + } + } + + if (inputArrayIndex < 0) + { + AZLOG + ( + NET_Prediction, + "Discarding old or out of order move input (current: %u, received %u)", + aznumeric_cast(GetLastInputId()), + aznumeric_cast(m_lastInputReceived[0].GetClientInputId()) + ); + return; + } + + bool lostInput = false; + if (GetLastInputId() < inputArray.GetPreviousInputId()) + { + // last move id processed is older than the previous input id, we missed some input packets + lostInput = true; + } + + SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration + + while (inputArrayIndex >= 0) + { + NetworkInput& input = m_lastInputReceived[inputArrayIndex]; + + // Anticheat, if we're receiving too many inputs, and fall outside our variable latency input window + // Discard move input events, client may be speed hacking + if (m_clientBankedTime < sv_MaxBankTimeWindowSec) + { + m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary + + { + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec)); + } + if (lostInput) + { + AZLOG(NET_Prediction, "InputLost InputId=%u", aznumeric_cast(input.GetClientInputId())); + } + else + { + AZLOG(NET_Prediction, "Processed InputId=%u", aznumeric_cast(input.GetClientInputId())); + } + } + else + { + AZLOG(NET_Prediction, "Dropped InputId=%u", aznumeric_cast(input.GetClientInputId())); + } + --inputArrayIndex; + } + + if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs)) + { + m_lastCorrectionSentTimeMs = currentTimeMs; + + AzNetworking::HashSerializer hashSerializer; + GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); + + const AZ::HashValue32 localAuthorityHash = hashSerializer.GetHash(); + + if (stateHash != localAuthorityHash) + { + // Produce correction for client + AzNetworking::PacketEncodingBuffer correction; + correction.Resize(correction.GetCapacity()); + AzNetworking::NetworkInputSerializer serializer(correction.GetBuffer(), correction.GetCapacity()); + + // only deserialize if we have data (for client/server profile/debug mismatches) + if (correction.GetSize() > 0) + { + GetNetBindComponent()->SerializeEntityCorrection(serializer); + } + + correction.Resize(serializer.GetSize()); + + // Send correction + SendClientInputCorrection(GetLastInputId(), correction); + +#ifdef _DEBUG + // In debug, show which states caused the correction + AZStd::string clientStateString; + AZStd::string serverStateString; + { + // Write in client state + AzNetworking::NetworkOutputSerializer clientStateSerializer(clientState.GetBuffer(), clientState.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(clientStateSerializer); + + // Read out state values + AzNetworking::StringifySerializer clientValues; + GetNetBindComponent()->SerializeEntityCorrection(clientValues); + + // Restore server state + AzNetworking::NetworkOutputSerializer serverStateSerializer(correction.GetBuffer(), correction.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(serverStateSerializer); + + // Read out state values + AzNetworking::StringifySerializer serverValues; + GetNetBindComponent()->SerializeEntityCorrection(serverValues); + + AZStd::map> mapComparison; + // put the server value in the first part of the pair + for (const auto& pair : serverValues.GetValueMap()) + { + mapComparison[pair.first].first = pair.second; + } + // put the client value in the second part of the pair + for (const auto& pair : clientValues.GetValueMap()) + { + mapComparison[pair.first].second = pair.second; + } + + bool firstIt = true; + for (const auto& mapPair : mapComparison) + { + if (mapPair.second.first != mapPair.second.second) + { + if (!firstIt) + { + clientStateString += ","; + serverStateString += ","; + } + firstIt = false; + + AZStd::string clientValue = mapPair.second.second.empty() ? "" : mapPair.second.second; + AZStd::string serverValue = mapPair.second.first.empty() ? "" : mapPair.second.first; + clientStateString += mapPair.first + "=" + clientValue; + serverStateString += mapPair.first + "=" + serverValue; + } + } + } +#else + const AZStd::string clientStateString = "available in debug only"; + const AZStd::string serverStateString = "available in debug only"; +#endif + + AZLOG_ERROR("** Autonomous proxy desync detected! ** clientState=[%s], serverState=[%s]", clientStateString.c_str(), serverStateString.c_str()); + } + } } void LocalPredictionPlayerInputComponentController::HandleSendMigrateClientInput ( - [[maybe_unused]] const Multiplayer::MigrateNetworkInputVector& inputArray + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputMigrationVector& inputArray ) { - ; + if (!m_allowMigrateClientInput) + { + AZLOG_ERROR("Client attempting to SendMigrateClientInput message when server was not expecting it. This may be an attempt to cheat"); + return; + } + + // We only allow the client to send this message exactly once, when the component has been migrated + // Any further processing of these messages from the client would be exploitable + m_allowMigrateClientInput = false; + + if (invokingConnection == nullptr) + { + // Discard any input migration messages that were locally dispatched or sent by disconnected clients + return; + } + + const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + + // Copy array so we can modify input ids + NetworkInputMigrationVector inputArrayCopy = inputArray; + + for (uint32_t i = 0; i < inputArrayCopy.GetSize(); ++i) + { + NetworkInput& input = inputArrayCopy[i]; + + ++ModifyLastInputId(); + input.SetClientInputId(GetLastInputId()); + + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); + + AZLOG + ( + NET_Prediction, + "Migrated InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + // Don't bother checking for corrections here, the next regular input will trigger any corrections if necessary + // Also don't bother with any cheat detection here, because the input array is limited in size and at most and can only be sent once + // So this highly constrains anything a malicious client can do + } } void LocalPredictionPlayerInputComponentController::HandleSendClientInputCorrection ( - [[maybe_unused]] const Multiplayer::ClientInputId& inputId, - [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& correction + AzNetworking::IConnection* invokingConnection, + const Multiplayer::ClientInputId& inputId, + const AzNetworking::PacketEncodingBuffer& correction ) { - ; + AZ_Assert(inputId <= m_clientInputId, "Invalid correction frame id, correction is for a move the client has not yet submitted to the server"); + if (inputId > m_clientInputId) + { + AZLOG_ERROR("Discarding correction for non-existent move, correction represents a move we haven't sent to the server yet"); + return; + } + + if (inputId <= m_lastCorrectionInputId) + { + AZLOG(NET_Prediction, "Discarding old correction for client frame %u", aznumeric_cast(inputId)); + return; + } + + m_lastCorrectionInputId = inputId; + + // Apply the correction + AzNetworking::TrackChangedSerializer serializer(correction.GetBuffer(), correction.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(serializer); + m_correctionEvent.Signal(); + + AZLOG + ( + NET_Prediction, + "Corrected InputId=%d - o=[%s]", + aznumeric_cast(m_lastCorrectionInputId), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + const uint32_t inputHistorySize = m_inputHistory.Size(); + const uint32_t historicalDelta = aznumeric_cast(m_clientInputId - inputId); // Do not replay the move we just corrected, that was already processed by the server + + // If this correction is for a move outside our input history window, just start replaying from the oldest move we have available + const uint32_t startReplayIndex = (inputHistorySize > historicalDelta) ? (inputHistorySize - historicalDelta) : 0; + + // Flag that we are replaying inputs + struct ScopedReplayingInput + { + ScopedReplayingInput(LocalPredictionPlayerInputComponentController* instance) + : m_instance(instance) + { + m_instance->m_replayingInput = true; + } + ~ScopedReplayingInput() + { + m_instance->m_replayingInput = false; + } + LocalPredictionPlayerInputComponentController* m_instance; + }; + ScopedReplayingInput markReplayingInput(this); + + const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + for (uint32_t replayIndex = startReplayIndex; replayIndex < inputHistorySize; ++replayIndex) + { + // Reprocess the input for this frame + NetworkInput& input = m_inputHistory[replayIndex]; + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); + + AZLOG + ( + NET_Prediction, + "Replayed InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + } + } + + bool LocalPredictionPlayerInputComponentController::IsReplayingInput() const + { + return m_replayingInput; + } + + bool LocalPredictionPlayerInputComponentController::IsMigrating() const + { + return m_lastMigratedInputId != ClientInputId{ 0 }; + } + + ClientInputId LocalPredictionPlayerInputComponentController::GetLastInputId() const + { + return m_clientInputId; + } + + HostFrameId LocalPredictionPlayerInputComponentController::GetInputFrameId(const NetworkInput& input) const + { + // If the client has sent us an invalid server frame id + // this is because they are in the process of migrating from one server to another + // In this situation, use whatever the server frame id was when this component was migrated + // This will match the closest state to what the client sees + return (input.GetHostFrameId() == InvalidHostFrameId) ? m_serverMigrateFrameId : input.GetHostFrameId(); + } + + void LocalPredictionPlayerInputComponentController::CorrectionEventAddHandle(CorrectionEvent::Handler& handler) + { + handler.Connect(m_correctionEvent); + } + + void LocalPredictionPlayerInputComponentController::OnMigrateStart(ClientInputId migratedInputId) + { + m_lastMigratedInputId = migratedInputId; + } + + void LocalPredictionPlayerInputComponentController::OnMigrateEnd() + { + NetworkInputMigrationVector inputArray; + + // Roll up all inputs that the new server doesn't have and send them now + for (AZStd::size_t i = 0; i < m_inputHistory.Size(); ++i) + { + NetworkInput& input = m_inputHistory[i]; + + // New server already has these inputs + if (input.GetClientInputId() <= m_lastMigratedInputId) + { + continue; + } + + // Clear out the old server frame id + // We don't know what server frame ids to use for the new server yet, but the new server will figure out how to deal with this + input.SetHostFrameId(InvalidHostFrameId); + + // New server doesn't have these inputs + if (!inputArray.PushBack(input)) + { + break; // Reached capacity + } + } + + // Send these inputs to the server + SendMigrateClientInput(inputArray); + + // Done migrating + m_lastMigratedInputId = ClientInputId{ 0 }; + } + + void LocalPredictionPlayerInputComponentController::UpdateAutonomous(AZ::TimeMs deltaTimeMs) + { + const double deltaTime = static_cast(deltaTimeMs) / 1000.0; + const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; + +#ifndef _RELEASE + m_moveAccumulator += deltaTime * cl_DebugHackTimeMultiplier; +#else + m_moveAccumulator += deltaTime; +#endif + + const uint32_t maxClientInputs = inputRate > 0.0 ? static_cast(maxRewindHistory / inputRate) : 0; + + INetworkTime* networkTime = AZ::Interface::Get(); + IMultiplayer* multiplayer = AZ::Interface::Get(); + while (m_moveAccumulator >= inputRate) + { + m_moveAccumulator -= inputRate; + ++m_clientInputId; + + NetworkInputArray inputArray(GetEntityHandle()); + NetworkInput& input = inputArray[0]; + + input.SetClientInputId(m_clientInputId); + input.SetHostFrameId(networkTime->GetHostFrameId()); + input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs()); + + // Allow components to form the input for this frame + GetNetBindComponent()->CreateInput(input, inputRate); + + // Process the input for this frame + GetNetBindComponent()->ProcessInput(input, inputRate); + + AZLOG + ( + NET_Prediction, + "Processed InutId=%d - i=[%s] o=[%s]", + aznumeric_cast(m_clientInputId), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + // Generate a hash based on the current client predicted states + AzNetworking::HashSerializer hashSerializer; + GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); + + // In debug, send the entire client output state to the server to make it easier to debug desync issues + AzNetworking::PacketEncodingBuffer processInputResult; +#ifdef _DEBUG + AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); + GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); + processInputResult.Resize(processInputResultSerializer.GetSize()); +#endif + + // Save this input and discard move history outside our client rewind window + m_inputHistory.PushBack(input); + while (m_inputHistory.Size() > maxClientInputs) + { + m_inputHistory.PopFront(); + } + + const size_t inputHistorySize = m_inputHistory.Size(); + + // Form the rest of the input array using the n most recent elements in the history buffer + // NOTE: inputArray[0] has already been initialized hence start at i = 1 + for (uint32_t i = 1; i < NetworkInputArray::MaxElements; ++i) + { + if (i < inputHistorySize) + { + inputArray[i] = m_inputHistory[inputHistorySize - 1 - i]; + } + else // History is too small? + { + // Plug in the most recent input + inputArray[i] = input; + } + } + + // Send the input to server (only when we are not migrating) + if (!IsMigrating()) + { + SendClientInput(inputArray, hashSerializer.GetHash(), processInputResult); + } + } + } + + void LocalPredictionPlayerInputComponentController::UpdateBankedTime(AZ::TimeMs deltaTimeMs) + { + const double deltaTime = static_cast(deltaTimeMs) / 1000.0; + const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; + + // Update banked time accumulator + m_clientBankedTime -= deltaTime; + + // Forcibly tick any clients who are too far behind our variable latency window + // Client may be slow hacking + if (m_clientBankedTime < -sv_MaxBankTimeWindowSec) + { + m_clientBankedTime = -sv_MaxBankTimeWindowSec; // clamp to boundary + + NetworkInput& input = m_lastInputReceived[0]; + { + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), AzNetworking::InvalidConnectionId); + GetNetBindComponent()->ProcessInput(input, inputRate); + } + + AZLOG + ( + NET_Prediction, + "Forced InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + } + + // Decay our bank time window, in case the remote endpoint has suffered a more persistent shift in latency, this should cause the client to eventually recover + m_clientBankedTime = m_clientBankedTime * (1.0 - sv_BankTimeDecay); } } diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h index b332315799..15a4f3a048 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h @@ -13,9 +13,12 @@ #pragma once #include +#include namespace Multiplayer { + using CorrectionEvent = AZ::Event<>; + class LocalPredictionPlayerInputComponent : public LocalPredictionPlayerInputComponentBase { @@ -24,24 +27,87 @@ namespace Multiplayer static void Reflect([[maybe_unused]] AZ::ReflectContext* context); - void OnInit() override {} - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - - + void OnInit() override; + void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; }; class LocalPredictionPlayerInputComponentController : public LocalPredictionPlayerInputComponentControllerBase { public: - LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent) : LocalPredictionPlayerInputComponentControllerBase(parent) {} + LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent); + + void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; + + void HandleSendClientInput + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputArray& inputArray, + const AZ::HashValue32& stateHash, + const AzNetworking::PacketEncodingBuffer& clientState + ) override; + + void HandleSendMigrateClientInput + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputMigrationVector& inputArray + ) override; + + void HandleSendClientInputCorrection + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::ClientInputId& inputId, + const AzNetworking::PacketEncodingBuffer& correction + ) override; + + //! Return true if we're currently replaying inputs after a correction. + //! If this value returns true, effects, audio, and other cosmetic triggers should be suppressed + //! @return true if we're within correction scope and replaying inputs + bool IsReplayingInput() const; + + //! Return true if we're currently migrating from one host to another. + //! @return boolean true if we're currently migrating from one host to another + bool IsMigrating() const; + + ClientInputId GetLastInputId() const; + HostFrameId GetInputFrameId(const NetworkInput& input) const; + + void CorrectionEventAddHandle(CorrectionEvent::Handler& handler); + + private: + + void OnMigrateStart(ClientInputId migratedInputId); + void OnMigrateEnd(); + void UpdateAutonomous(AZ::TimeMs deltaTimeMs); + void UpdateBankedTime(AZ::TimeMs deltaTimeMs); + + // Implicitly sorted player input history, back() is the input that corresponds to the latest client input Id + NetworkInputHistory m_inputHistory; + + // Anti-cheat accumulator for clients who purposely mess with their clock rate + NetworkInputArray m_lastInputReceived; + + AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection + AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates + + CorrectionEvent m_correctionEvent; + EntityMigrationStartEvent::Handler m_migrateStartHandler; + EntityMigrationEndEvent::Handler m_migrateEndHandler; + + double m_moveAccumulator = 0.0; + double m_clientBankedTime = 0.0; + + AZ::TimeMs m_lastInputReceivedTimeMs = AZ::TimeMs{ 0 }; + AZ::TimeMs m_lastCorrectionSentTimeMs = AZ::TimeMs{ 0 }; - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} + ClientInputId m_clientInputId = ClientInputId{ 0 }; + ClientInputId m_lastCorrectionInputId = ClientInputId{ 0 }; + ClientInputId m_lastMigratedInputId = ClientInputId{ 0 }; // Used to resend inputs that were queued during a migration event + HostFrameId m_serverMigrateFrameId = InvalidHostFrameId; - void HandleSendClientInput(const Multiplayer::NetworkInputVector& inputArray, const uint32_t& stateHash, const AzNetworking::PacketEncodingBuffer& clientState) override; - void HandleSendMigrateClientInput(const Multiplayer::MigrateNetworkInputVector& inputArray) override; - void HandleSendClientInputCorrection(const Multiplayer::ClientInputId& inputId, const AzNetworking::PacketEncodingBuffer& correction) override; + bool m_replayingInput = false; // True if we're replaying inputs under a correction event (use this to suppress effects or audio) + bool m_allowMigrateClientInput = false; // True if this component was migrated, we will allow the client to send us migrated inputs (one time only) }; } diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h index 3642a55476..0f64221dde 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -69,7 +69,7 @@ namespace Multiplayer virtual NetComponentId GetNetComponentId() const = 0; - virtual bool HandleRpcMessage(NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0; + virtual bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0; virtual bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) = 0; virtual void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord) = 0; virtual bool HasController() const = 0; diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h index 9e3c7d68ab..de07e39e66 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index bb1dac5a4e..eba09734a9 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -13,10 +13,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -192,12 +192,12 @@ namespace Multiplayer return bounds; } - bool NetBindComponent::HandleRpcMessage(NetEntityRole remoteRole, NetworkEntityRpcMessage& message) + bool NetBindComponent::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message) { auto findIt = m_multiplayerComponentMap.find(message.GetComponentId()); if (findIt != m_multiplayerComponentMap.end()) { - return findIt->second->HandleRpcMessage(remoteRole, message); + return findIt->second->HandleRpcMessage(invokingConnection, remoteRole, message); } return false; } @@ -274,9 +274,19 @@ namespace Multiplayer m_localNotificationRecord.Clear(); } - void NetBindComponent::NotifyMigration(HostId remoteHostId, AzNetworking::ConnectionId connectionId) + void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId) { - m_entityMigrationEvent.Signal(m_netEntityHandle, remoteHostId, connectionId); + m_entityMigrationStartEvent.Signal(migratedInputId); + } + + void NetBindComponent::NotifyMigrationEnd() + { + m_entityMigrationEndEvent.Signal(); + } + + void NetBindComponent::NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId) + { + m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId); } void NetBindComponent::AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler) @@ -289,9 +299,19 @@ namespace Multiplayer eventHandler.Connect(m_dirtiedEvent); } - void NetBindComponent::AddEntityMigrationEventHandler(EntityMigrationEvent::Handler& eventHandler) + void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityMigrationStartEvent); + } + + void NetBindComponent::AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityMigrationEndEvent); + } + + void NetBindComponent::AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler) { - eventHandler.Connect(m_entityMigrationEvent); + eventHandler.Connect(m_entityServerMigrationEvent); } bool NetBindComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer) diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h index e992dbfd72..0885e44aa4 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h @@ -21,8 +21,9 @@ #include #include #include -#include -#include +#include +#include +#include #include #include @@ -34,7 +35,9 @@ namespace Multiplayer using EntityStopEvent = AZ::Event; using EntityDirtiedEvent = AZ::Event<>; - using EntityMigrationEvent = AZ::Event; + using EntityMigrationStartEvent = AZ::Event; + using EntityMigrationEndEvent = AZ::Event<>; + using EntityServerMigrationEvent = AZ::Event; //! @class NetBindComponent //! @brief Component that provides net-binding to a networked entity. @@ -72,7 +75,7 @@ namespace Multiplayer void ProcessInput(NetworkInput& networkInput, float deltaTime); AZ::Aabb GetRewindBoundsForInput(const NetworkInput& networkInput, float deltaTime) const; - bool HandleRpcMessage(NetEntityRole remoteRole, NetworkEntityRpcMessage& message); + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message); bool HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges = true); RpcSendEvent& GetSendAuthorityToClientRpcEvent(); @@ -84,11 +87,15 @@ namespace Multiplayer void MarkDirty(); void NotifyLocalChanges(); - void NotifyMigration(HostId remoteHostId, AzNetworking::ConnectionId connectionId); + void NotifyMigrationStart(ClientInputId migratedInputId); + void NotifyMigrationEnd(); + void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId); void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler); void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler); - void AddEntityMigrationEventHandler(EntityMigrationEvent::Handler& eventHandler); + void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler); + void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler); + void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler); bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer); @@ -119,7 +126,7 @@ namespace Multiplayer ReplicationRecord m_currentRecord = NetEntityRole::InvalidRole; ReplicationRecord m_totalRecord = NetEntityRole::InvalidRole; - ReplicationRecord m_predictableRecord = NetEntityRole::InvalidRole; + ReplicationRecord m_predictableRecord = NetEntityRole::Autonomous; ReplicationRecord m_localNotificationRecord = NetEntityRole::InvalidRole; PrefabEntityId m_prefabEntityId; AZStd::unordered_map m_multiplayerComponentMap; @@ -133,7 +140,9 @@ namespace Multiplayer EntityStopEvent m_entityStopEvent; EntityDirtiedEvent m_dirtiedEvent; - EntityMigrationEvent m_entityMigrationEvent; + EntityMigrationStartEvent m_entityMigrationStartEvent; + EntityMigrationEndEvent m_entityMigrationEndEvent; + EntityServerMigrationEvent m_entityServerMigrationEvent; AZ::Event<> m_onRemove; RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle; AZ::Event<>::Handler m_handleMarkedDirty; diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp index 4420e0689c..ee308f6ed8 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp @@ -50,8 +50,9 @@ namespace Multiplayer return m_entityReplicationManager; } - void ClientToServerConnectionData::Update([[maybe_unused]] AZ::TimeMs serverGameTimeMs) + void ClientToServerConnectionData::Update(AZ::TimeMs hostTimeMs) { m_entityReplicationManager.ActivatePendingEntities(); + m_entityReplicationManager.SendUpdates(hostTimeMs); } } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h index 76a809b351..b72a6aad2b 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h @@ -12,7 +12,8 @@ #pragma once -#include +#include +#include namespace Multiplayer { @@ -32,7 +33,7 @@ namespace Multiplayer ConnectionDataType GetConnectionDataType() const override; AzNetworking::IConnection* GetConnection() const override; EntityReplicationManager& GetReplicationManager() override; - void Update(AZ::TimeMs serverGameTimeMs) override; + void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; //! @} diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp index 7a7e266a38..d2440d28f4 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp @@ -35,7 +35,7 @@ namespace Multiplayer if (netBindComponent != nullptr) { netBindComponent->AddEntityStopEventHandler(m_controlledEntityRemovedHandler); - netBindComponent->AddEntityMigrationEventHandler(m_controlledEntityMigrationHandler); + netBindComponent->AddEntityServerMigrationEventHandler(m_controlledEntityMigrationHandler); } m_entityReplicationManager.SetMaxRemoteEntitiesPendingCreationCount(sv_ClientMaxRemoteEntitiesPendingCreationCount); @@ -63,7 +63,7 @@ namespace Multiplayer return m_entityReplicationManager; } - void ServerToClientConnectionData::Update(AZ::TimeMs serverGameTimeMs) + void ServerToClientConnectionData::Update(AZ::TimeMs hostTimeMs) { m_entityReplicationManager.ActivatePendingEntities(); @@ -73,7 +73,7 @@ namespace Multiplayer // potentially false if we just migrated the player, if that is the case, don't send any more updates if (netBindComponent != nullptr && (netBindComponent->GetNetEntityRole() == NetEntityRole::Authority)) { - m_entityReplicationManager.SendUpdates(serverGameTimeMs); + m_entityReplicationManager.SendUpdates(hostTimeMs); } } } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h index 7ea62b15fd..b02e6de9aa 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h @@ -12,7 +12,8 @@ #pragma once -#include +#include +#include namespace Multiplayer { @@ -33,7 +34,7 @@ namespace Multiplayer ConnectionDataType GetConnectionDataType() const override; AzNetworking::IConnection* GetConnection() const override; EntityReplicationManager& GetReplicationManager() override; - void Update(AZ::TimeMs serverGameTimeMs) override; + void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; //! @} @@ -49,7 +50,7 @@ namespace Multiplayer EntityReplicationManager m_entityReplicationManager; NetworkEntityHandle m_controlledEntity; EntityStopEvent::Handler m_controlledEntityRemovedHandler; - EntityMigrationEvent::Handler m_controlledEntityMigrationHandler; + EntityServerMigrationEvent::Handler m_controlledEntityMigrationHandler; AzNetworking::IConnection* m_connection = nullptr; bool m_canSendUpdates = false; }; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 506581b5e4..aec8d8520e 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -235,7 +235,7 @@ namespace Multiplayer if (m_displayMultiplayerStats) { - if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_HorizontalScrollbar)) + if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None)) { IMultiplayer* multiplayer = AZ::Interface::Get(); const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats(); @@ -254,7 +254,7 @@ namespace Multiplayer if (ImGui::BeginTable("", 5, flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide, TEXT_BASE_WIDTH * 36.0f); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Total Calls", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); ImGui::TableSetupColumn("Total Bytes", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); ImGui::TableSetupColumn("Calls/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); diff --git a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h index 95bfc211cf..c1abbe74cd 100644 --- a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h +++ b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 03c661ab03..e6fb77eca7 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -127,7 +127,8 @@ namespace Multiplayer void MultiplayerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZ::TimeMs serverGameTimeMs = AZ::GetElapsedTimeMs(); + AZ::TimeMs deltaTimeMs = aznumeric_cast(static_cast(deltaTime * 1000.0f)); + AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs(); // Handle deferred local rpc messages that were generated during the updates m_networkEntityManager.DispatchLocalDeferredRpcMessages(); @@ -137,18 +138,19 @@ namespace Multiplayer m_networkEntityManager.NotifyEntitiesDirtied(); MultiplayerStats& stats = GetStats(); + stats.TickStats(deltaTimeMs); stats.m_entityCount = GetNetworkEntityManager()->GetEntityCount(); stats.m_serverConnectionCount = 0; stats.m_clientConnectionCount = 0; // Send out the game state update to all connections { - auto sendNetworkUpdates = [serverGameTimeMs, &stats](IConnection& connection) + auto sendNetworkUpdates = [hostTimeMs, &stats](IConnection& connection) { if (connection.GetUserData() != nullptr) { IConnectionData* connectionData = reinterpret_cast(connection.GetUserData()); - connectionData->Update(serverGameTimeMs); + connectionData->Update(hostTimeMs); if (connectionData->GetConnectionDataType() == ConnectionDataType::ServerToClient) { stats.m_clientConnectionCount++; @@ -481,7 +483,7 @@ namespace Multiplayer } } - MultiplayerAgentType MultiplayerSystemComponent::GetAgentType() + MultiplayerAgentType MultiplayerSystemComponent::GetAgentType() const { return m_agentType; } @@ -528,6 +530,18 @@ namespace Multiplayer }); } + AZ::TimeMs MultiplayerSystemComponent::GetCurrentHostTimeMs() const + { + if (GetAgentType() == MultiplayerAgentType::Client) + { + return m_lastReplicatedHostTimeMs; + } + else // ClientServer or DedicatedServer + { + return m_networkTime.GetHostTimeMs(); + } + } + const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const { return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index f25e530b61..477745e6b5 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -84,12 +84,13 @@ namespace Multiplayer //! IMultiplayer interface //! @{ - MultiplayerAgentType GetAgentType() override; + MultiplayerAgentType GetAgentType() const override; void InitializeMultiplayer(MultiplayerAgentType state) override; void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; void SendReadyForEntityUpdates(bool readyForEntityUpdates) override; + AZ::TimeMs GetCurrentHostTimeMs() const override; const char* GetComponentGemName(NetComponentId netComponentId) const override; const char* GetComponentName(NetComponentId netComponentId) const override; const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const override; @@ -119,5 +120,8 @@ namespace Multiplayer SessionInitEvent m_initEvent; SessionShutdownEvent m_shutdownEvent; ConnectionAcquiredEvent m_connAcquiredEvent; + + AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 }; + HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index 74bdcd5cf0..1e7649f561 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -14,14 +14,14 @@ #include #include #include -#include -#include #include #include -#include #include #include +#include #include +#include +#include #include #include #include @@ -93,10 +93,10 @@ namespace Multiplayer } } - void EntityReplicationManager::SendUpdates(AZ::TimeMs serverGameTimeMs) + void EntityReplicationManager::SendUpdates(AZ::TimeMs hostTimeMs) { m_frameTimeMs = AZ::GetElapsedTimeMs(); - SendEntityUpdates(serverGameTimeMs); + SendEntityUpdates(hostTimeMs); SendEntityRpcs(m_deferredRpcMessagesReliable, true); SendEntityRpcs(m_deferredRpcMessagesUnreliable, false); @@ -118,7 +118,7 @@ namespace Multiplayer void EntityReplicationManager::SendEntityUpdatesPacketHelper ( - AZ::TimeMs serverGameTimeMs, + AZ::TimeMs hostTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection @@ -127,7 +127,8 @@ namespace Multiplayer uint32_t pendingPacketSize = 0; EntityReplicatorList replicatorUpdatedList; MultiplayerPackets::EntityUpdates entityUpdatePacket; - entityUpdatePacket.SetHostTimeMs(serverGameTimeMs); + entityUpdatePacket.SetHostTimeMs(hostTimeMs); + entityUpdatePacket.SetHostFrameId(InvalidHostFrameId); // Serialize everything while (!toSendList.empty()) { @@ -249,7 +250,7 @@ namespace Multiplayer return toSendList; } - void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs serverGameTimeMs) + void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs hostTimeMs) { EntityReplicatorList toSendList = GenerateEntityUpdateList(); @@ -264,7 +265,7 @@ namespace Multiplayer // While our to send list is not empty, build up another packet to send do { - SendEntityUpdatesPacketHelper(serverGameTimeMs, toSendList, m_maxPayloadSize, m_connection); + SendEntityUpdatesPacketHelper(hostTimeMs, toSendList, m_maxPayloadSize, m_connection); } while (!toSendList.empty()); } @@ -747,7 +748,7 @@ namespace Multiplayer bool EntityReplicationManager::HandleEntityUpdateMessage ( - [[maybe_unused]] AzNetworking::IConnection* connection, + [[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage ) @@ -803,7 +804,7 @@ namespace Multiplayer return handled; } - bool EntityReplicationManager::HandleEntityRpcMessage([[maybe_unused]] AzNetworking::IConnection* connection, NetworkEntityRpcMessage& message) + bool EntityReplicationManager::HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message) { EntityReplicator* entityReplicator = GetEntityReplicator(message.GetEntityId()); const bool isReplicatorValid = (entityReplicator != nullptr) && !entityReplicator->IsMarkedForRemoval(); @@ -815,7 +816,7 @@ namespace Multiplayer } else { - return entityReplicator->HandleRpcMessage(message); + return entityReplicator->HandleRpcMessage(invokingConnection, message); } } @@ -833,8 +834,7 @@ namespace Multiplayer ); return false; } - - return entityReplicator->HandleRpcMessage(message); + return entityReplicator->HandleRpcMessage(nullptr, message); } AZ::TimeMs EntityReplicationManager::GetResendTimeoutTimeMs() const @@ -877,7 +877,6 @@ namespace Multiplayer AzNetworking::TimeoutResult EntityReplicationManager::OrphanedEntityRpcs::HandleTimeout(AzNetworking::TimeoutQueue::TimeoutItem& item) { NetEntityId timedOutEntityId = aznumeric_cast(item.m_userData); - auto entityRpcsIter = m_entityRpcMap.find(timedOutEntityId); if (entityRpcsIter != m_entityRpcMap.end()) { @@ -887,7 +886,6 @@ namespace Multiplayer } m_entityRpcMap.erase(entityRpcsIter); } - return AzNetworking::TimeoutResult::Delete; } @@ -1089,7 +1087,7 @@ namespace Multiplayer if (m_updateMode == EntityReplicationManager::Mode::LocalServerToRemoteServer) { - netBindComponent->NotifyMigration(GetRemoteHostId(), GetConnection().GetConnectionId()); + netBindComponent->NotifyServerMigration(GetRemoteHostId(), GetConnection().GetConnectionId()); } bool didSucceed = true; @@ -1127,7 +1125,7 @@ namespace Multiplayer } } - bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* connection, MultiplayerPackets::EntityMigration& message) + bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message) { EntityReplicator* replicator = GetEntityReplicator(message.GetEntityId()); { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h index a6470e6c34..4fc14e210f 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h @@ -13,11 +13,11 @@ #pragma once #include -#include -#include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -59,7 +59,7 @@ namespace Multiplayer HostId GetRemoteHostId() const; void ActivatePendingEntities(); - void SendUpdates(AZ::TimeMs serverGameTimeMs); + void SendUpdates(AZ::TimeMs hostTimeMs); void Clear(bool forMigration); bool SetEntityRebasing(NetworkEntityHandle& entityHandle); @@ -82,10 +82,10 @@ namespace Multiplayer void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event::Handler& handler); - bool HandleMessage(AzNetworking::IConnection* connection, MultiplayerPackets::EntityMigration& message); + bool HandleMessage(AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message); bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); - bool HandleEntityUpdateMessage(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); - bool HandleEntityRpcMessage(AzNetworking::IConnection* connection, NetworkEntityRpcMessage& message); + bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); + bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message); AZ::TimeMs GetResendTimeoutTimeMs() const; @@ -118,9 +118,9 @@ namespace Multiplayer using EntityReplicatorList = AZStd::deque; EntityReplicatorList GenerateEntityUpdateList(); - void SendEntityUpdatesPacketHelper(AZ::TimeMs serverGameTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection); + void SendEntityUpdatesPacketHelper(AZ::TimeMs hostTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection); - void SendEntityUpdates(AZ::TimeMs serverGameTimeMs); + void SendEntityUpdates(AZ::TimeMs hostTimeMs); void SendEntityRpcs(RpcMessages& deferredRpcs, bool reliable); void MigrateEntityInternal(NetEntityId entityId); @@ -155,31 +155,27 @@ namespace Multiplayer OrphanedEntityRpcs(EntityReplicationManager& replicationManager); void Update(); bool DispatchOrphanedRpcs(EntityReplicator& entityReplicator); - void AddOrphanedRpc(NetEntityId entityId, NetworkEntityRpcMessage& entityPrcMessage); + void AddOrphanedRpc(NetEntityId entityId, NetworkEntityRpcMessage& entityRpcMessage); AZStd::size_t Size() const { return m_entityRpcMap.size(); } private: AzNetworking::TimeoutResult HandleTimeout(AzNetworking::TimeoutQueue::TimeoutItem& item) override; - struct OrphanedRpcs { OrphanedRpcs() = default; OrphanedRpcs(OrphanedRpcs&& rhs) { + m_rpcMessages.swap(rhs.m_rpcMessages); m_timeoutId = rhs.m_timeoutId; rhs.m_timeoutId = AzNetworking::TimeoutId{ 0 }; - m_rpcMessages.swap(rhs.m_rpcMessages); } - - AzNetworking::TimeoutId m_timeoutId = AzNetworking::TimeoutId{ 0 }; RpcMessages m_rpcMessages; + AzNetworking::TimeoutId m_timeoutId = AzNetworking::TimeoutId{ 0 }; }; - typedef AZStd::unordered_map EntityRpcMap; EntityRpcMap m_entityRpcMap; AzNetworking::TimeoutQueue m_timeoutQueue; EntityReplicationManager& m_replicationManager; }; - OrphanedEntityRpcs m_orphanedEntityRpcs; EntityReplicatorMap m_entityReplicatorMap; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index b645101677..7431b95a22 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -628,7 +628,7 @@ namespace Multiplayer return result; } - bool EntityReplicator::HandleRpcMessage(NetworkEntityRpcMessage& entityRpcMessage) + bool EntityReplicator::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage) { // Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics MultiplayerStats& stats = AZ::Interface::Get()->GetStats(); @@ -676,7 +676,7 @@ namespace Multiplayer switch (result) { case RpcValidationResult::HandleRpc: - return m_netBindComponent->HandleRpcMessage(GetRemoteNetworkRole(), entityRpcMessage); + return m_netBindComponent->HandleRpcMessage(invokingConnection, GetRemoteNetworkRole(), entityRpcMessage); case RpcValidationResult::DropRpc: return true; case RpcValidationResult::DropRpcAndDisconnect: @@ -703,7 +703,7 @@ namespace Multiplayer break; } - AZ_Assert(false, "Unhandled ERpcValidationResult %d", result); + AZ_Assert(false, "Unhandled RpcValidationResult %d", result); return false; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h index 66274f638e..93494ab07c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h @@ -75,8 +75,8 @@ namespace Multiplayer const PropertyPublisher* GetPropertyPublisher() const; PropertySubscriber* GetPropertySubscriber(); - // Handlers for messages - bool HandleRpcMessage(NetworkEntityRpcMessage& entityRpcMessage); + // Handlers for Rpc messages + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage); //! AZ::EntityBus overrides //! @{ diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h b/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h deleted file mode 100644 index 24e43de66a..0000000000 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -namespace Multiplayer -{ - //! @class INetworkEntityDomain - //! @brief A class that determines if an entity should belong to a particular EntityManager. - class INetworkEntityDomain - { - public: - using EntitiesNotInDomain = AZStd::unordered_set; - - virtual ~INetworkEntityDomain() = default; - - //! Enable Entity Domain Exit Tracking for entities on the server. - //! @param ownedEntitySet - virtual void ActivateTracking(const INetworkEntityManager::OwnedEntitySet& ownedEntitySet) = 0; - - //! Return the set of entities not in this domain. - //! @param outEntitiesNotInDomain - virtual void RetrieveEntitiesNotInDomain(EntitiesNotInDomain& outEntitiesNotInDomain) const = 0; - - //! Returns whether or not an entity should be owned by an entity manager. - //! @param entityHandle the handle of the entity to check for inclusion in the domain - //! @return false if this entity should not belong to the entity manger, true if it could be owned by the entity manager - virtual bool IsInDomain(const ConstNetworkEntityHandle& entityHandle) const = 0; - }; -} diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp index a37d444046..797d67e3ef 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp index 650b113186..ca0275d20b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index ce55f66caa..1c7fb5f7af 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -218,7 +218,7 @@ namespace Multiplayer { NetBindComponent* netBindComponent = entity->FindComponent(); AZ_Assert(netBindComponent != nullptr, "Attempting to send an RPC to an entity with no NetBindComponent"); - netBindComponent->HandleRpcMessage(NetEntityRole::Server, rpcMessage); + netBindComponent->HandleRpcMessage(nullptr, NetEntityRole::Server, rpcMessage); } } m_localDeferredRpcMessages.clear(); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index 4439503373..ae2cb0dd9e 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -15,11 +15,11 @@ #include #include #include -#include #include #include #include -#include +#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp index 4ced19f8d9..69f715317a 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h index ffc150e5cc..4cfb242154 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp index a02bc4209d..0ab1d5ffcc 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp @@ -48,19 +48,34 @@ namespace Multiplayer return m_inputId; } - void NetworkInput::SetServerTimeMs(AZ::TimeMs serverTimeMs) + void NetworkInput::SetHostFrameId(HostFrameId hostFrameId) { - m_serverTimeMs = serverTimeMs; + m_hostFrameId = hostFrameId; } - AZ::TimeMs NetworkInput::GetServerTimeMs() const + HostFrameId NetworkInput::GetHostFrameId() const { - return m_serverTimeMs; + return m_hostFrameId; } - AZ::TimeMs& NetworkInput::ModifyServerTimeMs() + HostFrameId& NetworkInput::ModifyHostFrameId() { - return m_serverTimeMs; + return m_hostFrameId; + } + + void NetworkInput::SetHostTimeMs(AZ::TimeMs hostTimeMs) + { + m_hostTimeMs = hostTimeMs; + } + + AZ::TimeMs NetworkInput::GetHostTimeMs() const + { + return m_hostTimeMs; + } + + AZ::TimeMs& NetworkInput::ModifyHostTimeMs() + { + return m_hostTimeMs; } void NetworkInput::AttachNetBindComponent(NetBindComponent* netBindComponent) @@ -76,17 +91,19 @@ namespace Multiplayer bool NetworkInput::Serialize(AzNetworking::ISerializer& serializer) { - if (!serializer.Serialize(m_inputId, "InputId")) + if (!serializer.Serialize(m_inputId, "InputId") + || !serializer.Serialize(m_hostTimeMs, "HostTimeMs") + || !serializer.Serialize(m_hostFrameId, "HostFrameId")) { return false; } - uint8_t componentInputCount = static_cast(m_componentInputs.size()); + uint16_t componentInputCount = static_cast(m_componentInputs.size()); serializer.Serialize(componentInputCount, "ComponentInputCount"); m_componentInputs.resize(componentInputCount); if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) { - for (uint8_t i = 0; i < componentInputCount; ++i) + for (uint16_t i = 0; i < componentInputCount; ++i) { // We need to do a little extra work here, the delta serializer won't actually write out values if they were the same as the parent. // We need to make sure we don't lose state that is intrinsic to the underlying type @@ -148,7 +165,7 @@ namespace Multiplayer void NetworkInput::CopyInternal(const NetworkInput& rhs) { m_inputId = rhs.m_inputId; - m_serverTimeMs = rhs.m_serverTimeMs; + m_hostTimeMs = rhs.m_hostTimeMs; m_componentInputs.resize(rhs.m_componentInputs.size()); for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i) { diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h index 43768c4196..b2b0fa12c6 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h @@ -12,8 +12,9 @@ #pragma once -#include -#include +#include +#include +#include #include namespace Multiplayer @@ -21,8 +22,6 @@ namespace Multiplayer // Forwards class NetBindComponent; - AZ_TYPE_SAFE_INTEGRAL(ClientInputId, uint16_t); - //! @class NetworkInput //! @brief A single networked client input command. class NetworkInput final @@ -30,8 +29,8 @@ namespace Multiplayer public: //! Intentionally restrict instancing of these objects to associated containers classes only //! This is a mechanism used to restrict calling autonomous client predicted setter functions to the ProcessInput call chain only - friend class NetworkInputVector; - friend class MigrateNetworkInputVector; + friend class NetworkInputArray; + friend class NetworkInputMigrationVector; friend class NetworkInputHistory; friend class NetworkInputChild; @@ -42,9 +41,13 @@ namespace Multiplayer ClientInputId GetClientInputId() const; ClientInputId& ModifyClientInputId(); - void SetServerTimeMs(AZ::TimeMs serverTimeMs); - AZ::TimeMs GetServerTimeMs() const; - AZ::TimeMs& ModifyServerTimeMs(); + void SetHostFrameId(HostFrameId hostFrameId); + HostFrameId GetHostFrameId() const; + HostFrameId& ModifyHostFrameId(); + + void SetHostTimeMs(AZ::TimeMs hostTimeMs); + AZ::TimeMs GetHostTimeMs() const; + AZ::TimeMs& ModifyHostTimeMs(); void AttachNetBindComponent(NetBindComponent* netBindComponent); @@ -72,10 +75,9 @@ namespace Multiplayer MultiplayerComponentInputVector m_componentInputs; ClientInputId m_inputId = ClientInputId{ 0 }; - AZ::TimeMs m_serverTimeMs = AZ::TimeMs{ 0 }; + HostFrameId m_hostFrameId = InvalidHostFrameId; + AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; ConstNetworkEntityHandle m_owner; bool m_wasAttached = false; }; } - -AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ClientInputId); diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp similarity index 53% rename from Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp rename to Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp index 466a112e12..0f5a0d7c0c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp @@ -10,21 +10,21 @@ * */ -#include -#include +#include +#include #include #include namespace Multiplayer { - NetworkInputVector::NetworkInputVector() + NetworkInputArray::NetworkInputArray() : m_owner() , m_inputs() { ; } - NetworkInputVector::NetworkInputVector(const ConstNetworkEntityHandle& entityHandle) + NetworkInputArray::NetworkInputArray(const ConstNetworkEntityHandle& entityHandle) : m_owner(entityHandle) , m_inputs() { @@ -38,27 +38,27 @@ namespace Multiplayer } } - NetworkInput& NetworkInputVector::operator[](uint32_t index) + NetworkInput& NetworkInputArray::operator[](uint32_t index) { return m_inputs[index].m_networkInput; } - const NetworkInput& NetworkInputVector::operator[](uint32_t index) const + const NetworkInput& NetworkInputArray::operator[](uint32_t index) const { return m_inputs[index].m_networkInput; } - void NetworkInputVector::SetPreviousInputId(ClientInputId previousInputId) + void NetworkInputArray::SetPreviousInputId(ClientInputId previousInputId) { m_previousInputId = previousInputId; } - ClientInputId NetworkInputVector::GetPreviousInputId() const + ClientInputId NetworkInputArray::GetPreviousInputId() const { return m_previousInputId; } - bool NetworkInputVector::Serialize(AzNetworking::ISerializer& serializer) + bool NetworkInputArray::Serialize(AzNetworking::ISerializer& serializer) { // Always serialize the full first element if (!m_inputs[0].m_networkInput.Serialize(serializer)) @@ -105,67 +105,4 @@ namespace Multiplayer serializer.Serialize(m_previousInputId, "PreviousInputId"); return true; } - - - MigrateNetworkInputVector::MigrateNetworkInputVector() - : m_owner() - { - ; - } - - MigrateNetworkInputVector::MigrateNetworkInputVector(const ConstNetworkEntityHandle& entityHandle) - : m_owner(entityHandle) - { - ; - } - - uint32_t MigrateNetworkInputVector::GetSize() const - { - return aznumeric_cast(m_inputs.size()); - } - - NetworkInput& MigrateNetworkInputVector::operator[](uint32_t index) - { - return m_inputs[index].m_networkInput; - } - - const NetworkInput& MigrateNetworkInputVector::operator[](uint32_t index) const - { - return m_inputs[index].m_networkInput; - } - - bool MigrateNetworkInputVector::PushBack(const NetworkInput& networkInput) - { - if (m_inputs.size() < m_inputs.capacity()) - { - m_inputs.push_back(networkInput); - return true; - } - return false; - } - - bool MigrateNetworkInputVector::Serialize(AzNetworking::ISerializer& serializer) - { - NetEntityId ownerId = m_owner.GetNetEntityId(); - serializer.Serialize(ownerId, "OwnerId"); - - uint32_t inputCount = aznumeric_cast(m_inputs.size()); - serializer.Serialize(inputCount, "InputCount"); - - if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) - { - // make sure all the possible NetworkInputs get attached prior to serialization, this double sends the size, but this message is only sent on server migration - m_inputs.resize(inputCount); - m_owner = GetNetworkEntityManager()->GetEntity(ownerId); - NetBindComponent* netBindComponent = m_owner.GetNetBindComponent(); - if (netBindComponent) - { - for (uint32_t i = 0; i < m_inputs.size(); ++i) - { - m_inputs[i].m_networkInput.AttachNetBindComponent(netBindComponent); - } - } - } - return serializer.Serialize(m_inputs, "Inputs"); - } } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h new file mode 100644 index 0000000000..504992fecb --- /dev/null +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h @@ -0,0 +1,54 @@ +/* +* 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 +#include +#include +#include + +namespace Multiplayer +{ + //! @class NetworkInputArray + //! @brief An array of network inputs. Used to mitigate loss of input packets on the server. Compresses subsequent elements. + class NetworkInputArray final + { + public: + static constexpr uint32_t MaxElements = 8; // Never try to replicate a list larger than this amount + + NetworkInputArray(); + NetworkInputArray(const ConstNetworkEntityHandle& entityHandle); + ~NetworkInputArray() = default; + + NetworkInput& operator[](uint32_t index); + const NetworkInput& operator[](uint32_t index) const; + + void SetPreviousInputId(ClientInputId previousInputId); + ClientInputId GetPreviousInputId() const; + + bool Serialize(AzNetworking::ISerializer& serializer); + + private: + + struct Wrapper // Strictly a workaround to deal with the private constructor of NetworkInput + { + Wrapper() : m_networkInput() {} + Wrapper(const NetworkInput& networkInput) : m_networkInput(networkInput) {} + NetworkInput m_networkInput; + }; + + ConstNetworkEntityHandle m_owner; + AZStd::array m_inputs; + ClientInputId m_previousInputId; + }; +} diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp index bb5f9a488d..8f70f7e1fa 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp new file mode 100644 index 0000000000..dee72156ed --- /dev/null +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp @@ -0,0 +1,80 @@ +/* +* 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 +#include +#include + +namespace Multiplayer +{ + NetworkInputMigrationVector::NetworkInputMigrationVector() + : m_owner() + { + ; + } + + NetworkInputMigrationVector::NetworkInputMigrationVector(const ConstNetworkEntityHandle& entityHandle) + : m_owner(entityHandle) + { + ; + } + + uint32_t NetworkInputMigrationVector::GetSize() const + { + return aznumeric_cast(m_inputs.size()); + } + + NetworkInput& NetworkInputMigrationVector::operator[](uint32_t index) + { + return m_inputs[index].m_networkInput; + } + + const NetworkInput& NetworkInputMigrationVector::operator[](uint32_t index) const + { + return m_inputs[index].m_networkInput; + } + + bool NetworkInputMigrationVector::PushBack(const NetworkInput& networkInput) + { + if (m_inputs.size() < m_inputs.capacity()) + { + m_inputs.push_back(networkInput); + return true; + } + return false; + } + + bool NetworkInputMigrationVector::Serialize(AzNetworking::ISerializer& serializer) + { + NetEntityId ownerId = m_owner.GetNetEntityId(); + serializer.Serialize(ownerId, "OwnerId"); + + uint32_t inputCount = aznumeric_cast(m_inputs.size()); + serializer.Serialize(inputCount, "InputCount"); + + if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) + { + // make sure all the possible NetworkInputs get attached prior to serialization, this double sends the size, but this message is only sent on server migration + m_inputs.resize(inputCount); + m_owner = GetNetworkEntityManager()->GetEntity(ownerId); + NetBindComponent* netBindComponent = m_owner.GetNetBindComponent(); + if (netBindComponent) + { + for (uint32_t i = 0; i < m_inputs.size(); ++i) + { + m_inputs[i].m_networkInput.AttachNetBindComponent(netBindComponent); + } + } + } + return serializer.Serialize(m_inputs, "Inputs"); + } +} diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h similarity index 53% rename from Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h rename to Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h index be41495577..c6ea425fec 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h @@ -13,54 +13,22 @@ #pragma once #include -#include +#include +#include #include namespace Multiplayer { - //! @class NetworkInputVector - //! @brief An array of network inputs. Used to mitigate loss of input packets on the server. Compresses subsequent elements. - class NetworkInputVector final - { - public: - static constexpr uint32_t MaxElements = 8; // Never try to replicate a list larger than this amount - - NetworkInputVector(); - NetworkInputVector(const ConstNetworkEntityHandle& entityHandle); - ~NetworkInputVector() = default; - - NetworkInput& operator[](uint32_t index); - const NetworkInput& operator[](uint32_t index) const; - - void SetPreviousInputId(ClientInputId previousInputId); - ClientInputId GetPreviousInputId() const; - - bool Serialize(AzNetworking::ISerializer& serializer); - - private: - - struct Wrapper // Strictly a workaround to deal with the private constructor of NetworkInput - { - Wrapper() : m_networkInput() {} - Wrapper(const NetworkInput& networkInput) : m_networkInput(networkInput) {} - NetworkInput m_networkInput; - }; - - ConstNetworkEntityHandle m_owner; - AZStd::fixed_vector m_inputs; - ClientInputId m_previousInputId; - }; - - //! @class MigrateNetworkInputVector + //! @class NetworkInputMigrationVector //! @brief A variable sized array of input commands, used specifically when migrate a clients inputs. - class MigrateNetworkInputVector final + class NetworkInputMigrationVector final { public: static constexpr uint32_t MaxElements = 90; // Never try to migrate a list larger than this amount, bumped up to handle DTLS connection time - MigrateNetworkInputVector(); - MigrateNetworkInputVector(const ConstNetworkEntityHandle& entityHandle); - virtual ~MigrateNetworkInputVector() = default; + NetworkInputMigrationVector(); + NetworkInputMigrationVector(const ConstNetworkEntityHandle& entityHandle); + virtual ~NetworkInputMigrationVector() = default; uint32_t GetSize() const; NetworkInput& operator[](uint32_t index); diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp index b062569dce..9a0e784d36 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp @@ -24,36 +24,31 @@ namespace Multiplayer AZ::Interface::Unregister(this); } - AZ::TimeMs NetworkTime::ConvertFrameIdToTimeMs([[maybe_unused]] ApplicationFrameId frameId) const - { - return AZ::TimeMs{0}; - } - - ApplicationFrameId NetworkTime::ConvertTimeMsToFrameId([[maybe_unused]] AZ::TimeMs timeMs) const - { - return ApplicationFrameId{0}; - } - - bool NetworkTime::IsApplicationFrameIdRewound() const + bool NetworkTime::IsTimeRewound() const { return m_rewindingConnectionId != AzNetworking::InvalidConnectionId; } - ApplicationFrameId NetworkTime::GetApplicationFrameId() const + HostFrameId NetworkTime::GetHostFrameId() const { - return m_applicationFrameId; + return m_hostFrameId; } - ApplicationFrameId NetworkTime::GetUnalteredApplicationFrameId() const + HostFrameId NetworkTime::GetUnalteredHostFrameId() const { return m_unalteredFrameId; } - void NetworkTime::IncrementApplicationFrameId() + void NetworkTime::IncrementHostFrameId() { - AZ_Assert(!IsApplicationFrameIdRewound(), "Incrementing the global application frameId is unsupported under a rewound time scope"); + AZ_Assert(!IsTimeRewound(), "Incrementing the global application frameId is unsupported under a rewound time scope"); ++m_unalteredFrameId; - m_applicationFrameId = m_unalteredFrameId; + m_hostFrameId = m_unalteredFrameId; + } + + AZ::TimeMs NetworkTime::GetHostTimeMs() const + { + return m_hostTimeMs; } void NetworkTime::SyncRewindableEntityState() @@ -66,14 +61,15 @@ namespace Multiplayer return m_rewindingConnectionId; } - ApplicationFrameId NetworkTime::GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const + HostFrameId NetworkTime::GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const { - return (IsApplicationFrameIdRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_applicationFrameId; + return (IsTimeRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_hostFrameId; } - void NetworkTime::AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) + void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) { - m_applicationFrameId = frameId; + m_hostFrameId = frameId; + m_hostTimeMs = timeMs; m_rewindingConnectionId = rewindConnectionId; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h index 55ccb45e69..06e758b349 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include @@ -28,22 +28,22 @@ namespace Multiplayer //! INetworkTime overrides. //! @{ - AZ::TimeMs ConvertFrameIdToTimeMs(ApplicationFrameId frameId) const override; - ApplicationFrameId ConvertTimeMsToFrameId(AZ::TimeMs timeMs) const override; - bool IsApplicationFrameIdRewound() const override; - ApplicationFrameId GetApplicationFrameId() const override; - ApplicationFrameId GetUnalteredApplicationFrameId() const override; - void IncrementApplicationFrameId() override; + bool IsTimeRewound() const override; + HostFrameId GetHostFrameId() const override; + HostFrameId GetUnalteredHostFrameId() const override; + void IncrementHostFrameId() override; + AZ::TimeMs GetHostTimeMs() const override; void SyncRewindableEntityState() override; AzNetworking::ConnectionId GetRewindingConnectionId() const override; - ApplicationFrameId GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; - void AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) override; + HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; + void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override; //! @} private: - ApplicationFrameId m_applicationFrameId = ApplicationFrameId{0}; - ApplicationFrameId m_unalteredFrameId = ApplicationFrameId{0}; + HostFrameId m_hostFrameId = HostFrameId{ 0 }; + HostFrameId m_unalteredFrameId = HostFrameId{ 0 }; + AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; AzNetworking::ConnectionId m_rewindingConnectionId = AzNetworking::InvalidConnectionId; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h index cdea98dc07..4e830d4480 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include #include @@ -87,25 +87,25 @@ namespace Multiplayer //! Returns what the appropriate current time is for this rewindable property. //! @return the appropriate current time is for this rewindable property - ApplicationFrameId GetCurrentTimeForProperty() const; + HostFrameId GetCurrentTimeForProperty() const; //! Updates the latest value for this object instance, if frameTime represents a current or future time. //! Any attempts to set old values on the object will fail //! @param value the new value to set in the object history //! @param frameTime the time to set the value for - void SetValueForTime(const BASE_TYPE& value, ApplicationFrameId frameTime); + void SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime); //! Const value accessor, returns the correct value for the provided input time. //! @param frameTime the frame time to return the associated value for //! @return value given the current input time - const BASE_TYPE& GetValueForTime(ApplicationFrameId frameTime) const; + const BASE_TYPE& GetValueForTime(HostFrameId frameTime) const; //! Helper method to compute clamped array index values accounting for the offset head index. AZStd::size_t GetOffsetIndex(AZStd::size_t absoluteIndex) const; AZStd::array m_history; AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId; - ApplicationFrameId m_headTime = ApplicationFrameId{0}; + HostFrameId m_headTime = HostFrameId{0}; uint32_t m_headIndex = 0; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl index 69752210bb..0835421ebd 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl +++ b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl @@ -48,7 +48,7 @@ namespace Multiplayer inline RewindableObject &RewindableObject::operator =(const RewindableObject& rhs) { INetworkTime* networkTime = AZ::Interface::Get(); - SetValueForTime(rhs.GetValueForTime(networkTime->GetApplicationFrameId()), GetCurrentTimeForProperty()); + SetValueForTime(rhs.GetValueForTime(networkTime->GetHostFrameId()), GetCurrentTimeForProperty()); return *this; } @@ -73,7 +73,7 @@ namespace Multiplayer template inline BASE_TYPE& RewindableObject::Modify() { - const ApplicationFrameId frameTime = GetCurrentTimeForProperty(); + const HostFrameId frameTime = GetCurrentTimeForProperty(); if (frameTime < m_headTime) { AZ_Assert(false, "Trying to mutate a rewindable in the past"); @@ -103,7 +103,7 @@ namespace Multiplayer template inline bool RewindableObject::Serialize(AzNetworking::ISerializer& serializer) { - const ApplicationFrameId frameTime = GetCurrentTimeForProperty(); + const HostFrameId frameTime = GetCurrentTimeForProperty(); BASE_TYPE value = GetValueForTime(frameTime); if (serializer.Serialize(value, "Element") && (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject)) { @@ -113,14 +113,14 @@ namespace Multiplayer } template - inline ApplicationFrameId RewindableObject::GetCurrentTimeForProperty() const + inline HostFrameId RewindableObject::GetCurrentTimeForProperty() const { INetworkTime* networkTime = AZ::Interface::Get(); - return networkTime->GetApplicationFrameIdForRewindingConnection(m_owningConnectionId); + return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId); } template - inline void RewindableObject::SetValueForTime(const BASE_TYPE& value, ApplicationFrameId frameTime) + inline void RewindableObject::SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime) { if (frameTime < m_headTime) { @@ -155,7 +155,7 @@ namespace Multiplayer } template - inline const BASE_TYPE &RewindableObject::GetValueForTime(ApplicationFrameId frameTime) const + inline const BASE_TYPE &RewindableObject::GetValueForTime(HostFrameId frameTime) const { if (frameTime > m_headTime) { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp index 698376dccf..726c75ad86 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp @@ -10,7 +10,7 @@ * */ -#include "NullReplicationWindow.h" +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h index 76562a34e2..1922e65941 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index f6aa6b2de9..c54a610de2 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -56,6 +56,8 @@ namespace Multiplayer ServerToClientReplicationWindow::ServerToClientReplicationWindow(NetworkEntityHandle controlledEntity, const AzNetworking::IConnection* connection) : m_controlledEntity(controlledEntity) + , m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); }) + , m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); }) , m_connection(connection) , m_lastCheckedSentPackets(connection->GetMetrics().m_packetsSent) , m_lastCheckedLostPackets(connection->GetMetrics().m_packetsLost) @@ -74,7 +76,9 @@ namespace Multiplayer //} m_updateWindowEvent.Enqueue(sv_ClientReplicationWindowUpdateMs, true); - AZ::EntitySystemBus::Handler::BusConnect(); + + AZ::Interface::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler); + AZ::Interface::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler); } bool ServerToClientReplicationWindow::ReplicationSetUpdateReady() @@ -146,24 +150,29 @@ namespace Multiplayer } ); + NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker(); + // Add all the neighbors for (AzFramework::VisibilityEntry* visEntry : gatheredEntries) { - // TODO: Discard entities that don't have a NetBindComponent - //if (mp_ControlledFilteredEntityComponent && mp_ControlledFilteredEntityComponent->IsEntityFiltered(iterator.Get())) //{ // continue; //} // We want to find the closest extent to the player and prioritize using that distance - const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter(); - const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal); - const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition); - const float priority = (gatherDistanceSquared > 0.0f) ? 1.0f / gatherDistanceSquared : 0.0f; AZ::Entity* entity = static_cast(visEntry->m_userData); - NetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); - AddEntityToReplicationSet(entityHandle, priority, gatherDistanceSquared); + NetBindComponent* entryNetBindComponent = entity->template FindComponent(); + if (entryNetBindComponent != nullptr) + { + const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter(); + const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal); + const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition); + const float priority = (gatherDistanceSquared > 0.0f) ? 1.0f / gatherDistanceSquared : 0.0f; + + NetworkEntityHandle entityHandle(entryNetBindComponent, networkEntityTracker); + AddEntityToReplicationSet(entityHandle, priority, gatherDistanceSquared); + } } // Add in Autonomous Entities @@ -200,10 +209,8 @@ namespace Multiplayer //} } - void ServerToClientReplicationWindow::OnEntityActivated(const AZ::EntityId& entityId) + void ServerToClientReplicationWindow::OnEntityActivated(AZ::Entity* entity) { - AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - ConstNetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent(); if (netBindComponent != nullptr) @@ -231,10 +238,8 @@ namespace Multiplayer } } - void ServerToClientReplicationWindow::OnEntityDeactivated(const AZ::EntityId& entityId) + void ServerToClientReplicationWindow::OnEntityDeactivated(AZ::Entity* entity) { - AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - ConstNetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent(); if (netBindComponent != nullptr) diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index 4dad4bd01f..55a6a4b56e 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -12,9 +12,9 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include #include @@ -27,7 +27,6 @@ namespace Multiplayer class ServerToClientReplicationWindow : public IReplicationWindow - , public AZ::EntitySystemBus::Handler { public: @@ -56,11 +55,8 @@ namespace Multiplayer //! @} private: - //! EntitySystemBus interface - //! @{ - void OnEntityActivated(const AZ::EntityId&) override; - void OnEntityDeactivated(const AZ::EntityId&) override; - //! @} + void OnEntityActivated(AZ::Entity* entity); + void OnEntityDeactivated(AZ::Entity* entity); //void CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController); //void OnAddFilteredEntity(NetEntityId filteredEntityId); @@ -79,6 +75,9 @@ namespace Multiplayer NetworkEntityHandle m_controlledEntity; AZ::TransformInterface* m_controlledEntityTransform = nullptr; + AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler; + AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler; + //FilteredEntityComponent::Authority* m_controlledFilteredEntityComponent = nullptr; //NetBindComponent* m_controlledNetBindComponent = nullptr; diff --git a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp index d2d41723eb..367b7ee0de 100644 --- a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp +++ b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp @@ -37,12 +37,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 0; i < 16; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } @@ -50,12 +50,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 16; i < 48; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } } @@ -68,12 +68,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } { // Note that we didn't actually set any value for time rewindableBufferFrames, so we're testing fetching a value past the last time set - Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(RewindableBufferFrames - 1, test); } } @@ -91,12 +91,12 @@ namespace UnitTest { Object& value = test.Modify(); value.value = i; - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 0; i < RewindableBufferFrames; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); const Object& value = test; EXPECT_EQ(value.value, i); } @@ -105,19 +105,19 @@ namespace UnitTest TEST_F(RewindableObjectTests, TestBackfillOnLargeTimestep) { Multiplayer::RewindableObject test(0); - Multiplayer::ScopedAlterTime time1(static_cast(0), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time1(static_cast(0), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); test = 1; - Multiplayer::ScopedAlterTime time2(static_cast(31), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time2(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); test = 2; for (uint32_t i = 0; i < 31; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(1, test); } - Multiplayer::ScopedAlterTime time3(static_cast(31), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time3(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(2, test); } @@ -127,13 +127,13 @@ namespace UnitTest for (uint32_t i = 0; i < 1000; ++i) { - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } test = 1000; for (uint32_t i = 0; i < 1000; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(1000, test); } } diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index f26e40355e..1f4e57ae43 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -10,10 +10,18 @@ # set(FILES + Include/IConnectionData.h + Include/IEntityDomain.h Include/IMultiplayer.h + Include/IMultiplayerComponentInput.h + Include/INetworkEntityManager.h + Include/INetworkTime.h + Include/IReplicationWindow.h Include/MultiplayerStats.cpp Include/MultiplayerStats.h Include/MultiplayerTypes.h + Include/NetworkEntityHandle.h + Include/NetworkEntityHandle.inl Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/MultiplayerSystemComponent.cpp @@ -41,13 +49,11 @@ set(FILES Source/ConnectionData/ClientToServerConnectionData.cpp Source/ConnectionData/ClientToServerConnectionData.h Source/ConnectionData/ClientToServerConnectionData.inl - Source/ConnectionData/IConnectionData.h Source/ConnectionData/ServerToClientConnectionData.cpp Source/ConnectionData/ServerToClientConnectionData.h Source/ConnectionData/ServerToClientConnectionData.inl Source/EntityDomains/FullOwnershipEntityDomain.cpp Source/EntityDomains/FullOwnershipEntityDomain.h - Source/EntityDomains/IEntityDomain.h Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp Source/NetworkEntity/EntityReplication/EntityReplicationManager.h Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -59,12 +65,9 @@ set(FILES Source/NetworkEntity/EntityReplication/PropertySubscriber.h Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp Source/NetworkEntity/EntityReplication/ReplicationRecord.h - Source/NetworkEntity/INetworkEntityManager.h Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp Source/NetworkEntity/NetworkEntityAuthorityTracker.h Source/NetworkEntity/NetworkEntityHandle.cpp - Source/NetworkEntity/NetworkEntityHandle.h - Source/NetworkEntity/NetworkEntityHandle.inl Source/NetworkEntity/NetworkEntityManager.cpp Source/NetworkEntity/NetworkEntityManager.h Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -76,16 +79,16 @@ set(FILES Source/NetworkEntity/NetworkEntityTracker.inl Source/NetworkEntity/NetworkEntityUpdateMessage.cpp Source/NetworkEntity/NetworkEntityUpdateMessage.h - Source/NetworkInput/IMultiplayerComponentInput.h Source/NetworkInput/NetworkInput.cpp Source/NetworkInput/NetworkInput.h + Source/NetworkInput/NetworkInputArray.cpp + Source/NetworkInput/NetworkInputArray.h Source/NetworkInput/NetworkInputChild.cpp Source/NetworkInput/NetworkInputChild.h Source/NetworkInput/NetworkInputHistory.cpp Source/NetworkInput/NetworkInputHistory.h - Source/NetworkInput/NetworkInputVector.cpp - Source/NetworkInput/NetworkInputVector.h - Source/NetworkTime/INetworkTime.h + Source/NetworkInput/NetworkInputMigrationVector.cpp + Source/NetworkInput/NetworkInputMigrationVector.h Source/NetworkTime/NetworkTime.cpp Source/NetworkTime/NetworkTime.h Source/NetworkTime/RewindableObject.h @@ -96,7 +99,6 @@ set(FILES Source/Pipeline/NetworkSpawnableHolderComponent.h Source/ReplicationWindows/NullReplicationWindow.cpp Source/ReplicationWindows/NullReplicationWindow.h - Source/ReplicationWindows/IReplicationWindow.h Source/ReplicationWindows/ServerToClientReplicationWindow.cpp Source/ReplicationWindows/ServerToClientReplicationWindow.h ) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index f0cea19645..9e061135fc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -582,7 +582,7 @@ namespace ScriptCanvas int SetExecutionOut(lua_State* lua) { // \note Return values could become necessary. - // \see https://jira.agscollab.com/browse/LY-99750 + // \see LY-99750 AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOut is not userdata (Nodeable)"); AZ_Assert(lua_isnumber(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOut is not a number"); @@ -605,7 +605,7 @@ namespace ScriptCanvas int SetExecutionOutResult(lua_State* lua) { // \note Return values could become necessary. - // \see https://jira.agscollab.com/browse/LY-99750 + // \see LY-99750 AZ_Assert(lua_isuserdata(lua, -3), "Error in compiled lua file, 1st argument to SetExecutionOutResult is not userdata (Nodeable)"); AZ_Assert(lua_isnumber(lua, -2), "Error in compiled lua file, 2nd argument to SetExecutionOutResult is not a number"); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 5e11b17c54..8dff6da9b1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -3114,7 +3114,7 @@ namespace ScriptCanvas /// NOTE: after basic iteration works correctly /// \todo when subsequent input (from nodes connected to the break slot) looks up the slot from the node with key or the value, /// it is going to have to find the output of the get/key value functions in BOTH the child outs of break and loop - /// https://jira.agscollab.com/browse/LY-109862 may be required for this + /// LY-109862 may be required for this ExecutionTreePtr lastExecution = forEachLoopBody; diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index ca7e2a3583..32437ae22a 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -82,6 +82,10 @@ protected: void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/TextureAtlas/Code/Source/TextureAtlasSystemComponent.cpp b/Gems/TextureAtlas/Code/Source/TextureAtlasSystemComponent.cpp index 1fe3e07e61..80d4898c41 100644 --- a/Gems/TextureAtlas/Code/Source/TextureAtlasSystemComponent.cpp +++ b/Gems/TextureAtlas/Code/Source/TextureAtlasSystemComponent.cpp @@ -98,14 +98,16 @@ namespace TextureAtlasNamespace SResourceAsync* pInfo = new SResourceAsync(); pInfo->eClassName = eRCN_Texture; pInfo->pResource = iterator->second.m_atlas->GetTexture(); - gEnv->pRenderer->ReleaseResourceAsync(pInfo); + // ToDo: Update to work with Atom? LYN-3680 + // ???->ReleaseResourceAsync(pInfo); } // Reload Texture AZStd::string imagePath = iterator->second.m_path.substr(0, iterator->second.m_path.find_last_of('.')); imagePath.append(".dds"); - uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM); - ITexture* texture = gEnv->pRenderer->EF_LoadTexture(imagePath.c_str(), loadTextureFlags); + // ToDo: Update to work with Atom? LYN-3680 + // uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM); + ITexture* texture = nullptr; if (!texture || !texture->IsTextureLoaded()) { @@ -189,8 +191,9 @@ namespace TextureAtlasNamespace AzFramework::StringFunc::Path::ReplaceExtension(imagePath, "dds"); // Load the image in - uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM); - ITexture* texture = gEnv->pRenderer->EF_LoadTexture(imagePath.c_str(), loadTextureFlags); + // ToDo: Update to work with Atom? LYN-3680 + // uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM); + ITexture* texture = nullptr; if (!texture || !texture->IsTextureLoaded()) { @@ -241,7 +244,8 @@ namespace TextureAtlasNamespace SResourceAsync* pInfo = new SResourceAsync(); pInfo->eClassName = eRCN_Texture; pInfo->pResource = temp.m_atlas->GetTexture(); - gEnv->pRenderer->ReleaseResourceAsync(pInfo); + // ToDo: Update to work with Atom? LYN-3680 + // ???->ReleaseResourceAsync(pInfo); } // Delete the atlas SAFE_DELETE(temp.m_atlas); diff --git a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp index ec8c929719..099bd2e90c 100644 --- a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp +++ b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp @@ -192,25 +192,8 @@ void DebugComponent::DrawGlobalDebugInfo() void DebugComponent::DrawInstanceDebug() { #if defined(VEG_PROFILE_ENABLED) - ISystem* crySystem = GetISystem(); - if (!crySystem) - { - return; - } - - IRenderer* renderer = crySystem->GetIRenderer(); - if (!renderer) - { - return; - } - - IRenderAuxGeom* renderAuxGeom = renderer->GetIRenderAuxGeom(); - if (!renderAuxGeom) - { - return; - } - - renderAuxGeom->SetRenderFlags(e_Mode3D | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOn); + // ToDo: Re-implement with Atom. LYN-3681 + /*renderAuxGeom->SetRenderFlags(e_Mode3D | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOn); AZStd::unordered_map areaDebugDisplayDataMap; @@ -241,7 +224,7 @@ void DebugComponent::DrawInstanceDebug() AABB bounds(pos - radius, pos + radius); renderAuxGeom->DrawAABB(bounds, true, ColorB(areaDebugDisplayData.m_instanceColor.ToU32()), eBBD_Faceted); - } + }*/ #endif } @@ -922,25 +905,8 @@ void DebugComponent::RemoveConsoleVariables() void DebugComponent::DrawDebugStats() { - ISystem* crySystem = GetISystem(); - if (!crySystem) - { - return; - } - - IRenderer* renderer = crySystem->GetIRenderer(); - if (!renderer) - { - return; - } - - IRenderAuxGeom* renderAuxGeom = renderer->GetIRenderAuxGeom(); - if (!renderAuxGeom) - { - return; - } - - if (!m_debugData) + // ToDo: Re-implement with Atom. LYN-3681 + /*if (!m_debugData) { return; } @@ -961,7 +927,7 @@ void DebugComponent::DrawDebugStats() destroyTaskCount, m_debugData->m_areaTaskQueueCount.load(AZStd::memory_order_relaxed), m_debugData->m_areaTaskActiveCount.load(AZStd::memory_order_relaxed) - ).c_str()); + ).c_str());*/ } void DebugComponent::AddConsoleVariables() diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index e88b4ce686..d4ab543404 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -414,8 +414,7 @@ namespace WhiteBox m_localAabb.reset(); m_faces.reset(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); // must have been created in Activate or have had the Entity made visible again if (m_renderMesh.has_value()) diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index 087a0f5d96..5f397db06b 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -188,9 +188,12 @@ "pattern": ".*\\\\/ArtSource\\\\/.*" }, //------------------------------------------------------------------------------ - // RC params mapping examples + // Copying Files Automatically Into the Cache //------------------------------------------------------------------------------ + // The below section is used to register patterns (*.something) to copy into the cache + // the "params" block must either be "copy" (copy the file) or "skip" (used for per-platfrom skipping) + // 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. @@ -198,88 +201,43 @@ // Use a regex for matching files, same params for all platforms // "RC TGAs": { // "pattern": ".+\\\\.tga$", - // "params": "/tga /texture" + // "params": "copy" //} - // Use a glob, have special params for es3 platform + // Example Use a glob instead of a regex, skip the copy for the "server" platform // "RC TIFFs": { // "glob": "*.tif", - // "params": "/texture", - // "es3": "/pvrt" + // "params": "copy", + // "server": "skip" //} // You can also modify a version to compile all matching files again // By default the version is empty // "RC tif": { // "glob": "*.tif", - // "params": "\\someparams", + // "params": "copy", // "version": 1.0 //} - // This will make the AssetProcessor compile all the .tif files again + // This will make the AssetProcessor compile all the .tif files again if version changes. // 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 - //} + // this is used to sort jobs when no other external circumstance sorts them (higher wins, default is 0) // 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 + //Example: copy everything EXCEPT the ones in the libs/ui // "RC png-normal": { // "pattern": "(?!.*libs\\\\/ui\\\\/).*\\.png", - // "params": "/imagecompressor=CTSquish /streaming=0", - // "lockSource": true + // "params": "copy" //} - //Example: Process everything in the libs/ui folder with linear color space + //Example: Process everything in the libs/ui folder // "RC png-ui": { // "pattern": "(.*libs\\\\/ui\\\\/).*\\.png", - // "params": "/imagecompressor=CTSquish /streaming=0 /colorspace=linear,linear", - // "lockSource": true + // "params": "copy" //} // More example Regexes: @@ -288,20 +246,8 @@ // "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}" - }, + // This is a JSON object - every entry must start with "RC" but make sure + // to give every entry its own unique Name or else they will overwrite each other: "RC mp4": { "glob": "*.mp4", "params": "copy", @@ -331,22 +277,6 @@ "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", @@ -357,43 +287,6 @@ "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}", @@ -411,11 +304,6 @@ "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" @@ -425,15 +313,6 @@ "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" diff --git a/Templates/DefaultGem/Template/CMakeLists.txt b/Templates/DefaultGem/Template/CMakeLists.txt index eaf5cdff3e..fb63008782 100644 --- a/Templates/DefaultGem/Template/CMakeLists.txt +++ b/Templates/DefaultGem/Template/CMakeLists.txt @@ -9,13 +9,18 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # {END_LICENSE} +set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_gem_json ${o3de_gem_path}/gem.json) +o3de_gem_name(${o3de_gem_json} o3de_gem_name) +o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) + # Currently we are in the DefaultProjectSource folder: ${CMAKE_CURRENT_LIST_DIR} # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here: DefaultProjectSource/Platform/ or # //DefaultProjectSource -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # project cmake for this platform. diff --git a/Templates/DefaultGem/Template/Code/CMakeLists.txt b/Templates/DefaultGem/Template/Code/CMakeLists.txt index 8510dc53d5..3511f8ff83 100644 --- a/Templates/DefaultGem/Template/Code/CMakeLists.txt +++ b/Templates/DefaultGem/Template/Code/CMakeLists.txt @@ -15,7 +15,7 @@ # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or # //Gems/${Name}/Code -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this gem diff --git a/Templates/DefaultGem/Template/gem.json b/Templates/DefaultGem/Template/gem.json index 0d233d0c50..5b8fb3fde0 100644 --- a/Templates/DefaultGem/Template/gem.json +++ b/Templates/DefaultGem/Template/gem.json @@ -4,7 +4,11 @@ "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", "display_name": "${Name}", "summary": "A short description of ${Name}.", - "canonical_tags": ["Gem"], - "user_tags": ["${Name}"], + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], "icon_path": "preview.png" } diff --git a/Templates/DefaultGem/template.json b/Templates/DefaultGem/template.json index 9b14a7af3a..22d4eb27e6 100644 --- a/Templates/DefaultGem/template.json +++ b/Templates/DefaultGem/template.json @@ -1,5 +1,7 @@ { "template_name": "DefaultGem", + "restricted": "o3de", + "restricted_platform_relative_path": "Templates", "origin": "The primary repo for DefaultGem goes here: i.e. http://www.mydomain.com", "license": "What license DefaultGem uses goes here: i.e. https://opensource.org/licenses/MIT", "display_name": "DefaultGem", @@ -270,6 +272,10 @@ } ], "createDirectories": [ + { + "dir": "Assets", + "origin": "Assets" + }, { "dir": "Code", "origin": "Code" @@ -339,4 +345,4 @@ "origin": "Platform/iOS" } ] -} \ No newline at end of file +} diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index c314f0da5c..ad0a4c869d 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -23,38 +23,64 @@ function(add_vs_debugger_arguments) endforeach() endfunction() +set(o3de_project_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_project_json ${o3de_project_path}/project.json) + if(NOT PROJECT_NAME) cmake_minimum_required(VERSION 3.19) project(${Name} LANGUAGES C CXX VERSION 1.0.0.0 ) - include(EngineFinder.cmake OPTIONAL) - find_package(o3de REQUIRED) - o3de_initialize() - add_vs_debugger_arguments() -else() - # Add the project_name to global LY_PROJECTS_TARGET_NAME property - file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json) - string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name") - if(json_error) - message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'") + # set this project as the only project + set(LY_PROJECTS ${CMAKE_CURRENT_LIST_DIR}) + + # o3de manifest + include(o3de_manifest.cmake) + + ################################################################################ + # Set the engine_path and resolve this engines restricted path if it has one + ################################################################################ + o3de_engine_path(${o3de_project_json} o3de_engine_path) + o3de_project_name(${o3de_project_json} o3de_project_name) + o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) + message(STATUS "O3DE Project Name: ${o3de_project_name}") + message(STATUS "O3DE Project Path: ${o3de_project_path}") + if(o3de_project_restricted_path) + message(STATUS "O3DE Project Restricted Path: ${o3de_project_restricted_path}") endif() - set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) + # add the engines cmake folder to the CMAKE_MODULE_PATH + list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") + + # add subdirectory on the engine path for this project + add_subdirectory(${o3de_engine_path} o3de) - # Currently we are in the ${Name} folder: ${CMAKE_CURRENT_LIST_DIR} - # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} + # add this --project-path arguments to visual studio debugger + add_vs_debugger_arguments() + +else() + ###################################################### + # the engine is calling add sub_directory() on us + ###################################################### + o3de_project_name(${o3de_project_json} o3de_project_name) + o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) + + # Currently we are in the folder: ${CMAKE_CURRENT_LIST_DIR} + # Get the platform specific folder ${pal_dir} for the folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform # in which case it will see if that platform is present here or in the restricted folder. - # i.e. It could here: ${Name}/Platform/ or - # //${Name} - ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) + # i.e. It could here: TestDP/Platform/ or + # //TestDP + ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # project cmake for this platform. include(${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_project.cmake) + # Add the project_name to global LY_PROJECTS_TARGET_NAME property + set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${o3de_project_name}) + add_subdirectory(Code) endif() diff --git a/Templates/DefaultProject/Template/Code/CMakeLists.txt b/Templates/DefaultProject/Template/Code/CMakeLists.txt index cb98254b3b..38999c031c 100644 --- a/Templates/DefaultProject/Template/Code/CMakeLists.txt +++ b/Templates/DefaultProject/Template/Code/CMakeLists.txt @@ -15,7 +15,7 @@ # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here : ${Name}/Code/Platform/ or # //${Name}/Code -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this project diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake deleted file mode 100644 index d1b83b6b6c..0000000000 --- a/Templates/DefaultProject/Template/EngineFinder.cmake +++ /dev/null @@ -1,56 +0,0 @@ -# {BEGIN_LICENSE} -# -# 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. -# -# {END_LICENSE} - -# This file is copied during engine registration. Edits to this file will be lost next -# time a registration happens. -include_guard() - -# Read the engine name from the project_json file -file(READ ${CMAKE_CURRENT_LIST_DIR}/project.json project_json) -string(JSON LY_ENGINE_NAME_TO_USE ERROR_VARIABLE json_error GET ${project_json} engine) -if(json_error) - message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") -endif() - -# Read the list of paths from ~.o3de/o3de_manifest.json -file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows -if((NOT home_directory) OR (NOT EXISTS ${home_directory})) - file(TO_CMAKE_PATH "$ENV{HOME}" home_directory)# Unix -endif() - -if (NOT home_directory) - message(FATAL_ERROR "Cannot find user home directory, the o3de manifest cannot be found") -endif() -# Set manifest path to path in the user home directory -set(manifest_path ${home_directory}/.o3de/o3de_manifest.json) - -if(EXISTS ${manifest_path}) - file(READ ${manifest_path} manifest_json) - string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines) - if(json_error) - message(FATAL_ERROR "Unable to read key 'engines' from '${manifest_path}', error: ${json_error}") - endif() - math(EXPR engines_count "${engines_count}-1") - foreach(engine_path_index RANGE ${engines_count}) - string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines ${engine_path_index}) - if(${json_error}) - message(FATAL_ERROR "Unable to read engines[${engine_path_index}] '${manifest_path}', error: ${json_error}") - endif() - list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") - endforeach() -endif() - - - - - diff --git a/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi b/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi index ac1d663bb8..ac27571828 100644 --- a/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi +++ b/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi @@ -1,3 +1,4 @@ +// {BEGIN_LICENSE} /* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. @@ -9,6 +10,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ +// {END_LICENSE} #pragma once diff --git a/Templates/DefaultProject/Template/project.json b/Templates/DefaultProject/Template/project.json index 5c4a152caf..7f6b5d3b78 100644 --- a/Templates/DefaultProject/Template/project.json +++ b/Templates/DefaultProject/Template/project.json @@ -4,8 +4,12 @@ "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", "display_name": "${Name}", "summary": "A short description of ${Name}.", - "canonical_tags": ["Project"], - "user_tags": ["${Name}"], + "canonical_tags": [ + "Project" + ], + "user_tags": [ + "${Name}" + ], "icon_path": "preview.png", "engine": "o3de" -} \ No newline at end of file +} diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 10e3079f2e..56278a6b04 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -1,5 +1,7 @@ { "template_name": "DefaultProject", + "restricted": "o3de", + "restricted_platform_relative_path": "Templates", "origin": "The primary repo for DefaultProject goes here: i.e. http://www.mydomain.com", "license": "What license DefaultProject uses goes here: i.e. https://opensource.org/licenses/MIT", "display_name": "DefaultProject", @@ -268,12 +270,6 @@ "isTemplated": false, "isOptional": false }, - { - "file": "EngineFinder.cmake", - "origin": "EngineFinder.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Platform/Android/android_project.cmake", "origin": "Platform/Android/android_project.cmake", @@ -568,6 +564,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "ShaderLib/raytracingscenesrg.srgi", + "origin": "ShaderLib/raytracingscenesrg.srgi", + "isTemplated": true, + "isOptional": false + }, { "file": "ShaderLib/scenesrg.srgi", "origin": "ShaderLib/scenesrg.srgi", diff --git a/Tests/Atom/windows/screenshot_comparison_atomsampleviewer_windows.py b/Tests/Atom/windows/screenshot_comparison_atomsampleviewer_windows.py index 7d05046b7e..fca50c9901 100755 --- a/Tests/Atom/windows/screenshot_comparison_atomsampleviewer_windows.py +++ b/Tests/Atom/windows/screenshot_comparison_atomsampleviewer_windows.py @@ -86,7 +86,7 @@ # return final_path -# # Commenting out debug due to https://jira.agscollab.com/browse/ATOM-1677 +# # Commenting out debug due to ATOM-1677 # @pytest.mark.parametrize("platform,configuration,project,spec,sample", [ # pytest.param("win_x64_vs2017", "profile", "BaseViewer", "all", "RPI/BistroBenchmark", # marks=pytest.mark.skipif(not WINDOWS, reason="Only supported on Windows hosts")), diff --git a/Tests/pipeline/product_dependency_tests/TestFixtures.py b/Tests/pipeline/product_dependency_tests/TestFixtures.py index c7feab76f3..91151748a5 100755 --- a/Tests/pipeline/product_dependency_tests/TestFixtures.py +++ b/Tests/pipeline/product_dependency_tests/TestFixtures.py @@ -52,8 +52,8 @@ def HeliosProjectFixture(request): # These tests are run on Jenkins after other tests, to minimize time spent on Jenkins jobs. # Verify that the correct project has been set before this test starts. - # Temporarily disabling while https://jira.agscollab.com/browse/LY-103017 is not in Helios branch - # Creating a task to revert this change later: https://jira.agscollab.com/browse/LY-103334 + # Temporarily disabling while LY-103017 is not in Helios branch + # Creating a task to revert this change later: LY-103334 # Run asset processor once to process all assets, so the tests themselves can run at consistent speeds. SubprocessUtils.SubprocessWithTimeout([buildInfo.assetProcessorBatch], engineRoot, 120) diff --git a/Tools/LyTestTools/ly_test_tools/__init__.py b/Tools/LyTestTools/ly_test_tools/__init__.py index 1c78176b87..d534f5e0d2 100755 --- a/Tools/LyTestTools/ly_test_tools/__init__.py +++ b/Tools/LyTestTools/ly_test_tools/__init__.py @@ -17,7 +17,7 @@ logger = logging.getLogger(__name__) # Supported platforms. ALL_PLATFORM_OPTIONS = ['android', 'ios', 'linux', 'mac', 'windows'] -ALL_LAUNCHER_OPTIONS = ['android', 'base', 'mac', 'windows', 'windows_editor', 'windows_dedicated'] +ALL_LAUNCHER_OPTIONS = ['android', 'base', 'mac', 'windows', 'windows_editor', 'windows_dedicated', 'windows_generic'] ANDROID = False IOS = False # Not implemented - see SPEC-2505 LINUX = sys.platform.startswith('linux') # Not implemented - see SPEC-2501 @@ -37,12 +37,15 @@ if WINDOWS: HOST_OS_PLATFORM = 'windows' HOST_OS_EDITOR = 'windows_editor' HOST_OS_DEDICATED_SERVER = 'windows_dedicated' + HOST_OS_GENERIC_EXECUTABLE = 'windows_generic' import ly_test_tools.mobile.android - from ly_test_tools.launchers import AndroidLauncher, WinLauncher, DedicatedWinLauncher, WinEditor + from ly_test_tools.launchers import ( + AndroidLauncher, WinLauncher, DedicatedWinLauncher, WinEditor, WinGenericLauncher) ANDROID = ly_test_tools.mobile.android.can_run_android() LAUNCHERS['windows'] = WinLauncher LAUNCHERS['windows_editor'] = WinEditor LAUNCHERS['windows_dedicated'] = DedicatedWinLauncher + LAUNCHERS['windows_generic'] = WinGenericLauncher LAUNCHERS['android'] = AndroidLauncher elif MAC: HOST_OS_PLATFORM = 'mac' diff --git a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py index c4249441b0..87a396ea1c 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/pytest_plugin/test_tools_fixtures.py @@ -29,7 +29,7 @@ import ly_test_tools.environment.file_system import ly_test_tools.launchers.launcher_helper import ly_test_tools.launchers.platforms.base import ly_test_tools.environment.watchdog -from ly_test_tools import ALL_PLATFORM_OPTIONS, HOST_OS_PLATFORM +from ly_test_tools import ALL_PLATFORM_OPTIONS, HOST_OS_PLATFORM, HOST_OS_DEDICATED_SERVER, HOST_OS_GENERIC_EXECUTABLE logger = logging.getLogger(__name__) @@ -260,7 +260,7 @@ def dedicated_launcher(request, workspace, crash_log_watchdog): return _dedicated_launcher( request=request, workspace=workspace, - launcher_platform=get_fixture_argument(request, 'launcher_platform', HOST_OS_PLATFORM), + launcher_platform=get_fixture_argument(request, 'launcher_platform', HOST_OS_DEDICATED_SERVER), level=get_fixture_argument(request, 'level', '')) @@ -281,6 +281,21 @@ def _dedicated_launcher(request, workspace, launcher_platform, level=""): return launcher + +@pytest.fixture(scope="function") +def generic_launcher(workspace, request, crash_log_watchdog): + # type: (...) -> ly_test_tools.launchers.platforms.base.Launcher + return _generic_launcher( + workspace=workspace, + launcher_platform=get_fixture_argument(request, 'launcher_platform', HOST_OS_GENERIC_EXECUTABLE), + exe_file_name=get_fixture_argument(request, 'exe_file_name', '')) + + +def _generic_launcher(workspace, launcher_platform, exe_file_name): + """Separate implementation to call directly during unit tests""" + return ly_test_tools.launchers.launcher_helper.create_generic_launcher(workspace, launcher_platform, exe_file_name) + + @pytest.fixture def automatic_process_killer(request): # type: (_pytest.fixtures.SubRequest) -> ly_process_killer diff --git a/Tools/LyTestTools/ly_test_tools/launchers/__init__.py b/Tools/LyTestTools/ly_test_tools/launchers/__init__.py index 2203d2eb39..5f7a391afb 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/__init__.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/__init__.py @@ -11,5 +11,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. from ly_test_tools.launchers.platforms.base import Launcher from ly_test_tools.launchers.platforms.mac.launcher import MacLauncher -from ly_test_tools.launchers.platforms.win.launcher import WinLauncher, DedicatedWinLauncher, WinEditor +from ly_test_tools.launchers.platforms.win.launcher import ( + WinLauncher, DedicatedWinLauncher, WinEditor, WinGenericLauncher) from ly_test_tools.launchers.platforms.android.launcher import AndroidLauncher diff --git a/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py b/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py index 4ed4c43dee..45f5e6e73f 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/launcher_helper.py @@ -61,3 +61,19 @@ def create_editor(workspace, launcher_platform=ly_test_tools.HOST_OS_EDITOR, arg """ launcher_class = ly_test_tools.LAUNCHERS.get(launcher_platform, ly_test_tools.HOST_OS_EDITOR) return launcher_class(workspace, args) + + +def create_generic_launcher(workspace, launcher_platform, exe_file_name, args=None): + # type: (ly_test_tools.managers.workspace.WorkspaceManager, str, str, List[str]) -> Launcher + """ + Create a generic launcher compatible with the specified workspace. + Allows custom .exe files to serve as the launcher instead of ones listed in the ly_test_tools.LAUNCHERS constant + + :param workspace: lumberyard workspace to use + :param launcher_platform: the platform to target for a launcher (i.e. 'windows' for WinLauncher) + :param exe_file_name: .exe file name which has to be launched for this launcher (i.e. 'MaterialEditor.exe') + :param args: List of arguments to pass to the launcher's 'args' argument during construction + :return: Launcher instance. + """ + launcher_class = ly_test_tools.LAUNCHERS.get(launcher_platform, ly_test_tools.HOST_OS_GENERIC_EXECUTABLE) + return launcher_class(workspace, exe_file_name, args) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py index 6b53c1f8f3..36746b510f 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py @@ -70,7 +70,7 @@ class Launcher(object): return config_dict - def setup(self, backupFiles = True, launch_ap = True): + def setup(self, backupFiles=True, launch_ap=True): """ Perform setup of this launcher, must be called before launching. Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files @@ -193,7 +193,7 @@ class Launcher(object): """ raise NotImplementedError("There is no binary file for this launcher") - def start(self, backupFiles = True, launch_ap = True): + def start(self, backupFiles=True, launch_ap=None): """ Automatically prepare and launch the application When called using "with launcher.start():" it will automatically call stop() when block exits @@ -203,14 +203,14 @@ class Launcher(object): """ return _Application(self, backupFiles, launch_ap=launch_ap) - def _start_impl(self, backupFiles = True, launch_ap=True): + def _start_impl(self, backupFiles = True, launch_ap=None): """ Implementation of start(), intended to be called via context manager in _Application :param backupFiles: Bool to backup settings files :return None: """ - self.setup(backupFiles, launch_ap=launch_ap) + self.setup(backupFiles=backupFiles, launch_ap=launch_ap) self.launch() def stop(self): @@ -326,7 +326,7 @@ class _Application(object): """ Context-manager for opening an application, enables using both "launcher.start()" and "with launcher.start()" """ - def __init__(self, launcher, backupFiles = True, launch_ap = True): + def __init__(self, launcher, backupFiles = True, launch_ap=None): """ Called during both "launcher.start()" and "with launcher.start()" @@ -334,7 +334,7 @@ class _Application(object): :return None: """ self.launcher = launcher - launcher._start_impl(backupFiles, launch_ap=launch_ap) + launcher._start_impl(backupFiles, launch_ap) def __enter__(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index 800771c9bc..30c3e6eddd 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -42,21 +42,26 @@ class WinLauncher(Launcher): assert self.workspace.project is not None return os.path.join(self.workspace.paths.build_directory(), f"{self.workspace.project}.GameLauncher.exe") - def setup(self, backupFiles = True, launch_ap = True): + def setup(self, backupFiles=True, launch_ap=True): """ Perform setup of this launcher, must be called before launching. Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files :param backupFiles: Bool to backup setup files + :param lauch_ap: Bool to lauch the asset processor :return: None """ # Backup if backupFiles: self.backup_settings() + # Base setup defaults to None + if launch_ap is None: + launch_ap = True + # Modify and re-configure self.configure_settings() - super(WinLauncher, self).setup(launch_ap=launch_ap) + super(WinLauncher, self).setup(backupFiles, launch_ap) def launch(self): """ @@ -177,6 +182,21 @@ class WinLauncher(Launcher): class DedicatedWinLauncher(WinLauncher): + def setup(self, backupFiles=True, launch_ap=False): + """ + Perform setup of this launcher, must be called before launching. + Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files + + :param backupFiles: Bool to backup setup files + :param lauch_ap: Bool to lauch the asset processor + :return: None + """ + # Base setup defaults to None + if launch_ap is None: + launch_ap = False + + super(DedicatedWinLauncher, self).setup(backupFiles, launch_ap) + def binary_path(self): """ Return full path to the dedicated server launcher for the build directory. @@ -203,3 +223,28 @@ class WinEditor(WinLauncher): """ assert self.workspace.project is not None return os.path.join(self.workspace.paths.build_directory(), "Editor.exe") + + +class WinGenericLauncher(WinLauncher): + + def __init__(self, build, exe_file_name, args=None): + super(WinGenericLauncher, self).__init__(build, args) + self.exe_file_name = exe_file_name + self.expected_executable_path = os.path.join( + self.workspace.paths.build_directory(), f"{self.exe_file_name}.exe") + + if not os.path.exists(self.expected_executable_path): + raise ProcessNotStartedError( + f"Unable to locate executable '{self.exe_file_name}.exe' " + f"in path: '{self.expected_executable_path}'") + + def binary_path(self): + """ + Return full path to the .exe file for this build's configuration and project + Relies on the build_directory() in self.workspace.paths to be accurate + + :return: full path to the given exe file + """ + assert self.workspace.project is not None, ( + 'Project cannot be NoneType - please specify a project name string.') + return self.expected_executable_path diff --git a/Tools/LyTestTools/tests/unit/test_launcher_win.py b/Tools/LyTestTools/tests/unit/test_launcher_win.py index 193589f457..37e04ac99e 100755 --- a/Tools/LyTestTools/tests/unit/test_launcher_win.py +++ b/Tools/LyTestTools/tests/unit/test_launcher_win.py @@ -184,3 +184,31 @@ class TestDedicatedWinLauncher(object): launcher.workspace.build(dedicated=True) mock_workspace.build.assert_called_once_with(dedicated=True) + + +class TestWinGenericLauncher(object): + + @mock.patch('ly_test_tools.launchers.platforms.win.launcher.os.path.exists') + def test_BinaryPath_DummyPathExeExists_AddPathToExe(self, mock_os_path_exists): + dummy_path = "dummy_workspace_path" + dummy_executable = 'SomeCustomLauncher.exe' + mock_os_path_exists.return_value = True + mock_workspace = mock.MagicMock() + mock_workspace.paths.build_directory.return_value = dummy_path + launcher = ly_test_tools.launchers.WinGenericLauncher(mock_workspace, dummy_executable, ["some_args"]) + + under_test = launcher.binary_path() + + assert dummy_executable in under_test, f"executable named {dummy_executable} not found" + assert dummy_path in under_test, "workspace path unexpectedly missing " + + @mock.patch('ly_test_tools.launchers.platforms.win.launcher.os.path.exists') + def test_BinaryPath_DummyPathExeDoesNotExist_RaiseProcessNotStartedError(self, mock_os_path_exists): + dummy_path = "dummy_workspace_path" + dummy_executable = 'SomeCustomLauncher.exe' + mock_os_path_exists.return_value = False + mock_workspace = mock.MagicMock() + mock_workspace.paths.build_directory.return_value = dummy_path + + with pytest.raises(ly_test_tools.launchers.exceptions.ProcessNotStartedError): + ly_test_tools.launchers.WinGenericLauncher(mock_workspace, dummy_executable, ["some_args"]) diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index c7adb660f0..7802ac8c58 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -22,7 +22,7 @@ file(GLOB detection_files "cmake/Platform/*/PALDetection_*.cmake") foreach(detection_file ${detection_files}) include(${detection_file}) endforeach() -file(GLOB detection_files "restricted/*/cmake/PALDetection_*.cmake") +file(GLOB detection_files ${o3de_engine_restricted_path}/*/cmake/PALDetection_*.cmake) foreach(detection_file ${detection_files}) include(${detection_file}) endforeach() @@ -36,43 +36,99 @@ string(TOLOWER ${PAL_HOST_PLATFORM_NAME} PAL_HOST_PLATFORM_NAME_LOWERCASE) ly_set(PAL_HOST_PLATFORM_NAME_LOWERCASE ${PAL_HOST_PLATFORM_NAME_LOWERCASE}) set(PAL_RESTRICTED_PLATFORMS) -file(GLOB pal_restricted_files "restricted/*/cmake/PAL_*.cmake") + +string(LENGTH ${o3de_engine_restricted_path} engine_restricted_length) +file(GLOB pal_restricted_files ${o3de_engine_restricted_path}/*/cmake/PAL_*.cmake) foreach(pal_restricted_file ${pal_restricted_files}) - string(FIND ${pal_restricted_file} "restricted/" start) - math(EXPR start "${start} + 11") string(FIND ${pal_restricted_file} "/cmake/PAL" end) if(${end} GREATER -1) - math(EXPR length "${end} - ${start}") - string(SUBSTRING ${pal_restricted_file} ${start} ${length} platform) + math(EXPR platform_length "${end} - ${engine_restricted_length} - 1") + math(EXPR platform_start "${engine_restricted_length} + 1") + string(SUBSTRING ${pal_restricted_file} ${platform_start} ${platform_length} platform) list(APPEND PAL_RESTRICTED_PLATFORMS "${platform}") endif() endforeach() ly_set(PAL_RESTRICTED_PLATFORMS ${PAL_RESTRICTED_PLATFORMS}) function(ly_get_absolute_pal_filename out_name in_name) - if(${ARGC} GREATER 2) - set(repo_dir ${ARGV2}) - else() - if(DEFINED LY_ROOT_FOLDER) - set(repo_dir ${LY_ROOT_FOLDER}) - else() - set(repo_dir ${CMAKE_CURRENT_SOURCE_DIR}) + set(full_name ${in_name}) + + if(${ARGC} GREATER 4) + # The user has supplied an object restricted path, the object path and the object name for consideration + set(object_restricted_path ${ARGV2}) + set(object_path ${ARGV3}) + set(object_name ${ARGV4}) + + # if the file is not in the object path then we cannot determine a PAL file for it + file(RELATIVE_PATH relative_path ${object_path} ${full_name}) + if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) + if (NOT EXISTS ${full_name}) + string(REGEX MATCH "${object_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) + if(NOT CMAKE_MATCH_1) + string(REGEX MATCH "${object_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) + set(full_name ${object_restricted_path}/${CMAKE_MATCH_1}/${object_name}) + if(CMAKE_MATCH_2) + string(APPEND full_name "/" ${CMAKE_MATCH_2}) + endif() + elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) + set(full_name ${object_restricted_path}/${CMAKE_MATCH_2}/${object_name}/${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + string(APPEND full_name "/" ${CMAKE_MATCH_3}) + endif() + endif() + endif() endif() - endif() + set(${out_name} ${full_name} PARENT_SCOPE) - set(full_name ${in_name}) - if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${repo_dir}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) - if(PAL_RESTRICTED_PLATFORMS) - if("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) - set(full_name ${repo_dir}/restricted/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) - if(NOT "${CMAKE_MATCH_3}" STREQUAL "") - string(APPEND full_name "/" ${CMAKE_MATCH_3}) + elseif(${ARGC} GREATER 3) + # The user has supplied an object restricted path, the object path for consideration + set(object_restricted_path ${ARGV2}) + set(object_path ${ARGV3}) + + # if the file is not in the object path then we cannot determine a PAL file for it + file(RELATIVE_PATH relative_path ${object_path} ${full_name}) + if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) + if (NOT EXISTS ${full_name}) + string(REGEX MATCH "${object_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) + if(NOT CMAKE_MATCH_1) + string(REGEX MATCH "${object_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) + set(full_name ${object_restricted_path}/${CMAKE_MATCH_1}) + if(CMAKE_MATCH_2) + string(APPEND full_name "/" ${CMAKE_MATCH_2}) + endif() + elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) + set(full_name ${object_restricted_path}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + string(APPEND full_name "/" ${CMAKE_MATCH_3}) + endif() endif() endif() endif() + set(${out_name} ${full_name} PARENT_SCOPE) + + else() + # The user has not supplied any path so we must assume it is the o3de engine restricted and o3de engine path + # if the file is not in the o3de engine path then we cannot determine a PAL file for it + file(RELATIVE_PATH relative_path ${o3de_engine_path} ${full_name}) + if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) + if (NOT EXISTS ${full_name}) + string(REGEX MATCH "${o3de_engine_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) + if(NOT CMAKE_MATCH_1) + string(REGEX MATCH "${o3de_engine_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) + set(full_name ${o3de_engine_restricted_path}/${CMAKE_MATCH_1}) + if(CMAKE_MATCH_2) + string(APPEND full_name "/" ${CMAKE_MATCH_2}) + endif() + elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) + set(full_name ${o3de_engine_restricted_path}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + string(APPEND full_name "/" ${CMAKE_MATCH_3}) + endif() + endif() + endif() + endif() + set(${out_name} ${full_name} PARENT_SCOPE) endif() - set(${out_name} ${full_name} PARENT_SCOPE) endfunction() function(ly_get_list_relative_pal_filename out_name in_name) @@ -93,3 +149,25 @@ set(LY_DISABLE_TEST_MODULES FALSE CACHE BOOL "Option to forcibly disable the inc if(LY_DISABLE_TEST_MODULES) ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED FALSE) endif() + +################################################################################ +# Add each restricted platform in the engines restricted folder +# If the enabled restricted platform does not have a folder add one. +# If the restricted platform folder does not have a CMakeLists.txt, create one +# so the add_subdirectory on the external folder does not fail. +################################################################################ +function(o3de_add_engine_restricted_platform_external_subdirs) + foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS}) + if(restricted_platform IN_LIST enabled_platforms) + set(o3de_engine_restricted_platform_folder ${o3de_engine_restricted_path}/${restricted_platform}) + if(NOT EXISTS ${o3de_engine_restricted_platform_folder}) + file(MAKE_DIRECTORY ${o3de_engine_restricted_platform_folder}) + endif() + set(o3de_engine_restricted_platform_folder_cmakelists ${o3de_engine_restricted_platform_folder}/CMakeLists.txt) + if(NOT EXISTS ${o3de_engine_restricted_platform_folder_cmakelists}) + file(TOUCH ${o3de_engine_restricted_platform_folder_cmakelists}) + endif() + list(APPEND LY_EXTERNAL_SUBDIRS ${o3de_engine_restricted_platform_folder}) + endif() + endforeach() +endfunction() diff --git a/cmake/Tools/add_remove_gem.py b/cmake/Tools/add_remove_gem.py deleted file mode 100755 index fab488bdbc..0000000000 --- a/cmake/Tools/add_remove_gem.py +++ /dev/null @@ -1,634 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import argparse -import logging -import os -import sys -import pathlib - -from cmake.Tools import utils -from cmake.Tools import common - -logger = logging.getLogger() -logging.basicConfig() - - -def add_gem_dependency(cmake_file: str, - gem_target: str) -> int: - """ - adds a gem dependency to a cmake file - :param cmake_file: path to the cmake file - :param gem_target: name of the cmake target - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - # on a line by basis, see if there already is Gem::{gem_name} - # find the first occurrence of a gem, copy its formatting and replace - # the gem name with the new one and append it - # if the gem is already present fail - t_data = [] - added = False - with open(cmake_file, 'r') as s: - for line in s: - if f'Gem::{gem_target}' in line: - logger.warning(f'{gem_target} is already a gem dependency.') - return 0 - if not added and r'Gem::' in line: - new_gem = ' ' * line.find(r'Gem::') + f'Gem::{gem_target}\n' - t_data.append(new_gem) - added = True - t_data.append(line) - - # if we didn't add it the set gem dependencies could be empty so - # add a new gem, if empty the correct format is 1 tab=4spaces - if not added: - index = 0 - for line in t_data: - index = index + 1 - if r'set(GEM_DEPENDENCIES' in line: - t_data.insert(index, f' Gem::{gem_target}\n') - added = True - break - - # if we didn't add it then it's not here, add a whole new one - if not added: - t_data.append('\n') - t_data.append('set(GEM_DEPENDENCIES\n') - t_data.append(f' Gem::{gem_target}\n') - t_data.append(')\n') - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def get_project_gem_list(project_path: str, - platform: str = 'Common') -> set: - runtime_gems = get_gem_list(get_dependencies_cmake(project_path, 'runtime', platform)) - tool_gems = get_gem_list(get_dependencies_cmake(project_path, 'tool', platform)) - server_gems = get_gem_list(get_dependencies_cmake(project_path, 'server', platform)) - return runtime_gems.union(tool_gems.union(server_gems)) - - -def get_gem_list(cmake_file: str) -> set: - """ - Gets a list of declared gem dependencies of a cmake file - :param cmake_file: path to the cmake file - :return: set of gems found - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return set() - - gem_list = set() - with open(cmake_file, 'r') as s: - for line in s: - gem_name = line.split('Gem::') - if len(gem_name) > 1: - # Only take the name as everything leading up to the first '.' if found - # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName - # as different targets of the GemName Gem - gem_list.add(gem_name[1].split('.')[0].replace('\n', '')) - return gem_list - - -def remove_gem_dependency(cmake_file: str, - gem_target: str) -> int: - """ - removes a gem dependency from a cmake file - :param cmake_file: path to the cmake file - :param gem_target: cmake target name - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - # on a line by basis, remove any line with Gem::{gem_name} - t_data = [] - # Remove the gem from the cmake_dependencies file by skipping the gem name entry - removed = False - with open(cmake_file, 'r') as s: - for line in s: - if f'Gem::{gem_target}' in line: - removed = True - else: - t_data.append(line) - - if not removed: - logger.error(f'Failed to remove Gem::{gem_target} from cmake file {cmake_file}') - return 1 - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def add_gem_subdir(cmake_file: str, - gem_name: str) -> int: - """ - adds a gem subdir to a cmake file - :param cmake_file: path to the cmake file - :param gem_name: name of the gem to add - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - if not utils.validate_identifier(gem_name): - logger.error(f'{gem_name} is not a valid gem name') - return 1 - - # on a line by basis, see if there already is Gem::{gem_name} - # find the first occurrence of a gem, copy its formatting and replace - # the gem name with the new one and append it - # if the gem is already present fail - t_data = [] - added = False - add_line = f'add_subdirectory({gem_name})' - with open(cmake_file, 'r') as s: - for line in s: - if add_line in line: - logger.info(f'{add_line} is already in {cmake_file} - skipping.') - return 0 - if not added and r'add_subdirectory(' in line: - new_gem = ' ' * line.find(r'add_subdirectory(') + f'add_subdirectory({gem_name})\n' - t_data.append(new_gem) - added = True - t_data.append(line) - - if not added: - logger.error(f'Failed to add add_subdirectory({gem_name}) from {cmake_file}.') - return 1 - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def remove_gem_subdir(cmake_file: str, - gem_name: str) -> int: - """ - removes a gem subdir form a cmake file - :param cmake_file: path to the cmake file - :param gem_name: name of the gem to remove - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - # on a line by basis, remove any line with Gem::{gem_name} - t_data = [] - # Remove the gem from the cmake_dependencies file by skipping the gem name entry - removed = False - with open(cmake_file, 'r') as s: - for line in s: - if f'add_subdirectory({gem_name})' in line: - removed = True - else: - t_data.append(line) - - if not removed: - logger.error(f'Failed to remove add_subdirectory({gem_name}) from {cmake_file}') - return 1 - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def get_dependencies_cmake(project_path: str, - dependency_type: str = 'runtime', - platform: str = 'Common') -> str: - if not project_path: - return '' - if platform == 'Common': - dependencies_file = f'{dependency_type}_dependencies.cmake' - gem_path = os.path.join(project_path, 'Gem', 'Code', dependencies_file) - if os.path.isfile(gem_path): - return gem_path - return os.path.join(project_path, 'Code', dependencies_file) - else: - dependencies_file = f'{platform.lower()}_{dependency_type}_dependencies.cmake' - gem_path = os.path.join(project_path, 'Gem', 'Code', 'Platform', platform, dependencies_file) - if os.path.isfile(gem_path): - return gem_path - return os.path.join(project_path, 'Code', 'Platform', platform, dependencies_file) - -# this function is making some not so good assumptions about gem naming -def find_all_gems(gem_folder_list: list) -> list: - """ - Find all Modules which appear to be gems living within a list of folders - This method can be replaced or improved on with something more deterministic when LYN-1942 is done - :param gem_folder_list: - :return: list of gem objects containing gem Name and Path - """ - module_gems = {} - for folder in gem_folder_list: - root_len = len(os.path.normpath(folder).split(os.sep)) - for root, dirs, files in os.walk(folder): - for file in files: - if file == 'CMakeLists.txt': - with open(os.path.join(root, file), 'r') as s: - for line in s: - trimmed = line.lstrip() - if trimmed.startswith('NAME '): - trimmed = trimmed.rstrip(' \n') - split_trimmed = trimmed.split(' ') - # Is this a type indicating a gem lives here - if len(split_trimmed) == 3 and split_trimmed[2] in ['MODULE', 'GEM_MODULE', - '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}']: - # Hold our "Name parts" such as Gem.MyGem.Editor as ['Gem', 'MyGem', 'Editor'] - name_split = split_trimmed[1].split('.') - split_folders = os.path.normpath(root).split(os.sep) - # This verifies we were passed a folder lower in the folder structure than the - # gem we've found, so we'll name it by the first directory. This is the common - # case currently of being handed "Gems" where things that live under Gems are - # known by the directory name - if len(split_folders) > root_len: - # Assume the gem is named by the root folder. May modules may exist - # together within the gem that are added collectively - gem_name = split_folders[root_len] - else: - # We were passed the folder with the gem already inside it, we have to name - # it by the gem name we found - gem_name = name_split[0] - this_gem = module_gems.get(gem_name, None) - if not this_gem: - if len(split_folders) > root_len: - # Assume the gem is named by the root folder. May modules may exist - # together within the gem that are added collectively - this_gem = {'Name': gem_name, - 'Path': os.path.join(folder, split_folders[root_len])} - else: - this_gem = {'Name': gem_name, 'Path': folder} - # Add any module types we know to be tools only here - if len(name_split) > 1 and name_split[1] in ['Editor', 'Builder']: - this_gem['Tools'] = True - else: - this_gem['Runtime'] = True - this_gem['Tools'] = True - - module_gems[gem_name] = this_gem - break - - return sorted(list(module_gems.values()), key=lambda x: x.get('Name')) - - -def find_gem_modules(gem_folder: str) -> list: - """ - Find all gem modules which appear to be gems living in this folder - :param gem_folder: the folder to walk down - :return: list of gem targets - """ - module_identifiers = [ - 'MODULE', - 'GEM_MODULE', - '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}' - ] - modules = [] - for root, dirs, files in os.walk(gem_folder): - for file in files: - if file == 'CMakeLists.txt': - with open(os.path.join(root, file), 'r') as s: - for line in s: - trimmed = line.lstrip() - if trimmed.startswith('NAME '): - trimmed = trimmed.rstrip(' \n') - split_trimmed = trimmed.split(' ') - if len(split_trimmed) == 3 and split_trimmed[2] in module_identifiers: - modules.append(split_trimmed[1]) - return modules - - -def add_remove_gem(add: bool, - dev_root: str, - gem_path: str, - gem_target: str, - project_path: str, - dependencies_file: str or None, - project_restricted_path: str = 'restricted', - runtime_dependency: bool = False, - tool_dependency: bool = False, - server_dependency: bool = False, - platforms: str = 'Common', - gem_cmake: str = None) -> int: - """ - add a gem to a project - :param add: should we add a gem, if false we remove a gem - :param dev_root: the dev root of the engine - :param gem_path: path to the gem to add - :param gem_target: the name of teh cmake gem module - :param project_path: path to the project to add the gem to - :param dependencies_file: if this dependency goes/is in a specific file - :param project_restricted_path: path to the projects restricted folder - :param runtime_dependency: bool to specify this is a runtime gem for the game - :param tool_dependency: bool to specify this is a tool gem for the editor - :param server_dependency: bool to specify this is a server gem for the server - :param platforms: str to specify common or which specific platforms - :param gem_cmake: str to specify that this gem should be removed from the Gems/CMakeLists.txt - :return: 0 for success or non 0 failure code - """ - - # if no dev root error - if not dev_root: - logger.error('Dev root cannot be empty.') - return 1 - if not os.path.isabs(dev_root): - dev_root = os.path.abspath(dev_root) - dev_root = pathlib.Path(dev_root) - if not dev_root.is_dir(): - logger.error(f'Dev root {dev_root} is not a folder.') - return 1 - - # if no project path error - if not project_path: - logger.error('Project path cannot be empty.') - return 1 - if not os.path.isabs(project_path): - project_path = f'{dev_root}/{project_path}' - project_path = pathlib.Path(project_path) - if not project_path.is_dir(): - logger.error(f'Project path {project_path} is not a folder.') - return 1 - - project_restricted_path = project_restricted_path.replace('\\', '/') - if not os.path.isabs(project_restricted_path): - project_restricted_path = f'{dev_root}/{project_restricted_path}' - project_restricted_path = pathlib.Path(project_restricted_path) - if not project_restricted_path.is_dir(): - logger.error(f'Project Restricted path {project_restricted_path} is not a folder.') - return 1 - - # if no gem path error - if not gem_path: - logger.error('Gem path cannot be empty.') - return 1 - if not os.path.isabs(gem_path): - gem_path = f'{dev_root}/Gems/{gem_path}' - gem_path = pathlib.Path(gem_path) - # make sure this gem already exists if we're adding. We can always remove a gem. - if add and not gem_path.is_dir(): - logger.error(f'{gem_path} dir does not exist.') - return 1 - - # find all available modules in this gem_path - modules = find_gem_modules(gem_path) - if len(modules) == 0: - logger.error(f'No gem modules found.') - return 1 - - # if gem target not specified, see if there is only 1 module - if not gem_target: - if len(modules) == 1: - gem_target = modules[0] - else: - logger.error(f'Gem target not specified: {modules}') - return 1 - elif gem_target not in modules: - logger.error(f'Gem target not in gem modules: {modules}') - return 1 - - # gem cmake list text file is assumed to be in the parent folder is not specified - if add or isinstance(gem_cmake, str): - if not gem_cmake: - gem_cmake = gem_path.parent / 'CMakeLists.txt' - if not os.path.isabs(gem_cmake): - gem_cmake = f'{dev_root}/{gem_cmake}' - gem_cmake = pathlib.Path(gem_cmake) - if not gem_cmake.is_file(): - logger.error(f'CMakeLists.txt file {gem_cmake} does not exist.') - return 1 - - # if the user has not specified either we will assume they meant the most common which is runtime - if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: - logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") - runtime_dependency = True - - ret_val = 0 - - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if dependencies_file: - dependencies_file = pathlib.Path(dependencies_file) - # make sure this is a project has a dependencies_file - if not dependencies_file.is_file(): - logger.error(f'Dependencies file {dependencies_file} is not present.') - return 1 - if add: - # add the dependency - ret_val = add_gem_dependency(dependencies_file, gem_target) - else: - # remove the dependency - ret_val = remove_gem_dependency(dependencies_file, gem_target) - else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - if runtime_dependency: - # make sure this is a project has a runtime_dependencies.cmake file - project_runtime_dependencies_file = pathlib.Path(get_dependencies_cmake(project_path, 'runtime', platform)) - if not project_runtime_dependencies_file.is_file(): - logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') - return 1 - - if add: - # add the dependency - ret_val = add_gem_dependency(project_runtime_dependencies_file, gem_target) - else: - # remove the dependency - ret_val = remove_gem_dependency(project_runtime_dependencies_file, gem_target) - - if (ret_val == 0 or not add) and tool_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_tool_dependencies_file = pathlib.Path(get_dependencies_cmake(project_path, 'tool', platform)) - if not project_tool_dependencies_file.is_file(): - logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') - return 1 - - if add: - # add the dependency - ret_val = add_gem_dependency(project_tool_dependencies_file, gem_target) - else: - # remove the dependency - ret_val = remove_gem_dependency(project_tool_dependencies_file, gem_target) - - if (ret_val == 0 or not add) and server_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_server_dependencies_file = pathlib.Path(get_dependencies_cmake(project_path, 'server', platform)) - if not project_server_dependencies_file.is_file(): - logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') - return 1 - - if add: - # add the dependency - ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) - else: - # remove the dependency - ret_val = remove_gem_dependency(project_server_dependencies_file, gem_target) - - if add: - # add the gem subdir to the CMakeList.txt - ret_val = add_gem_subdir(gem_cmake, gem_path.name) - elif gem_cmake: - # remove the gem subdir from the CMakeList.txt - ret_val = remove_gem_subdir(gem_cmake, gem_path.name) - - return ret_val - - -def _run_add_gem(args: argparse) -> int: - return add_remove_gem(True, - common.determine_engine_root(), - args.gem_path, - args.gem_target, - args.project_path, - args.dependencies_file, - args.project_restricted_path, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.add_to_cmake) - - -def _run_remove_gem(args: argparse) -> int: - return add_remove_gem(False, - common.determine_engine_root(), - args.gem_path, - args.gem_target, - args.project_path, - args.dependencies_file, - args.project_restricted_path, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.remove_from_cmake) - - -def add_args(parser, subparsers) -> None: - """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or aggregated by a central python file. - Ex. Directly run from this file alone with: python add_remove_gem.py add_gem --gem TestGem --project TestProject - OR - lmbr.py can aggregate commands by importing add_remove_gem, call add_args and - execute: python lmbr.py add_gem --gem TestGem --project TestProject - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here - """ - add_gem_subparser = subparsers.add_parser('add-gem') - add_gem_subparser.add_argument('-pp', '--project-path', type=str, required=True, - help='The path to the project, can be absolute or dev root relative') - add_gem_subparser.add_argument('-prp', '--project-restricted-path', type=str, required=False, - default='restricted', - help='The path to the projects restricted folder, can be absolute or dev root' - ' relative') - add_gem_subparser.add_argument('-gp', '--gem-path', type=str, required=True, - help='The path to the gem, can be absolute or dev root/Gems relative') - add_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - add_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' - 'If not specified it will assume ') - add_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a runtime dependency') - add_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a tool dependency') - add_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a server dependency') - add_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be added to.' - ' Ex. --platforms Mac,Windows,Linux') - add_gem_subparser.add_argument('-a', '--add-to-cmake', type=str, required=False, - default=None, - help='Add the gem folder to the CMakeLists.txt so that it builds. If not' - ' specified it will assume the CMakeLists.txt file in the parent folder of' - ' the gem_path.') - add_gem_subparser.set_defaults(func=_run_add_gem) - - remove_gem_subparser = subparsers.add_parser('remove-gem') - remove_gem_subparser.add_argument('-pp', '--project-path', type=str, required=True, - help='The path to the project, can be absolute or dev root relative') - remove_gem_subparser.add_argument('-prp', '--project-restricted-path', type=str, required=False, - default='restricted', - help='The path to the projects restricted folder, can be absolute or dev root' - ' relative') - remove_gem_subparser.add_argument('-gp', '--gem-path', type=str, required=True, - help='The path to the gem, can be absolute or dev root/Gems relative') - remove_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - remove_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' - 'If not specified it will assume ') - remove_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a runtime dependency') - remove_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be removed from' - ' Ex. --platforms Mac,Windows,Linux') - remove_gem_subparser.add_argument('-r', '--remove-from-cmake', type=str, required=False, - default=None, - help='Remove the gem folder from the CMakeLists.txt that includes it so that it ' - 'no longer builds build. If not specified it will assume you dont want to' - ' remove it.') - remove_gem_subparser.set_defaults(func=_run_remove_gem) - - -if __name__ == "__main__": - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') - - # add args to the parser - add_args(the_parser, the_subparsers) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) - - # return - sys.exit(ret) diff --git a/cmake/Tools/current_project.py b/cmake/Tools/current_project.py deleted file mode 100755 index 8be18fd3c9..0000000000 --- a/cmake/Tools/current_project.py +++ /dev/null @@ -1,117 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import argparse -import logging -import os -import sys -import re - -from cmake.Tools import common - -logger = logging.getLogger() -logging.basicConfig() - - -def set_current_project(dev_root: str, - project_path: str) -> int: - """ - set what the current project is - :param dev_root: the dev root of the engine - :param project_path: the path of the project you want to set - :return: 0 for success or non 0 failure code - """ - project_path = project_path.strip() - if not project_path.isalnum(): - logger.error('Project Name invalid. Set current project failed.') - return 1 - try: - with open(os.path.join(dev_root, 'bootstrap.cfg'), 'r') as s: - data = s.read() - data = re.sub(r'(.*project_path\s*?[=:]\s*?)([^\n]+)\n', r'\1 {}\n'.format(project_path), - data, flags=re.IGNORECASE) - if os.path.isfile(os.path.join(dev_root, 'bootstrap.cfg')): - os.unlink(os.path.join(dev_root, 'bootstrap.cfg')) - with open(os.path.join(dev_root, 'bootstrap.cfg'), 'w') as s: - s.write(data) - except Exception as e: - logger.error('Set current project failed.' + str(e)) - return 1 - return 0 - - -def get_current_project(dev_root: str) -> str: - """ - get what the current project set is - :param dev_root: the dev root of the engine - :return: project_path or None on failure - """ - try: - with open(os.path.join(dev_root, 'bootstrap.cfg'), 'r') as s: - data = s.read() - project_path = re.search(r'(.*project_path\s*?[=:]\s*?)(?P[^\n]+)\n', - data, flags=re.IGNORECASE).group('project_path').strip() - except Exception as e: - logger.error('Failed to get current project. Exception: ' + str(e)) - return '' - return project_path - - -def _run_get_current_project(args: argparse) -> int: - project_path = get_current_project(common.determine_engine_root()) - if project_path: - print(project_path) - return 0 - return 1 - - -def _run_set_current_project(args: argparse) -> int: - return set_current_project(common.determine_engine_root(), args.project_path) - - -def add_args(parser, subparsers) -> None: - """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or aggregated by a central python file. - Ex. Directly run from this file alone with: python current_project.py set_current_project --project TestProject - OR - lmbr.py can aggregate commands by importing current_project, call add_args and - execute: python lmbr.py set_current_project --project TestProject - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here - """ - get_current_project_subparser = subparsers.add_parser('get-current-project') - get_current_project_subparser.set_defaults(func=_run_get_current_project) - - set_current_project_subparser = subparsers.add_parser('set-current-project') - set_current_project_subparser.add_argument('-pp', '--project-path', required=True, - help='The path to the project, can be absolute or dev root relative') - set_current_project_subparser.set_defaults(func=_run_set_current_project) - - -if __name__ == "__main__": - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') - - # add args to the parser - add_args(the_parser, the_subparsers) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) - - # return - sys.exit(ret) diff --git a/cmake/Tools/engine_template.py b/cmake/Tools/engine_template.py index bf1ca93e57..eefb8c5541 100755 --- a/cmake/Tools/engine_template.py +++ b/cmake/Tools/engine_template.py @@ -21,7 +21,7 @@ import uuid import re from cmake.Tools import utils -from cmake.Tools import common +import cmake.Tools.registration as registration logger = logging.getLogger() logging.basicConfig() @@ -117,7 +117,7 @@ def _transform(s_data: str, end = t_data.find('{END_LICENSE}') end = t_data.find('\n', end) if end != -1: - t_data = t_data[:line_start] + t_data[end+1:] + t_data = t_data[:line_start] + t_data[end + 1:] ################################################################### return t_data @@ -131,8 +131,6 @@ def _transform_copy(source_file: str, :param source_file: the source file to be transformed :param destination_file: the destination file, this is the transformed file :param replacements: list of transformation pairs A->B - :param keep_restricted_in_instance: whether or not you want ot keep the templates restricted files in your instance - or separate them out into the restricted folder :param keep_license_text: whether or not you want to keep license text """ # if its a known binary type just copy it, else try to transform it. @@ -159,7 +157,7 @@ def _transform_copy(source_file: str, pass -def _execute_template_json(json_data: str, +def _execute_template_json(json_data: dict, destination_path: str, template_path: str, replacements: list, @@ -203,7 +201,7 @@ def _execute_template_json(json_data: str, shutil.copy(in_file, out_file) -def _execute_restricted_template_json(json_data: str, +def _execute_restricted_template_json(json_data: dict, restricted_platform: str, destination_name, template_name, @@ -215,11 +213,22 @@ def _execute_restricted_template_json(json_data: str, replacements: list, keep_restricted_in_instance: bool = False, keep_license_text: bool = False) -> None: + # if we are not keeping restricted in instance make restricted.json if not present + if not keep_restricted_in_instance: + restricted_json = f"{destination_restricted_path}/restricted.json".replace('//', '/') + os.makedirs(os.path.dirname(restricted_json), exist_ok=True) + if not os.path.isfile(restricted_json): + with open(restricted_json, 'w') as s: + restricted_json_data = {} + restricted_json_data.update({"restricted_name": destination_name}) + s.write(json.dumps(restricted_json_data, indent=4)) + # create dirs first # for each createDirectory entry, transform the folder name for create_directory in json_data['createDirectories']: # construct the new folder name - new_dir = f"{destination_restricted_path}/{restricted_platform}/{destination_restricted_platform_relative_path}/{destination_name}/{create_directory['dir']}".replace('//', '/') + new_dir = f"{destination_restricted_path}/{restricted_platform}/{destination_restricted_platform_relative_path}/{destination_name}/{create_directory['dir']}".replace( + '//', '/') if keep_restricted_in_instance: new_dir = f"{destination_path}/{create_directory['origin']}".replace('//', '/') @@ -233,7 +242,8 @@ def _execute_restricted_template_json(json_data: str, # regular copy if not templated for copy_file in json_data['copyFiles']: # construct the input file name - in_file = f"{template_restricted_path}/{restricted_platform}/{template_restricted_platform_relative_path}/{template_name}/Template/{copy_file['file']}".replace('//', '/') + in_file = f"{template_restricted_path}/{restricted_platform}/{template_restricted_platform_relative_path}/{template_name}/Template/{copy_file['file']}".replace( + '//', '/') # the file can be marked as optional, if it is and it does not exist skip if copy_file['isOptional'] and copy_file['isOptional'] == 'true': @@ -241,7 +251,8 @@ def _execute_restricted_template_json(json_data: str, continue # construct the output file name - out_file = f"{destination_restricted_path}/{restricted_platform}/{destination_restricted_platform_relative_path}/{destination_name}/{copy_file['file']}".replace('//', '/') + out_file = f"{destination_restricted_path}/{restricted_platform}/{destination_restricted_platform_relative_path}/{destination_name}/{copy_file['file']}".replace( + '//', '/') if keep_restricted_in_instance: out_file = f"{destination_path}/{copy_file['origin']}".replace('//', '/') @@ -258,7 +269,8 @@ def _execute_restricted_template_json(json_data: str, shutil.copy(in_file, out_file) -def _instantiate_template(destination_name: str, +def _instantiate_template(template_json_data: dict, + destination_name: str, template_name: str, destination_path: str, template_path: str, @@ -272,47 +284,47 @@ def _instantiate_template(destination_name: str, """ Internal function to create a concrete instance from a template - :param destination_path: the folder you want to instantiate the template in, absolute or dev_root relative + :param template_json_data: the template json data + :param destination_name: the name of folder you want to instantiate the template in + :param template_name: the name of the template + :param destination_path: the path you want to instantiate the template in :param template_path: the path of the template - :param template_path_rel: the relative path of the template + :param destination_restricted_path: the path of the restricted destination :param template_restricted_path: the path of the restricted template + :param destination_restricted_platform_relative_path: any path after the Platform of the restricted destination + :param template_restricted_platform_relative_path: any path after the Platform of the restricted template :param replacements: optional list of strings uses to make concrete names out of templated parameters. X->Y pairs Ex. ${Name},TestGem,${Player},TestGemPlayer This will cause all references to ${Name} be replaced by TestGem, and all ${Player} replaced by 'TestGemPlayer' - :param keep_restricted_in_instance: whether or not you want ot keep the templates restricted files in your instance + :param keep_restricted_in_instance: whether or not you want to keep the templates restricted files in your instance or separate them out into the restricted folder - :param keep_license_text: whether or not you want ot keep the templates license text in your instance. + :param keep_license_text: whether or not you want to keep the templates license text in your instance. template can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, this controls if you want to keep the license text from the template in the new instance. It is false by default - because most customers will not want license text in there instances, but we may want to keep them. + because most customers will not want license text in their instances, but we may want to keep them. :return: 0 for success or non 0 failure code """ - # make sure the template json is found - template_json = f'{template_path}/{template_file_name}' - if not os.path.isfile(template_json): - logger.error(f'Template json {template_json} not found.') - return 1 - - # load the template json and execute it - with open(template_json, 'r') as s: - try: - json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to load {template_json}: ' + str(e)) - return 1 - _execute_template_json(json_data, - destination_path, - template_path, - replacements, - keep_license_text) + # execute the template json + _execute_template_json(template_json_data, + destination_path, + template_path, + replacements, + keep_license_text) # execute restricted platform jsons if any - if os.path.isdir(template_restricted_path): + if template_restricted_path: for restricted_platform in os.listdir(template_restricted_path): + if os.path.isfile(restricted_platform): + continue template_restricted_platform = f'{template_restricted_path}/{restricted_platform}' template_restricted_platform_path_rel = f'{template_restricted_platform}/{template_restricted_platform_relative_path}/{template_name}' platform_json = f'{template_restricted_platform_path_rel}/{template_file_name}'.replace('//', '/') + if os.path.isfile(platform_json): + if not registration.valid_o3de_template_json(platform_json): + logger.error(f'Template json {platform_json} is invalid.') + return 1 + # load the template json and execute it with open(platform_json, 'r') as s: try: @@ -320,72 +332,64 @@ def _instantiate_template(destination_name: str, except Exception as e: logger.error(f'Failed to load {platform_json}: ' + str(e)) return 1 - _execute_restricted_template_json(json_data, - restricted_platform, - destination_name, - template_name, - destination_path, - destination_restricted_path, - template_restricted_path, - destination_restricted_platform_relative_path, - template_restricted_platform_relative_path, - replacements, - keep_restricted_in_instance, - keep_license_text) + else: + _execute_restricted_template_json(json_data, + restricted_platform, + destination_name, + template_name, + destination_path, + destination_restricted_path, + template_restricted_path, + destination_restricted_platform_relative_path, + template_restricted_platform_relative_path, + replacements, + keep_restricted_in_instance, + keep_license_text) return 0 -def create_template(dev_root: str, - source_path: str, +def create_template(source_path: str, template_path: str, - source_restricted_path: str, - template_restricted_path: str, - source_restricted_platform_relative_path: str, - template_restricted_platform_relative_path: str, + source_restricted_path: str = None, + source_restricted_name: str = None, + template_restricted_path: str = None, + template_restricted_name: str = None, + source_restricted_platform_relative_path: str = None, + template_restricted_platform_relative_path: str = None, keep_restricted_in_template: bool = False, keep_license_text: bool = False, replace: list = None) -> int: """ - Create a generic template from a source directory using replacement + Create a template from a source directory using replacement - :param dev_root: the path to dev root of the engine - :param source_path: source folder, absolute or dev_root relative - :param template_path: the path of the template to create, can be absolute or relative to dev root/Templates, if none - then it will be the source_name - :param source_restricted_path: path to the projects restricted folder + :param source_path: The path to the source that you want to make into a template + :param template_path: the path of the template to create, can be absolute or relative to default templates path + :param source_restricted_path: path to the source restricted folder + :param source_restricted_name: name of the source restricted folder :param template_restricted_path: path to the templates restricted folder + :param template_restricted_name: name of the templates restricted folder + :param source_restricted_platform_relative_path: any path after the platform in the source restricted + :param template_restricted_platform_relative_path: any path after the platform in the template restricted :param replace: optional list of strings uses to make templated parameters out of concrete names. X->Y pairs Ex. TestGem,${Name},TestGemPlayer,${Player} This will cause all references to 'TestGem' be replaced by ${Name}, and all 'TestGemPlayer' replaced by ${Player} Note these replacements are executed in order, so if you have larger matches, do them first, i.e. TestGemPlayer,${Player},TestGem,${Name} TestGemPlayer will get matched first and become ${Player} and will not become ${Name}Player - :param keep_restricted_in_template: whether or not you want ot keep the templates restricted in your template. - :param keep_license_text: whether or not you want ot keep the templates license text in your instance. - template can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, + :param keep_restricted_in_template: whether or not you want to keep the templates restricted in your template. + :param keep_license_text: whether or not you want to keep the templates license text in your instance. + Templated files can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, this controls if you want to keep the license text from the template in the new instance. It is false by default - because most customers will not want license text in there instances, but we may want to keep them. + because most people will not want license text in their instances. :return: 0 for success or non 0 failure code """ - # if no dev root error - if not dev_root: - logger.error('Dev root cannot be empty.') - return 1 - dev_root = dev_root.replace('\\', '/') - if not os.path.isabs(dev_root): - dev_root = os.path.abspath(dev_root) - if not os.path.isdir(dev_root): - logger.error(f'Dev root {dev_root} is not a folder.') - return 1 # if no src path error if not source_path: logger.error('Src path cannot be empty.') return 1 source_path = source_path.replace('\\', '/') - if not os.path.isabs(source_path): - source_path = f'{dev_root}/{source_path}' if not os.path.isdir(source_path): logger.error(f'Src path {source_path} is not a folder.') return 1 @@ -393,13 +397,15 @@ def create_template(dev_root: str, # source_name is now the last component of the source_path source_name = os.path.basename(source_path) - # if no new template path error + # if no template path, error if not template_path: - logger.warning('Template path empty. Using source name') + logger.info(f'Template path empty. Using source name {source_name}') template_path = source_name template_path = template_path.replace('\\', '/') if not os.path.isabs(template_path): - template_path = f'{dev_root}/Templates/{template_path}' + default_templates_folder = registration.get_registered(default_folder='templates') + template_path = f'{default_templates_folder}/{template_path}' + logger.info(f'Template path not a full path. Using default templates folder {template_path}') if os.path.isdir(template_path): logger.error(f'Template path {template_path} is already exists.') return 1 @@ -412,26 +418,85 @@ def create_template(dev_root: str, logger.error(f'Template path cannot be a restricted name. {template_name}') return 1 + if source_restricted_name and not source_restricted_path: + source_restricted_path = registration.get_registered(restricted_name=source_restricted_name) + # source_restricted_path - source_restricted_path = source_restricted_path.replace('\\', '/') - if not os.path.isabs(source_restricted_path): - source_restricted_path = f'{dev_root}/{source_restricted_path}' - if not os.path.isdir(source_restricted_path): - logger.error(f'Src restricted path {source_restricted_path} is not a folder.') - return 1 + if source_restricted_path: + source_restricted_path = source_restricted_path.replace('\\', '/') + if not os.path.isabs(source_restricted_path): + engine_json = f'{registration.get_this_engine_path()}/engine.json' + if not registration.valid_o3de_engine_json(engine_json): + logger.error(f"Engine json {engine_json} is not valid.") + return 1 + with open(engine_json) as s: + try: + engine_json_data = json.load(s) + except Exception as e: + logger.error(f"Failed to read engine json {engine_json}: {str(e)}") + return 1 + try: + engine_restricted = engine_json_data['restricted'] + except Exception as e: + logger.error(f"Engine json {engine_json} restricted not found.") + return 1 + engine_restricted_folder = registration.get_registered(restricted_name=engine_restricted) + new_source_restricted_path = f'{engine_restricted_folder}/{source_restricted_path}' + logger.info(f'Source restricted path {source_restricted_path} not a full path. We must assume this engines' + f' restricted folder {new_source_restricted_path}') + if not os.path.isdir(source_restricted_path): + logger.error(f'Source restricted path {source_restricted_path} is not a folder.') + return 1 + + if template_restricted_name and not template_restricted_path: + template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + + if not template_restricted_name: + template_restricted_name = template_name # template_restricted_path - template_restricted_path = template_restricted_path.replace('\\', '/') - if not os.path.isabs(template_restricted_path): - template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - os.makedirs(template_restricted_path) + if template_restricted_path: + template_restricted_path = template_restricted_path.replace('\\', '/') + if not os.path.isabs(template_restricted_path): + default_templates_restricted_folder = registration.get_registered(restricted_name='templates') + new_template_restricted_path = f'{default_templates_restricted_folder}/{template_restricted_path}' + logger.info(f'Template restricted path {template_restricted_path} not a full path. We must assume the' + f' default templates restricted folder {new_template_restricted_path}') + template_restricted_path = new_template_restricted_path + + if os.path.isdir(template_restricted_path): + # see if this is already a restricted path, if it is get the "restricted_name" from the restricted json + # so we can set "restricted" to it for this template + restricted_json = f'{template_restricted_path}/restricted.json' + if os.path.isfile(restricted_json): + if not registration.valid_o3de_restricted_json(restricted_json): + logger.error(f'{restricted_json} is not valid.') + return 1 + with open(restricted_json, 'r') as s: + try: + restricted_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load {restricted_json}: ' + str(e)) + return 1 + try: + template_restricted_name = restricted_json_data['restricted_name'] + except Exception as e: + logger.error(f'Failed to read restricted_name from {restricted_json}') + return 1 + else: + os.makedirs(template_restricted_path) # source restricted relative - source_restricted_platform_relative_path = source_restricted_platform_relative_path.replace('\\', '/') + if source_restricted_platform_relative_path: + source_restricted_platform_relative_path = source_restricted_platform_relative_path.replace('\\', '/') + else: + source_restricted_platform_relative_path = '' # template restricted relative - template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + if template_restricted_platform_relative_path: + template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + else: + template_restricted_platform_relative_path = '' logger.info(f'Processing Src: {source_path}') @@ -452,7 +517,7 @@ def create_template(dev_root: str, def _transform_into_template(s_data: object) -> (bool, object): """ Internal function to transform any data into templated data - :param source_data: the input data, this could be file data or file name data + :param s_data: the input data, this could be file data or file name data :return: bool: whether or not the returned data MAY need to be transformed to instantiate it t_data: potentially transformed data 0 for success or non 0 failure code """ @@ -507,7 +572,7 @@ def create_template(dev_root: str, platform: str) -> (bool, object): """ Internal function to transform a restricted platform file name into restricted template file name - :param source_data: the input data, this could be file data or file name data + :param s_data: the input data, this could be file data or file name data :return: bool: whether or not the returned data MAY need to be transformed to instantiate it t_data: potentially transformed data 0 for success or non 0 failure code """ @@ -581,14 +646,14 @@ def create_template(dev_root: str, else: after.append(components[x]) else: - for x in range(0, num_components-1): + for x in range(0, num_components - 1): relative += f'{components[x]}/' if os.path.isdir(f'{source_path}/{relative}'): before.append(components[x]) else: after.append(components[x]) - after.append(components[num_components-1]) + after.append(components[num_components - 1]) before.append("Platform") warn_if_not_platform = f'{source_path}/{"/".join(before)}' @@ -598,7 +663,8 @@ def create_template(dev_root: str, origin_entry_rel = '/'.join(before) if not os.path.isdir(warn_if_not_platform): - logger.warning(f'{entry_abs} -> {origin_entry_rel}: Other Platforms not found in {warn_if_not_platform}') + logger.warning( + f'{entry_abs} -> {origin_entry_rel}: Other Platforms not found in {warn_if_not_platform}') destination_entry_rel = origin_entry_rel destination_entry_abs = f'{template_path}/Template/{origin_entry_rel}' @@ -666,7 +732,8 @@ def create_template(dev_root: str, "dir": destination_entry_rel, "origin": origin_entry_rel }) - _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, root_abs, entry_abs) + _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, root_abs, + entry_abs) def _transform_dir_into_copyfiles_and_createdirs(root_abs: str, path_abs: str = None) -> None: @@ -722,6 +789,11 @@ def create_template(dev_root: str, # if not then create a normal relative and abs dst entry name _, origin_entry_rel = _transform_into_template(entry_rel) if platform and found_platform in restricted_platforms: + # if we don't have a template restricted path and we found restricted files... warn and skip + # the file/dir + if not template_restricted_path: + logger.warning("Restricted platform files found!!! {entry_rel}, {found_platform}") + continue _, destination_entry_rel = _transform_into_template_restricted_filename(entry_rel, found_platform) destination_entry_abs = f'{template_restricted_path}/{found_platform}/{template_restricted_platform_relative_path}/{template_name}/Template/{destination_entry_rel}' else: @@ -831,10 +903,13 @@ def create_template(dev_root: str, # every src may have a matching restricted folder per restricted platform # run the transformation on each src restricted folder - for restricted_platform in os.listdir(source_restricted_path): - restricted_platform_src_path_abs = f'{source_restricted_path}/{restricted_platform}/{source_restricted_platform_relative_path}/{source_name}'.replace('//', '/') - if os.path.isdir(restricted_platform_src_path_abs): - _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, restricted_platform_src_path_abs) + if source_restricted_path: + for restricted_platform in os.listdir(source_restricted_path): + restricted_platform_src_path_abs = f'{source_restricted_path}/{restricted_platform}/{source_restricted_platform_relative_path}/{source_name}'.replace( + '//', '/') + if os.path.isdir(restricted_platform_src_path_abs): + _transform_restricted_into_copyfiles_and_createdirs(source_path, restricted_platform, + restricted_platform_src_path_abs) # sort copy_files.sort(key=lambda x: x['file']) @@ -845,12 +920,17 @@ def create_template(dev_root: str, json_data = {} json_data.update({'template_name': template_name}) json_data.update({'origin': f'The primary repo for {template_name} goes here: i.e. http://www.mydomain.com'}) - json_data.update({'license': f'What license {template_name} uses goes here: i.e. https://opensource.org/licenses/MIT'}) + json_data.update( + {'license': f'What license {template_name} uses goes here: i.e. https://opensource.org/licenses/MIT'}) json_data.update({'display_name': template_name}) json_data.update({'summary': f"A short description of {template_name}."}) json_data.update({'canonical_tags': []}) json_data.update({'user_tags': [f"{template_name}"]}) json_data.update({'icon_path': "preview.png"}) + if template_restricted_path: + json_data.update({'restricted': template_restricted_name}) + if template_restricted_platform_relative_path != '': + json_data.update({'template_restricted_platform_relative_path': template_restricted_platform_relative_path}) json_data.update({'copyFiles': copy_files}) json_data.update({'createDirectories': create_dirs}) @@ -862,174 +942,289 @@ def create_template(dev_root: str, with open(json_name, 'w') as s: s.write(json.dumps(json_data, indent=4)) - #copy the default preview.png + # copy the default preview.png this_script_parent = os.path.dirname(os.path.realpath(__file__)) preview_png_src = f'{this_script_parent}/preview.png' preview_png_dst = f'{template_path}/Template/preview.png' if not os.path.isfile(preview_png_dst): shutil.copy(preview_png_src, preview_png_dst) - # now write out each restricted platform template json separately - for restricted_platform in restricted_platform_entries: - restricted_template_path = f'{template_restricted_path}/{restricted_platform}/{template_restricted_platform_relative_path}/{template_name}'.replace('//', '/') - - #sort - restricted_platform_entries[restricted_platform]['copyFiles'].sort(key=lambda x: x['file']) - restricted_platform_entries[restricted_platform]['createDirs'].sort(key=lambda x: x['dir']) - - json_data = {} - json_data.update({'template_name': template_name}) - json_data.update({'origin': f'The primary repo for {template_name} goes here: i.e. http://www.mydomain.com'}) - json_data.update({'license': f'What license {template_name} uses goes here: i.e. https://opensource.org/licenses/MIT'}) - json_data.update({'display_name': template_name}) - json_data.update({'summary': f"A short description of {template_name}."}) - json_data.update({'canonical_tags': []}) - json_data.update({'user_tags': [f'{template_name}']}) - json_data.update({'icon_path': "preview.png"}) - json_data.update({'copyFiles': restricted_platform_entries[restricted_platform]['copyFiles']}) - json_data.update({'createDirectories': restricted_platform_entries[restricted_platform]['createDirs']}) - - json_name = f'{restricted_template_path}/{template_file_name}' - os.makedirs(os.path.dirname(json_name), exist_ok=True) - - # if the json file we are about to write already exists for some reason, delete it - if os.path.isfile(json_name): - os.unlink(json_name) - with open(json_name, 'w') as s: - s.write(json.dumps(json_data, indent=4)) - - preview_png_dst = f'{restricted_template_path}/Template/preview.png' - if not os.path.isfile(preview_png_dst): - shutil.copy(preview_png_src, preview_png_dst) + # if no restricted template path was given and restricted platform files were found + if not template_restricted_path and len(restricted_platform_entries): + logger.info(f'Restricted platform files found!!! and no template restricted path was found...') + + if template_restricted_path: + # now write out each restricted platform template json separately + for restricted_platform in restricted_platform_entries: + restricted_template_path = f'{template_restricted_path}/{restricted_platform}/{template_restricted_platform_relative_path}/{template_name}'.replace( + '//', '/') + + # sort + restricted_platform_entries[restricted_platform]['copyFiles'].sort(key=lambda x: x['file']) + restricted_platform_entries[restricted_platform]['createDirs'].sort(key=lambda x: x['dir']) + + json_data = {} + json_data.update({'template_name': template_name}) + json_data.update( + {'origin': f'The primary repo for {template_name} goes here: i.e. http://www.mydomain.com'}) + json_data.update( + {'license': f'What license {template_name} uses goes here: i.e. https://opensource.org/licenses/MIT'}) + json_data.update({'display_name': template_name}) + json_data.update({'summary': f"A short description of {template_name}."}) + json_data.update({'canonical_tags': []}) + json_data.update({'user_tags': [f'{template_name}']}) + json_data.update({'icon_path': "preview.png"}) + json_data.update({'copyFiles': restricted_platform_entries[restricted_platform]['copyFiles']}) + json_data.update({'createDirectories': restricted_platform_entries[restricted_platform]['createDirs']}) + + json_name = f'{restricted_template_path}/{template_file_name}' + os.makedirs(os.path.dirname(json_name), exist_ok=True) + + # if the json file we are about to write already exists for some reason, delete it + if os.path.isfile(json_name): + os.unlink(json_name) + with open(json_name, 'w') as s: + s.write(json.dumps(json_data, indent=4)) + + preview_png_dst = f'{restricted_template_path}/Template/preview.png' + if not os.path.isfile(preview_png_dst): + shutil.copy(preview_png_src, preview_png_dst) return 0 -def find_all_gem_templates(template_folder_list: list) -> list: - """ - Find all subfolders in the given list of folders which appear to be gem templates - :param template_folder_list: List of folders to search - :return: list of tuples of TemplateName, AbsolutePath - """ - return find_all_templates(template_folder_list, 'gem.json') - - -def find_all_project_templates(template_folder_list: list) -> list: - """ - Find all subfolders in the given list of folders which appear to be project templates - :param template_folder_list: List of folders to search - :return: list of tuples of TemplateName, AbsolutePath - """ - return find_all_templates(template_folder_list, 'project.json') - - -def find_all_templates(template_folder_list: list, template_marker_file: str) -> list: - """ - Find all subfolders in the given list of folders which appear to be templates - :param template_folder_list: List of folders to search - :param template_marker_file: file expected in the template folder - :return: list of tuples of TemplateName, AbsolutePath - """ - templates_found = [] - for folder in template_folder_list: - for root, dirs, files in os.walk(folder): - for dir in dirs: - if os.path.isfile(os.path.join(root, dir, template_file_name)) and \ - os.path.isfile(os.path.join(root, dir, 'Template', template_marker_file)): - templates_found.append((dir, os.path.join(root, dir))) - break # We only want root folders containing templates, do not recurse - return templates_found - - -def create_from_template(dev_root: str, - destination_path: str, - template_path: str, - destination_restricted_path: str, - template_restricted_path: str, - destination_restricted_platform_relative_path: str, - template_restricted_platform_relative_path: str, +def create_from_template(destination_path: str, + template_path: str = None, + template_name: str = None, + destination_restricted_path: str = None, + destination_restricted_name: str = None, + template_restricted_path: str = None, + template_restricted_name: str = None, + destination_restricted_platform_relative_path: str = None, + template_restricted_platform_relative_path: str = None, keep_restricted_in_instance: bool = False, keep_license_text: bool = False, replace: list = None) -> int: """ - Generic template instantiation. - :param dev_root: the path to the dev root of the engine - :param destination_path: the folder you want to put the instantiate template in, absolute or dev_root relative - :param template_path: the name of the template you want to instance + Generic template instantiation for non o3de object templates. This function makes NO assumptions! + Assumptions are made only for specializations like create_project or create_gem etc... So this function + will NOT try to divine intent. + :param destination_path: the folder you want to instantiate the template into + :param template_path: the path to the template you want to instance + :param template_name: the name of the template you want to instance, resolves template_path :param destination_restricted_path: path to the projects restricted folder - :param template_restricted_path: path to the templates restricted folder - :param keep_restricted_in_instance: whether or not you want ot keep the templates restricted files in your instance + :param destination_restricted_name: name of the projects restricted folder, resolves destination_restricted_path + :param template_restricted_path: path of the templates restricted folder + :param template_restricted_name: name of the templates restricted folder, resolves template_restricted_path + :param destination_restricted_platform_relative_path: any path after the platform in the destination restricted + :param template_restricted_platform_relative_path: any path after the platform in the template restricted + :param keep_restricted_in_instance: whether or not you want to keep the templates restricted files in your instance or separate them out into the restricted folder - :param keep_license_text: whether or not you want ot keep the templates license text in your instance. + :param keep_license_text: whether or not you want to keep the templates license text in your instance. template can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, this controls if you want to keep the license text from the template in the new instance. It is false by default - because most customers will not want license text in there instances, but we may want to keep them. + because most customers will not want license text in their instances, but we may want to keep them. :param replace: optional list of strings uses to make concrete names out of templated parameters. X->Y pairs Ex. ${Name},TestGem,${Player},TestGemPlayer This will cause all references to ${Name} be replaced by TestGem, and all ${Player} replaced by 'TestGemPlayer' :return: 0 for success or non 0 failure code """ - # if no dev root error - if not dev_root: - logger.error('Dev root cannot be empty.') + if template_name and template_path: + logger.error(f'Template Name and Template Path provided, these are mutually exclusive.') return 1 - dev_root = dev_root.replace('\\', '/') - if not os.path.isabs(dev_root): - dev_root = os.path.abspath(dev_root) - if not os.path.isdir(dev_root): - logger.error(f'Dev root {dev_root} is not a folder.') + + if destination_restricted_name and destination_restricted_path: + logger.error(f'Destination Restricted Name and Destination Restricted Path provided, these are mutually' + f' exclusive.') return 1 - # if no destination_path error - if not destination_path: - logger.error('Dst path cannot be empty.') + if template_restricted_name and template_restricted_path: + logger.error(f'Template Restricted Name and Template Restricted Path provided, these are mutually exclusive.') return 1 - destination_path = destination_path.replace('\\', '/') - if not os.path.isabs(destination_path): - destination_path = f'{dev_root}/{destination_path}' - # dst name is now the last component of the destination_path - destination_name = os.path.basename(destination_path) + # need either the template name or path + if not template_path and not template_name: + logger.error(f'Template Name or Template Path must be specified.') + return 1 - # destination name cannot be the same as a restricted platform name - if destination_name in restricted_platforms: - logger.error(f'Destination path cannot be a restricted name. {destination_name}') + if template_name: + template_path = registration.get_registered(template_name=template_name) + + if not os.path.isdir(template_path): + logger.error(f'Could not find the template {template_name}=>{template_path}') return 1 - # if no template_path error - if not template_path: - logger.error('Template path cannot be empty.') + # template folder name is now the last component of the template_path + template_folder_name = os.path.basename(template_path) + + # the template.json should be in the template_path, make sure it's there a nd valid + template_json = f'{template_path}/template.json' + if not registration.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_path} is invalid.') return 1 - template_path = template_path.replace('\\', '/') - if not os.path.isabs(template_path): - template_path = f'{dev_root}/Templates/{template_path}' - if not os.path.isdir(template_path): - logger.error(f'Could not find the template {template_path}') + + # read in the template.json + with open(template_json) as s: + try: + template_json_data = json.load(s) + except Exception as e: + logger.error(f'Could read template json {template_json}: {str(e)}.') + return 1 + + # read template name from the json + try: + template_name = template_json_data['template_name'] + except Exception as e: + logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') return 1 - # template name is now the last component of the template_path - template_name = os.path.basename(template_path) + # if the user has not specified either a restricted name or restricted path + # see if the template itself specifies a restricted name + if not template_restricted_name and not template_restricted_path: + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".') + else: + template_restricted_name = template_json_restricted_name + + # if no restricted name or path we continue on as if there is no template restricted files. + if template_restricted_name or template_restricted_path: + # If the user specified a --template-restricted-name we need to check that against the templates + # 'restricted' if it has one and see if they match. If they match then we don't have a problem. + # If they don't then we error out. If supplied but not present in the template we warn and use it. + # If not supplied we set what's in the template. If not supplied and not in the template we continue + # on as if there is no template restricted files. + if template_restricted_name: + # The user specified a --template-restricted-name + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_name}') + else: + if template_json_restricted_name != template_restricted_name: + logger.error( + f'The supplied --template-restricted-name {template_restricted_name} does not match the' + f' templates "restricted". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') + + template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + else: + # The user has supplied the --template-restricted-path, see if that matches the template specifies. + # If it does then we do not have a problem. If it doesn't match then error out. If not specified + # in the template then warn and use the --template-restricted-path + template_restricted_path = template_restricted_path.replace('\\', '/') + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_path}') + else: + template_json_restricted_path = registration.get_registered( + restricted_name=template_json_restricted_name) + if template_json_restricted_path != template_restricted_path: + logger.error( + f'The supplied --template-restricted-path {template_restricted_path} does not match the' + f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' Either the the supplied --template-restricted-path is incorrect or the templates' + f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name} --template-restricted-path need not be supplied' + f' and {template_json_restricted_path} will be used.') + return 1 + + # check and make sure the restricted exists + if not os.path.isdir(template_restricted_path): + logger.error(f'Template restricted path {template_restricted_path} does not exist.') + return 1 - # destination_restricted_path - destination_restricted_path = destination_restricted_path.replace('\\', '/') - if not os.path.isabs(destination_restricted_path): - destination_restricted_path = f'{dev_root}/{destination_restricted_path}' - if not os.path.isdir(destination_restricted_path): - os.makedirs(destination_restricted_path) + # If the user specified a --template-restricted-platform-relative-path we need to check that against + # the templates 'restricted_platform_relative_path' and see if they match. If they match we don't have + # a problem. If they don't match then we error out. If supplied but not present in the template we warn + # and use --template-restricted-platform-relative-path. If not supplied we set what's in the template. + # If not supplied and not in the template set empty string. + if template_restricted_platform_relative_path: + # The user specified a --template-restricted-platform-relative-path + template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace( + '\\', '/') + try: + template_json_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it + logger.info(f'The template does not specify a "restricted_platform_relative_path".' + f' Using {template_restricted_platform_relative_path}') + else: + # the template has a 'restricted_platform_relative_path', if it matches we are fine, if not + # something is wrong with either the --template-restricted-platform-relative or the template is. + if template_restricted_platform_relative_path != template_json_restricted_platform_relative_path: + logger.error(f'The supplied --template-restricted-platform-relative-path does not match the' + f' templates "restricted_platform_relative_path". Either' + f' --template-restricted-platform-relative-path is incorrect or the templates' + f' "restricted_platform_relative_path" is wrong. Note that since this template' + f' specifies "restricted_platform_relative_path" it need not be supplied and' + f' {template_json_restricted_platform_relative_path} will be used.') + return 1 + else: + # The user has not supplied --template-restricted-platform-relative-path, try to read it from + # the template json. + try: + template_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. + template_restricted_platform_relative_path = '' - # template_restricted_path - template_restricted_path = template_restricted_path.replace('\\', '/') - if not os.path.isabs(template_restricted_path): - template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') + if not template_restricted_platform_relative_path: + template_restricted_platform_relative_path = '' + + # if no destination_path, error + if not destination_path: + logger.error('Destination path cannot be empty.') + return 1 + destination_path = destination_path.replace('\\', '/') + if os.path.isdir(destination_path): + logger.error(f'Destination path {destination_path} already exists.') return 1 + else: + os.makedirs(destination_path) - # destination restricted relative - destination_restricted_platform_relative_path = destination_restricted_platform_relative_path.replace('\\', '/') + # destination name is now the last component of the destination_path + destination_name = os.path.basename(destination_path) - # template restricted relative - template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + # destination name cannot be the same as a restricted platform name + if destination_name in restricted_platforms: + logger.error(f'Destination path cannot be a restricted name. {destination_name}') + return 1 + + # destination restricted name + if destination_restricted_name: + destination_restricted_path = registration.get_registered(restricted_name=destination_restricted_name) + + # destination restricted path + elif destination_restricted_path: + destination_restricted_path = destination_restricted_path.replace('\\', '/') + if os.path.isabs(destination_restricted_path): + restricted_default_path = registration.get_registered(default='restricted') + new_destination_restricted_path = f'{restricted_default_path}/{destination_restricted_path}' + logger.info(f'{destination_restricted_path} is not a full path, making it relative' + f' to default restricted path = {new_destination_restricted_path}') + destination_restricted_path = new_destination_restricted_path + elif template_restricted_path: + restricted_default_path = registration.get_registered(default='restricted') + logger.info(f'--destination-restricted-path is not specified, using default restricted path / destination name' + f' = {restricted_default_path}') + destination_restricted_path = restricted_default_path + + # destination restricted relative + if destination_restricted_platform_relative_path: + destination_restricted_platform_relative_path = destination_restricted_platform_relative_path.replace('\\', '/') + else: + destination_restricted_platform_relative_path = '' # any user supplied replacements replacements = list() @@ -1043,23 +1238,56 @@ def create_from_template(dev_root: str, replacements.append(("${NameUpper}", destination_name.upper())) replacements.append(("${NameLower}", destination_name.lower())) - return _instantiate_template(destination_name, - template_name, - destination_path, - template_path, - template_restricted_path, - replacements, - keep_restricted_in_instance, - keep_license_text) - - -def create_project(dev_root: str, - project_path: str, - template_path: str, - project_restricted_path: str = "restricted", - template_restricted_path: str = "restricted", - project_restricted_platform_relative_path: str or None = '', - template_restricted_platform_relative_path: str = "Templates", + if _instantiate_template(template_json_data, + destination_name, + template_name, + destination_path, + template_path, + destination_restricted_path, + template_restricted_path, + destination_restricted_platform_relative_path, + template_restricted_platform_relative_path, + replacements, + keep_restricted_in_instance, + keep_license_text): + logger.error(f'Instantiation of the template has failed.') + return 1 + + # We created the destination, now do anything extra that a destination requires + + # If we are not keeping the restricted in the destination read the destination restricted this might be a new + # restricted folder, so make sure the restricted has this destinations name + # Note there is no linking of non o3de objects to o3de restricted. So this will make no attempt to figure out + # if this destination was actually an o3de object and try to alter the .json + if not keep_restricted_in_instance: + if destination_restricted_path: + os.makedirs(destination_restricted_path, exist_ok=True) + + # read the restricted_name from the destination restricted.json + restricted_json = f"{destination_restricted_path}/restricted.json".replace('//', '/') + if not os.path.isfile(restricted_json): + with open(restricted_json, 'w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': destination_name}) + s.write(json.dumps(restricted_json_data, indent=4)) + + logger.warning(f'Instantiation successful. NOTE: This is a generic instantiation of the template. If this' + f' was a template of an o3de object like a project, gem, template, etc. then you should have used' + f' specialization that knows how to link that object type via its project.json or gem.json, etc.' + f' Create from template is meant only to instance a template of a non o3de object.') + + return 0 + + +def create_project(project_path: str, + template_path: str = None, + template_name: str = None, + project_restricted_path: str = None, + project_restricted_name: str = None, + template_restricted_path: str = None, + template_restricted_name: str = None, + project_restricted_platform_relative_path: str = None, + template_restricted_platform_relative_path: str = None, keep_restricted_in_project: bool = False, keep_license_text: bool = False, replace: list = None, @@ -1067,61 +1295,196 @@ def create_project(dev_root: str, editor_system_component_class_id: str = None, module_id: str = None) -> int: """ - Template instantiation that make all default assumptions for a Project template instantiation, reducing the effort - needed in instancing a project - :param dev_root: the path to the dev root of the engine - :param project_path: the project path, can be absolute or dev_root relative - :param template_path: the path to the template you want to instance, can be abs or relative, - defaults to DefaultProject - :param project_restricted_path: path to the projects restricted folder - :param template_restricted_path: path to the templates restricted folder - :param project_restricted_platform_relative_path: path to append to the project-restricted-path - :param template_restricted_platform_relative_path: path to append to the template_restricted_path - :param keep_restricted_in_project: whether or not you want ot keep the templates restricted files in your project or + Template instantiation specialization that makes all default assumptions for a Project template instantiation, + reducing the effort needed in instancing a project + :param project_path: the project path, can be absolute or relative to default projects path + :param template_path: the path to the template you want to instance, can be absolute or relative to default templates path + :param template_name: the name the registered template you want to instance, defaults to DefaultProject, resolves template_path + :param project_restricted_path: path to the projects restricted folder, can be absolute or relative to the restricted='projects' + :param project_restricted_name: name of the registered projects restricted path, resolves project_restricted_path + :param template_restricted_path: templates restricted path can be absolute or relative to restricted='templates' + :param template_restricted_name: name of the registered templates restricted path, resolves template_restricted_path + :param project_restricted_platform_relative_path: any path after the platform to append to the project_restricted_path + :param template_restricted_platform_relative_path: any path after the platform to append to the template_restricted_path + :param keep_restricted_in_project: whether or not you want to keep the templates restricted files in your project or separate them out into the restricted folder - :param keep_license_text: whether or not you want ot keep the templates license text in your instance. + :param keep_license_text: whether or not you want to keep the templates license text in your instance. template can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, this controls if you want to keep the license text from the template in the new instance. It is false by default - because most customers will not want license text in there instances, but we may want to keep them. + because most customers will not want license text in their instances, but we may want to keep them. :param replace: optional list of strings uses to make concrete names out of templated parameters. X->Y pairs Ex. ${Name},TestGem,${Player},TestGemPlayer This will cause all references to ${Name} be replaced by TestGem, and all ${Player} replaced by 'TestGemPlayer' :param system_component_class_id: optionally specify a uuid for the system component class, default is random uuid - :param editor_system_component_class_id: optionally specify a uuid for the editor system component class, default is random uuid + :param editor_system_component_class_id: optionally specify a uuid for the editor system component class, default is + random uuid :param module_id: optionally specify a uuid for the module class, default is random uuid :return: 0 for success or non 0 failure code """ - # if no dev root error - if not dev_root: - logger.error('Dev root cannot be empty.') + if template_name and template_path: + logger.error(f'Template Name and Template Path provided, these are mutually exclusive.') return 1 - dev_root = dev_root.replace('\\', '/') - if not os.path.isabs(dev_root): - dev_root = os.path.abspath(dev_root) - if not os.path.isdir(dev_root): - logger.error(f'Dev root {dev_root} is not a folder.') + + if project_restricted_name and project_restricted_path: + logger.error(f'Project Restricted Name and Project Restricted Path provided, these are mutually exclusive.') return 1 - if not template_path: - logger.error('Template path cannot be empty.') + if template_restricted_name and template_restricted_path: + logger.error(f'Template Restricted Name and Template Restricted Path provided, these are mutually exclusive.') return 1 - template_path = template_path.replace('\\', '/') - if not os.path.isabs(template_path): - template_path = f'{dev_root}/Templates/{template_path}' + + if not template_path and not template_name: + template_name = 'DefaultProject' + + if template_name and not template_path: + template_path = registration.get_registered(template_name=template_name) + if not os.path.isdir(template_path): - logger.error(f'Could not find the template {template_path}') + logger.error(f'Could not find the template {template_name}=>{template_path}') return 1 - # template name is now the last component of the template_path - template_name = os.path.basename(template_path) + # template folder name is now the last component of the template_path + template_folder_name = os.path.basename(template_path) + + # the template.json should be in the template_path, make sure it's there and valid + template_json = f'{template_path}/template.json' + if not registration.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_path} is not valid.') + return 1 + + # read in the template.json + with open(template_json) as s: + try: + template_json_data = json.load(s) + except Exception as e: + logger.error(f'Could read template json {template_json}: {str(e)}.') + return 1 + + # read template name from the json + try: + template_name = template_json_data['template_name'] + except Exception as e: + logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') + return 1 - # project path + # if the user has not specified either a restricted name or restricted path + # see if the template itself specifies a restricted name + if not template_restricted_name and not template_restricted_path: + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".') + else: + template_restricted_name = template_json_restricted_name + + # if no restricted name or path we continue on as if there is no template restricted files. + if template_restricted_name or template_restricted_path: + # If the user specified a --template-restricted-name we need to check that against the templates + # 'restricted' if it has one and see if they match. If they match then we don't have a problem. + # If they don't then we error out. If supplied but not present in the template we warn and use it. + # If not supplied we set what's in the template. If not supplied and not in the template we continue + # on as if there is no template restricted files. + if template_restricted_name and not template_restricted_path: + # The user specified a --template-restricted-name + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_name}') + else: + if template_json_restricted_name != template_restricted_name: + logger.error( + f'The supplied --template-restricted-name {template_restricted_name} does not match the' + f' templates "restricted". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') + + template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + else: + # The user has supplied the --template-restricted-path, see if that matches the template specifies. + # If it does then we do not have a problem. If it doesn't match then error out. If not specified + # in the template then warn and use the --template-restricted-path + template_restricted_path = template_restricted_path.replace('\\', '/') + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_path}') + else: + template_json_restricted_path = registration.get_registered( + restricted_name=template_json_restricted_name) + if template_json_restricted_path != template_restricted_path: + logger.error( + f'The supplied --template-restricted-path {template_restricted_path} does not match the' + f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' Either the the supplied --template-restricted-path is incorrect or the templates' + f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name} --template-restricted-path need not be supplied' + f' and {template_json_restricted_path} will be used.') + return 1 + + # check and make sure the restricted exists + if not os.path.isdir(template_restricted_path): + logger.error(f'Template restricted path {template_restricted_path} does not exist.') + return 1 + + # If the user specified a --template-restricted-platform-relative-path we need to check that against + # the templates 'restricted_platform_relative_path' and see if they match. If they match we don't have + # a problem. If they don't match then we error out. If supplied but not present in the template we warn + # and use --template-restricted-platform-relative-path. If not supplied we set what's in the template. + # If not supplied and not in the template set empty string. + if template_restricted_platform_relative_path: + # The user specified a --template-restricted-platform-relative-path + template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + try: + template_json_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it + logger.info(f'The template does not specify a "restricted_platform_relative_path".' + f' Using {template_restricted_platform_relative_path}') + else: + # the template has a 'restricted_platform_relative_path', if it matches we are fine, if not + # something is wrong with either the --template-restricted-platform-relative or the template is. + if template_restricted_platform_relative_path != template_json_restricted_platform_relative_path: + logger.error(f'The supplied --template-restricted-platform-relative-path does not match the' + f' templates "restricted_platform_relative_path". Either' + f' --template-restricted-platform-relative-path is incorrect or the templates' + f' "restricted_platform_relative_path" is wrong. Note that since this template' + f' specifies "restricted_platform_relative_path" it need not be supplied and' + f' {template_json_restricted_platform_relative_path} will be used.') + return 1 + else: + # The user has not supplied --template-restricted-platform-relative-path, try to read it from + # the template json. + try: + template_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. + template_restricted_platform_relative_path = '' + if not template_restricted_platform_relative_path: + template_restricted_platform_relative_path = '' + + # if no project path, error if not project_path: logger.error('Project path cannot be empty.') return 1 project_path = project_path.replace('\\', '/') if not os.path.isabs(project_path): - project_path = f'{dev_root}/{project_path}' + default_projects_folder = registration.get_registered(default_folder='projects') + new_project_path = f'{default_projects_folder}/{project_path}' + logger.info(f'Project Path {project_path} is not a full path, we must assume its relative' + f' to default projects path = {new_project_path}') + project_path = new_project_path + if os.path.isdir(project_path): + logger.error(f'Project path {project_path} already exists.') + return 1 + else: + os.makedirs(project_path) # project name is now the last component of the project_path project_name = os.path.basename(project_path) @@ -1131,26 +1494,30 @@ def create_project(dev_root: str, logger.error(f'Project path cannot be a restricted name. {project_name}') return 1 - # project_restricted_path - project_restricted_path = project_restricted_path.replace('\\', '/') - if not os.path.isabs(project_restricted_path): - project_restricted_path = f'{dev_root}/{project_restricted_path}' - if not os.path.isdir(project_restricted_path): - os.makedirs(project_restricted_path) - - # template_restricted_path - template_restricted_path = template_restricted_path.replace('\\', '/') - if not os.path.isabs(template_restricted_path): - template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 - - # project restricted relative - project_restricted_platform_relative_path = project_restricted_platform_relative_path.replace('\\', '/') - - # template restricted relative - template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + # project restricted name + if project_restricted_name and not project_restricted_path: + project_restricted_path = registration.get_registered(restricted_name=project_restricted_name) + + # project restricted path + elif project_restricted_path: + project_restricted_path = project_restricted_path.replace('\\', '/') + if not os.path.isabs(project_restricted_path): + default_projects_restricted_folder = registration.get_registered(restricted_name='projects') + new_project_restricted_path = f'{default_projects_restricted_folder}/{project_restricted_path}' + logger.info(f'Project restricted path {project_restricted_path} is not a full path, we must assume its' + f' relative to default projects restricted path = {new_project_restricted_path}') + project_restricted_path = new_project_restricted_path + elif template_restricted_path: + project_restricted_default_path = registration.get_registered(restricted_name='projects') + logger.info(f'--project-restricted-path is not specified, using default project restricted path / project name' + f' = {project_restricted_default_path}') + project_restricted_path = project_restricted_default_path + + # project restricted relative path + if project_restricted_platform_relative_path: + project_restricted_platform_relative_path = project_restricted_platform_relative_path.replace('\\', '/') + else: + project_restricted_platform_relative_path = '' # any user supplied replacements replacements = list() @@ -1185,14 +1552,15 @@ def create_project(dev_root: str, if editor_system_component_class_id: if '{' not in editor_system_component_class_id or '-' not in editor_system_component_class_id: logger.error( - f'Editor System component class id {editor_system_component_class_id} is malformed. Should look like Ex.' + - '{b60c92eb-3139-454b-a917-a9d3c5819594}') + f'Editor System component class id {editor_system_component_class_id} is malformed. Should look like' + f' Ex.' + '{b60c92eb-3139-454b-a917-a9d3c5819594}') return 1 replacements.append(("${EditorSysCompClassId}", editor_system_component_class_id)) else: replacements.append(("${EditorSysCompClassId}", '{' + str(uuid.uuid4()) + '}')) - if _instantiate_template(project_name, + if _instantiate_template(template_json_data, + project_name, template_name, project_path, template_path, @@ -1202,14 +1570,65 @@ def create_project(dev_root: str, template_restricted_platform_relative_path, replacements, keep_restricted_in_project, - keep_license_text) == 0: + keep_license_text): + logger.error(f'Instantiation of the template has failed.') + return 1 + + # We created the project, now do anything extra that a project requires - # we created the project, now do anything extra that a project requires + # If we are not keeping the restricted in the project read the name of the restricted folder from the + # restricted json and set that as this projects restricted + if not keep_restricted_in_project: + if project_restricted_path: + os.makedirs(project_restricted_path, exist_ok=True) + + # read the restricted_name from the projects restricted.json + restricted_json = f"{project_restricted_path}/restricted.json".replace('//', '/') + if os.path.isfile(restricted_json): + if not registration.valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return 1 + else: + with open(restricted_json, 'w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': project_name}) + s.write(json.dumps(restricted_json_data, indent=4)) + + with open(restricted_json, 'r') as s: + try: + restricted_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load restricted json {restricted_json}.') + return 1 + + try: + restricted_name = restricted_json_data["restricted_name"] + except Exception as e: + logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') + return 1 + + # set the "restricted": "restricted_name" element of the project.json + project_json = f"{project_path}/project.json".replace('//', '/') + if not registration.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + + with open(project_json, 'r') as s: + try: + project_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load project json {project_json}.') + return 1 + + project_json_data.update({"restricted": restricted_name}) + os.unlink(project_json) + with open(project_json, 'w') as s: + try: + s.write(json.dumps(project_json_data, indent=4)) + except Exception as e: + logger.error(f'Failed to write project json {project_json}.') + return 1 - # If we do not keep the restricted folders in the project then we have to make sure - # the restricted project folder has a CMakeLists.txt file in it so that when the restricted - # folders CMakeLists.txt is executed it will find a CMakeLists.txt in the restricted project root - if not keep_restricted_in_project: for restricted_platform in restricted_platforms: restricted_project = f'{project_restricted_path}/{restricted_platform}/{project_name}' os.makedirs(restricted_project, exist_ok=True) @@ -1218,25 +1637,38 @@ def create_project(dev_root: str, with open(cmakelists_file_name, 'w') as d: if keep_license_text: d.write('# {BEGIN_LICENSE}\n') - d.write('# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or\n') + d.write('# All or portions of this file Copyright (c) Amazon.com, Inc. or its' + ' affiliates or\n') d.write('# its licensors.\n') d.write('#\n') - d.write('# For complete copyright and license terms please see the LICENSE at the root of this\n') - d.write('# distribution (the "License"). All use of this software is governed by the License,\n') - d.write('# or, if provided, by the license below or the license accompanying this file. Do not\n') - d.write('# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,\n') + d.write('# For complete copyright and license terms please see the LICENSE at the' + ' root of this\n') + d.write('# distribution (the "License"). All use of this software is governed by' + ' the License,\n') + d.write('# or, if provided, by the license below or the license accompanying this' + ' file. Do not\n') + d.write('# remove or modify any license notices. This file is distributed on an' + ' "AS IS" BASIS,\n') d.write('# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n') d.write('# {END_LICENSE}\n') + + # copy the o3de_manifest.cmake into the project root + engine_path = registration.get_this_engine_path() + o3de_manifest_cmake = f'{engine_path}/cmake/o3de_manifest.cmake' + shutil.copy(o3de_manifest_cmake, project_path) + return 0 -def create_gem(dev_root: str, - gem_path: str, - template_path: str, - gem_restricted_path: str, - template_restricted_path: str, - gem_restricted_platform_relative_path: str or None, - template_restricted_platform_relative_path: str, +def create_gem(gem_path: str, + template_path: str = None, + template_name: str = None, + gem_restricted_path: str = None, + gem_restricted_name: str = None, + template_restricted_path: str = None, + template_restricted_name: str = None, + gem_restricted_platform_relative_path: str = None, + template_restricted_platform_relative_path: str = None, keep_restricted_in_gem: bool = False, keep_license_text: bool = False, replace: list = None, @@ -1244,46 +1676,194 @@ def create_gem(dev_root: str, editor_system_component_class_id: str = None, module_id: str = None) -> int: """ - Template instantiation that make all default assumptions for a Gem template instantiation, reducing the effort - needed in instancing a gem - :param dev_root: the path to the dev root of the engine - :param gem_path: the gem path, can be absolute or dev_root/Gems relative - :param gem_restricted_path: the gem restricted path, can be absolute or dev_root/Gems relative - :param template_path: the template path you want to instance, abs or dev_root/Templates relative, - defaults to DefaultGem - :param template_restricted_path: path to the templates restricted folder - :param keep_restricted_in_gem: whether or not you want ot keep the templates restricted files in your instance or - seperate them out into the restricted folder - :param keep_license_text: whether or not you want ot keep the templates license text in your instance. template can + Template instantiation specialization that makes all default assumptions for a Gem template instantiation, + reducing the effort needed in instancing a gem + :param gem_path: the gem path, can be absolute or relative to default gems path + :param template_path: the template path you want to instance, can be absolute or relative to default templates path + :param template_name: the name of the registered template you want to instance, defaults to DefaultGem, resolves template_path + :param gem_restricted_path: path to the gems restricted folder, can be absolute or relative to the restricted='gems' + :param gem_restricted_name: str = name of the registered gems restricted path, resolves gem_restricted_path + :param template_restricted_path: the templates restricted path, can be absolute or relative to the restricted='templates' + :param template_restricted_name: name of the registered templates restricted path, resolves template_restricted_path + :param gem_restricted_platform_relative_path: any path after the platform to append to the gem_restricted_path + :param template_restricted_platform_relative_path: any path after the platform to append to the template_restricted_path + :param keep_restricted_in_gem: whether or not you want to keep the templates restricted files in your instance or + separate them out into the restricted folder + :param keep_license_text: whether or not you want to keep the templates license text in your instance. template can have license blocks starting with {BEGIN_LICENSE} and ending with {END_LICENSE}, this controls if you want to keep the license text from the template in the new instance. It is false by default because most customers will not - want license text in there instances, but we may want to keep them. + want license text in their instances, but we may want to keep them. :param replace: optional list of strings uses to make concrete names out of templated parameters. X->Y pairs Ex. ${Name},TestGem,${Player},TestGemPlayer This will cause all references to ${Name} be replaced by TestGem, and all ${Player} replaced by 'TestGemPlayer' :param system_component_class_id: optionally specify a uuid for the system component class, default is random uuid - :param editor_system_component_class_id: optionally specify a uuid for the editor system component class, default is random uuid + :param editor_system_component_class_id: optionally specify a uuid for the editor system component class, default is + random uuid :param module_id: optionally specify a uuid for the module class, default is random uuid :return: 0 for success or non 0 failure code """ - # if no dev root error - if not dev_root: - logger.error('Dev root cannot be empty.') + if template_name and template_path: + logger.error(f'Template Name and Template Path provided, these are mutually exclusive.') + return 1 + + if gem_restricted_name and gem_restricted_path: + logger.error(f'Gem Restricted Name and Gem Restricted Path provided, these are mutually exclusive.') + return 1 + + if template_restricted_name and template_restricted_path: + logger.error(f'Template Restricted Name and Template Restricted Path provided, these are mutually exclusive.') + return 1 + + if not template_name and not template_path: + template_name = 'DefaultGem' + + if template_name and not template_path: + template_path = registration.get_registered(template_name=template_name) + + if not os.path.isdir(template_path): + logger.error(f'Could not find the template {template_name}=>{template_path}') + return 1 + + # template name is now the last component of the template_path + template_folder_name = os.path.basename(template_path) + + # the template.json should be in the template_path, make sure it's there and valid + template_json = f'{template_path}/template.json' + if not registration.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_path} is not valid.') return 1 - dev_root = dev_root.replace('\\', '/') - if not os.path.isabs(dev_root): - dev_root = os.path.abspath(dev_root) - if not os.path.isdir(dev_root): - logger.error(f'Dev root {dev_root} is not a folder.') + + # read in the template.json + with open(template_json) as s: + try: + template_json_data = json.load(s) + except Exception as e: + logger.error(f'Could read template json {template_json}: {str(e)}.') + return 1 + + # read template name from the json + try: + template_name = template_json_data['template_name'] + except Exception as e: + logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') return 1 - # if no destination_path error + # if the user has not specified either a restricted name or restricted path + # see if the template itself specifies a restricted name + if not template_restricted_name and not template_restricted_path: + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".') + else: + template_restricted_name = template_json_restricted_name + + # if no restricted name or path we continue on as if there is no template restricted files. + if template_restricted_name or template_restricted_path: + # if the user specified a --template-restricted-name we need to check that against the templates 'restricted' + # if it has one and see if they match. If they match then we don't have a problem. If they don't then we error + # out. If supplied but not present in the template we warn and use it. If not supplied we set what's in the + # template. If not supplied and not in the template we continue on as if there is no template restricted files. + if template_restricted_name and not template_restricted_path: + # The user specified a --template-restricted-name + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_name}') + else: + if template_json_restricted_name != template_restricted_name: + logger.error( + f'The supplied --template-restricted-name {template_restricted_name} does not match the' + f' templates "restricted". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') + + template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + else: + # The user has supplied the --template-restricted-path, see if that matches the template specifies. + # If it does then we do not have a problem. If it doesn't match then error out. If not specified + # in the template then warn and use the --template-restricted-path + template_restricted_path = template_restricted_path.replace('\\', '/') + try: + template_json_restricted_name = template_json_data['restricted'] + except Exception as e: + # the template json doesn't have a 'restricted' element warn and use it + logger.info(f'The template does not specify a "restricted".' + f' Using supplied {template_restricted_path}') + else: + template_json_restricted_path = registration.get_registered( + restricted_name=template_json_restricted_name) + if template_json_restricted_path != template_restricted_path: + logger.error( + f'The supplied --template-restricted-path {template_restricted_path} does not match the' + f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' Either the the supplied --template-restricted-path is incorrect or the templates' + f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' {template_json_restricted_name} --template-restricted-path need not be supplied' + f' and {template_json_restricted_path} will be used.') + return 1 + # check and make sure the restricted path exists + if not os.path.isdir(template_restricted_path): + logger.error(f'Template restricted path {template_restricted_path} does not exist.') + return 1 + + # If the user specified a --template-restricted-platform-relative-path we need to check that against + # the templates 'restricted_platform_relative_path' and see if they match. If they match we don't have + # a problem. If they don't match then we error out. If supplied but not present in the template we warn + # and use --template-restricted-platform-relative-path. If not supplied we set what's in the template. + # If not supplied and not in the template set empty string. + if template_restricted_platform_relative_path: + # The user specified a --template-restricted-platform-relative-path + template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + try: + template_json_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it + logger.info(f'The template does not specify a "restricted_platform_relative_path".' + f' Using {template_restricted_platform_relative_path}') + else: + # the template has a 'restricted_platform_relative_path', if it matches we are fine, if not something is + # wrong with either the --template-restricted-platform-relative or the template is + if template_restricted_platform_relative_path != template_json_restricted_platform_relative_path: + logger.error(f'The supplied --template-restricted-platform-relative-path does not match the' + f' templates "restricted_platform_relative_path". Either' + f' --template-restricted-platform-relative-path is incorrect or the templates' + f' "restricted_platform_relative_path" is wrong. Note that since this template' + f' specifies "restricted_platform_relative_path" it need not be supplied and' + f' {template_json_restricted_platform_relative_path} will be used.') + return 1 + else: + # The user has not supplied --template-restricted-platform-relative-path, try to read it from + # the template json. + try: + template_restricted_platform_relative_path = template_json_data[ + 'restricted_platform_relative_path'] + except Exception as e: + # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. + template_restricted_platform_relative_path = '' + if not template_restricted_platform_relative_path: + template_restricted_platform_relative_path = '' + + # if no gem_path, error if not gem_path: logger.error('Gem path cannot be empty.') return 1 gem_path = gem_path.replace('\\', '/') if not os.path.isabs(gem_path): - gem_path = f'{dev_root}/Gems/{gem_path}' + default_gems_folder = registration.get_registered(default_folder='gems') + new_gem_path = f'{default_gems_folder}/{gem_path}' + logger.info(f'Gem Path {gem_path} is not a full path, we must assume its relative' + f' to default gems path = {new_gem_path}') + gem_path = new_gem_path + if os.path.isdir(gem_path): + logger.error(f'Gem path {gem_path} already exists.') + return 1 + else: + os.makedirs(gem_path) # gem name is now the last component of the gem_path gem_name = os.path.basename(gem_path) @@ -1293,39 +1873,30 @@ def create_gem(dev_root: str, logger.error(f'Gem path cannot be a restricted name. {gem_name}') return 1 - if not template_path: - logger.error('Template path cannot be empty.') - return 1 - template_path = template_path.replace('\\', '/') - if not os.path.isabs(template_path): - template_path = f'{dev_root}/Templates/{template_path}' - if not os.path.isdir(template_path): - logger.error(f'Could not find the template {template_path}') - return 1 - - # template name is now the last component of the template_path - template_name = os.path.basename(template_path) - - # gem_restricted_path - gem_restricted_path = gem_restricted_path.replace('\\', '/') - if not os.path.isabs(gem_restricted_path): - gem_restricted_path = f'{dev_root}/{gem_restricted_path}' - if not os.path.isdir(gem_restricted_path): - os.makedirs(gem_restricted_path) - - # template_restricted_path - template_restricted_path = template_restricted_path.replace('\\', '/') - if not os.path.isabs(template_restricted_path): - template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 + # gem restricted name + if gem_restricted_name and not gem_restricted_path: + gem_restricted_path = registration.get_registered(restricted_name=gem_restricted_name) + + # gem restricted path + elif gem_restricted_path: + gem_restricted_path = gem_restricted_path.replace('\\', '/') + if not os.path.isabs(gem_restricted_path): + default_gems_restricted_folder = registration.get_registered(restricted_name='gems') + new_gem_restricted_path = f'{default_gems_restricted_folder}/{gem_restricted_path}' + logger.info(f'Gem restricted path {gem_restricted_path} is not a full path, we must assume its' + f' relative to default gems restricted path = {new_gem_restricted_path}') + gem_restricted_path = new_gem_restricted_path + elif template_restricted_path: + gem_restricted_default_path = registration.get_registered(restricted_name='gems') + logger.info(f'--gem-restricted-path is not specified, using default gem restricted path / gem name' + f' = {gem_restricted_default_path}') + gem_restricted_path = gem_restricted_default_path # gem restricted relative - gem_restricted_platform_relative_path = gem_restricted_platform_relative_path.replace('\\', '/') - - # template restricted relative - template_restricted_platform_relative_path = template_restricted_platform_relative_path.replace('\\', '/') + if gem_restricted_platform_relative_path: + gem_restricted_platform_relative_path = gem_restricted_platform_relative_path.replace('\\', '/') + else: + gem_restricted_platform_relative_path = '' # any user supplied replacements replacements = list() @@ -1360,32 +1931,115 @@ def create_gem(dev_root: str, if editor_system_component_class_id: if '{' not in editor_system_component_class_id or '-' not in editor_system_component_class_id: logger.error( - f'Editor System component class id {editor_system_component_class_id} is malformed. Should look like Ex.' + - '{b60c92eb-3139-454b-a917-a9d3c5819594}') + f'Editor System component class id {editor_system_component_class_id} is malformed. Should look like' + f' Ex.' + '{b60c92eb-3139-454b-a917-a9d3c5819594}') return 1 replacements.append(("${EditorSysCompClassId}", editor_system_component_class_id)) else: replacements.append(("${EditorSysCompClassId}", '{' + str(uuid.uuid4()) + '}')) - return _instantiate_template(gem_name, - template_name, - gem_path, - template_path, - gem_restricted_path, - template_restricted_path, - gem_restricted_platform_relative_path, - template_restricted_platform_relative_path, - replacements, - keep_restricted_in_gem, - keep_license_text) + if _instantiate_template(template_json_data, + gem_name, + template_name, + gem_path, + template_path, + gem_restricted_path, + template_restricted_path, + gem_restricted_platform_relative_path, + template_restricted_platform_relative_path, + replacements, + keep_restricted_in_gem, + keep_license_text): + logger.error(f'Instantiation of the template has failed.') + return 1 + + # We created the gem, now do anything extra that a gem requires + + # If we are not keeping the restricted in the gem read the name of the restricted folder from the + # restricted json and set that as this gems restricted + if not keep_restricted_in_gem: + if gem_restricted_path: + os.makedirs(gem_restricted_path, exist_ok=True) + + # read the restricted_name from the gems restricted.json + restricted_json = f"{gem_restricted_path}/restricted.json".replace('//', '/') + if os.path.isfile(restricted_json): + if not registration.valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return 1 + else: + with open(restricted_json, 'w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': gem_name}) + s.write(json.dumps(restricted_json_data, indent=4)) + + with open(restricted_json, 'r') as s: + try: + restricted_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load restricted json {restricted_json}.') + return 1 + + try: + restricted_name = restricted_json_data["restricted_name"] + except Exception as e: + logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') + return 1 + + # set the "restricted": "restricted_name" element of the gem.json + gem_json = f"{gem_path}/gem.json".replace('//', '/') + if not registration.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + with open(gem_json, 'r') as s: + try: + gem_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load gem json {gem_json}.') + return 1 + + gem_json_data.update({"restricted": restricted_name}) + os.unlink(gem_json) + with open(gem_json, 'w') as s: + try: + s.write(json.dumps(gem_json_data, indent=4)) + except Exception as e: + logger.error(f'Failed to write project json {gem_json}.') + return 1 + + for restricted_platform in restricted_platforms: + restricted_gem = f'{gem_restricted_path}/{restricted_platform}/{gem_name}' + os.makedirs(restricted_gem, exist_ok=True) + cmakelists_file_name = f'{restricted_gem}/CMakeLists.txt' + if not os.path.isfile(cmakelists_file_name): + with open(cmakelists_file_name, 'w') as d: + if keep_license_text: + d.write('# {BEGIN_LICENSE}\n') + d.write( + '# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or\n') + d.write('# its licensors.\n') + d.write('#\n') + d.write( + '# For complete copyright and license terms please see the LICENSE at the root of this\n') + d.write( + '# distribution (the "License"). All use of this software is governed by the License,\n') + d.write( + '# or, if provided, by the license below or the license accompanying this file. Do not\n') + d.write( + '# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,\n') + d.write('# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n') + d.write('# {END_LICENSE}\n') + return 0 def _run_create_template(args: argparse) -> int: - return create_template(common.determine_engine_root(), - args.source_path, + return create_template(args.source_path, args.template_path, args.source_restricted_path, + args.source_restricted_name, args.template_restricted_path, + args.template_restricted_name, args.source_restricted_platform_relative_path, args.template_restricted_platform_relative_path, args.keep_restricted_in_template, @@ -1394,11 +2048,13 @@ def _run_create_template(args: argparse) -> int: def _run_create_from_template(args: argparse) -> int: - return create_from_template(common.determine_engine_root(), - args.destination_path, + return create_from_template(args.destination_path, args.template_path, + args.template_name, args.destination_restricted_path, + args.destination_restricted_name, args.template_restricted_path, + args.template_restricted_name, args.destination_restricted_platform_relative_path, args.template_restricted_platform_relative_path, args.keep_restricted_in_instance, @@ -1407,11 +2063,13 @@ def _run_create_from_template(args: argparse) -> int: def _run_create_project(args: argparse) -> int: - return create_project(common.determine_engine_root(), - args.project_path, + return create_project(args.project_path, args.template_path, + args.template_name, args.project_restricted_path, + args.project_restricted_name, args.template_restricted_path, + args.template_restricted_name, args.project_restricted_platform_relative_path, args.template_restricted_platform_relative_path, args.keep_restricted_in_project, @@ -1423,11 +2081,13 @@ def _run_create_project(args: argparse) -> int: def _run_create_gem(args: argparse) -> int: - return create_gem(common.determine_engine_root(), - args.gem_path, + return create_gem(args.gem_path, args.template_path, + args.template_name, args.gem_restricted_path, + args.gem_restricted_name, args.template_restricted_path, + args.template_restricted_name, args.gem_restricted_platform_relative_path, args.template_restricted_platform_relative_path, args.keep_restricted_in_gem, @@ -1452,49 +2112,55 @@ def add_args(parser, subparsers) -> None: # turn a directory into a template create_template_subparser = subparsers.add_parser('create-template') create_template_subparser.add_argument('-sp', '--source-path', type=str, required=True, - help='The path to the source that you want to make into a template,' - ' can be absolute or dev root relative.' - 'Ex. C:/o3de/Test' - 'Test = ') - create_template_subparser.add_argument('-srp', '--source-restricted-path', type=str, required=False, - default='restricted', - help='The path to the src restricted folder if any to read from, can be' - ' absolute or dev root relative, default is the dev root/restricted.') - create_template_subparser.add_argument('-srprp', '--source-restricted-platform-relative-path', type=str, required=False, - default='', + help='The path to the source that you want to make into a template') + create_template_subparser.add_argument('-tp', '--template-path', type=str, required=False, + help='The path to the template to create, can be absolute or relative' + ' to default templates path') + group = create_template_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-srp', '--source-restricted-path', type=str, required=False, + default=None, + help='The path to the source restricted folder.') + group.add_argument('-srn', '--source-restricted-name', type=str, required=False, + default=None, + help='The name of the source restricted folder. If supplied this will resolve' + ' the --source-restricted-path.') + + group = create_template_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-trp', '--template-restricted-path', type=str, required=False, + default=None, + help='The path to the templates restricted folder.') + group.add_argument('-trn', '--template-restricted-name', type=str, required=False, + default=None, + help='The name of the templates restricted folder. If supplied this will resolve' + ' the --template-restricted-path.') + + create_template_subparser.add_argument('-srprp', '--source-restricted-platform-relative-path', type=str, + required=False, + default=None, help='Any path to append to the --source-restricted-path/' - ' to where the restricted source is.' + ' to where the restricted source is. EX.' ' --source-restricted-path C:/restricted' ' --source-restricted-platform-relative-path some/folder' ' => C:/restricted//some/folder/') - create_template_subparser.add_argument('-tp', '--template-path', type=str, required=False, - help='The path to the template you wish to create,' - ' can be absolute or dev root/Templates relative, default is' - ' source_name which is the last component of source path' - ' Ex. C:/o3de/TestTemplate' - ' Test = ') - create_template_subparser.add_argument('-trp', '--template-restricted-path', type=str, required=False, - default='restricted', - help='The path to where to put the templates restricted folders write to if' - ' any, can be absolute or dev root relative, default is' - ' dev root/restricted.') create_template_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', type=str, - required=False, - default='Templates', - help='Any path to append to the --template-restricted-path/' - ' to where the restricted template source is.' - ' --template-restricted-path C:/restricted' - ' --template-restricted-platform-relative-path some/folder' - ' => C:/restricted//some/folder/') + required=False, + default=None, + help='Any path to append to the --template-restricted-path/' + ' to where the restricted template source is.' + ' --template-restricted-path C:/restricted' + ' --template-restricted-platform-relative-path some/folder' + ' => C:/restricted//some/folder/') create_template_subparser.add_argument('-kr', '--keep-restricted-in-template', action='store_true', default=False, help='Should the template keep the restricted platforms in the template, or' ' create the restricted files in the restricted folder, default is' - ' False') + ' False so it will create a restricted folder by default') create_template_subparser.add_argument('-kl', '--keep-license-text', action='store_true', default=False, - help='Should license text be kept in the instantiation,' - ' default is False') + help='Should license in the template files text be kept in the' + ' instantiation, default is False, so will not keep license text' + ' by default. License text is defined as all lines of text starting' + ' on a line with {BEGIN_LICENSE} and ending line {END_LICENSE}.') create_template_subparser.add_argument('-r', '--replace', type=str, required=False, nargs='*', help='String that specifies A->B replacement pairs.' @@ -1505,34 +2171,51 @@ def add_args(parser, subparsers) -> None: ' Note: is automatically ${NameUpper}') create_template_subparser.set_defaults(func=_run_create_template) - # creation from a template + # create from template create_from_template_subparser = subparsers.add_parser('create-from-template') create_from_template_subparser.add_argument('-dp', '--destination-path', type=str, required=True, help='The path to where you want the template instantiated,' ' can be absolute or dev root relative.' 'Ex. C:/o3de/Test' 'Test = ') - create_from_template_subparser.add_argument('-drp', '--destination-restricted-path', type=str, required=False, - default='restricted', - help='The path to the dst restricted folder to read from if any, can be' - ' absolute or dev root relative. default is dev root/restricted') - create_from_template_subparser.add_argument('-drprp', '--destination-restricted-platform-relative-path', type=str, required=False, + + group = create_from_template_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-tp', '--template-path', type=str, required=False, + help='The path to the template you want to instantiate, can be absolute' + ' or dev root/Templates relative.' + 'Ex. C:/o3de/Template/TestTemplate' + 'TestTemplate = ') + group.add_argument('-tn', '--template-name', type=str, required=False, + help='The name to the registered template you want to instantiate. If supplied this will' + ' resolve the --template-path.') + + group = create_from_template_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-drp', '--destination-restricted-path', type=str, required=False, + default=None, + help='The destination restricted path is where the restricted files' + ' will be written to.') + group.add_argument('-drn', '--destination-restricted-name', type=str, required=False, + default=None, + help='The name the registered restricted path where the restricted files' + ' will be written to. If supplied this will resolve the --destination-restricted-path.') + + group = create_from_template_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-trp', '--template-restricted-path', type=str, required=False, + default=None, + help='The template restricted path to read from if any') + group.add_argument('-trn', '--template-restricted-name', type=str, required=False, + default=None, + help='The name of the registered restricted path to read from if any. If supplied this will' + ' resolve the --template-restricted-path.') + + create_from_template_subparser.add_argument('-drprp', '--destination-restricted-platform-relative-path', type=str, + required=False, default='', help='Any path to append to the --destination-restricted-path/' - ' to where the restricted destination is.' - ' --destination-restricted-path C:/instance' - ' --destination-restricted-platform-relative-path some/folder' - ' => C:/instance//some/folder/') - create_from_template_subparser.add_argument('-tp', '--template-path', type=str, required=True, - help='The path to the template you want to instantiate, can be absolute' - ' or dev root/Templates relative.' - 'Ex. C:/o3de/Template/TestTemplate' - 'TestTemplate = ') - create_from_template_subparser.add_argument('-trp', '--template-restricted-path', type=str, required=False, - default='restricted', - help='The path to the template restricted folder to write to if any,' - ' can be absolute or dev root relative, default is' - ' dev root/restricted') + ' to where the restricted destination is.' + ' --destination-restricted-path C:/instance' + ' --destination-restricted-platform-relative-path some/folder' + ' => C:/instance//some/folder/') create_from_template_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', type=str, required=False, default='Templates', @@ -1548,8 +2231,10 @@ def add_args(parser, subparsers) -> None: ' is False') create_from_template_subparser.add_argument('-kl', '--keep-license-text', action='store_true', default=False, - help='Should license text be kept in the instantiation,' - ' default is False') + help='Should license in the template files text be kept in the instantiation,' + ' default is False, so will not keep license text by default.' + ' License text is defined as all lines of text starting on a line' + ' with {BEGIN_LICENSE} and ending line {END_LICENSE}.') create_from_template_subparser.add_argument('-r', '--replace', type=str, required=False, nargs='*', help='String that specifies A->B replacement pairs.' @@ -1567,31 +2252,48 @@ def add_args(parser, subparsers) -> None: ' can be an absolute path or dev root relative.' ' Ex. C:/o3de/TestProject' ' TestProject = ') - create_project_subparser.add_argument('-prp', '--project-restricted-path', type=str, required=False, - default='restricted', - help='The path to the project restricted folder to write to if any, can be' - ' absolute or dev root relative, default is dev root/restricted') + + group = create_project_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-tp', '--template-path', type=str, required=False, + default=None, + help='the path to the template you want to instance, can be absolute or' + ' relative to default templates path') + group.add_argument('-tn', '--template-name', type=str, required=False, + default=None, + help='The name the registered template you want to instance, defaults' + ' to DefaultProject. If supplied this will resolve the --template-path.') + + group = create_project_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-prp', '--project-restricted-path', type=str, required=False, + default=None, + help='path to the projects restricted folder, can be absolute or relative' + ' to the restricted="projects"') + group.add_argument('-prn', '--project-restricted-name', type=str, required=False, + default=None, + help='The name of the registered projects restricted path. If supplied this will resolve' + ' the --project-restricted-path.') + + group = create_project_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-trp', '--template-restricted-path', type=str, required=False, + default=None, + help='The templates restricted path can be absolute or relative to' + ' restricted="templates"') + group.add_argument('-trn', '--template-restricted-name', type=str, required=False, + default=None, + help='The name of the registered templates restricted path. If supplied this will resolve' + ' the --template-restricted-path.') + create_project_subparser.add_argument('-prprp', '--project-restricted-platform-relative-path', type=str, required=False, - default='', + default=None, help='Any path to append to the --project-restricted-path/' ' to where the restricted project is.' ' --project-restricted-path C:/restricted' ' --project-restricted-platform-relative-path some/folder' ' => C:/restricted//some/folder/') - create_project_subparser.add_argument('-tp', '--template-path', type=str, required=False, - default='DefaultProject', - help='The path to the template you want to instantiate, can be absolute' - ' or dev root/Templates relative, defaults to the DefaultProject.' - ' Ex. C:/o3de/Template/TestTemplate' - ' TestTemplate = ') - create_project_subparser.add_argument('-trp', '--template-restricted-path', type=str, required=False, - default='restricted', - help='The path to the template restricted folder to read from if any, can be' - ' absolute or dev root relative, default is dev root/restricted') create_project_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', type=str, required=False, - default='Templates', + default=None, help='Any path to append to the --template-restricted-path/' ' to where the restricted template is.' ' --template-restricted-path C:/restricted' @@ -1603,7 +2305,10 @@ def add_args(parser, subparsers) -> None: 'create the restricted files in the restricted folder, default is False') create_project_subparser.add_argument('-kl', '--keep-license-text', action='store_true', default=False, - help='Should license text be kept in the instantiation, default is False') + help='Should license in the template files text be kept in the instantiation,' + ' default is False, so will not keep license text by default.' + ' License text is defined as all lines of text starting on a line' + ' with {BEGIN_LICENSE} and ending line {END_LICENSE}.') create_project_subparser.add_argument('-r', '--replace', required=False, nargs='*', help='String that specifies ADDITIONAL A->B replacement pairs. ${Name} and' @@ -1618,9 +2323,10 @@ def add_args(parser, subparsers) -> None: create_project_subparser.add_argument('--system-component-class-id', type=utils.validate_uuid4, required=False, help='The uuid you want to associate with the system class component, default' ' is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') - create_project_subparser.add_argument('--editor-system-component-class-id', type=utils.validate_uuid4, required=False, - help='The uuid you want to associate with the editor system class component, default' - ' is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') + create_project_subparser.add_argument('--editor-system-component-class-id', type=utils.validate_uuid4, + required=False, + help='The uuid you want to associate with the editor system class component,' + ' default is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') create_project_subparser.add_argument('--module-id', type=utils.validate_uuid4, required=False, help='The uuid you want to associate with the module, default is a random' ' uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') @@ -1629,33 +2335,50 @@ def add_args(parser, subparsers) -> None: # creation of a gem from a template (like create from template but makes gem assumptions) create_gem_subparser = subparsers.add_parser('create-gem') create_gem_subparser.add_argument('-gp', '--gem-path', type=str, required=True, - help='The path to the gem you want to create, can be absolute or dev root/Gems' - ' relative.' - ' Ex. C:/o3de/TestGem' - ' TestGem = ') - create_gem_subparser.add_argument('-grp', '--gem-restricted-path', type=str, required=False, - default='restricted', - help='The path to the gem restricted to write to folder if any, can be' - 'absolute or dev root relative, default is dev root/restricted.') + help='The gem path, can be absolute or relative to default gems path') + + group = create_gem_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-tp', '--template-path', type=str, required=False, + default=None, + help='The template path you want to instance, can be absolute or relative' + ' to default templates path') + group.add_argument('-tn', '--template-name', type=str, required=False, + default=None, + help='The name of the registered template you want to instance, defaults' + ' to DefaultGem. If supplied this will resolve the --template-path.') + + group = create_gem_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-grp', '--gem-restricted-path', type=str, required=False, + default=None, + help='The path to the gem restricted to write to folder if any, can be' + 'absolute or dev root relative, default is dev root/restricted.') + group.add_argument('-grn', '--gem-restricted-name', type=str, required=False, + default=None, + help='The path to the gem restricted to write to folder if any, can be' + 'absolute or dev root relative, default is dev root/restricted. If supplied' + ' this will resolve the --gem-restricted-path.') + + group = create_gem_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-trp', '--template-restricted-path', type=str, required=False, + default=None, + help='The templates restricted path, can be absolute or relative to' + ' the restricted="templates"') + group.add_argument('-trn', '--template-restricted-name', type=str, required=False, + default=None, + help='The name of the registered templates restricted path. If supplied' + ' this will resolve the --template-restricted-path.') + create_gem_subparser.add_argument('-grprp', '--gem-restricted-platform-relative-path', type=str, required=False, - default='Gems', + default=None, help='Any path to append to the --gem-restricted-path/' ' to where the restricted template is.' ' --gem-restricted-path C:/restricted' ' --gem-restricted-platform-relative-path some/folder' ' => C:/restricted//some/folder/') - create_gem_subparser.add_argument('-tp', '--template-path', type=str, required=False, - default='DefaultGem', - help='The path to the template you want to instantiate, can be absolute or' - ' relative to the dev root/Templates. Default is DefaultGem.') - create_gem_subparser.add_argument('-trp', '--template-restricted-path', type=str, required=False, - default='restricted', - help='The path to the gem restricted folder to read from if any, can be' - 'absolute or dev root relative, default is dev root/restricted.') create_gem_subparser.add_argument('-trprp', '--template-restricted-platform-relative-path', type=str, required=False, - default='Templates', + default=None, help='Any path to append to the --template-restricted-path/' ' to where the restricted template is.' ' --template-restricted-path C:/restricted' @@ -1678,14 +2401,17 @@ def add_args(parser, subparsers) -> None: 'create the restricted files in the restricted folder, default is False') create_gem_subparser.add_argument('-kl', '--keep-license-text', action='store_true', default=False, - help='Should license text be kept in the instantiation, default is False') + help='Should license in the template files text be kept in the instantiation,' + ' default is False, so will not keep license text by default.' + ' License text is defined as all lines of text starting on a line' + ' with {BEGIN_LICENSE} and ending line {END_LICENSE}.') create_gem_subparser.add_argument('--system-component-class-id', type=utils.validate_uuid4, required=False, help='The uuid you want to associate with the system class component, default' ' is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') create_gem_subparser.add_argument('--editor-system-component-class-id', type=utils.validate_uuid4, required=False, - help='The uuid you want to associate with the editor system class component, default' - ' is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') + help='The uuid you want to associate with the editor system class component,' + ' default is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') create_gem_subparser.add_argument('--module-id', type=utils.validate_uuid4, required=False, help='The uuid you want to associate with the gem module,' ' default is a random uuid Ex. {b60c92eb-3139-454b-a917-a9d3c5819594}') diff --git a/cmake/Tools/global_project.py b/cmake/Tools/global_project.py new file mode 100644 index 0000000000..1d84d9dcfb --- /dev/null +++ b/cmake/Tools/global_project.py @@ -0,0 +1,168 @@ +# +# 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. +# + +import argparse +import logging +import os +import sys +import re +import pathlib +import json +import cmake.Tools.registration as registration + +logger = logging.getLogger() +logging.basicConfig() + + +def set_global_project(project_name: str or None, + project_path: str or pathlib.Path or None) -> int: + """ + set what the current project is + :param project_name: the name of the project you want to set, resolves project_path + :param project_path: the path of the project you want to set + :return: 0 for success or non 0 failure code + """ + if project_path and project_name: + logger.error(f'Project Name and Project Path provided, these are mutually exclusive.') + return 1 + + if not project_name and not project_path: + logger.error('Must specify either a Project name or Project Path.') + return 1 + + if project_name and not project_path: + project_path = registration.get_registered(project_name=project_name) + + if not project_path: + logger.error(f'Project Path {project_path} has not been registered.') + return 1 + + project_path = pathlib.Path(project_path).resolve() + + bootstrap_setreg_file = registration.get_o3de_registry_folder() / 'bootstrap.setreg' + if bootstrap_setreg_file.is_file(): + with bootstrap_setreg_file.open('r') as f: + try: + json_data = json.load(f) + except Exception as e: + logger.error(f'Bootstrap.setreg failed to load: {str(e)}') + else: + try: + json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] = project_path + except Exception as e: + logger.error(f'Bootstrap.setreg failed to load: {str(e)}') + else: + try: + os.unlink(bootstrap_setreg_file) + except Exception as e: + logger.error(f'Failed to unlink bootstrap file {bootstrap_setreg_file}: {str(e)}') + return 1 + else: + json_data = {} + json_data.update({"Amazon":{"AzCore":{"Bootstrap":{"project_path":project_path.as_posix()}}}}) + + with bootstrap_setreg_file.open('w') as s: + s.write(json.dumps(json_data, indent=4)) + + return 0 + + +def get_global_project() -> pathlib.Path or None: + """ + get what the current project set is + :return: project_path or None on failure + """ + bootstrap_setreg_file = registration.get_o3de_registry_folder() / 'bootstrap.setreg' + if not bootstrap_setreg_file.is_file(): + logger.error(f'Bootstrap.setreg file {bootstrap_setreg_file} does not exist.') + return None + + with bootstrap_setreg_file.open('r') as f: + try: + json_data = json.load(f) + except Exception as e: + logger.error(f'Bootstrap.setreg failed to load: {str(e)}') + else: + try: + project_path = json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] + except Exception as e: + logger.error(f'Bootstrap.setreg cannot find Amazon:AzCore:Bootstrap:project_path: {str(e)}') + else: + return pathlib.Path(project_path).resolve() + return None + +def _run_get_global_project(args: argparse) -> int: + if args.override_home_folder: + registration.override_home_folder = args.override_home_folder + + project_path = get_global_project() + if project_path: + print(project_path.as_posix()) + return 0 + return 1 + + +def _run_set_global_project(args: argparse) -> int: + if args.override_home_folder: + registration.override_home_folder = args.override_home_folder + + return set_global_project(args.project_name, + args.project_path) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or aggregated by a central python file. + Ex. Directly run from this file alone with: python global_project.py set_global_project --project-name TestProject + OR + o3de.py can aggregate commands by importing global_project, call add_args and + execute: python o3de.py set_global_project --project-path C:/TestProject + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + get_global_project_subparser = subparsers.add_parser('get-global-project') + get_global_project_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + get_global_project_subparser.set_defaults(func=_run_get_global_project) + + set_global_project_subparser = subparsers.add_parser('set-global-project') + group = set_global_project_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-pn', '--project-name', required=False, + help='The name of the project. If supplied this will resolve the --project-path.') + group.add_argument('-pp', '--project-path', required=False, + help='The path to the project') + + set_global_project_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + set_global_project_subparser.set_defaults(func=_run_set_global_project) + + +if __name__ == "__main__": + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + the_subparsers = the_parser.add_subparsers(help='sub-command help') + + # add args to the parser + add_args(the_parser, the_subparsers) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) + + # return + sys.exit(ret) diff --git a/cmake/Tools/registration.py b/cmake/Tools/registration.py index c16a712859..292ec33d1f 100755 --- a/cmake/Tools/registration.py +++ b/cmake/Tools/registration.py @@ -11,6 +11,7 @@ """ This file contains all the code that has to do with registering engines, projects, gems and templates """ + import argparse import logging import os @@ -19,133 +20,611 @@ import json import pathlib import hashlib import shutil -import urllib +import zipfile +import urllib.parse +import urllib.request logger = logging.getLogger() logging.basicConfig() -def backup(file_name): +def backup_file(file_name: str or pathlib.Path) -> None: index = 0 renamed = False while not renamed: - backup_file_name = pathlib.Path(str(file_name) + '.bak' + str(index)) + backup_file_name = pathlib.Path(str(file_name) + '.bak' + str(index)).resolve() + index += 1 if not backup_file_name.is_file(): - file_name = pathlib.Path(file_name) + file_name = pathlib.Path(file_name).resolve() file_name.rename(backup_file_name) - renamed = True + if backup_file_name.is_file(): + renamed = True + + +def backup_folder(folder: str or pathlib.Path) -> None: + index = 0 + renamed = False + while not renamed: + backup_folder_name = pathlib.Path(str(folder) + '.bak' + str(index)).resolve() + index += 1 + if not backup_folder_name.is_dir(): + folder = pathlib.Path(folder).resolve() + folder.rename(backup_folder_name) + if backup_folder_name.is_dir(): + renamed = True + + +def get_this_engine_path() -> pathlib.Path: + return pathlib.Path(os.path.realpath(__file__)).parents[2].resolve() + + +override_home_folder = None + + +def get_home_folder() -> pathlib.Path: + if override_home_folder: + return pathlib.Path(override_home_folder).resolve() + else: + return pathlib.Path(os.path.expanduser("~")).resolve() + + +def get_o3de_folder() -> pathlib.Path: + o3de_folder = get_home_folder() / '.o3de' + o3de_folder.mkdir(parents=True, exist_ok=True) + return o3de_folder + + +def get_o3de_registry_folder() -> pathlib.Path: + registry_folder = get_o3de_folder() / 'Registry' + registry_folder.mkdir(parents=True, exist_ok=True) + return registry_folder + + +def get_o3de_cache_folder() -> pathlib.Path: + cache_folder = get_o3de_folder() / 'Cache' + cache_folder.mkdir(parents=True, exist_ok=True) + return cache_folder + + +def get_o3de_download_folder() -> pathlib.Path: + download_folder = get_o3de_folder() / 'Download' + download_folder.mkdir(parents=True, exist_ok=True) + return download_folder + + +def get_o3de_engines_folder() -> pathlib.Path: + engines_folder = get_o3de_folder() / 'Engines' + engines_folder.mkdir(parents=True, exist_ok=True) + return engines_folder + + +def get_o3de_projects_folder() -> pathlib.Path: + projects_folder = get_o3de_folder() / 'Projects' + projects_folder.mkdir(parents=True, exist_ok=True) + return projects_folder + + +def get_o3de_gems_folder() -> pathlib.Path: + gems_folder = get_o3de_folder() / 'Gems' + gems_folder.mkdir(parents=True, exist_ok=True) + return gems_folder -def register_shipped_engine_o3de_objects(): - # register this engines shipped projects, gems and templates + +def get_o3de_templates_folder() -> pathlib.Path: + templates_folder = get_o3de_folder() / 'Templates' + templates_folder.mkdir(parents=True, exist_ok=True) + return templates_folder + + +def get_o3de_restricted_folder() -> pathlib.Path: + restricted_folder = get_o3de_folder() / 'Restricted' + restricted_folder.mkdir(parents=True, exist_ok=True) + return restricted_folder + + +def get_o3de_logs_folder() -> pathlib.Path: + restricted_folder = get_o3de_folder() / 'Logs' + restricted_folder.mkdir(parents=True, exist_ok=True) + return restricted_folder + + +def register_shipped_engine_o3de_objects() -> int: engine_path = get_this_engine_path() - for root, dirs, files in os.walk(engine_path / 'AtomSampleViewer', topdown=False): + + ret_val = 0 + + # directories with engines + starting_engines_directories = [ + ] + for engines_directory in sorted(starting_engines_directories, reverse=True): + error_code = register_all_engines_in_folder(engines_path=engines_directory) + if error_code: + ret_val = error_code + + # specific engines + starting_engines = [ + ] + for engine_path in sorted(starting_engines): + error_code = register(engine_path=engine_path) + if error_code: + ret_val = error_code + + # directories with projects + starting_projects_directories = [ + ] + for projects_directory in sorted(starting_projects_directories, reverse=True): + error_code = register_all_projects_in_folder(engine_path=engine_path, projects_path=projects_directory) + if error_code: + ret_val = error_code + + # specific projects + starting_projects = [ + f'{engine_path}/AutomatedTesting' + ] + for project_path in sorted(starting_projects, reverse=True): + error_code = register(engine_path=engine_path, project_path=project_path) + if error_code: + ret_val = error_code + + # directories with gems + starting_gems_directories = [ + f'{engine_path}/Gems' + ] + for gems_directory in sorted(starting_gems_directories, reverse=True): + error_code = register_all_gems_in_folder(engine_path=engine_path, gems_path=gems_directory) + if error_code: + ret_val = error_code + + # specific gems + starting_gems = [ + ] + for gem_path in sorted(starting_gems, reverse=True): + error_code = register(engine_path=engine_path, gem_path=gem_path) + if error_code: + ret_val = error_code + + # directories with templates + starting_templates_directories = [ + f'{engine_path}/Templates' + ] + for templates_directory in sorted(starting_templates_directories, reverse=True): + error_code = register_all_templates_in_folder(engine_path=engine_path, templates_path=templates_directory) + if error_code: + ret_val = error_code + + # specific templates + starting_templates = [ + ] + for template_path in sorted(starting_templates, reverse=True): + error_code = register(engine_path=engine_path, template_path=template_path) + if error_code: + ret_val = error_code + + # directories with restricted + starting_restricted_directories = [ + ] + for restricted_directory in sorted(starting_restricted_directories, reverse=True): + error_code = register_all_restricted_in_folder(engine_path=engine_path, restricted_path=restricted_directory) + if error_code: + ret_val = error_code + + # specific restricted + starting_restricted = [ + ] + for restricted_path in sorted(starting_restricted, reverse=True): + error_code = register(engine_path=engine_path, restricted_path=restricted_path) + if error_code: + ret_val = error_code + + # directories with repos + starting_repo_directories = [ + ] + for repos_directory in sorted(starting_repo_directories, reverse=True): + error_code = register_all_repos_in_folder(engine_path=engine_path, repos_path=repos_directory) + if error_code: + ret_val = error_code + + # specific repos + starting_repos = [ + ] + for repo_uri in sorted(starting_repos, reverse=True): + error_code = register(repo_uri=repo_uri) + if error_code: + ret_val = error_code + + # register anything in the users default folders globally + error_code = register_all_engines_in_folder(get_registered(default_folder='engines')) + if error_code: + ret_val = error_code + error_code = register_all_projects_in_folder(get_registered(default_folder='projects')) + if error_code: + ret_val = error_code + error_code = register_all_gems_in_folder(get_registered(default_folder='gems')) + if error_code: + ret_val = error_code + error_code = register_all_templates_in_folder(get_registered(default_folder='templates')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(get_registered(default_folder='restricted')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(get_registered(default_folder='projects')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(get_registered(default_folder='gems')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(get_registered(default_folder='templates')) + if error_code: + ret_val = error_code + + starting_external_subdirectories = [ + f'{engine_path}/Gems/Atom', + f'{engine_path}/Gems/AtomLyIntegration' + ] + for external_subdir in sorted(starting_external_subdirectories, reverse=True): + error_code = add_external_subdirectory(engine_path=engine_path, external_subdir=external_subdir) + if error_code: + ret_val = error_code + + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + gems = json_data['gems'].copy() + gems.extend(engine_object['gems']) + for gem_path in sorted(gems, key=len): + gem_path = pathlib.Path(gem_path).resolve() + gem_cmake_lists_txt = gem_path / 'CMakeLists.txt' + if gem_cmake_lists_txt.is_file(): + add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, supress_errors=True) # don't care about errors + + return ret_val + + +def register_all_in_folder(folder_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None, + exclude: list = None) -> int: + if not folder_path: + logger.error(f'Folder path cannot be empty.') + return 1 + + folder_path = pathlib.Path(folder_path).resolve() + if not folder_path.is_dir(): + logger.error(f'Folder path is not dir.') + return 1 + + engines_set = set() + projects_set = set() + gems_set = set() + templates_set = set() + restricted_set = set() + repo_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(folder_path): + if root in exclude: + continue + for name in files: - if name == 'project.json': - register(project_path=root) + if name == 'engine.json': + engines_set.add(root) + elif name == 'project.json': + projects_set.add(root) elif name == 'gem.json': - register(gem_path=root) + gems_set.add(root) elif name == 'template.json': - register(template_path=root) + templates_set.add(root) + elif name == 'restricted.json': + restricted_set.add(root) + elif name == 'repo.json': + repo_set.add(root) + + for engine in sorted(engines_set, reverse=True): + error_code = register(engine_path=engine, remove=remove) + if error_code: + ret_val = error_code + + for project in sorted(projects_set, reverse=True): + error_code = register(engine_path=engine_path, project_path=project, remove=remove) + if error_code: + ret_val = error_code + + for gem in sorted(gems_set, reverse=True): + error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) + if error_code: + ret_val = error_code + + for template in sorted(templates_set, reverse=True): + error_code = register(engine_path=engine_path, template_path=template, remove=remove) + if error_code: + ret_val = error_code + + for restricted in sorted(restricted_set, reverse=True): + error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) + if error_code: + ret_val = error_code + + for repo in sorted(repo_set, reverse=True): + error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_engines_in_folder(engines_path: str or pathlib.Path, + remove: bool = False) -> int: + if not engines_path: + logger.error(f'Engines path cannot be empty.') + return 1 - for root, dirs, files in os.walk(engine_path / 'AtomTest', topdown=False): + engines_path = pathlib.Path(engines_path).resolve() + if not engines_path.is_dir(): + logger.error(f'Engines path is not dir.') + return 1 + + engines_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(engines_path): + for name in files: + if name == 'engine.json': + engines_set.add(name) + + for engine in sorted(engines_set, reverse=True): + error_code = register(engine_path=engine, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_projects_in_folder(projects_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not projects_path: + logger.error(f'Projects path cannot be empty.') + return 1 + + projects_path = pathlib.Path(projects_path).resolve() + if not projects_path.is_dir(): + logger.error(f'Projects path is not dir.') + return 1 + + projects_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(projects_path): for name in files: if name == 'project.json': - register(project_path=root) - elif name == 'gem.json': - register(gem_path=root) - elif name == 'template.json': - register(template_path=root) + projects_set.add(root) + + for project in sorted(projects_set, reverse=True): + error_code = register(engine_path=engine_path, project_path=project, remove=remove) + if error_code: + ret_val = error_code - for root, dirs, files in os.walk(engine_path / 'Gems', topdown=False): + return ret_val + + +def register_all_gems_in_folder(gems_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not gems_path: + logger.error(f'Gems path cannot be empty.') + return 1 + + gems_path = pathlib.Path(gems_path).resolve() + if not gems_path.is_dir(): + logger.error(f'Gems path is not dir.') + return 1 + + gems_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(gems_path): for name in files: if name == 'gem.json': - register(gem_path=root) + gems_set.add(root) + + for gem in sorted(gems_set, reverse=True): + error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) + if error_code: + ret_val = error_code - engine_templates = os.listdir(engine_path / 'Templates') - for engine_template in engine_templates: - register(template_path=engine_path / 'Templates' / engine_template) + return ret_val - engine_projects = os.listdir(engine_path) - for engine_project in engine_projects: - engine_project_json = engine_path / engine_project / 'project.json' - if engine_project_json.is_file(): - register(project_path=engine_path / engine_project) +def register_all_templates_in_folder(templates_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not templates_path: + logger.error(f'Templates path cannot be empty.') + return 1 -def get_this_engine_path(): - return pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + templates_path = pathlib.Path(templates_path).resolve() + if not templates_path.is_dir(): + logger.error(f'Templates path is not dir.') + return 1 + templates_set = set() -def get_home_folder(): - return pathlib.Path(os.path.expanduser("~")) + ret_val = 0 + for root, dirs, files in os.walk(templates_path): + for name in files: + if name == 'template.json': + templates_set.add(root) + for template in sorted(templates_set, reverse=True): + error_code = register(engine_path=engine_path, template_path=template, remove=remove) + if error_code: + ret_val = error_code -def get_o3de_folder(): - o3de_folder = get_home_folder() / '.o3de' - o3de_folder.mkdir(parents=True, exist_ok=True) - return o3de_folder + return ret_val -def get_o3de_cache(): - cache_folder = get_o3de_folder() / 'cache' - cache_folder.mkdir(parents=True, exist_ok=True) - return cache_folder +def register_all_restricted_in_folder(restricted_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') + return 1 + + restricted_path = pathlib.Path(restricted_path).resolve() + if not restricted_path.is_dir(): + logger.error(f'Restricted path is not dir.') + return 1 + + restricted_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(restricted_path): + for name in files: + if name == 'restricted.json': + restricted_set.add(root) + + for restricted in sorted(restricted_set, reverse=True): + error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_repos_in_folder(repos_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not repos_path: + logger.error(f'Repos path cannot be empty.') + return 1 + + repos_path = pathlib.Path(repos_path).resolve() + if not repos_path.is_dir(): + logger.error(f'Repos path is not dir.') + return 1 + + repo_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(repos_path): + for name in files: + if name == 'repo.json': + repo_set.add(root) + for repo in sorted(repo_set, reverse=True): + error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) + if error_code: + ret_val = error_code -def get_o3de_registry(): - registry_path = get_o3de_folder() / 'o3de_manifest.json' - if not registry_path.is_file(): + return ret_val + +def get_o3de_manifest() -> pathlib.Path: + manifest_path = get_o3de_folder() / 'o3de_manifest.json' + if not manifest_path.is_file(): username = os.path.split(get_home_folder())[-1] + o3de_folder = get_o3de_folder() + default_registry_folder = get_o3de_registry_folder() + default_cache_folder = get_o3de_cache_folder() + default_downloads_folder = get_o3de_download_folder() + default_logs_folder = get_o3de_logs_folder() + default_engines_folder = get_o3de_engines_folder() + default_projects_folder = get_o3de_projects_folder() + default_gems_folder = get_o3de_gems_folder() + default_templates_folder = get_o3de_templates_folder() + default_restricted_folder = get_o3de_restricted_folder() + + default_projects_restricted_folder = default_projects_folder / 'Restricted' + default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) + default_gems_restricted_folder = default_gems_folder / 'Restricted' + default_gems_restricted_folder.mkdir(parents=True, exist_ok=True) + default_templates_restricted_folder = default_templates_folder / 'Restricted' + default_templates_restricted_folder.mkdir(parents=True, exist_ok=True) + json_data = {} - json_data.update({'repo_name': f'{username}'}) - json_data.update({'origin': get_o3de_folder().as_posix()}) - json_data.update({'engines': []}) + json_data.update({'o3de_manifest_name': f'{username}'}) + json_data.update({'origin': o3de_folder.as_posix()}) + json_data.update({'default_engines_folder': default_engines_folder.as_posix()}) + json_data.update({'default_projects_folder': default_projects_folder.as_posix()}) + json_data.update({'default_gems_folder': default_gems_folder.as_posix()}) + json_data.update({'default_templates_folder': default_templates_folder.as_posix()}) + json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) + json_data.update({'projects': []}) json_data.update({'gems': []}) json_data.update({'templates': []}) + json_data.update({'restricted': []}) json_data.update({'repos': []}) - default_projects_folder = get_home_folder() / 'my_o3de/projects' - default_projects_folder.mkdir(parents=True, exist_ok=True) - json_data.update({'default_projects_folder': default_projects_folder.as_posix()}) - default_gems_folder = get_home_folder() / 'my_o3de/gems' - default_gems_folder.mkdir(parents=True, exist_ok=True) - json_data.update({'default_gems_folder': default_gems_folder.as_posix()}) - default_templates_folder = get_home_folder() / 'my_o3de/templates' - default_templates_folder.mkdir(parents=True, exist_ok=True) - json_data.update({'default_templates_folder': default_templates_folder.as_posix()}) - with registry_path.open('w') as s: + json_data.update({'engines': []}) + + default_restricted_folder_json = default_restricted_folder / 'restricted.json' + if not default_restricted_folder_json.is_file(): + with default_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'o3de'}) + s.write(json.dumps(restricted_json_data, indent=4)) + json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) + + default_projects_restricted_folder_json = default_projects_restricted_folder / 'restricted.json' + if not default_projects_restricted_folder_json.is_file(): + with default_projects_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'projects'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + default_gems_restricted_folder_json = default_gems_restricted_folder / 'restricted.json' + if not default_gems_restricted_folder_json.is_file(): + with default_gems_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'gems'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + default_templates_restricted_folder_json = default_templates_restricted_folder / 'restricted.json' + if not default_templates_restricted_folder_json.is_file(): + with default_templates_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'templates'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + with manifest_path.open('w') as s: s.write(json.dumps(json_data, indent=4)) - return registry_path + return manifest_path -def load_o3de_registry(): - with get_o3de_registry().open('r') as f: - return json.load(f) +def load_o3de_manifest() -> dict: + with get_o3de_manifest().open('r') as f: + try: + json_data = json.load(f) + except Exception as e: + logger.error(f'Manifest json failed to load: {str(e)}') + else: + return json_data -def save_o3de_registry(json_data): - with get_o3de_registry().open('w') as s: - s.write(json.dumps(json_data, indent=4)) +def save_o3de_manifest(json_data: dict) -> None: + with get_o3de_manifest().open('w') as s: + try: + s.write(json.dumps(json_data, indent=4)) + except Exception as e: + logger.error(f'Manifest json failed to save: {str(e)}') -def register_engine_path(json_data, - engine_path: str, +def register_engine_path(json_data: dict, + engine_path: str or pathlib.Path, remove: bool = False) -> int: if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 + engine_path = pathlib.Path(engine_path).resolve() - while engine_path in json_data['engines']: - json_data['engines'].remove(engine_path) - engine_path = pathlib.Path(engine_path) - while engine_path.as_posix() in json_data['engines']: - json_data['engines'].remove(engine_path.as_posix()) + for engine_object in json_data['engines']: + engine_object_path = pathlib.Path(engine_object['path']).resolve() + if engine_object_path == engine_path: + json_data['engines'].remove(engine_object) if remove: - logger.warn(f'Removing Engine path {engine_path}.') return 0 if not engine_path.is_dir(): @@ -157,27 +636,53 @@ def register_engine_path(json_data, logger.error(f'Engine json {engine_json} is not valid.') return 1 - json_data['engines'].insert(0, engine_path.as_posix()) + engine_object = {} + engine_object.update({'path': engine_path.as_posix()}) + engine_object.update({'projects': []}) + engine_object.update({'gems': []}) + engine_object.update({'templates': []}) + engine_object.update({'restricted': []}) + engine_object.update({'external_subdirectories': []}) + + json_data['engines'].insert(0, engine_object) return 0 -def register_gem_path(json_data, - gem_path: str, - remove: bool = False) -> int: +def register_gem_path(json_data: dict, + gem_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: if not gem_path: logger.error(f'Gem path cannot be empty.') return 1 + gem_path = pathlib.Path(gem_path).resolve() - while gem_path in json_data['gems']: - json_data['gems'].remove(gem_path) - gem_path = pathlib.Path(gem_path) - while gem_path.as_posix() in json_data['gems']: - json_data['gems'].remove(gem_path.as_posix()) + if engine_path: + engine_data = find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 - if remove: - logger.warn(f'Removing Gem path {gem_path}.') - return 0 + while gem_path in engine_data['gems']: + engine_data['gems'].remove(gem_path) + + while gem_path.as_posix() in engine_data['gems']: + engine_data['gems'].remove(gem_path.as_posix()) + + if remove: + logger.warn(f'Removing Gem path {gem_path}.') + return 0 + else: + while gem_path in json_data['gems']: + json_data['gems'].remove(gem_path) + + while gem_path.as_posix() in json_data['gems']: + json_data['gems'].remove(gem_path.as_posix()) + + if remove: + logger.warn(f'Removing Gem path {gem_path}.') + return 0 if not gem_path.is_dir(): logger.error(f'Gem path {gem_path} does not exist.') @@ -188,27 +693,48 @@ def register_gem_path(json_data, logger.error(f'Gem json {gem_json} is not valid.') return 1 - json_data['gems'].insert(0, gem_path.as_posix()) + if engine_path: + engine_data['gems'].insert(0, gem_path.as_posix()) + else: + json_data['gems'].insert(0, gem_path.as_posix()) return 0 -def register_project_path(json_data, - project_path: str, - remove: bool = False) -> int: +def register_project_path(json_data: dict, + project_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: if not project_path: logger.error(f'Project path cannot be empty.') return 1 + project_path = pathlib.Path(project_path).resolve() - while project_path in json_data['projects']: - json_data['projects'].remove(project_path) - project_path = pathlib.Path(project_path) - while project_path.as_posix() in json_data['projects']: - json_data['projects'].remove(project_path.as_posix()) + if engine_path: + engine_data = find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 - if remove: - logger.warn(f'Removing Project path {project_path}.') - return 0 + while project_path in engine_data['projects']: + engine_data['projects'].remove(project_path) + + while project_path.as_posix() in engine_data['projects']: + engine_data['projects'].remove(project_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Project path {project_path}.') + return 0 + else: + while project_path in json_data['projects']: + json_data['projects'].remove(project_path) + + while project_path.as_posix() in json_data['projects']: + json_data['projects'].remove(project_path.as_posix()) + + if remove: + logger.warn(f'Removing Project path {project_path}.') + return 0 if not project_path.is_dir(): logger.error(f'Project path {project_path} does not exist.') @@ -219,14 +745,25 @@ def register_project_path(json_data, logger.error(f'Project json {project_json} is not valid.') return 1 - json_data['projects'].insert(0, project_path.as_posix()) + if engine_path: + engine_data['projects'].insert(0, project_path.as_posix()) + else: + json_data['projects'].insert(0, project_path.as_posix()) # registering a project has the additional step of setting the project.json 'engine' field this_engine_json = get_this_engine_path() / 'engine.json' with this_engine_json.open('r') as f: - this_engine_json = json.load(f) + try: + this_engine_json = json.load(f) + except Exception as e: + logger.error(f'Engine json failed to load: {str(e)}') + return 1 with project_json.open('r') as f: - project_json_data = json.load(f) + try: + project_json_data = json.load(f) + except Exception as e: + logger.error(f'Project json failed to load: {str(e)}') + return 1 update_project_json = False try: @@ -236,29 +773,51 @@ def register_project_path(json_data, if update_project_json: project_json_data['engine'] = this_engine_json['engine_name'] - backup(project_json) + backup_file(project_json) with project_json.open('w') as s: - s.write(json.dumps(project_json_data, indent=4)) + try: + s.write(json.dumps(project_json_data, indent=4)) + except Exception as e: + logger.error(f'Project json failed to save: {str(e)}') + return 1 return 0 -def register_template_path(json_data, - template_path: str, - remove: bool = False) -> int: +def register_template_path(json_data: dict, + template_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: if not template_path: logger.error(f'Template path cannot be empty.') return 1 + template_path = pathlib.Path(template_path).resolve() - while template_path in json_data['templates']: - json_data['templates'].remove(template_path) - template_path = pathlib.Path(template_path) - while template_path.as_posix() in json_data['templates']: - json_data['templates'].remove(template_path.as_posix()) + if engine_path: + engine_data = find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 - if remove: - logger.warn(f'Removing Template path {template_path}.') - return 0 + while template_path in engine_data['templates']: + engine_data['templates'].remove(template_path) + + while template_path.as_posix() in engine_data['templates']: + engine_data['templates'].remove(template_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Template path {template_path}.') + return 0 + else: + while template_path in json_data['templates']: + json_data['templates'].remove(template_path) + + while template_path.as_posix() in json_data['templates']: + json_data['templates'].remove(template_path.as_posix()) + + if remove: + logger.warn(f'Removing Template path {template_path}.') + return 0 if not template_path.is_dir(): logger.error(f'Template path {template_path} does not exist.') @@ -269,223 +828,470 @@ def register_template_path(json_data, logger.error(f'Template json {template_json} is not valid.') return 1 - json_data['templates'].insert(0, template_path.as_posix()) + if engine_path: + engine_data['templates'].insert(0, template_path.as_posix()) + else: + json_data['templates'].insert(0, template_path.as_posix()) return 0 -def register_repo(json_data, - repo_uri: str, - remove: bool = False) -> int: - if not repo_uri: - logger.error(f'Repo URI cannot be empty.') +def register_restricted_path(json_data: dict, + restricted_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') return 1 + restricted_path = pathlib.Path(restricted_path).resolve() - while repo_uri in json_data['repos']: - json_data['repos'].remove(repo_uri) + if engine_path: + engine_data = find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 - if remove: - logger.warn(f'Removing repo uri {repo_uri}.') + while restricted_path in engine_data['restricted']: + engine_data['restricted'].remove(restricted_path) - if remove: - result = refresh_repos() + while restricted_path.as_posix() in engine_data['restricted']: + engine_data['restricted'].remove(restricted_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Restricted path {restricted_path}.') + return 0 else: - repo_hash = hashlib.md5(repo_uri.encode()) - cache_folder = get_o3de_cache() - cache_file = cache_folder / str(repo_hash.hexdigest() + '.json') - parsed_uri = urllib.parse.urlparse(repo_uri) - - if parsed_uri.scheme == 'http' or parsed_uri.scheme == 'https' or parsed_uri.scheme == 'ftp' or parsed_uri.scheme == 'ftps': - result = 0 # a function that processes the uri and returns result - if not result: - json_data['repos'].insert(0, repo_uri) - else: - repo_uri = pathlib.Path(repo_uri) - json_data['repos'].insert(0, repo_uri.as_posix()) - result = 0 + while restricted_path in json_data['restricted']: + json_data['restricted'].remove(restricted_path) - return result + while restricted_path.as_posix() in json_data['restricted']: + json_data['restricted'].remove(restricted_path.as_posix()) + if remove: + logger.warn(f'Removing Restricted path {restricted_path}.') + return 0 -def valid_o3de_manifest_json(file_name: str) -> bool: - try: - file_name = pathlib.Path(file_name) - if not file_name.is_file(): - return False - with file_name.open('r') as f: + if not restricted_path.is_dir(): + logger.error(f'Restricted path {restricted_path} does not exist.') + return 1 + + restricted_json = restricted_path / 'restricted.json' + if not valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return 1 + + if engine_path: + engine_data['restricted'].insert(0, restricted_path.as_posix()) + else: + json_data['restricted'].insert(0, restricted_path.as_posix()) + + return 0 + + +def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + + with file_name.open('r') as f: + try: json_data = json.load(f) test = json_data['repo_name'] test = json_data['origin'] - test = json_data['engines'] - test = json_data['projects'] - test = json_data['gems'] - test = json_data['templates'] - test = json_data['repos'] - except Exception as e: - return False + except Exception as e: + return False return True -def valid_o3de_engine_json(file_name: str) -> bool: - try: - file_name = pathlib.Path(file_name) - if not file_name.is_file(): - return False - with file_name.open('r') as f: - json_data = json.load(f) - test = json_data['engine_name'] - except Exception as e: +def valid_o3de_engine_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['engine_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False return True -def valid_o3de_project_json(file_name: str) -> bool: - try: - file_name = pathlib.Path(file_name) - if not file_name.is_file(): - return False - with file_name.open('r') as f: - json_data = json.load(f) - test = json_data['project_name'] - except Exception as e: +def valid_o3de_project_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['project_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False return True -def valid_o3de_gem_json(file_name: str) -> bool: - try: - file_name = pathlib.Path(file_name) - if not file_name.is_file(): - return False - with file_name.open('r') as f: - json_data = json.load(f) - test = json_data['gem_name'] - except Exception as e: +def valid_o3de_gem_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['gem_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False return True -def valid_o3de_template_json(file_name: str) -> bool: - try: - file_name = pathlib.Path(file_name) - if not file_name.is_file(): - return False - with file_name.open('r') as f: +def valid_o3de_template_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + with file_name.open('r') as f: + try: json_data = json.load(f) test = json_data['template_name'] - except Exception as e: - return False + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True + +def valid_o3de_restricted_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['restricted_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False return True -def register_default_projects_folder(json_data, - default_projects_folder: str, - remove: bool = False) -> int: - if remove: - json_data['default_projects_folder'] = '' - else: - # make sure the path exists - default_projects_folder = pathlib.Path(default_projects_folder) - if not default_projects_folder.is_dir(): - logger.error(f'Default projects folder {default_projects_folder} does not exist.') - return 1 +def process_add_o3de_repo(file_name: str or pathlib.Path, + repo_set: set) -> int: + file_name = pathlib.Path(file_name).resolve() + if not valid_o3de_repo_json(file_name): + return 1 + + cache_folder = get_o3de_cache_folder() - default_projects_folder = default_projects_folder.as_posix() - json_data['default_projects_folder'] = default_projects_folder + with file_name.open('r') as f: + try: + repo_data = json.load(f) + except Exception as e: + logger.error(f'{file_name} failed to load: {str(e)}') + return 1 + for engine_uri in repo_data['engines']: + engine_uri = f'{engine_uri}/engine.json' + engine_sha256 = hashlib.sha256(engine_uri.encode()) + cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(engine_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(engine_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + engine_json = pathlib.Path(engine_uri).resolve() + if not engine_json.is_file(): + return 1 + shutil.copy(engine_json, cache_file) + + for project_uri in repo_data['projects']: + project_uri = f'{project_uri}/project.json' + project_sha256 = hashlib.sha256(project_uri.encode()) + cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(project_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(project_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + project_json = pathlib.Path(project_uri).resolve() + if not project_json.is_file(): + return 1 + shutil.copy(project_json, cache_file) + + for gem_uri in repo_data['gems']: + gem_uri = f'{gem_uri}/gem.json' + gem_sha256 = hashlib.sha256(gem_uri.encode()) + cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(gem_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(gem_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + gem_json = pathlib.Path(gem_uri).resolve() + if not gem_json.is_file(): + return 1 + shutil.copy(gem_json, cache_file) + + for template_uri in repo_data['templates']: + template_uri = f'{template_uri}/template.json' + template_sha256 = hashlib.sha256(template_uri.encode()) + cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(template_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(template_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + template_json = pathlib.Path(template_uri).resolve() + if not template_json.is_file(): + return 1 + shutil.copy(template_json, cache_file) + + for repo_uri in repo_data['repos']: + if repo_uri not in repo_set: + repo_set.add(repo_uri) + repo_uri = f'{repo_uri}/repo.json' + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(repo_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + repo_json = pathlib.Path(repo_uri).resolve() + if not repo_json.is_file(): + return 1 + shutil.copy(repo_json, cache_file) return 0 -def register_default_gems_folder(json_data, - default_gems_folder: str, - remove: bool = False) -> int: +def register_repo(json_data: dict, + repo_uri: str or pathlib.Path, + remove: bool = False) -> int: + if not repo_uri: + logger.error(f'Repo URI cannot be empty.') + return 1 + + url = f'{repo_uri}/repo.json' + parsed_uri = urllib.parse.urlparse(url) + + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + while repo_uri in json_data['repos']: + json_data['repos'].remove(repo_uri) + else: + repo_uri = pathlib.Path(repo_uri).resolve() + while repo_uri.as_posix() in json_data['repos']: + json_data['repos'].remove(repo_uri.as_posix()) + if remove: - json_data['default_gems_folder'] = '' + logger.warn(f'Removing repo uri {repo_uri}.') + return 0 + + repo_sha256 = hashlib.sha256(url.encode()) + cache_file = get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') + + result = 0 + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + if not cache_file.is_file(): + with urllib.request.urlopen(url) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + json_data['repos'].insert(0, repo_uri) else: - # make sure the path exists - default_gems_folder = pathlib.Path(default_gems_folder) - if not default_gems_folder.is_dir(): - logger.error(f'Default gems folder {default_gems_folder} does not exist.') - return 1 + if not cache_file.is_file(): + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, origin_file) + json_data['repos'].insert(0, repo_uri.as_posix()) - default_gems_folder = default_gems_folder.as_posix() - json_data['default_gems_folder'] = default_gems_folder + repo_set = set() + result = process_add_o3de_repo(cache_file, repo_set) - return 0 + return result -def register_default_templates_folder(json_data, - default_templates_folder: str, - remove: bool = False) -> int: +def register_default_engines_folder(json_data: dict, + default_engines_folder: str or pathlib.Path, + remove: bool = False) -> int: if remove: - json_data['default_templates_folder'] = '' - else: - # make sure the path exists - default_templates_folder = pathlib.Path(default_templates_folder) - if not default_templates_folder.is_dir(): - logger.error(f'Default templates folder {default_templates_folder} does not exist.') - return 1 + default_engines_folder = get_o3de_engines_folder() + + # make sure the path exists + default_engines_folder = pathlib.Path(default_engines_folder).resolve() + if not default_engines_folder.is_dir(): + logger.error(f'Default engines folder {default_engines_folder} does not exist.') + return 1 - default_templates_folder = default_templates_folder.as_posix() - json_data['default_templates_folder'] = default_templates_folder + default_engines_folder = default_engines_folder.as_posix() + json_data['default_engines_folder'] = default_engines_folder return 0 -def register(engine_path: str = None, - project_path: str = None, - gem_path: str = None, - template_path: str = None, - default_projects_folder: str = None, - default_gems_folder: str = None, - default_templates_folder: str = None, - repo_uri: str = None, - remove: bool = False) -> int: - """ - Adds/Updates entries to the .o3de/o3de_manifest.json +def register_default_projects_folder(json_data: dict, + default_projects_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_projects_folder = get_o3de_projects_folder() - :param engine_path: engine folder - :param project_path: project folder - :param gem_path: gem folder - :param template_path: template folder - :param default_projects_folder: default projects folder - :param default_gems_folder: default gems folder - :param default_templates_folder: default templates folder - :param repo_uri: repo uri - :param remove: add/remove the entries - :return: 0 for success or non 0 failure code - """ + # make sure the path exists + default_projects_folder = pathlib.Path(default_projects_folder).resolve() + if not default_projects_folder.is_dir(): + logger.error(f'Default projects folder {default_projects_folder} does not exist.') + return 1 - json_data = load_o3de_registry() + default_projects_folder = default_projects_folder.as_posix() + json_data['default_projects_folder'] = default_projects_folder - if isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): - if not engine_path: - logger.error(f'Engine path cannot be empty.') - return 1 - result = register_engine_path(json_data, engine_path, remove) + return 0 - elif isinstance(project_path, str) or isinstance(project_path, pathlib.PurePath): - if not project_path: - logger.error(f'Project path cannot be empty.') - return 1 - result = register_project_path(json_data, project_path, remove) - elif isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): +def register_default_gems_folder(json_data: dict, + default_gems_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_gems_folder = get_o3de_gems_folder() + + # make sure the path exists + default_gems_folder = pathlib.Path(default_gems_folder).resolve() + if not default_gems_folder.is_dir(): + logger.error(f'Default gems folder {default_gems_folder} does not exist.') + return 1 + + default_gems_folder = default_gems_folder.as_posix() + json_data['default_gems_folder'] = default_gems_folder + + return 0 + + +def register_default_templates_folder(json_data: dict, + default_templates_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_templates_folder = get_o3de_templates_folder() + + # make sure the path exists + default_templates_folder = pathlib.Path(default_templates_folder).resolve() + if not default_templates_folder.is_dir(): + logger.error(f'Default templates folder {default_templates_folder} does not exist.') + return 1 + + default_templates_folder = default_templates_folder.as_posix() + json_data['default_templates_folder'] = default_templates_folder + + return 0 + + +def register_default_restricted_folder(json_data: dict, + default_restricted_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_restricted_folder = get_o3de_restricted_folder() + + # make sure the path exists + default_restricted_folder = pathlib.Path(default_restricted_folder).resolve() + if not default_restricted_folder.is_dir(): + logger.error(f'Default restricted folder {default_restricted_folder} does not exist.') + return 1 + + default_restricted_folder = default_restricted_folder.as_posix() + json_data['default_restricted_folder'] = default_restricted_folder + + return 0 + + +def register(engine_path: str or pathlib.Path = None, + project_path: str or pathlib.Path = None, + gem_path: str or pathlib.Path = None, + template_path: str or pathlib.Path = None, + restricted_path: str or pathlib.Path = None, + repo_uri: str or pathlib.Path = None, + default_engines_folder: str or pathlib.Path = None, + default_projects_folder: str or pathlib.Path = None, + default_gems_folder: str or pathlib.Path = None, + default_templates_folder: str or pathlib.Path = None, + default_restricted_folder: str or pathlib.Path = None, + remove: bool = False + ) -> int: + """ + Adds/Updates entries to the .o3de/o3de_manifest.json + + :param engine_path: if engine folder is supplied the path will be added to the engine if it can, if not global + :param project_path: project folder + :param gem_path: gem folder + :param template_path: template folder + :param restricted_path: restricted folder + :param repo_uri: repo uri + :param default_engines_folder: default engines folder + :param default_projects_folder: default projects folder + :param default_gems_folder: default gems folder + :param default_templates_folder: default templates folder + :param default_restricted_folder: default restricted code folder + :param remove: add/remove the entries + + :return: 0 for success or non 0 failure code + """ + + json_data = load_o3de_manifest() + + result = 0 + + # do anything that could require a engine context first + if isinstance(project_path, str) or isinstance(project_path, pathlib.PurePath): + if not project_path: + logger.error(f'Project path cannot be empty.') + return 1 + result = register_project_path(json_data, project_path, remove, engine_path) + + elif isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): if not gem_path: logger.error(f'Gem path cannot be empty.') return 1 - result = register_gem_path(json_data, gem_path, remove) + result = register_gem_path(json_data, gem_path, remove, engine_path) elif isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): if not template_path: logger.error(f'Template path cannot be empty.') return 1 - result = register_template_path(json_data, template_path, remove) + result = register_template_path(json_data, template_path, remove, engine_path) + + elif isinstance(restricted_path, str) or isinstance(restricted_path, pathlib.PurePath): + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') + return 1 + result = register_restricted_path(json_data, restricted_path, remove, engine_path) elif isinstance(repo_uri, str) or isinstance(repo_uri, pathlib.PurePath): if not repo_uri: @@ -493,6 +1299,9 @@ def register(engine_path: str = None, return 1 result = register_repo(json_data, repo_uri, remove) + elif isinstance(default_engines_folder, str) or isinstance(default_engines_folder, pathlib.PurePath): + result = register_default_engines_folder(json_data, default_engines_folder, remove) + elif isinstance(default_projects_folder, str) or isinstance(default_projects_folder, pathlib.PurePath): result = register_default_projects_folder(json_data, default_projects_folder, remove) @@ -502,578 +1311,2746 @@ def register(engine_path: str = None, elif isinstance(default_templates_folder, str) or isinstance(default_templates_folder, pathlib.PurePath): result = register_default_templates_folder(json_data, default_templates_folder, remove) + elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): + result = register_default_restricted_folder(json_data, default_restricted_folder, remove) + + # engine is done LAST + # Now that everything that could have an engine context is done, if the engine is supplied that means this is + # registering the engine itself + elif isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): + if not engine_path: + logger.error(f'Engine path cannot be empty.') + return 1 + result = register_engine_path(json_data, engine_path, remove) + if not result: - save_o3de_registry(json_data) + save_o3de_manifest(json_data) - return 0 + return result -def remove_invalid_o3de_objects(): - json_data = load_o3de_registry() +def remove_invalid_o3de_objects() -> None: + json_data = load_o3de_manifest() - for engine in json_data['engines']: - if not valid_o3de_engine_json(pathlib.Path(engine) / 'engine.json'): - logger.warn(f"Engine path {engine} is invalid.") - register(engine_path=engine, remove=True) + for engine_object in json_data['engines']: + engine_path = engine_object['path'] + if not valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): + logger.warn(f"Engine path {engine_path} is invalid.") + register(engine_path=engine_path, remove=True) + else: + for project in engine_object['projects']: + if not valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): + logger.warn(f"Project path {project} is invalid.") + register(engine_path=engine_path, project_path=project, remove=True) + + for gem_path in engine_object['gems']: + if not valid_o3de_gem_json(pathlib.Path(gem_path).resolve() / 'gem.json'): + logger.warn(f"Gem path {gem_path} is invalid.") + register(engine_path=engine_path, gem_path=gem_path, remove=True) + + for template_path in engine_object['templates']: + if not valid_o3de_template_json(pathlib.Path(template_path).resolve() / 'template.json'): + logger.warn(f"Template path {template_path} is invalid.") + register(engine_path=engine_path, template_path=template_path, remove=True) + + for restricted in engine_object['restricted']: + if not valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): + logger.warn(f"Restricted path {restricted} is invalid.") + register(engine_path=engine_path, restricted_path=restricted, remove=True) + + for external in engine_object['external_subdirectories']: + external = pathlib.Path(external).resolve() + if not external.is_dir(): + logger.warn(f"External subdirectory {external} is invalid.") + remove_external_subdirectory(external) for project in json_data['projects']: - if not valid_o3de_project_json(pathlib.Path(project) / 'project.json'): + if not valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): logger.warn(f"Project path {project} is invalid.") register(project_path=project, remove=True) for gem in json_data['gems']: - if not valid_o3de_gem_json(pathlib.Path(gem) / 'gem.json'): + if not valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'): logger.warn(f"Gem path {gem} is invalid.") register(gem_path=gem, remove=True) for template in json_data['templates']: - if not valid_o3de_template_json(pathlib.Path(template) / 'template.json'): + if not valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): logger.warn(f"Template path {template} is invalid.") register(template_path=template, remove=True) - default_projects_folder = pathlib.Path(json_data['default_projects_folder']) + for restricted in json_data['restricted']: + if not valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): + logger.warn(f"Restricted path {restricted} is invalid.") + register(restricted_path=restricted, remove=True) + + default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() + if not default_engines_folder.is_dir(): + new_default_engines_folder = get_o3de_folder() / 'Engines' + new_default_engines_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default engines folder {default_engines_folder} is invalid. Set default {new_default_engines_folder}") + register(default_engines_folder=new_default_engines_folder.as_posix()) + + default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() if not default_projects_folder.is_dir(): - new_default_projects_folder = get_home_folder() / 'my_o3de/projects' + new_default_projects_folder = get_o3de_folder() / 'Projects' new_default_projects_folder.mkdir(parents=True, exist_ok=True) - logger.warn(f"Default projects folder {default_projects_folder} is invalid. Set default {new_default_projects_folder}") + logger.warn( + f"Default projects folder {default_projects_folder} is invalid. Set default {new_default_projects_folder}") register(default_projects_folder=new_default_projects_folder.as_posix()) - default_gems_folder = pathlib.Path(json_data['default_gems_folder']) + default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() if not default_gems_folder.is_dir(): - new_default_gems_folder = get_home_folder() / 'my_o3de/gems' + new_default_gems_folder = get_o3de_folder() / 'Gems' new_default_gems_folder.mkdir(parents=True, exist_ok=True) - logger.warn(f"Default gems folder {default_gems_folder} is invalid. Set default {new_default_gems_folder}") + logger.warn(f"Default gems folder {default_gems_folder} is invalid." + f" Set default {new_default_gems_folder}") register(default_gems_folder=new_default_gems_folder.as_posix()) - default_templates_folder = pathlib.Path(json_data['default_templates_folder']) + default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() if not default_templates_folder.is_dir(): - new_default_templates_folder = get_home_folder() / 'my_o3de/templates' + new_default_templates_folder = get_o3de_folder() / 'Templates' new_default_templates_folder.mkdir(parents=True, exist_ok=True) - logger.warn(f"Default templates folder {default_templates_folder} is invalid. Set default {new_default_templates_folder}") + logger.warn( + f"Default templates folder {default_templates_folder} is invalid." + f" Set default {new_default_templates_folder}") register(default_templates_folder=new_default_templates_folder.as_posix()) + default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() + if not default_restricted_folder.is_dir(): + default_restricted_folder = get_o3de_folder() / 'Restricted' + default_restricted_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default restricted folder {default_restricted_folder} is invalid." + f" Set default {default_restricted_folder}") + register(default_restricted_folder=default_restricted_folder.as_posix()) + + +def refresh_repos() -> int: + json_data = load_o3de_manifest() + + # clear the cache + cache_folder = get_o3de_cache_folder() + shutil.rmtree(cache_folder) + cache_folder = get_o3de_cache_folder() # will recreate it + + result = 0 + + # set will stop circular references + repo_set = set() + + for repo_uri in json_data['repos']: + if repo_uri not in repo_set: + repo_set.add(repo_uri) + + repo_uri = f'{repo_uri}/repo.json' + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(repo_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(repo_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(repo_uri).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, cache_file) + + if not valid_o3de_repo_json(cache_file): + logger.error(f'Repo json {repo_uri} is not valid.') + cache_file.unlink() + return 1 + + last_failure = process_add_o3de_repo(cache_file, repo_set) + if last_failure: + result = last_failure + + return result + + +def search_repo(repo_set: set, + repo_json_data: dict, + engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + restricted_name: str = None) -> dict or None: + cache_folder = get_o3de_cache_folder() + + if isinstance(engine_name, str) or isinstance(engine_name, pathlib.PurePath): + for engine_uri in repo_json_data['engines']: + engine_uri = f'{engine_uri}/engine.json' + engine_sha256 = hashlib.sha256(engine_uri.encode()) + engine_cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') + if engine_cache_file.is_file(): + with engine_cache_file.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_cache_file} failed to load: {str(e)}') + else: + if engine_json_data['engine_name'] == engine_name: + return engine_json_data + + elif isinstance(project_name, str) or isinstance(project_name, pathlib.PurePath): + for project_uri in repo_json_data['projects']: + project_uri = f'{project_uri}/project.json' + project_sha256 = hashlib.sha256(project_uri.encode()) + project_cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') + if project_cache_file.is_file(): + with project_cache_file.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_cache_file} failed to load: {str(e)}') + else: + if project_json_data['project_name'] == project_name: + return project_json_data + + elif isinstance(gem_name, str) or isinstance(gem_name, pathlib.PurePath): + for gem_uri in repo_json_data['gems']: + gem_uri = f'{gem_uri}/gem.json' + gem_sha256 = hashlib.sha256(gem_uri.encode()) + gem_cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') + if gem_cache_file.is_file(): + with gem_cache_file.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_cache_file} failed to load: {str(e)}') + else: + if gem_json_data['gem_name'] == gem_name: + return gem_json_data + + elif isinstance(template_name, str) or isinstance(template_name, pathlib.PurePath): + for template_uri in repo_json_data['templates']: + template_uri = f'{template_uri}/template.json' + template_sha256 = hashlib.sha256(template_uri.encode()) + template_cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') + if template_cache_file.is_file(): + with template_cache_file.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_cache_file} failed to load: {str(e)}') + else: + if template_json_data['template_name'] == template_name: + return template_json_data + + elif isinstance(restricted_name, str) or isinstance(restricted_name, pathlib.PurePath): + for restricted_uri in repo_json_data['restricted']: + restricted_uri = f'{restricted_uri}/restricted.json' + restricted_sha256 = hashlib.sha256(restricted_uri.encode()) + restricted_cache_file = cache_folder / str(restricted_sha256.hexdigest() + '.json') + if restricted_cache_file.is_file(): + with restricted_cache_file.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_cache_file} failed to load: {str(e)}') + else: + if restricted_json_data['restricted_name'] == restricted_name: + return restricted_json_data + # recurse + else: + for repo_repo_uri in repo_json_data['repos']: + if repo_repo_uri not in repo_set: + repo_set.add(repo_repo_uri) + repo_repo_uri = f'{repo_repo_uri}/repo.json' + repo_repo_sha256 = hashlib.sha256(repo_repo_uri.encode()) + repo_repo_cache_file = cache_folder / str(repo_repo_sha256.hexdigest() + '.json') + if repo_repo_cache_file.is_file(): + with repo_repo_cache_file.open('r') as f: + try: + repo_repo_json_data = json.load(f) + except Exception as e: + logger.warn(f'{repo_repo_cache_file} failed to load: {str(e)}') + else: + item = search_repo(repo_set, + repo_repo_json_data, + engine_name, + project_name, + gem_name, + template_name) + if item: + return item + return None + + +def get_downloadable(engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + restricted_name: str = None) -> dict or None: + json_data = load_o3de_manifest() + cache_folder = get_o3de_cache_folder() + repo_set = set() + for repo_uri in json_data['repos']: + if repo_uri not in repo_set: + repo_set.add(repo_uri) + repo_uri = f'{repo_uri}/repo.json' + repo_sha256 = hashlib.sha256(repo_uri.encode()) + repo_cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if repo_cache_file.is_file(): + with repo_cache_file.open('r') as f: + try: + repo_json_data = json.load(f) + except Exception as e: + logger.warn(f'{repo_cache_file} failed to load: {str(e)}') + else: + item = search_repo(repo_set, + repo_json_data, + engine_name, + project_name, + gem_name, + template_name, + restricted_name) + if item: + return item + return None + + +def get_registered(engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + default_folder: str = None, + repo_name: str = None, + restricted_name: str = None) -> pathlib.Path or None: + json_data = load_o3de_manifest() + + # check global first then this engine + if isinstance(engine_name, str): + for engine in json_data['engines']: + engine_path = pathlib.Path(engine['path']).resolve() + engine_json = engine_path / 'engine.json' + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + this_engines_name = engine_json_data['engine_name'] + if this_engines_name == engine_name: + return engine_path + + elif isinstance(project_name, str): + engine_object = find_engine_data(json_data) + projects = json_data['projects'].copy() + projects.extend(engine_object['projects']) + for project_path in projects: + project_path = pathlib.Path(project_path).resolve() + project_json = project_path / 'project.json' + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + this_projects_name = project_json_data['project_name'] + if this_projects_name == project_name: + return project_path + + elif isinstance(gem_name, str): + engine_object = find_engine_data(json_data) + gems = json_data['gems'].copy() + gems.extend(engine_object['gems']) + for gem_path in gems: + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + this_gems_name = gem_json_data['gem_name'] + if this_gems_name == gem_name: + return gem_path + + elif isinstance(template_name, str): + engine_object = find_engine_data(json_data) + templates = json_data['templates'].copy() + templates.extend(engine_object['templates']) + for template_path in templates: + template_path = pathlib.Path(template_path).resolve() + template_json = template_path / 'template.json' + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_path} failed to load: {str(e)}') + else: + this_templates_name = template_json_data['template_name'] + if this_templates_name == template_name: + return template_path + + elif isinstance(restricted_name, str): + engine_object = find_engine_data(json_data) + restricted = json_data['restricted'].copy() + restricted.extend(engine_object['restricted']) + for restricted_path in restricted: + restricted_path = pathlib.Path(restricted_path).resolve() + restricted_json = restricted_path / 'restricted.json' + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + this_restricted_name = restricted_json_data['restricted_name'] + if this_restricted_name == restricted_name: + return restricted_path + + elif isinstance(default_folder, str): + if default_folder == 'engines': + default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() + return default_engines_folder + elif default_folder == 'projects': + default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() + return default_projects_folder + elif default_folder == 'gems': + default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() + return default_gems_folder + elif default_folder == 'templates': + default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() + return default_templates_folder + elif default_folder == 'restricted': + default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() + return default_restricted_folder + + elif isinstance(repo_name, str): + cache_folder = get_o3de_cache_folder() + for repo_uri in json_data['repos']: + repo_uri = pathlib.Path(repo_uri).resolve() + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if cache_file.is_file(): + repo = pathlib.Path(cache_file).resolve() + with repo.open('r') as f: + try: + repo_json_data = json.load(f) + except Exception as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + this_repos_name = repo_json_data['repo_name'] + if this_repos_name == repo_name: + return repo_uri + return None + + +def print_engines_data(engines_data: dict) -> None: + print('\n') + print("Engines================================================") + for engine_object in engines_data: + # if it's not local it should be in the cache + engine_uri = engine_object['path'] + parsed_uri = urllib.parse.urlparse(engine_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(engine_uri.encode()) + cache_folder = get_o3de_cache_folder() + engine = cache_folder / str(repo_sha256.hexdigest() + '.json') + print(f'{engine_uri}/engine.json cached as:') + else: + engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json' + + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + print(engine_json) + print(json.dumps(engine_json_data, indent=4)) + print('\n') + + +def print_projects_data(projects_data: dict) -> None: + print('\n') + print("Projects================================================") + for project_uri in projects_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(project_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(project_uri.encode()) + cache_folder = get_o3de_cache_folder() + project_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + project_json = pathlib.Path(project_uri).resolve() / 'project.json' + + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + print(project_json) + print(json.dumps(project_json_data, indent=4)) + print('\n') + + +def print_gems_data(gems_data: dict) -> None: + print('\n') + print("Gems================================================") + for gem_uri in gems_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(gem_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(gem_uri.encode()) + cache_folder = get_o3de_cache_folder() + gem_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + gem_json = pathlib.Path(gem_uri).resolve() / 'gem.json' + + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + print(gem_json) + print(json.dumps(gem_json_data, indent=4)) + print('\n') + + +def print_templates_data(templates_data: dict) -> None: + print('\n') + print("Templates================================================") + for template_uri in templates_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(template_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(template_uri.encode()) + cache_folder = get_o3de_cache_folder() + template_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + template_json = pathlib.Path(template_uri).resolve() / 'template.json' + + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_json} failed to load: {str(e)}') + else: + print(template_json) + print(json.dumps(template_json_data, indent=4)) + print('\n') + + +def print_repos_data(repos_data: dict) -> None: + print('\n') + print("Repos================================================") + cache_folder = get_o3de_cache_folder() + for repo_uri in repos_data: + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if valid_o3de_repo_json(cache_file): + with cache_file.open('r') as s: + try: + repo_json_data = json.load(s) + except Exception as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + print(f'{repo_uri}/repo.json cached as:') + print(cache_file) + print(json.dumps(repo_json_data, indent=4)) + print('\n') + + +def print_restricted_data(restricted_data: dict) -> None: + print('\n') + print("Restricted================================================") + for restricted_path in restricted_data: + restricted_json = pathlib.Path(restricted_path).resolve() / 'restricted.json' + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + print(restricted_json) + print(json.dumps(restricted_json_data, indent=4)) + print('\n') + + +def get_this_engine() -> dict: + json_data = load_o3de_manifest() + engine_data = find_engine_data(json_data) + return engine_data + + +def get_engines() -> dict: + json_data = load_o3de_manifest() + return json_data['engines'] + + +def get_projects() -> dict: + json_data = load_o3de_manifest() + return json_data['projects'] + + +def get_gems() -> dict: + json_data = load_o3de_manifest() + return json_data['gems'] + + +def get_templates() -> dict: + json_data = load_o3de_manifest() + return json_data['templates'] + + +def get_restricted() -> dict: + json_data = load_o3de_manifest() + return json_data['restricted'] + + +def get_repos() -> dict: + json_data = load_o3de_manifest() + return json_data['repos'] + + +def get_engine_projects() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + return engine_object['projects'] + + +def get_engine_gems() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + return engine_object['gems'] + + +def get_engine_templates() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + return engine_object['templates'] + + +def get_engine_restricted() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + return engine_object['restricted'] + + +def get_external_subdirectories() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + return engine_object['external_subdirectories'] + + +def get_all_projects() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + projects_data = json_data['projects'].copy() + projects_data.extend(engine_object['projects']) + return projects_data + + +def get_all_gems() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + gems_data = json_data['gems'].copy() + gems_data.extend(engine_object['gems']) + return gems_data + + +def get_all_templates() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + templates_data = json_data['templates'].copy() + templates_data.extend(engine_object['templates']) + return templates_data + + +def get_all_restricted() -> dict: + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data) + restricted_data = json_data['restricted'].copy() + restricted_data.extend(engine_object['restricted']) + return restricted_data + + +def print_this_engine(verbose: int) -> None: + engine_data = get_this_engine() + print(json.dumps(engine_data, indent=4)) + if verbose > 0: + print_engines_data(engine_data) + + +def print_engines(verbose: int) -> None: + engines_data = get_engines() + print(json.dumps(engines_data, indent=4)) + if verbose > 0: + print_engines_data(engines_data) + + +def print_projects(verbose: int) -> None: + projects_data = get_projects() + print(json.dumps(projects_data, indent=4)) + if verbose > 0: + print_projects_data(projects_data) + + +def print_gems(verbose: int) -> None: + gems_data = get_gems() + print(json.dumps(gems_data, indent=4)) + if verbose > 0: + print_gems_data(gems_data) + + +def print_templates(verbose: int) -> None: + templates_data = get_templates() + print(json.dumps(templates_data, indent=4)) + if verbose > 0: + print_templates_data(templates_data) + + +def print_restricted(verbose: int) -> None: + restricted_data = get_restricted() + print(json.dumps(restricted_data, indent=4)) + if verbose > 0: + print_restricted_data(restricted_data) + + +def register_show_repos(verbose: int) -> None: + repos_data = get_repos() + print(json.dumps(repos_data, indent=4)) + if verbose > 0: + print_repos_data(repos_data) + + +def print_engine_projects(verbose: int) -> None: + engine_projects_data = get_engine_projects() + print(json.dumps(engine_projects_data, indent=4)) + if verbose > 0: + print_projects_data(engine_projects_data) + + +def print_engine_gems(verbose: int) -> None: + engine_gems_data = get_engine_gems() + print(json.dumps(engine_gems_data, indent=4)) + if verbose > 0: + print_gems_data(engine_gems_data) + + +def print_engine_templates(verbose: int) -> None: + engine_templates_data = get_engine_templates() + print(json.dumps(engine_templates_data, indent=4)) + if verbose > 0: + print_templates_data(engine_templates_data) + + +def print_engine_restricted(verbose: int) -> None: + engine_restricted_data = get_engine_restricted() + print(json.dumps(engine_restricted_data, indent=4)) + if verbose > 0: + print_restricted_data(engine_restricted_data) + + +def print_external_subdirectories(verbose: int) -> None: + external_subdirs_data = get_external_subdirectories() + print(json.dumps(external_subdirs_data, indent=4)) + + +def print_all_projects(verbose: int) -> None: + all_projects_data = get_all_projects() + print(json.dumps(all_projects_data, indent=4)) + if verbose > 0: + print_projects_data(all_projects_data) + + +def print_all_gems(verbose: int) -> None: + all_gems_data = get_all_gems() + print(json.dumps(all_gems_data, indent=4)) + if verbose > 0: + print_gems_data(all_gems_data) + + +def print_all_templates(verbose: int) -> None: + all_templates_data = get_all_templates() + print(json.dumps(all_templates_data, indent=4)) + if verbose > 0: + print_templates_data(all_templates_data) + + +def print_all_restricted(verbose: int) -> None: + all_restricted_data = get_all_restricted() + print(json.dumps(all_restricted_data, indent=4)) + if verbose > 0: + print_restricted_data(all_restricted_data) + + +def register_show(verbose: int) -> None: + json_data = load_o3de_manifest() + print(f"{get_o3de_manifest()}:") + print(json.dumps(json_data, indent=4)) + + if verbose > 0: + print_engines_data(get_engines()) + print_projects_data(get_all_projects()) + print_gems_data(get_gems()) + print_templates_data(get_all_templates()) + print_restricted_data(get_all_restricted()) + print_repos_data(get_repos()) + + +def find_engine_data(json_data: dict, + engine_path: str or pathlib.Path = None) -> dict or None: + if not engine_path: + engine_path = get_this_engine_path() + engine_path = pathlib.Path(engine_path).resolve() + + for engine_object in json_data['engines']: + engine_object_path = pathlib.Path(engine_object['path']).resolve() + if engine_path == engine_object_path: + return engine_object + + return None + + +def get_engine_data(engine_name: str = None, + engine_path: str or pathlib.Path = None, ) -> dict or None: + if not engine_name and not engine_path: + logger.error('Must specify either a Engine name or Engine Path.') + return 1 + + if engine_name and not engine_path: + engine_path = get_registered(engine_name=engine_name) + + if not engine_path: + logger.error(f'Engine Path {engine_path} has not been registered.') + return 1 + + engine_path = pathlib.Path(engine_path).resolve() + engine_json = engine_path / 'engine.json' + if not engine_json.is_file(): + logger.error(f'Engine json {engine_json} is not present.') + return 1 + if not valid_o3de_engine_json(engine_json): + logger.error(f'Engine json {engine_json} is not valid.') + return 1 + + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + return engine_json_data + + return None + + +def get_project_data(project_name: str = None, + project_path: str or pathlib.Path = None, ) -> dict or None: + if not project_name and not project_path: + logger.error('Must specify either a Project name or Project Path.') + return 1 + + if project_name and not project_path: + project_path = get_registered(project_name=project_name) + + if not project_path: + logger.error(f'Project Path {project_path} has not been registered.') + return 1 + + project_path = pathlib.Path(project_path).resolve() + project_json = project_path / 'project.json' + if not project_json.is_file(): + logger.error(f'Project json {project_json} is not present.') + return 1 + if not valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + return project_json_data + + return None + + +def get_gem_data(gem_name: str = None, + gem_path: str or pathlib.Path = None, ) -> dict or None: + if not gem_name and not gem_path: + logger.error('Must specify either a Gem name or Gem Path.') + return 1 + + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) + + if not gem_path: + logger.error(f'Gem Path {gem_path} has not been registered.') + return 1 + + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + logger.error(f'Gem json {gem_json} is not present.') + return 1 + if not valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + return gem_json_data + + return None + + +def get_template_data(template_name: str = None, + template_path: str or pathlib.Path = None, ) -> dict or None: + if not template_name and not template_path: + logger.error('Must specify either a Template name or Template Path.') + return 1 + + if template_name and not template_path: + template_path = get_registered(template_name=template_name) + + if not template_path: + logger.error(f'Template Path {template_path} has not been registered.') + return 1 + + template_path = pathlib.Path(template_path).resolve() + template_json = template_path / 'template.json' + if not template_json.is_file(): + logger.error(f'Template json {template_json} is not present.') + return 1 + if not valid_o3de_template_json(template_json): + logger.error(f'Template json {template_json} is not valid.') + return 1 + + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_json} failed to load: {str(e)}') + else: + return template_json_data + + return None + + +def get_restricted_data(restricted_name: str = None, + restricted_path: str or pathlib.Path = None, ) -> dict or None: + if not restricted_name and not restricted_path: + logger.error('Must specify either a Restricted name or Restricted Path.') + return 1 + + if restricted_name and not restricted_path: + restricted_path = get_registered(restricted_name=restricted_name) + + if not restricted_path: + logger.error(f'Restricted Path {restricted_path} has not been registered.') + return 1 + + restricted_path = pathlib.Path(restricted_path).resolve() + restricted_json = restricted_path / 'restricted.json' + if not restricted_json.is_file(): + logger.error(f'Restricted json {restricted_json} is not present.') + return 1 + if not valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return 1 + + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + return restricted_json_data + + return None + + +def get_downloadables() -> dict: + json_data = load_o3de_manifest() + downloadable_data = {} + downloadable_data.update({'engines': []}) + downloadable_data.update({'projects': []}) + downloadable_data.update({'gems': []}) + downloadable_data.update({'templates': []}) + downloadable_data.update({'restricted': []}) + + def recurse_downloadables(repo_uri: str or pathlib.Path) -> None: + cache_folder = get_o3de_cache_folder() + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if valid_o3de_repo_json(cache_file): + with cache_file.open('r') as s: + try: + repo_json_data = json.load(s) + except Exception as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + for engine in repo_json_data['engines']: + if engine not in downloadable_data['engines']: + downloadable_data['engines'].append(engine) + + for project in repo_json_data['projects']: + if project not in downloadable_data['projects']: + downloadable_data['projects'].append(project) + + for gem in repo_json_data['gems']: + if gem not in downloadable_data['gems']: + downloadable_data['gems'].append(gem) + + for template in repo_json_data['templates']: + if template not in downloadable_data['templates']: + downloadable_data['templates'].append(template) + + for restricted in repo_json_data['restricted']: + if restricted not in downloadable_data['restricted']: + downloadable_data['restricted'].append(restricted) + + for repo in repo_json_data['repos']: + if repo not in downloadable_data['repos']: + downloadable_data['repos'].append(repo) + + for repo in downloadable_data['repos']: + recurse_downloadables(repo) + + for repo_entry in json_data['repos']: + recurse_downloadables(repo_entry) + return downloadable_data + + +def get_downloadable_engines() -> dict: + downloadable_data = get_downloadables() + return downloadable_data['engines'] + + +def get_downloadable_projects() -> dict: + downloadable_data = get_downloadables() + return downloadable_data['projects'] + + +def get_downloadable_gems() -> dict: + downloadable_data = get_downloadables() + return downloadable_data['gems'] + + +def get_downloadable_templates() -> dict: + downloadable_data = get_downloadables() + return downloadable_data['templates'] + + +def get_downloadable_restricted() -> dict: + downloadable_data = get_downloadables() + return downloadable_data['restricted'] + + +def print_downloadable_engines(verbose: int) -> None: + downloadable_engines = get_downloadable_engines() + for engine_data in downloadable_engines: + print(json.dumps(engine_data, indent=4)) + if verbose > 0: + print_engines_data(downloadable_engines) + + +def print_downloadable_projects(verbose: int) -> None: + downloadable_projects = get_downloadable_projects() + for projects_data in downloadable_projects: + print(json.dumps(projects_data, indent=4)) + if verbose > 0: + print_projects_data(downloadable_projects) + + +def print_downloadable_gems(verbose: int) -> None: + downloadable_gems = get_downloadable_gems() + for gem_data in downloadable_gems: + print(json.dumps(gem_data, indent=4)) + if verbose > 0: + print_gems_data(downloadable_gems) + + +def print_downloadable_templates(verbose: int) -> None: + downloadable_templates = get_downloadable_templates() + for template_data in downloadable_templates: + print(json.dumps(template_data, indent=4)) + if verbose > 0: + print_engines_data(downloadable_templates) + + +def print_downloadable_restricted(verbose: int) -> None: + downloadable_restricted = get_downloadable_restricted() + for restricted_data in downloadable_restricted: + print(json.dumps(restricted_data, indent=4)) + if verbose > 0: + print_engines_data(downloadable_restricted) + + +def print_downloadables(verbose: int) -> None: + downloadable_data = get_downloadables() + print(json.dumps(downloadable_data, indent=4)) + if verbose > 0: + print_engines_data(downloadable_data['engines']) + print_projects_data(downloadable_data['projects']) + print_gems_data(downloadable_data['gems']) + print_templates_data(downloadable_data['templates']) + print_restricted_data(downloadable_data['templates']) + + +def download_engine(engine_name: str, + dest_path: str) -> int: + if not dest_path: + dest_path = get_registered(default_folder='engines') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True) + + download_path = get_o3de_download_folder() / 'engines' / engine_name + download_path.mkdir(exist_ok=True) + download_zip_path = download_path / 'engine.zip' + + downloadable_engine_data = get_downloadable(engine_name=engine_name) + if not downloadable_engine_data: + logger.error(f'Downloadable engine {engine_name} not found.') + return 1 + + origin = downloadable_engine_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Engine zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the engine.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_engine_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised engine you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised engine!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded engine.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the engine.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_engine_folder = dest_path / engine_name + if dest_engine_folder.is_dir(): + backup_folder(dest_engine_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_engine_json = dest_engine_folder / 'engine.json' + if not unzipped_engine_json.is_file(): + logger.error(f'Engine json {unzipped_engine_json} is missing.') + return 1 + + if not valid_o3de_engine_json(unzipped_engine_json): + logger.error(f'Engine json {unzipped_engine_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable engine.json + # then compare it to the engine.json in the zip, they should now be identical + try: + del downloadable_engine_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_engine_data, indent=4).encode('utf8')).hexdigest() + with unzipped_engine_json.open('r') as s: + try: + unzipped_engine_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read engine json {unzipped_engine_json}. Unable to confirm this' + f' is the same template that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_engine_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded engine.json does not match' + f' the advertised engine.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_project(project_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = get_registered(default_folder='projects') + if not dest_path: + logger.error(f'Destination path not specified and not default projects path.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = get_o3de_download_folder() / 'projects' / project_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'project.zip' + + downloadable_project_data = get_downloadable(project_name=project_name) + if not downloadable_project_data: + logger.error(f'Downloadable project {project_name} not found.') + return 1 + + origin = downloadable_project_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Project zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the project.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_project_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised project you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised project!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded project.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the project.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_project_folder = dest_path / project_name + if dest_project_folder.is_dir(): + backup_folder(dest_project_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_project_folder) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_project_json = dest_project_folder / 'project.json' + if not unzipped_project_json.is_file(): + logger.error(f'Project json {unzipped_project_json} is missing.') + return 1 + + if not valid_o3de_project_json(unzipped_project_json): + logger.error(f'Project json {unzipped_project_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable project.json + # then compare it to the project.json in the zip, they should now be identical + try: + del downloadable_project_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_project_data, indent=4).encode('utf8')).hexdigest() + with unzipped_project_json.open('r') as s: + try: + unzipped_project_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Project json {unzipped_project_json}. Unable to confirm this' + f' is the same project that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_project_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded project.json does not match' + f' the advertised project.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_gem(gem_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = get_registered(default_folder='gems') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = get_o3de_download_folder() / 'gems' / gem_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'gem.zip' + + downloadable_gem_data = get_downloadable(gem_name=gem_name) + if not downloadable_gem_data: + logger.error(f'Downloadable gem {gem_name} not found.') + return 1 + + origin = downloadable_gem_data['origin'] + url = f'{origin}/gem.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Gem zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the gem.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_gem_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised gem you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised gem!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded gem.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the gem.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_gem_folder = dest_path / gem_name + if dest_gem_folder.is_dir(): + backup_folder(dest_gem_folder) + with zipfile.ZipFile(download_zip_path, 'r') as gem_zip: + try: + gem_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_gem_json = dest_gem_folder / 'gem.json' + if not unzipped_gem_json.is_file(): + logger.error(f'Engine json {unzipped_gem_json} is missing.') + return 1 + + if not valid_o3de_engine_json(unzipped_gem_json): + logger.error(f'Engine json {unzipped_gem_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable gem.json + # then compare it to the gem.json in the zip, they should now be identical + try: + del downloadable_gem_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_gem_data, indent=4).encode('utf8')).hexdigest() + with unzipped_gem_json.open('r') as s: + try: + unzipped_gem_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read gem json {unzipped_gem_json}. Unable to confirm this' + f' is the same gem that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_gem_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded gem.json does not match' + f' the advertised gem.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_template(template_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = get_registered(default_folder='templates') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = get_o3de_download_folder() / 'templates' / template_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'template.zip' + + downloadable_template_data = get_downloadable(template_name=template_name) + if not downloadable_template_data: + logger.error(f'Downloadable template {template_name} not found.') + return 1 + + origin = downloadable_template_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + result = 0 + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Template zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the template.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_template_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised template you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised template!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded template.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the template.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_template_folder = dest_path / template_name + if dest_template_folder.is_dir(): + backup_folder(dest_template_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_template_json = dest_template_folder / 'template.json' + if not unzipped_template_json.is_file(): + logger.error(f'Template json {unzipped_template_json} is missing.') + return 1 + + if not valid_o3de_engine_json(unzipped_template_json): + logger.error(f'Template json {unzipped_template_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable template.json + # then compare it to the template.json in the zip, they should now be identical + try: + del downloadable_template_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_template_data, indent=4).encode('utf8')).hexdigest() + with unzipped_template_json.open('r') as s: + try: + unzipped_template_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Template json {unzipped_template_json}. Unable to confirm this' + f' is the same template that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_template_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded template.json does not match' + f' the advertised template.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_restricted(restricted_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = get_registered(default_folder='restricted') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = get_o3de_download_folder() / 'restricted' / restricted_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'restricted.zip' + + downloadable_restricted_data = get_downloadable(restricted_name=restricted_name) + if not downloadable_restricted_data: + logger.error(f'Downloadable Restricted {restricted_name} not found.') + return 1 + + origin = downloadable_restricted_data['origin'] + url = f'{origin}/restricted.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Restricted already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Restricted zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the restricted.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_restricted_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised restricted you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised restricted!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded restricted.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the restricted.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_restricted_folder = dest_path / restricted_name + if dest_restricted_folder.is_dir(): + backup_folder(dest_restricted_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_restricted_json = dest_restricted_folder / 'restricted.json' + if not unzipped_restricted_json.is_file(): + logger.error(f'Restricted json {unzipped_restricted_json} is missing.') + return 1 + + if not valid_o3de_engine_json(unzipped_restricted_json): + logger.error(f'Restricted json {unzipped_restricted_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable restricted.json + # then compare it to the restricted.json in the zip, they should now be identical + try: + del downloadable_restricted_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_restricted_data, indent=4).encode('utf8')).hexdigest() + with unzipped_restricted_json.open('r') as s: + try: + unzipped_restricted_json_data = json.load(s) + except Exception as e: + logger.error( + f'Failed to read Restricted json {unzipped_restricted_json}. Unable to confirm this' + f' is the same restricted that was advertised.') + return 1 + sha256B = hashlib.sha256( + json.dumps(unzipped_restricted_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded restricted.json does not match' + f' the advertised restricted.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def add_gem_dependency(cmake_file: str or pathlib.Path, + gem_target: str) -> int: + """ + adds a gem dependency to a cmake file + :param cmake_file: path to the cmake file + :param gem_target: name of the cmake target + :return: 0 for success or non 0 failure code + """ + if not os.path.isfile(cmake_file): + logger.error(f'Failed to locate cmake file {cmake_file}') + return 1 + + # on a line by basis, see if there already is Gem::{gem_name} + # find the first occurrence of a gem, copy its formatting and replace + # the gem name with the new one and append it + # if the gem is already present fail + t_data = [] + added = False + with open(cmake_file, 'r') as s: + for line in s: + if f'Gem::{gem_target}' in line: + logger.warning(f'{gem_target} is already a gem dependency.') + return 0 + if not added and r'Gem::' in line: + new_gem = ' ' * line.find(r'Gem::') + f'Gem::{gem_target}\n' + t_data.append(new_gem) + added = True + t_data.append(line) + + # if we didn't add it the set gem dependencies could be empty so + # add a new gem, if empty the correct format is 1 tab=4spaces + if not added: + index = 0 + for line in t_data: + index = index + 1 + if r'set(GEM_DEPENDENCIES' in line: + t_data.insert(index, f' Gem::{gem_target}\n') + added = True + break + + # if we didn't add it then it's not here, add a whole new one + if not added: + t_data.append('\n') + t_data.append('set(GEM_DEPENDENCIES\n') + t_data.append(f' Gem::{gem_target}\n') + t_data.append(')\n') + + # write the cmake + os.unlink(cmake_file) + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +def get_project_runtime_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + + +def get_project_tool_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + + +def get_project_server_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + + +def get_project_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + runtime_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + tool_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + server_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + return runtime_gems.union(tool_gems.union(server_gems)) + + +def get_gem_targets_from_cmake_file(cmake_file: str or pathlib.Path) -> set: + """ + Gets a list of declared gem targets dependencies of a cmake file + :param cmake_file: path to the cmake file + :return: set of gem targets found + """ + cmake_file = pathlib.Path(cmake_file).resolve() + + if not cmake_file.is_file(): + logger.error(f'Failed to locate cmake file {cmake_file}') + return set() + + gem_target_set = set() + with cmake_file.open('r') as s: + for line in s: + gem_name = line.split('Gem::') + if len(gem_name) > 1: + # Only take the name as everything leading up to the first '.' if found + # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName + # as different targets of the GemName Gem + gem_target_set.add(gem_name[1].replace('\n', '')) + return gem_target_set + + +def get_project_runtime_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + + +def get_project_tool_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + + +def get_project_server_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + + +def get_project_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + runtime_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + tool_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + server_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + return runtime_gem_names.union(tool_gem_names.union(server_gem_names)) + + +def get_gem_names_from_cmake_file(cmake_file: str or pathlib.Path) -> set: + """ + Gets a list of declared gem dependencies of a cmake file + :param cmake_file: path to the cmake file + :return: set of gems found + """ + cmake_file = pathlib.Path(cmake_file).resolve() + + if not cmake_file.is_file(): + logger.error(f'Failed to locate cmake file {cmake_file}') + return set() + + gem_set = set() + with cmake_file.open('r') as s: + for line in s: + gem_name = line.split('Gem::') + if len(gem_name) > 1: + # Only take the name as everything leading up to the first '.' if found + # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName + # as different targets of the GemName Gem + gem_set.add(gem_name[1].split('.')[0].replace('\n', '')) + return gem_set + + +def get_project_runtime_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_runtime_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_tool_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_tool_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_server_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_server_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(get_registered(gem_name=gem_name)) + return gem_paths + + +def remove_gem_dependency(cmake_file: str or pathlib.Path, + gem_target: str) -> int: + """ + removes a gem dependency from a cmake file + :param cmake_file: path to the cmake file + :param gem_target: cmake target name + :return: 0 for success or non 0 failure code + """ + if not os.path.isfile(cmake_file): + logger.error(f'Failed to locate cmake file {cmake_file}') + return 1 + + # on a line by basis, remove any line with Gem::{gem_name} + t_data = [] + # Remove the gem from the cmake_dependencies file by skipping the gem name entry + removed = False + with open(cmake_file, 'r') as s: + for line in s: + if f'Gem::{gem_target}' in line: + removed = True + else: + t_data.append(line) + + if not removed: + logger.error(f'Failed to remove Gem::{gem_target} from cmake file {cmake_file}') + return 1 + + # write the cmake + os.unlink(cmake_file) + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element + project_templates = [] + for template in get_all_templates(): + if 'Project' in template: + project_templates.append(template) + return project_templates -def refresh_repos() -> int: - json_data = load_o3de_registry() - cache_folder = get_o3de_cache() - shutil.rmtree(cache_folder) - cache_folder.mkdir(parents=True, exist_ok=True) - if len(json_data['repos']) == 0: - return 0 - result = 0 - last_failure = 0 - for repo_uri in json_data['repos']: - repo_hash = hashlib.md5(repo_uri.encode()) - cache_file = cache_folder / str(repo_hash.hexdigest() + '.json') - parsed_uri = urllib.parse.urlparse(repo_uri) +def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element + gem_templates = [] + for template in get_all_templates(): + if 'Gem' in template: + gem_templates.append(template) + return gem_templates - last_failure = 0 # download and validate the repo_uri - if not last_failure: - result = 1 - return result +def get_generic_templates(): # temporary until we have a better way to do this... maybe template_type element + generic_templates = [] + for template in get_all_templates(): + if 'Project' not in template and 'Gem' not in template: + generic_templates.append(template) + return generic_templates -def get_registered(engine_name: str = None, - project_name: str = None, - gem_name: str = None, - template_name: str = None, - default_folder: str = None, - repo_name: str = None): - json_data = load_o3de_registry() +def get_dependencies_cmake_file(project_name: str = None, + project_path: str or pathlib.Path = None, + dependency_type: str = 'runtime', + platform: str = 'Common') -> str or None: + """ + get the standard cmake file name for a particular type of dependency + :param gem_name: name of the gem, resolves gem_path + :param gem_path: path of the gem + :return: list of gem targets + """ + if not project_name and not project_path: + logger.error(f'Must supply either a Project Name or Project Path.') + return None - if type(engine_name) == str: - for engine in json_data['engines']: - engine = pathlib.Path(engine) / 'engine.json' - with engine.open('r') as f: - engine_json_data = json.load(f) - this_engines_name = engine_json_data['engine_name'] - if this_engines_name == engine_name: - engine = engine.parent.as_posix() - return engine - - elif type(project_name) == str: - for project in json_data['projects']: - project = pathlib.Path(project) / 'project.json' - with project.open('r') as f: - project_json_data = json.load(f) - this_projects_name = project_json_data['project_name'] - if this_projects_name == project_name: - project = project.parent.as_posix() - return project - - elif type(gem_name) == str: - for gem in json_data['gems']: - gem = pathlib.Path(gem) / 'gem.json' - with gem.open('r') as f: - gem_json_data = json.load(f) - this_gems_name = gem_json_data['gem_name'] - if this_gems_name == gem_name: - gem = gem.parent.as_posix() - return gem - - elif type(template_name) == str: - for template in json_data['templates']: - template = pathlib.Path(template) / 'template.json' - with template.open('r') as f: - template_json_data = json.load(f) - this_templates_name = template_json_data['template_name'] - if this_templates_name == template_name: - template = template.parent.as_posix() - return template - - elif type(default_folder) == str: - if default_folder == 'project': - return json_data['default_projects_folder'] - elif default_folder == 'gem': - return json_data['default_gems_folder'] - elif default_folder == 'template': - return json_data['default_templates_folder'] - - elif type(repo_name) == str: - cache_folder = get_o3de_cache() - cache_folder.mkdir(parents=True, exist_ok=True) - for repo_uri in json_data['repos']: - repo_hash = hashlib.md5(repo_uri.encode()) - cache_file = cache_folder / str(repo_hash.hexdigest() + '.json') - if cache_file.is_file(): - repo = pathlib.Path(cache_file) - with repo.open('r') as f: - repo_json_data = json.load(f) - this_repos_name = repo_json_data['repo_name'] - if this_repos_name == repo_name: - repo = repo.parent.as_posix() - return repo - return None + if project_name and not project_path: + project_path = get_registered(project_name=project_name) + project_path = pathlib.Path(project_path).resolve() -def print_engines(json_data, - verbose: int): - if verbose > 0: - print('\n') - print("Engines================================================") - for engine in json_data['engines']: - engine = pathlib.Path(engine) / 'engine.json' - with engine.open('r') as f: - engine_json_data = json.load(f) - print(engine) - print(json.dumps(engine_json_data, indent=4)) - print('\n') + if platform == 'Common': + dependencies_file = f'{dependency_type}_dependencies.cmake' + dependencies_file_path = project_path / 'Gem/Code' / dependencies_file + if dependencies_file_path.is_file(): + return dependencies_file_path + return project_path / 'Code' / dependencies_file + else: + dependencies_file = f'{platform.lower()}_{dependency_type}_dependencies.cmake' + dependencies_file_path = project_path / 'Gem/Code/Platform' / platform / dependencies_file + if dependencies_file_path.is_file(): + return dependencies_file_path + return project_path / 'Code/Platform' / platform / dependencies_file -def print_projects(json_data, - verbose: int): - if verbose > 0: - print('\n') - print("Projects================================================") - for project in json_data['projects']: - project = pathlib.Path(project) / 'project.json' - with project.open('r') as f: - project_json_data = json.load(f) - print(project) - print(json.dumps(project_json_data, indent=4)) - print('\n') +def get_all_gem_targets() -> list: + modules = [] + for gem_path in get_all_gems(): + this_gems_targets = get_gem_targets(gem_path=gem_path) + modules.extend(this_gems_targets) + return modules -def print_gems(json_data, - verbose: int): - if verbose > 0: - print('\n') - print("Gems================================================") - for gem in json_data['gems']: - gem = pathlib.Path(gem) / 'gem.json' - with gem.open('r') as f: - gem_json_data = json.load(f) - print(gem) - print(json.dumps(gem_json_data, indent=4)) - print('\n') +def get_gem_targets(gem_name: str = None, + gem_path: str or pathlib.Path = None) -> list: + """ + Finds gem targets in a gem + :param gem_name: name of the gem, resolves gem_path + :param gem_path: path of the gem + :return: list of gem targets + """ + if not gem_name and not gem_path: + return [] + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) -def print_templates(json_data, - verbose: int): - if verbose > 0: - print("Templates================================================") - for template in json_data['templates']: - template = pathlib.Path(template) / 'template.json' - with template.open('r') as f: - template_json_data = json.load(f) - print(template) - print(json.dumps(template_json_data, indent=4)) - print('\n') + if not gem_path: + return [] + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not valid_o3de_gem_json(gem_json): + return [] + + module_identifiers = [ + 'MODULE', + 'GEM_MODULE', + '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}' + ] + modules = [] + for root, dirs, files in os.walk(gem_path): + for file in files: + if file == 'CMakeLists.txt': + with open(os.path.join(root, file), 'r') as s: + for line in s: + trimmed = line.lstrip() + if trimmed.startswith('NAME '): + trimmed = trimmed.rstrip(' \n') + split_trimmed = trimmed.split(' ') + if len(split_trimmed) == 3 and split_trimmed[2] in module_identifiers: + modules.append(split_trimmed[1]) + return modules + + +def add_external_subdirectory(external_subdir: str or pathlib.Path, + engine_path: str or pathlib.Path = None, + supress_errors: bool = False) -> int: + """ + add external subdirectory to a cmake + :param external_subdir: external subdirectory to add to cmake + :param engine_path: optional engine path, defaults to this engine + :param supress_errors: optional silence errors + :return: 0 for success or non 0 failure code + """ + external_subdir = pathlib.Path(external_subdir).resolve() + if not external_subdir.is_dir(): + if not supress_errors: + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') + return 1 -def print_repos(json_data: str, - verbose: int): - if verbose > 0: - print("Repos================================================") - cache_folder = get_o3de_cache() - cache_folder.mkdir(parents=True, exist_ok=True) - for repo in json_data['repos']: - repo_hash = hashlib.md5(repo.encode()) - cache_file = cache_folder / str(repo_hash.hexdigest() + '.json') - if valid_o3de_manifest_json(cache_file): - with cache_file.open('r') as s: - repo_json_data = json.load(s) - print(repo) - print(json.dumps(repo_json_data, indent=4)) - print('\n') + external_subdir_cmake = external_subdir / 'CMakeLists.txt' + if not external_subdir_cmake.is_file(): + if not supress_errors: + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') + return 1 + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data, engine_path) + if not engine_object: + if not supress_errors: + logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') + return 1 -def register_show_engines(verbose: int): - json_data = load_o3de_registry() + while external_subdir.as_posix() in engine_object['external_subdirectories']: + engine_object['external_subdirectories'].remove(external_subdir.as_posix()) + + def parse_cmake_file(cmake: str or pathlib.Path, + files: set()): + cmake_path = pathlib.Path(cmake).resolve() + cmake_file = cmake_path + if cmake_path.is_dir(): + files.add(cmake_path) + cmake_file = cmake_path / 'CMakeLists.txt' + elif cmake_path.is_file(): + cmake_path = cmake_path.parent + else: + return + + with cmake_file.open('r') as s: + lines = s.readlines() + for line in lines: + line = line.strip() + start = line.find('include(') + if start == 0: + end = line.find(')', start) + if end > start + len('include('): + try: + include_cmake_file = pathlib.Path(engine_path / line[start + len('include('): end]).resolve() + except Exception as e: + pass + else: + parse_cmake_file(include_cmake_file, files) + else: + start = line.find('add_subdirectory(') + if start == 0: + end = line.find(')', start) + if end > start + len('add_subdirectory('): + try: + include_cmake_file = pathlib.Path( + cmake_path / line[start + len('add_subdirectory('): end]).resolve() + except Exception as e: + pass + else: + parse_cmake_file(include_cmake_file, files) + + cmake_files = set() + parse_cmake_file(engine_path, cmake_files) + for external in engine_object["external_subdirectories"]: + parse_cmake_file(external, cmake_files) + + if external_subdir in cmake_files: + save_o3de_manifest(json_data) + if not supress_errors: + logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') + return 1 - del json_data['repo_name'] - del json_data['origin'] - del json_data['projects'] - del json_data['gems'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + engine_object['external_subdirectories'].insert(0, external_subdir.as_posix()) + engine_object['external_subdirectories'] = sorted(engine_object['external_subdirectories']) - print(json.dumps(json_data, indent=4)) - print_engines(json_data, - verbose) + save_o3de_manifest(json_data) + return 0 -def register_show_projects(verbose: int): - json_data = load_o3de_registry() - del json_data['repo_name'] - del json_data['origin'] - del json_data['engines'] - del json_data['gems'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] +def remove_external_subdirectory(external_subdir: str or pathlib.Path, + engine_path: str or pathlib.Path = None) -> int: + """ + remove external subdirectory from cmake + :param external_subdir: external subdirectory to add to cmake + :param engine_path: optional engine path, defaults to this engine + :return: 0 for success or non 0 failure code + """ + json_data = load_o3de_manifest() + engine_object = find_engine_data(json_data, engine_path) + if not engine_object: + logger.error(f'Remove External Subdirectory Failed: {engine_path} not registered.') + return 1 - print(json.dumps(json_data, indent=4)) - print_projects(json_data, - verbose) + external_subdir = pathlib.Path(external_subdir).resolve() + while external_subdir.as_posix() in engine_object['external_subdirectories']: + engine_object['external_subdirectories'].remove(external_subdir.as_posix()) + save_o3de_manifest(json_data) -def register_show_gems(verbose: int): - json_data = load_o3de_registry() + return 0 - del json_data['repo_name'] - del json_data['origin'] - del json_data['engines'] - del json_data['projects'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] - print(json.dumps(json_data, indent=4)) - print_gems(json_data, - verbose) +def add_gem_to_cmake(gem_name: str = None, + gem_path: str or pathlib.Path = None, + engine_name: str = None, + engine_path: str or pathlib.Path = None, + supress_errors: bool = False) -> int: + """ + add a gem to a cmake as an external subdirectory for an engine + :param gem_name: name of the gem to add to cmake + :param gem_path: the path of the gem to add to cmake + :param engine_name: name of the engine to add to cmake + :param engine_path: the path of the engine to add external subdirectory to, default to this engine + :param supress_errors: optional silence errors + :return: 0 for success or non 0 failure code + """ + if not gem_name and not gem_path: + if not supress_errors: + logger.error('Must specify either a Gem name or Gem Path.') + return 1 + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) -def register_show_templates(verbose: int): - json_data = load_o3de_registry() + if not gem_path: + if not supress_errors: + logger.error(f'Gem Path {gem_path} has not been registered.') + return 1 - del json_data['repo_name'] - del json_data['origin'] - del json_data['engines'] - del json_data['projects'] - del json_data['gems'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + if not supress_errors: + logger.error(f'Gem json {gem_json} is not present.') + return 1 + if not valid_o3de_gem_json(gem_json): + if not supress_errors: + logger.error(f'Gem json {gem_json} is not valid.') + return 1 - print(json.dumps(json_data, indent=4)) - print_templates(json_data, - verbose) + if not engine_name and not engine_path: + engine_path = get_this_engine_path() + if engine_name and not engine_path: + engine_path = get_registered(engine_name=engine_name) -def register_show_repos(verbose: int): - json_data = load_o3de_registry() + if not engine_path: + if not supress_errors: + logger.error(f'Engine Path {engine_path} has not been registered.') + return 1 - del json_data['repo_name'] - del json_data['origin'] - del json_data['engines'] - del json_data['projects'] - del json_data['gems'] - del json_data['templates'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + engine_json = engine_path / 'engine.json' + if not engine_json.is_file(): + if not supress_errors: + logger.error(f'Engine json {engine_json} is not present.') + return 1 + if not valid_o3de_engine_json(engine_json): + if not supress_errors: + logger.error(f'Engine json {engine_json} is not valid.') + return 1 - print(json.dumps(json_data, indent=4)) - print_repos(json_data, - verbose) + return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, supress_errors=supress_errors) -def register_show(verbose: int): - json_data = load_o3de_registry() - if verbose > 0: - print(f"{get_o3de_registry()}:") +def remove_gem_from_cmake(gem_name: str = None, + gem_path: str or pathlib.Path = None, + engine_name: str = None, + engine_path: str or pathlib.Path = None) -> int: + """ + remove a gem to cmake as an external subdirectory + :param gem_name: name of the gem to remove from cmake + :param gem_path: the path of the gem to add to cmake + :param engine_name: optional name of the engine to remove from cmake + :param engine_path: the path of the engine to remove external subdirectory from, defaults to this engine + :return: 0 for success or non 0 failure code + """ + if not gem_name and not gem_path: + logger.error('Must specify either a Gem name or Gem Path.') + return 1 - print(json.dumps(json_data, indent=4)) + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) - print_engines(json_data, - verbose) - print_projects(json_data, - verbose) - print_gems(json_data, - verbose) - print_templates(json_data, - verbose) - print_repos(json_data, - verbose) + if not gem_path: + logger.error(f'Gem Path {gem_path} has not been registered.') + return 1 - if verbose > 0: - print("Default Folders================================================") - print(f"Default projects folder: {json_data['default_projects_folder']}") - print(os.listdir(json_data['default_projects_folder'])) - print('\n') - print(f"Default gems folder: {json_data['default_gems_folder']}") - print(os.listdir(json_data['default_gems_folder'])) - print('\n') - print(f"Default templates folder: {json_data['default_templates_folder']}") - print(os.listdir(json_data['default_templates_folder'])) + if not engine_name and not engine_path: + engine_path = get_this_engine_path() + if engine_name and not engine_path: + engine_path = get_registered(engine_name=engine_name) -def aggregate_repo(json_data, repo_uri: str): - cache_folder = get_o3de_cache() - cache_folder.mkdir(parents=True, exist_ok=True) - repo_hash = hashlib.md5(repo_uri.encode()) - cache_file = cache_folder / str(repo_hash.hexdigest() + '.json') - if valid_o3de_manifest_json(cache_file): - with cache_file.open('r') as s: - repo_json_data = json.load(s) - for engine in repo_json_data['engines']: - if engine not in json_data['engines']: - json_data['engines'].append(engine) - - for project in repo_json_data['projects']: - if project not in json_data['projects']: - json_data['projects'].append(project) - - for gem in repo_json_data['gems']: - if gem not in json_data['gems']: - json_data['gems'].append(gem) - - for template in repo_json_data['templates']: - if template not in json_data['templates']: - json_data['templates'].append(template) - - for repo in repo_json_data['repos']: - if repo not in json_data['repos']: - json_data['repos'].append(repo) - - for repo_uri in repo_json_data['repos']: - aggregate_repo(json_data, repo_uri) - - -def register_show_aggregate_engines(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) - - del json_data['projects'] - del json_data['gems'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + if not engine_path: + logger.error(f'Engine Path {engine_path} is not registered.') + return 1 - print(json.dumps(json_data, indent=4)) - print_engines(json_data, - verbose) + return remove_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) -def register_show_aggregate_projects(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) +def add_gem_to_project(gem_name: str = None, + gem_path: str or pathlib.Path = None, + gem_target: str = None, + project_name: str = None, + project_path: str or pathlib.Path = None, + dependencies_file: str or pathlib.Path = None, + runtime_dependency: bool = False, + tool_dependency: bool = False, + server_dependency: bool = False, + platforms: str = 'Common', + add_to_cmake: bool = True) -> int: + """ + add a gem to a project + :param gem_name: name of the gem to add + :param gem_path: path to the gem to add + :param gem_target: the name of the cmake gem module + :param project_name: name of to the project to add the gem to + :param project_path: path to the project to add the gem to + :param dependencies_file: if this dependency goes/is in a specific file + :param runtime_dependency: bool to specify this is a runtime gem for the game + :param tool_dependency: bool to specify this is a tool gem for the editor + :param server_dependency: bool to specify this is a server gem for the server + :param platforms: str to specify common or which specific platforms + :param add_to_cmake: bool to specify that this gem should be added to cmake + :return: 0 for success or non 0 failure code + """ + # we need either a project name or path + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return 1 - del json_data['engines'] - del json_data['gems'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + # if project name resolve it into a path + if project_name and not project_path: + project_path = get_registered(project_name=project_name) + project_path = pathlib.Path(project_path).resolve() + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return 1 - print(json.dumps(json_data, indent=4)) - print_projects(json_data, - verbose) + # get the engine name this project is associated with + # and resolve that engines path + project_json = project_path / 'project.json' + if not valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + with project_json.open('r') as s: + try: + project_json_data = json.load(s) + except Exception as e: + logger.error(f'Error loading Project json {project_json}: {str(e)}') + return 1 + else: + try: + engine_name = project_json_data['engine'] + except Exception as e: + logger.error(f'Project json {project_json} "engine" not found: {str(e)}') + return 1 + else: + engine_path = get_registered(engine_name=engine_name) + if not engine_path: + logger.error(f'Engine {engine_name} is not registered.') + return 1 + + # we need either a gem name or path + if not gem_name and not gem_path: + logger.error(f'Must either specify a Gem path or Gem Name.') + return 1 + # if gem name resolve it into a path + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) + gem_path = pathlib.Path(gem_path).resolve() + # make sure this gem already exists if we're adding. We can always remove a gem. + if not gem_path.is_dir(): + logger.error(f'Gem Path {gem_path} does not exist.') + return 1 -def register_show_aggregate_gems(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) + # if add to cmake, make sure the gem.json exists and valid before we proceed + if add_to_cmake: + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + logger.error(f'Gem json {gem_json} is not present.') + return 1 + if not valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 - del json_data['engines'] - del json_data['projects'] - del json_data['templates'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + # find all available modules in this gem_path + modules = get_gem_targets(gem_path=gem_path) + if len(modules) == 0: + logger.error(f'No gem modules found under {gem_path}.') + return 1 - print(json.dumps(json_data, indent=4)) - print_gems(json_data, - verbose) + # if the gem has no modules and the user has specified a target fail + if gem_target and not modules: + logger.error(f'Gem has no targets, but gem target {gem_target} was specified.') + return 1 + # if the gem target is not in the modules + if gem_target not in modules: + logger.error(f'Gem target not in gem modules: {modules}') + return 1 -def register_show_aggregate_templates(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) + if gem_target: + # if the user has not specified either we will assume they meant the most common which is runtime + if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: + logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") + runtime_dependency = True - del json_data['engines'] - del json_data['projects'] - del json_data['gems'] - del json_data['repos'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + ret_val = 0 - print(json.dumps(json_data, indent=4)) - print_templates(json_data, - verbose) + # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags + if dependencies_file: + dependencies_file = pathlib.Path(dependencies_file).resolve() + # make sure this is a project has a dependencies_file + if not dependencies_file.is_file(): + logger.error(f'Dependencies file {dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(dependencies_file, gem_target) + else: + if ',' in platforms: + platforms = platforms.split(',') + else: + platforms = [platforms] + for platform in platforms: + if runtime_dependency: + # make sure this is a project has a runtime_dependencies.cmake file + project_runtime_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)).resolve() + if not project_runtime_dependencies_file.is_file(): + logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_runtime_dependencies_file, gem_target) + + if (ret_val == 0) and tool_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_tool_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)).resolve() + if not project_tool_dependencies_file.is_file(): + logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_tool_dependencies_file, gem_target) + + if (ret_val == 0) and server_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_server_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)).resolve() + if not project_server_dependencies_file.is_file(): + logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) + + if not ret_val and add_to_cmake: + ret_val = add_gem_to_cmake(gem_path=gem_path, engine_path=engine_path) + + return ret_val + + +def remove_gem_from_project(gem_name: str = None, + gem_path: str or pathlib.Path = None, + gem_target: str = None, + project_name: str = None, + project_path: str or pathlib.Path = None, + dependencies_file: str or pathlib.Path = None, + runtime_dependency: bool = False, + tool_dependency: bool = False, + server_dependency: bool = False, + platforms: str = 'Common', + remove_from_cmake: bool = False) -> int: + """ + remove a gem from a project + :param gem_name: name of the gem to add + :param gem_path: path to the gem to add + :param gem_target: the name of teh cmake gem module + :param project_name: name of the project to add the gem to + :param project_path: path to the project to add the gem to + :param dependencies_file: if this dependency goes/is in a specific file + :param runtime_dependency: bool to specify this is a runtime gem for the game + :param tool_dependency: bool to specify this is a tool gem for the editor + :param server_dependency: bool to specify this is a server gem for the server + :param platforms: str to specify common or which specific platforms + :param remove_from_cmake: bool to specify that this gem should be removed from cmake + :return: 0 for success or non 0 failure code + """ -def register_show_aggregate_repos(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) + # we need either a project name or path + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return 1 - del json_data['engines'] - del json_data['projects'] - del json_data['gems'] - del json_data['templates'] - del json_data['default_projects_folder'] - del json_data['default_gems_folder'] - del json_data['default_templates_folder'] + # if project name resolve it into a path + if project_name and not project_path: + project_path = get_registered(project_name=project_name) + project_path = pathlib.Path(project_path).resolve() + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return 1 - print(json.dumps(json_data, indent=4)) - print_repos(json_data, - verbose) + # We need either a gem name or path + if not gem_name and not gem_path: + logger.error(f'Must either specify a Gem path or Gem Name.') + return 1 + # if gem name resolve it into a path + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) + gem_path = pathlib.Path(gem_path).resolve() + # make sure this gem already exists if we're adding. We can always remove a gem. + if not gem_path.is_dir(): + logger.error(f'Gem Path {gem_path} does not exist.') + return 1 -def register_show_aggregate(verbose: int): - json_data = load_o3de_registry() - repos = json_data['repos'].copy() - for repo_uri in repos: - aggregate_repo(json_data, repo_uri) + # find all available modules in this gem_path + modules = get_gem_targets(gem_path=gem_path) + if len(modules) == 0: + logger.error(f'No gem modules found.') + return 1 - print(json.dumps(json_data, indent=4)) + # if the user has not set a specific gem target remove all of them - print_engines(json_data, - verbose) - print_projects(json_data, - verbose) - print_gems(json_data, - verbose) - print_templates(json_data, - verbose) - print_repos(json_data, - verbose) + # if gem target not specified, see if there is only 1 module + if not gem_target: + if len(modules) == 1: + gem_target = modules[0] + else: + logger.error(f'Gem target not specified: {modules}') + return 1 + elif gem_target not in modules: + logger.error(f'Gem target not in gem modules: {modules}') + return 1 - if verbose > 0: - print("Default Folders================================================") - print(f"Default projects folder: {json_data['default_projects_folder']}") - print(os.listdir(json_data['default_projects_folder'])) - print('\n') - print(f"Default gems folder: {json_data['default_gems_folder']}") - print(os.listdir(json_data['default_gems_folder'])) - print('\n') - print(f"Default templates folder: {json_data['default_templates_folder']}") - print(os.listdir(json_data['default_templates_folder'])) + # if the user has not specified either we will assume they meant the most common which is runtime + if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: + logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") + runtime_dependency = True + # when removing we will try to do as much as possible even with failures so ret_val will be the last error code + ret_val = 0 -def _run_register(args: argparse) -> int: - if args.update: - remove_invalid_o3de_objects() - return refresh_repos() + # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags + if dependencies_file: + dependencies_file = pathlib.Path(dependencies_file).resolve() + # make sure this is a project has a dependencies_file + if not dependencies_file.is_file(): + logger.error(f'Dependencies file {dependencies_file} is not present.') + return 1 + # remove the dependency + error_code = remove_gem_dependency(dependencies_file, gem_target) + if error_code: + ret_val = error_code else: - if args.this_engine: - register(engine_path=get_this_engine_path()) - register_shipped_engine_o3de_objects() + if ',' in platforms: + platforms = platforms.split(',') else: - return register(args.engine_path, - args.project_path, - args.gem_path, - args.template_path, - args.default_projects_folder, - args.default_gems_folder, - args.default_templates_folder, - args.repo_uri, - args.remove) - - -def _run_get_registered(args: argparse) -> int: + platforms = [platforms] + for platform in platforms: + if runtime_dependency: + # make sure this is a project has a runtime_dependencies.cmake file + project_runtime_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)).resolve() + if not project_runtime_dependencies_file.is_file(): + logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_runtime_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if tool_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_tool_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)).resolve() + if not project_tool_dependencies_file.is_file(): + logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_tool_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if server_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_server_dependencies_file = pathlib.Path( + get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)).resolve() + if not project_server_dependencies_file.is_file(): + logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_server_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if remove_from_cmake: + error_code = remove_gem_from_cmake(gem_path=gem_path) + if error_code: + ret_val = error_code + + return ret_val + + +def sha256(file_path: str or pathlib.Path, + json_path: str or pathlib.Path = None) -> int: + if not file_path: + logger.error(f'File path cannot be empty.') + return 1 + file_path = pathlib.Path(file_path).resolve() + if not file_path.is_file(): + logger.error(f'File path {file_path} does not exist.') + return 1 + + if json_path: + json_path = pathlib.Path(json_path).resolve() + if not json_path.is_file(): + logger.error(f'Json path {json_path} does not exist.') + return 1 + + sha256 = hashlib.sha256(file_path.open('rb').read()).hexdigest() + + if json_path: + with json_path.open('r') as s: + try: + json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Json path {json_path}: {str(e)}') + return 1 + json_data.update({"sha256": sha256}) + backup_file(json_path) + with json_path.open('w') as s: + try: + s.write(json.dumps(json_data, indent=4)) + except Exception as e: + logger.error(f'Failed to write Json path {json_path}: {str(e)}') + return 1 + else: + print(sha256) + return 0 + + +def _run_get_registered(args: argparse) -> str or pathlib.Path: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + return get_registered(args.engine_name, args.project_name, args.gem_name, args.template_name, args.default_folder, - args.repo_name) + args.repo_name, + args.restricted_name) def _run_register_show(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder - if args.aggregate: - register_show_aggregate(args.verbose) - return 0 - if args.aggregate_engines: - register_show_aggregate_engines(args.verbose) - return 0 - elif args.aggregate_projects: - register_show_aggregate_projects(args.verbose) - return 0 - elif args.aggregate_gems: - register_show_aggregate_gems(args.verbose) - return 0 - elif args.aggregate_templates: - register_show_aggregate_templates(args.verbose) - return 0 - elif args.aggregate_repos: - register_show_aggregate_repos(args.verbose) + if args.this_engine: + print_this_engine(args.verbose) return 0 + elif args.engines: - register_show_engines(args.verbose) + print_engines(args.verbose) return 0 elif args.projects: - register_show_projects(args.verbose) + print_projects(args.verbose) return 0 elif args.gems: - register_show_gems(args.verbose) + print_gems(args.verbose) return 0 elif args.templates: - register_show_templates(args.verbose) + print_templates(args.verbose) return 0 elif args.repos: register_show_repos(args.verbose) return 0 + elif args.restricted: + print_restricted(args.verbose) + return 0 + + elif args.engine_projects: + print_engine_projects(args.verbose) + return 0 + elif args.engine_gems: + print_engine_gems(args.verbose) + return 0 + elif args.engine_templates: + print_engine_templates(args.verbose) + return 0 + elif args.engine_restricted: + print_engine_restricted(args.verbose) + return 0 + elif args.external_subdirectories: + print_external_subdirectories(args.verbose) + return 0 + + elif args.all_projects: + print_all_projects(args.verbose) + return 0 + elif args.all_gems: + print_all_gems(args.verbose) + return 0 + elif args.all_templates: + print_all_templates(args.verbose) + return 0 + elif args.all_restricted: + print_all_restricted(args.verbose) + return 0 + + elif args.downloadables: + print_downloadables(args.verbose) + return 0 + if args.downloadable_engines: + print_downloadable_engines(args.verbose) + return 0 + elif args.downloadable_projects: + print_downloadable_projects(args.verbose) + return 0 + elif args.downloadable_gems: + print_downloadable_gems(args.verbose) + return 0 + elif args.downloadable_templates: + print_downloadable_templates(args.verbose) + return 0 else: register_show(args.verbose) return 0 +def _run_download(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + if args.engine_name: + return download_engine(args.engine_name, + args.dest_path) + elif args.project_name: + return download_project(args.project_name, + args.dest_path) + elif args.gem_nanme: + return download_gem(args.gem_name, + args.dest_path) + elif args.template_name: + return download_template(args.template_name, + args.dest_path) + + +def _run_register(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + if args.update: + remove_invalid_o3de_objects() + return refresh_repos() + elif args.this_engine: + ret_val = register(engine_path=get_this_engine_path()) + error_code = register_shipped_engine_o3de_objects() + if error_code: + ret_val = error_code + return ret_val + elif args.all_engines_path: + return register_all_engines_in_folder(args.all_engines_path, args.remove) + elif args.all_projects_path: + return register_all_projects_in_folder(args.all_projects_path, args.remove) + elif args.all_gems_path: + return register_all_gems_in_folder(args.all_gems_path, args.remove) + elif args.all_templates_path: + return register_all_templates_in_folder(args.all_templates_path, args.remove) + elif args.all_restricted_path: + return register_all_restricted_in_folder(args.all_restricted_path, args.remove) + elif args.all_repo_uri: + return register_all_repos_in_folder(args.all_restricted_path, args.remove) + else: + return register(engine_path=args.engine_path, + project_path=args.project_path, + gem_path=args.gem_path, + template_path=args.template_path, + restricted_path=args.restricted_path, + repo_uri=args.repo_uri, + default_engines_folder=args.default_engines_folder, + default_projects_folder=args.default_projects_folder, + default_gems_folder=args.default_gems_folder, + default_templates_folder=args.default_templates_folder, + default_restricted_folder=args.default_restricted_folder, + remove=args.remove) + + +def _run_add_external_subdirectory(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return add_external_subdirectory(args.external_subdirectory) + + +def _run_remove_external_subdirectory(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return remove_external_subdirectory(args.external_subdirectory) + + +def _run_add_gem_to_cmake(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return add_gem_to_cmake(gem_name=args.gem_name, gem_path=args.gem_path) + + +def _run_remove_gem_from_cmake(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return remove_gem_from_cmake(args.gem_name, args.gem_path) + + +def _run_add_gem_to_project(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return add_gem_to_project(args.gem_name, + args.gem_path, + args.gem_target, + args.project_name, + args.project_path, + args.dependencies_file, + args.runtime_dependency, + args.tool_dependency, + args.server_dependency, + args.platforms, + args.add_to_cmake) + + +def _run_remove_gem_from_project(args: argparse) -> int: + if args.override_home_folder: + global override_home_folder + override_home_folder = args.override_home_folder + + return remove_gem_from_project(args.gem_name, + args.gem_path, + args.gem_target, + args.project_path, + args.project_name, + args.dependencies_file, + args.runtime_dependency, + args.tool_dependency, + args.server_dependency, + args.platforms, + args.remove_from_cmake) + + +def _run_sha256(args: argparse) -> int: + return sha256(args.file_path, + args.json_path) + + def add_args(parser, subparsers) -> None: """ add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or aggregated by a central python file. + invoked locally or added by a central python file. Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" OR - o3de.py can aggregate commands by importing engine_template, + o3de.py can downloadable commands by importing engine_template, call add_args and execute: python o3de.py register --gem-path "C:/TestGem" :param parser: the caller instantiates a parser and passes it in here :param subparsers: the caller instantiates subparsers and passes it in here @@ -1081,98 +4058,317 @@ def add_args(parser, subparsers) -> None: # register register_subparser = subparsers.add_parser('register') group = register_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('--this-engine', action = 'store_true', required=False, - default = False, + group.add_argument('--this-engine', action='store_true', required=False, + default=False, help='Registers the engine this script is running from.') - group.add_argument('-e', '--engine-path', type=str, required=False, + group.add_argument('-ep', '--engine-path', type=str, required=False, help='Engine path to register/remove.') - group.add_argument('-p', '--project-path', type=str, required=False, + group.add_argument('-pp', '--project-path', type=str, required=False, help='Project path to register/remove.') - group.add_argument('-g', '--gem-path', type=str, required=False, + group.add_argument('-gp', '--gem-path', type=str, required=False, help='Gem path to register/remove.') - group.add_argument('-t', '--template-path', type=str, required=False, + group.add_argument('-tp', '--template-path', type=str, required=False, help='Template path to register/remove.') - group.add_argument('-dp', '--default-projects-folder', type=str, required=False, + group.add_argument('-rp', '--restricted-path', type=str, required=False, + help='A restricted folder to register/remove.') + group.add_argument('-ru', '--repo-uri', type=str, required=False, + help='A repo uri to register/remove.') + group.add_argument('-aep', '--all-engines-path', type=str, required=False, + help='All engines under this folder to register/remove.') + group.add_argument('-app', '--all-projects-path', type=str, required=False, + help='All projects under this folder to register/remove.') + group.add_argument('-agp', '--all-gems-path', type=str, required=False, + help='All gems under this folder to register/remove.') + group.add_argument('-atp', '--all-templates-path', type=str, required=False, + help='All templates under this folder to register/remove.') + group.add_argument('-arp', '--all-restricted-path', type=str, required=False, + help='All templates under this folder to register/remove.') + group.add_argument('-aru', '--all-repo-uri', type=str, required=False, + help='All repos under this folder to register/remove.') + group.add_argument('-def', '--default-engines-folder', type=str, required=False, + help='The default engines folder to register/remove.') + group.add_argument('-dpf', '--default-projects-folder', type=str, required=False, help='The default projects folder to register/remove.') - group.add_argument('-dg', '--default-gems-folder', type=str, required=False, + group.add_argument('-dgf', '--default-gems-folder', type=str, required=False, help='The default gems folder to register/remove.') - group.add_argument('-dt', '--default-templates-folder', type=str, required=False, + group.add_argument('-dtf', '--default-templates-folder', type=str, required=False, help='The default templates folder to register/remove.') - group.add_argument('-ru', '--repo-uri', type=str, required=False, - help='A repo uri to register/remove.') + group.add_argument('-drf', '--default-restricted-folder', type=str, required=False, + help='The default restricted folder to register/remove.') group.add_argument('-u', '--update', action='store_true', required=False, default=False, help='Refresh the repo cache.') + + register_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + register_subparser.add_argument('-r', '--remove', action='store_true', required=False, default=False, help='Remove entry.') - register_subparser.set_defaults(func=_run_register) # show register_show_subparser = subparsers.add_parser('register-show') group = register_show_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-te', '--this-engine', action='store_true', required=False, + default=False, + help='Just the local engines.') group.add_argument('-e', '--engines', action='store_true', required=False, default=False, - help='Just the local engines. Ignores repos') + help='Just the local engines.') group.add_argument('-p', '--projects', action='store_true', required=False, default=False, - help='Just the local projects. Ignores repos.') + help='Just the local projects.') group.add_argument('-g', '--gems', action='store_true', required=False, default=False, - help='Just the local gems. Ignores repos') + help='Just the local gems.') group.add_argument('-t', '--templates', action='store_true', required=False, default=False, - help='Just the local templates. Ignores repos.') + help='Just the local templates.') group.add_argument('-r', '--repos', action='store_true', required=False, default=False, help='Just the local repos. Ignores repos.') - group.add_argument('-a', '--aggregate', action='store_true', required=False, + group.add_argument('-rs', '--restricted', action='store_true', required=False, + default=False, + help='The local restricted folders.') + + group.add_argument('-ep', '--engine-projects', action='store_true', required=False, + default=False, + help='Just the local projects. Ignores repos.') + group.add_argument('-eg', '--engine-gems', action='store_true', required=False, + default=False, + help='Just the local gems. Ignores repos') + group.add_argument('-et', '--engine-templates', action='store_true', required=False, + default=False, + help='Just the local templates. Ignores repos.') + group.add_argument('-ers', '--engine-restricted', action='store_true', required=False, + default=False, + help='The restricted folders.') + group.add_argument('-x', '--external-subdirectories', action='store_true', required=False, + default=False, + help='The external subdirectories.') + + group.add_argument('-ap', '--all-projects', action='store_true', required=False, + default=False, + help='Just the local projects. Ignores repos.') + group.add_argument('-ag', '--all-gems', action='store_true', required=False, + default=False, + help='Just the local gems. Ignores repos') + group.add_argument('-at', '--all-templates', action='store_true', required=False, + default=False, + help='Just the local templates. Ignores repos.') + group.add_argument('-ars', '--all-restricted', action='store_true', required=False, + default=False, + help='The restricted folders.') + + group.add_argument('-d', '--downloadables', action='store_true', required=False, default=False, help='Combine all repos into a single list of resources.') - group.add_argument('-ae', '--aggregate-engines', action='store_true', required=False, + group.add_argument('-de', '--downloadable-engines', action='store_true', required=False, default=False, help='Combine all repos engines into a single list of resources.') - group.add_argument('-ap', '--aggregate-projects', action='store_true', required=False, + group.add_argument('-dp', '--downloadable-projects', action='store_true', required=False, default=False, help='Combine all repos projects into a single list of resources.') - group.add_argument('-ag', '--aggregate-gems', action='store_true', required=False, + group.add_argument('-dg', '--downloadable-gems', action='store_true', required=False, default=False, help='Combine all repos gems into a single list of resources.') - group.add_argument('-at', '--aggregate-templates', action='store_true', required=False, + group.add_argument('-dt', '--downloadable-templates', action='store_true', required=False, default=False, help='Combine all repos templates into a single list of resources.') - group.add_argument('-ar', '--aggregate-repos', action='store_true', required=False, - default=False, - help='Combine all repos into a single list of resources.') - group = register_show_subparser.add_mutually_exclusive_group(required=False) - group.add_argument('-v', '--verbose', action='count', required=False, - default=0, - help='How verbose do you want the output to be.') + register_show_subparser.add_argument('-v', '--verbose', action='count', required=False, + default=0, + help='How verbose do you want the output to be.') + + register_show_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') register_show_subparser.set_defaults(func=_run_register_show) # get-registered get_registered_subparser = subparsers.add_parser('get-registered') group = get_registered_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-e', '--engine-name', type=str, required=False, + group.add_argument('-en', '--engine-name', type=str, required=False, help='Engine name.') - group.add_argument('-p', '--project-name', type=str, required=False, + group.add_argument('-pn', '--project-name', type=str, required=False, help='Project name.') - group.add_argument('-g', '--gem-name', type=str, required=False, + group.add_argument('-gn', '--gem-name', type=str, required=False, help='Gem name.') - group.add_argument('-t', '--template-name', type=str, required=False, + group.add_argument('-tn', '--template-name', type=str, required=False, help='Template name.') - group.add_argument('-f', '--default-folder', type=str, required=False, - choices=['projects', 'gems', 'templates'], - help='The default folder.') - group.add_argument('-r', '--repo-name', type=str, required=False, - help='A repo uri to register/remove.') + group.add_argument('-df', '--default-folder', type=str, required=False, + choices=['engines', 'projects', 'gems', 'templates', 'restricted'], + help='The default folders for o3de.') + group.add_argument('-rn', '--repo-name', type=str, required=False, + help='Repo name.') + group.add_argument('-rsn', '--restricted-name', type=str, required=False, + help='Restricted name.') + + get_registered_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') get_registered_subparser.set_defaults(func=_run_get_registered) + # download + download_subparser = subparsers.add_parser('download') + group = download_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-e', '--engine-name', type=str, required=False, + help='Downloadable engine name.') + group.add_argument('-p', '--project-name', type=str, required=False, + help='Downloadable project name.') + group.add_argument('-g', '--gem-name', type=str, required=False, + help='Downloadable gem name.') + group.add_argument('-t', '--template-name', type=str, required=False, + help='Downloadable template name.') + download_subparser.add_argument('-dp', '--dest-path', type=str, required=False, + default=None, + help='Optional destination folder to download into.' + ' i.e. download --project-name "StarterGame" --dest-path "C:/projects"' + ' will result in C:/projects/StarterGame' + ' If blank will download to default object type folder') + + download_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + download_subparser.set_defaults(func=_run_download) + + # add external subdirectories + add_external_subdirectory_subparser = subparsers.add_parser('add-external-subdirectory') + add_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, + help='add an external subdirectory to cmake') + + add_external_subdirectory_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + add_external_subdirectory_subparser.set_defaults(func=_run_add_external_subdirectory) + + # remove external subdirectories + remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') + remove_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', + type=str, + help='remove external subdirectory from cmake') + + remove_external_subdirectory_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + remove_external_subdirectory_subparser.set_defaults(func=_run_remove_external_subdirectory) + + # add gems to cmake + # convenience functions to disambiguate the gem name -> gem_path and call add-external-subdirectory on gem_path + add_gem_to_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') + group = add_gem_to_cmake_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + + add_gem_to_cmake_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + add_gem_to_cmake_subparser.set_defaults(func=_run_add_gem_to_cmake) + + # remove gems from cmake + # convenience functions to disambiguate the gem name -> gem_path and call remove-external-subdirectory on gem_path + remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') + group = remove_gem_from_cmake_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + + remove_gem_from_cmake_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + remove_gem_from_cmake_subparser.set_defaults(func=_run_remove_gem_from_cmake) + + # add a gem to a project + add_gem_subparser = subparsers.add_parser('add-gem-to-project') + group = add_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-pp', '--project-path', type=str, required=False, + help='The path to the project.') + group.add_argument('-pn', '--project-name', type=str, required=False, + help='The name of the project.') + group = add_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + add_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + help='The cmake target name to add. If not specified it will assume gem_name') + add_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + help='The cmake dependencies file in which the gem dependencies are specified.' + 'If not specified it will assume ') + add_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a runtime dependency') + add_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a tool dependency') + add_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a server dependency') + add_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + default='Common', + help='Optional list of platforms this gem should be added to.' + ' Ex. --platforms Mac,Windows,Linux') + add_gem_subparser.add_argument('-a', '--add-to-cmake', type=bool, required=False, + default=True, + help='Automatically call add-gem-to-cmake.') + + add_gem_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + add_gem_subparser.set_defaults(func=_run_add_gem_to_project) + + # remove a gem from a project + remove_gem_subparser = subparsers.add_parser('remove-gem-from-project') + group = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-pp', '--project-path', type=str, required=False, + help='The path to the project.') + group.add_argument('-pn', '--project-name', type=str, required=False, + help='The name of the project.') + group = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + remove_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + help='The cmake target name to add. If not specified it will assume gem_name') + remove_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + help='The cmake dependencies file in which the gem dependencies are specified.' + 'If not specified it will assume ') + remove_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a runtime dependency') + remove_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a server dependency') + remove_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a server dependency') + remove_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + default='Common', + help='Optional list of platforms this gem should be removed from' + ' Ex. --platforms Mac,Windows,Linux') + remove_gem_subparser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, + default=False, + help='Automatically call remove-from-cmake.') + + remove_gem_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + help='By default the home folder is the user folder, override it to this folder.') + + remove_gem_subparser.set_defaults(func=_run_remove_gem_from_project) + + # sha256 + sha256_subparser = subparsers.add_parser('sha256') + sha256_subparser.add_argument('-f', '--file-path', type=str, required=True, + help='The path to the file you want to sha256.') + sha256_subparser.add_argument('-j', '--json-path', type=str, required=False, + help='optional path to an o3de json file to add the "sha256" element to.') + sha256_subparser.set_defaults(func=_run_sha256) + if __name__ == "__main__": # parse the command line args diff --git a/cmake/o3de_manifest.cmake b/cmake/o3de_manifest.cmake new file mode 100644 index 0000000000..1585ec2d2f --- /dev/null +++ b/cmake/o3de_manifest.cmake @@ -0,0 +1,986 @@ +# +# 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 the user home directory +set(O3DE_HOME_PATH "" CACHE PATH "Override the user home to this path") +if(O3DE_HOME_PATH) + set(home_directory ${O3DE_HOME_PATH}) +elseif(CMAKE_HOST_WIN32) + file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) +else() + file(TO_CMAKE_PATH "$ENV{HOME}" home_directory) +endif() +if (NOT home_directory) + message(FATAL_ERROR "Cannot find user home directory, without the user home directory the o3de manifest cannot be found") +endif() + +# Optionally delete the home directory +if(O3DE_DELETE_HOME_PATH) + message(STATUS "O3DE_DELETE_HOME_PATH=${O3DE_DELETE_HOME_PATH}") + if(EXISTS ${home_directory}/.o3de) + message(STATUS "Deleting ${home_directory}/.o3de") + file(REMOVE_RECURSE ${home_directory}/.o3de) + else() + message(STATUS "Home path ${home_directory}/.o3de doesnt exist.") + endif() +endif() + +######################################################################################################################## +# If O3DE_REGISTER_ENGINE_PATH variable is set on the commandline this will allow registration of anything using +# O3DE_REGISTER_ENGINE_PATH o3de script. This is handy for situations like build servers which download the code and +# are expected to build without the need for someone to register o3de objects like this engine by manually typing it in. +# If O3DE_REGISTER_THIS_ENGINE=TRUE is set on the commandline when O3DE_REGISTER_ENGINE_PATH is also set this will call: +# O3DE_REGISTER_ENGINE_PATH/scripts>o3de register --this-engine --override-home-folder +# Note: register --this-engine will automatically register anything it finds in known folders, so if you put your +# o3de objects like projects/gems/templates/restricted/etc... in known folders for those types they will get registered +# automatically. Known folders for types are your .o3de/Projects and .o3de/Gems etc. So if I wanted my project to be +# registered and built by this build server I could simply put them in those known folders on the build server and they +# would get registered automatically by this call. +# OR +# I could put them on the commandline as well. This would be the way if the o3de objects we need to regiater are NOT +# in known folders or you do not intend to call with O3DE_REGISTER_THIS_ENGINE=TRUE Ex. +# -DO3DE_REGISTER_ENGINE_PATH=C:\this\engine +# -DO3DE_REGISTER_PROJECT_PATHS=C:\ThisGame;C:\ThatGame +# -DO3DE_REGISTER_GEM_PATHS=C:\ThisGem;C:\ThatGem;C:\And\Some\Other\Gem +# -DO3DE_REGISTER_RESTRICTED_PATHS=C:\this\engine\Restricted;C:\ThisGame\Restricted;C:\ThisGem\Restricted +######################################################################################################################## +if(O3DE_REGISTER_ENGINE_PATH) + message(STATUS "O3DE_REGISTER_ENGINE_PATH=${O3DE_REGISTER_ENGINE_PATH}") + + if(O3DE_REGISTER_THIS_ENGINE) + message(STATUS "O3DE_REGISTER_THIS_ENGINE=${O3DE_REGISTER_THIS_ENGINE}") + message(STATUS "register --this-engine") + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --this-engine --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_this_engine_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --this-engine --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_this_engine_cmd_result + ) + endif() + if(o3de_register_this_engine_cmd_result) + message(FATAL_ERROR "An error occured trying to register --this-engine: ${o3de_register_this_engine_cmd_result}") + else() + message(STATUS "Engine ${O3DE_REGISTER_ENGINE_PATH} registration successfull.") + endif() + endif() + + if(O3DE_REGISTER_RESTRICTED_PATHS) + message(STATUS "O3DE_REGISTER_RESTRICTED_PATHS=${O3DE_REGISTER_RESTRICTED_PATHS}") + foreach(restricted_path ${O3DE_REGISTER_RESTRICTED_PATHS}) + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --restricted-path ${restricted_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_restricted_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --restricted-path ${restricted_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_restricted_cmd_result + ) + endif() + if(o3de_register_restricted_cmd_result) + message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --restricted-path ${restricted_path} --override-home-folder ${home_directory}: ${o3de_register_restricted_cmd_result}") + else() + message(STATUS "Restricted ${restricted_path} registration successfull.") + endif() + endforeach() + endif() + + if(O3DE_REGISTER_PROJECT_PATHS) + message(STATUS "O3DE_REGISTER_PROJECT_PATHS=${O3DE_REGISTER_PROJECT_PATHS}") + foreach(project_path ${O3DE_REGISTER_PROJECT_PATHS}) + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --project-path ${project_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_project_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --project-path ${project_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_project_cmd_result + ) + endif() + if(o3de_register_project_cmd_result) + message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --project-path ${project_path} --override-home-folder ${home_directory}") + else() + message(STATUS "Project ${project_path} registration successfull.") + endif() + endforeach() + endif() + + if(O3DE_REGISTER_GEM_PATHS) + message(STATUS "O3DE_REGISTER_GEM_PATHS=${O3DE_REGISTER_GEM_PATHS}") + foreach(gem_path ${O3DE_REGISTER_GEM_PATHS}) + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --gem-path ${gem_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_gem_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --gem-path ${gem_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_gem_cmd_result + ) + endif() + if(o3de_register_gem_cmd_result) + message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --gem-path ${gem_path} --override-home-folder ${home_directory}") + else() + message(STATUS "Gem ${gem_path} registration successfull.") + endif() + endforeach() + endif() + + if(O3DE_REGISTER_TEMPLATE_PATHS) + message(STATUS "O3DE_REGISTER_TEMPLATE_PATHS=${O3DE_REGISTER_TEMPLATE_PATHS}") + foreach(template_path ${O3DE_REGISTER_TEMPLATE_PATHS}) + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --template-path ${template_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_template_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --template-path ${template_path} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_template_cmd_result + ) + endif() + if(o3de_register_template_cmd_result) + message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --template-path ${template_path} --override-home-folder ${home_directory}") + else() + message(STATUS "Template ${template_path} registration successfull.") + endif() + endforeach() + endif() + + if(O3DE_REGISTER_REPO_URIS) + message(STATUS "O3DE_REGISTER_REPO_URIS=${O3DE_REGISTER_REPO_URIS}") + foreach(repo_uri ${O3DE_REGISTER_REPO_URIS}) + if(CMAKE_HOST_WIN32) + execute_process( + COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --repo-uri ${repo_uri} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_repo_cmd_result + ) + else() + execute_process( + COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --repo-uri ${repo_uri} --override-home-folder ${home_directory} + RESULT_VARIABLE o3de_register_repo_cmd_result + ) + endif() + if(o3de_register_repo_cmd_result) + message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --repo-uri ${repo_uri} --override-home-folder ${home_directory}") + else() + message(STATUS "Repo ${repo_uri} registration successfull.") + endif() + endforeach() + endif() +endif() + +################################################################################ +# o3de manifest +################################################################################ +# Set manifest json path to the /.o3de/o3de_manifest.json +set(o3de_manifest_json_path ${home_directory}/.o3de/o3de_manifest.json) +if(NOT EXISTS ${o3de_manifest_json_path}) + message(FATAL_ERROR "${o3de_manifest_json_path} not found. You must o3de register --this-engine.") +endif() +file(READ ${o3de_manifest_json_path} manifest_json_data) + +################################################################################ +# o3de manifest name +################################################################################ +string(JSON o3de_manifest_name ERROR_VARIABLE json_error GET ${manifest_json_data} o3de_manifest_name) +message(STATUS "o3de_manifest_name: ${o3de_manifest_name}") +if(json_error) + message(FATAL_ERROR "Unable to read repo_name from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de origin +################################################################################ +string(JSON o3de_origin ERROR_VARIABLE json_error GET ${manifest_json_data} origin) +if(json_error) + message(FATAL_ERROR "Unable to read origin from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de default engines folder +################################################################################ +string(JSON o3de_default_engines_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_engines_folder) +message(STATUS "default_engines_folder: ${o3de_default_engines_folder}") +if(json_error) + message(FATAL_ERROR "Unable to read default_engines_folder from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de default projects folder +################################################################################ +string(JSON o3de_default_projects_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_projects_folder) +message(STATUS "default_projects_folder: ${o3de_default_projects_folder}") +if(json_error) + message(FATAL_ERROR "Unable to read default_projects_folder from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de default gems folder +################################################################################ +string(JSON o3de_default_gems_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_gems_folder) +message(STATUS "default_gems_folder: ${o3de_default_gems_folder}") +if(json_error) + message(FATAL_ERROR "Unable to read default_gems_folder from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de default templates folder +################################################################################ +string(JSON o3de_default_templates_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_templates_folder) +message(STATUS "default_templates_folder: ${o3de_default_templates_folder}") +if(json_error) + message(FATAL_ERROR "Unable to read default_templates_folder from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de default restricted folder +################################################################################ +string(JSON o3de_default_restricted_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_restricted_folder) +message(STATUS "default_restricted_folder: ${o3de_default_restricted_folder}") +if(json_error) + message(FATAL_ERROR "Unable to read default_restricted_folder from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +################################################################################ +# o3de projects +################################################################################ +string(JSON o3de_projects_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} projects) +if(json_error) + message(FATAL_ERROR "Unable to read key 'projects' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() +if(${o3de_projects_count} GREATER 0) + math(EXPR o3de_projects_count "${o3de_projects_count}-1") + foreach(projects_index RANGE ${o3de_projects_count}) + string(JSON projects_path ERROR_VARIABLE json_error GET ${manifest_json_data} projects ${projects_index}) + if(json_error) + message(FATAL_ERROR "Unable to read projects[${projects_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_projects ${projects_path}) + list(APPEND o3de_global_projects ${projects_path}) + endforeach() +endif() + +################################################################################ +# o3de gems +################################################################################ +string(JSON o3de_gems_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} gems) +if(json_error) + message(FATAL_ERROR "Unable to read key 'gems' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() +if(${o3de_gems_count} GREATER 0) + math(EXPR o3de_gems_count "${o3de_gems_count}-1") + foreach(gems_index RANGE ${o3de_gems_count}) + string(JSON gems_path ERROR_VARIABLE json_error GET ${manifest_json_data} gems ${gems_index}) + if(json_error) + message(FATAL_ERROR "Unable to read gems[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_gems ${gems_path}) + list(APPEND o3de_global_gems ${gems_path}) + endforeach() +endif() + +################################################################################ +# o3de templates +################################################################################ +string(JSON o3de_templates_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} templates) +if(json_error) + message(FATAL_ERROR "Unable to read key 'templates' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() +if(${o3de_templates_count} GREATER 0) + math(EXPR o3de_templates_count "${o3de_templates_count}-1") + foreach(templates_index RANGE ${o3de_templates_count}) + string(JSON templates_path ERROR_VARIABLE json_error GET ${manifest_json_data} templates ${templates_index}) + if(json_error) + message(FATAL_ERROR "Unable to read templates[${templates_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_templates ${templates_path}) + list(APPEND o3de_global_templates ${templates_path}) + endforeach() +endif() + +################################################################################ +# o3de repos +################################################################################ +string(JSON o3de_repos_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} repos) +if(json_error) + message(FATAL_ERROR "Unable to read key 'repos' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() +if(${o3de_repos_count} GREATER 0) + math(EXPR o3de_repos_count "${o3de_repos_count}-1") + foreach(repos_index RANGE ${o3de_repos_count}) + string(JSON repo_uri ERROR_VARIABLE json_error GET ${manifest_json_data} repos ${repos_index}) + if(json_error) + message(FATAL_ERROR "Unable to read repos[${repos_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_repos ${repo_uri}) + list(APPEND o3de_global_repos ${repo_uri}) + endforeach() +endif() + +################################################################################ +# o3de restricted +################################################################################ +string(JSON o3de_restricted_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} restricted) +if(json_error) + message(FATAL_ERROR "Unable to read key 'restricted' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() +if(${o3de_restricted_count} GREATER 0) + math(EXPR o3de_restricted_count "${o3de_restricted_count}-1") + foreach(restricted_index RANGE ${o3de_restricted_count}) + string(JSON restricted_path ERROR_VARIABLE json_error GET ${manifest_json_data} restricted ${restricted_index}) + if(json_error) + message(FATAL_ERROR "Unable to read restricted[${restricted_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_restricted ${restricted_path}) + list(APPEND o3de_global_restricted ${restricted_path}) + endforeach() +endif() + +################################################################################ +# o3de engines +################################################################################ +string(JSON o3de_engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} engines) +if(json_error) + message(FATAL_ERROR "Unable to read key 'engines' from '${o3de_manifest_json_path}', error: ${json_error}") +endif() + +if(${o3de_engines_count} GREATER 0) + math(EXPR o3de_engines_count "${o3de_engines_count}-1") + # Either the engine_path and engine_json are set in which case the user is configuring from the engine + # or project_path and project_json are set in which case the user is configuring from the project. + # We need to know which engine_path the user is using so if the project_json is set then we need + # to read the project_json and disambiguate the engine_path. + if(NOT o3de_engine_path) + if(NOT o3de_project_json) + message(FATAL_ERROR "Neither o3de_engine_path nor o3de_project_json defined. Cannot determine engine!") + endif() + + # get the name of the engine this project uses + file(READ ${o3de_project_json} project_json_data) + string(JSON project_engine_name ERROR_VARIABLE json_error GET ${project_json_data} engine) + if(json_error) + message(FATAL_ERROR "Unable to read 'engine' from '${o3de_project_json}', error: ${json_error}") + endif() + + # search each engine in order from the manifest to find the matching engine name + foreach(engines_index RANGE ${o3de_engines_count}) + string(JSON engine_data ERROR_VARIABLE json_error GET ${manifest_json_data} engines ${engines_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engines[${engines_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + + # get this engines path + string(JSON this_engine_path ERROR_VARIABLE json_error GET ${engine_data} path) + if(json_error) + message(FATAL_ERROR "Unable to read engine path from '${o3de_manifest_json_path}', error: ${json_error}") + endif() + + # add this engine to the engines list + list(APPEND o3de_engines ${this_engine_path}) + + # use path to get the engine.json + set(this_engine_json ${this_engine_path}/engine.json) + + # read the name of this engine + file(READ ${this_engine_json} this_engine_json_data) + string(JSON this_engine_name ERROR_VARIABLE json_error GET ${this_engine_json_data} engine_name) + if(json_error) + message(FATAL_ERROR "Unable to read engine_name from '${this_engine_json}', error: ${json_error}") + endif() + + # see if this engines name is the same as the one this projects should use + if(${this_engine_name} STREQUAL ${project_engine_name}) + message(STATUS "Found engine: '${project_engine_name}' at ${this_engine_path}") + set(o3de_engine_path ${this_engine_path}) + break() + endif() + endforeach() + endif() +endif() + +#we should have an engine_path at this point +if(NOT o3de_engine_path) + message(FATAL_ERROR "o3de_engine_path not defined. Cannot determine engine!") +endif() + +# now that we have an engine_path read in that engines o3de resources +if(${o3de_engines_count} GREATER -1) + foreach(engines_index RANGE ${o3de_engines_count}) + string(JSON engine_data ERROR_VARIABLE json_error GET ${manifest_json_data} engines ${engines_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engines[${engines_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + + # get this engines path + string(JSON this_engine_path ERROR_VARIABLE json_error GET ${engine_data} path) + if(json_error) + message(FATAL_ERROR "Unable to read engine path from '${o3de_manifest_json_path}', error: ${json_error}") + endif() + + if(${o3de_engine_path} STREQUAL ${this_engine_path}) + ################################################################################ + # o3de engine projects + ################################################################################ + string(JSON o3de_engine_projects_count ERROR_VARIABLE json_error LENGTH ${engine_data} projects) + if(json_error) + message(FATAL_ERROR "Unable to read key 'projects' from '${engine_data}', error: ${json_error}") + endif() + if(${o3de_engine_projects_count} GREATER 0) + math(EXPR o3de_engine_projects_count "${o3de_engine_projects_count}-1") + foreach(engine_projects_index RANGE ${o3de_engine_projects_count}) + string(JSON engine_projects_path ERROR_VARIABLE json_error GET ${engine_data} projects ${engine_projects_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engine projects[${projects_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_projects ${engine_projects_path}) + list(APPEND o3de_engine_projects ${engine_projects_path}) + endforeach() + endif() + + ################################################################################ + # o3de engine gems + ################################################################################ + string(JSON o3de_engine_gems_count ERROR_VARIABLE json_error LENGTH ${engine_data} gems) + if(json_error) + message(FATAL_ERROR "Unable to read key 'gems' from '${engine_data}', error: ${json_error}") + endif() + if(${o3de_engine_gems_count} GREATER 0) + math(EXPR o3de_engine_gems_count "${o3de_engine_gems_count}-1") + foreach(engine_gems_index RANGE ${o3de_engine_gems_count}) + string(JSON engine_gems_path ERROR_VARIABLE json_error GET ${engine_data} gems ${engine_gems_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engine gems[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_gems ${engine_gems_path}) + list(APPEND o3de_engine_gems ${engine_gems_path}) + endforeach() + endif() + + ################################################################################ + # o3de engine templates + ################################################################################ + string(JSON o3de_engine_templates_count ERROR_VARIABLE json_error LENGTH ${engine_data} templates) + if(json_error) + message(FATAL_ERROR "Unable to read key 'templates' from '${o3de_manifest_json_path}', error: ${json_error}") + endif() + if(${o3de_engine_gems_count} GREATER 0) + math(EXPR o3de_engine_templates_count "${o3de_engine_templates_count}-1") + foreach(engine_templates_index RANGE ${o3de_engine_templates_count}) + string(JSON engine_templates_path ERROR_VARIABLE json_error GET ${engine_data} templates ${engine_templates_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engine templates[${templates_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_templates ${engine_templates_path}) + list(APPEND o3de_engine_templates ${engine_templates_path}) + endforeach() + endif() + + ################################################################################ + # o3de engine restricted + ################################################################################ + string(JSON o3de_engine_restricted_count ERROR_VARIABLE json_error LENGTH ${engine_data} restricted) + if(json_error) + message(FATAL_ERROR "Unable to read key 'restricted' from '${o3de_manifest_json_path}', error: ${json_error}") + endif() + if(${o3de_engine_restricted_count} GREATER 0) + math(EXPR o3de_engine_restricted_count "${o3de_engine_restricted_count}-1") + foreach(engine_restricted_index RANGE ${o3de_engine_restricted_count}) + string(JSON engine_restricted_path ERROR_VARIABLE json_error GET ${engine_data} restricted ${engine_restricted_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engine restricted[${engine_restricted_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_restricted ${engine_restricted_path}) + list(APPEND o3de_engine_restricted ${engine_restricted_path}) + endforeach() + endif() + + ################################################################################ + # o3de engine external_subdirectories + ################################################################################ + string(JSON o3de_external_subdirectories_count ERROR_VARIABLE json_error LENGTH ${engine_data} external_subdirectories) + if(json_error) + message(FATAL_ERROR "Unable to read key 'external_subdirectories' from '${o3de_manifest_json_path}', error: ${json_error}") + endif() + if(${o3de_external_subdirectories_count} GREATER 0) + math(EXPR o3de_external_subdirectories_count "${o3de_external_subdirectories_count}-1") + foreach(external_subdirectories_index RANGE ${o3de_external_subdirectories_count}) + string(JSON external_subdirectories_path ERROR_VARIABLE json_error GET ${engine_data} external_subdirectories ${external_subdirectories_index}) + if(json_error) + message(FATAL_ERROR "Unable to read engine external_subdirectories[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") + endif() + list(APPEND o3de_engine_external_subdirectories ${external_subdirectories_path}) + endforeach() + endif() + + break() + + endif() + endforeach() +endif() + + +################################################################################ +#! o3de_engine_id: +# +# \arg:engine returns the engine association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_engine_id o3de_json_file engine) + file(READ ${o3de_json_file} json_data) + string(JSON engine_entry ERROR_VARIABLE json_error GET ${json_data} engine) + if(json_error) + message(WARNING "Unable to read engine from '${o3de_json_file}', error: ${json_error}") + message(WARNING "Setting engine to engine default 'o3de'") + set(engine_entry "o3de") + endif() + if(engine_entry) + set(${engine} ${engine_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_project_id: +# +# \arg:project returns the project association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_project_id o3de_json_file project) + file(READ ${o3de_json_file} json_data) + string(JSON project_entry ERROR_VARIABLE json_error GET ${json_data} project) + if(json_error) + message(FATAL_ERROR "Unable to read project from '${o3de_json_file}', error: ${json_error}") + endif() + if(project_entry) + set(${project} ${project_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_gem_id: +# +# \arg:gem returns the gem association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_gem_id o3de_json_file gem) + file(READ ${o3de_json_file} json_data) + string(JSON gem_entry ERROR_VARIABLE json_error GET ${json_data} gem) + if(json_error) + message(FATAL_ERROR "Unable to read gem from '${o3de_json_file}', error: ${json_error}") + endif() + if(gem_entry) + set(${gem} ${gem_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_template_id: +# +# \arg:template returns the template association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_template_id o3de_json_file template) + file(READ ${o3de_json_file} json_data) + string(JSON template_entry ERROR_VARIABLE json_error GET ${json_data} template) + if(json_error) + message(FATAL_ERROR "Unable to read template from '${o3de_json_file}', error: ${json_error}") + endif() + if(template_entry) + set(${template} ${template_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_repo_id: +# +# \arg:repo returns the repo association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_repo_id o3de_json_file repo) + file(READ ${o3de_json_file} json_data) + string(JSON repo_entry ERROR_VARIABLE json_error GET ${json_data} repo) + if(json_error) + message(FATAL_ERROR "Unable to read repo from '${o3de_json_file}', error: ${json_error}") + endif() + if(repo_entry) + set(${repo} ${repo_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_restricted_id: +# +# \arg:restricted returns the restricted association element from an o3de json, otherwise engine 'o3de' is assumed +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_restricted_id o3de_json_file restricted) + file(READ ${o3de_json_file} json_data) + string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} restricted) + if(json_error) + message(WARNING "Unable to read restricted from '${o3de_json_file}', error: ${json_error}") + message(WARNING "Setting restricted to engine default 'o3de'") + set(restricted_entry "o3de") + endif() + if(restricted_entry) + set(${restricted} ${restricted_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_find_engine_folder: +# +# \arg:engine_path returns the path of the o3de engine folder with name engine_name +# \arg:engine_name name of the engine +################################################################################ +function(o3de_find_engine_folder engine_name engine_path) + foreach(engine_entry ${o3de_engines}) + set(engine_json_file ${engine_entry}/engine.json) + file(READ ${engine_json_file} engine_json) + string(JSON this_engine_name ERROR_VARIABLE json_error GET ${engine_json} engine_name) + if(json_error) + message(WARNING "Unable to read engine_name from '${engine_json_file}', error: ${json_error}") + else() + if(this_engine_name STREQUAL engine_name) + set(${engine_path} ${engine_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find repo_name: '${engine_name}'") +endfunction() + + +################################################################################ +#! o3de_find_project_folder: +# +# \arg:project_path returns the path of the o3de project folder with name project_name +# \arg:project_name name of the project +################################################################################ +function(o3de_find_project_folder project_name project_path) + foreach(project_entry ${o3de_projects}) + set(project_json_file ${project_entry}/project.json) + file(READ ${project_json_file} project_json) + string(JSON this_project_name ERROR_VARIABLE json_error GET ${project_json} project_name) + if(json_error) + message(WARNING "Unable to read project_name from '${project_json_file}', error: ${json_error}") + else() + if(this_project_name STREQUAL project_name) + set(${project_path} ${project_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find project_name: '${project_name}'") +endfunction() + + +################################################################################ +#! o3de_find_gem_folder: +# +# \arg:gem_path returns the path of the o3de gem folder with name gem_name +# \arg:gem_name name of the gem +################################################################################ +function(o3de_find_gem_folder gem_name gem_path) + foreach(gem_entry ${o3de_gems}) + set(gem_json_file ${gem_entry}/gem.json) + file(READ ${gem_json_file} gem_json) + string(JSON this_gem_name ERROR_VARIABLE json_error GET ${gem_json} gem_name) + if(json_error) + message(WARNING "Unable to read gem_name from '${gem_json_file}', error: ${json_error}") + else() + if(this_gem_name STREQUAL gem_name) + set(${gem_path} ${gem_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find gem_name: '${gem_name}'") +endfunction() + + +################################################################################ +#! o3de_find_template_folder: +# +# \arg:template_path returns the path of the o3de template folder with name template_name +# \arg:template_name name of the template +################################################################################ +function(o3de_find_template_folder template_name template_path) + foreach(template_entry ${o3de_templates}) + set(template_json_file ${template_entry}/template.json) + file(READ ${template_json_file} template_json) + string(JSON this_template_name ERROR_VARIABLE json_error GET ${template_json} template_name) + if(json_error) + message(WARNING "Unable to read template_name from '${template_json_file}', error: ${json_error}") + else() + if(this_template_name STREQUAL template_name) + set(${template_path} ${template_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find template_name: '${template_name}'") +endfunction() + + +################################################################################ +#! o3de_find_repo_folder: +# +# \arg:repo_path returns the path of the o3de repo folder with name repo_name +# \arg:repo_name name of the repo +################################################################################ +function(o3de_find_repo_folder repo_name repo_path) + foreach(repo_entry ${o3de_repos}) + set(repo_json_file ${repo_entry}/repo.json) + file(READ ${repo_json_file} repo_json) + string(JSON this_repo_name ERROR_VARIABLE json_error GET ${repo_json} repo_name) + if(json_error) + message(WARNING "Unable to read repo_name from '${repo_json_file}', error: ${json_error}") + else() + if(this_repo_name STREQUAL repo_name) + set(${repo_path} ${repo_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find repo_name: '${repo_name}'") +endfunction() + + +################################################################################ +#! o3de_find_restricted_folder: +# +# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_name name of the restricted +################################################################################ +function(o3de_find_restricted_folder restricted_name restricted_path) + foreach(restricted_entry ${o3de_restricted}) + set(restricted_json_file ${restricted_entry}/restricted.json) + file(READ ${restricted_json_file} restricted_json) + string(JSON this_restricted_name ERROR_VARIABLE json_error GET ${restricted_json} restricted_name) + if(json_error) + message(WARNING "Unable to read restricted_name from '${restricted_json_file}', error: ${json_error}") + else() + if(this_restricted_name STREQUAL restricted_name) + set(${restricted_path} ${restricted_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() + message(FATAL_ERROR "Unable to find restricted_name: '${restricted_name}'") +endfunction() + + +################################################################################ +#! o3de_engine_name: +# +# \arg:engine returns the engine_name element from an engine.json +# \arg:o3de_engine_json_file name of the o3de json file +################################################################################ +function(o3de_engine_name o3de_engine_json_file engine) + file(READ ${o3de_engine_json_file} json_data) + string(JSON engine_entry ERROR_VARIABLE json_error GET ${json_data} engine_name) + if(json_error) + message(FATAL_ERROR "Unable to read engine_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(engine_entry) + set(${engine} ${engine_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_project_name: +# +# \arg:project returns the project_name element from an project.json +# \arg:o3de_project_json_file name of the o3de json file +################################################################################ +function(o3de_project_name o3de_project_json_file project) + file(READ ${o3de_project_json_file} json_data) + string(JSON project_entry ERROR_VARIABLE json_error GET ${json_data} project_name) + if(json_error) + message(FATAL_ERROR "Unable to read project_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(project_entry) + set(${project} ${project_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_gem_name: +# +# \arg:gem returns the gem_name element from an gem.json +# \arg:o3de_gem_json_file name of the o3de json file +################################################################################ +function(o3de_gem_name o3de_gem_json_file gem) + file(READ ${o3de_gem_json_file} json_data) + string(JSON gem_entry ERROR_VARIABLE json_error GET ${json_data} gem_name) + if(json_error) + message(FATAL_ERROR "Unable to read gem_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(gem_entry) + set(${gem} ${gem_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_template_name: +# +# \arg:template returns the template_name element from an template json +# \arg:o3de_template_json_file name of the o3de json file +################################################################################ +function(o3de_template_name o3de_template_json_file template) + file(READ ${o3de_template_json_file} json_data) + string(JSON template_entry ERROR_VARIABLE json_error GET ${json_data} template_name) + if(json_error) + message(FATAL_ERROR "Unable to read template_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(template_entry) + set(${template} ${template_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_repo_name: +# +# \arg:repo returns the repo_name element from an repo.json or o3de_manifest.json +# \arg:o3de_repo_json_file name of the o3de json file +################################################################################ +function(o3de_repo_name o3de_repo_json_file repo) + file(READ ${o3de_repo_json_file} json_data) + string(JSON repo_entry ERROR_VARIABLE json_error GET ${json_data} repo_name) + if(json_error) + message(FATAL_ERROR "Unable to read repo_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(repo_entry) + set(${repo} ${repo_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_restricted_name: +# +# \arg:restricted returns the restricted association element from an o3de json +# \arg:o3de_json_file name of the o3de json file +################################################################################ +function(o3de_restricted_name o3de_json_file restricted) + file(READ ${o3de_json_file} json_data) + string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} restricted_name) + if(json_error) + message(WARNING "FATAL_ERROR to read restricted_name from '${o3de_json_file}', error: ${json_error}") + endif() + if(restricted_entry) + set(${restricted} ${restricted_entry} PARENT_SCOPE) + endif() +endfunction() + + +################################################################################ +#! o3de_engine_path: +# +# \arg:engine_path returns the path of the o3de engine folder with name engine_name +# \arg:engine_name name of the engine +################################################################################ +function(o3de_engine_path o3de_json_file engine_path) + o3de_engine_id(${o3de_json_file} engine_name) + if(engine_name) + o3de_find_engine_folder(${engine_name} engine_folder) + if(engine_folder) + set(${engine_path} ${engine_folder} PARENT_SCOPE) + endif() + endif() +endfunction() + + +################################################################################ +#! o3de_project_path: +# +# \arg:project_path returns the path of the o3de project folder with name project_name +# \arg:project_name name of the project +################################################################################ +function(o3de_project_path o3de_json_file project_path) + o3de_project_id(${o3de_json_file} project_name) + if(project_name) + o3de_find_project_folder(${project_name} project_folder) + if(project_folder) + set(${project_path} ${project_folder} PARENT_SCOPE) + endif() + endif() +endfunction() + + +################################################################################ +#! o3de_template_path: +# +# \arg:template_path returns the path of the o3de template folder with name template_name +# \arg:template_name name of the template +################################################################################ +function(o3de_template_path o3de_json_file template_path) + o3de_template_id(${o3de_json_file} template_name) + if(template_name) + o3de_find_template_folder(${template_name} template_folder) + if(template_folder) + set(${template_path} ${template_folder} PARENT_SCOPE) + endif() + endif() +endfunction() + + +################################################################################ +#! o3de_repo_path: +# +# \arg:repo_path returns the path of the o3de repo folder with name repo_name +# \arg:repo_name name of the repo +################################################################################ +function(o3de_repo_path o3de_json_file repo_path) + o3de_repo_id(${o3de_json_file} repo_name) + if(repo_name) + o3de_find_repo_folder(${repo_name} repo_folder) + if(repo_folder) + set(${repo_path} ${repo_folder} PARENT_SCOPE) + endif() + endif() +endfunction() + + +################################################################################ +#! o3de_restricted_path: +# +# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_name name of the restricted +################################################################################ +function(o3de_restricted_path o3de_json_file restricted_path) + o3de_restricted_id(${o3de_json_file} restricted_name) + if(restricted_name) + o3de_find_restricted_folder(${restricted_name} restricted_folder) + if(restricted_folder) + set(${restricted_path} ${restricted_folder} PARENT_SCOPE) + endif() + endif() +endfunction() diff --git a/engine.json b/engine.json index 5091605f4c..22ac2512f5 100644 --- a/engine.json +++ b/engine.json @@ -1,5 +1,6 @@ { "engine_name": "o3de", + "restricted": "o3de", "FileVersion": 1, "O3DEVersion": "0.0.0.0", "O3DECopyrightYear": 2021 diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index f85b0b5ef4..ae2779eba8 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -60,7 +60,7 @@ def palRm(path) { } else { def win_path = path.replace('/','\\') bat label: "Removing ${win_path}", - script: "del ${win_path}" + script: "del /Q ${win_path}" } } @@ -354,6 +354,16 @@ def TestMetrics(Map pipelineConfig, String workspace, String branchName, String } } +def ExportTestResults(Map options, String platform, String type, String workspace, Map params) { + catchError(message: "Error exporting tests results (this won't fail the build)", buildResult: 'SUCCESS', stageResult: 'FAILURE') { + def o3deroot = "${workspace}/${ENGINE_REPOSITORY_NAME}" + dir("${o3deroot}/${params.OUTPUT_DIRECTORY}") { + junit testResults: "Testing/**/*.xml" + palRmDir("Testing") + } + } +} + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -396,6 +406,14 @@ def CreateTestMetricsStage(Map pipelineConfig, String branchName, Map environmen } } +def CreateExportTestResultsStage(Map pipelineConfig, String platformName, String jobName, Map environmentVars, Map params) { + return { + stage("${jobName}_results") { + ExportTestResults(pipelineConfig, platformName, jobName, environmentVars['WORKSPACE'], params) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage('Teardown') { @@ -511,11 +529,15 @@ try { } } finally { - if (env.MARS_REPO && platform.value.build_types[build_job_name].PARAMETERS.containsKey('TEST_METRICS') && platform.value.build_types[build_job_name].PARAMETERS.TEST_METRICS == 'True') { - def output_directory = platform.value.build_types[build_job_name].PARAMETERS.OUTPUT_DIRECTORY - def configuration = platform.value.build_types[build_job_name].PARAMETERS.CONFIGURATION + def params = platform.value.build_types[build_job_name].PARAMETERS + if (env.MARS_REPO && params && params.containsKey('TEST_METRICS') && params.TEST_METRICS == 'True') { + def output_directory = params.OUTPUT_DIRECTORY + def configuration = params.CONFIGURATION CreateTestMetricsStage(pipelineConfig, branchName, envVars, build_job_name, output_directory, configuration).call() } + if (params && params.containsKey('TEST_RESULTS') && params.TEST_RESULTS == 'True') { + CreateExportTestResultsStage(pipelineConfig, platform.key, build_job_name, envVars, params).call() + } CreateTeardownStage(envVars).call() } } diff --git a/scripts/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index 699ccdf20a..d0fce80964 100644 --- a/scripts/build/Platform/Android/build_config.json +++ b/scripts/build/Platform/Android/build_config.json @@ -35,7 +35,7 @@ "PARAMETERS": { "CONFIGURATION":"debug", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -76,7 +76,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=FALSE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -93,7 +93,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -128,7 +128,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\mono_android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index 4ae4c4ec0b..bbfc3e4269 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -53,7 +53,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -80,7 +80,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" @@ -92,7 +92,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" @@ -108,7 +108,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -122,7 +122,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -140,7 +140,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"" @@ -156,7 +156,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"" @@ -172,7 +172,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -187,7 +187,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } diff --git a/scripts/build/Platform/Mac/build_config.json b/scripts/build/Platform/Mac/build_config.json index 1e6ca79d8e..f312279fe6 100644 --- a/scripts/build/Platform/Mac/build_config.json +++ b/scripts/build/Platform/Mac/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -51,7 +51,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=FALSE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -81,7 +81,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"" @@ -115,7 +115,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"" @@ -131,7 +131,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -146,7 +146,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 263539cd4a..ee34bae3e3 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -87,7 +87,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -101,12 +101,13 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "profile_vs2019": { @@ -118,7 +119,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -134,7 +135,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=FALSE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -149,12 +150,13 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "test_gpu_profile_vs2019": { @@ -169,12 +171,13 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_smoke_REQUIRES_gpu|SUITE_main_REQUIRES_gpu)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "asset_profile_vs2019": { @@ -187,7 +190,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -206,12 +209,13 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "sandbox_test_profile_vs2019": { @@ -227,12 +231,13 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_sandbox", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_sandbox)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "benchmark_test_profile_vs2019": { @@ -245,12 +250,13 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\" -T Test", - "TEST_METRICS": "True" + "TEST_METRICS": "True", + "TEST_RESULTS": "True" } }, "release_vs2019": { @@ -263,7 +269,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -279,7 +285,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\mono_windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -294,7 +300,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCMAKE_INSTALL_PREFIX=install", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCMAKE_INSTALL_PREFIX=install -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "INSTALL", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/Windows/package_build_config.json b/scripts/build/Platform/Windows/package_build_config.json index a5ca861377..40f479a098 100644 --- a/scripts/build/Platform/Windows/package_build_config.json +++ b/scripts/build/Platform/Windows/package_build_config.json @@ -4,7 +4,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "windows_vs2017", - "CMAKE_OPTIONS": "-G \"Visual Studio 15 2017\" -A x64 -T host=x64 -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 15 2017\" -A x64 -T host=x64 -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AtomTest;AtomSampleViewer", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m:4 /p:CL_MPCount=!HALF_PROCESSORS! /nologo" @@ -15,7 +15,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS":"AtomTest;AtomSampleViewer", "CMAKE_TARGET":"ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/iOS/build_config.json b/scripts/build/Platform/iOS/build_config.json index 75b5e7b10d..4566d243ee 100644 --- a/scripts/build/Platform/iOS/build_config.json +++ b/scripts/build/Platform/iOS/build_config.json @@ -27,7 +27,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -44,7 +44,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=FALSE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -94,7 +94,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" diff --git a/scripts/build/tools/email_to_lionbridge.py b/scripts/build/tools/email_to_lionbridge.py index c2edcbe9f2..7f522bb564 100755 --- a/scripts/build/tools/email_to_lionbridge.py +++ b/scripts/build/tools/email_to_lionbridge.py @@ -10,7 +10,7 @@ # """ -This script will be used in https://jenkins.agscollab.com/view/%7ESandbox/job/PACKAGE_COPY_S3/ +This script will be used in the Sandobx Jenkins job PACKAGE_COPY_S3 PACKAGE_COPY_S3 is a downstream job of nightly packaging job, it copies the nightly packages from Infra S3 bucket to Lionbridge S3 bucket based on the INCLUDE_FILTER passed from packaging job """ import os diff --git a/scripts/o3de.bat b/scripts/o3de.bat index 9dd0d5b539..0a65b722d7 100644 --- a/scripts/o3de.bat +++ b/scripts/o3de.bat @@ -33,4 +33,6 @@ popd EXIT /b 1 :end popd +EXIT /b %ERRORLEVEL% + diff --git a/scripts/o3de.py b/scripts/o3de.py index 1c528704f4..dbb9c53e4b 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -19,15 +19,13 @@ if ROOT_DEV_PATH not in sys.path: sys.path.append(ROOT_DEV_PATH) from cmake.Tools import engine_template -from cmake.Tools import current_project -from cmake.Tools import add_remove_gem +from cmake.Tools import global_project from cmake.Tools import registration def add_args(parser, subparsers) -> None: - current_project.add_args(parser, subparsers) + global_project.add_args(parser, subparsers) engine_template.add_args(parser, subparsers) - add_remove_gem.add_args(parser, subparsers) registration.add_args(parser, subparsers) diff --git a/scripts/o3de.sh b/scripts/o3de.sh index 6b789b494f..dde8808551 100755 --- a/scripts/o3de.sh +++ b/scripts/o3de.sh @@ -15,11 +15,9 @@ #Note this does not actually change the working directory SCRIPT_DIR=$(cd `dirname $0` && pwd) -#The engine root is always the parent of the scripts directory, so $(dirname "$SCRIPT_DIR") should get us engine root -ENGINE_ROOT=$(dirname "$SCRIPT_DIR") - -#The engines python is in the engineroot/python -PYTHON_DIRECTORY="$ENGINE_ROOT/python" +#python should be in the base path +BASE_PATH=$(dirname "$SCRIPT_DIR") +PYTHON_DIRECTORY="$BASE_PATH/python" #If engine python exists use it, if not try the system python if [ ! -d "$PYTHON_DIRECTORY" ]; then @@ -33,4 +31,5 @@ if [ ! -f "$PYTHON_EXECUTABLE" ]; then fi #run the o3de.py pass along the command -$PYTHON_EXECUTABLE "$SCRIPT_DIR/o3de.py" $* \ No newline at end of file +$PYTHON_EXECUTABLE "$SCRIPT_DIR/o3de.py" $* +exit $? \ No newline at end of file diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 5cd506c515..51db7a6440 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -12,47 +12,45 @@ # PySide project and gem selector GUI import os +import pathlib import sys import argparse import json import logging import subprocess -import threading -import platform from logging.handlers import RotatingFileHandler - from typing import List - -from pathlib import Path from pyside import add_pyside_environment, is_pyside_ready, uninstall_env +engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) +sys.path.append(engine_path) +executable_path = '' + logger = logging.getLogger() logger.setLevel(logging.INFO) -log_path = os.path.join(os.path.dirname(__file__), "logs") -if not os.path.isdir(log_path): - os.makedirs(log_path) -log_path = os.path.join(log_path, "project_manager.log") -log_file_handler = RotatingFileHandler(filename=log_path, maxBytes=1024 * 1024, backupCount=1) +from cmake.Tools import engine_template +from cmake.Tools import registration + +o3de_folder = registration.get_o3de_folder() +o3de_logs_folder = registration.get_o3de_logs_folder() +project_manager_log_file_path = o3de_log_folder / "project_manager.log" +log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1) formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') log_file_handler.setFormatter(formatter) logger.addHandler(log_file_handler) logger.info("Starting Project Manager") -engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) -sys.path.append(engine_path) -executable_path = '' - def initialize_pyside_from_parser(): # Parse arguments up top. We need to know the path to our binaries and QT libs in particular to load up # PySide parser = argparse.ArgumentParser() - parser.add_argument('--executable_path', required=True, help='Path to Executable to launch with project') - parser.add_argument('--binaries_path', default=None, help='Path to QT Binaries necessary for PySide. If not' - 'provided executable_path folder is assumed') - parser.add_argument('--parent_pid', default=0, help='Process ID of launching process') + parser.add_argument('--executable-path', required=True, help='Path to Executable to launch with project') + parser.add_argument('--binaries-path', default=None, help='Path to QT Binaries necessary for PySide. If not' + ' provided executable_path folder is assumed') + parser.add_argument('--parent-pid', default=0, help='Process ID of launching process') args = parser.parse_args() @@ -81,21 +79,6 @@ except ImportError as e: logger.error(f"PySide2 imports successful") -from cmake.Tools import engine_template -from cmake.Tools import add_remove_gem - -ui_path = os.path.join(os.path.join(os.path.dirname(__file__), 'ui')) -ui_file = 'projects.ui' -ui_icon_file = 'projects.ico' -manage_gems_file = 'manage_gems.ui' -create_project_file = 'create_project.ui' - -mru_file_name = 'o3de_projects.json' -default_settings_folder = os.path.join(Path.home(), '.o3de') - -# Used to indicate a folder which appears to be a valid o3de project -project_marker_file = 'project.json' - class DialogLoggerSignaller(QObject): send_to_dialog = Signal(str) @@ -132,14 +115,16 @@ class DialogLogger(logging.Handler): self.signaller.send_to_dialog.emit(self.format(record)) - -class ProjectDialog(QObject): +class ProjectManagerDialog(QObject): """ - Main project dialog class responsible for displaying the project selection list + Main project manager dialog is responsible for displaying the project selection list and output pane """ - def __init__(self, parent=None, my_ui_path=ui_path, settings_folder=default_settings_folder): - super(ProjectDialog, self).__init__(parent) + def __init__(self, parent=None): + super(ProjectManagerDialog, self).__init__(parent) + + self.ui_path = (pathlib.Path(__file__).parent / 'ui').resolve() + self.home_folder = registration.get_home_folder() self.log_display = None self.dialog_logger = DialogLogger(self) @@ -147,76 +132,100 @@ class ProjectDialog(QObject): logger.setLevel(logging.INFO) self.dialog_logger.signaller.send_to_dialog.connect(self.handle_log_message) - self.displayed_projects = [] + self.mru_file_path = o3de_folder / 'mru.json' - self.mru_file_path = os.path.join(settings_folder, mru_file_name) + self.create_from_template_ui_file_path = self.ui_path / 'create_from_template.ui' + self.create_gem_ui_file_path = self.ui_path / 'create_gem.ui' + self.create_project_ui_file_path = self.ui_path / 'create_project.ui' + self.manage_project_gem_targets_ui_file_path = self.ui_path / 'manage_gem_targets.ui' + self.project_manager_icon_file_path = self.ui_path / 'project_manager.ico' + self.project_manager_ui_file_path = self.ui_path / 'project_manager.ui' - self.my_ui_file_path = os.path.join(my_ui_path, ui_file) - self.my_ui_icon_path = os.path.join(my_ui_path, ui_icon_file) - self.my_ui_manage_gems_path = os.path.join(my_ui_path, manage_gems_file) - self.my_ui_create_project_path = os.path.join(my_ui_path, create_project_file) - self.ui_dir = my_ui_path - self.ui_file = QFile(self.my_ui_file_path) - self.ui_file.open(QFile.ReadOnly) + self.project_manager_ui_file = QFile(self.project_manager_ui_file_path.as_posix()) + self.project_manager_ui_file.open(QFile.ReadOnly) loader = QUiLoader() - self.dialog = loader.load(self.ui_file) - self.dialog.setWindowIcon(QIcon(self.my_ui_icon_path)) + self.dialog = loader.load(self.project_manager_ui_file) + self.dialog.setWindowIcon(QIcon(self.project_manager_icon_file_path.as_posix())) self.dialog.setFixedSize(self.dialog.size()) - self.browse_projects_button = self.dialog.findChild(QPushButton, 'browseProjectsButton') - self.browse_projects_button.clicked.connect(self.browse_projects_handler) - self.log_display = self.dialog.findChild(QLabel, 'logDisplay') + self.project_list_box = self.dialog.findChild(QComboBox, 'projectListBox') + self.refresh_project_list() + mru = self.get_mru_list() + if len(mru): + last_mru = pathlib.Path(mru[0]).resolve() + for this_slot in range(self.project_list_box.count()): + item_text = self.project_list_box.itemText(this_slot) + if last_mru.as_posix() in item_text: + self.project_list_box.setCurrentIndex(this_slot) + break self.create_project_button = self.dialog.findChild(QPushButton, 'createProjectButton') self.create_project_button.clicked.connect(self.create_project_handler) + self.create_gem_button = self.dialog.findChild(QPushButton, 'createGemButton') + self.create_gem_button.clicked.connect(self.create_gem_handler) + self.create_template_button = self.dialog.findChild(QPushButton, 'createTemplateButton') + self.create_template_button.clicked.connect(self.create_template_handler) + self.create_from_template_button = self.dialog.findChild(QPushButton, 'createFromTemplateButton') + self.create_from_template_button.clicked.connect(self.create_from_template_handler) + + self.add_project_button = self.dialog.findChild(QPushButton, 'addProjectButton') + self.add_project_button.clicked.connect(self.add_project_handler) + self.add_gem_button = self.dialog.findChild(QPushButton, 'addGemButton') + self.add_gem_button.clicked.connect(self.add_gem_handler) + self.add_template_button = self.dialog.findChild(QPushButton, 'addTemplateButton') + self.add_template_button.clicked.connect(self.add_template_handler) + self.add_restricted_button = self.dialog.findChild(QPushButton, 'addRestrictedButton') + self.add_restricted_button.clicked.connect(self.add_restricted_handler) + + self.remove_project_button = self.dialog.findChild(QPushButton, 'removeProjectButton') + self.remove_project_button.clicked.connect(self.remove_project_handler) + self.remove_gem_button = self.dialog.findChild(QPushButton, 'removeGemButton') + self.remove_gem_button.clicked.connect(self.remove_gem_handler) + self.remove_template_button = self.dialog.findChild(QPushButton, 'removeTemplateButton') + self.remove_template_button.clicked.connect(self.remove_template_handler) + self.remove_restricted_button = self.dialog.findChild(QPushButton, 'removeRestrictedButton') + self.remove_restricted_button.clicked.connect(self.remove_restricted_handler) + + self.manage_runtime_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageRuntimeGemTargetsButton') + self.manage_runtime_project_gem_targets_button.clicked.connect(self.manage_runtime_project_gem_targets_handler) + self.manage_tool_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageToolGemTargetsButton') + self.manage_tool_project_gem_targets_button.clicked.connect(self.manage_tool_project_gem_targets_handler) + self.manage_server_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageServerGemTargetsButton') + self.manage_server_project_gem_targets_button.clicked.connect(self.manage_server_project_gem_targets_handler) + + self.log_display = self.dialog.findChild(QLabel, 'logDisplay') self.ok_cancel_button = self.dialog.findChild(QDialogButtonBox, 'okCancel') self.ok_cancel_button.accepted.connect(self.accepted_handler) - self.manage_gems_button = self.dialog.findChild(QPushButton, 'manageGemsButton') - self.manage_gems_button.clicked.connect(self.manage_gems_handler) - - self.project_list_box = self.dialog.findChild(QComboBox, 'projectListBox') - self.add_projects(self.get_mru_list()) - self.project_gem_list = [] - self.dialog.show() - self.load_thread = None - self.gems_list = [] - self.load_gems() + def refresh_project_list(self) -> None: + projects = registration.get_all_projects() + self.project_list_box.clear() + for this_slot in range(len(projects)): + display_name = f'{os.path.basename(os.path.normpath(projects[this_slot]))} ({projects[this_slot]})' + self.project_list_box.addItem(display_name) + self.project_list_box.setItemData(self.project_list_box.count() - 1, projects[this_slot], + Qt.ToolTipRole) - def update_gems(self) -> None: + def accepted_handler(self) -> None: """ - Perform a full refresh of active project and available gems. Loads both from - data on disk and refreshes UI + Override for handling "Ok" on main project dialog to first check whether the user has selected a project and + prompt them to if not. If a project is selected will attempt to open it. :return: None """ - project_path = self.path_for_selection() - if not project_path: - self.project_gem_list = set() - else: - self.project_gem_list = add_remove_gem.get_project_gem_list(self.path_for_selection()) - project_gem_model = QStandardItemModel() - for item in sorted(self.project_gem_list): - project_gem_model.appendRow(QStandardItem(item)) - self.project_gems.setModel(project_gem_model) - - add_gem_model = QStandardItemModel() - for item in self.gems_list: - if item.get('Name') in self.project_gem_list: - continue - model_item = QStandardItem(item.get('Name')) - model_item.setData(item.get('Path'), Qt.UserRole) - add_gem_model.appendRow(model_item) - self.add_gems_list.setModel(add_gem_model) - - def get_selected_project_name(self) -> str: - return os.path.basename(self.path_for_selection()) + if not self.project_list_box.currentText(): + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText("Please select a project") + msg_box.exec() + return + self.launch_with_project_path(self.get_selected_project_path()) def get_launch_project(self) -> str: - return os.path.normpath(self.path_for_selection()) + return os.path.normpath(self.get_selected_project_path()) def get_executable_launch_params(self) -> list: """ @@ -228,363 +237,718 @@ class ProjectDialog(QObject): f'-regset="/Amazon/AzCore/Bootstrap/project_path={self.get_launch_project()}"'] return launch_params - def load_gems(self) -> None: + def launch_with_project_path(self, project_path: str) -> None: """ - Starts another thread to discover available gems. This requires file discovery/parsing and would likely - cause a noticeable pause if it were not on another thread + Launch the desired application given the selected project + :param project_path: Path to currently selected project :return: None """ - self.load_thread = threading.Thread(target=self.load_gems_thread_func) - self.load_thread.start() + logger.info(f'Attempting to open {project_path}') + self.update_mru_list(project_path) + launch_params = self.get_executable_launch_params() + logger.info(f'Launching with params {launch_params}') + subprocess.run(launch_params, env=uninstall_env()) + + def get_selected_project_path(self) -> str: + if self.project_list_box.currentIndex() == -1: + logger.warning("No project selected") + return "" + return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole) - def load_gems_thread_func(self) -> None: + def get_selected_project_name(self) -> str: + project_data = registration.get_project_data(project_path=self.get_selected_project_path()) + return project_data['project_name'] + + def create_project_handler(self): """ - Actual load function for load_gems thread. Blocking call to lower level find method to fill out gems_list + Opens the Create Project pane. Retrieves a list of available templates for display :return: None """ - self.gems_list = add_remove_gem.find_all_gems([os.path.join(engine_path, 'Gems')]) + loader = QUiLoader() + self.create_project_file = QFile(self.create_project_ui_file_path.as_posix()) + + if not self.create_project_file: + logger.error(f'Failed to create project UI file at {self.create_project_file}') + return + + self.create_project_dialog = loader.load(self.create_project_file) + + if not self.create_project_dialog: + logger.error(f'Failed to load create project dialog file at {self.create_project_file}') + return + + self.create_project_ok_button = self.create_project_dialog.findChild(QDialogButtonBox, 'okCancel') + self.create_project_ok_button.accepted.connect(self.create_project_accepted_handler) + + self.create_project_template_list = self.create_project_dialog.findChild(QListView, 'projectTemplates') + self.refresh_create_project_template_list() + + self.create_project_dialog.exec() - def load_template_list(self) -> None: + def create_project_accepted_handler(self) -> None: """ - Search for available templates to fill out template list + Searches the available gems list for selected gems and attempts to add each one to the current project. + Updates UI after completion. :return: None """ - self.project_templates = engine_template.find_all_project_templates([os.path.join(engine_path, 'Templates')]) - def get_gem_info(self, gem_name: str) -> str: + selected_item = self.create_project_template_list.selectionModel().currentIndex() + project_template_path = self.create_project_template_list.model().data(selected_item) + if not project_template_path: + return + + folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", + registration.get_o3de_projects_folder().as_posix()) + folder_dialog.setFileMode(QFileDialog.AnyFile) + folder_dialog.setOptions(QFileDialog.ShowDirsOnly) + project_count = 0 + project_name = "MyNewProject" + while os.path.exists(os.path.join(engine_path, project_name)): + project_name = f"MyNewProject{project_count}" + project_count += 1 + folder_dialog.selectFile(project_name) + project_folder = None + if folder_dialog.exec(): + project_folder = folder_dialog.selectedFiles() + if project_folder: + if engine_template.create_project(project_path=project_folder[0], + template_path=project_template_path) == 0: + # Success + registration.register(project_path=project_folder[0]) + self.refresh_project_list() + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Project {project_folder[0]} created.") + msg_box.exec() + return + + def create_gem_handler(self): """ - Provided a known gem name provides gem info - :param gem_name: Name of known gem. Names are based on Gem. module names in CMakeLists.txt rather - than folders a Gem lives in. - :return: Dictionary with data about gem if known + Opens the Create Gem pane. Retrieves a list of available templates for display + :return: None """ - for this_gem in self.gems_list: - if this_gem.get('Name') == gem_name: - this_gem - return None + loader = QUiLoader() + self.create_gem_file = QFile(self.create_gem_ui_file_path.as_posix()) + + if not self.create_gem_file: + logger.error(f'Failed to create gem UI file at {self.create_gem_file}') + return + + self.create_gem_dialog = loader.load(self.create_gem_file) + + if not self.create_gem_dialog: + logger.error(f'Failed to load create gem dialog file at {self.create_gem_file}') + return + + self.create_gem_ok_button = self.create_gem_dialog.findChild(QDialogButtonBox, 'okCancel') + self.create_gem_ok_button.accepted.connect(self.create_gem_accepted_handler) + + self.create_gem_template_list = self.create_gem_dialog.findChild(QListView, 'gemTemplates') + self.refresh_create_gem_template_list() - def get_gem_info_by_path(self, gem_path: str) -> str: + self.create_gem_dialog.exec() + + def create_gem_accepted_handler(self) -> None: """ - Provided a gem path returns the gem info if known - :param gem_path: Path to gem - :return: Dictionary with data about gem if known + Searches the available gems list for selected gems and attempts to add each one to the current gem. + Updates UI after completion. + :return: None """ - for this_gem in self.gems_list: - if this_gem.get('Path') == gem_path: - return this_gem - return None + selected_item = self.create_gem_template_list.selectionModel().currentIndex() + gem_template_path = self.create_gem_template_list.model().data(selected_item) + if not gem_template_path: + return - def path_for_gem(self, gem_name: str) -> str: + folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", + registration.get_o3de_gems_folder().as_posix()) + folder_dialog.setFileMode(QFileDialog.AnyFile) + folder_dialog.setOptions(QFileDialog.ShowDirsOnly) + gem_count = 0 + gem_name = "MyNewGem" + while os.path.exists(os.path.join(engine_path, gem_name)): + gem_name = f"MyNewGem{gem_count}" + gem_count += 1 + folder_dialog.selectFile(gem_name) + gem_folder = None + if folder_dialog.exec(): + gem_folder = folder_dialog.selectedFiles() + if gem_folder: + if engine_template.create_gem(gem_path=gem_folder[0], + template_path=gem_template_path) == 0: + # Success + registration.register(gem_path=gem_folder[0]) + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Gem {gem_folder[0]} created.") + msg_box.exec() + return + + def create_template_handler(self): """ - Provided a known gem name provides the full path on disk - :param gem_name: Name of known gem. Names are based on Gem. module names in CMakeLists.txt rather - than folders a Gem lives in. - :return: Path to CMakeLists.txt containing the Gem modules + Opens a foldr select dialog and lets the user select the source folder they want to make a template + out of, then opens a second folder select dialog to get where they want to put the template and it name + :return: None """ - for this_gem in self.gems_list: - if this_gem.get('Name') == gem_name: - return this_gem.get('Path') - return '' - def open_project(self, project_path: str) -> None: + source_folder = QFileDialog.getExistingDirectory(self.dialog, + "Select a Folder to make a template out of.", + registration.get_o3de_folder().as_posix()) + if not source_folder: + return + + destination_template_folder_dialog = QFileDialog(self.dialog, + "Select where the template is to be created and named.", + registration.get_o3de_templates_folder().as_posix()) + destination_template_folder_dialog.setFileMode(QFileDialog.AnyFile) + destination_template_folder_dialog.setOptions(QFileDialog.ShowDirsOnly) + destination_folder = None + if destination_template_folder_dialog.exec(): + destination_folder = destination_template_folder_dialog.selectedFiles() + if not destination_folder: + return + + if engine_template.create_template(source_path=source_folder, + template_path=destination_folder[0]) == 0: + # Success + registration.register(template_path=destination_folder[0]) + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Template {destination_folder[0]} created.") + msg_box.exec() + return + + def create_from_template_handler(self): """ - Launch the desired application given the selected project - :param project_path: Path to currently selected project + Opens the Create from_template pane. Retrieves a list of available from_templates for display :return: None """ - logger.info(f'Attempting to open {project_path}') - self.update_mru_list(project_path) - launch_params = self.get_executable_launch_params() - try: - logger.info(f'Launching with params {launch_params}') - subprocess.Popen(launch_params, env=uninstall_env()) - quit(0) - except subprocess.CalledProcessError as e: - logger.error(f'Failed to start executable with launch params {launch_params} error {e}') + loader = QUiLoader() + self.create_from_template_file = QFile(self.create_from_template_ui_file_path.as_posix()) + + if not self.create_from_template_file: + logger.error(f'Failed to create from_template UI file at {self.create_from_template_file}') + return + + self.create_from_template_dialog = loader.load(self.create_from_template_file) + + if not self.create_from_template_dialog: + logger.error(f'Failed to load create from_template dialog file at {self.create_from_template_file}') + return + + self.create_from_template_ok_button = self.create_from_template_dialog.findChild(QDialogButtonBox, 'okCancel') + self.create_from_template_ok_button.accepted.connect(self.create_from_template_accepted_handler) - def path_for_selection(self) -> str: + self.create_from_template_list = self.create_from_template_dialog.findChild(QListView, 'genericTemplates') + self.refresh_create_from_template_list() + + self.create_from_template_dialog.exec() + + def create_from_template_accepted_handler(self) -> None: """ - Retrive the full path to the project the user currently has selected in the drop down - :return: str path to project + Searches the available gems list for selected gems and attempts to add each one to the current gem. + Updates UI after completion. + :return: None """ - if self.project_list_box.currentIndex() == -1: - logger.warning("No project selected") - return "" - return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole) + create_gem_item = self.get_selected_gem_template() + if not create_gem_item: + return - def accepted_handler(self) -> None: + folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", + registration.get_o3de_gems_folder().as_posix()) + folder_dialog.setFileMode(QFileDialog.AnyFile) + folder_dialog.setOptions(QFileDialog.ShowDirsOnly) + gem_count = 0 + gem_name = "MyNewGem" + while os.path.exists(os.path.join(engine_path, gem_name)): + gem_name = f"MyNewGem{gem_count}" + gem_count += 1 + folder_dialog.selectFile(gem_name) + gem_folder = None + if folder_dialog.exec(): + gem_folder = folder_dialog.selectedFiles() + if gem_folder: + if engine_template.create_gem(gem_folder[0], create_gem_item[1]) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"gem {os.path.basename(os.path.normpath(gem_folder[0]))} created." + " Build your\nnew gem before hitting OK to launch.") + msg_box.exec() + return + + def add_project_handler(self): """ - Override for handling "Ok" on main project dialog to first check whether the user has selected a project and - prompt them to if not. If a project is selected will attempt to open it. + Open a file search dialog looking for a folder which contains a valid project. If valid + will update the mru list with the new entry, if invalid will warn the user. :return: None """ - if not self.project_list_box.currentText(): - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText("Please select a project") - msg_box.exec() - return - self.open_project(self.path_for_selection()) + project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", + registration.get_o3de_projects_folder().as_posix()) + if project_folder: + if registration.register(project_path=project_folder) == 0: + # Success + self.refresh_project_list() - def is_project_folder(self, project_path: str) -> bool: + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Added Project {project_folder}.") + msg_box.exec() + return + + def add_gem_handler(self): """ - Checks whether the supplied path appears to be a canonical project folder. - Root of a valid project should contain the canonical file - :param project_path: - :return: + Open a file search dialog looking for a folder which contains a gem. If valid + will update the mru list with the new entry, if invalid will warn the user. + :return: None """ - return os.path.isfile(os.path.join(project_path, project_marker_file)) + gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", + registration.get_o3de_gems_folder().as_posix()) + if gem_folder: + if registration.register(gem_path=gem_folder) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Added Gem {gem_folder}.") + msg_box.exec() + return - def add_new_project(self, project_folder, update_mru=True, reset_selected=True, validate=True): + def add_template_handler(self): """ - Handle request to add a new project to our display and mru lists. Validation checks whether the folder - appears to be a project. Duplicates should never be added with or without validation. - :param project_folder: Absolute path to project folder - :param update_mru: Should the project also be promoted to "most recent" in our mru list - :param reset_selected: Update our drop down to show this as our current selection - :param validate: Verify the folder appears to be a valid project folder - :return: + Open a file search dialog looking for a folder which contains a valid template. If valid + will update the mru list with the new entry, if invalid will warn the user. + :return: None """ - if validate: - if not self.is_project_folder(project_folder): - QMessageBox.warning(self.dialog, "Invalid Project Folder", - f"{project_folder} does not contain a {project_marker_file}" - f" and does not appear to be a valid project") - return - self.add_projects([project_folder]) - if reset_selected: - self.project_list_box.setCurrentIndex(self.project_list_box.count() - 1) - if update_mru: - self.update_mru_list(project_folder) + template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", + registration.get_o3de_templates_folder().as_posix()) + if template_folder: + if registration.register(template_path=template_folder) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Added Template {template_folder}.") + msg_box.exec() + return + + def add_restricted_handler(self): + """ + Open a file search dialog looking for a folder which contains a valid template. If valid + will update the mru list with the new entry, if invalid will warn the user. + :return: None + """ + restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", + registration.get_o3de_restricted_folder().as_posix()) + if restricted_folder: + if registration.register(restricted_path=restricted_folder) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Added Restricted {restricted_folder}.") + msg_box.exec() + return - def browse_projects_handler(self): + def remove_project_handler(self): """ - Open a file search dialog looking for a folder which contains a valid project marker. If valid + Open a file search dialog looking for a folder which contains a valid project. If valid will update the mru list with the new entry, if invalid will warn the user. :return: None """ - project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", engine_path) + project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", + registration.get_o3de_projects_folder().as_posix()) if project_folder: - self.add_new_project(project_folder) + if registration.register(project_path=project_folder, remove=True) == 0: + # Success + self.refresh_project_list() + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Removed Project {project_folder}.") + msg_box.exec() return - def get_selected_project_gems(self) -> list: + def remove_gem_handler(self): """ - :return: List of (GemName, GemPath) of currently selected gems in the project gems list + Open a file search dialog looking for a folder which contains a gem. If valid + will update the mru list with the new entry, if invalid will warn the user. + :return: None """ - selected_items = self.project_gems.selectionModel().selectedRows() - return [self.project_gems.model().data(item) for item in selected_items] + gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", + registration.get_o3de_gems_folder().as_posix()) + if gem_folder: + if registration.register(gem_path=gem_folder, remove=True) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Removed Gem {gem_folder}.") + msg_box.exec() + return - def remove_gems_handler(self): + def remove_template_handler(self): """ - Finds the currently selected gems in the active gems list and attempts to remove each and updates the UI. + Open a file search dialog looking for a folder which contains a valid template. If valid + will update the mru list with the new entry, if invalid will warn the user. :return: None """ - remove_gems = self.get_selected_project_gems() + template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", + registration.get_o3de_templates_folder().as_posix()) + if template_folder: + if registration.register(template_path=template_folder, remove=True) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Removed Template {template_folder}.") + msg_box.exec() + return - for this_gem in remove_gems: - gem_path = self.path_for_gem(this_gem) - add_remove_gem.add_remove_gem(add=False, - dev_root=engine_path, - gem_path=gem_path or os.path.join(engine_path, 'Gems', this_gem), - gem_target=this_gem, - project_path=self.path_for_selection(), - dependencies_file=None, - runtime_dependency=True, - tool_dependency=True, - server_dependency=True) - self.update_gems() + def remove_restricted_handler(self): + """ + Open a file search dialog looking for a folder which contains a valid template. If valid + will update the mru list with the new entry, if invalid will warn the user. + :return: None + """ + restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", + registration.get_o3de_restricted_folder().as_posix()) + if restricted_folder: + if registration.register(restricted_path=restricted_folder, remove=True) == 0: + # Success + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText(f"Removed Restricted {restricted_folder}.") + msg_box.exec() + return - def manage_gems_handler(self): + def manage_runtime_project_gem_targets_handler(self): """ Opens the Gem management pane. Waits for the load thread to complete if still running and displays all active gems for the current project as well as all available gems which aren't currently active. :return: None """ - if not self.path_for_selection(): + if not self.get_selected_project_path(): msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") msg_box.setText("Please select a project") msg_box.exec() return - self.load_thread.join() loader = QUiLoader() - self.manage_gems_file = QFile(self.my_ui_manage_gems_path) + self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix()) - if not self.manage_gems_file: - logger.error(f'Failed to load gems UI file at {self.manage_gems_file}') + if not self.manage_project_gem_targets_file: + logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}') return - self.manage_gems_dialog = loader.load(self.manage_gems_file) + self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file) - if not self.manage_gems_dialog: - logger.error(f'Failed to load gems dialog file at {self.manage_gems_file}') + if not self.manage_project_gem_targets_dialog: + logger.error(f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}') return - self.manage_gems_dialog.setWindowTitle(f"Manage Gems for {self.get_selected_project_name()}") - - self.add_gems_button = self.manage_gems_dialog.findChild(QPushButton, 'addGemsButton') - self.add_gems_button.clicked.connect(self.add_gems_handler) + self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Runtime Gem Targets for Project:" + f" {self.get_selected_project_name()}") - self.add_gems_list = self.manage_gems_dialog.findChild(QListView, 'addGemsList') + self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton') + self.add_gem_button.clicked.connect(self.add_runtime_project_gem_targets_handler) - self.remove_gems_button = self.manage_gems_dialog.findChild(QPushButton, 'removeGemsButton') - self.remove_gems_button.clicked.connect(self.remove_gems_handler) + self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'availableGemTargetsList') + self.refresh_runtime_project_gem_targets_available_list() - self.project_gems = self.manage_gems_dialog.findChild(QListView, 'projectGems') - self.update_gems() + self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, + 'removeGemTargetsButton') + self.remove_project_gem_targets_button.clicked.connect(self.remove_runtime_project_gem_targets_handler) - self.manage_gems_dialog.exec() + self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'enabledGemTargetsList') + self.refresh_runtime_project_gem_targets_enabled_list() - def get_selected_add_gems(self) -> list: - """ - Find returns a list of currently selected gems in the add listas (GemName, GemPath) - :return: - """ - selected_items = self.add_gems_list.selectionModel().selectedRows() - return [(self.add_gems_list.model().data(item), self.add_gems_list.model().data(item, Qt.UserRole)) for - item in selected_items] + self.manage_project_gem_targets_dialog.exec() - def add_gems_handler(self) -> None: + def manage_tool_project_gem_targets_handler(self): """ - Searches the available gems list for selected gems and attempts to add each one to the current project. - Updates UI after completion. + Opens the Gem management pane. Waits for the load thread to complete if still running and displays all + active gems for the current project as well as all available gems which aren't currently active. :return: None """ - add_gems_list = self.get_selected_add_gems() - for this_gem in add_gems_list: - gem_info = self.get_gem_info_by_path(this_gem[1]) - if not gem_info: - logger.error(f'Unknown gem {this_gem}!') - continue - add_remove_gem.add_remove_gem(add=True, - dev_root=engine_path, - gem_path=this_gem[1], - gem_target=gem_info.get('Name'), - project_path=self.path_for_selection(), - dependencies_file=None, - runtime_dependency=gem_info.get('Runtime', False), - tool_dependency=gem_info.get('Tools', False), - server_dependency=gem_info.get('Tools', False)) - self.update_gems() - def create_project_handler(self): - """ - Opens the Create Project pane. Retrieves a list of available templates for display - :return: None - """ + if not self.get_selected_project_path(): + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText("Please select a project") + msg_box.exec() + return + loader = QUiLoader() - self.create_project_file = QFile(self.my_ui_create_project_path) + self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix()) - if not self.create_project_file: - logger.error(f'Failed to create project UI file at {self.create_project_file}') + if not self.manage_project_gem_targets_file: + logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}') return - self.create_project_dialog = loader.load(self.create_project_file) + self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file) - if not self.create_project_dialog: - logger.error(f'Failed to load create project dialog file at {self.create_project_file}') + if not self.manage_project_gem_targets_dialog: + logger.error( + f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}') return - self.create_project_ok_button = self.create_project_dialog.findChild(QDialogButtonBox, 'okCancel') - self.create_project_ok_button.accepted.connect(self.create_project_accepted_handler) + self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Tool Gem Targets for Project:" + f" {self.get_selected_project_name()}") - self.project_template_list = self.create_project_dialog.findChild(QListView, 'projectTemplates') + self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton') + self.add_gem_button.clicked.connect(self.add_tool_project_gem_targets_handler) - self.load_template_list() + self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'availableGemTargetsList') + self.refresh_tool_project_gem_targets_available_list() - self.load_template_model = QStandardItemModel() - for item in self.project_templates: - model_item = QStandardItem(item[0]) - model_item.setData(item[1], Qt.UserRole) - self.load_template_model.appendRow(model_item) + self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, + 'removeGemTargetsButton') + self.remove_project_gem_targets_button.clicked.connect(self.remove_tool_project_gem_targets_handler) - self.project_template_list.setModel(self.load_template_model) + self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'enabledGemTargetsList') + self.refresh_tool_project_gem_targets_enabled_list() - self.create_project_dialog.exec() + self.manage_project_gem_targets_dialog.exec() - def get_selected_project_template(self) -> tuple: + def manage_server_project_gem_targets_handler(self): """ - Get the current pair templatename, path to template selecte dby the user - :return: pair + Opens the Gem management pane. Waits for the load thread to complete if still running and displays all + active gems for the current project as well as all available gems which aren't currently active. + :return: None """ - selected_item = self.project_template_list.selectionModel().currentIndex() - if not selected_item.isValid(): - logger.warning("Select a template to create from") - return None + if not self.get_selected_project_path(): + msg_box = QMessageBox(parent=self.dialog) + msg_box.setWindowTitle("O3DE") + msg_box.setText("Please select a project") + msg_box.exec() + return - create_project_item = (self.project_template_list.model().data(selected_item), - self.project_template_list.model().data(selected_item, Qt.UserRole)) - return create_project_item + loader = QUiLoader() + self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix()) - def create_project_accepted_handler(self) -> None: - """ - Searches the available gems list for selected gems and attempts to add each one to the current project. - Updates UI after completion. - :return: None - """ - create_project_item = self.get_selected_project_template() - if not create_project_item: + if not self.manage_project_gem_targets_file: + logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}') return - folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", engine_path) - folder_dialog.setFileMode(QFileDialog.AnyFile) - folder_dialog.setOptions(QFileDialog.ShowDirsOnly) - project_count = 0 - project_name = "MyNewProject" - while os.path.exists(os.path.join(engine_path, project_name)): - project_name = f"MyNewProject{project_count}" - project_count += 1 - folder_dialog.selectFile(project_name) - project_folder = None - if folder_dialog.exec(): - project_folder = folder_dialog.selectedFiles() - if project_folder: - if engine_template.create_project(engine_path, project_folder[0], create_project_item[1]) == 0: - # Success - self.add_new_project(project_folder[0], validate=False) - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Project {os.path.basename(os.path.normpath(project_folder[0]))} created." - " Build your\nnew project before hitting OK to launch.") - msg_box.exec() - return + self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file) - def get_display_name(self, project_path: str) -> str: - """ - Returns the project path in the format to be displayed in the projects MRU list - :param project_path: Path to the project folder - :return: Formatted path - """ - return f'{os.path.basename(os.path.normpath(project_path))} ({project_path})' + if not self.manage_project_gem_targets_dialog: + logger.error( + f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}') + return - def add_projects(self, new_list: List[str]) -> None: - """ - Attempt to add a list of known projects. Performs validation first that the supplied folder appears valid and - silently drops invalid folders - these can simply be folders which were previously valid and are in the MRU list - but have been moved or deleted. Used both when loading the MRU list or when a user browses or creates a new - project - :param new_list: List of full paths to projects to add - :return: None - """ - new_display_items = [] - new_display_paths = [] - for this_item in new_list: - if self.is_project_folder(this_item) and this_item not in self.displayed_projects: - self.displayed_projects.append(this_item) - new_display_items.append(self.get_display_name(this_item)) - new_display_paths.append(this_item) - # Storing the full path in the tooltip, if this is altered we need to store this elsewhere - # as it's used when selecting a project to open - - for this_slot in range(len(new_display_items)): - self.project_list_box.addItem(new_display_items[this_slot]) - self.project_list_box.setItemData(self.project_list_box.count() - 1, new_display_paths[this_slot], - Qt.ToolTipRole) + self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Server Gem Targets for Project:" + f" {self.get_selected_project_name()}") + + self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton') + self.add_gem_button.clicked.connect(self.add_server_project_gem_targets_handler) + + self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'availableGemTargetsList') + self.refresh_server_project_gem_targets_available_list() + + self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, + 'removeGemTargetsButton') + self.remove_project_gem_targets_button.clicked.connect(self.remove_server_project_gem_targets_handler) + + self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, + 'enabledGemTargetsList') + self.refresh_server_project_gem_targets_enabled_list() + + self.manage_project_gem_targets_dialog.exec() + + def manage_project_gem_targets_get_selected_available_gems(self) -> list: + selected_items = self.available_gem_targets_list.selectionModel().selectedRows() + return [(self.available_gem_targets_list.model().data(item)) for item in selected_items] + + def manage_project_gem_targets_get_selected_enabled_gems(self) -> list: + selected_items = self.enabled_gem_targets_list.selectionModel().selectedRows() + return [(self.enabled_gem_targets_list.model().data(item)) for item in selected_items] + + def add_runtime_project_gem_targets_handler(self) -> None: + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.add_gem_to_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + runtime_dependency=True) + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + return + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + + def remove_runtime_project_gem_targets_handler(self): + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.remove_gem_from_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + runtime_dependency=True) + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + return + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + + def add_tool_project_gem_targets_handler(self) -> None: + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.add_gem_to_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + tool_dependency=True) + self.refresh_tool_project_gem_targets_available_list() + self.refresh_tool_project_gem_targets_enabled_list() + return + self.refresh_tool_project_gem_targets_available_list() + self.refresh_tool_project_gem_targets_enabled_list() + + def remove_tool_project_gem_targets_handler(self): + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.remove_gem_from_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + tool_dependency=True) + self.refresh_tool_project_gem_targets_available_list() + self.refresh_tool_project_gem_targets_enabled_list() + return + self.refresh_tool_project_gem_targets_available_list() + self.refresh_tool_project_gem_targets_enabled_list() + + def add_server_project_gem_targets_handler(self) -> None: + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.add_gem_to_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + server_dependency=True) + self.refresh_server_project_gem_targets_available_list() + self.refresh_server_project_gem_targets_enabled_list() + return + self.refresh_server_project_gem_targets_available_list() + self.refresh_server_project_gem_targets_enabled_list() + + def remove_server_project_gem_targets_handler(self): + gem_paths = registration.get_all_gems() + for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): + for gem_path in gem_paths: + this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + for this_gem_target in this_gems_targets: + if gem_target == this_gem_target: + registration.remove_gem_from_project(gem_path=gem_path, + gem_target=gem_target, + project_path=self.get_selected_project_path(), + server_dependency=True) + self.refresh_server_project_gem_targets_available_list() + self.refresh_server_project_gem_targets_enabled_list() + return + self.refresh_server_project_gem_targets_available_list() + self.refresh_server_project_gem_targets_enabled_list() + + def refresh_runtime_project_gem_targets_enabled_list(self) -> None: + enabled_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_runtime_gem_targets( + project_path=self.get_selected_project_path()) + for gem_target in sorted(enabled_project_gem_targets): + model_item = QStandardItem(gem_target) + enabled_project_gem_targets_model.appendRow(model_item) + self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model) + + def refresh_runtime_project_gem_targets_available_list(self) -> None: + available_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_runtime_gem_targets( + project_path=self.get_selected_project_path()) + all_gem_targets = registration.get_all_gem_targets() + for gem_target in sorted(all_gem_targets): + if gem_target not in enabled_project_gem_targets: + model_item = QStandardItem(gem_target) + available_project_gem_targets_model.appendRow(model_item) + self.available_gem_targets_list.setModel(available_project_gem_targets_model) + + def refresh_tool_project_gem_targets_enabled_list(self) -> None: + enabled_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_tool_gem_targets( + project_path=self.get_selected_project_path()) + for gem_target in sorted(enabled_project_gem_targets): + model_item = QStandardItem(gem_target) + enabled_project_gem_targets_model.appendRow(model_item) + self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model) + + def refresh_tool_project_gem_targets_available_list(self) -> None: + available_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_tool_gem_targets( + project_path=self.get_selected_project_path()) + all_gem_targets = registration.get_all_gem_targets() + for gem_target in sorted(all_gem_targets): + if gem_target not in enabled_project_gem_targets: + model_item = QStandardItem(gem_target) + available_project_gem_targets_model.appendRow(model_item) + self.available_gem_targets_list.setModel(available_project_gem_targets_model) + + def refresh_server_project_gem_targets_enabled_list(self) -> None: + enabled_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_server_gem_targets( + project_path=self.get_selected_project_path()) + for gem_target in sorted(enabled_project_gem_targets): + model_item = QStandardItem(gem_target) + enabled_project_gem_targets_model.appendRow(model_item) + self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model) + + def refresh_server_project_gem_targets_available_list(self) -> None: + available_project_gem_targets_model = QStandardItemModel() + enabled_project_gem_targets = registration.get_project_server_gem_targets( + project_path=self.get_selected_project_path()) + all_gem_targets = registration.get_all_gem_targets() + for gem_target in sorted(all_gem_targets): + if gem_target not in enabled_project_gem_targets: + model_item = QStandardItem(gem_target) + available_project_gem_targets_model.appendRow(model_item) + self.available_gem_targets_list.setModel(available_project_gem_targets_model) + + def refresh_create_project_template_list(self) -> None: + self.create_project_template_model = QStandardItemModel() + for project_template_path in registration.get_project_templates(): + model_item = QStandardItem(project_template_path) + self.create_project_template_model.appendRow(model_item) + self.create_project_template_list.setModel(self.create_project_template_model) + + def refresh_create_gem_template_list(self) -> None: + self.create_gem_template_model = QStandardItemModel() + for gem_template_path in registration.get_gem_templates(): + model_item = QStandardItem(gem_template_path) + self.create_gem_template_model.appendRow(model_item) + self.create_gem_template_list.setModel(self.create_gem_template_model) + + def refresh_create_from_template_list(self) -> None: + self.create_from_template_model = QStandardItemModel() + for generic_template_path in registration.get_generic_templates(): + model_item = QStandardItem(generic_template_path) + self.create_from_template_model.appendRow(model_item) + self.create_from_template_list.setModel(self.create_from_template_model) def update_mru_list(self, used_project: str) -> None: """ @@ -621,7 +985,7 @@ class ProjectDialog(QObject): def get_mru_list(self) -> List[str]: """ - Retrive the current MRU list. Does not perform validation that the projects still appear valid + Retrieve the current MRU list. Does not perform validation that the projects still appear valid :return: list of full path strings to project folders """ if not os.path.exists(os.path.dirname(self.mru_file_path)): @@ -653,6 +1017,6 @@ class ProjectDialog(QObject): if __name__ == "__main__": dialog_app = QApplication(sys.argv) - my_dialog = ProjectDialog() + my_dialog = ProjectManagerDialog() dialog_app.exec_() sys.exit(0) diff --git a/scripts/project_manager/tests/test_projects.py b/scripts/project_manager/tests/test_projects.py index 69895accfd..d073cf6c7a 100755 --- a/scripts/project_manager/tests/test_projects.py +++ b/scripts/project_manager/tests/test_projects.py @@ -9,54 +9,67 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # + import pytest +''' import os import sys import tempfile import logging +import pathlib from unittest.mock import MagicMock logger = logging.getLogger() # Code lives one folder above -projects_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) -sys.path.append(projects_path) +project_manager_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.append(project_manager_path) from pyside import add_pyside_environment, is_configuration_valid from ly_test_tools import WINDOWS -project_marker_file = "project.json" +sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))) +executable_path = '' +from cmake.Tools import registration +from cmake.Tools import engine_template + class ProjectHelper: def __init__(self): - self._temp_directory = tempfile.TemporaryDirectory() - self.temp_project_root = self._temp_directory.name - self.temp_file_dir = os.path.join(self.temp_project_root, "o3de") + self._temp_directory = pathlib.Path(tempfile.TemporaryDirectory().name).resolve() + self._temp_directory.mkdir(parents=True, exist_ok=True) + + self.home_path = self._temp_directory + registration.override_home_folder = self.home_path + self.engine_path = registration.get_this_engine_path() + if registration.register(engine_path=self.engine_path): + assert True, f"Failed to register the engine." + + if registration.register_shipped_engine_o3de_objects(): + assert True, f"Failed to register shipped engine objects." + + self.projects_folder = registration.get_o3de_projects_folder() + if not self.projects_folder.is_dir(): + assert True self.application = None self.dialog = None - if not os.path.exists(self.temp_file_dir): - os.makedirs(self.temp_file_dir) - def create_empty_projects(self): - self.project_1_dir = os.path.join(self.temp_project_root, "Project1") - if not os.path.exists(self.project_1_dir): - os.makedirs(self.project_1_dir) - with open(os.path.join(self.project_1_dir,project_marker_file), 'w') as marker_file: - marker_file.write("{}") - self.project_2_dir = os.path.join(self.temp_project_root, "Project2") - if not os.path.exists(self.project_2_dir): - os.makedirs(self.project_2_dir) - with open(os.path.join(self.project_2_dir, project_marker_file), 'w') as marker_file: - marker_file.write("{}") - self.project_3_dir = os.path.join(self.temp_project_root, "Project3") - if not os.path.exists(self.project_3_dir): - os.makedirs(self.project_3_dir) - with open(os.path.join(self.project_3_dir, project_marker_file), 'w') as marker_file: - marker_file.write("{}") - self.invalid_project_dir = os.path.join(self.temp_project_root, "InvalidProject") + self.project_1_dir = self.projects_folder / "Project1" + if engine_template.create_project(project_manager_path=self.project_1_dir): + assert True, f"Failed to create Project1." + + self.project_2_dir = self.projects_folder / "Project2" + if engine_template.create_project(project_manager_path=self.project_2_dir): + assert True, f"Failed to create Project2." + + self.project_3_dir = self.projects_folder / "Project3" + if engine_template.create_project(project_manager_path=self.project_3_dir): + assert True, f"Failed to create Project3." + self.invalid_project_dir = self.projects_folder / "InvalidProject" + self.invalid_project_dir.mkdir(parents=True, exist_ok=True) def setup_dialog_test(self, workspace): add_pyside_environment(workspace.paths.build_directory()) @@ -66,6 +79,7 @@ class ProjectHelper: # need to use the profile version of PySide which works with the profile QT libs which aren't in the debug # folder we've built. return None + from PySide2.QtWidgets import QApplication, QMessageBox if QApplication.instance(): @@ -74,13 +88,13 @@ class ProjectHelper: self.application = QApplication(sys.argv) assert self.application - from projects import ProjectDialog + from projects import ProjectManagerDialog try: - self.dialog = ProjectDialog(settings_folder=self.temp_file_dir) + self.dialog = ProjectManagerDialog(settings_folder=self.home_path) return self.dialog except Exception as e: - logger.error(f'Failed to create ProjectDialog with error {e}') + logger.error(f'Failed to create ProjectManagerDialog with error {e}') return None def create_project_from_template(self, project_name) -> bool: @@ -90,21 +104,24 @@ class ProjectHelper: :return: True for Success, False for failure """ from PySide2.QtWidgets import QWidget, QFileDialog - from projects import ProjectDialog + from projects import ProjectManagerDialog QWidget.exec = MagicMock() self.dialog.create_project_handler() QWidget.exec.assert_called_once() assert len(self.dialog.project_templates), 'Failed to find any project templates' - ProjectDialog.get_selected_project_template = MagicMock(return_value=self.dialog.project_templates[0]) + ProjectManagerDialog.get_selected_project_template = MagicMock(return_value=self.dialog.project_templates[0]) QFileDialog.exec = MagicMock() - create_project_dir = os.path.join(self.temp_project_root, project_name) - QFileDialog.selectedFiles = MagicMock(return_value=[create_project_dir]) + create_project_path = self.projects_folder / project_name + QFileDialog.selectedFiles = MagicMock(return_value=[create_project_path]) self.dialog.create_project_accepted_handler() - assert os.path.isdir(create_project_dir), f"Expected project folder not found at {create_project_dir}" - assert QWidget.exec.call_count == 2, "Message box confirming project creation failed to show" + if create_project_path.is_dir(): + assert True, f"Expected project creation folder not found at {create_project_path}" + + if QWidget.exec.call_count == 2: + assert True, "Message box confirming project creation failed to show" @pytest.fixture @@ -113,7 +130,7 @@ def project_helper(): @pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent +@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent def test_logger_handler(workspace, project_helper): my_dialog = project_helper.setup_dialog_test(workspace) if not my_dialog: @@ -126,7 +143,7 @@ def test_logger_handler(workspace, project_helper): @pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent +@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent def test_mru_list(workspace, project_helper): my_dialog = project_helper.setup_dialog_test(workspace) if not my_dialog: @@ -140,16 +157,16 @@ def test_mru_list(workspace, project_helper): assert len(mru_list) == 0, f'MRU list unexpectedly had entries: {mru_list}' QMessageBox.warning = MagicMock() - my_dialog.add_new_project('TestProjectInvalid') + my_dialog.add_project(project_helper.invalid_project_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 0, f'MRU list unexpectedly added an invalid project : {mru_list}' QMessageBox.warning.assert_called_once() - my_dialog.add_new_project(project_helper.project_1_dir) + my_dialog.add_project(project_helper.project_1_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 1, f'MRU list failed to add project at {project_helper.project_1_dir}' - my_dialog.add_new_project(project_helper.project_1_dir) + my_dialog.add_project(project_helper.project_1_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}' @@ -157,7 +174,7 @@ def test_mru_list(workspace, project_helper): mru_list = my_dialog.get_mru_list() assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}' - my_dialog.add_new_project(project_helper.project_2_dir) + my_dialog.add_project(project_helper.project_2_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 2, f'MRU list failed to add project at {project_helper.project_2_dir}' @@ -170,13 +187,13 @@ def test_mru_list(workspace, project_helper): assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item" assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item" - my_dialog.add_new_project(project_helper.invalid_project_dir) + my_dialog.add_project(project_helper.invalid_project_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 2, f'MRU list added invalid item {mru_list}' assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item" assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item" - my_dialog.add_new_project(project_helper.project_3_dir) + my_dialog.add_project(project_helper.project_3_dir) mru_list = my_dialog.get_mru_list() assert len(mru_list) == 3, f'MRU list failed to add {project_helper.project_3_dir} : {mru_list}' assert mru_list[0] == project_helper.project_3_dir, f"{project_helper.project_3_dir} wasn't first item" @@ -185,7 +202,7 @@ def test_mru_list(workspace, project_helper): @pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent +@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent def test_create_project(workspace, project_helper): my_dialog = project_helper.setup_dialog_test(workspace) if not my_dialog: @@ -195,7 +212,7 @@ def test_create_project(workspace, project_helper): @pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent +@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent def test_add_remove_gems(workspace, project_helper): my_dialog = project_helper.setup_dialog_test(workspace) if not my_dialog: @@ -203,32 +220,36 @@ def test_add_remove_gems(workspace, project_helper): my_project_name = "TestAddRemoveGems" - project_helper.create_project_from_template(my_project_name) - my_project_path = os.path.join(project_helper.temp_project_root, my_project_name) + project_helper.create_project_from_template(project_manager_path=my_project_name) + my_project_path = project_helper.projects_folder / my_project_name from PySide2.QtWidgets import QWidget, QFileDialog - from projects import ProjectDialog + from projects import ProjectManagerDialog - assert my_dialog.path_for_selection() == my_project_path, "Gems project not selected" + assert my_dialog.get_selected_project_path() == my_project_path, "TestAddRemoveGems project not selected" QWidget.exec = MagicMock() my_dialog.manage_gems_handler() - assert my_dialog.manage_gems_dialog, "No gem management dialog created" + assert my_dialog.manage_gem_targets_dialog, "No gem management dialog created" QWidget.exec.assert_called_once() - assert len(my_dialog.gems_list), 'Failed to find any gems' - my_test_gem = my_dialog.gems_list[0] - my_test_gem_name = my_test_gem.get("Name") - my_test_gem_path = my_test_gem.get("Path") - my_test_gem_selection = (my_test_gem_name, my_test_gem_path) - ProjectDialog.get_selected_add_gems = MagicMock(return_value=[my_test_gem_selection]) + if not len(my_dialog.all_gems_list): + assert True, 'Failed to find any gems' + my_test_gem_path = my_dialog.all_gems_list[0] + gem_data = registration.get_gem_data(my_test_gem_path) + my_test_gem_selection = (my_test_gem_name, my_test_gem_path) + ProjectManagerDialog.get_selected_add_gems = MagicMock(return_value=[my_test_gem_selection]) assert my_test_gem_name, "No Name set in test gem" assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} already in project gem list' + my_dialog.add_gems_handler() assert my_test_gem_name in my_dialog.project_gem_list, f'Gem {my_test_gem_name} failed to add to gem list' - ProjectDialog.get_selected_project_gems = MagicMock(return_value=[my_test_gem_name]) + + ProjectManagerDialog.get_selected_project_gems = MagicMock(return_value=[my_test_gem_name]) my_dialog.remove_gems_handler() assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} still in project gem list' +''' - +def test_project_place_holder(): + pass \ No newline at end of file diff --git a/scripts/project_manager/ui/create_from_template.ui b/scripts/project_manager/ui/create_from_template.ui new file mode 100644 index 0000000000..b6a8740594 --- /dev/null +++ b/scripts/project_manager/ui/create_from_template.ui @@ -0,0 +1,94 @@ + + + createFromTemplateDialog + + + + 0 + 0 + 467 + 288 + + + + Create From Template + + + + + 50 + 250 + 400 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 20 + 449 + 221 + + + + QAbstractItemView::SingleSelection + + + + + + 10 + 0 + 300 + 16 + + + + Available Templates + + + + + + + okCancel + accepted() + createFromTemplateDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + okCancel + rejected() + createFromTemplateDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/scripts/project_manager/ui/create_gem.ui b/scripts/project_manager/ui/create_gem.ui new file mode 100644 index 0000000000..5a5fd14a6d --- /dev/null +++ b/scripts/project_manager/ui/create_gem.ui @@ -0,0 +1,94 @@ + + + createGemDialog + + + + 0 + 0 + 467 + 288 + + + + Create Gem + + + + + 50 + 250 + 400 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 20 + 449 + 221 + + + + QAbstractItemView::SingleSelection + + + + + + 10 + 0 + 300 + 16 + + + + Available Templates + + + + + + + okCancel + accepted() + createGemDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + okCancel + rejected() + createGemDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/scripts/project_manager/ui/create_project.ui b/scripts/project_manager/ui/create_project.ui index b4c8fb5caa..67a13325b0 100644 --- a/scripts/project_manager/ui/create_project.ui +++ b/scripts/project_manager/ui/create_project.ui @@ -6,7 +6,7 @@ 0 0 - 226 + 467 288 @@ -18,7 +18,7 @@ 50 250 - 171 + 400 32 @@ -34,7 +34,7 @@ 10 20 - 211 + 449 221 @@ -47,7 +47,7 @@ 10 0 - 101 + 300 16 diff --git a/scripts/project_manager/ui/manage_gems.ui b/scripts/project_manager/ui/manage_gem_targets.ui similarity index 74% rename from scripts/project_manager/ui/manage_gems.ui rename to scripts/project_manager/ui/manage_gem_targets.ui index 36083bd9df..ea9e607d42 100644 --- a/scripts/project_manager/ui/manage_gems.ui +++ b/scripts/project_manager/ui/manage_gem_targets.ui @@ -1,24 +1,24 @@ - addGemsDialog - + manageGemTargetsDialog + 0 0 - 635 - 327 + 702 + 297 - Manage Gems + Manage Gem Targets - 460 - 290 - 171 + 310 + 260 + 71 32 @@ -29,10 +29,10 @@ QDialogButtonBox::Close - + - 380 + 440 50 250 221 @@ -48,7 +48,7 @@ QAbstractItemView::ExtendedSelection - + 10 @@ -64,14 +64,14 @@ - 380 + 440 30 - 91 + 251 16 - Available Gems + Available Gem Targets @@ -79,38 +79,38 @@ 10 30 - 71 + 251 16 - Enabled Gems + Enabled Gem Targets - + - 267 + 264 130 - 105 + 171 23 - Remove Gems >> + Remove Gem Targets >> - + - 267 + 264 100 - 105 + 171 23 - << Add Gems + << Add Gem Targets @@ -118,12 +118,12 @@ 10 5 - 241 - 16 + 400 + 21 - Adding new Gems may require rebuilding + Adding new Gem Targets may require rebuilding @@ -132,7 +132,7 @@ close accepted() - addGemsDialog + manageGemTargetsDialog accept() @@ -148,7 +148,7 @@ close rejected() - addGemsDialog + manageGemTargetsDialog reject() diff --git a/scripts/project_manager/ui/projects.ico b/scripts/project_manager/ui/project_manager.ico similarity index 100% rename from scripts/project_manager/ui/projects.ico rename to scripts/project_manager/ui/project_manager.ico diff --git a/scripts/project_manager/ui/project_manager.ui b/scripts/project_manager/ui/project_manager.ui new file mode 100644 index 0000000000..6b3b5f758c --- /dev/null +++ b/scripts/project_manager/ui/project_manager.ui @@ -0,0 +1,407 @@ + + + Dialog + + + + 0 + 0 + 712 + 395 + + + + + 1 + 0 + + + + O3DE + + + Select and manage your projects for O3DE + + + + + 540 + 360 + 161 + 31 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 30 + 691 + 31 + + + + Current project to launch or manage gems for. + + + + + + 10 + 10 + 47 + 13 + + + + Project + + + + + + 270 + 220 + 431 + 141 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 10 + 70 + 241 + 151 + + + + Create + + + + + 10 + 110 + 221 + 31 + + + + Create a new O3DE object from a pre configured template. + + + Create From Template + + + + + + 10 + 20 + 221 + 31 + + + + Create a new O3DE object from a pre configured template. + + + Create Project + + + + + + 11 + 50 + 221 + 31 + + + + Create a new O3DE object from a pre configured template. + + + Create Gem + + + + + + 11 + 80 + 221 + 31 + + + + Create a new O3DE object from a pre configured template. + + + Create Template + + + + + + + 260 + 70 + 451 + 141 + + + + Registration + + + + + 10 + 80 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Add Template + + + + + + 10 + 20 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Add Project + + + + + + 10 + 50 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Add Gem + + + + + + 10 + 110 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Add Restricted + + + + + + 230 + 110 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Remove Restricted + + + + + + 230 + 20 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Remove Project + + + + + + 230 + 50 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Remove Gem + + + + + + 230 + 80 + 211 + 31 + + + + Browse for an existing O3DE project. + + + Remove Template + + + + + + + 10 + 230 + 241 + 121 + + + + Manage Project + + + + + 10 + 80 + 221 + 31 + + + + Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. + + + Manage Server Gem Targets + + + + + + 10 + 50 + 221 + 31 + + + + Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. + + + Manage Tool Gem Targets + + + + + + 10 + 20 + 221 + 31 + + + + Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. + + + Manage Runtime Gem Targets + + + + + + + + okCancel + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + okCancel + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/scripts/project_manager/ui/projects.ui b/scripts/project_manager/ui/projects.ui deleted file mode 100644 index 4445029dda..0000000000 --- a/scripts/project_manager/ui/projects.ui +++ /dev/null @@ -1,167 +0,0 @@ - - - Dialog - - - - 0 - 0 - 464 - 136 - - - - - 1 - 0 - - - - O3DE - - - Select and manage your projects for O3DE - - - - - 290 - 100 - 171 - 31 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 30 - 451 - 31 - - - - Current project to launch or manage gems for. - - - - - - 10 - 70 - 91 - 23 - - - - Create a new O3DE project from a pre configured template. - - - Create New - - - - - - 10 - 10 - 47 - 13 - - - - Project - - - - - - 110 - 70 - 91 - 23 - - - - Browse for an existing O3DE project. - - - Browse - - - - - - 350 - 70 - 91 - 23 - - - - Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. - - - Manage Gems - - - - - - 5 - 110 - 275 - 16 - - - - - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - okCancel - accepted() - Dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - okCancel - rejected() - Dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - -