From 137382b4241ffcb659f8161b4e9b59c626f2048a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 19:09:22 +0300 Subject: [PATCH 1/5] Reserve capacity for physics NIF collections --- components/nif/physics.cpp | 87 +++++++++----------------------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp index 2b1a186ef7..ba69d8ed22 100644 --- a/components/nif/physics.cpp +++ b/components/nif/physics.cpp @@ -7,6 +7,13 @@ namespace Nif { + namespace + { + void readBoneTransformGroup(NIFStream& stream, std::vector& value) + { + stream.readVectorOfRecords(value); + } + } /// Non-record data types @@ -566,13 +573,7 @@ namespace Nif void bhkPackedNiTriStripsShape::read(NIFStream* nif) { if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB) - { - uint16_t numSubshapes; - nif->read(numSubshapes); - mSubshapes.resize(numSubshapes); - for (hkSubPartData& subshape : mSubshapes) - subshape.read(nif); - } + nif->readVectorOfRecords(mSubshapes); nif->read(mUserData); nif->skip(4); // Unused nif->read(mRadius); @@ -589,12 +590,7 @@ namespace Nif void hkPackedNiTriStripsData::read(NIFStream* nif) { - uint32_t numTriangles; - nif->read(numTriangles); - mTriangles.resize(numTriangles); - for (uint32_t i = 0; i < numTriangles; i++) - mTriangles[i].read(nif); - + nif->readVectorOfRecords(mTriangles); uint32_t numVertices; nif->read(numVertices); bool compressed = false; @@ -605,13 +601,7 @@ namespace Nif else nif->skip(6 * numVertices); // Half-precision vectors are not currently supported if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) - { - uint16_t numSubshapes; - nif->read(numSubshapes); - mSubshapes.resize(numSubshapes); - for (hkSubPartData& subshape : mSubshapes) - subshape.read(nif); - } + nif->readVectorOfRecords(mSubshapes); } void bhkSphereRepShape::read(NIFStream* nif) @@ -733,9 +723,7 @@ namespace Nif nif->read(mRadius); nif->skip(8); // Unknown nif->read(mScale); - mShapeProperties.resize(nif->get()); - for (bhkWorldObjCInfoProperty& property : mShapeProperties) - property.read(nif); + nif->readVectorOfRecords(mShapeProperties); nif->skip(12); // Unknown readRecordList(nif, mDataList); } @@ -759,11 +747,7 @@ namespace Nif mHavokMaterial.read(nif); mChildShapeProperty.read(nif); mChildFilterProperty.read(nif); - uint32_t numFilters; - nif->read(numFilters); - mHavokFilters.resize(numFilters); - for (HavokFilter& filter : mHavokFilters) - filter.read(nif); + nif->readVectorOfRecords(mHavokFilters); } void bhkListShape::post(Reader& nif) @@ -803,35 +787,12 @@ namespace Nif nif->skip(nif->get() * 4); // Unused nif->skip(nif->get() * 4); // Unused nif->skip(nif->get() * 4); // Unused - - uint32_t numMaterials; - nif->read(numMaterials); - mMaterials.resize(numMaterials); - for (bhkMeshMaterial& material : mMaterials) - material.read(nif); - + nif->readVectorOfRecords(mMaterials); nif->skip(4); // Unused - - uint32_t numTransforms; - nif->read(numTransforms); - mChunkTransforms.resize(numTransforms); - for (bhkQsTransform& transform : mChunkTransforms) - transform.read(nif); - + nif->readVectorOfRecords(mChunkTransforms); nif->readVector(mBigVerts, nif->get()); - - uint32_t numBigTriangles; - nif->read(numBigTriangles); - mBigTris.resize(numBigTriangles); - for (bhkCMSBigTri& tri : mBigTris) - tri.read(nif); - - uint32_t numChunks; - nif->read(numChunks); - mChunks.resize(numChunks); - for (bhkCMSChunk& chunk : mChunks) - chunk.read(nif); - + nif->readVectorOfRecords(mBigTris); + nif->readVectorOfRecords(mChunks); nif->skip(4); // Unused } @@ -910,9 +871,7 @@ namespace Nif if (numPivots % 2 != 0) throw Nif::Exception( "Invalid number of constraints in bhkBallSocketConstraintChain", nif->getFile().getFilename()); - mConstraints.resize(numPivots / 2); - for (bhkBallAndSocketConstraintCInfo& info : mConstraints) - info.read(nif); + nif->readVectorOfRecords(numPivots / 2, mConstraints); nif->read(mTau); nif->read(mDamping); nif->read(mConstraintForceMixing); @@ -1009,9 +968,7 @@ namespace Nif nif->read(mFriction); nif->read(mRadius); mHavokMaterial.read(nif); - mConstraints.resize(nif->get()); - for (bhkWrappedConstraintData& constraint : mConstraints) - constraint.read(nif); + nif->readVectorOfRecords(mConstraints); } void bhkPoseArray::BoneTransform::read(NIFStream* nif) @@ -1024,13 +981,7 @@ namespace Nif void bhkPoseArray::read(NIFStream* nif) { nif->readVector(mBones, nif->get()); - mPoses.resize(nif->get()); - for (std::vector& pose : mPoses) - { - pose.resize(nif->get()); - for (BoneTransform& transform : pose) - transform.read(nif); - } + nif->readVectorOfRecords(readBoneTransformGroup, mPoses); } } // Namespace From ea506019dc8b0f0574fb547b290b7de7d636b4cb Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 20:04:01 +0300 Subject: [PATCH 2/5] 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; From 7332b4e2328daa98ae742b1fbae44f8a5f7bceed Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 20:36:47 +0300 Subject: [PATCH 3/5] Reserve capacity for extra data NIF collections --- components/nif/extra.cpp | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp index a9f8f7994c..619d6ec243 100644 --- a/components/nif/extra.cpp +++ b/components/nif/extra.cpp @@ -64,11 +64,10 @@ namespace Nif { Extra::read(nif); - const uint32_t num = nif->get(); if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3) - nif->readVectorOfRecords(num, mLegacyMarkers); + nif->readVectorOfRecords(mLegacyMarkers); else - nif->readVectorOfRecords(num, mMarkers); + nif->readVectorOfRecords(mMarkers); } void BSInvMarker::read(NIFStream* nif) @@ -94,9 +93,7 @@ namespace Nif { Extra::read(nif); - mData.resize(nif->get()); - for (BoneLOD& lod : mData) - lod.read(nif); + nif->readVectorOfRecords(mData); } void BSBoneLODExtraData::BoneLOD::read(NIFStream* nif) @@ -109,9 +106,7 @@ namespace Nif { NiFloatExtraData::read(nif); - mBlocks.resize(nif->get()); - for (Block& block : mBlocks) - block.read(nif); + nif->readVectorOfRecords(mBlocks); } void BSDecalPlacementVectorExtraData::Block::read(NIFStream* nif) @@ -143,9 +138,7 @@ namespace Nif { NiExtraData::read(nif); - mPoints.resize(nif->get()); - for (Point& point : mPoints) - point.read(nif); + nif->readVectorOfRecords(mPoints); } void BSConnectPoint::Children::read(NIFStream* nif) @@ -179,9 +172,7 @@ namespace Nif nif->read(mLOD1TriOffset); nif->read(mLOD2TriCount); nif->read(mLOD2TriOffset); - mCombined.resize(nif->get()); - for (BSPackedGeomDataCombined& data : mCombined) - data.read(nif); + nif->readVectorOfRecords(mCombined); mVertexDesc.read(nif); } @@ -194,12 +185,8 @@ namespace Nif nif->read(mNumTriangles); nif->read(mFlags1); nif->read(mFlags2); - mObjects.resize(nif->get()); - for (BSPackedGeomObject& object : mObjects) - object.read(nif); - mObjectData.resize(mObjects.size()); - for (BSPackedSharedGeomData& objectData : mObjectData) - objectData.read(nif); + nif->readVectorOfRecords(mObjects); + nif->readVectorOfRecords(mObjects.size(), mObjectData); } } From 02d9c26289327878ec9cf213c70aee799d889808 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 22:17:29 +0300 Subject: [PATCH 4/5] Reserve capacity for node NIF collections --- components/nif/node.cpp | 89 +++++++++++++++++++---------------------- components/nif/node.hpp | 1 + 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 086d1969ae..7a91392d5d 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -63,6 +63,16 @@ namespace namespace Nif { + namespace + { + void readBSDistantObjectInstanceTransform(NIFStream& stream, osg::Matrixf& value) + { + std::array mat; + stream.readArray(mat); + value.set(mat.data()); + } + } + void BoundingVolume::read(NIFStream* nif) { nif->read(mType); @@ -200,12 +210,13 @@ namespace Nif { if (nif->getVersion() < NIFStream::generateVersion(10, 0, 1, 0)) return; + std::uint32_t numNames = 0; if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5)) - mNames.resize(nif->get()); + numNames = nif->get(); else if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3)) - mNames.resize(nif->get()); - nif->readVector(mNames, mNames.size()); - nif->readVector(mExtra, mNames.size()); + numNames = nif->get(); + nif->readVector(mNames, numNames); + nif->readVector(mExtra, numNames); if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5)) nif->read(mActive); if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) @@ -371,9 +382,7 @@ namespace Nif { NiTriShape::read(nif); - mSegments.resize(nif->get()); - for (SegmentData& segment : mSegments) - segment.read(nif); + nif->readVectorOfRecords(mSegments); } void BSLODTriShape::read(NIFStream* nif) @@ -540,17 +549,19 @@ namespace Nif mAlphaProperty.read(nif); mVertDesc.read(nif); + size_t numTriangleIndices; if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4) - mTriangles.resize(nif->get() * 3); + numTriangleIndices = nif->get() * 3; else - mTriangles.resize(nif->get() * 3); - mVertData.resize(nif->get()); + numTriangleIndices = nif->get() * 3; + nif->read(mNumVertices); + mVertData.reserve(mNumVertices); nif->read(mDataSize); if (mDataSize > 0) { - for (auto& vertex : mVertData) - vertex.read(nif, mVertDesc.mFlags); - nif->readVector(mTriangles, mTriangles.size()); + for (uint16_t i = 0; i < mNumVertices; ++i) + mVertData.emplace_back().read(nif, mVertDesc.mFlags); + nif->readVector(mTriangles, numTriangleIndices); } if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE) @@ -558,9 +569,9 @@ namespace Nif nif->read(mParticleDataSize); if (mParticleDataSize > 0) { - nif->readVector(mParticleVerts, mVertData.size() * 3); - nif->readVector(mParticleNormals, mVertData.size() * 3); - nif->readVector(mParticleTriangles, mTriangles.size()); + nif->readVector(mParticleVerts, mNumVertices * 3); + nif->readVector(mParticleNormals, mNumVertices * 3); + nif->readVector(mParticleTriangles, numTriangleIndices); } } } @@ -582,8 +593,8 @@ namespace Nif nif->read(mDynamicDataSize); // nifly style. - // Consider complaining if mDynamicDataSize * 16 != mVertData.size()? - nif->readVector(mDynamicData, mVertData.size()); + // Consider complaining if mDynamicDataSize * 16 != mNumVertices? + nif->readVector(mDynamicData, mNumVertices); } void BSMeshLODTriShape::read(NIFStream* nif) @@ -606,9 +617,7 @@ namespace Nif nif->read(mStartIndex); nif->read(mNumPrimitives); nif->read(mParentArrayIndex); - mSubSegments.resize(nif->get()); - for (SubSegment& subsegment : mSubSegments) - subsegment.read(nif); + nif->readVectorOfRecords(mSubSegments); } void BSSubIndexTriShape::SubSegmentDataRecord::read(NIFStream* nif) @@ -622,22 +631,19 @@ namespace Nif { uint32_t numArrayIndices; nif->read(numArrayIndices); - mDataRecords.resize(nif->get()); + const uint32_t numRecords = nif->get(); nif->readVector(mArrayIndices, numArrayIndices); - for (SubSegmentDataRecord& dataRecord : mDataRecords) - dataRecord.read(nif); + nif->readVectorOfRecords(numRecords, mDataRecords); mSSFFile = nif->getSizedString(nif->get()); } void BSSubIndexTriShape::Segmentation::read(NIFStream* nif) { nif->read(mNumPrimitives); - mSegments.resize(nif->get()); + const uint32_t numSegments = nif->get(); nif->read(mNumTotalSegments); - for (Segment& segment : mSegments) - segment.read(nif); - - if (mSegments.size() < mNumTotalSegments) + nif->readVectorOfRecords(numSegments, mSegments); + if (numSegments < mNumTotalSegments) mSubSegmentData.read(nif); } @@ -646,11 +652,7 @@ namespace Nif BSTriShape::read(nif); if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE) - { - mSegments.resize(nif->get()); - for (BSSegmentedTriShape::SegmentData& segment : mSegments) - segment.read(nif); - } + nif->readVectorOfRecords(mSegments); else if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4 && mDataSize > 0) mSegmentation.read(nif); } @@ -752,30 +754,23 @@ namespace Nif { mResourceID.read(nif); nif->skip(12 * nif->get()); // Unknown data - mTransforms.resize(nif->get()); - for (osg::Matrixf& transform : mTransforms) - { - std::array mat; - nif->readArray(mat); - transform.set(mat.data()); - } + nif->readVectorOfRecords(readBSDistantObjectInstanceTransform, mTransforms); } void BSShaderTextureArray::read(NIFStream* nif) { nif->skip(1); // Unknown - mTextureArrays.resize(nif->get()); - for (std::vector& textureArray : mTextureArrays) - nif->getSizedStrings(textureArray, nif->get()); + const uint32_t numArrays = nif->get(); + mTextureArrays.reserve(numArrays); + for (uint32_t i = 0; i < numArrays; ++i) + nif->getSizedStrings(mTextureArrays.emplace_back(), nif->get()); } void BSDistantObjectInstancedNode::read(NIFStream* nif) { BSMultiBoundNode::read(nif); - mInstances.resize(nif->get()); - for (BSDistantObjectInstance& instance : mInstances) - instance.read(nif); + nif->readVectorOfRecords(mInstances); for (BSShaderTextureArray& textureArray : mShaderTextureArrays) textureArray.read(nif); } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 86a75bb287..c2d92c7f88 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -385,6 +385,7 @@ namespace Nif NiAlphaPropertyPtr mAlphaProperty; BSVertexDesc mVertDesc; uint32_t mDataSize; + uint16_t mNumVertices; std::vector mVertData; std::vector mTriangles; uint32_t mParticleDataSize; From 3927eaef6640c539f972310a4e306942c1819117 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 14 Dec 2025 22:31:12 +0300 Subject: [PATCH 5/5] Reserve capacity for controller NIF collections --- components/nif/controller.cpp | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index b70b8c16a7..af81f5d124 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -211,10 +211,9 @@ namespace Nif nif->read(mSpawnMultiplier); nif->read(mSpawnSpeedChaos); nif->read(mSpawnDirChaos); - mParticles.resize(nif->get()); + const uint16_t numParticles = nif->get(); nif->read(mNumValid); - for (NiParticleInfo& particle : mParticles) - particle.read(nif); + nif->readVectorOfRecords(numParticles, mParticles); nif->skip(4); // NiEmitterModifier link } mModifier.read(nif); @@ -347,9 +346,7 @@ namespace Nif { NiInterpController::read(nif); - mExtraTargets.resize(nif->get()); - for (NiAVObjectPtr& extraTarget : mExtraTargets) - extraTarget.read(nif); + nif->readVectorOfRecords(mExtraTargets); } void NiMultiTargetTransformController::post(Reader& nif) @@ -413,12 +410,13 @@ namespace Nif return; } - mInterpolators.resize(nif->get()); - mWeights.resize(mInterpolators.size()); - for (size_t i = 0; i < mInterpolators.size(); i++) + const uint32_t numInterpolators = nif->get(); + mInterpolators.reserve(numInterpolators); + mWeights.reserve(numInterpolators); + for (size_t i = 0; i < numInterpolators; ++i) { - mInterpolators[i].read(nif); - nif->read(mWeights[i]); + mInterpolators.emplace_back().read(nif); + nif->read(mWeights.emplace_back()); } } @@ -733,7 +731,7 @@ namespace Nif if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112)) { nif->read(mFlags); - mItems.resize(nif->get()); + const uint8_t numItems = nif->get(); nif->read(mWeightThreshold); if (!(mFlags & Flag_ManagerControlled)) { @@ -745,17 +743,14 @@ namespace Nif nif->read(mHighWeightsSum); nif->read(mNextHighWeightsSum); nif->read(mHighEaseSpinner); - for (Item& item : mItems) - item.read(nif); + nif->readVectorOfRecords(numItems, mItems); } return; } if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 110)) { - mItems.resize(nif->get()); - for (Item& item : mItems) - item.read(nif); + nif->readVectorOfRecords(mItems); if (nif->get()) mFlags |= Flag_ManagerControlled; nif->read(mWeightThreshold); @@ -770,10 +765,9 @@ namespace Nif return; } - mItems.resize(nif->get()); + const uint16_t numItems = nif->get(); nif->read(mArrayGrowBy); - for (Item& item : mItems) - item.read(nif); + nif->readVectorOfRecords(numItems, mItems); if (nif->get()) mFlags |= Flag_ManagerControlled; nif->read(mWeightThreshold);