diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 4f76139d9..b239ec6a1 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -8,7 +8,7 @@ namespace { // somewhat arbitrary though 64KB buffers didn't seem to improve performance any -const size_t sBufferSize = 4096; +const size_t sBufferSize = 8192; } namespace Files diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index d0fc9bab0..08a7466fa 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -6,138 +6,8 @@ namespace Nif { //Private functions -uint8_t NIFStream::read_byte() -{ - uint8_t byte; - inp->read((char*)&byte, 1); - return byte; -} -uint16_t NIFStream::read_le16() -{ - uint8_t buffer[2]; - inp->read((char*)buffer, 2); - return buffer[0] | (buffer[1]<<8); -} -uint32_t NIFStream::read_le32() -{ - uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); -} -float NIFStream::read_le32f() -{ - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; -} -//Public functions -osg::Vec2f NIFStream::getVector2() -{ - osg::Vec2f vec; - for(size_t i = 0;i < 2;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec3f NIFStream::getVector3() -{ - osg::Vec3f vec; - for(size_t i = 0;i < 3;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec4f NIFStream::getVector4() -{ - osg::Vec4f vec; - for(size_t i = 0;i < 4;i++) - vec._v[i] = getFloat(); - return vec; -} -Matrix3 NIFStream::getMatrix3() -{ - Matrix3 mat; - for(size_t i = 0;i < 3;i++) - { - for(size_t j = 0;j < 3;j++) - mat.mValues[i][j] = getFloat(); - } - return mat; -} -osg::Quat NIFStream::getQuaternion() -{ - osg::Quat quat; - quat.w() = getFloat(); - quat.x() = getFloat(); - quat.y() = getFloat(); - quat.z() = getFloat(); - return quat; -} -Transformation NIFStream::getTrafo() -{ - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; -} -std::string NIFStream::getString(size_t length) -{ - std::vector str (length+1, 0); - - inp->read(&str[0], length); - - return &str[0]; -} -std::string NIFStream::getString() -{ - size_t size = read_le32(); - return getString(size); -} -std::string NIFStream::getVersionString() -{ - std::string result; - std::getline(*inp, result); - return result; -} - -void NIFStream::getUShorts(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); -} -void NIFStream::getFloats(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); -} -void NIFStream::getVector2s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); -} -void NIFStream::getVector3s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); -} -void NIFStream::getVector4s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); -} -void NIFStream::getQuaternions(std::vector &quat, size_t size) -{ - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); -} +//Public functions } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 860c62e64..d00069be7 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -21,16 +21,70 @@ namespace Nif class NIFFile; +/* + readLittleEndianBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); + /* + Due to the loop iterations being known at compile time, + this nested loop will most likely be unrolled + For example, for 2 instances of a 4 byte data type, you should get the below result + */ + union { + IntegerT i; + T t; + } u; + for (uint32_t i = 0; i < numInstances; i++) + { + u = { 0 }; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + u.i |= (((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8)); + dest[i] = u.t; + } +#endif +} + +/* + readLittleEndianDynamicBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); + union { + IntegerT i; + T t; + } u; + for (uint32_t i = 0; i < numInstances; i++) + { + u.i = 0; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + u.i |= ((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8); + dest[i] = u.t; + } +#endif +} +template type inline readLittleEndianType(Files::IStreamPtr &pIStream) +{ + type val; + readLittleEndianBufferOfType<1,type,IntegerT>(pIStream, (type*)&val); + return val; +} + class NIFStream { /// Input stream Files::IStreamPtr inp; - uint8_t read_byte(); - uint16_t read_le16(); - uint32_t read_le32(); - float read_le32f(); - public: NIFFile * const file; @@ -39,33 +93,117 @@ public: void skip(size_t size) { inp->ignore(size); } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - unsigned int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - - osg::Vec2f getVector2(); - osg::Vec3f getVector3(); - osg::Vec4f getVector4(); - Matrix3 getMatrix3(); - osg::Quat getQuaternion(); - Transformation getTrafo(); + char getChar() + { + return readLittleEndianType(inp); + } + short getShort() + { + return readLittleEndianType(inp); + } + unsigned short getUShort() + { + return readLittleEndianType(inp); + } + int getInt() + { + return readLittleEndianType(inp); + } + unsigned int getUInt() + { + return readLittleEndianType(inp); + } + float getFloat() + { + return readLittleEndianType(inp); + } + + osg::Vec2f getVector2() { + osg::Vec2f vec; + readLittleEndianBufferOfType<2,float,uint32_t>(inp, (float*)&vec._v[0]); + return vec; + } + osg::Vec3f getVector3() { + osg::Vec3f vec; + readLittleEndianBufferOfType<3, float,uint32_t>(inp, (float*)&vec._v[0]); + return vec; + } + osg::Vec4f getVector4() { + osg::Vec4f vec; + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&vec._v[0]); + return vec; + } + Matrix3 getMatrix3() { + Matrix3 mat; + readLittleEndianBufferOfType<9, float,uint32_t>(inp, (float*)&mat.mValues); + return mat; + } + osg::Quat getQuaternion() { + float f[4]; + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&f); + osg::Quat quat; + quat.w() = f[0]; + quat.x() = f[1]; + quat.y() = f[2]; + quat.z() = f[3]; + return quat; + } + Transformation getTrafo() { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; + } ///Read in a string of the given length - std::string getString(size_t length); + std::string getString(size_t length) { + std::vector str(length + 1, 0); + + inp->read(&str[0], length); + + return &str[0]; + } ///Read in a string of the length specified in the file - std::string getString(); + std::string getString() { + size_t size = readLittleEndianType(inp); + return getString(size); + } ///This is special since the version string doesn't start with a number, and ends with "\n" - std::string getVersionString(); - - void getUShorts(std::vector &vec, size_t size); - void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); + std::string getVersionString() { + std::string result; + std::getline(*inp, result); + return result; + } + + void getUShorts(std::vector &vec, size_t size) { + vec.resize(size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + } + void getFloats(std::vector &vec, size_t size) { + vec.resize(size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + } + void getVector2s(std::vector &vec, size_t size) { + vec.resize(size); + /* The packed storage of each Vec2f is 2 floats exactly */ + readLittleEndianDynamicBufferOfType(inp,(float*) &vec.front(), size*2); + } + void getVector3s(std::vector &vec, size_t size) { + vec.resize(size); + /* The packed storage of each Vec3f is 3 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*3); + } + void getVector4s(std::vector &vec, size_t size) { + vec.resize(size); + /* The packed storage of each Vec4f is 4 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*4); + } + void getQuaternions(std::vector &quat, size_t size) { + quat.resize(size); + for (size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; }