diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index a2595d17b8..7abfae9e84 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#include + namespace Nif { @@ -11,168 +13,278 @@ class NIFStream { /// Input stream Ogre::DataStreamPtr inp; - uint8_t read_byte() + template + value_t read_le () { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; + uint8_t buffer [sizeof (value_t)]; + + if (inp->read (buffer, sizeof (buffer)) != sizeof (buffer)) + throw std::runtime_error ("unexpected"); + + value_t Value = 0; + value_t Shift = 0; + + for (size_t i = 0; i < sizeof (value_t); ++i) + { + Value |= value_t (buffer[i]) << Shift; + Shift += 8; + } + + return Value; } public: + /* + * This should be true for any processor/platform whose endianess, alignment + * and packing rules would be compatible with x86 and not fault or degrade + * with misaligned reads. This enables some pretty big savings when reading in + * animations and meshes. + */ +#if defined (__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + static const bool FileCompatiblePlatform = true; +#else + static const bool FileCompatiblePlatform = false; +#endif + + template + struct handler; + + template + struct le_handler; + + template + friend struct le_handler; + + template + struct conversion_handler; + NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp) : file (file), inp (inp) {} /************************************************* Parser functions ****************************************************/ - template - struct GetHandler - { - typedef T (NIFStream::*fn_t)(); - - static const fn_t sValue; // this is specialized per supported type in the .cpp file - - static T read (NIFStream* nif) - { - return (nif->*sValue) (); - } - }; + void skip(size_t size) { return inp->skip (size); } + size_t read (void * data, size_t size) { return inp->read (data, size); } template - void read (NIFStream* nif, T & Value) + void uncheckedRead (T & Value) { - Value = GetHandler ::read (nif); + typedef handler handler_t; + handler_t::extract (*this, Value); } - void skip(size_t size) { inp->skip(size); } - void read (void * data, size_t size) { inp->read (data, size); } + template + T getValue () + { + T Value; + getValue (Value); + return Value; + } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2() + template + void getValue (T & Value) { - float a[2]; - for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); - } - Ogre::Vector3 getVector3() - { - float a[3]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) + typedef handler handler_t; + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (T), "unexpected structure size"); + + inp->read (&Value, handler_t::EncodedLength); + } + else + { + handler_t::extract (*this, Value); } - return Ogre::Matrix3(a); } - Ogre::Quaternion getQuaternion() + + template + void getArray (element_type * Array, size_t Size) { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + typedef handler handler_t; + + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) + { + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (element_type), "unexpected structure size"); + + inp->read (Array, handler_t::EncodedLength * Size); + } + else + { + for(size_t i = 0; i < Size; i++) + handler_t::extract (*this, Array[i]); + } } - Transformation getTrafo() + + template + void getStdVector (std::vector & Vector, size_t Size) { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; + Vector.resize(Size); + + getArray (&Vector.front (), Vector.size ()); } + template + void getStdVector (std::vector & Vector) + { + length_type Length; + + getValue (Length); + + getStdVector (Vector, Length); + } + + char getChar() { return getValue (); } + signed int getInt() { return getValue (); } + unsigned int getUInt() { return getValue (); } + signed short getShort() { return getValue (); } + unsigned short getUShort() { return getValue (); } + //signed long getLong() { return getValue (); } + //unsigned long getULong() { return getValue (); } + float getFloat() { return getValue (); } + + Ogre::Vector2 getVector2() { return getValue (); } + Ogre::Vector3 getVector3() { return getValue (); } + Ogre::Vector4 getVector4() { return getValue (); } + Ogre::Matrix3 getMatrix3() { return getValue (); } + Ogre::Quaternion getQuaternion() { return getValue (); } + + Transformation getTrafo() { return getValue (); } + + void getShorts(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getFloats(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector2s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector3s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector4s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getQuaternions(std::vector &vec, size_t size) { return getStdVector (vec, size); } + std::string getString(size_t length) { std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) + if(read(&str[0], length) != length) throw std::runtime_error ("string length in NIF file does not match"); return &str[0]; } std::string getString() { - size_t size = read_le32(); + size_t size = getValue (); return getString(size); } +}; - void getShorts(std::vector &vec, size_t size) +/* + * generic type handlers + */ + +template +struct NIFStream::handler < type [Size] > +{ + typedef handler inner_handler; + + static const bool FixedLength = inner_handler::FixedLength; + static const size_t EncodedLength = inner_handler::EncodedLength * Size; + static const bool FileCompatibleLayout = inner_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, type (&Value) [Size]) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + for (size_t i = 0; i < Size; ++i) + inner_handler::extract (Stream, Value [i]); } - void getFloats(std::vector &vec, size_t size) +}; + +template +struct NIFStream::le_handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = sizeof (backing_type); + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & Stream, presentation_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + BOOST_STATIC_ASSERT_MSG(sizeof (presentation_type) == sizeof (backing_type), "Invalid use of NIFile::le_handler template"); + + union { + + backing_type Backing; + presentation_type Presentation; + + } u; + + u.Backing = Stream.read_le (); + + Value = u.Presentation; } - void getVector2s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = false; + + static void extract (NIFStream & Stream, final_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + store_type StoreValue; + store_handler::extract (Stream, StoreValue); + Value = final_type (StoreValue); } - void getVector3s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = store_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, final_type & FinalValue) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + store_handler::extract (Stream, reinterpret_cast (FinalValue)); } - void getVector4s(std::vector &vec, size_t size) +}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; + +template <> struct NIFStream::handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = + handler ::EncodedLength + + handler ::EncodedLength + + handler ::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & stream, Transformation & value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); - } - void getQuaternions(std::vector &quat, size_t size) - { - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); + stream.uncheckedRead (value.pos); + stream.uncheckedRead (value.rotation); + stream.uncheckedRead (value.scale); } };