From ea506019dc8b0f0574fb547b290b7de7d636b4cb Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 20:04:01 +0300 Subject: [PATCH] Reserve capacity for data NIF collections --- components/nif/data.cpp | 141 ++++++++++++++++++++++------------------ components/nif/data.hpp | 10 +-- 2 files changed, 81 insertions(+), 70 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 3351658090..ea4bb129c1 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -17,6 +17,24 @@ namespace Nif stream.read(weight); } + void readNiTriShapeDataMatchGroup(NIFStream& stream, std::vector& value) + { + stream.readVector(value, stream.get()); + } + + struct ReadNiGeometryDataUVSet + { + uint16_t mNumVertices; + + void operator()(NIFStream& stream, std::vector& value) const + { + stream.readVector(value, mNumVertices); + // Flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin + for (osg::Vec2f& uv : value) + uv.y() = 1.f - uv.y(); + } + }; + struct ReadNiSkinDataBoneInfo { bool mHasVertexWeights; @@ -46,6 +64,27 @@ namespace Nif stream.readVector(value.mVertices, mNumVerts); } }; + + struct ReadNiAdditionalGeometryDataDataBlock + { + bool mBSPacked; + + void operator()(NIFStream& stream, NiAdditionalGeometryData::DataBlock& value) const + { + stream.read(value.mValid); + if (!value.mValid) + return; + stream.read(value.mBlockSize); + stream.readVector(value.mBlockOffsets, stream.get()); + stream.readVector(value.mDataSizes, stream.get()); + stream.readVector(value.mData, value.mDataSizes.size() * value.mBlockSize); + if (!mBSPacked) + return; + + stream.read(value.mShaderIndex); + stream.read(value.mTotalSize); + } + }; } void NiGeometryData::read(NIFStream* nif) @@ -118,14 +157,8 @@ namespace Nif if (hasData) { - mUVList.resize(numUVs); - for (std::vector& list : mUVList) - { - nif->readVector(list, mNumVertices); - // flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin - for (osg::Vec2f& uv : list) - uv.y() = 1.f - uv.y(); - } + const ReadNiGeometryDataUVSet readUVSet{ .mNumVertices = mNumVertices }; + nif->readVectorOfRecords(numUVs, readUVSet, mUVList); } if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) @@ -152,9 +185,7 @@ namespace Nif if (nif->getVersion() > NIFFile::NIFVersion::VER_OB_OLD && !nif->get()) numIndices = 0; nif->readVector(mTriangles, numIndices); - mMatchGroups.resize(nif->get()); - for (auto& group : mMatchGroups) - nif->readVector(group, nif->get()); + nif->readVectorOfRecords(readNiTriShapeDataMatchGroup, mMatchGroups); } void NiTriStripsData::read(NIFStream* nif) @@ -165,11 +196,12 @@ namespace Nif nif->read(numStrips); std::vector lengths; nif->readVector(lengths, numStrips); - if (nif->getVersion() > NIFFile::NIFVersion::VER_OB_OLD && !nif->get()) - numStrips = 0; - mStrips.resize(numStrips); - for (int i = 0; i < numStrips; i++) - nif->readVector(mStrips[i], lengths[i]); + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD || nif->get()) + { + mStrips.reserve(numStrips); + for (size_t i = 0; i < numStrips; ++i) + nif->readVector(mStrips.emplace_back(), lengths[i]); + } } void NiLinesData::read(NIFStream* nif) @@ -403,19 +435,20 @@ namespace Nif mPartitions.post(nif); } + void BSSkinBoneData::BoneInfo::read(NIFStream* nif) + { + nif->read(mBoundSphere); + nif->read(mTransform); + } + void BSSkinBoneData::read(NIFStream* nif) { - mBones.resize(nif->get()); - for (BoneInfo& bone : mBones) - { - nif->read(bone.mBoundSphere); - nif->read(bone.mTransform); - } + nif->readVectorOfRecords(mBones); } void NiSkinPartition::read(NIFStream* nif) { - mPartitions.resize(nif->get()); + const uint32_t numPartitions = nif->get(); if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE) { @@ -423,13 +456,13 @@ namespace Nif nif->read(mVertexSize); mVertexDesc.read(nif); - mVertexData.resize(mDataSize / mVertexSize); - for (auto& vertexData : mVertexData) - vertexData.read(nif, mVertexDesc.mFlags); + uint32_t numVertices = mDataSize / mVertexSize; + mVertexData.reserve(numVertices); + for (uint32_t i = 0; i < numVertices; ++i) + mVertexData.emplace_back().read(nif, mVertexDesc.mFlags); } - for (auto& partition : mPartitions) - partition.read(nif); + nif->readVectorOfRecords(numPartitions, mPartitions); } void NiSkinPartition::Partition::read(NIFStream* nif) @@ -452,9 +485,9 @@ namespace Nif { if (numStrips) { - mStrips.resize(numStrips); - for (size_t i = 0; i < numStrips; i++) - nif->readVector(mStrips[i], stripLengths[i]); + mStrips.reserve(numStrips); + for (size_t i = 0; i < numStrips; ++i) + nif->readVector(mStrips.emplace_back(), stripLengths[i]); } else nif->readVector(mTriangles, numTriangles * 3); @@ -524,17 +557,15 @@ namespace Nif void NiPalette::read(NIFStream* nif) { - bool useAlpha = nif->get() != 0; - uint32_t alphaMask = useAlpha ? 0 : 0xFF000000; - - uint32_t numEntries; - nif->read(numEntries); - // Fill the entire palette with black even if there isn't enough entries. - mColors.resize(numEntries > 256 ? numEntries : 256); + const bool useAlpha = nif->get() != 0; + const uint32_t alphaMask = useAlpha ? 0 : 0xFF000000; + const uint32_t numEntries = nif->get(); for (uint32_t i = 0; i < numEntries; i++) { - nif->read(mColors[i]); - mColors[i] |= alphaMask; + const uint32_t color = nif->get(); + // Indices past 255 are always unused + if (i < 256) + mColors[i] = color | alphaMask; } } @@ -566,12 +597,10 @@ namespace Nif void NiAdditionalGeometryData::read(NIFStream* nif) { nif->read(mNumVertices); - mBlockInfos.resize(nif->get()); - for (DataStream& info : mBlockInfos) - info.read(nif); - mBlocks.resize(nif->get()); - for (DataBlock& block : mBlocks) - block.read(nif, recType == RC_BSPackedAdditionalGeometryData); + nif->readVectorOfRecords(mBlockInfos); + const ReadNiAdditionalGeometryDataDataBlock readDataBlock{ .mBSPacked + = recType == RC_BSPackedAdditionalGeometryData }; + nif->readVectorOfRecords(readDataBlock, mBlocks); } void NiAdditionalGeometryData::DataStream::read(NIFStream* nif) @@ -585,22 +614,6 @@ namespace Nif nif->read(mFlags); } - void NiAdditionalGeometryData::DataBlock::read(NIFStream* nif, bool bsPacked) - { - nif->read(mValid); - if (!mValid) - return; - nif->read(mBlockSize); - nif->readVector(mBlockOffsets, nif->get()); - nif->readVector(mDataSizes, nif->get()); - nif->readVector(mData, mDataSizes.size() * mBlockSize); - if (bsPacked) - { - nif->read(mShaderIndex); - nif->read(mTotalSize); - } - } - void BSMultiBound::read(NIFStream* nif) { mData.read(nif); @@ -646,9 +659,7 @@ namespace Nif void BSAnimNotes::read(NIFStream* nif) { - mList.resize(nif->get()); - for (auto& note : mList) - note.read(nif); + nif->readVectorOfRecords(mList); } void BSAnimNotes::post(Reader& nif) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 55ae92074a..6ce9c1229d 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -266,6 +266,8 @@ namespace Nif { osg::BoundingSpheref mBoundSphere; NiTransform mTransform; + + void read(NIFStream* nif); }; std::vector mBones; @@ -293,8 +295,8 @@ namespace Nif }; std::vector mPartitions; - unsigned int mDataSize; - unsigned int mVertexSize; + uint32_t mDataSize; + uint32_t mVertexSize; BSVertexDesc mVertexDesc; std::vector mVertexData; @@ -348,7 +350,7 @@ namespace Nif struct NiPalette : public Record { // 32-bit RGBA colors that correspond to 8-bit indices - std::vector mColors; + std::array mColors{}; void read(NIFStream* nif) override; }; @@ -406,8 +408,6 @@ namespace Nif std::vector mData; uint32_t mShaderIndex; uint32_t mTotalSize; - - void read(NIFStream* nif, bool bsPacked); }; uint16_t mNumVertices;