/**************************************************************************** Copyright (c) 2006, Radon Labs GmbH Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #pragma once //------------------------------------------------------------------------------ /** @class System::ByteOrder Provides information and methods to help with byte ordering issues. The following byte orders are defined: - ByteOrder::LittleEndian: Intel byte order - ByteOrder::BigEndian: Motorola byte order - ByteOrder::Network network byte order (always big endian) - ByteOrder::Host hardwired to little or big endian depending on host cpu NOTE: on console-platforms it is strongly recommended to store binary data in console-byte-order during asset processing on the development PC, so that the console doesn't waste loading time with byte conversions! */ #include "core/types.h" #include "math/float4.h" #include "math/matrix44.h" //------------------------------------------------------------------------------ namespace System { class ByteOrder { public: // byte orders enum Type { LittleEndian = 0, // e.g. x86 BigEndian, // e.g. PowerPC Network = BigEndian, // network byte order #if __WIN32__ || __ANDROID__ Host = LittleEndian, #else Host = BigEndian, #endif }; /// default constructor ByteOrder(); /// constructor: set byte order conversion rule ByteOrder(Type fromByteOrder, Type toByteOrder); /// set from-byte-order void SetFromByteOrder(Type fromByteOrder); /// get from-byte-order Type GetFromByteOrder() const; /// set to-byte-order void SetToByteOrder(Type toByteOrder); /// get to-byte-order Type GetToByteOrder() const; /// endian-convert in place template void ConvertInPlace(TYPE& val) const; /// endian-convert by copy template TYPE Convert(TYPE val) const; /// endian-convert in place template static void ConvertInPlace(Type fromByteOrder, Type toByteOrder, TYPE& val); /// endian-convert by copy template static TYPE Convert(Type fromByteOrder, Type toByteOrder, TYPE val); private: Type from; Type to; union PunFloatUL { float f; ulong u; }; union PunDoubleULL { double d; unsigned long long u; }; }; //------------------------------------------------------------------------------ /** */ __forceinline ByteOrder::ByteOrder() : from(Host), to(Host) { // empty } //------------------------------------------------------------------------------ /** */ __forceinline ByteOrder::ByteOrder(ByteOrder::Type fromByteOrder, ByteOrder::Type toByteOrder) : from(fromByteOrder), to(toByteOrder) { // empty } //------------------------------------------------------------------------------ /** */ __forceinline void ByteOrder::SetFromByteOrder(Type fromByteOrder) { this->from = fromByteOrder; } //------------------------------------------------------------------------------ /** */ __forceinline ByteOrder::Type ByteOrder::GetFromByteOrder() const { return this->from; } //------------------------------------------------------------------------------ /** */ __forceinline void ByteOrder::SetToByteOrder(Type toByteOrder) { this->to = toByteOrder; } //------------------------------------------------------------------------------ /** */ __forceinline ByteOrder::Type ByteOrder::GetToByteOrder() const { return this->to; } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, short& val) { if (fromByteOrder != toByteOrder) { ushort res = _byteswap_ushort((ushort)val); val = (short)res; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(short& val) const { if (this->from != this->to) { ushort res = _byteswap_ushort((ushort)val); val = (short)res; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline short ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, short val) { if (fromByteOrder != toByteOrder) { return (short)_byteswap_ushort((ushort)val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline short ByteOrder::Convert(short val) const { if (this->from != this->to) { return (short)_byteswap_ushort((ushort)val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, ushort& val) { if (fromByteOrder != toByteOrder) { val = _byteswap_ushort(val); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(ushort& val) const { if (this->from != this->to) { val = _byteswap_ushort(val); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline ushort ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, ushort val) { if (fromByteOrder != toByteOrder) { return _byteswap_ushort(val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline ushort ByteOrder::Convert(ushort val) const { if (this->from != this->to) { return _byteswap_ushort(val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, int& val) { if (fromByteOrder != toByteOrder) { uint res = _byteswap_ulong((uint)val); val = (int)res; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(int& val) const { if (this->from != this->to) { uint res = _byteswap_ulong((uint)val); val = (int)res; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline int ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, int val) { if (fromByteOrder != toByteOrder) { return (int) _byteswap_ulong((uint)val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline int ByteOrder::Convert(int val) const { if (this->from != this->to) { return (int) _byteswap_ulong((uint)val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, uint& val) { if (fromByteOrder != toByteOrder) { val = _byteswap_ulong(val); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(uint& val) const { if (this->from != this->to) { val = _byteswap_ulong(val); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline uint ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, uint val) { if (fromByteOrder != toByteOrder) { return _byteswap_ulong(val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline uint ByteOrder::Convert(uint val) const { if (this->from != this->to) { return _byteswap_ulong(val); } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, float& val) { if (fromByteOrder != toByteOrder) { PunFloatUL pun; pun.f = val; pun.u = _byteswap_ulong(pun.u); val = pun.f; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(float& val) const { if (this->from != this->to) { PunFloatUL pun; pun.f = val; pun.u = _byteswap_ulong(pun.u); val = pun.f; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline float ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, float val) { if (fromByteOrder != toByteOrder) { PunFloatUL pun; pun.f = val; pun.u = _byteswap_ulong(pun.u); return pun.f; } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline float ByteOrder::Convert(float val) const { if (this->from != this->to) { PunFloatUL pun; pun.f = val; pun.u = _byteswap_ulong(pun.u); return pun.f; } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, double& val) { if (fromByteOrder != toByteOrder) { PunDoubleULL pun; pun.d = val; pun.u = _byteswap_uint64(pun.u); val = pun.d; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(double& val) const { if (this->from != this->to) { PunDoubleULL pun; pun.d = val; pun.u = _byteswap_uint64(pun.u); val = pun.d; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline double ByteOrder::Convert(Type fromByteOrder, Type toByteOrder, double val) { if (fromByteOrder != toByteOrder) { PunDoubleULL pun; pun.d = val; pun.u = _byteswap_uint64(pun.u); return pun.d; } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline double ByteOrder::Convert(double val) const { if (this->from != this->to) { PunDoubleULL pun; pun.d = val; pun.u = _byteswap_uint64(pun.u); return pun.d; } else { return val; } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, Math::float4& val) { if (fromByteOrder != toByteOrder) { ConvertInPlace(fromByteOrder, toByteOrder, val.x()); ConvertInPlace(fromByteOrder, toByteOrder, val.y()); ConvertInPlace(fromByteOrder, toByteOrder, val.z()); ConvertInPlace(fromByteOrder, toByteOrder, val.w()); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Math::float4& val) const { if (this->from != this->to) { ConvertInPlace(val.x()); ConvertInPlace(val.y()); ConvertInPlace(val.z()); ConvertInPlace(val.w()); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Type fromByteOrder, Type toByteOrder, Math::matrix44& val) { if (fromByteOrder != toByteOrder) { Math::float4 row0 = val.getrow0(); Math::float4 row1 = val.getrow1(); Math::float4 row2 = val.getrow2(); Math::float4 row3 = val.getrow3(); ConvertInPlace(fromByteOrder, toByteOrder, row0); ConvertInPlace(fromByteOrder, toByteOrder, row1); ConvertInPlace(fromByteOrder, toByteOrder, row2); ConvertInPlace(fromByteOrder, toByteOrder, row3); val.setrow0(row0); val.setrow1(row1); val.setrow2(row2); val.setrow3(row3); } } //------------------------------------------------------------------------------ /** */ template<> __forceinline void ByteOrder::ConvertInPlace(Math::matrix44& val) const { if (this->from != this->to) { Math::float4 row0 = val.getrow0(); Math::float4 row1 = val.getrow1(); Math::float4 row2 = val.getrow2(); Math::float4 row3 = val.getrow3(); ConvertInPlace(row0); ConvertInPlace(row1); ConvertInPlace(row2); ConvertInPlace(row3); val.setrow0(row0); val.setrow1(row1); val.setrow2(row2); val.setrow3(row3); } } } // namespace System //------------------------------------------------------------------------------