From e654a52b70a006e335aea2ccefde13a6f22a1405 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Sun, 29 Dec 2019 15:53:44 +0300 Subject: [PATCH 1/4] More NIF adjustments Constant interpolation support --- components/nif/data.cpp | 18 +++-- components/nif/niffile.cpp | 17 +---- components/nif/niffile.hpp | 68 +++++++++++++++--- components/nif/nifkey.hpp | 61 ++++++++-------- components/nif/nifstream.cpp | 17 +++++ components/nif/nifstream.hpp | 48 ++++++++++++- components/nif/node.hpp | 2 +- components/nif/property.cpp | 2 +- components/nif/recordptr.hpp | 1 + components/nifosg/controller.hpp | 117 ++++++++++++++++--------------- components/nifosg/nifloader.cpp | 14 ++-- components/nifosg/particle.hpp | 1 - 12 files changed, 236 insertions(+), 130 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 4e1487f695..cde8e58765 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -35,16 +35,16 @@ void ShapeData::read(NIFStream *nif) { int verts = nif->getUShort(); - if(nif->getInt()) + if (nif->getBoolean()) nif->getVector3s(vertices, verts); - if(nif->getInt()) + if (nif->getBoolean()) nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); - if(nif->getInt()) + if (nif->getBoolean()) nif->getVector4s(colors, verts); // Only the first 6 bits are used as a count. I think the rest are @@ -120,7 +120,7 @@ void NiAutoNormalParticlesData::read(NIFStream *nif) particleRadius = nif->getFloat(); activeCount = nif->getUShort(); - if(nif->getInt()) + if (nif->getBoolean()) { // Particle sizes nif->getFloats(sizes, vertices.size()); @@ -131,7 +131,7 @@ void NiRotatingParticlesData::read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); - if(nif->getInt()) + if (nif->getBoolean()) { // Rotation quaternions. nif->getQuaternions(rotations, vertices.size()); @@ -176,7 +176,7 @@ void NiPixelData::read(NIFStream *nif) numberOfMipmaps = nif->getUInt(); - // Bytes per pixel, should be bpp * 8 + // Bytes per pixel, should be bpp / 8 /* int bytes = */ nif->getUInt(); for(unsigned int i=0; igetInt(); // -1 bones.resize(boneNum); - for(int i=0;igetMatrix3(); bi.trafo.pos = nif->getVector3(); bi.trafo.scale = nif->getFloat(); @@ -267,7 +265,7 @@ void NiKeyframeData::read(NIFStream *nif) { mRotations = std::make_shared(); mRotations->read(nif); - if(mRotations->mInterpolationType == Vector3KeyMap::sXYZInterpolation) + if(mRotations->mInterpolationType == Vector3KeyMap::XYZ) { //Chomp unused float nif->getFloat(); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index d4f1203cc3..bced4d8e2a 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -9,9 +9,7 @@ namespace Nif /// Open a NIF stream. The name is used for error messages. NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) - : ver(0) - , filename(name) - , mUseSkinning(false) + : filename(name) { parse(stream); } @@ -139,27 +137,18 @@ void NIFFile::parse(Files::IStreamPtr stream) // Check the header string std::string head = nif.getVersionString(); if(head.compare(0, 22, "NetImmerse File Format") != 0) - fail("Invalid NIF header: " + head); + fail("Invalid NIF header: " + head); // Get BCD version ver = nif.getUInt(); // 4.0.0.0 is an older, practically identical version of the format. // It's not used by Morrowind assets but Morrowind supports it. - if(ver != 0x04000000 && ver != VER_MW) + if(ver != VER_4_0_0_0 && ver != VER_MW) fail("Unsupported NIF version: " + printVersion(ver)); // Number of records size_t recNum = nif.getInt(); records.resize(recNum); - /* The format for 10.0.1.0 seems to be a bit different. After the - header, it contains the number of records, r (int), just like - 4.0.0.2, but following that it contains a short x, followed by x - strings. Then again by r shorts, one for each record, giving - which of the above strings to use to identify the record. After - this follows two ints (zero?) and then the record data. However - we do not support or plan to support other versions yet. - */ - for(size_t i = 0;i < recNum;i++) { Record *r = nullptr; diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 15001f5113..a85e46ea5e 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -26,21 +26,27 @@ struct File virtual size_t numRoots() const = 0; + virtual std::string getString(size_t index) const = 0; + virtual void setUseSkinning(bool skinning) = 0; virtual bool getUseSkinning() const = 0; virtual std::string getFilename() const = 0; + + virtual unsigned int getVersion() const = 0; + + virtual unsigned int getUserVersion() const = 0; + + virtual unsigned int getBethVersion() const = 0; }; class NIFFile final : public File { - enum NIFVersion { - VER_MW = 0x04000002 // Morrowind NIFs - }; - - /// Nif file version - unsigned int ver; + /// File version, user version, Bethesda version + unsigned int ver = 0; + unsigned int userVer = 0; + unsigned int bethVer = 0; /// File name, used for error messages and opening the file std::string filename; @@ -51,7 +57,10 @@ class NIFFile final : public File /// Root list. This is a select portion of the pointers from records std::vector roots; - bool mUseSkinning; + /// String table + std::vector strings; + + bool mUseSkinning = false; /// Parse the file void parse(Files::IStreamPtr stream); @@ -66,6 +75,34 @@ class NIFFile final : public File void operator = (NIFFile const &); public: + enum NIFVersion + { + // Feature-relevant + VER_4_1_0_0 = 0x04010000, // 1-byte booleans (previously 4-byte) + VER_5_0_0_1 = 0x05000001, // Optimized record type listings + VER_5_0_0_6 = 0x05000006, // Record groups + VER_10_0_1_8 = 0x0A000108, // The last version without user version + VER_20_1_0_1 = 0x14010001, // String tables + VER_20_2_0_5 = 0x14020005, // Record sizes + // Game-relevant + VER_4_0_0_0 = 0x04000000, // Freedom Force NIFs, supported by Morrowind + VER_MW = 0x04000002, // 4.0.0.2. Morrowind and Freedom Force NIFs + VER_4_2_1_0 = 0x04020100, // Used in Civ4 and Dark Age of Camelot + VER_CI = 0x04020200, // 4.2.2.0. Main Culpa Innata NIF version, also used in Civ4 + VER_ZT2 = 0x0A000100, // 10.0.1.0. Main Zoo Tycoon 2 NIF version, also used in Oblivion and Civ4 + VER_OB_OLD = 0x0A000102, // 10.0.1.2. Main older Oblivion NIF version + VER_GAMEBRYO = 0x0A010000, // 10.1.0.0. Lots of games use it. The first version that has Gamebryo File Format header. + VER_10_2_0_0 = 0x0A020000, // Lots of games use this version as well. + VER_CIV4 = 0x14000004, // 20.0.0.4. Main Civilization IV NIF version. + VER_OB = 0x14000005, // 20.0.0.5. Main Oblivion NIF version + VER_BGS = 0x14020007 // 20.2.0.7. Main Fallout 3/4/76/New Vegas and Skyrim/SkyrimSE NIF version. + }; + enum BethVersion + { + BETHVER_FO3 = 34, // Fallout 3 + BETHVER_FO4 = 130 // Fallout 4 + }; + /// Used if file parsing fails void fail(const std::string &msg) const { @@ -101,6 +138,12 @@ public: /// Number of roots size_t numRoots() const override { return roots.size(); } + /// Get a given string from the file's string table + std::string getString(size_t index) const override + { + return strings.at(index); + } + /// Set whether there is skinning contained in this NIF file. /// @note This is just a hint for users of the NIF file and has no effect on the loading procedure. void setUseSkinning(bool skinning) override; @@ -109,8 +152,17 @@ public: /// Get the name of the file std::string getFilename() const override { return filename; } + + /// Get the version of the NIF format used + unsigned int getVersion() const override { return ver; } + + /// Get the user version of the NIF format used + unsigned int getUserVersion() const override { return userVer; } + + /// Get the Bethesda version of the NIF format used + unsigned int getBethVersion() const override { return bethVer; } }; -typedef std::shared_ptr NIFFilePtr; +using NIFFilePtr = std::shared_ptr; diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 9238a65488..3e03b4b1f9 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -26,34 +26,37 @@ struct KeyT { float mContinuity; // Only for TBC interpolation */ }; -typedef KeyT FloatKey; -typedef KeyT Vector3Key; -typedef KeyT Vector4Key; -typedef KeyT QuaternionKey; +using FloatKey = KeyT; +using Vector3Key = KeyT; +using Vector4Key = KeyT; +using QuaternionKey = KeyT; template struct KeyMapT { - typedef std::map< float, KeyT > MapType; + using MapType = std::map>; - typedef T ValueType; - typedef KeyT KeyType; + using ValueType = T; + using KeyType = KeyT; - static const unsigned int sLinearInterpolation = 1; - static const unsigned int sQuadraticInterpolation = 2; - static const unsigned int sTBCInterpolation = 3; - static const unsigned int sXYZInterpolation = 4; + enum InterpolationType + { + Unknown = 0, + Linear = 1, + Quadratic = 2, + TBC = 3, + XYZ = 4, + Constant = 5 + }; - unsigned int mInterpolationType; + unsigned int mInterpolationType = Linear; MapType mKeys; - KeyMapT() : mInterpolationType(sLinearInterpolation) {} - //Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) void read(NIFStream *nif, bool force=false) { assert(nif); - mInterpolationType = 0; + mInterpolationType = Unknown; size_t count = nif->getUInt(); if(count == 0 && !force) @@ -66,7 +69,7 @@ struct KeyMapT { KeyT key; NIFStream &nifReference = *nif; - if(mInterpolationType == sLinearInterpolation) + if (mInterpolationType == Linear || mInterpolationType == Constant) { for(size_t i = 0;i < count;i++) { @@ -75,7 +78,7 @@ struct KeyMapT { mKeys[time] = key; } } - else if(mInterpolationType == sQuadraticInterpolation) + else if (mInterpolationType == Quadratic) { for(size_t i = 0;i < count;i++) { @@ -84,7 +87,7 @@ struct KeyMapT { mKeys[time] = key; } } - else if(mInterpolationType == sTBCInterpolation) + else if (mInterpolationType == TBC) { for(size_t i = 0;i < count;i++) { @@ -98,7 +101,7 @@ struct KeyMapT { // Eats a floating point number, then // Re-runs the read function 3 more times. // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. - else if(mInterpolationType == sXYZInterpolation) + else if(mInterpolationType == XYZ) { //Don't try to read XYZ keys into the wrong part if ( count != 1 ) @@ -109,7 +112,7 @@ struct KeyMapT { nif->file->fail(error.str()); } } - else if (0 == mInterpolationType) + else if (mInterpolationType == Unknown) { if (count != 0) nif->file->fail("Interpolation type 0 doesn't work with keys"); @@ -149,15 +152,17 @@ private: /*key.mContinuity = */nif.getFloat(); } }; -typedef KeyMapT FloatKeyMap; -typedef KeyMapT Vector3KeyMap; -typedef KeyMapT Vector4KeyMap; -typedef KeyMapT QuaternionKeyMap; +using FloatKeyMap = KeyMapT; +using Vector3KeyMap = KeyMapT; +using Vector4KeyMap = KeyMapT; +using QuaternionKeyMap = KeyMapT; +using ByteKeyMap = KeyMapT; -typedef std::shared_ptr FloatKeyMapPtr; -typedef std::shared_ptr Vector3KeyMapPtr; -typedef std::shared_ptr Vector4KeyMapPtr; -typedef std::shared_ptr QuaternionKeyMapPtr; +using FloatKeyMapPtr = std::shared_ptr; +using Vector3KeyMapPtr = std::shared_ptr; +using Vector4KeyMapPtr = std::shared_ptr; +using QuaternionKeyMapPtr = std::shared_ptr; +using ByteKeyMapPtr = std::shared_ptr; } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 3811d05ee0..6e00cbd138 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -24,4 +24,21 @@ namespace Nif t.scale = getFloat(); return t; } + + ///Currently specific for 4.0.0.2 and earlier + bool NIFStream::getBoolean() + { + return !!getInt(); + } + + ///Read in a string, either from the string table using the index (currently absent) or from the stream using the specified length + std::string NIFStream::getString() + { + return getSizedString(); + } + + // Convenience utility functions: get the versions of the currently read file + unsigned int NIFStream::getVersion() { return file->getVersion(); } + unsigned int NIFStream::getUserVersion() { return file->getBethVersion(); } + unsigned int NIFStream::getBethVersion() { return file->getBethVersion(); } } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index b685c56629..7ecd660844 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -155,8 +155,16 @@ public: Transformation getTrafo(); + bool getBoolean(); + + std::string getString(); + + unsigned int getVersion(); + unsigned int getUserVersion(); + unsigned int getBethVersion(); + ///Read in a string of the given length - std::string getString(size_t length) + std::string getSizedString(size_t length) { std::vector str(length + 1, 0); @@ -165,11 +173,19 @@ public: return str.data(); } ///Read in a string of the length specified in the file - std::string getString() + std::string getSizedString() { size_t size = readLittleEndianType(inp); - return getString(size); + return getSizedString(size); } + + ///Specific to Bethesda headers, uses a byte for length + std::string getExportString() + { + size_t size = static_cast(readLittleEndianType(inp)); + return getSizedString(size); + } + ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString() { @@ -190,6 +206,18 @@ public: readLittleEndianDynamicBufferOfType(inp, vec.data(), size); } + void getInts(std::vector &vec, size_t size) + { + vec.resize(size); + readLittleEndianDynamicBufferOfType(inp, vec.data(), size); + } + + void getUInts(std::vector &vec, size_t size) + { + vec.resize(size); + readLittleEndianDynamicBufferOfType(inp, vec.data(), size); + } + void getVector2s(std::vector &vec, size_t size) { vec.resize(size); @@ -217,6 +245,20 @@ public: for (size_t i = 0;i < quat.size();i++) quat[i] = getQuaternion(); } + + void getStrings(std::vector &vec, size_t size) + { + vec.resize(size); + for (size_t i = 0; i < vec.size(); i++) + vec[i] = getString(); + } + /// We need to use this when the string table isn't actually initialized. + void getSizedStrings(std::vector &vec, size_t size) + { + vec.resize(size); + for (size_t i = 0; i < vec.size(); i++) + vec[i] = getSizedString(); + } }; } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 5e5f445cf4..50221784c9 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -24,7 +24,7 @@ class Node : public Named { public: // Node flags. Interpretation depends somewhat on the type of node. - int flags; + unsigned int flags; Transformation trafo; osg::Vec3f velocity; // Unused? Might be a run-time game state PropertyList props; diff --git a/components/nif/property.cpp b/components/nif/property.cpp index 1398326be0..de30e7da9c 100644 --- a/components/nif/property.cpp +++ b/components/nif/property.cpp @@ -14,7 +14,7 @@ void Property::read(NIFStream *nif) void NiTexturingProperty::Texture::read(NIFStream *nif) { - inUse = !!nif->getInt(); + inUse = nif->getBoolean(); if(!inUse) return; texture.read(nif); diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index d165111b8f..478ecfdbb3 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -167,6 +167,7 @@ using NiParticleModifierPtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT; +using ExtraList = RecordListT; using NiSourceTextureList = RecordListT; } // Namespace diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index a16bb6b710..85da77eda8 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -35,17 +35,33 @@ namespace NifOsg { // interpolation of keyframes - template + template class ValueInterpolator { - public: - typedef typename MapT::ValueType ValueT; - - ValueInterpolator() - : mDefaultVal(ValueT()) + typename MapT::MapType::const_iterator retrieveKey(float time) const { + // retrieve the current position in the map, optimized for the most common case + // where time moves linearly along the keyframe track + if (mLastHighKey != mKeys->mKeys.end()) + { + if (time > mLastHighKey->first) + { + // try if we're there by incrementing one + ++mLastLowKey; + ++mLastHighKey; + } + if (mLastHighKey != mKeys->mKeys.end() && time >= mLastLowKey->first && time <= mLastHighKey->first) + return mLastHighKey; + } + + return mKeys->mKeys.lower_bound(time); } + public: + using ValueT = typename MapT::ValueType; + + ValueInterpolator() = default; + ValueInterpolator(std::shared_ptr keys, ValueT defaultVal = ValueT()) : mKeys(keys) , mDefaultVal(defaultVal) @@ -67,44 +83,21 @@ namespace NifOsg if(time <= keys.begin()->first) return keys.begin()->second.mValue; - // retrieve the current position in the map, optimized for the most common case - // where time moves linearly along the keyframe track - typename MapT::MapType::const_iterator it = mLastHighKey; - if (mLastHighKey != keys.end()) - { - if (time > mLastHighKey->first) - { - // try if we're there by incrementing one - ++mLastLowKey; - ++mLastHighKey; - it = mLastHighKey; - } - if (mLastHighKey == keys.end() || (time < mLastLowKey->first || time > mLastHighKey->first)) - it = keys.lower_bound(time); // still not there, reorient by performing lower_bound check on the whole map - } - else - it = keys.lower_bound(time); + typename MapT::MapType::const_iterator it = retrieveKey(time); // now do the actual interpolation if (it != keys.end()) { - float aTime = it->first; - const typename MapT::KeyType* aKey = &it->second; - // cache for next time mLastHighKey = it; + mLastLowKey = --it; - typename MapT::MapType::const_iterator last = --it; - mLastLowKey = last; - float aLastTime = last->first; - const typename MapT::KeyType* aLastKey = &last->second; + float a = (time - mLastLowKey->first) / (mLastHighKey->first - mLastLowKey->first); - float a = (time - aLastTime) / (aTime - aLastTime); - - return InterpolationFunc()(aLastKey->mValue, aKey->mValue, a); + return interpolate(mLastLowKey->second, mLastHighKey->second, a, mKeys->mInterpolationType); } - else - return keys.rbegin()->second.mValue; + + return keys.rbegin()->second.mValue; } bool empty() const @@ -113,36 +106,44 @@ namespace NifOsg } private: + template + ValueType interpolate(const Nif::KeyT& a, const Nif::KeyT& b, float fraction, unsigned int type) const + { + switch (type) + { + case 5: + return fraction > 0.5f ? b.mValue : a.mValue; + default: + return a.mValue + ((b.mValue - a.mValue) * fraction); + } + } + osg::Quat interpolate(const Nif::KeyT& a, const Nif::KeyT& b, float fraction, unsigned int type) const + { + switch (type) + { + case 5: + return fraction > 0.5f ? b.mValue : a.mValue; + default: + { + osg::Quat result; + result.slerp(fraction, a.mValue, b.mValue); + return result; + } + } + } + mutable typename MapT::MapType::const_iterator mLastLowKey; mutable typename MapT::MapType::const_iterator mLastHighKey; std::shared_ptr mKeys; - ValueT mDefaultVal; + ValueT mDefaultVal = ValueT(); }; - struct LerpFunc - { - template - inline ValueType operator()(const ValueType& a, const ValueType& b, float fraction) - { - return a + ((b - a) * fraction); - } - }; - - struct QuaternionSlerpFunc - { - inline osg::Quat operator()(const osg::Quat& a, const osg::Quat& b, float fraction) - { - osg::Quat result; - result.slerp(fraction, a, b); - return result; - } - }; - - typedef ValueInterpolator QuaternionInterpolator; - typedef ValueInterpolator FloatInterpolator; - typedef ValueInterpolator Vec3Interpolator; + using QuaternionInterpolator = ValueInterpolator; + using FloatInterpolator = ValueInterpolator; + using Vec3Interpolator = ValueInterpolator; + using Vec4Interpolator = ValueInterpolator; class ControllerFunction : public SceneUtil::ControllerFunction { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2fd42e77a5..50c1c66276 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -184,14 +184,16 @@ namespace NifOsg { public: /// @param filename used for warning messages. - LoaderImpl(const std::string& filename) - : mFilename(filename), mFirstRootTextureIndex(-1), mFoundFirstRootTexturingProperty(false) + LoaderImpl(const std::string& filename, unsigned int ver, unsigned int userver, unsigned int bethver) + : mFilename(filename), mVersion(ver), mUserVersion(userver), mBethVersion(bethver) { } std::string mFilename; - size_t mFirstRootTextureIndex; - bool mFoundFirstRootTexturingProperty; + unsigned int mVersion, mUserVersion, mBethVersion; + + size_t mFirstRootTextureIndex = -1; + bool mFoundFirstRootTexturingProperty = false; static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { @@ -1846,13 +1848,13 @@ namespace NifOsg osg::ref_ptr Loader::load(Nif::NIFFilePtr file, Resource::ImageManager* imageManager) { - LoaderImpl impl(file->getFilename()); + LoaderImpl impl(file->getFilename(), file->getVersion(), file->getUserVersion(), file->getBethVersion()); return impl.load(file, imageManager); } void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) { - LoaderImpl impl(kf->getFilename()); + LoaderImpl impl(kf->getFilename(), kf->getVersion(), kf->getUserVersion(), kf->getBethVersion()); impl.loadKf(kf, target); } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 4b6891fed7..e159914c71 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -151,7 +151,6 @@ namespace NifOsg float mCachedDefaultSize; }; - typedef ValueInterpolator Vec4Interpolator; class ParticleColorAffector : public osgParticle::Operator { public: From c61f64ae8605b4ae0bb8cad51d4e020095d54c9f Mon Sep 17 00:00:00 2001 From: capostrophic Date: Mon, 30 Dec 2019 13:33:53 +0300 Subject: [PATCH 2/4] Fix tests --- apps/openmw_test_suite/nifloader/testbulletnifloader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index b02b8b9ef7..3044bf2704 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -266,9 +266,13 @@ namespace MOCK_CONST_METHOD0(numRecords, std::size_t ()); MOCK_CONST_METHOD1(getRoot, Nif::Record* (std::size_t)); MOCK_CONST_METHOD0(numRoots, std::size_t ()); + MOCK_CONST_METHOD1(getString, std::string (std::size_t)); MOCK_METHOD1(setUseSkinning, void (bool)); MOCK_CONST_METHOD0(getUseSkinning, bool ()); MOCK_CONST_METHOD0(getFilename, std::string ()); + MOCK_CONST_METHOD0(getVersion, unsigned int ()); + MOCK_CONST_METHOD0(getUserVersion, unsigned int ()); + MOCK_CONST_METHOD0(getBethVersion, unsigned int ()); }; struct RecordMock : Nif::Record From 32caab663f5e0ed00781ec949465407e25d0deaa Mon Sep 17 00:00:00 2001 From: capostrophic Date: Tue, 31 Dec 2019 13:38:57 +0300 Subject: [PATCH 3/4] Enumerate interpolation types properly --- components/nif/data.cpp | 2 +- components/nif/nifkey.hpp | 39 ++++++++++++++++---------------- components/nifosg/controller.hpp | 4 ++-- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index cde8e58765..828f5c368a 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -265,7 +265,7 @@ void NiKeyframeData::read(NIFStream *nif) { mRotations = std::make_shared(); mRotations->read(nif); - if(mRotations->mInterpolationType == Vector3KeyMap::XYZ) + if(mRotations->mInterpolationType == InterpolationType_XYZ) { //Chomp unused float nif->getFloat(); diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 3e03b4b1f9..333d8a7cfa 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -13,6 +13,16 @@ namespace Nif { +enum InterpolationType +{ + InterpolationType_Unknown = 0, + InterpolationType_Linear = 1, + InterpolationType_Quadratic = 2, + InterpolationType_TBC = 3, + InterpolationType_XYZ = 4, + InterpolationType_Constant = 5 +}; + template struct KeyT { T mValue; @@ -38,17 +48,7 @@ struct KeyMapT { using ValueType = T; using KeyType = KeyT; - enum InterpolationType - { - Unknown = 0, - Linear = 1, - Quadratic = 2, - TBC = 3, - XYZ = 4, - Constant = 5 - }; - - unsigned int mInterpolationType = Linear; + unsigned int mInterpolationType = InterpolationType_Linear; MapType mKeys; //Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) @@ -56,7 +56,7 @@ struct KeyMapT { { assert(nif); - mInterpolationType = Unknown; + mInterpolationType = InterpolationType_Unknown; size_t count = nif->getUInt(); if(count == 0 && !force) @@ -69,7 +69,8 @@ struct KeyMapT { KeyT key; NIFStream &nifReference = *nif; - if (mInterpolationType == Linear || mInterpolationType == Constant) + if (mInterpolationType == InterpolationType_Linear + || mInterpolationType == InterpolationType_Constant) { for(size_t i = 0;i < count;i++) { @@ -78,7 +79,7 @@ struct KeyMapT { mKeys[time] = key; } } - else if (mInterpolationType == Quadratic) + else if (mInterpolationType == InterpolationType_Quadratic) { for(size_t i = 0;i < count;i++) { @@ -87,7 +88,7 @@ struct KeyMapT { mKeys[time] = key; } } - else if (mInterpolationType == TBC) + else if (mInterpolationType == InterpolationType_TBC) { for(size_t i = 0;i < count;i++) { @@ -97,11 +98,11 @@ struct KeyMapT { } } //XYZ keys aren't actually read here. - //data.hpp sees that the last type read was sXYZInterpolation and: + //data.hpp sees that the last type read was InterpolationType_XYZ and: // Eats a floating point number, then // Re-runs the read function 3 more times. - // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. - else if(mInterpolationType == XYZ) + // When it does that it's reading in a bunch of InterpolationType_Linear keys, not InterpolationType_XYZ. + else if(mInterpolationType == InterpolationType_XYZ) { //Don't try to read XYZ keys into the wrong part if ( count != 1 ) @@ -112,7 +113,7 @@ struct KeyMapT { nif->file->fail(error.str()); } } - else if (mInterpolationType == Unknown) + else if (mInterpolationType == InterpolationType_Unknown) { if (count != 0) nif->file->fail("Interpolation type 0 doesn't work with keys"); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 85da77eda8..c9bda2e627 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -111,7 +111,7 @@ namespace NifOsg { switch (type) { - case 5: + case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; default: return a.mValue + ((b.mValue - a.mValue) * fraction); @@ -121,7 +121,7 @@ namespace NifOsg { switch (type) { - case 5: + case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; default: { From f234d532691c115708dc3557c603f54e59d69e93 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Thu, 2 Jan 2020 13:09:54 +0300 Subject: [PATCH 4/4] Don't use double negation --- components/nif/controlled.cpp | 2 +- components/nif/nifstream.cpp | 2 +- components/nif/node.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 51ccf85412..9b7c9319bf 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -9,7 +9,7 @@ namespace Nif { Named::read(nif); - external = !!nif->getChar(); + external = nif->getChar() != 0; if(external) filename = nif->getString(); else diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 6e00cbd138..4ecb0e373b 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -28,7 +28,7 @@ namespace Nif ///Currently specific for 4.0.0.2 and earlier bool NIFStream::getBoolean() { - return !!getInt(); + return getInt() != 0; } ///Read in a string, either from the string table using the index (currently absent) or from the stream using the specified length diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 50221784c9..71a0a93cac 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -44,7 +44,7 @@ public: velocity = nif->getVector3(); props.read(nif); - hasBounds = !!nif->getInt(); + hasBounds = nif->getBoolean(); if(hasBounds) { nif->getInt(); // always 1