diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8ef95507..b38d89e6 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -14,12 +14,12 @@ These instructions define how GitHub Copilot should assist with this project. Th - See the tutorial at [Getting Started](https://github.com/microsoft/DirectXMesh/wiki/Getting-Started). - The recommended way to integrate *DirectXMesh* into your project is by using the *vcpkg* Package Manager. -- You can make use of the nuget.org packages **directxmesh_desktop_2019**, **directxmesh_desktop_win10**, or **directxmesh_uwp**. +- You can make use of the nuget.org packages **directxmesh_desktop_win10** or **directxmesh_uwp**. - You can also use the library source code directly in your project or as a git submodule. ## General Guidelines -- **Code Style**: The project uses an .editorconfig file to enforce coding standards. Follow the rules defined in `.editorconfig` for indentation, line endings, and other formatting. Additional information can be found on the wiki at [Implementation](https://github.com/microsoft/DirectXTK/wiki/Implementation). The library implementation is written to be compatible with C++14 features, but C++17 is required to build the project for the command-line tools which utilize C++17 filesystem for long file path support. +- **Code Style**: The project uses an .editorconfig file to enforce coding standards. Follow the rules defined in `.editorconfig` for indentation, line endings, and other formatting. Additional information can be found on the wiki at [Implementation](https://github.com/microsoft/DirectXTK/wiki/Implementation). The library's public API requires C++11, and the project builds with C++17 (`CMAKE_CXX_STANDARD 17`). The command-line tools utilize C++17 filesystem for long file path support. > Notable `.editorconfig` rules: C/C++ files use 4-space indentation, `crlf` line endings, and `latin1` charset — avoid non-ASCII characters in source files. HLSL files have separate indent/spacing rules defined in `.editorconfig`. - **Documentation**: The project provides documentation in the form of wiki pages available at [Documentation](https://github.com/microsoft/DirectXMesh/wiki/). - **Error Handling**: Use C++ exceptions for error handling and uses RAII smart pointers to ensure resources are properly managed. For some functions that return HRESULT error codes, they are marked `noexcept`, use `std::nothrow` for memory allocation, and should not throw exceptions. @@ -110,12 +110,13 @@ HRESULT DirectX::ComputeNormals( #### `noexcept` Rules - All query and utility functions that cannot fail (e.g., `IsValidVB`, `IsValidIB`) are marked `noexcept`. -- All HRESULT-returning I/O and processing functions are also `noexcept` — errors are communicated via return code, never via exceptions. +- HRESULT-returning functions that do not perform heap allocation or use Standard C++ containers are `noexcept` — errors are communicated via return code, never via exceptions (e.g., `ComputeNormals`, `ReorderIB`, `FinalizeIB`, `FinalizeVB`, `CompactVB`, `OptimizeVertices`, `ComputeCullData`). +- HRESULT-returning functions that use `std::vector`, `std::function`, or other potentially throwing types are *not* marked `noexcept` — they may throw on allocation failure (e.g., `GenerateAdjacencyAndPointReps`, `Validate`, `Clean`, `WeldVertices`, `ComputeMeshlets`, `OptimizeFaces`). - Constructors and functions that perform heap allocation or utilize Standard C++ containers that may throw are marked `noexcept(false)`. #### Enum Flags Pattern -Flags enums follow this pattern — a `uint32_t`-based unscoped enum with a `_NONE = 0x0` base case, followed by a call to `DEFINE_ENUM_FLAG_OPERATORS` (defined in `DirectXMesh.inl`) to enable `|`, `&`, and `~` operators: +Flags enums follow this pattern — a `uint32_t`-based unscoped enum with a `_DEFAULT = 0x0` base case, followed by a call to `DEFINE_ENUM_FLAG_OPERATORS` (defined in `DirectXMesh.inl`) to enable `|`, `&`, and `~` operators: ```cpp enum CNORM_FLAGS : uint32_t @@ -223,6 +224,7 @@ When creating documentation: - The code supports building for Windows and Linux. - Portability and conformance of the code is validated by building with Visual C++, clang/LLVM for Windows, MinGW, and GCC for Linux compilers. +- The project ships MSBuild projects for Visual Studio 2022 (`.sln` / `.vcxproj`) and Visual Studio 2026 (`.slnx` / `.vcxproj`). VS 2019 projects have been retired. ### Platform and Compiler `#ifdef` Guards @@ -235,6 +237,7 @@ Use these established guards — do not invent new ones: | `_GAMING_XBOX_SCARLETT` | Xbox Series X\|S | | `_XBOX_ONE && _TITLE` | Legacy Xbox One XDK — **no longer supported**; triggers a `#error` at compile time | | `_MSC_VER` | MSVC-specific (and MSVC-like clang-cl) pragmas and warning suppression | +| `__INTEL_COMPILER` | Intel C++ Compiler classic warning suppression | | `__clang__` | Clang/LLVM diagnostic suppressions | | `__MINGW32__` | MinGW compatibility headers | | `__GNUC__` | MinGW/GCC DLL attribute equivalents | @@ -256,6 +259,7 @@ The following symbols are not custom error codes, but aliases for `HRESULT_FROM_ | `HRESULT_E_ARITHMETIC_OVERFLOW` | `HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)` | | `HRESULT_E_NOT_SUPPORTED` | `HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)` | | `HRESULT_E_INVALID_NAME` | `HRESULT_FROM_WIN32(ERROR_INVALID_NAME)` | +| `E_BOUNDS` | `0x8000000BL` (conditionally defined if not already present) | ## Code Review Instructions diff --git a/DirectXMesh/DirectXMesh.h b/DirectXMesh/DirectXMesh.h index 3eef83fb..25106acd 100644 --- a/DirectXMesh/DirectXMesh.h +++ b/DirectXMesh/DirectXMesh.h @@ -426,48 +426,48 @@ namespace DirectX }; DIRECTX_MESH_API HRESULT __cdecl OptimizeFaces( - _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t vertexCache = OPTFACES_V_DEFAULT, _In_ uint32_t restart = OPTFACES_R_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFaces( - _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t vertexCache = OPTFACES_V_DEFAULT, _In_ uint32_t restart = OPTFACES_R_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesLRU( - _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t lruCacheSize = OPTFACES_LRU_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesLRU( - _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t lruCacheSize = OPTFACES_LRU_DEFAULT); // Reorders faces to increase hit rate of vertex caches DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesEx( - _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _In_reads_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t vertexCache = OPTFACES_V_DEFAULT, _In_ uint32_t restart = OPTFACES_R_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesEx( - _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _In_reads_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t vertexCache = OPTFACES_V_DEFAULT, _In_ uint32_t restart = OPTFACES_R_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesLRUEx( - _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint16_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t lruCacheSize = OPTFACES_LRU_DEFAULT); DIRECTX_MESH_API HRESULT __cdecl OptimizeFacesLRUEx( - _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const uint32_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap, _In_ uint32_t lruCacheSize = OPTFACES_LRU_DEFAULT); diff --git a/DirectXMesh/DirectXMeshOptimizeLRU.cpp b/DirectXMesh/DirectXMeshOptimizeLRU.cpp index 7277b6fa..f32cca35 100644 --- a/DirectXMesh/DirectXMeshOptimizeLRU.cpp +++ b/DirectXMesh/DirectXMeshOptimizeLRU.cpp @@ -194,7 +194,7 @@ namespace template HRESULT OptimizeFacesImpl( - _In_reads_(indexCount) const IndexType* indexList, uint32_t indexCount, + _In_reads_(indexCount) const IndexType* indexList, uint32_t indexCount, size_t nVerts, _Out_writes_(indexCount / 3) uint32_t* faceRemap, uint32_t lruCacheSize, uint32_t offset) { std::unique_ptr[]> vertexDataList(new (std::nothrow) OptimizeVertexData[indexCount]); @@ -245,6 +245,9 @@ namespace continue; } + if (indexList[idx] >= nVerts) + return E_UNEXPECTED; + if (!i || first || sortFunc(indexSorted[i - 1], idx)) { // it's not a duplicate @@ -510,10 +513,11 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesLRU( const uint16_t* indices, size_t nFaces, + size_t nVerts, uint32_t* faceRemap, uint32_t lruCacheSize) { - if (!indices || !nFaces || !faceRemap) + if (!indices || !nFaces || !nVerts || !faceRemap) return E_INVALIDARG; if (!lruCacheSize || lruCacheSize > kMaxVertexCacheSize) @@ -528,17 +532,18 @@ HRESULT DirectX::OptimizeFacesLRU( std::call_once(s_initOnce, ComputeVertexScores); #endif - return OptimizeFacesImpl(indices, static_cast(nFaces * 3), faceRemap, lruCacheSize, 0); + return OptimizeFacesImpl(indices, static_cast(nFaces * 3), nVerts, faceRemap, lruCacheSize, 0); } _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesLRU( const uint32_t* indices, size_t nFaces, + size_t nVerts, uint32_t* faceRemap, uint32_t lruCacheSize) { - if (!indices || !nFaces || !faceRemap) + if (!indices || !nFaces || !nVerts || !faceRemap) return E_INVALIDARG; if (!lruCacheSize || lruCacheSize > kMaxVertexCacheSize) @@ -553,7 +558,7 @@ HRESULT DirectX::OptimizeFacesLRU( std::call_once(s_initOnce, ComputeVertexScores); #endif - return OptimizeFacesImpl(indices, static_cast(nFaces * 3), faceRemap, lruCacheSize, 0); + return OptimizeFacesImpl(indices, static_cast(nFaces * 3), nVerts, faceRemap, lruCacheSize, 0); } @@ -562,11 +567,12 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesLRUEx( const uint16_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* attributes, uint32_t* faceRemap, uint32_t lruCacheSize) { - if (!indices || !nFaces || !attributes || !faceRemap) + if (!indices || !nFaces || !nVerts || !attributes || !faceRemap) return E_INVALIDARG; if (!lruCacheSize || lruCacheSize > kMaxVertexCacheSize) @@ -602,7 +608,7 @@ HRESULT DirectX::OptimizeFacesLRUEx( return E_UNEXPECTED; HRESULT hr = OptimizeFacesImpl( - &indices[it.first * 3], static_cast(it.second * 3), + &indices[it.first * 3], static_cast(it.second * 3), nVerts, &faceRemap[it.first], lruCacheSize, uint32_t(it.first)); if (FAILED(hr)) return hr; @@ -615,11 +621,12 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesLRUEx( const uint32_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* attributes, uint32_t* faceRemap, uint32_t lruCacheSize) { - if (!indices || !nFaces || !attributes || !faceRemap) + if (!indices || !nFaces || !nVerts || !attributes || !faceRemap) return E_INVALIDARG; if (!lruCacheSize || lruCacheSize > kMaxVertexCacheSize) @@ -655,7 +662,7 @@ HRESULT DirectX::OptimizeFacesLRUEx( return E_UNEXPECTED; HRESULT hr = OptimizeFacesImpl( - &indices[it.first * 3], static_cast(it.second * 3), + &indices[it.first * 3], static_cast(it.second * 3), nVerts, &faceRemap[it.first], lruCacheSize, uint32_t(it.first)); if (FAILED(hr)) return hr; diff --git a/DirectXMesh/DirectXMeshOptimizeTVC.cpp b/DirectXMesh/DirectXMeshOptimizeTVC.cpp index ca79e145..8c87e09c 100644 --- a/DirectXMesh/DirectXMeshOptimizeTVC.cpp +++ b/DirectXMesh/DirectXMeshOptimizeTVC.cpp @@ -31,7 +31,9 @@ namespace {} HRESULT initialize( - _In_reads_(nFaces * 3) const index_t* indices, size_t nFaces, + _In_reads_(nFaces * 3) const index_t* indices, + size_t nFaces, + size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, const std::vector>& subsets) { @@ -74,7 +76,13 @@ namespace index_t i1 = indices[face * 3 + 1]; index_t i2 = indices[face * 3 + 2]; - if (i0 == index_t(-1) + if ((i0 != index_t(-1) && i0 >= nVerts) + || (i1 != index_t(-1) && i1 >= nVerts) + || (i2 != index_t(-1) && i2 >= nVerts)) + { + return E_UNEXPECTED; + } + else if (i0 == index_t(-1) || i1 == index_t(-1) || i2 == index_t(-1) || i0 == i1 @@ -163,7 +171,7 @@ namespace } HRESULT setSubset( - _In_reads_(nFaces * 3) const index_t* indices, size_t nFaces, + _In_reads_(nFaces * 3) const index_t* indices, size_t nFaces, size_t nVerts, size_t faceOffset, size_t faceCount) noexcept { if (!indices || !mListElements) @@ -202,6 +210,11 @@ namespace continue; } + if (i0 >= nVerts + || i1 >= nVerts + || i2 >= nVerts) + return E_UNEXPECTED; + uint32_t unprocessed = 0; for (uint32_t n = 0; n < 3; ++n) @@ -508,7 +521,7 @@ namespace //--------------------------------------------------------------------------------- template HRESULT StripReorderImpl( - _In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _In_reads_opt_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap) @@ -518,7 +531,7 @@ namespace return E_UNEXPECTED; mesh_status status; - HRESULT hr = status.initialize(indices, nFaces, adjacency, subsets); + HRESULT hr = status.initialize(indices, nFaces, nVerts, adjacency, subsets); if (FAILED(hr)) return hr; @@ -530,7 +543,7 @@ namespace for (const auto& it : subsets) { - hr = status.setSubset(indices, nFaces, it.first, it.second); + hr = status.setSubset(indices, nFaces, nVerts, it.first, it.second); if (FAILED(hr)) return hr; @@ -585,7 +598,7 @@ namespace //--------------------------------------------------------------------------------- template HRESULT VertexCacheStripReorderImpl( - _In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces, + _In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces, _In_ size_t nVerts, _In_reads_(nFaces * 3) const uint32_t* adjacency, _In_reads_opt_(nFaces) const uint32_t* attributes, _Out_writes_(nFaces) uint32_t* faceRemap, @@ -596,7 +609,7 @@ namespace return E_UNEXPECTED; mesh_status status; - HRESULT hr = status.initialize(indices, nFaces, adjacency, subsets); + HRESULT hr = status.initialize(indices, nFaces, nVerts, adjacency, subsets); if (FAILED(hr)) return hr; @@ -616,7 +629,7 @@ namespace for (const auto& it : subsets) { - hr = status.setSubset(indices, nFaces, it.first, it.second); + hr = status.setSubset(indices, nFaces, nVerts, it.first, it.second); if (FAILED(hr)) return hr; @@ -771,12 +784,13 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFaces( const uint16_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* adjacency, uint32_t* faceRemap, uint32_t vertexCache, uint32_t restart) { - if (!indices || !nFaces || !adjacency || !faceRemap) + if (!indices || !nFaces || !nVerts || !adjacency || !faceRemap) return E_INVALIDARG; if ((uint64_t(nFaces) * 3) >= UINT32_MAX) @@ -784,14 +798,14 @@ HRESULT DirectX::OptimizeFaces( if (vertexCache == OPTFACES_V_STRIPORDER) { - return StripReorderImpl(indices, nFaces, adjacency, nullptr, faceRemap); + return StripReorderImpl(indices, nFaces, nVerts, adjacency, nullptr, faceRemap); } else { if (restart > vertexCache) return E_INVALIDARG; - return VertexCacheStripReorderImpl(indices, nFaces, adjacency, nullptr, faceRemap, vertexCache, restart); + return VertexCacheStripReorderImpl(indices, nFaces, nVerts, adjacency, nullptr, faceRemap, vertexCache, restart); } } @@ -799,12 +813,13 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFaces( const uint32_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* adjacency, uint32_t* faceRemap, uint32_t vertexCache, uint32_t restart) { - if (!indices || !nFaces || !adjacency || !faceRemap) + if (!indices || !nFaces || !nVerts || !adjacency || !faceRemap) return E_INVALIDARG; if ((uint64_t(nFaces) * 3) >= UINT32_MAX) @@ -812,14 +827,14 @@ HRESULT DirectX::OptimizeFaces( if (vertexCache == OPTFACES_V_STRIPORDER) { - return StripReorderImpl(indices, nFaces, adjacency, nullptr, faceRemap); + return StripReorderImpl(indices, nFaces, nVerts, adjacency, nullptr, faceRemap); } else { if (restart > vertexCache) return E_INVALIDARG; - return VertexCacheStripReorderImpl(indices, nFaces, adjacency, nullptr, faceRemap, vertexCache, restart); + return VertexCacheStripReorderImpl(indices, nFaces, nVerts, adjacency, nullptr, faceRemap, vertexCache, restart); } } @@ -829,13 +844,14 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesEx( const uint16_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* adjacency, const uint32_t* attributes, uint32_t* faceRemap, uint32_t vertexCache, uint32_t restart) { - if (!indices || !nFaces || !adjacency || !attributes || !faceRemap) + if (!indices || !nFaces || !nVerts || !adjacency || !attributes || !faceRemap) return E_INVALIDARG; if ((uint64_t(nFaces) * 3) >= UINT32_MAX) @@ -843,14 +859,14 @@ HRESULT DirectX::OptimizeFacesEx( if (vertexCache == OPTFACES_V_STRIPORDER) { - return StripReorderImpl(indices, nFaces, adjacency, attributes, faceRemap); + return StripReorderImpl(indices, nFaces, nVerts, adjacency, attributes, faceRemap); } else { if (restart > vertexCache) return E_INVALIDARG; - return VertexCacheStripReorderImpl(indices, nFaces, adjacency, attributes, faceRemap, vertexCache, restart); + return VertexCacheStripReorderImpl(indices, nFaces, nVerts, adjacency, attributes, faceRemap, vertexCache, restart); } } @@ -858,13 +874,14 @@ _Use_decl_annotations_ HRESULT DirectX::OptimizeFacesEx( const uint32_t* indices, size_t nFaces, + size_t nVerts, const uint32_t* adjacency, const uint32_t* attributes, uint32_t* faceRemap, uint32_t vertexCache, uint32_t restart) { - if (!indices || !nFaces || !adjacency || !attributes || !faceRemap) + if (!indices || !nFaces || !nVerts || !adjacency || !attributes || !faceRemap) return E_INVALIDARG; if ((uint64_t(nFaces) * 3) >= UINT32_MAX) @@ -872,13 +889,13 @@ HRESULT DirectX::OptimizeFacesEx( if (vertexCache == OPTFACES_V_STRIPORDER) { - return StripReorderImpl(indices, nFaces, adjacency, attributes, faceRemap); + return StripReorderImpl(indices, nFaces, nVerts, adjacency, attributes, faceRemap); } else { if (restart > vertexCache) return E_INVALIDARG; - return VertexCacheStripReorderImpl(indices, nFaces, adjacency, attributes, faceRemap, vertexCache, restart); + return VertexCacheStripReorderImpl(indices, nFaces, nVerts, adjacency, attributes, faceRemap, vertexCache, restart); } } diff --git a/Meshconvert/Mesh.cpp b/Meshconvert/Mesh.cpp index f5c391d7..59574885 100644 --- a/Meshconvert/Mesh.cpp +++ b/Meshconvert/Mesh.cpp @@ -654,20 +654,20 @@ HRESULT Mesh::Optimize(bool lru) noexcept // Optimize faces for pre-transform vertex cache if (lru) { - hr = OptimizeFacesLRUEx(mIndices.get(), mnFaces, mAttributes.get(), remap.get()); + hr = OptimizeFacesLRUEx(mIndices.get(), mnFaces, mnVerts, mAttributes.get(), remap.get()); } else { - hr = OptimizeFacesEx(mIndices.get(), mnFaces, mAdjacency.get(), mAttributes.get(), remap.get()); + hr = OptimizeFacesEx(mIndices.get(), mnFaces, mnVerts, mAdjacency.get(), mAttributes.get(), remap.get()); } } else if (lru) { - hr = OptimizeFacesLRU(mIndices.get(), mnFaces, remap.get()); + hr = OptimizeFacesLRU(mIndices.get(), mnFaces, mnVerts, remap.get()); } else { - hr = OptimizeFaces(mIndices.get(), mnFaces, mAdjacency.get(), remap.get()); + hr = OptimizeFaces(mIndices.get(), mnFaces, mnVerts, mAdjacency.get(), remap.get()); } if (FAILED(hr)) return hr;