Add BSGeometry bone weight loading from mesh data#61
Merged
ousnius merged 5 commits intoMay 17, 2026
Conversation
GetShapeBoneWeights had no path for BSGeometry shapes. Starfield meshes store per-vertex bone weights in BSGeometryMeshData::skinWeights as packed uint16 values (65535 = 1.0). Add a BSGeometry case that reads these weights, bridging the gap that caused all SF mesh vertices to appear unweighted in Outfit Studio. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends Starfield BSGeometry skinning support by teaching NifFile::GetShapeBoneWeights how to read per-vertex bone weights from BSGeometryMeshData::skinWeights, addressing cases where Starfield meshes previously appeared unweighted.
Changes:
- Add a
BSGeometrycode path inGetShapeBoneWeightsthat extracts weights fromBSGeometryMeshData::skinWeightsand normalizesuint16weights to floats. - Preserve existing behavior for
BSTriShapeandNiSkinInstance-backed shapes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review notes on the BSGeometry GetShapeBoneWeights path: - The vertex loop counter was uint16_t while skinWeights.size() is 32-bit, causing an infinite loop on meshes with more than 65535 vertices. Iterate with a size_t index capped at the uint16_t-keyed output map's range. - Add a Starfield regression test that loads the external mesh data and verifies GetShapeBoneWeights returns normalized weights in [0, 1]. https://claude.ai/code/session_01M73z1PscSn8M97dpyPYUW5
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
In tests/TestNifFile.cpp (BSGeometry bone weights test) replace structured bindings that returned full file tuples with std::get<0>() to only retrieve the input path (fileInput / meshFileInput). Add REQUIRE checks to ensure external mesh path lists and mesh path strings are not empty before attempting to open streams. These changes remove unused tuple elements and add safer assertions to avoid opening invalid paths during the test.
Replace hardcoded magic values (0x10000 and 65535) with constexpr derived from std::numeric_limits<uint16_t>::max(). Cap vertCount via std::min to avoid overflow on meshes with >65535 vertices and normalize bone weights by a named maxWeightValue. Improves clarity and avoids magic numbers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BSGeometrycase toGetShapeBoneWeightsthat reads per-vertex bone weights fromBSGeometryMeshData::skinWeights(packeduint16values where 65535 = 1.0)Context
Follow-up to PR #60 (merged). This commit was on the same branch but not included in that PR.
🤖 Generated with the help of Claude Code
@