diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index ef5b8e1..1ce7fa2 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -1413,7 +1413,7 @@ namespace AssetStudio result[i] = BitConverter.ToSingle(inputBytes, i * 4); break; case VertexFormat.Float16: - result[i] = Half.ToHalf(inputBytes, i * 2); + result[i] = (float)HalfHelper.ToHalf(inputBytes, i * 2); break; case VertexFormat.UNorm8: result[i] = inputBytes[i] / 255f; diff --git a/AssetStudio/Math/Half.cs b/AssetStudio/Math/Half.cs index 45efd92..26b361f 100644 --- a/AssetStudio/Math/Half.cs +++ b/AssetStudio/Math/Half.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Globalization; +#if NETFRAMEWORK namespace AssetStudio { /// @@ -35,27 +36,27 @@ namespace AssetStudio /// /// Represents the smallest positive System.Half value greater than zero. This field is constant. /// - public static readonly Half Epsilon = Half.ToHalf(0x0001); + public static readonly Half Epsilon = HalfHelper.ToHalf(0x0001); /// /// Represents the largest possible value of System.Half. This field is constant. /// - public static readonly Half MaxValue = Half.ToHalf(0x7bff); + public static readonly Half MaxValue = HalfHelper.ToHalf(0x7bff); /// /// Represents the smallest possible value of System.Half. This field is constant. /// - public static readonly Half MinValue = Half.ToHalf(0xfbff); + public static readonly Half MinValue = HalfHelper.ToHalf(0xfbff); /// /// Represents not a number (NaN). This field is constant. /// - public static readonly Half NaN = Half.ToHalf(0xfe00); + public static readonly Half NaN = HalfHelper.ToHalf(0xfe00); /// /// Represents negative infinity. This field is constant. /// - public static readonly Half NegativeInfinity = Half.ToHalf(0xfc00); + public static readonly Half NegativeInfinity = HalfHelper.ToHalf(0xfc00); /// /// Represents positive infinity. This field is constant. /// - public static readonly Half PositiveInfinity = Half.ToHalf(0x7c00); + public static readonly Half PositiveInfinity = HalfHelper.ToHalf(0x7c00); #endregion #region Constructors @@ -63,7 +64,7 @@ namespace AssetStudio /// Initializes a new instance of System.Half to the value of the specified single-precision floating-point number. /// /// The value to represent as a System.Half. - public Half(float value) { this = HalfHelper.SingleToHalf(value); } + public Half(float value) { this = HalfHelper.ToHalf(value); } /// /// Initializes a new instance of System.Half to the value of the specified 32-bit signed integer. /// @@ -314,7 +315,7 @@ namespace AssetStudio /// /// A System.Half to convert. /// A single-precision floating-point number that represents the converted System.Half. - public static implicit operator float(Half value) { return (float)HalfHelper.HalfToSingle(value); } + public static implicit operator float(Half value) { return value.ToSingle(); } /// /// Converts a System.Half to a double-precision floating-point number. /// @@ -508,32 +509,6 @@ namespace AssetStudio { return value.value; } - /// - /// Returns a half-precision floating point number converted from two bytes - /// at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A half-precision floating point number formed by two bytes beginning at startIndex. - /// - /// startIndex is greater than or equal to the length of value minus 1, and is - /// less than or equal to the length of value minus 1. - /// - /// value is null. - /// startIndex is less than zero or greater than the length of value minus 1. - public static Half ToHalf(byte[] value, int startIndex) - { - return Half.ToHalf((ushort)BitConverter.ToInt16(value, startIndex)); - } - /// - /// Returns a half-precision floating point number converted from its binary representation. - /// - /// Binary representation of System.Half value - /// A half-precision floating point number formed by its binary representation. - public static Half ToHalf(ushort bits) - { - return new Half { value = bits }; - } /// /// Returns a value indicating the sign of a half-precision floating-point number. @@ -886,3 +861,4 @@ namespace AssetStudio #endregion } } +#endif diff --git a/AssetStudio/Math/HalfHelper.cs b/AssetStudio/Math/HalfHelper.cs index 82e46b4..5e05b1c 100644 --- a/AssetStudio/Math/HalfHelper.cs +++ b/AssetStudio/Math/HalfHelper.cs @@ -1,18 +1,32 @@ using System; +using System.Buffers.Binary; using System.Runtime.InteropServices; namespace AssetStudio { +#if NET + public static class HalfHelper + { + public static Half ToHalf(ushort bits) + { + return (Half)bits; + } + + public static Half ToHalf(ReadOnlySpan bytes, int startIndex) + { + return BinaryPrimitives.ReadHalfLittleEndian(bytes[startIndex..]); + } + } +#else /// /// Helper class for Half conversions and some low level operations. - /// This class is internally used in the Half class. /// /// /// References: /// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf /// [ComVisible(false)] - internal static class HalfHelper + public static class HalfHelper { private static uint[] mantissaTable = GenerateMantissaTable(); private static uint[] exponentTable = GenerateExponentTable(); @@ -169,27 +183,54 @@ namespace AssetStudio ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); return Half.ToHalf(result); }*/ - public static float HalfToSingle(Half half) + + /// + /// Returns a half-precision floating point number converted from two bytes + /// at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A half-precision floating point number formed by two bytes beginning at startIndex. + /// + /// startIndex is greater than or equal to the length of value minus 1, and is + /// less than or equal to the length of value minus 1. + /// + /// value is null. + /// startIndex is less than zero or greater than the length of value minus 1. + public static Half ToHalf(ReadOnlySpan value, int startIndex) + { + return ToHalf((ushort)BinaryPrimitives.ReadInt16LittleEndian(value.Slice(startIndex))); + } + /// + /// Returns a half-precision floating point number converted from its binary representation. + /// + /// Binary representation of System.Half value + /// A half-precision floating point number formed by its binary representation. + public static Half ToHalf(ushort bits) + { + return new Half { value = bits }; + } + public static Half ToHalf(float single) + { + byte[] singleBytes = BitConverter.GetBytes(single); + uint value = BitConverter.ToUInt32(singleBytes, 0); + ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); + return ToHalf(result); + } + public static float ToSingle(this Half half) { uint result = mantissaTable[offsetTable[half.value >> 10] + (half.value & 0x3ff)] + exponentTable[half.value >> 10]; byte[] uintBytes = BitConverter.GetBytes(result); return BitConverter.ToSingle(uintBytes, 0); } - public static Half SingleToHalf(float single) - { - byte[] singleBytes = BitConverter.GetBytes(single); - uint value = BitConverter.ToUInt32(singleBytes, 0); - ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); - return Half.ToHalf(result); - } public static Half Negate(Half half) { - return Half.ToHalf((ushort)(half.value ^ 0x8000)); + return ToHalf((ushort)(half.value ^ 0x8000)); } public static Half Abs(Half half) { - return Half.ToHalf((ushort)(half.value & 0x7fff)); + return ToHalf((ushort)(half.value & 0x7fff)); } public static bool IsNaN(Half half) @@ -209,4 +250,5 @@ namespace AssetStudio return (half.value == 0xfc00); } } +#endif } diff --git a/AssetStudioUtility/Texture2DConverter.cs b/AssetStudioUtility/Texture2DConverter.cs index 8e39187..34675f5 100644 --- a/AssetStudioUtility/Texture2DConverter.cs +++ b/AssetStudioUtility/Texture2DConverter.cs @@ -440,7 +440,7 @@ namespace AssetStudio { buff[i] = 0; buff[i + 1] = 0; - buff[i + 2] = (byte)MathF.Round(Half.ToHalf(image_data, i / 2) * 255f); + buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i / 2) * 255f); buff[i + 3] = 255; } return true; @@ -451,8 +451,8 @@ namespace AssetStudio for (var i = 0; i < outPutDataSize; i += 4) { buff[i] = 0; - buff[i + 1] = (byte)MathF.Round(Half.ToHalf(image_data, i + 2) * 255f); - buff[i + 2] = (byte)MathF.Round(Half.ToHalf(image_data, i) * 255f); + buff[i + 1] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i + 2) * 255f); + buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i) * 255f); buff[i + 3] = 255; } return true; @@ -462,10 +462,10 @@ namespace AssetStudio { for (var i = 0; i < outPutDataSize; i += 4) { - buff[i] = (byte)MathF.Round(Half.ToHalf(image_data, i * 2 + 4) * 255f); - buff[i + 1] = (byte)MathF.Round(Half.ToHalf(image_data, i * 2 + 2) * 255f); - buff[i + 2] = (byte)MathF.Round(Half.ToHalf(image_data, i * 2) * 255f); - buff[i + 3] = (byte)MathF.Round(Half.ToHalf(image_data, i * 2 + 6) * 255f); + buff[i] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 4) * 255f); + buff[i + 1] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 2) * 255f); + buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2) * 255f); + buff[i + 3] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 6) * 255f); } return true; }