1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-01 04:36:44 +00:00

More NIF adjustments

Constant interpolation support
This commit is contained in:
capostrophic 2019-12-29 15:53:44 +03:00
parent a5289035e2
commit e654a52b70
12 changed files with 236 additions and 130 deletions

View file

@ -35,16 +35,16 @@ void ShapeData::read(NIFStream *nif)
{ {
int verts = nif->getUShort(); int verts = nif->getUShort();
if(nif->getInt()) if (nif->getBoolean())
nif->getVector3s(vertices, verts); nif->getVector3s(vertices, verts);
if(nif->getInt()) if (nif->getBoolean())
nif->getVector3s(normals, verts); nif->getVector3s(normals, verts);
center = nif->getVector3(); center = nif->getVector3();
radius = nif->getFloat(); radius = nif->getFloat();
if(nif->getInt()) if (nif->getBoolean())
nif->getVector4s(colors, verts); nif->getVector4s(colors, verts);
// Only the first 6 bits are used as a count. I think the rest are // 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(); particleRadius = nif->getFloat();
activeCount = nif->getUShort(); activeCount = nif->getUShort();
if(nif->getInt()) if (nif->getBoolean())
{ {
// Particle sizes // Particle sizes
nif->getFloats(sizes, vertices.size()); nif->getFloats(sizes, vertices.size());
@ -131,7 +131,7 @@ void NiRotatingParticlesData::read(NIFStream *nif)
{ {
NiAutoNormalParticlesData::read(nif); NiAutoNormalParticlesData::read(nif);
if(nif->getInt()) if (nif->getBoolean())
{ {
// Rotation quaternions. // Rotation quaternions.
nif->getQuaternions(rotations, vertices.size()); nif->getQuaternions(rotations, vertices.size());
@ -176,7 +176,7 @@ void NiPixelData::read(NIFStream *nif)
numberOfMipmaps = nif->getUInt(); numberOfMipmaps = nif->getUInt();
// Bytes per pixel, should be bpp * 8 // Bytes per pixel, should be bpp / 8
/* int bytes = */ nif->getUInt(); /* int bytes = */ nif->getUInt();
for(unsigned int i=0; i<numberOfMipmaps; i++) for(unsigned int i=0; i<numberOfMipmaps; i++)
@ -228,10 +228,8 @@ void NiSkinData::read(NIFStream *nif)
nif->getInt(); // -1 nif->getInt(); // -1
bones.resize(boneNum); bones.resize(boneNum);
for(int i=0;i<boneNum;i++) for (BoneInfo &bi : bones)
{ {
BoneInfo &bi = bones[i];
bi.trafo.rotation = nif->getMatrix3(); bi.trafo.rotation = nif->getMatrix3();
bi.trafo.pos = nif->getVector3(); bi.trafo.pos = nif->getVector3();
bi.trafo.scale = nif->getFloat(); bi.trafo.scale = nif->getFloat();
@ -267,7 +265,7 @@ void NiKeyframeData::read(NIFStream *nif)
{ {
mRotations = std::make_shared<QuaternionKeyMap>(); mRotations = std::make_shared<QuaternionKeyMap>();
mRotations->read(nif); mRotations->read(nif);
if(mRotations->mInterpolationType == Vector3KeyMap::sXYZInterpolation) if(mRotations->mInterpolationType == Vector3KeyMap::XYZ)
{ {
//Chomp unused float //Chomp unused float
nif->getFloat(); nif->getFloat();

View file

@ -9,9 +9,7 @@ namespace Nif
/// Open a NIF stream. The name is used for error messages. /// Open a NIF stream. The name is used for error messages.
NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name) NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name)
: ver(0) : filename(name)
, filename(name)
, mUseSkinning(false)
{ {
parse(stream); parse(stream);
} }
@ -139,27 +137,18 @@ void NIFFile::parse(Files::IStreamPtr stream)
// Check the header string // Check the header string
std::string head = nif.getVersionString(); std::string head = nif.getVersionString();
if(head.compare(0, 22, "NetImmerse File Format") != 0) if(head.compare(0, 22, "NetImmerse File Format") != 0)
fail("Invalid NIF header: " + head); fail("Invalid NIF header: " + head);
// Get BCD version // Get BCD version
ver = nif.getUInt(); ver = nif.getUInt();
// 4.0.0.0 is an older, practically identical version of the format. // 4.0.0.0 is an older, practically identical version of the format.
// It's not used by Morrowind assets but Morrowind supports it. // 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)); fail("Unsupported NIF version: " + printVersion(ver));
// Number of records // Number of records
size_t recNum = nif.getInt(); size_t recNum = nif.getInt();
records.resize(recNum); 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++) for(size_t i = 0;i < recNum;i++)
{ {
Record *r = nullptr; Record *r = nullptr;

View file

@ -26,21 +26,27 @@ struct File
virtual size_t numRoots() const = 0; virtual size_t numRoots() const = 0;
virtual std::string getString(size_t index) const = 0;
virtual void setUseSkinning(bool skinning) = 0; virtual void setUseSkinning(bool skinning) = 0;
virtual bool getUseSkinning() const = 0; virtual bool getUseSkinning() const = 0;
virtual std::string getFilename() 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 class NIFFile final : public File
{ {
enum NIFVersion { /// File version, user version, Bethesda version
VER_MW = 0x04000002 // Morrowind NIFs unsigned int ver = 0;
}; unsigned int userVer = 0;
unsigned int bethVer = 0;
/// Nif file version
unsigned int ver;
/// File name, used for error messages and opening the file /// File name, used for error messages and opening the file
std::string filename; std::string filename;
@ -51,7 +57,10 @@ class NIFFile final : public File
/// Root list. This is a select portion of the pointers from records /// Root list. This is a select portion of the pointers from records
std::vector<Record*> roots; std::vector<Record*> roots;
bool mUseSkinning; /// String table
std::vector<std::string> strings;
bool mUseSkinning = false;
/// Parse the file /// Parse the file
void parse(Files::IStreamPtr stream); void parse(Files::IStreamPtr stream);
@ -66,6 +75,34 @@ class NIFFile final : public File
void operator = (NIFFile const &); void operator = (NIFFile const &);
public: 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 /// Used if file parsing fails
void fail(const std::string &msg) const void fail(const std::string &msg) const
{ {
@ -101,6 +138,12 @@ public:
/// Number of roots /// Number of roots
size_t numRoots() const override { return roots.size(); } 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. /// 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. /// @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; void setUseSkinning(bool skinning) override;
@ -109,8 +152,17 @@ public:
/// Get the name of the file /// Get the name of the file
std::string getFilename() const override { return filename; } 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<const Nif::NIFFile> NIFFilePtr; using NIFFilePtr = std::shared_ptr<const Nif::NIFFile>;

View file

@ -26,34 +26,37 @@ struct KeyT {
float mContinuity; // Only for TBC interpolation float mContinuity; // Only for TBC interpolation
*/ */
}; };
typedef KeyT<float> FloatKey; using FloatKey = KeyT<float>;
typedef KeyT<osg::Vec3f> Vector3Key; using Vector3Key = KeyT<osg::Vec3f>;
typedef KeyT<osg::Vec4f> Vector4Key; using Vector4Key = KeyT<osg::Vec4f>;
typedef KeyT<osg::Quat> QuaternionKey; using QuaternionKey = KeyT<osg::Quat>;
template<typename T, T (NIFStream::*getValue)()> template<typename T, T (NIFStream::*getValue)()>
struct KeyMapT { struct KeyMapT {
typedef std::map< float, KeyT<T> > MapType; using MapType = std::map<float, KeyT<T>>;
typedef T ValueType; using ValueType = T;
typedef KeyT<T> KeyType; using KeyType = KeyT<T>;
static const unsigned int sLinearInterpolation = 1; enum InterpolationType
static const unsigned int sQuadraticInterpolation = 2; {
static const unsigned int sTBCInterpolation = 3; Unknown = 0,
static const unsigned int sXYZInterpolation = 4; Linear = 1,
Quadratic = 2,
TBC = 3,
XYZ = 4,
Constant = 5
};
unsigned int mInterpolationType; unsigned int mInterpolationType = Linear;
MapType mKeys; MapType mKeys;
KeyMapT() : mInterpolationType(sLinearInterpolation) {}
//Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) //Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html)
void read(NIFStream *nif, bool force=false) void read(NIFStream *nif, bool force=false)
{ {
assert(nif); assert(nif);
mInterpolationType = 0; mInterpolationType = Unknown;
size_t count = nif->getUInt(); size_t count = nif->getUInt();
if(count == 0 && !force) if(count == 0 && !force)
@ -66,7 +69,7 @@ struct KeyMapT {
KeyT<T> key; KeyT<T> key;
NIFStream &nifReference = *nif; NIFStream &nifReference = *nif;
if(mInterpolationType == sLinearInterpolation) if (mInterpolationType == Linear || mInterpolationType == Constant)
{ {
for(size_t i = 0;i < count;i++) for(size_t i = 0;i < count;i++)
{ {
@ -75,7 +78,7 @@ struct KeyMapT {
mKeys[time] = key; mKeys[time] = key;
} }
} }
else if(mInterpolationType == sQuadraticInterpolation) else if (mInterpolationType == Quadratic)
{ {
for(size_t i = 0;i < count;i++) for(size_t i = 0;i < count;i++)
{ {
@ -84,7 +87,7 @@ struct KeyMapT {
mKeys[time] = key; mKeys[time] = key;
} }
} }
else if(mInterpolationType == sTBCInterpolation) else if (mInterpolationType == TBC)
{ {
for(size_t i = 0;i < count;i++) for(size_t i = 0;i < count;i++)
{ {
@ -98,7 +101,7 @@ struct KeyMapT {
// Eats a floating point number, then // Eats a floating point number, then
// Re-runs the read function 3 more times. // Re-runs the read function 3 more times.
// When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. // 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 //Don't try to read XYZ keys into the wrong part
if ( count != 1 ) if ( count != 1 )
@ -109,7 +112,7 @@ struct KeyMapT {
nif->file->fail(error.str()); nif->file->fail(error.str());
} }
} }
else if (0 == mInterpolationType) else if (mInterpolationType == Unknown)
{ {
if (count != 0) if (count != 0)
nif->file->fail("Interpolation type 0 doesn't work with keys"); nif->file->fail("Interpolation type 0 doesn't work with keys");
@ -149,15 +152,17 @@ private:
/*key.mContinuity = */nif.getFloat(); /*key.mContinuity = */nif.getFloat();
} }
}; };
typedef KeyMapT<float,&NIFStream::getFloat> FloatKeyMap; using FloatKeyMap = KeyMapT<float,&NIFStream::getFloat>;
typedef KeyMapT<osg::Vec3f,&NIFStream::getVector3> Vector3KeyMap; using Vector3KeyMap = KeyMapT<osg::Vec3f,&NIFStream::getVector3>;
typedef KeyMapT<osg::Vec4f,&NIFStream::getVector4> Vector4KeyMap; using Vector4KeyMap = KeyMapT<osg::Vec4f,&NIFStream::getVector4>;
typedef KeyMapT<osg::Quat,&NIFStream::getQuaternion> QuaternionKeyMap; using QuaternionKeyMap = KeyMapT<osg::Quat,&NIFStream::getQuaternion>;
using ByteKeyMap = KeyMapT<char,&NIFStream::getChar>;
typedef std::shared_ptr<FloatKeyMap> FloatKeyMapPtr; using FloatKeyMapPtr = std::shared_ptr<FloatKeyMap>;
typedef std::shared_ptr<Vector3KeyMap> Vector3KeyMapPtr; using Vector3KeyMapPtr = std::shared_ptr<Vector3KeyMap>;
typedef std::shared_ptr<Vector4KeyMap> Vector4KeyMapPtr; using Vector4KeyMapPtr = std::shared_ptr<Vector4KeyMap>;
typedef std::shared_ptr<QuaternionKeyMap> QuaternionKeyMapPtr; using QuaternionKeyMapPtr = std::shared_ptr<QuaternionKeyMap>;
using ByteKeyMapPtr = std::shared_ptr<ByteKeyMap>;
} // Namespace } // Namespace
#endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP

View file

@ -24,4 +24,21 @@ namespace Nif
t.scale = getFloat(); t.scale = getFloat();
return t; 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(); }
} }

View file

@ -155,8 +155,16 @@ public:
Transformation getTrafo(); Transformation getTrafo();
bool getBoolean();
std::string getString();
unsigned int getVersion();
unsigned int getUserVersion();
unsigned int getBethVersion();
///Read in a string of the given length ///Read in a string of the given length
std::string getString(size_t length) std::string getSizedString(size_t length)
{ {
std::vector<char> str(length + 1, 0); std::vector<char> str(length + 1, 0);
@ -165,11 +173,19 @@ public:
return str.data(); return str.data();
} }
///Read in a string of the length specified in the file ///Read in a string of the length specified in the file
std::string getString() std::string getSizedString()
{ {
size_t size = readLittleEndianType<uint32_t,uint32_t>(inp); size_t size = readLittleEndianType<uint32_t,uint32_t>(inp);
return getString(size); return getSizedString(size);
} }
///Specific to Bethesda headers, uses a byte for length
std::string getExportString()
{
size_t size = static_cast<size_t>(readLittleEndianType<uint8_t,uint8_t>(inp));
return getSizedString(size);
}
///This is special since the version string doesn't start with a number, and ends with "\n" ///This is special since the version string doesn't start with a number, and ends with "\n"
std::string getVersionString() std::string getVersionString()
{ {
@ -190,6 +206,18 @@ public:
readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, vec.data(), size); readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, vec.data(), size);
} }
void getInts(std::vector<int> &vec, size_t size)
{
vec.resize(size);
readLittleEndianDynamicBufferOfType<int,int>(inp, vec.data(), size);
}
void getUInts(std::vector<unsigned int> &vec, size_t size)
{
vec.resize(size);
readLittleEndianDynamicBufferOfType<unsigned int,unsigned int>(inp, vec.data(), size);
}
void getVector2s(std::vector<osg::Vec2f> &vec, size_t size) void getVector2s(std::vector<osg::Vec2f> &vec, size_t size)
{ {
vec.resize(size); vec.resize(size);
@ -217,6 +245,20 @@ public:
for (size_t i = 0;i < quat.size();i++) for (size_t i = 0;i < quat.size();i++)
quat[i] = getQuaternion(); quat[i] = getQuaternion();
} }
void getStrings(std::vector<std::string> &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<std::string> &vec, size_t size)
{
vec.resize(size);
for (size_t i = 0; i < vec.size(); i++)
vec[i] = getSizedString();
}
}; };
} }

View file

@ -24,7 +24,7 @@ class Node : public Named
{ {
public: public:
// Node flags. Interpretation depends somewhat on the type of node. // Node flags. Interpretation depends somewhat on the type of node.
int flags; unsigned int flags;
Transformation trafo; Transformation trafo;
osg::Vec3f velocity; // Unused? Might be a run-time game state osg::Vec3f velocity; // Unused? Might be a run-time game state
PropertyList props; PropertyList props;

View file

@ -14,7 +14,7 @@ void Property::read(NIFStream *nif)
void NiTexturingProperty::Texture::read(NIFStream *nif) void NiTexturingProperty::Texture::read(NIFStream *nif)
{ {
inUse = !!nif->getInt(); inUse = nif->getBoolean();
if(!inUse) return; if(!inUse) return;
texture.read(nif); texture.read(nif);

View file

@ -167,6 +167,7 @@ using NiParticleModifierPtr = RecordPtrT<NiParticleModifier>;
using NodeList = RecordListT<Node>; using NodeList = RecordListT<Node>;
using PropertyList = RecordListT<Property>; using PropertyList = RecordListT<Property>;
using ExtraList = RecordListT<Extra>;
using NiSourceTextureList = RecordListT<NiSourceTexture>; using NiSourceTextureList = RecordListT<NiSourceTexture>;
} // Namespace } // Namespace

View file

@ -35,17 +35,33 @@ namespace NifOsg
{ {
// interpolation of keyframes // interpolation of keyframes
template <typename MapT, typename InterpolationFunc> template <typename MapT>
class ValueInterpolator class ValueInterpolator
{ {
public: typename MapT::MapType::const_iterator retrieveKey(float time) const
typedef typename MapT::ValueType ValueT;
ValueInterpolator()
: mDefaultVal(ValueT())
{ {
// 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<const MapT> keys, ValueT defaultVal = ValueT()) ValueInterpolator(std::shared_ptr<const MapT> keys, ValueT defaultVal = ValueT())
: mKeys(keys) : mKeys(keys)
, mDefaultVal(defaultVal) , mDefaultVal(defaultVal)
@ -67,44 +83,21 @@ namespace NifOsg
if(time <= keys.begin()->first) if(time <= keys.begin()->first)
return keys.begin()->second.mValue; return keys.begin()->second.mValue;
// retrieve the current position in the map, optimized for the most common case typename MapT::MapType::const_iterator it = retrieveKey(time);
// 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);
// now do the actual interpolation // now do the actual interpolation
if (it != keys.end()) if (it != keys.end())
{ {
float aTime = it->first;
const typename MapT::KeyType* aKey = &it->second;
// cache for next time // cache for next time
mLastHighKey = it; mLastHighKey = it;
mLastLowKey = --it;
typename MapT::MapType::const_iterator last = --it; float a = (time - mLastLowKey->first) / (mLastHighKey->first - mLastLowKey->first);
mLastLowKey = last;
float aLastTime = last->first;
const typename MapT::KeyType* aLastKey = &last->second;
float a = (time - aLastTime) / (aTime - aLastTime); return interpolate(mLastLowKey->second, mLastHighKey->second, a, mKeys->mInterpolationType);
return InterpolationFunc()(aLastKey->mValue, aKey->mValue, a);
} }
else
return keys.rbegin()->second.mValue; return keys.rbegin()->second.mValue;
} }
bool empty() const bool empty() const
@ -113,36 +106,44 @@ namespace NifOsg
} }
private: private:
template <typename ValueType>
ValueType interpolate(const Nif::KeyT<ValueType>& a, const Nif::KeyT<ValueType>& 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<osg::Quat>& a, const Nif::KeyT<osg::Quat>& 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 mLastLowKey;
mutable typename MapT::MapType::const_iterator mLastHighKey; mutable typename MapT::MapType::const_iterator mLastHighKey;
std::shared_ptr<const MapT> mKeys; std::shared_ptr<const MapT> mKeys;
ValueT mDefaultVal; ValueT mDefaultVal = ValueT();
}; };
struct LerpFunc using QuaternionInterpolator = ValueInterpolator<Nif::QuaternionKeyMap>;
{ using FloatInterpolator = ValueInterpolator<Nif::FloatKeyMap>;
template <typename ValueType> using Vec3Interpolator = ValueInterpolator<Nif::Vector3KeyMap>;
inline ValueType operator()(const ValueType& a, const ValueType& b, float fraction) using Vec4Interpolator = ValueInterpolator<Nif::Vector4KeyMap>;
{
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<Nif::QuaternionKeyMap, QuaternionSlerpFunc> QuaternionInterpolator;
typedef ValueInterpolator<Nif::FloatKeyMap, LerpFunc> FloatInterpolator;
typedef ValueInterpolator<Nif::Vector3KeyMap, LerpFunc> Vec3Interpolator;
class ControllerFunction : public SceneUtil::ControllerFunction class ControllerFunction : public SceneUtil::ControllerFunction
{ {

View file

@ -184,14 +184,16 @@ namespace NifOsg
{ {
public: public:
/// @param filename used for warning messages. /// @param filename used for warning messages.
LoaderImpl(const std::string& filename) LoaderImpl(const std::string& filename, unsigned int ver, unsigned int userver, unsigned int bethver)
: mFilename(filename), mFirstRootTextureIndex(-1), mFoundFirstRootTexturingProperty(false) : mFilename(filename), mVersion(ver), mUserVersion(userver), mBethVersion(bethver)
{ {
} }
std::string mFilename; std::string mFilename;
size_t mFirstRootTextureIndex; unsigned int mVersion, mUserVersion, mBethVersion;
bool mFoundFirstRootTexturingProperty;
size_t mFirstRootTextureIndex = -1;
bool mFoundFirstRootTexturingProperty = false;
static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target)
{ {
@ -1846,13 +1848,13 @@ namespace NifOsg
osg::ref_ptr<osg::Node> Loader::load(Nif::NIFFilePtr file, Resource::ImageManager* imageManager) osg::ref_ptr<osg::Node> 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); return impl.load(file, imageManager);
} }
void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) 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); impl.loadKf(kf, target);
} }

View file

@ -151,7 +151,6 @@ namespace NifOsg
float mCachedDefaultSize; float mCachedDefaultSize;
}; };
typedef ValueInterpolator<Nif::Vector4KeyMap, LerpFunc> Vec4Interpolator;
class ParticleColorAffector : public osgParticle::Operator class ParticleColorAffector : public osgParticle::Operator
{ {
public: public: