From 02cd0405eed66a050109498ff8df2dc247eff3d2 Mon Sep 17 00:00:00 2001
From: Ian Chen <ichen@openrobotics.org>
Date: Mon, 9 Sep 2024 20:25:46 +0000
Subject: [PATCH] Merge from gz-common6

Signed-off-by: Ian Chen <ichen@openrobotics.org>
---
 CMakeLists.txt                     |   2 +-
 Changelog.md                       | 112 ++++++++++++++++++++++++++++-
 README.md                          |  10 +--
 graphics/src/AssimpLoader.cc       |  68 +++++++++++++-----
 graphics/src/ColladaLoader_TEST.cc |   1 +
 include/gz/common/Console.hh       |   2 +-
 src/Console_TEST.cc                |   4 ++
 7 files changed, 172 insertions(+), 27 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 492f754a..b9103b6f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ set(GZ_CMAKE_VER ${gz-cmake4_VERSION_MAJOR})
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
-gz_configure_project(VERSION_SUFFIX)
+gz_configure_project(VERSION_SUFFIX pre2)
 
 #============================================================================
 # Set project-specific options
diff --git a/Changelog.md b/Changelog.md
index 7e9ef3d0..e139732b 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,6 +1,116 @@
 ## Gazebo Common 6.x
 
-## Gazebo Common 6.0.0 (20XX-XX-XX)
+## Gazebo Common 6.0.0 (2024-09-XX)
+
+1. **Baseline:** this includes all changes from 5.6.0 and earlier.
+
+1. Experimenting with spdlog
+    * [Pull request #615](https://github.com/gazebosim/gz-common/pull/615)
+
+1. Update Changelog, README and prepare for gz-common6.0.0~pre1 release
+    * [Pull request #626](https://github.com/gazebosim/gz-common/pull/626)
+
+1. Use self-pipe trick to implement signal handlers
+    * [Pull request #618](https://github.com/gazebosim/gz-common/pull/618)
+
+1. Replace GTS with CDT
+    * [Pull request #617](https://github.com/gazebosim/gz-common/pull/617)
+
+1. Remove debug logging introduced accidentally in PR review
+    * [Pull request #622](https://github.com/gazebosim/gz-common/pull/622)
+
+1. Fix crash when calling absPath with empty input
+    * [Pull request #620](https://github.com/gazebosim/gz-common/pull/620)
+
+1. DEM: Add support for GDAL vsicurl, vsizip support and avoid segfaults with huge VRT datasets
+    * [Pull request #597](https://github.com/gazebosim/gz-common/pull/597)
+
+1. Enable 24.04 CI, require cmake 3.22.1
+    * [Pull request #619](https://github.com/gazebosim/gz-common/pull/619)
+
+1. SubMesh::RecalculateNormals improvement
+    * [Pull request #609](https://github.com/gazebosim/gz-common/pull/609)
+
+1. fix data race tsan issue
+    * [Pull request #612](https://github.com/gazebosim/gz-common/pull/612)
+
+1. Generate a more unique texture name for glb embedded textures
+    * [Pull request #606](https://github.com/gazebosim/gz-common/pull/606)
+
+1. Add package.xml
+    * [Pull request #587](https://github.com/gazebosim/gz-common/pull/587)
+
+1. Fix deprecation warnings
+    * [Pull request #603](https://github.com/gazebosim/gz-common/pull/603)
+
+1. Fix macOS workflow and update on-push branches
+    * [Pull request #602](https://github.com/gazebosim/gz-common/pull/602)
+
+1. port: 5 to main
+    * [Pull request #594](https://github.com/gazebosim/gz-common/pull/594)
+
+1. Clean up Clang compiler warnings
+    * [Pull request #589](https://github.com/gazebosim/gz-common/pull/589)
+
+1. Add new function in MeshManager to merge all submeshes of a mesh into one
+    * [Pull request #588](https://github.com/gazebosim/gz-common/pull/588)
+
+1. Adds new function in MeshManager for performing convex decomposition
+    * [Pull request #585](https://github.com/gazebosim/gz-common/pull/585)
+
+1. Fix compatibility with FFmpeg5.0
+    * [Pull request #581](https://github.com/gazebosim/gz-common/pull/581)
+
+1. Remove HIDE_SYMBOLS_BY_DEFAULT: replace by a default configuration in gz-cmake.
+    * [Pull request #568](https://github.com/gazebosim/gz-common/pull/568)
+
+1. Fix search for UUID on Windows logic
+    * [Pull request #556](https://github.com/gazebosim/gz-common/pull/556)
+
+1. Fix windows compilation by setting right visibility attributes
+    * [Pull request #550](https://github.com/gazebosim/gz-common/pull/550)
+
+1. Drop the internal vendored version of TinyXML2
+    * [Pull request #542](https://github.com/gazebosim/gz-common/pull/542)
+
+1. Revert "Add missing visibility declarations (#548)"
+    * [Pull request #553](https://github.com/gazebosim/gz-common/pull/553)
+
+1. Add missing visibility declarations
+    * [Pull request #548](https://github.com/gazebosim/gz-common/pull/548)
+
+1. Remove ignition
+    * [Pull request #525](https://github.com/gazebosim/gz-common/pull/525)
+
+1. Bumps in ionic: use gz-cmake4, gz-utils3, gz-math8
+    * [Pull request #539](https://github.com/gazebosim/gz-common/pull/539)
+
+1. Remove deprecated std::iterator inheritance
+    * [Pull request #529](https://github.com/gazebosim/gz-common/pull/529)
+
+1. Collada and Assimp test for default animation names
+    * [Pull request #476](https://github.com/gazebosim/gz-common/pull/476)
+
+1. Avoid Io.hh header name clash
+    * [Pull request #471](https://github.com/gazebosim/gz-common/pull/471)
+
+1. Default name assignment to animations without names
+    * [Pull request #413](https://github.com/gazebosim/gz-common/pull/413)
+
+1. Skip CSV header when reading DataFrame
+    * [Pull request #435](https://github.com/gazebosim/gz-common/pull/435)
+
+1. Main deprecations
+    * [Pull request #433](https://github.com/gazebosim/gz-common/pull/433)
+
+1. Add CSV data parsing
+    * [Pull request #402](https://github.com/gazebosim/gz-common/pull/402)
+
+1. Introduces Flips UV flag, removes empty space
+    * [Pull request #420](https://github.com/gazebosim/gz-common/pull/420)
+
+1. ⬆️  Bump main to 6.0.0~pre1
+    * [Pull request #412](https://github.com/gazebosim/gz-common/pull/412)
 
 ## Gazebo Common 5.x
 
diff --git a/README.md b/README.md
index 628f501d..f2e02e2c 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@
 
 Build | Status
 -- | --
-Test coverage | [![codecov](https://codecov.io/gh/gazebosim/gz-common/tree/gz-common5/graph/badge.svg)](https://codecov.io/gh/gazebosim/gz-common/tree/gz-common5)
-Ubuntu Jammy  | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_common-ci-gz-common5-jammy-amd64)](https://build.osrfoundation.org/job/gz_common-ci-gz-common5-jammy-amd64)
-Homebrew      | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_common-ci-gz-common5-homebrew-amd64)](https://build.osrfoundation.org/job/gz_common-ci-gz-common5-homebrew-amd64)
-Windows       | [![Build Status](https://build.osrfoundation.org/job/gz_common-5-win/badge/icon)](https://build.osrfoundation.org/job/gz_common-5-win/)
+Test coverage | [![codecov](https://codecov.io/gh/gazebosim/gz-common/tree/gz-common6/graph/badge.svg)](https://codecov.io/gh/gazebosim/gz-common/tree/gz-common6)
+Ubuntu Noble  | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_common-ci-gz-common6-noble-amd64)](https://build.osrfoundation.org/job/gz_common-ci-gz-common6-noble-amd64)
+Homebrew      | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_common-ci-gz-common6-homebrew-amd64)](https://build.osrfoundation.org/job/gz_common-ci-gz-common6-homebrew-amd64)
+Windows       | [![Build Status](https://build.osrfoundation.org/job/gz_common-6-win/badge/icon)](https://build.osrfoundation.org/job/gz_common-6-win/)
 
 Gazebo Common, a component of [Gazebo](https://gazebosim.org), provides a set of libraries that
 cover many different use cases. An audio-visual library supports
@@ -59,7 +59,7 @@ See the [installation tutorial](https://gazebosim.org/api/common/6/install.html)
 
 # Usage
 
-Please refer to the [examples directory](https://github.com/gazebosim/gz-common/tree/main/examples).
+Please refer to the [examples directory](https://github.com/gazebosim/gz-common/tree/gz-common6/examples).
 
 # Folder Structure
 
diff --git a/graphics/src/AssimpLoader.cc b/graphics/src/AssimpLoader.cc
index bcbd7096..d144dbab 100644
--- a/graphics/src/AssimpLoader.cc
+++ b/graphics/src/AssimpLoader.cc
@@ -16,9 +16,11 @@
  */
 
 #include <cstddef>
+#include <memory>
 #include <queue>
 #include <string>
 #include <unordered_set>
+#include <vector>
 
 #include "gz/common/graphics/Types.hh"
 #include "gz/common/AssimpLoader.hh"
@@ -462,22 +464,50 @@ MaterialPtr AssimpLoader::Implementation::CreateMaterial(
           "Roughness"));
       pbr.SetRoughnessMap(texName, texData);
     }
-    // Load lightmap only if it is not a glb/glTF mesh that contains a
-    // MetallicRoughness texture
-    // It was found that lightmap field just stores the entire MetallicRoughness
-    // texture. Issues were also reported in assimp:
-    // https://github.com/assimp/assimp/issues/3120
-    // https://github.com/assimp/assimp/issues/4637
-    unsigned int uvIdx = 0;
-    ret = assimpMat->GetTexture(
-        aiTextureType_LIGHTMAP, 0, &texturePath, NULL, &uvIdx);
-    if (ret == AI_SUCCESS)
+  }
+
+  // The lightmap / ambient occlusion texture may be the same texture as the
+  // metallicRoughness texture but it can also be a separate texture using a
+  // different uv index. In the former case, we expect the occlusion
+  // data to be packed in the R channel of the metallicRoughness texture,
+  // so load the occlusion data in the same ways as we do in the
+  // SplitMetallicRoughnessMap function.
+  // In the latter case (separate texture), no extra processing is
+  // required.
+  unsigned int uvIdx = 0;
+  ret = assimpMat->GetTexture(
+      aiTextureType_LIGHTMAP, 0, &texturePath, NULL, &uvIdx);
+  if (ret == AI_SUCCESS)
+  {
+    auto [texName, texData] = this->LoadTexture(_scene, texturePath,
+        this->GenerateTextureName(_fileBaseName, _scene, assimpMat,
+        "Lightmap"));
+    // Separate uv set so treat it as a separate texture
+    if (uvIdx > 0)
     {
-      auto [texName, texData] = this->LoadTexture(_scene, texturePath,
-          this->GenerateTextureName(_fileBaseName, _scene, assimpMat,
-          "Lightmap"));
       pbr.SetLightMap(texName, uvIdx, texData);
     }
+    // else split the occlusion data from the metallicRoughness texture
+    else
+    {
+      // R channel contains the occlusion data
+      // Note we are still creating an RGBA texture which seems watesful
+      // but that's what gz-rendering expects
+      auto origRGBAData = texData->RGBAData();
+      std::vector<unsigned char> texRData(origRGBAData.size());
+      for (unsigned int i = 0; i < origRGBAData.size(); i+=4)
+      {
+        auto r = origRGBAData.at(i);
+        texRData[i] = r;
+        texRData[i + 1] = r;
+        texRData[i + 2] = r;
+        texRData[i + 3] = 255;
+      }
+      auto tex = std::make_shared<Image>();
+      tex->SetFromData(&texRData[0], texData->Width(), texData->Height(),
+          Image::RGBA_INT8);
+      pbr.SetLightMap(texName, uvIdx, tex);
+    }
   }
 #endif
   ret = assimpMat->GetTexture(aiTextureType_NORMALS, 0, &texturePath);
@@ -650,14 +680,14 @@ SubMesh AssimpLoader::Implementation::CreateSubMesh(
     subMesh.AddVertex(vertex);
     subMesh.AddNormal(normal);
     // Iterate over sets of texture coordinates
-    int uvIdx = 0;
-    while(_assimpMesh->HasTextureCoords(uvIdx))
+    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
     {
+      if (!_assimpMesh->HasTextureCoords(i))
+        continue;
       math::Vector3d texcoords;
-      texcoords.X(_assimpMesh->mTextureCoords[uvIdx][vertexIdx].x);
-      texcoords.Y(_assimpMesh->mTextureCoords[uvIdx][vertexIdx].y);
-      subMesh.AddTexCoordBySet(texcoords.X(), texcoords.Y(), uvIdx);
-      ++uvIdx;
+      texcoords.X(_assimpMesh->mTextureCoords[i][vertexIdx].x);
+      texcoords.Y(_assimpMesh->mTextureCoords[i][vertexIdx].y);
+      subMesh.AddTexCoordBySet(texcoords.X(), texcoords.Y(), i);
     }
   }
   for (unsigned faceIdx = 0; faceIdx < _assimpMesh->mNumFaces; ++faceIdx)
diff --git a/graphics/src/ColladaLoader_TEST.cc b/graphics/src/ColladaLoader_TEST.cc
index 754f913d..3634b172 100644
--- a/graphics/src/ColladaLoader_TEST.cc
+++ b/graphics/src/ColladaLoader_TEST.cc
@@ -112,6 +112,7 @@ TEST_F(ColladaLoader, LoadZeroCount)
       common::testing::TestFile("data", "zero_count.dae"));
   ASSERT_TRUE(mesh);
 #ifndef _WIN32
+  common::Console::Root().RawLogger().flush();
   std::string log = LogContent();
 
   // Expect no errors about missing values
diff --git a/include/gz/common/Console.hh b/include/gz/common/Console.hh
index a188de20..b20dffec 100644
--- a/include/gz/common/Console.hh
+++ b/include/gz/common/Console.hh
@@ -77,7 +77,7 @@ namespace gz
 
     /// \brief Output a message to a log file.
     #define gzlog gz::common::LogMessage( \
-      __FILE__, __LINE__, spdlog::level::err).stream()
+      __FILE__, __LINE__, spdlog::level::trace).stream()
 
     /// \brief Output a message.
     #define gzmsg gz::common::LogMessage( \
diff --git a/src/Console_TEST.cc b/src/Console_TEST.cc
index 97d65c32..5c31b9ce 100644
--- a/src/Console_TEST.cc
+++ b/src/Console_TEST.cc
@@ -82,6 +82,7 @@ TEST_F(Console_TEST, NoInitAndLog)
   // Get the absolute log file path
   std::string logPath = ".gz/auto_default.log";
 
+  common::Console::Root().RawLogger().flush();
   // Expect to find the string in the log file
   EXPECT_TRUE(GetLogContent(logPath).find(logString) != std::string::npos);
 
@@ -118,6 +119,7 @@ TEST_F(Console_TEST, InitAndLog)
   // Get the absolute log file path
   std::string logPath = common::joinPaths(path, "test.log");
 
+  common::Console::Root().RawLogger().flush();
   // Expect to find the string in the log file
   EXPECT_TRUE(GetLogContent(logPath).find(logString) != std::string::npos);
 
@@ -149,6 +151,7 @@ TEST_F(Console_TEST, LogSlashN)
     gzlog << logString << " _n__ " << i << '\n';
   }
 
+  common::Console::Root().RawLogger().flush();
   std::string logContent = GetLogContent(logPath);
 
   for (int i = 0; i < g_messageRepeat; ++i)
@@ -179,6 +182,7 @@ TEST_F(Console_TEST, LogStdEndl)
     gzlog << logString << " endl " << i << std::endl;
   }
 
+  common::Console::Root().RawLogger().flush();
   std::string logContent = GetLogContent(logPath);
 
   for (int i = 0; i < g_messageRepeat; ++i)