diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 897e87735..1c3f442c2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (bsa ) add_component_dir (nif - controlled effect niftypes record controller extra node record_ptr data niffile property + controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node ) add_component_dir (nifcache diff --git a/components/nif/data.cpp b/components/nif/data.cpp new file mode 100644 index 000000000..4248b93d2 --- /dev/null +++ b/components/nif/data.cpp @@ -0,0 +1,29 @@ +#include "data.hpp" +#include "node.hpp" + +namespace Nif +{ +void NiSkinInstance::post(NIFFile *nif) +{ + data.post(nif); + root.post(nif); + bones.post(nif); + + if(data.empty() || root.empty()) + nif->fail("NiSkinInstance missing root or data"); + + size_t bnum = bones.length(); + if(bnum != data->bones.size()) + nif->fail("Mismatch in NiSkinData bone count"); + + root->makeRootBone(&data->trafo); + + for(size_t i=0; ifail("Oops: Missing bone! Don't know how to handle this."); + bones[i]->makeBone(i, data->bones[i]); + } +} + +} // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index e94388768..7fd905f00 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -25,9 +25,8 @@ #define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" - -#include -#include +#include "nifstream.hpp" +#include "nifkey.hpp" namespace Nif { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 6c38f73dc..df85e4803 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -1,39 +1,7 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (nif_file.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #include "niffile.hpp" -#include "record.hpp" -#include "components/misc/stringops.hpp" - -#include "extra.hpp" -#include "controlled.hpp" -#include "node.hpp" -#include "property.hpp" -#include "data.hpp" #include "effect.hpp" -#include "controller.hpp" -#include +#include namespace Nif { @@ -204,15 +172,6 @@ void NIFFile::parse() r->recIndex = i; records[i] = r; r->read(&nif); - - // Discard tranformations for the root node, otherwise some meshes - // occasionally get wrong orientation. Only for NiNode-s for now, but - // can be expanded if needed. - // This should be rewritten when the method is cleaned up. - if (0 == i && rec == "NiNode") - { - static_cast(r)->trafo = Nif::Transformation::getIdentity(); - } } size_t rootNum = nif.getUInt(); @@ -229,81 +188,4 @@ void NIFFile::parse() records[i]->post(this); } -/// \todo move to the write cpp file - -void NiSkinInstance::post(NIFFile *nif) -{ - data.post(nif); - root.post(nif); - bones.post(nif); - - if(data.empty() || root.empty()) - nif->fail("NiSkinInstance missing root or data"); - - size_t bnum = bones.length(); - if(bnum != data->bones.size()) - nif->fail("Mismatch in NiSkinData bone count"); - - root->makeRootBone(&data->trafo); - - for(size_t i=0; ifail("Oops: Missing bone! Don't know how to handle this."); - bones[i]->makeBone(i, data->bones[i]); - } -} - - -void Node::getProperties(const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop) const -{ - if(parent) - parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - for(size_t i = 0;i < props.length();i++) - { - // Entries may be empty - if(props[i].empty()) - continue; - - const Nif::Property *pr = props[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName <getWorldTransform() * getLocalTransform(); - return getLocalTransform(); -} - } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 9790d8453..108e455d7 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -1,53 +1,13 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (nif_file.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ +///Main header for reading .nif files #ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP #define OPENMW_COMPONENTS_NIF_NIFFILE_HPP -#include -#include -#include -#include -#include -#include -#include -#include - #include #include -#include -#include - -#include -#include -#include -#include - -#include +#include #include "record.hpp" -#include "niftypes.hpp" -#include "nifstream.hpp" namespace Nif { @@ -61,37 +21,39 @@ class NIFFile /// Nif file version int ver; - /// File name, used for error messages + /// File name, used for error messages and opening the file std::string filename; /// Record list std::vector records; - /// Root list + /// Root list. This is a select portion of the pointers from records std::vector roots; /// Parse the file void parse(); + ///Private Copy Constructor NIFFile (NIFFile const &); + ///\overload void operator = (NIFFile const &); public: - /// Used for error handling + /// Used if file parsing fails void fail(const std::string &msg) { std::string err = "NIFFile Error: " + msg; err += "\nFile: " + filename; throw std::runtime_error(err); } - + /// Used when something goes wrong, but not catastrophically so void warn(const std::string &msg) { std::cerr << "NIFFile Warning: " << msg < -struct KeyT { - float mTime; - T mValue; - T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList - T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation -}; -typedef KeyT FloatKey; -typedef KeyT Vector3Key; -typedef KeyT Vector4Key; -typedef KeyT QuaternionKey; - -template -struct KeyListT { - typedef std::vector< KeyT > VecType; - - static const unsigned int sLinearInterpolation = 1; - static const unsigned int sQuadraticInterpolation = 2; - static const unsigned int sTBCInterpolation = 3; - static const unsigned int sXYZInterpolation = 4; - - unsigned int mInterpolationType; - VecType mKeys; - - KeyListT() : 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; - - size_t count = nif->getUInt(); - if(count == 0 && !force) - return; - - //If we aren't forcing things, make sure that read clears any previous keys - if(!force) - mKeys.clear(); - - mInterpolationType = nif->getUInt(); - - KeyT key; - NIFStream &nifReference = *nif; - - if(mInterpolationType == sLinearInterpolation) - { - for(size_t i = 0;i < count;i++) - { - readTimeAndValue(nifReference, key); - mKeys.push_back(key); - } - } - else if(mInterpolationType == sQuadraticInterpolation) - { - for(size_t i = 0;i < count;i++) - { - readQuadratic(nifReference, key); - mKeys.push_back(key); - } - } - else if(mInterpolationType == sTBCInterpolation) - { - for(size_t i = 0;i < count;i++) - { - readTBC(nifReference, key); - mKeys.push_back(key); - } - } - //XYZ keys aren't actually read here. - //data.hpp sees that the last type read was sXYZInterpolation and: - // Eats a floating point number, then - // Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared. - // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. - else if(mInterpolationType == sXYZInterpolation) - { - //Don't try to read XYZ keys into the wrong part - if ( count != 1 ) - nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); - } - else if (0 == mInterpolationType) - { - if (count != 0) - nif->file->fail("Interpolation type 0 doesn't work with keys"); - } - else - nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); - } - -private: - static void readTimeAndValue(NIFStream &nif, KeyT &key) - { - key.mTime = nif.getFloat(); - key.mValue = (nif.*getValue)(); - } - - static void readQuadratic(NIFStream &nif, KeyT &key) - { - readTimeAndValue(nif, key); - } - - template - static void readQuadratic(NIFStream &nif, KeyT &key) - { - readTimeAndValue(nif, key); - key.mForwardValue = (nif.*getValue)(); - key.mBackwardValue = (nif.*getValue)(); - } - - static void readTBC(NIFStream &nif, KeyT &key) - { - readTimeAndValue(nif, key); - key.mTension = nif.getFloat(); - key.mBias = nif.getFloat(); - key.mContinuity = nif.getFloat(); - } -}; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; } // Namespace #endif diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp new file mode 100644 index 000000000..403499e7f --- /dev/null +++ b/components/nif/nifkey.hpp @@ -0,0 +1,140 @@ +///File to handle keys used by nif file records + +#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP +#define OPENMW_COMPONENTS_NIF_NIFKEY_HPP + +#include + +#include "nifstream.hpp" + +namespace Nif +{ + +template +struct KeyT { + float mTime; + T mValue; + T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList + T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList + float mTension; // Only for TBC interpolation + float mBias; // Only for TBC interpolation + float mContinuity; // Only for TBC interpolation +}; +typedef KeyT FloatKey; +typedef KeyT Vector3Key; +typedef KeyT Vector4Key; +typedef KeyT QuaternionKey; + +template +struct KeyListT { + typedef std::vector< KeyT > VecType; + + static const unsigned int sLinearInterpolation = 1; + static const unsigned int sQuadraticInterpolation = 2; + static const unsigned int sTBCInterpolation = 3; + static const unsigned int sXYZInterpolation = 4; + + unsigned int mInterpolationType; + VecType mKeys; + + KeyListT() : 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; + + size_t count = nif->getUInt(); + if(count == 0 && !force) + return; + + //If we aren't forcing things, make sure that read clears any previous keys + if(!force) + mKeys.clear(); + + mInterpolationType = nif->getUInt(); + + KeyT key; + NIFStream &nifReference = *nif; + + if(mInterpolationType == sLinearInterpolation) + { + for(size_t i = 0;i < count;i++) + { + readTimeAndValue(nifReference, key); + mKeys.push_back(key); + } + } + else if(mInterpolationType == sQuadraticInterpolation) + { + for(size_t i = 0;i < count;i++) + { + readQuadratic(nifReference, key); + mKeys.push_back(key); + } + } + else if(mInterpolationType == sTBCInterpolation) + { + for(size_t i = 0;i < count;i++) + { + readTBC(nifReference, key); + mKeys.push_back(key); + } + } + //XYZ keys aren't actually read here. + //data.hpp sees that the last type read was sXYZInterpolation and: + // Eats a floating point number, then + // Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared. + // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. + else if(mInterpolationType == sXYZInterpolation) + { + //Don't try to read XYZ keys into the wrong part + if ( count != 1 ) + nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); + } + else if (0 == mInterpolationType) + { + if (count != 0) + nif->file->fail("Interpolation type 0 doesn't work with keys"); + } + else + nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } + +private: + static void readTimeAndValue(NIFStream &nif, KeyT &key) + { + key.mTime = nif.getFloat(); + key.mValue = (nif.*getValue)(); + } + + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + } + + template + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + key.mForwardValue = (nif.*getValue)(); + key.mBackwardValue = (nif.*getValue)(); + } + + static void readTBC(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + key.mTension = nif.getFloat(); + key.mBias = nif.getFloat(); + key.mContinuity = nif.getFloat(); + } +}; +typedef KeyListT FloatKeyList; +typedef KeyListT Vector3KeyList; +typedef KeyListT Vector4KeyList; +typedef KeyListT QuaternionKeyList; + +} // Namespace +#endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP \ No newline at end of file diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index a2595d17b..22d39b8d7 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -1,6 +1,20 @@ +///Functions used to read raw binary data from .nif files + #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "niftypes.hpp" + namespace Nif { diff --git a/components/nif/node.cpp b/components/nif/node.cpp new file mode 100644 index 000000000..b7ca98113 --- /dev/null +++ b/components/nif/node.cpp @@ -0,0 +1,57 @@ +#include "node.hpp" + +namespace Nif +{ + +void Node::getProperties(const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) const +{ + if(parent) + parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + for(size_t i = 0;i < props.length();i++) + { + // Entries may be empty + if(props[i].empty()) + continue; + + const Nif::Property *pr = props[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName <getWorldTransform() * getLocalTransform(); + return getLocalTransform(); +} + +} diff --git a/components/nif/node.hpp b/components/nif/node.hpp index eebcd8be8..01e0e9a2d 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -1,26 +1,3 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (node.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #ifndef OPENMW_COMPONENTS_NIF_NODE_HPP #define OPENMW_COMPONENTS_NIF_NODE_HPP @@ -29,6 +6,7 @@ #include "controlled.hpp" #include "data.hpp" #include "property.hpp" +#include "niftypes.hpp" namespace Nif { @@ -149,6 +127,14 @@ struct NiNode : Node Node::read(nif); children.read(nif); effects.read(nif); + + // Discard tranformations for the root node, otherwise some meshes + // occasionally get wrong orientation. Only for NiNode-s for now, but + // can be expanded if needed. + if (0 == recIndex) + { + static_cast(this)->trafo = Nif::Transformation::getIdentity(); + } } void post(NIFFile *nif) diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 1a4fc235b..5eac277d0 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -1,30 +1,8 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (record_ptr.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #include "niffile.hpp" +#include "nifstream.hpp" #include namespace Nif diff --git a/components/nifcache/nifcache.hpp b/components/nifcache/nifcache.hpp index dc4155cad..173b91865 100644 --- a/components/nifcache/nifcache.hpp +++ b/components/nifcache/nifcache.hpp @@ -5,6 +5,8 @@ #include +#include + namespace Nif {