Ver código fonte

Whitebox Gem now compiles OpenMesh directly instead of using 3p packages (#18729)

* Whitebox Gem now compiles OpenMesh directly instead of 3p
Using a new FindPackage way of doing things that cleans it up
* Fixes script-only-mode for 3rd party library OpenMesh
* Fixes the unit tests for OpenMesh11.0
---------

Signed-off-by: Nicholas Lawson <[email protected]>
Nicholas Lawson 4 meses atrás
pai
commit
2692d5d0fc
25 arquivos alterados com 649 adições e 181 exclusões
  1. 123 0
      Gems/WhiteBox/3rdParty/FindOpenMesh.cmake
  2. 35 0
      Gems/WhiteBox/3rdParty/Installer/FindOpenMesh.cmake
  3. 209 0
      Gems/WhiteBox/3rdParty/openmesh-o3de-11.0.patch
  4. 3 1
      Gems/WhiteBox/CMakeLists.txt
  5. 15 53
      Gems/WhiteBox/Code/CMakeLists.txt
  6. 8 3
      Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp
  7. 0 7
      Gems/WhiteBox/Code/Source/Platform/Common/Clang/whitebox_editor_clang.cmake
  8. 0 12
      Gems/WhiteBox/Code/Source/Platform/Common/GCC/whitebox_editor_gcc.cmake
  9. 0 7
      Gems/WhiteBox/Code/Source/Platform/Common/MSVC/whitebox_editor_msvc.cmake
  10. 0 22
      Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake
  11. 0 2
      Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake
  12. 0 16
      Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake
  13. 0 23
      Gems/WhiteBox/Code/Source/WhiteBoxModuleUnsupported.cpp
  14. 131 20
      Gems/WhiteBox/Code/Tests/WhiteBoxTest.cpp
  15. 0 11
      Gems/WhiteBox/Code/whitebox_unsupported_files.cmake
  16. 0 1
      cmake/3rdParty/Platform/Linux/BuiltInPackages_linux_aarch64.cmake
  17. 0 1
      cmake/3rdParty/Platform/Linux/BuiltInPackages_linux_x86_64.cmake
  18. 0 1
      cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake
  19. 0 1
      cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake
  20. 9 0
      cmake/Configurations.cmake
  21. 53 0
      cmake/PatchIfNotAlreadyPatched.cmake
  22. 15 0
      cmake/Platform/Common/Clang/Configurations_clang.cmake
  23. 15 0
      cmake/Platform/Common/GCC/Configurations_gcc.cmake
  24. 17 0
      cmake/Platform/Common/MSVC/Configurations_clang.cmake
  25. 16 0
      cmake/Platform/Common/MSVC/Configurations_msvc.cmake

+ 123 - 0
Gems/WhiteBox/3rdParty/FindOpenMesh.cmake

@@ -0,0 +1,123 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+# Always start by checking if the target already exists.
+# This prevents repeated calls but also allows the user to substitute their own 3rd party library
+# if they wish to do so.
+
+if (TARGET 3rdParty::OpenMesh)
+    return()
+endif()
+
+# Variables inside a local function are scoped to the function body.
+# Putting all of this inside a function lets us basically ensure that any variables set by the 
+# external 3rdParty CMake file do not have any effect on the outside world.
+# and allows us not to have to save and restore anything.
+
+function(GetOpenMesh)
+    # Part 1:  Where do you get the library from?  Make sure to inform the user of the source of the library and any patches applied.
+    include(FetchContent)
+
+    set(OPENMESH_GIT_REPO "https://gitlab.vci.rwth-aachen.de:9000/OpenMesh/OpenMesh.git")
+    set(OPENMESH_GIT_TAG "OpenMesh-11.0")
+    set(OPENMESH_GIT_PATCH "${CMAKE_CURRENT_LIST_DIR}/openmesh-o3de-11.0.patch")
+
+    FetchContent_Declare(
+            OpenMesh
+            GIT_REPOSITORY ${OPENMESH_GIT_REPO}
+            GIT_TAG ${OPENMESH_GIT_TAG}
+            PATCH_COMMAND cmake -P "${LY_ROOT_FOLDER}/cmake/PatchIfNotAlreadyPatched.cmake" ${OPENMESH_GIT_PATCH}
+    )
+
+    # please always be really clear about what third parties your gem uses.
+    message(STATUS "WhiteBox Gem uses ${OPENMESH_GIT_TAG} (BSD-3-Clause) ${OPENMESH_GIT_REPO}")
+    message(STATUS "      With patch: ${OPENMESH_GIT_PATCH}")
+
+    # Part 2: Set the build settings and trigger the actual execution of the downloaded CMakeLists.txt file
+
+    # Note that CMAKE_ARGS does NOT WORK for FetchContent_*, only ExternalProject.
+    # Thus, you must set any configuration settings here, in the scope in which you call FetchContent_MakeAvailable.
+
+    # These settings will be applied only to the current CMake scope - so it is only worth saving and restoring values from settings
+    # that may affect other targets in the same CMake scope, most likely anything "CMAKE_xxxxxxxx".
+    set(OLD_LOG_LEVEL ${CMAKE_MESSAGE_LOG_LEVEL}) # save the old CMAKE_MESSAGE_LOG_LEVEL
+    set(CMAKE_MESSAGE_LOG_LEVEL ERROR)   # You can comment this line out if you want to see what messages output from its CMakeLists.txt
+    set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
+
+    # The rest of these are all specific settings that come from OpenMesh's CMakeLists.txt files.
+    set(OPENMESH_BUILD_SHARED OFF)
+    set(OPENMESH_DISABLE_INSTALL ON)
+    set(OPENMESH_DOCS OFF)
+    set(OPENMESH_BUILD_UNIT_TESTS OFF)
+    set(DISABLE_QMAKE_BUILD ON)
+    set(BUILD_APPS OFF)
+    set(VCI_NO_LIBRARY_INSTALL ON)
+    set(VCI_COMMON_DO_NOT_COPY_POST_BUILD ON)
+
+    # the below line is what actualy runs its CMakeList.txt file and executes targets and so on:
+    FetchContent_MakeAvailable(OpenMesh)
+
+    set(CMAKE_MESSAGE_LOG_LEVEL ${OLD_LOG_LEVEL})
+    set(CMAKE_WARN_DEPRECATED ON CACHE BOOL "" FORCE)
+
+    # Part 3: alias any targets to 3rdParty::xxx, make sure any O3DE-specific fixups are done on the target compile options
+    # generated by the above FetchContent_MakeAvailable call.  Generally, disable things like warnings-as-errors since we 
+    # can't really guarantee that the 3rd party library will compile cleanly with our settings.
+    set(OPENMESH_TARGETS OpenMeshCore OpenMeshTools OpenMeshCoreStatic OpenMeshToolsStatic)
+    foreach(OpenMesh_Target ${OPENMESH_TARGETS})
+        # OpenMesh Specific: on non-Windows platforms, it creates both a shared and a static library, and assigns them targetname
+        # xxxxxxxx and xxxxxxxxStatic.  On Windows platforms, it only makes a static library, and it is called just the targetname
+        # without appending Static on it.  We need to handle both cases here, so we have a "IF (NOT TARGET)" check.
+        if (NOT TARGET ${OpenMesh_Target})
+            continue()
+        endif()
+        # customize the compile options for the target, note that these defines already contain the 
+        # appropriate level of visibility (PUBLIC / INTERFACE / PRIVATE) and may be blank for a given compiler.
+        target_compile_options(${OpenMesh_Target}  
+            ${O3DE_COMPILE_OPTION_DISABLE_WARNINGS}     # OpenMesh does not pass Warning Level 4
+            ${O3DE_COMPILE_OPTION_EXPORT_SYMBOLS}       # OpenMesh requires symbols to be exported.
+            ${O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS})   # OpenMesh requires Exceptions enabled in it, and things that use it
+                
+        # this block makes sure that in IDEs like Visual Studio, they show up in the "External" subfolder under the gem.
+        get_property(this_gem_root GLOBAL PROPERTY "@GEMROOT:${gem_name}@")
+        ly_get_engine_relative_source_dir(${this_gem_root} relative_this_gem_root)
+        set_property(TARGET ${OpenMesh_Target} PROPERTY FOLDER "${relative_this_gem_root}/External")
+    endforeach()
+
+    # OpenMesh Specific: If the xxxxxxxStatic library exists, prefer using them over the xxxxxxx (without Static) library.
+    set(OpenMesh_Primary_Target      OpenMeshCore)
+    set(OpenMeshTools_Primary_Target OpenMeshTools)
+    if (TARGET OpenMeshCoreStatic)
+        set(OpenMesh_Primary_Target OpenMeshCoreStatic)
+        set(OpenMeshTools_Primary_Target OpenMeshToolsStatic)
+    endif()
+
+    # ly_create_alias is a helper function that creates an alias target with the given name and namespace
+    # However, it creates both the 3rdParty::xxxxxx and the xxxxxxx target.  
+    # Most importantly, it registers the alias with the installer generator, which will try to recreate the
+    # alias and target automatically for us, in the installer, which we don't want to do, since we're providing our
+    # own FindOpenMesh.cmake for the installer to use.  So avoid using ly_create_alias when you have a custom find file.
+    add_library(3rdParty::OpenMesh ALIAS ${OpenMesh_Primary_Target})
+    add_library(3rdParty::OpenMeshTools ALIAS OpenMeshTools)
+
+    # Part 4: Make sure things work in the Installer version of O3DE. 
+    # To make it simple, we just have a premade FindOpenMesh.cmake for the installer specifically
+    # that we put in a folder (cmake/3rdParty) that is already part of the search path for find_package calls in installers.
+    ly_install(FILES ${CMAKE_CURRENT_LIST_DIR}/Installer/FindOpenMesh.cmake DESTINATION cmake/3rdParty)
+    ly_install(FILES ${CMAKE_CURRENT_LIST_DIR}/openmesh-o3de-11.0.patch DESTINATION cmake/3rdParty)
+    
+    # signal that find_package(OpenMesh) has succeeded.
+    # we have to set it on the PARENT_SCOPE since we're in a function 
+    set(OpenMesh_FOUND TRUE PARENT_SCOPE)
+
+endfunction()
+
+GetOpenMesh()
+
+# for extra safety, we'll remove the function from the global scope, so that it can't be called again.
+unset(GetOpenMesh)

+ 35 - 0
Gems/WhiteBox/3rdParty/Installer/FindOpenMesh.cmake

@@ -0,0 +1,35 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+if (TARGET 3rdParty::OpenMesh)
+    return()
+endif()
+
+# This file is used in the INSTALLER version of O3DE.  
+# This file is included in cmake/3rdParty, which is already part of the search path for Findxxxxx.cmake files.
+
+# The OpenMesh library is used privately inside the WhiteBox gem, so neither its headers nor its static library needs
+# to actually be distributed here.  It is not expected for people to link to it, but rather use it via the WhiteBox Gem's
+# public API.
+
+# It is still worth notifying people that they are accepting a 3rd Party Library here, and what license it uses, and
+# where to get it.
+message(STATUS "WhiteBox Gem uses OpenMesh-11.0 (BSD-3-Clause) from https://gitlab.vci.rwth-aachen.de:9000/OpenMesh/OpenMesh.git")
+message(STATUS "    - patched with ${CMAKE_CURRENT_LIST_DIR}/openmesh-o3de-11.0.patch")
+
+# By providing both an "OpenMesh" and a "3rdParty::OpenMesh target, we stop O3DE from doing anything automatically
+# itself, such as attempting to invoke some other install script or find script or complaining about a missing target.
+add_library(OpenMesh IMPORTED INTERFACE GLOBAL)
+add_library(3rdParty::OpenMesh ALIAS OpenMesh)
+
+# Same thing to future-proof 3rdParty::OpenMeshTools
+add_library(OpenMeshTools IMPORTED INTERFACE GLOBAL)
+add_library(3rdParty::OpenMeshTools ALIAS OpenMeshTools)
+
+# notify O3DE That we have satisfied the OpenMesh find_package requirements.
+set(OpenMesh_FOUND TRUE)

+ 209 - 0
Gems/WhiteBox/3rdParty/openmesh-o3de-11.0.patch

@@ -0,0 +1,209 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 3aa81220..e56ee41a 100755
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -17,7 +17,6 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17")
+     cmake_policy(SET CMP0100 NEW)
+ endif()
+ 
+-
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ 	if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.9" OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "4.9")
+ 		message(WARNING "Your version of GCC contains an optimizer bug. Please verify that you do not use -O3!")
+@@ -193,13 +192,12 @@ set(PRIVATE_LIBS "-lOpenMeshCore -lOpenMeshTools")
+ 
+ configure_file("openmesh.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/openmesh.pc" @ONLY)
+ 
+-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openmesh.pc DESTINATION libdata/pkgconfig)
+-
+-# generate target file
+-
+-install(EXPORT OpenMeshConfig DESTINATION share/OpenMesh/cmake)
+-
+-export(TARGETS OpenMeshCore OpenMeshTools FILE OpenMeshConfig.cmake)
++if (NOT OPENMESH_DISABLE_INSTALL)
++  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openmesh.pc DESTINATION libdata/pkgconfig)
++  # generate target file
++  install(EXPORT OpenMeshConfig DESTINATION share/OpenMesh/cmake)
++  export(TARGETS OpenMeshCore OpenMeshTools FILE OpenMeshConfig.cmake)
++endif()
+ 
+ # display results
+ vci_print_configure_header (OPENMESH "OpenMesh")
+diff --git a/src/OpenMesh/Core/CMakeLists.txt b/src/OpenMesh/Core/CMakeLists.txt
+index 48f55474..76a678a3 100644
+--- a/src/OpenMesh/Core/CMakeLists.txt
++++ b/src/OpenMesh/Core/CMakeLists.txt
+@@ -221,26 +221,27 @@ else()
+   set (OPENMESH_NO_INSTALL_HEADERS TRUE CACHE BOOL "Should OpenMesh skip installing headers?")
+ endif()
+ 
+-if (NOT APPLE AND NOT ${OPENMESH_NO_INSTALL_HEADERS})
+-
+-# Install Header Files)
+-install(DIRECTORY . 
+-	DESTINATION include/OpenMesh/Core
+-        FILES_MATCHING 
+-	PATTERN "*.hh"
+-        PATTERN "CVS" EXCLUDE
+-        PATTERN ".svn" EXCLUDE
+-        PATTERN "tmp" EXCLUDE
+-	PATTERN "Templates" EXCLUDE
+-        PATTERN "Debian*" EXCLUDE)
+-
+-#install the config file
+-install(FILES System/config.h DESTINATION include/OpenMesh/Core/System)
+-
+-endif ()
+-
+-install(TARGETS OpenMeshCore EXPORT OpenMeshConfig
+-  ARCHIVE DESTINATION ${VCI_PROJECT_LIBDIR}
+-  LIBRARY DESTINATION ${VCI_PROJECT_LIBDIR}
+-  RUNTIME DESTINATION ${VCI_PROJECT_BINDIR})
+-
++if (NOT OPENMESH_DISABLE_INSTALL)
++  if (NOT APPLE AND NOT ${OPENMESH_NO_INSTALL_HEADERS})
++
++  # Install Header Files)
++  install(DIRECTORY . 
++    DESTINATION include/OpenMesh/Core
++          FILES_MATCHING 
++    PATTERN "*.hh"
++          PATTERN "CVS" EXCLUDE
++          PATTERN ".svn" EXCLUDE
++          PATTERN "tmp" EXCLUDE
++    PATTERN "Templates" EXCLUDE
++          PATTERN "Debian*" EXCLUDE)
++
++  #install the config file
++  install(FILES System/config.h DESTINATION include/OpenMesh/Core/System)
++
++  endif ()
++
++  install(TARGETS OpenMeshCore EXPORT OpenMeshConfig
++    ARCHIVE DESTINATION ${VCI_PROJECT_LIBDIR}
++    LIBRARY DESTINATION ${VCI_PROJECT_LIBDIR}
++    RUNTIME DESTINATION ${VCI_PROJECT_BINDIR})
++endif()
+diff --git a/src/OpenMesh/Core/IO/exporter/ExporterT.hh b/src/OpenMesh/Core/IO/exporter/ExporterT.hh
+index 2c1d4be5..10be83c1 100644
+--- a/src/OpenMesh/Core/IO/exporter/ExporterT.hh
++++ b/src/OpenMesh/Core/IO/exporter/ExporterT.hh
+@@ -103,12 +103,16 @@ public:
+ 
+   bool is_point_double() const override
+   {
+-    return OMFormat::is_double(typename Mesh::Point()[0]);
++// o3de change begin
++    return OMFormat::is_double(typename Mesh::Point().GetX());
++// o3de change end
+   }
+ 
+   bool is_normal_double() const override
+   {
+-    return OMFormat::is_double(typename Mesh::Normal()[0]);
++// o3de change begin
++    return OMFormat::is_double(typename Mesh::Normal().GetX());
++// o3de change end
+   }
+ 
+   Vec3f  normal(VertexHandle _vh)   const override
+diff --git a/src/OpenMesh/Core/Mesh/PolyMeshT_impl.hh b/src/OpenMesh/Core/Mesh/PolyMeshT_impl.hh
+index 5026a364..5ca6db10 100644
+--- a/src/OpenMesh/Core/Mesh/PolyMeshT_impl.hh
++++ b/src/OpenMesh/Core/Mesh/PolyMeshT_impl.hh
+@@ -103,6 +103,17 @@ PolyMeshT<Kernel>::calc_face_normal(FaceHandle _fh) const
+   >::Result());
+ }
+ 
++// o3de change begin
++template<typename Point, typename Normal>
++void newell_norm(
++    Normal& n, const Point& a, const Point& b)
++{
++    n[0] += static_cast<typename vector_traits<Normal>::value_type>(a[1] * b[2]);
++    n[1] += static_cast<typename vector_traits<Normal>::value_type>(a[2] * b[0]);
++    n[2] += static_cast<typename vector_traits<Normal>::value_type>(a[0] * b[1]);
++}
++// o3de change end
++
+ template <class Kernel>
+ typename PolyMeshT<Kernel>::Normal
+ PolyMeshT<Kernel>::calc_face_normal_impl(FaceHandle _fh, PointIs3DTag) const
+@@ -134,9 +145,7 @@ PolyMeshT<Kernel>::calc_face_normal_impl(FaceHandle _fh, PointIs3DTag) const
+ 
+     // Due to traits, the value types of normals and points can be different.
+     // Therefore we cast them here.
+-    n[0] += static_cast<typename vector_traits<Normal>::value_type>(a[1] * b[2]);
+-    n[1] += static_cast<typename vector_traits<Normal>::value_type>(a[2] * b[0]);
+-    n[2] += static_cast<typename vector_traits<Normal>::value_type>(a[0] * b[1]);
++    newell_norm(n, a, b); // o3de change
+   }
+ 
+   const typename vector_traits<Normal>::value_type length = norm(n);
+diff --git a/src/OpenMesh/Core/Mesh/TriConnectivity.cc b/src/OpenMesh/Core/Mesh/TriConnectivity.cc
+index cfae830d..1b16bcbc 100644
+--- a/src/OpenMesh/Core/Mesh/TriConnectivity.cc
++++ b/src/OpenMesh/Core/Mesh/TriConnectivity.cc
+@@ -494,7 +494,7 @@ void TriConnectivity::split_copy(EdgeHandle _eh, VertexHandle _vh)
+   const VertexHandle v0 = to_vertex_handle(halfedge_handle(_eh, 0));
+   const VertexHandle v1 = to_vertex_handle(halfedge_handle(_eh, 1));
+ 
+-  const size_t nf = n_faces();
++  const auto nf = n_faces(); // o3de change
+ 
+   // Split the halfedge ( handle will be preserved)
+   split(_eh, _vh);
+diff --git a/src/OpenMesh/Tools/CMakeLists.txt b/src/OpenMesh/Tools/CMakeLists.txt
+index 08baecbd..867f4a32 100644
+--- a/src/OpenMesh/Tools/CMakeLists.txt
++++ b/src/OpenMesh/Tools/CMakeLists.txt
+@@ -185,24 +185,26 @@ else()
+   set (OPENMESH_NO_INSTALL_HEADERS TRUE CACHE BOOL "Should OpenMesh skip installing headers?")
+ endif()
+ 
+-if (NOT APPLE AND NOT ${OPENMESH_NO_INSTALL_HEADERS})
+-  # Install Header Files
+-  install(DIRECTORY .
+-        DESTINATION include/OpenMesh/Tools
+-        FILES_MATCHING
+-        PATTERN "*.hh"
+-        PATTERN "CVS" EXCLUDE
+-        PATTERN ".svn" EXCLUDE
+-        PATTERN "tmp" EXCLUDE
+-        PATTERN "Templates" EXCLUDE
+-        PATTERN "Debian*" EXCLUDE)
+-
+-  #install the config file
+-  install(FILES Utils/getopt.h DESTINATION include/OpenMesh/Tools/Utils)
+-endif ()
+-
+-install(TARGETS OpenMeshTools EXPORT OpenMeshConfig
+-  ARCHIVE DESTINATION ${VCI_PROJECT_LIBDIR}
+-  LIBRARY DESTINATION ${VCI_PROJECT_LIBDIR}
+-  RUNTIME DESTINATION ${VCI_PROJECT_BINDIR})
+-
++if (NOT OPENMESH_DISABLE_INSTALL)
++  if (NOT APPLE AND NOT ${OPENMESH_NO_INSTALL_HEADERS})
++    # Install Header Files
++    install(DIRECTORY .
++          DESTINATION include/OpenMesh/Tools
++          FILES_MATCHING
++          PATTERN "*.hh"
++          PATTERN "CVS" EXCLUDE
++          PATTERN ".svn" EXCLUDE
++          PATTERN "tmp" EXCLUDE
++          PATTERN "Templates" EXCLUDE
++          PATTERN "Debian*" EXCLUDE)
++
++    #install the config file
++    install(FILES Utils/getopt.h DESTINATION include/OpenMesh/Tools/Utils)
++  endif ()
++
++  install(TARGETS OpenMeshTools EXPORT OpenMeshConfig
++    ARCHIVE DESTINATION ${VCI_PROJECT_LIBDIR}
++    LIBRARY DESTINATION ${VCI_PROJECT_LIBDIR}
++    RUNTIME DESTINATION ${VCI_PROJECT_BINDIR})
++
++endif()
+\ No newline at end of file

+ 3 - 1
Gems/WhiteBox/CMakeLists.txt

@@ -8,6 +8,8 @@
 
 o3de_gem_setup("WhiteBox")
 
-ly_add_external_target_path(${CMAKE_CURRENT_SOURCE_DIR}/3rdParty)
+# when compiling from source, use the 3rdParty/FindOpenMesh.cmake file
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/3rdParty)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
 
 add_subdirectory(Code)

+ 15 - 53
Gems/WhiteBox/Code/CMakeLists.txt

@@ -11,51 +11,20 @@ set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
 
 include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
 
-if(NOT PAL_TRAIT_WHITEBOX_SUPPORTED)
-    ly_add_target(
-        NAME ${gem_name} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
-        NAMESPACE Gem
-        FILES_CMAKE
-            whitebox_unsupported_files.cmake
-        INCLUDE_DIRECTORIES
-            PRIVATE
-                Source
-            PUBLIC
-                Include
-        BUILD_DEPENDENCIES
-            PRIVATE
-                AZ::AzCore
-    )
-    if(PAL_TRAIT_BUILD_HOST_TOOLS)
-        ly_add_target(
-            NAME ${gem_name}.Editor GEM_MODULE
-            NAMESPACE Gem
-            FILES_CMAKE
-                whitebox_unsupported_files.cmake
-            INCLUDE_DIRECTORIES
-                PRIVATE
-                    Source
-                PUBLIC
-                    Include
-            COMPILE_DEFINITIONS
-                PRIVATE
-                    WHITE_BOX_EDITOR
-            BUILD_DEPENDENCIES
-                PRIVATE
-                    AZ::AzCore
-            RUNTIME_DEPENDENCIES
-                Gem::EditorPythonBindings.Editor
-        )
-    endif()
+# note to maintainers
+# it is not necessary to make fake empty targets for platforms that are unsupported.
+# The gem system will only load modules if you declare 
+# ly_create_alias(NAME ${gem_name}.xxxxxx  NAMESPACE Gem TARGETS Gem::${gem_name})
+# If you don't declare any aliases with ${gem_name}.${variant}, then it communicates to the system
+# that no such module exists for that platform, and it will not be loaded.
+
+# Note that actually loading a level with WhiteBox components in it into the Editor on a platform
+# that doesn't support it will cause it to load without those components, and more importantly,
+# save without those components, destroying the data.  This would happen regardless of whether no
+# dll is loaded, or a dummy empty dll is loaded.  To preserve the data, you must make a real component
+# that declares all its structs and components so it knows how to load and save them at the very least!
 
-    # Inject the gem name into the Unsupported Module source file
-    ly_add_source_properties(
-        SOURCES
-            Source/WhiteBoxModuleUnsupported.cpp
-        PROPERTY COMPILE_DEFINITIONS
-            VALUES
-                O3DE_GEM_NAME=${gem_name}
-                O3DE_GEM_VERSION=${gem_version})
+if(NOT PAL_TRAIT_WHITEBOX_SUPPORTED)
     return()
 endif()
 
@@ -113,9 +82,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
         NAMESPACE Gem
         FILES_CMAKE
             whitebox_editor_supported_files.cmake
-        PLATFORM_INCLUDE_FILES
-            ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_tools.cmake
-            ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common/${PAL_TRAIT_COMPILER_ID}/whitebox_editor_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
         INCLUDE_DIRECTORIES
             PRIVATE
                 Source
@@ -134,6 +100,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
                 Legacy::EditorCommon
                 Legacy::Editor.Headers
                 Gem::${gem_name}.Static
+                3rdParty::OpenMesh # Needs to be public, so that the below .Editor gem module includes the lib.
     )
 
     ly_add_target(
@@ -164,8 +131,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
     # use the above ${gem_name}.Editor module in dev tools:
     ly_create_alias(NAME ${gem_name}.Tools    NAMESPACE Gem TARGETS Gem::${gem_name}.Editor)
     ly_create_alias(NAME ${gem_name}.Builders NAMESPACE Gem TARGETS Gem::${gem_name}.Editor)
-
-
 endif()
 
 ################################################################################
@@ -232,10 +197,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
                 Gem::PhysX.Editor
         )
 
-        ly_add_googletest(
-            NAME Gem::${gem_name}.Editor.Physics.Tests
-            LABELS REQUIRES_tiaf
-        )
+        ly_add_googletest(NAME Gem::${gem_name}.Editor.Physics.Tests)
 
     endif()
 endif()

+ 8 - 3
Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp

@@ -71,6 +71,7 @@ namespace OpenMesh
 
 // OpenMesh includes
 AZ_PUSH_DISABLE_WARNING(4702, "-Wunknown-warning-option") // OpenMesh\Core\Utils\Property.hh has unreachable code
+AZ_PUSH_DISABLE_WARNING(4127, "-Wunknown-warning-option") // Conditional expression is constant.
 #include <OpenMesh/Core/IO/MeshIO.hh>
 #include <OpenMesh/Core/IO/SR_binary.hh>
 #include <OpenMesh/Core/IO/importer/ImporterT.hh>
@@ -79,6 +80,7 @@ AZ_PUSH_DISABLE_WARNING(4702, "-Wunknown-warning-option") // OpenMesh\Core\Utils
 #include <OpenMesh/Core/Utils/GenProg.hh>
 #include <OpenMesh/Core/Utils/vector_traits.hh>
 AZ_POP_DISABLE_WARNING
+AZ_POP_DISABLE_WARNING
 
 AZ_DECLARE_BUDGET(AzToolsFramework);
 
@@ -326,6 +328,8 @@ namespace OpenMesh::IO
         using value_type = WhiteBox::FaceHandlePolygonMapping;
         static const bool is_streamable = true;
 
+        static std::string type_identifier(void) { return "WhiteBox::FaceHandlePolygonMapping"; }
+
         // return generic binary size of self, if known
         static size_t size_of()
         {
@@ -3380,10 +3384,10 @@ namespace WhiteBox
             AZStd::lock_guard lg(g_omSerializationLock);
 
             std::stringstream whiteBoxStream;
+            // OpenMesh 11.x + requires you to specify "Custom" options to write custom properties such as our polygons or those will be skipped
             if (OpenMesh::IO::write_mesh(
                     whiteBox.mesh, whiteBoxStream, ".om",
-                    OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::FaceTexCoord |
-                        OpenMesh::IO::Options::FaceNormal))
+                    OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::FaceTexCoord | OpenMesh::IO::Options::FaceNormal | OpenMesh::IO::Options::Custom))
             {
                 const std::string outputStr = whiteBoxStream.str();
                 output.clear();
@@ -3427,8 +3431,9 @@ namespace WhiteBox
                 return ReadResult::Error;
             }
 
+            // OpenMesh 11.x + requires you to specify "Custom" options to read custom properties such as our polygons or those will be skipped
             AZStd::lock_guard lg(g_omSerializationLock);
-            OpenMesh::IO::Options options{OpenMesh::IO::Options::FaceTexCoord | OpenMesh::IO::Options::FaceNormal};
+            OpenMesh::IO::Options options{OpenMesh::IO::Options::FaceTexCoord | OpenMesh::IO::Options::FaceNormal | OpenMesh::IO::Options::Custom};
             return OpenMesh::IO::read_mesh(whiteBox.mesh, input, ".om", options) ? ReadResult::Full : ReadResult::Error;
         }
 

+ 0 - 7
Gems/WhiteBox/Code/Source/Platform/Common/Clang/whitebox_editor_clang.cmake

@@ -1,7 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#

+ 0 - 12
Gems/WhiteBox/Code/Source/Platform/Common/GCC/whitebox_editor_gcc.cmake

@@ -1,12 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#
-
-set(LY_COMPILE_OPTIONS
-    PUBLIC
-        -fexceptions # OpenMesh 3rd Party library uses exception handling
-)

+ 0 - 7
Gems/WhiteBox/Code/Source/Platform/Common/MSVC/whitebox_editor_msvc.cmake

@@ -1,7 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#

+ 0 - 22
Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake

@@ -1,22 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#
-
-if(PAL_TRAIT_BUILD_HOST_TOOLS)
-
-    if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
-        ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux         TARGETS OpenMesh PACKAGE_HASH 805bd0b24911bb00c7f575b8c3f10d7ea16548a5014c40811894a9445f17a126)
-    elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
-        ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux-aarch64 TARGETS OpenMesh PACKAGE_HASH 0d53d215c4b2185879e3b27d1a4bdf61a53bcdb059eae30377ea4573bcd9ebc1)
-    else()
-        message(FATAL_ERROR "Unsupported linux architecture ${CMAKE_SYSTEM_PROCESSOR}")
-    endif()
-
-    set(LY_BUILD_DEPENDENCIES
-        PRIVATE
-            3rdParty::OpenMesh)
-endif()

+ 0 - 2
Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake

@@ -8,8 +8,6 @@
 
 if(PAL_TRAIT_BUILD_HOST_TOOLS)
 
-    ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-mac TARGETS OpenMesh PACKAGE_HASH af92db02a25c1f7e1741ec898f49d81d52631e00336bf9bddd1e191590063c2f)
-
     set(LY_BUILD_DEPENDENCIES
         PRIVATE
             3rdParty::OpenMesh)

+ 0 - 16
Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake

@@ -1,16 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#
-
-if(PAL_TRAIT_BUILD_HOST_TOOLS)
-
-    ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-windows TARGETS OpenMesh PACKAGE_HASH 7a6309323ad03bfc646bd04ecc79c3711de6790e4ff5a72f83a8f5a8f496d684)
-
-    set(LY_BUILD_DEPENDENCIES
-        PRIVATE
-            3rdParty::OpenMesh)
-endif()

+ 0 - 23
Gems/WhiteBox/Code/Source/WhiteBoxModuleUnsupported.cpp

@@ -1,23 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/Module/Module.h>
-
-#if defined(WHITE_BOX_EDITOR)
-#if defined(O3DE_GEM_NAME)
-AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME), AZ::Module)
-#else
-AZ_DECLARE_MODULE_CLASS(Gem_WhiteBoxEditorModule, AZ::Module)
-#endif
-#else
-#if defined(O3DE_GEM_NAME)
-AZ_DECLARE_MODULE_CLASS(AZ_JOIN(Gem_, O3DE_GEM_NAME), AZ::Module)
-#else
-AZ_DECLARE_MODULE_CLASS(Gem_WhiteBox, AZ::Module)
-#endif
-#endif

+ 131 - 20
Gems/WhiteBox/Code/Tests/WhiteBoxTest.cpp

@@ -180,15 +180,57 @@ namespace UnitTest
 
         Api::InitializeAsUnitCube(*m_whiteBox);
 
+        // Note to future maintainers, a half-edge is an edge between two vertices, with a direction.
+        // Think of it like an arrow starting at one vertex, and then pointing to another at its tip.
+        // The other vertex then has a corresponding half edge, from itself, pointing back to the first vertex.
+
+        // Given a vertex handle, you can ask Open Mesh to iterate over half-edges from that vertex.
+        // If you ask it for "outgoing" half-edges, you'll get all of the ones which start at the given vertex and point at others.
+        // If you ask it for "incoming" half-edges, you'll get all of the ones which point at the given vertex and start at others.
+
+        // Most importantly, the "handle" of a half edge is an opaque integer that is implementation version specific and does not
+        // impart meaning, similar to how the actual integer file handle returned when you open a user file using 'open' does not
+        // impart meaning.  You can only use it to refer to the half-edge in functions which query other aspects, such as which faces
+        // it is beside or which vertices it points at or comes from.  The acutal integer number is not guarinteed to remain in order
+        // or to be stable.
+
+        // Users, however to specify vertices, and in that case, the order matters. For this unit cube,
+        // vertex 0 is at the corner of the top of the cube.
+        // Vertex 0 has 5 outgoing half-edges, one for each of the 5 edges that connect from vertex 0 to other vertices as the model
+        // is actually made of triangles (not quads), so each quad face is actually 2 triangles.
+        // It has no 6th outgoing edge because the triangle-strip like zig-zag pattern which
+        // the triangles are constructed from means that vertex 0 connects to 5 other vertices via edges but isn't the nexus of all
+        // 3 cube sides it touches, as that would form a triangle fan around it instead of a strip.
+
         AZStd::vector<Api::HalfedgeHandle> outgoingHalfedgeHandles =
             Api::VertexOutgoingHalfedgeHandles(*m_whiteBox, Api::VertexHandle{0});
 
-        const Api::HalfedgeHandle expectedHalfedgeHandles[] = {
-            Api::HalfedgeHandle{9}, Api::HalfedgeHandle{34}, Api::HalfedgeHandle{24}, Api::HalfedgeHandle{0},
-            Api::HalfedgeHandle{5}};
+        ASSERT_EQ(outgoingHalfedgeHandles.size(), 5); // we are going to assume this going forward, so stop here if its not.
 
-        EXPECT_THAT(
-            outgoingHalfedgeHandles, ElementsAreArray(expectedHalfedgeHandles, std::size(expectedHalfedgeHandles)));
+        for (const auto& halfedgeHandle : outgoingHalfedgeHandles)
+        {
+            // when we are iterating over half-edges, the "tail" is the vertex that the half-edge is coming from, so in this case,
+            // because we asked it to get all the outgoing half-edges 0, that means 0 should be the tail of every such 'arrow'.
+            auto tailHandle = Api::VertexHandle{ 0 };
+            EXPECT_EQ(Api::HalfedgeVertexHandleAtTail(*m_whiteBox, halfedgeHandle), tailHandle);
+        }
+
+        // On the other hand, when we ask it for which vertex is at the tip of the edge, its the vertex on the other side of the
+        // half-edge, from vertex 0 - We expect it to connect to exactly 5 other vertices since there are 5 half-edges and no duplicates.
+        // Specifically the closest 5 from that corner in the cube.  Because the iterator always runs counter clockwise, this order is FIXED.
+        const Api::VertexHandle expectedOtherSideVertexHandles[] = {
+             Api::VertexHandle{ 7 },
+             Api::VertexHandle{ 4 },
+             Api::VertexHandle{ 1 },
+             Api::VertexHandle{ 2 },
+             Api::VertexHandle{ 3 }
+        };
+
+        ASSERT_EQ(AZ_ARRAY_SIZE(expectedOtherSideVertexHandles), outgoingHalfedgeHandles.size());
+        for (size_t halfEdgeIndex = 0; halfEdgeIndex < outgoingHalfedgeHandles.size(); ++halfEdgeIndex)
+        {
+            EXPECT_EQ(Api::HalfedgeVertexHandleAtTip(*m_whiteBox, outgoingHalfedgeHandles[halfEdgeIndex]), expectedOtherSideVertexHandles[halfEdgeIndex]);
+        }
     }
 
     TEST_F(WhiteBoxTestFixture, IncomingHalfedgesFromVertex)
@@ -201,12 +243,33 @@ namespace UnitTest
         AZStd::vector<Api::HalfedgeHandle> incomingHalfedgeHandles =
             Api::VertexIncomingHalfedgeHandles(*m_whiteBox, Api::VertexHandle{0});
 
-        const Api::HalfedgeHandle expectedHalfedgeHandles[] = {
-            Api::HalfedgeHandle{8}, Api::HalfedgeHandle{35}, Api::HalfedgeHandle{25}, Api::HalfedgeHandle{1},
-            Api::HalfedgeHandle{4}};
+        // see the note in the above check.
+        ASSERT_EQ(incomingHalfedgeHandles.size(), 5); // we are going to assume this going forward, so stop here if its not.
+        for (const auto& halfedgeHandle : incomingHalfedgeHandles)
+        {
+            // when we are iterating over half-edges, the "tip" is the vertex that the half-edge is pointing at,
+            // because we asked it to get all the incoming half-edges pointing at vertex 0, we expect that all of them return vertex 0
+            auto tailHandle = Api::VertexHandle{ 0 };
+            EXPECT_EQ(Api::HalfedgeVertexHandleAtTip(*m_whiteBox, halfedgeHandle), tailHandle);
+        }
 
-        EXPECT_THAT(
-            incomingHalfedgeHandles, ElementsAreArray(expectedHalfedgeHandles, std::size(expectedHalfedgeHandles)));
+        // On the other hand, when we ask it for which vertex is at the tail of the edge, its the one on the opposite side to vertex 0
+        // this should be exactly 5 other vertices, in counter clockwise order (so it should be a fixed order).
+        const Api::VertexHandle expectedOtherSideVertexHandles[] = {
+            Api::VertexHandle{ 7 },
+            Api::VertexHandle{ 4 },
+            Api::VertexHandle{ 1 },
+            Api::VertexHandle{ 2 },
+            Api::VertexHandle{ 3 }
+        };
+
+        ASSERT_EQ(AZ_ARRAY_SIZE(expectedOtherSideVertexHandles), incomingHalfedgeHandles.size());
+        for (size_t halfEdgeIndex = 0; halfEdgeIndex < incomingHalfedgeHandles.size(); ++halfEdgeIndex)
+        {
+            EXPECT_EQ(
+                Api::HalfedgeVertexHandleAtTail(*m_whiteBox, incomingHalfedgeHandles[halfEdgeIndex]),
+                expectedOtherSideVertexHandles[halfEdgeIndex]);
+        }
     }
 
     TEST_F(WhiteBoxTestFixture, AllHalfedgesFromVertex)
@@ -216,15 +279,59 @@ namespace UnitTest
 
         Api::InitializeAsUnitCube(*m_whiteBox);
 
+        // see the note on the previous 2 functions.  This one gets ALL of the half edges related to a vertex
+        // both incoming and outgiong.  Handles are opaque data types, so its unreliable to expect the handles
+        // to be any particular value.  However, each handle should point at vertex 0 at its head or tail
+        // and there is always a fixed number of them (5 incoming, 5 outgoing = 10 total).
+        // However, the iterator returns them in counter clockwise order, so the verts they connect to on each end are predictable.
         AZStd::vector<Api::HalfedgeHandle> allHalfedgeHandles =
             Api::VertexHalfedgeHandles(*m_whiteBox, Api::VertexHandle{0});
 
-        const Api::HalfedgeHandle expectedHalfedgeHandles[] = {
-            Api::HalfedgeHandle{9}, Api::HalfedgeHandle{34}, Api::HalfedgeHandle{24}, Api::HalfedgeHandle{0},
-            Api::HalfedgeHandle{5}, Api::HalfedgeHandle{8},  Api::HalfedgeHandle{35}, Api::HalfedgeHandle{25},
-            Api::HalfedgeHandle{1}, Api::HalfedgeHandle{4}};
+        ASSERT_EQ(allHalfedgeHandles.size(), 10);
+
+        // notice that when we ask for all halfedges, we get 5 incoming and 5 outgoing
+        // and it gets the outgoing first (so the tip will be all the other verts)
+        // then the incoming, so the tip will all be the vert we asked for, which is zero.
+        const Api::VertexHandle expectedTipVertexHandles[] = {
+            Api::VertexHandle{ 7 },
+            Api::VertexHandle{ 4 },
+            Api::VertexHandle{ 1 },
+            Api::VertexHandle{ 2 },
+            Api::VertexHandle{ 3 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 } };
+
+        // Similarly when we ask for all halfedges, the tail of each one is going be the outgoing
+        // first, so all 0's (since we asked for 0's halfedges), and then the incoming, so the other verts.
+        const Api::VertexHandle expectedTailVertexHandles[] = {
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 0 },
+            Api::VertexHandle{ 7 },
+            Api::VertexHandle{ 4 },
+            Api::VertexHandle{ 1 },
+            Api::VertexHandle{ 2 },
+            Api::VertexHandle{ 3 } };
+
+        AZStd::vector<Api::VertexHandle> actualTipVertexHandles;
+        AZStd::vector<Api::VertexHandle> actualTailVertexHandles;
+
+        ASSERT_EQ(AZ_ARRAY_SIZE(expectedTipVertexHandles),  allHalfedgeHandles.size());
+        ASSERT_EQ(AZ_ARRAY_SIZE(expectedTailVertexHandles), allHalfedgeHandles.size());
+
+        for (size_t halfEdgeIndex = 0; halfEdgeIndex < allHalfedgeHandles.size(); ++halfEdgeIndex)
+        {
+            actualTipVertexHandles.push_back(Api::HalfedgeVertexHandleAtTip(*m_whiteBox, allHalfedgeHandles[halfEdgeIndex]));
+            actualTailVertexHandles.push_back(Api::HalfedgeVertexHandleAtTail(*m_whiteBox, allHalfedgeHandles[halfEdgeIndex]));
+        }
 
-        EXPECT_THAT(allHalfedgeHandles, ElementsAreArray(expectedHalfedgeHandles, std::size(expectedHalfedgeHandles)));
+        EXPECT_THAT(actualTipVertexHandles, ElementsAreArray(expectedTipVertexHandles, std::size(expectedTipVertexHandles)));
+        EXPECT_THAT(actualTailVertexHandles, ElementsAreArray(expectedTailVertexHandles, std::size(expectedTailVertexHandles)));
     }
 
     TEST_F(WhiteBoxTestFixture, VerticesForFace)
@@ -2012,8 +2119,10 @@ namespace UnitTest
 
         const auto vertexUserEdgeVectors = Api::VertexUserEdgeVectors(*m_whiteBox, Api::VertexHandle{2});
 
+        // The order of these can change between versions of OM3D but the values should be the same (one for each basis)
+        // Winding is counter clockwise so it tends to go -X ... -Y ... -Z in latest OpenMesh 11.x
         const auto expectedUserEdgeVectors = AZStd::vector<AZ::Vector3>{
-            -AZ::Vector3::CreateAxisZ(), -AZ::Vector3::CreateAxisX(), -AZ::Vector3::CreateAxisY()};
+            -AZ::Vector3::CreateAxisX(), -AZ::Vector3::CreateAxisY(), -AZ::Vector3::CreateAxisZ()};
 
         EXPECT_THAT(vertexUserEdgeVectors, Pointwise(ContainerIsClose(), expectedUserEdgeVectors));
     }
@@ -2055,10 +2164,12 @@ namespace UnitTest
         const auto vertexUserEdgeVectors = Api::VertexUserEdgeVectors(*m_whiteBox, Api::VertexHandle{2});
         const auto vertexUserEdgeAxes = Api::VertexUserEdgeAxes(*m_whiteBox, Api::VertexHandle{2});
 
-        const auto expectedUserEdgeVectors =
-            AZStd::vector<AZ::Vector3>{-AZ::Vector3::CreateAxisZ(2.0f), -AZ::Vector3::CreateAxisY(3.0f)};
-        const auto expectedUserEdgeAxes =
-            AZStd::vector<AZ::Vector3>{-AZ::Vector3::CreateAxisZ(), -AZ::Vector3::CreateAxisY()};
+        // Again, these could change in order between versions of OpenMesh.  But the values will be present.
+        // In the OpenMesh 11.0 it tends to go (-x ... -y ... -z) so in this case its (-y, -z) becuase we have 
+        // collapsed along x, which will have a zero length and should no be returned.
+
+        const auto expectedUserEdgeVectors = AZStd::vector<AZ::Vector3>{ -AZ::Vector3::CreateAxisY(3.0f), -AZ::Vector3::CreateAxisZ(2.0f) };
+        const auto expectedUserEdgeAxes    = AZStd::vector<AZ::Vector3>{ -AZ::Vector3::CreateAxisY(), -AZ::Vector3::CreateAxisZ() };
 
         EXPECT_THAT(vertexUserEdgeVectors, Pointwise(ContainerIsClose(), expectedUserEdgeVectors));
         EXPECT_THAT(vertexUserEdgeAxes, Pointwise(ContainerIsClose(), expectedUserEdgeAxes));

+ 0 - 11
Gems/WhiteBox/Code/whitebox_unsupported_files.cmake

@@ -1,11 +0,0 @@
-#
-# Copyright (c) Contributors to the Open 3D Engine Project.
-# For complete copyright and license terms please see the LICENSE at the root of this distribution.
-#
-# SPDX-License-Identifier: Apache-2.0 OR MIT
-#
-#
-
-set(FILES
-    Source/WhiteBoxModuleUnsupported.cpp
-)

+ 0 - 1
cmake/3rdParty/Platform/Linux/BuiltInPackages_linux_aarch64.cmake

@@ -30,7 +30,6 @@ ly_associate_package(PACKAGE_NAME qt-5.15.2-rev9-linux-aarch64
 ly_associate_package(PACKAGE_NAME png-1.6.37-rev2-linux-aarch64                              TARGETS PNG                         PACKAGE_HASH fcf646c1b1b4163000efdb56d7c8f086b6ce0a520da5c8d3ffce4e1329ae798a)
 ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux-aarch64                     TARGETS libsamplerate               PACKAGE_HASH 751484da1527432cd19263909f69164d67b25644f87ec1d4ec974a343defacea)
 ly_associate_package(PACKAGE_NAME openimageio-opencolorio-2.3.17-rev2-linux-aarch64          TARGETS OpenImageIO OpenColorIO OpenColorIO::Runtime OpenImageIO::Tools::Binaries OpenImageIO::Tools::PythonPlugins PACKAGE_HASH 2bc6a43f60c8206b2606a65738e0fcf3b3b17e0db16089404d8389d337c85ad6)
-ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux-aarch64                            TARGETS OpenMesh                    PACKAGE_HASH 0d53d215c4b2185879e3b27d1a4bdf61a53bcdb059eae30377ea4573bcd9ebc1)
 ly_associate_package(PACKAGE_NAME OpenEXR-3.1.3-rev4-linux-aarch64                           TARGETS OpenEXR Imath               PACKAGE_HASH c9a81050f0d550ab03d2f5801e2f67f9f02747c26f4b39647e9919278585ad6a)
 ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1t-rev1-linux-aarch64                          TARGETS OpenSSL                     PACKAGE_HASH f32721bec9c82d1bd7fb244d78d5dc4e2a47e7b808bb36027236ad377e241ea5)
 ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.7.2308-o3de-rev1-linux-aarch64  TARGETS DirectXShaderCompilerDxc    PACKAGE_HASH 226eaf982fa182c3460e79a00edfa19d0df6144f089ee1746adfaa24f1f4e5d0)

+ 0 - 1
cmake/3rdParty/Platform/Linux/BuiltInPackages_linux_x86_64.cmake

@@ -30,7 +30,6 @@ ly_associate_package(PACKAGE_NAME qt-5.15.2-rev9-linux
 ly_associate_package(PACKAGE_NAME png-1.6.37-rev2-linux                             TARGETS PNG                         PACKAGE_HASH 5c82945a1648905a5c4c5cee30dfb53a01618da1bf58d489610636c7ade5adf5)
 ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux                    TARGETS libsamplerate               PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261)
 ly_associate_package(PACKAGE_NAME openimageio-opencolorio-2.3.17-rev2-linux         TARGETS OpenImageIO OpenColorIO OpenColorIO::Runtime OpenImageIO::Tools::Binaries OpenImageIO::Tools::PythonPlugins PACKAGE_HASH c8a9f1d9d6c9f8c3defdbc3761ba391d175b1cb62a70473183af1eaeaef70c36)
-ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux                           TARGETS OpenMesh                    PACKAGE_HASH 805bd0b24911bb00c7f575b8c3f10d7ea16548a5014c40811894a9445f17a126)
 ly_associate_package(PACKAGE_NAME OpenEXR-3.1.3-rev4-linux                          TARGETS OpenEXR Imath               PACKAGE_HASH fcbac68cfb4e3b694580bc3741443e111aced5f08fde21a92e0c768e8803c7af)
 ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1t-rev1-linux                         TARGETS OpenSSL                     PACKAGE_HASH 63aea898b7afe8faccd0c7261e62d2f8b7b870f678a4520d5be81e5815542b39)
 ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.7.2308-o3de-rev2-linux TARGETS DirectXShaderCompilerDxc    PACKAGE_HASH c0fa3034c88b5ad4efb81fd1f961ab52f9eddfb80506fd06ab7bd3dc857e5950)

+ 0 - 1
cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake

@@ -30,7 +30,6 @@ ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-mac
 ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-mac                             TARGETS mikkelsen                   PACKAGE_HASH 83af99ca8bee123684ad254263add556f0cf49486c0b3e32e6d303535714e505)
 ly_associate_package(PACKAGE_NAME googlebenchmark-1.7.0-rev1-mac                    TARGETS GoogleBenchmark             PACKAGE_HASH a1c8793eb1760905290065929b45600a4b4457345fcc129fce253d1a8980bbce)
 ly_associate_package(PACKAGE_NAME openimageio-opencolorio-2.3.17-rev3-mac           TARGETS OpenImageIO OpenColorIO OpenColorIO::Runtime OpenImageIO::Tools::Binaries OpenImageIO::Tools::PythonPlugins PACKAGE_HASH bc322f9e28d519ab5959a638b38ee3b773fefb868802823fad2396ab4f7bcbc8)
-ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-mac                             TARGETS OpenMesh                    PACKAGE_HASH af92db02a25c1f7e1741ec898f49d81d52631e00336bf9bddd1e191590063c2f)
 ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1o-rev1-mac                           TARGETS OpenSSL                     PACKAGE_HASH 73a4bd7856b53edf5ab9d2ff1d31ebb02301be818680a59206ce8ec5940f3468)
 ly_associate_package(PACKAGE_NAME OpenEXR-3.1.3-rev4-mac                            TARGETS OpenEXR Imath               PACKAGE_HASH 927b8ca6cc5815fa8ee4efe6ea2845487cba2540f7958d537692e7c9481a68fc)
 ly_associate_package(PACKAGE_NAME qt-5.15.2-rev8-mac                                TARGETS Qt                          PACKAGE_HASH d0f97579ea2822c73f0b316a26c68ceb5332763e691d7e78d6b02fe3104b1d31)

+ 0 - 1
cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake

@@ -36,7 +36,6 @@ ly_associate_package(PACKAGE_NAME openimageio-opencolorio-2.3.17-rev4-windows
 ly_associate_package(PACKAGE_NAME qt-5.15.2-rev7-windows                                TARGETS Qt                          PACKAGE_HASH 4343a04130657e740795e50a25ab5fe6e41100fa3c58a212c86bed612dde7775)
 ly_associate_package(PACKAGE_NAME png-1.6.37-rev2-windows                               TARGETS PNG                         PACKAGE_HASH e16539a0fff26ac9ef80dd11ef0103eca91745519eacd41d41d96911c173589f)
 ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows                      TARGETS libsamplerate               PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f)
-ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-windows                             TARGETS OpenMesh                    PACKAGE_HASH 7a6309323ad03bfc646bd04ecc79c3711de6790e4ff5a72f83a8f5a8f496d684)
 ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows                             TARGETS civetweb                    PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4)
 ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1o-rev1-windows                           TARGETS OpenSSL                     PACKAGE_HASH 52b9d2bc5f3e0c6e405a0f290d1904bf545acc0c73d6a52351247d917c4a06d2)
 ly_associate_package(PACKAGE_NAME Crashpad-0.8.0-rev1-windows                           TARGETS Crashpad                    PACKAGE_HASH d162aa3070147bc0130a44caab02c5fe58606910252caf7f90472bd48d4e31e2)

+ 9 - 0
cmake/Configurations.cmake

@@ -210,3 +210,12 @@ endforeach()
 o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
 include(${pal_dir}/Configurations_${PAL_PLATFORM_NAME_LOWERCASE}${LY_ARCHITECTURE_NAME_EXTENSION}.cmake)
 
+# Perform a self-check here - we expect certain values to be defined even if they are blank for a given platform.
+set(O3DE_REQUIRED_DEFINITIONS O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS O3DE_COMPILE_OPTION_EXPORT_SYMBOLS O3DE_COMPILE_OPTION_DISABLE_WARNINGS)
+foreach(def ${O3DE_REQUIRED_DEFINITIONS})
+    message(VERBOSE "Current compiler/arch sets ${def}=${${def}}")
+    if (NOT DEFINED ${def})
+        message(FATAL_ERROR, "${def} must be defined for every platform and compiler.  Set it to blank if it does not apply when you are defining a new toolchain")
+    endif()
+endforeach()
+

+ 53 - 0
cmake/PatchIfNotAlreadyPatched.cmake

@@ -0,0 +1,53 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+# This file is used to patch a file only if it has not already been patched.
+# This is useful for patching a file that is fetched by FetchContent, which
+# does not have a built-in way to only apply a patch if it has not already been
+# applied.
+
+# Usage:
+# cmake -P PatchIfNotAlreadyPatched.cmake <patchfile>
+# it expects the current working directory to be in the root of the repository
+# for which the patch applies and uses `git apply` to patch it.
+
+# note that CMAKE_ARGV0 will be the cmake executable
+#  and that CMAKE_ARGV1 will be -P to enable the script mode
+#  and that CMAKE_ARGV2 will be the name of this script file itself,
+# so we start at CMAKE_ARGV3 to get the first argument passed to this script.
+
+set(PATCH_FILE_NAME "${CMAKE_ARGV3}")
+set(PATCH_ALREADY_APPLIED "")
+
+# Check if the patch has already been applied.
+# if this command returns 0 it means that reversing the patch was successful
+# which means the patch was already applied.
+execute_process(
+    COMMAND git apply --check --reverse "${PATCH_FILE_NAME}"
+    RESULT_VARIABLE PATCH_ALREADY_APPLIED
+    OUTPUT_QUIET
+    ERROR_QUIET
+)
+
+if (PATCH_ALREADY_APPLIED STREQUAL "0")
+    message(STATUS "Skipping already applied patch ${PATCH_FILE_NAME} in dir ${CMAKE_BINARY_DIR}")
+else()
+    message(STATUS "Cleaning directory before patch...")
+    execute_process(COMMAND git restore .)
+    execute_process(COMMAND git clean -fdx)
+    message(STATUS "Applying patch ${PATCH_FILE_NAME} at ${CMAKE_BINARY_DIR}...")
+    execute_process(
+        COMMAND git apply --ignore-whitespace "${PATCH_FILE_NAME}"
+        RESULT_VARIABLE PATCH_RESULT
+    )
+    if (NOT PATCH_RESULT EQUAL 0)
+        message(FATAL_ERROR "Failed to apply patch")
+    else()
+        message(STATUS "Patch applied successfully")
+    endif()
+endif()

+ 15 - 0
cmake/Platform/Common/Clang/Configurations_clang.cmake

@@ -8,6 +8,21 @@
 
 include(cmake/Platform/Common/Configurations_common.cmake)
 
+# Exceptions are disabled by default.  Use this to turn them on just for a specific target.
+set(O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS PUBLIC -fexceptions)
+
+# O3DE Sets visibility to hidden by default, requiring explicit export.
+# However, some 3rd Party libraries will not export any symbols with this setting
+# as they expect to be built with visibility set to default.  Use this compile option
+# to turn visibility back to default for those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_EXPORT_SYMBOLS PRIVATE -fvisibility=default)
+
+# By default, O3DE sets warning level 4 and sets warnings as errors.  If you're pulling in
+# external code (from 3rd Party libraries) you can't really control whether they generate
+# warnings or not, and its usually out of scope to fix them.  Add this compile option to 
+# those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_DISABLE_WARNINGS PRIVATE -w)
+
 ly_append_configurations_options(
     DEFINES_PROFILE
         _FORTIFY_SOURCE=2

+ 15 - 0
cmake/Platform/Common/GCC/Configurations_gcc.cmake

@@ -8,6 +8,21 @@
 
 include(cmake/Platform/Common/Configurations_common.cmake)
 
+# Exceptions are disabled by default.  Use this to turn them on just for a specific target.
+set(O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS PUBLIC -fexceptions)
+
+# O3DE Sets visibility to hidden by default, requiring explicit export.
+# However, some 3rd Party libraries will not export any symbols with this setting
+# as they expect to be built with visibility set to default.  Use this compile option
+# to turn visibility back to default for those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_EXPORT_SYMBOLS PRIVATE -fvisibility=default)
+
+# By default, O3DE sets warning level 4 and sets warnings as errors.  If you're pulling in
+# external code (from 3rd Party libraries) you can't really control whether they generate
+# warnings or not, and its usually out of scope to fix them.  Add this compile option to 
+# those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_DISABLE_WARNINGS PRIVATE -w)
+
 set(LY_GCC_BUILD_FOR_GCOV FALSE CACHE BOOL "Flag to enable the build for gcov usage")
 if(LY_GCC_BUILD_FOR_GCOV)
     set(LY_GCC_GCOV_FLAGS "--coverage")

+ 17 - 0
cmake/Platform/Common/MSVC/Configurations_clang.cmake

@@ -8,6 +8,23 @@
 
 include(cmake/Platform/Common/Configurations_common.cmake)
 
+# Exceptions are disabled by default.  Use this to turn them on just for a specific target.
+# MSVC-Clang uses MSVC compiler option syntax (so /EHsc instead of -fexceptions)
+set(O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS PUBLIC /EHsc)
+
+# O3DE Sets visibility to hidden by default, requiring explicit export on non-windows platforms
+# But on MSVC or MS-Clang, these compilers use MSVC compiler options and behavior, which means
+# it is not necessary to set visibility to hidden as on MSVC, things behave similar to if
+# hidden by default.  As such, there is no need to change compile options for 3rd Party Libraries
+# to cause them to export symbols.  This is thus blank
+set(O3DE_COMPILE_OPTION_EXPORT_SYMBOLS "")
+
+# By default, O3DE sets warning level 4 and sets warnings as errors.  If you're pulling in
+# external code (from 3rd Party libraries) you can't really control whether they generate
+# warnings or not, and its usually out of scope to fix them.  Add this compile option to 
+# those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_DISABLE_WARNINGS PRIVATE /W0)
+
 ly_append_configurations_options(
     DEFINES_PROFILE
         _FORTIFY_SOURCE=2

+ 16 - 0
cmake/Platform/Common/MSVC/Configurations_msvc.cmake

@@ -8,6 +8,22 @@
 
 get_property(O3DE_SCRIPT_ONLY GLOBAL PROPERTY "O3DE_SCRIPT_ONLY")
 
+# Exceptions are disabled by default.  Use this to turn them on just for a specific target.
+set(O3DE_COMPILE_OPTION_ENABLE_EXCEPTIONS PUBLIC /EHsc)
+
+# O3DE Sets visibility to hidden by default, requiring explicit export on non-windows platforms
+# But on MSVC or MS-Clang, these compilers use MSVC compiler options and behavior, which means
+# it is not necessary to set visibility to hidden as on MSVC, things behave similar to if
+# hidden by default.  As such, there is no need to change compile options for 3rd Party Libraries
+# to cause them to export symbols.  This is thus blank
+set(O3DE_COMPILE_OPTION_EXPORT_SYMBOLS "")
+
+# By default, O3DE sets warning level 4 and sets warnings as errors.  If you're pulling in
+# external code (from 3rd Party libraries) you can't really control whether they generate
+# warnings or not, and its usually out of scope to fix them.  Add this compile option to 
+# those 3rd Party targets ONLY.
+set(O3DE_COMPILE_OPTION_DISABLE_WARNINGS PRIVATE /W0)
+
 if (NOT O3DE_SCRIPT_ONLY)
     set(minimum_supported_toolset 142)
     if(MSVC_TOOLSET_VERSION VERSION_LESS ${minimum_supported_toolset})