From e6ed312de2cb4c2f9291658a4186d542aa76c2cf Mon Sep 17 00:00:00 2001 From: Perfare Date: Thu, 3 Jan 2019 08:55:43 +0800 Subject: [PATCH] change math library fixed bug --- AssetStudio/AssetStudio.csproj | 15 +- AssetStudio/Classes/AnimationClip.cs | 1 - AssetStudio/Classes/AnimatorController.cs | 1 - AssetStudio/Classes/Avatar.cs | 3 +- AssetStudio/Classes/Material.cs | 7 +- AssetStudio/Classes/Mesh.cs | 9 +- AssetStudio/Classes/Sprite.cs | 5 +- AssetStudio/Classes/SpriteAtlas.cs | 3 +- AssetStudio/Classes/Transform.cs | 3 +- .../Extensions/BinaryReaderExtensions.cs | 19 +- AssetStudio/IImported.cs | 15 +- AssetStudio/Libraries/SharpDX.Mathematics.dll | Bin 215552 -> 0 bytes AssetStudio/Libraries/System.Half.dll | Bin 12800 -> 0 bytes AssetStudio/Math/Color.cs | 84 ++ AssetStudio/Math/Half.cs | 888 ++++++++++++++++++ AssetStudio/Math/HalfHelper.cs | 211 +++++ AssetStudio/Math/Matrix4x4f.cs | 241 +++++ AssetStudio/Math/Quaternion.cs | 66 ++ AssetStudio/Math/Vector2.cs | 150 +++ AssetStudio/Math/Vector3.cs | 146 +++ AssetStudio/Math/Vector4.cs | 163 ++++ AssetStudioFBX/AssetStudioFBX.h | 1 - AssetStudioFBX/AssetStudioFBX.vcxproj | 6 - AssetStudioFBX/AssetStudioFBXExporter.cpp | 32 +- AssetStudioGUI/AssetStudioGUIForm.cs | 4 +- AssetStudioUtility/AssetStudioUtility.csproj | 6 - AssetStudioUtility/ModelConverter.cs | 18 +- AssetStudioUtility/SpriteHelper.cs | 4 +- 28 files changed, 2011 insertions(+), 90 deletions(-) delete mode 100644 AssetStudio/Libraries/SharpDX.Mathematics.dll delete mode 100644 AssetStudio/Libraries/System.Half.dll create mode 100644 AssetStudio/Math/Color.cs create mode 100644 AssetStudio/Math/Half.cs create mode 100644 AssetStudio/Math/HalfHelper.cs create mode 100644 AssetStudio/Math/Matrix4x4f.cs create mode 100644 AssetStudio/Math/Quaternion.cs create mode 100644 AssetStudio/Math/Vector2.cs create mode 100644 AssetStudio/Math/Vector3.cs create mode 100644 AssetStudio/Math/Vector4.cs diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj index 8ce33cc..d1aa770 100644 --- a/AssetStudio/AssetStudio.csproj +++ b/AssetStudio/AssetStudio.csproj @@ -31,15 +31,9 @@ 4 - - Libraries\SharpDX.Mathematics.dll - - - Libraries\System.Half.dll - @@ -63,6 +57,14 @@ + + + + + + + + @@ -145,5 +147,6 @@ + \ No newline at end of file diff --git a/AssetStudio/Classes/AnimationClip.cs b/AssetStudio/Classes/AnimationClip.cs index 04eb23f..2c0d1cd 100644 --- a/AssetStudio/Classes/AnimationClip.cs +++ b/AssetStudio/Classes/AnimationClip.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using SharpDX; namespace AssetStudio { diff --git a/AssetStudio/Classes/AnimatorController.cs b/AssetStudio/Classes/AnimatorController.cs index ff4962c..24cdcdf 100644 --- a/AssetStudio/Classes/AnimatorController.cs +++ b/AssetStudio/Classes/AnimatorController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using SharpDX; namespace AssetStudio { diff --git a/AssetStudio/Classes/Avatar.cs b/AssetStudio/Classes/Avatar.cs index 074cce3..842b43e 100644 --- a/AssetStudio/Classes/Avatar.cs +++ b/AssetStudio/Classes/Avatar.cs @@ -1,5 +1,4 @@ -using SharpDX; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; namespace AssetStudio diff --git a/AssetStudio/Classes/Material.cs b/AssetStudio/Classes/Material.cs index a855b0a..abc689c 100644 --- a/AssetStudio/Classes/Material.cs +++ b/AssetStudio/Classes/Material.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using SharpDX; namespace AssetStudio { @@ -21,7 +20,7 @@ namespace AssetStudio { public KeyValuePair[] m_TexEnvs; public KeyValuePair[] m_Floats; - public KeyValuePair[] m_Colors; + public KeyValuePair[] m_Colors; public UnityPropertySheet(ObjectReader reader) { @@ -40,10 +39,10 @@ namespace AssetStudio } int m_ColorsSize = reader.ReadInt32(); - m_Colors = new KeyValuePair[m_ColorsSize]; + m_Colors = new KeyValuePair[m_ColorsSize]; for (int i = 0; i < m_ColorsSize; i++) { - m_Colors[i] = new KeyValuePair(reader.ReadAlignedString(), reader.ReadColor4()); + m_Colors[i] = new KeyValuePair(reader.ReadAlignedString(), reader.ReadColor4()); } } } diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index c8baf1d..04187d1 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using SharpDX; namespace AssetStudio { @@ -428,7 +427,7 @@ namespace AssetStudio public SubMesh[] m_SubMeshes; private uint[] m_IndexBuffer; public BlendShapeData m_Shapes; - public Matrix[] m_BindPose; + public Matrix4x4[] m_BindPose; public uint[] m_BoneNameHashes; public int m_VertexCount; public float[] m_Vertices; @@ -845,13 +844,13 @@ namespace AssetStudio { if (m_CompressedMesh.m_BindPoses.m_NumItems > 0) { - m_BindPose = new Matrix[m_CompressedMesh.m_BindPoses.m_NumItems / 16]; + m_BindPose = new Matrix4x4[m_CompressedMesh.m_BindPoses.m_NumItems / 16]; var m_BindPoses_Unpacked = m_CompressedMesh.m_BindPoses.UnpackFloats(16, 4 * 16); var buffer = new float[16]; for (int i = 0; i < m_BindPose.Length; i++) { Array.Copy(m_BindPoses_Unpacked, i * 16, buffer, 0, 16); - m_BindPose[i] = new Matrix(buffer); + m_BindPose[i] = new Matrix4x4(buffer); } } } @@ -1082,7 +1081,7 @@ namespace AssetStudio value = inputBytes[i] / 255.0f; break; case 2: - value = System.Half.ToHalf(inputBytes, i * 2); + value = Half.ToHalf(inputBytes, i * 2); break; case 4: value = BitConverter.ToSingle(inputBytes, i * 4); diff --git a/AssetStudio/Classes/Sprite.cs b/AssetStudio/Classes/Sprite.cs index e970099..7500a52 100644 --- a/AssetStudio/Classes/Sprite.cs +++ b/AssetStudio/Classes/Sprite.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using SharpDX; -using RectangleF = System.Drawing.RectangleF; +using System.Drawing; namespace AssetStudio { @@ -67,7 +66,7 @@ namespace AssetStudio public VertexData m_VertexData; public SpriteVertex[] vertices; public ushort[] indices; - public Matrix[] m_Bindpose; + public Matrix4x4[] m_Bindpose; public BoneWeights4[] m_SourceSkin; public RectangleF textureRect; public Vector2 textureRectOffset; diff --git a/AssetStudio/Classes/SpriteAtlas.cs b/AssetStudio/Classes/SpriteAtlas.cs index 27df0d6..c0cc60b 100644 --- a/AssetStudio/Classes/SpriteAtlas.cs +++ b/AssetStudio/Classes/SpriteAtlas.cs @@ -1,5 +1,4 @@ -using SharpDX; -using System; +using System; using System.Collections.Generic; namespace AssetStudio diff --git a/AssetStudio/Classes/Transform.cs b/AssetStudio/Classes/Transform.cs index 95050b5..4e730a0 100644 --- a/AssetStudio/Classes/Transform.cs +++ b/AssetStudio/Classes/Transform.cs @@ -1,5 +1,4 @@ -using SharpDX; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/AssetStudio/Extensions/BinaryReaderExtensions.cs b/AssetStudio/Extensions/BinaryReaderExtensions.cs index 1670aec..bf01a3f 100644 --- a/AssetStudio/Extensions/BinaryReaderExtensions.cs +++ b/AssetStudio/Extensions/BinaryReaderExtensions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Text; -using SharpDX; namespace AssetStudio { @@ -78,22 +77,14 @@ namespace AssetStudio return new System.Drawing.RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } - public static Color4 ReadColor4(this BinaryReader reader) + public static Color ReadColor4(this BinaryReader reader) { - return new Color4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } - public static Matrix ReadMatrix(this BinaryReader reader) + public static Matrix4x4 ReadMatrix(this BinaryReader reader) { - var m = new Matrix(); - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - m[i, j] = reader.ReadSingle(); - } - } - return m; + return new Matrix4x4(reader.ReadSingleArray(16)); } private static T[] ReadArray(Func del, int length) @@ -161,7 +152,7 @@ namespace AssetStudio return ReadArray(reader.ReadVector4, reader.ReadInt32()); } - public static Matrix[] ReadMatrixArray(this BinaryReader reader) + public static Matrix4x4[] ReadMatrixArray(this BinaryReader reader) { return ReadArray(reader.ReadMatrix, reader.ReadInt32()); } diff --git a/AssetStudio/IImported.cs b/AssetStudio/IImported.cs index 16087af..fd142d8 100644 --- a/AssetStudio/IImported.cs +++ b/AssetStudio/IImported.cs @@ -2,7 +2,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; -using SharpDX; namespace AssetStudio { @@ -146,7 +145,7 @@ namespace AssetStudio public class ImportedVertexWithColour : ImportedVertex { - public Color4 Colour { get; set; } + public Color Colour { get; set; } } public class ImportedFace @@ -157,17 +156,17 @@ namespace AssetStudio public class ImportedBone { public string Path { get; set; } - public Matrix Matrix { get; set; } + public Matrix4x4 Matrix { get; set; } } public class ImportedMaterial { public string Name { get; set; } - public Color4 Diffuse { get; set; } - public Color4 Ambient { get; set; } - public Color4 Specular { get; set; } - public Color4 Emissive { get; set; } - public Color4 Reflection { get; set; } + public Color Diffuse { get; set; } + public Color Ambient { get; set; } + public Color Specular { get; set; } + public Color Emissive { get; set; } + public Color Reflection { get; set; } public float Shininess { get; set; } public float Transparency { get; set; } public List Textures { get; set; } diff --git a/AssetStudio/Libraries/SharpDX.Mathematics.dll b/AssetStudio/Libraries/SharpDX.Mathematics.dll deleted file mode 100644 index 75bbb0dfa56473cb2de313ac42989cbbcb88f214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 215552 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
    ~FA^4S;p*CRoFK#0zU! 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 F{|7f{gvtN_ diff --git a/AssetStudio/Libraries/System.Half.dll b/AssetStudio/Libraries/System.Half.dll deleted file mode 100644 index 068cb28688e871229beee4f2aa34a7378883e7cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12800 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 + { + public float R; + public float G; + public float B; + public float A; + + public Color(float r, float g, float b, float a) + { + R = r; + G = g; + B = b; + A = a; + } + + public override int GetHashCode() + { + return ((Vector4)this).GetHashCode(); + } + + public override bool Equals(object other) + { + if (!(other is Color)) + return false; + return Equals((Color)other); + } + + public bool Equals(Color other) + { + return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); + } + + public static Color operator +(Color a, Color b) + { + return new Color(a.R + b.R, a.G + b.G, a.B + b.B, a.A + b.A); + } + + public static Color operator -(Color a, Color b) + { + return new Color(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A); + } + + public static Color operator *(Color a, Color b) + { + return new Color(a.R * b.R, a.G * b.G, a.B * b.B, a.A * b.A); + } + + public static Color operator *(Color a, float b) + { + return new Color(a.R * b, a.G * b, a.B * b, a.A * b); + } + + public static Color operator *(float b, Color a) + { + return new Color(a.R * b, a.G * b, a.B * b, a.A * b); + } + + public static Color operator /(Color a, float b) + { + return new Color(a.R / b, a.G / b, a.B / b, a.A / b); + } + + public static bool operator ==(Color lhs, Color rhs) + { + return (Vector4)lhs == (Vector4)rhs; + } + + public static bool operator !=(Color lhs, Color rhs) + { + return !(lhs == rhs); + } + + public static implicit operator Vector4(Color c) + { + return new Vector4(c.R, c.G, c.B, c.A); + } + } +} diff --git a/AssetStudio/Math/Half.cs b/AssetStudio/Math/Half.cs new file mode 100644 index 0000000..4bf2f57 --- /dev/null +++ b/AssetStudio/Math/Half.cs @@ -0,0 +1,888 @@ +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace System +{ + /// + /// Represents a half-precision floating point number. + /// + /// + /// Note: + /// Half is not fast enought and precision is also very bad, + /// so is should not be used for matemathical computation (use Single instead). + /// The main advantage of Half type is lower memory cost: two bytes per number. + /// Half is typically used in graphical applications. + /// + /// Note: + /// All functions, where is used conversion half->float/float->half, + /// are approx. ten times slower than float->double/double->float, i.e. ~3ns on 2GHz CPU. + /// + /// References: + /// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf + /// - IEEE 754 revision, link: http://grouper.ieee.org/groups/754/ + /// + [Serializable] + public struct Half : IComparable, IFormattable, IConvertible, IComparable, IEquatable + { + /// + /// Internal representation of the half-precision floating-point number. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal ushort value; + + #region Constants + /// + /// Represents the smallest positive System.Half value greater than zero. This field is constant. + /// + public static readonly Half Epsilon = Half.ToHalf(0x0001); + /// + /// Represents the largest possible value of System.Half. This field is constant. + /// + public static readonly Half MaxValue = Half.ToHalf(0x7bff); + /// + /// Represents the smallest possible value of System.Half. This field is constant. + /// + public static readonly Half MinValue = Half.ToHalf(0xfbff); + /// + /// Represents not a number (NaN). This field is constant. + /// + public static readonly Half NaN = Half.ToHalf(0xfe00); + /// + /// Represents negative infinity. This field is constant. + /// + public static readonly Half NegativeInfinity = Half.ToHalf(0xfc00); + /// + /// Represents positive infinity. This field is constant. + /// + public static readonly Half PositiveInfinity = Half.ToHalf(0x7c00); + #endregion + + #region Constructors + /// + /// 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); } + /// + /// Initializes a new instance of System.Half to the value of the specified 32-bit signed integer. + /// + /// The value to represent as a System.Half. + public Half(int value) : this((float)value) { } + /// + /// Initializes a new instance of System.Half to the value of the specified 64-bit signed integer. + /// + /// The value to represent as a System.Half. + public Half(long value) : this((float)value) { } + /// + /// Initializes a new instance of System.Half to the value of the specified double-precision floating-point number. + /// + /// The value to represent as a System.Half. + public Half(double value) : this((float)value) { } + /// + /// Initializes a new instance of System.Half to the value of the specified decimal number. + /// + /// The value to represent as a System.Half. + public Half(decimal value) : this((float)value) { } + /// + /// Initializes a new instance of System.Half to the value of the specified 32-bit unsigned integer. + /// + /// The value to represent as a System.Half. + public Half(uint value) : this((float)value) { } + /// + /// Initializes a new instance of System.Half to the value of the specified 64-bit unsigned integer. + /// + /// The value to represent as a System.Half. + public Half(ulong value) : this((float)value) { } + #endregion + + #region Numeric operators + + /// + /// Returns the result of multiplying the specified System.Half value by negative one. + /// + /// A System.Half. + /// A System.Half with the value of half, but the opposite sign. -or- Zero, if half is zero. + public static Half Negate(Half half) { return -half; } + /// + /// Adds two specified System.Half values. + /// + /// A System.Half. + /// A System.Half. + /// A System.Half value that is the sum of half1 and half2. + public static Half Add(Half half1, Half half2) { return half1 + half2; } + /// + /// Subtracts one specified System.Half value from another. + /// + /// A System.Half (the minuend). + /// A System.Half (the subtrahend). + /// The System.Half result of subtracting half2 from half1. + public static Half Subtract(Half half1, Half half2) { return half1 - half2; } + /// + /// Multiplies two specified System.Half values. + /// + /// A System.Half (the multiplicand). + /// A System.Half (the multiplier). + /// A System.Half that is the result of multiplying half1 and half2. + public static Half Multiply(Half half1, Half half2) { return half1 * half2; } + /// + /// Divides two specified System.Half values. + /// + /// A System.Half (the dividend). + /// A System.Half (the divisor). + /// The System.Half that is the result of dividing half1 by half2. + /// half2 is zero. + public static Half Divide(Half half1, Half half2) { return half1 / half2; } + + /// + /// Returns the value of the System.Half operand (the sign of the operand is unchanged). + /// + /// The System.Half operand. + /// The value of the operand, half. + public static Half operator +(Half half) { return half; } + /// + /// Negates the value of the specified System.Half operand. + /// + /// The System.Half operand. + /// The result of half multiplied by negative one (-1). + public static Half operator -(Half half) { return HalfHelper.Negate(half); } + /// + /// Increments the System.Half operand by 1. + /// + /// The System.Half operand. + /// The value of half incremented by 1. + public static Half operator ++(Half half) { return (Half)(half + 1f); } + /// + /// Decrements the System.Half operand by one. + /// + /// The System.Half operand. + /// The value of half decremented by 1. + public static Half operator --(Half half) { return (Half)(half - 1f); } + /// + /// Adds two specified System.Half values. + /// + /// A System.Half. + /// A System.Half. + /// The System.Half result of adding half1 and half2. + public static Half operator +(Half half1, Half half2) { return (Half)((float)half1 + (float)half2); } + /// + /// Subtracts two specified System.Half values. + /// + /// A System.Half. + /// A System.Half. + /// The System.Half result of subtracting half1 and half2. + public static Half operator -(Half half1, Half half2) { return (Half)((float)half1 - (float)half2); } + /// + /// Multiplies two specified System.Half values. + /// + /// A System.Half. + /// A System.Half. + /// The System.Half result of multiplying half1 by half2. + public static Half operator *(Half half1, Half half2) { return (Half)((float)half1 * (float)half2); } + /// + /// Divides two specified System.Half values. + /// + /// A System.Half (the dividend). + /// A System.Half (the divisor). + /// The System.Half result of half1 by half2. + public static Half operator /(Half half1, Half half2) { return (Half)((float)half1 / (float)half2); } + /// + /// Returns a value indicating whether two instances of System.Half are equal. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 and half2 are equal; otherwise, false. + public static bool operator ==(Half half1, Half half2) { return (!IsNaN(half1) && (half1.value == half2.value)); } + /// + /// Returns a value indicating whether two instances of System.Half are not equal. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 and half2 are not equal; otherwise, false. + public static bool operator !=(Half half1, Half half2) { return !(half1.value == half2.value); } + /// + /// Returns a value indicating whether a specified System.Half is less than another specified System.Half. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 is less than half1; otherwise, false. + public static bool operator <(Half half1, Half half2) { return (float)half1 < (float)half2; } + /// + /// Returns a value indicating whether a specified System.Half is greater than another specified System.Half. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 is greater than half2; otherwise, false. + public static bool operator >(Half half1, Half half2) { return (float)half1 > (float)half2; } + /// + /// Returns a value indicating whether a specified System.Half is less than or equal to another specified System.Half. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 is less than or equal to half2; otherwise, false. + public static bool operator <=(Half half1, Half half2) { return (half1 == half2) || (half1 < half2); } + /// + /// Returns a value indicating whether a specified System.Half is greater than or equal to another specified System.Half. + /// + /// A System.Half. + /// A System.Half. + /// true if half1 is greater than or equal to half2; otherwise, false. + public static bool operator >=(Half half1, Half half2) { return (half1 == half2) || (half1 > half2); } + #endregion + + #region Type casting operators + /// + /// Converts an 8-bit unsigned integer to a System.Half. + /// + /// An 8-bit unsigned integer. + /// A System.Half that represents the converted 8-bit unsigned integer. + public static implicit operator Half(byte value) { return new Half((float)value); } + /// + /// Converts a 16-bit signed integer to a System.Half. + /// + /// A 16-bit signed integer. + /// A System.Half that represents the converted 16-bit signed integer. + public static implicit operator Half(short value) { return new Half((float)value); } + /// + /// Converts a Unicode character to a System.Half. + /// + /// A Unicode character. + /// A System.Half that represents the converted Unicode character. + public static implicit operator Half(char value) { return new Half((float)value); } + /// + /// Converts a 32-bit signed integer to a System.Half. + /// + /// A 32-bit signed integer. + /// A System.Half that represents the converted 32-bit signed integer. + public static implicit operator Half(int value) { return new Half((float)value); } + /// + /// Converts a 64-bit signed integer to a System.Half. + /// + /// A 64-bit signed integer. + /// A System.Half that represents the converted 64-bit signed integer. + public static implicit operator Half(long value) { return new Half((float)value); } + /// + /// Converts a single-precision floating-point number to a System.Half. + /// + /// A single-precision floating-point number. + /// A System.Half that represents the converted single-precision floating point number. + public static explicit operator Half(float value) { return new Half((float)value); } + /// + /// Converts a double-precision floating-point number to a System.Half. + /// + /// A double-precision floating-point number. + /// A System.Half that represents the converted double-precision floating point number. + public static explicit operator Half(double value) { return new Half((float)value); } + /// + /// Converts a decimal number to a System.Half. + /// + /// decimal number + /// A System.Half that represents the converted decimal number. + public static explicit operator Half(decimal value) { return new Half((float)value); } + /// + /// Converts a System.Half to an 8-bit unsigned integer. + /// + /// A System.Half to convert. + /// An 8-bit unsigned integer that represents the converted System.Half. + public static explicit operator byte(Half value) { return (byte)(float)value; } + /// + /// Converts a System.Half to a Unicode character. + /// + /// A System.Half to convert. + /// A Unicode character that represents the converted System.Half. + public static explicit operator char(Half value) { return (char)(float)value; } + /// + /// Converts a System.Half to a 16-bit signed integer. + /// + /// A System.Half to convert. + /// A 16-bit signed integer that represents the converted System.Half. + public static explicit operator short(Half value) { return (short)(float)value; } + /// + /// Converts a System.Half to a 32-bit signed integer. + /// + /// A System.Half to convert. + /// A 32-bit signed integer that represents the converted System.Half. + public static explicit operator int(Half value) { return (int)(float)value; } + /// + /// Converts a System.Half to a 64-bit signed integer. + /// + /// A System.Half to convert. + /// A 64-bit signed integer that represents the converted System.Half. + public static explicit operator long(Half value) { return (long)(float)value; } + /// + /// Converts a System.Half to a single-precision floating-point number. + /// + /// 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); } + /// + /// Converts a System.Half to a double-precision floating-point number. + /// + /// A System.Half to convert. + /// A double-precision floating-point number that represents the converted System.Half. + public static implicit operator double(Half value) { return (double)(float)value; } + /// + /// Converts a System.Half to a decimal number. + /// + /// A System.Half to convert. + /// A decimal number that represents the converted System.Half. + public static explicit operator decimal(Half value) { return (decimal)(float)value; } + /// + /// Converts an 8-bit signed integer to a System.Half. + /// + /// An 8-bit signed integer. + /// A System.Half that represents the converted 8-bit signed integer. + public static implicit operator Half(sbyte value) { return new Half((float)value); } + /// + /// Converts a 16-bit unsigned integer to a System.Half. + /// + /// A 16-bit unsigned integer. + /// A System.Half that represents the converted 16-bit unsigned integer. + public static implicit operator Half(ushort value) { return new Half((float)value); } + /// + /// Converts a 32-bit unsigned integer to a System.Half. + /// + /// A 32-bit unsigned integer. + /// A System.Half that represents the converted 32-bit unsigned integer. + public static implicit operator Half(uint value) { return new Half((float)value); } + /// + /// Converts a 64-bit unsigned integer to a System.Half. + /// + /// A 64-bit unsigned integer. + /// A System.Half that represents the converted 64-bit unsigned integer. + public static implicit operator Half(ulong value) { return new Half((float)value); } + /// + /// Converts a System.Half to an 8-bit signed integer. + /// + /// A System.Half to convert. + /// An 8-bit signed integer that represents the converted System.Half. + public static explicit operator sbyte(Half value) { return (sbyte)(float)value; } + /// + /// Converts a System.Half to a 16-bit unsigned integer. + /// + /// A System.Half to convert. + /// A 16-bit unsigned integer that represents the converted System.Half. + public static explicit operator ushort(Half value) { return (ushort)(float)value; } + /// + /// Converts a System.Half to a 32-bit unsigned integer. + /// + /// A System.Half to convert. + /// A 32-bit unsigned integer that represents the converted System.Half. + public static explicit operator uint(Half value) { return (uint)(float)value; } + /// + /// Converts a System.Half to a 64-bit unsigned integer. + /// + /// A System.Half to convert. + /// A 64-bit unsigned integer that represents the converted System.Half. + public static explicit operator ulong(Half value) { return (ulong)(float)value; } + #endregion + + /// + /// Compares this instance to a specified System.Half object. + /// + /// A System.Half object. + /// + /// A signed number indicating the relative values of this instance and value. + /// Return Value Meaning Less than zero This instance is less than value. Zero + /// This instance is equal to value. Greater than zero This instance is greater than value. + /// + public int CompareTo(Half other) + { + int result = 0; + if (this < other) + { + result = -1; + } + else if (this > other) + { + result = 1; + } + else if (this != other) + { + if (!IsNaN(this)) + { + result = 1; + } + else if (!IsNaN(other)) + { + result = -1; + } + } + + return result; + } + /// + /// Compares this instance to a specified System.Object. + /// + /// An System.Object or null. + /// + /// A signed number indicating the relative values of this instance and value. + /// Return Value Meaning Less than zero This instance is less than value. Zero + /// This instance is equal to value. Greater than zero This instance is greater + /// than value. -or- value is null. + /// + /// value is not a System.Half + public int CompareTo(object obj) + { + int result = 0; + if (obj == null) + { + result = 1; + } + else + { + if (obj is Half) + { + result = CompareTo((Half)obj); + } + else + { + throw new ArgumentException("Object must be of type Half."); + } + } + + return result; + } + /// + /// Returns a value indicating whether this instance and a specified System.Half object represent the same value. + /// + /// A System.Half object to compare to this instance. + /// true if value is equal to this instance; otherwise, false. + public bool Equals(Half other) + { + return ((other == this) || (IsNaN(other) && IsNaN(this))); + } + /// + /// Returns a value indicating whether this instance and a specified System.Object + /// represent the same type and value. + /// + /// An System.Object. + /// true if value is a System.Half and equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + bool result = false; + if (obj is Half) + { + Half half = (Half)obj; + if ((half == this) || (IsNaN(half) && IsNaN(this))) + { + result = true; + } + } + + return result; + } + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return value.GetHashCode(); + } + /// + /// Returns the System.TypeCode for value type System.Half. + /// + /// The enumerated constant (TypeCode)255. + public TypeCode GetTypeCode() + { + return (TypeCode)255; + } + + #region BitConverter & Math methods for Half + /// + /// Returns the specified half-precision floating point value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 2. + public static byte[] GetBytes(Half value) + { + return BitConverter.GetBytes(value.value); + } + /// + /// Converts the value of a specified instance of System.Half to its equivalent binary representation. + /// + /// A System.Half value. + /// A 16-bit unsigned integer that contain the binary representation of value. + public static ushort GetBits(Half value) + { + 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. + /// + /// A signed number. + /// + /// A number indicating the sign of value. Number Description -1 value is less + /// than zero. 0 value is equal to zero. 1 value is greater than zero. + /// + /// value is equal to System.Half.NaN. + public static int Sign(Half value) + { + if (value < 0) + { + return -1; + } + else if (value > 0) + { + return 1; + } + else + { + if (value != 0) + { + throw new ArithmeticException("Function does not accept floating point Not-a-Number values."); + } + } + + return 0; + } + /// + /// Returns the absolute value of a half-precision floating-point number. + /// + /// A number in the range System.Half.MinValue ≤ value ≤ System.Half.MaxValue. + /// A half-precision floating-point number, x, such that 0 ≤ x ≤System.Half.MaxValue. + public static Half Abs(Half value) + { + return HalfHelper.Abs(value); + } + /// + /// Returns the larger of two half-precision floating-point numbers. + /// + /// The first of two half-precision floating-point numbers to compare. + /// The second of two half-precision floating-point numbers to compare. + /// + /// Parameter value1 or value2, whichever is larger. If value1, or value2, or both val1 + /// and value2 are equal to System.Half.NaN, System.Half.NaN is returned. + /// + public static Half Max(Half value1, Half value2) + { + return (value1 < value2) ? value2 : value1; + } + /// + /// Returns the smaller of two half-precision floating-point numbers. + /// + /// The first of two half-precision floating-point numbers to compare. + /// The second of two half-precision floating-point numbers to compare. + /// + /// Parameter value1 or value2, whichever is smaller. If value1, or value2, or both val1 + /// and value2 are equal to System.Half.NaN, System.Half.NaN is returned. + /// + public static Half Min(Half value1, Half value2) + { + return (value1 < value2) ? value1 : value2; + } + #endregion + + /// + /// Returns a value indicating whether the specified number evaluates to not a number (System.Half.NaN). + /// + /// A half-precision floating-point number. + /// true if value evaluates to not a number (System.Half.NaN); otherwise, false. + public static bool IsNaN(Half half) + { + return HalfHelper.IsNaN(half); + } + /// + /// Returns a value indicating whether the specified number evaluates to negative or positive infinity. + /// + /// A half-precision floating-point number. + /// true if half evaluates to System.Half.PositiveInfinity or System.Half.NegativeInfinity; otherwise, false. + public static bool IsInfinity(Half half) + { + return HalfHelper.IsInfinity(half); + } + /// + /// Returns a value indicating whether the specified number evaluates to negative infinity. + /// + /// A half-precision floating-point number. + /// true if half evaluates to System.Half.NegativeInfinity; otherwise, false. + public static bool IsNegativeInfinity(Half half) + { + return HalfHelper.IsNegativeInfinity(half); + } + /// + /// Returns a value indicating whether the specified number evaluates to positive infinity. + /// + /// A half-precision floating-point number. + /// true if half evaluates to System.Half.PositiveInfinity; otherwise, false. + public static bool IsPositiveInfinity(Half half) + { + return HalfHelper.IsPositiveInfinity(half); + } + + #region String operations (Parse and ToString) + /// + /// Converts the string representation of a number to its System.Half equivalent. + /// + /// The string representation of the number to convert. + /// The System.Half number equivalent to the number contained in value. + /// value is null. + /// value is not in the correct format. + /// value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue. + public static Half Parse(string value) + { + return (Half)float.Parse(value, CultureInfo.InvariantCulture); + } + /// + /// Converts the string representation of a number to its System.Half equivalent + /// using the specified culture-specific format information. + /// + /// The string representation of the number to convert. + /// An System.IFormatProvider that supplies culture-specific parsing information about value. + /// The System.Half number equivalent to the number contained in s as specified by provider. + /// value is null. + /// value is not in the correct format. + /// value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue. + public static Half Parse(string value, IFormatProvider provider) + { + return (Half)float.Parse(value, provider); + } + /// + /// Converts the string representation of a number in a specified style to its System.Half equivalent. + /// + /// The string representation of the number to convert. + /// + /// A bitwise combination of System.Globalization.NumberStyles values that indicates + /// the style elements that can be present in value. A typical value to specify is + /// System.Globalization.NumberStyles.Number. + /// + /// The System.Half number equivalent to the number contained in s as specified by style. + /// value is null. + /// + /// style is not a System.Globalization.NumberStyles value. -or- style is the + /// System.Globalization.NumberStyles.AllowHexSpecifier value. + /// + /// value is not in the correct format. + /// value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue. + public static Half Parse(string value, NumberStyles style) + { + return (Half)float.Parse(value, style, CultureInfo.InvariantCulture); + } + /// + /// Converts the string representation of a number to its System.Half equivalent + /// using the specified style and culture-specific format. + /// + /// The string representation of the number to convert. + /// + /// A bitwise combination of System.Globalization.NumberStyles values that indicates + /// the style elements that can be present in value. A typical value to specify is + /// System.Globalization.NumberStyles.Number. + /// + /// An System.IFormatProvider object that supplies culture-specific information about the format of value. + /// The System.Half number equivalent to the number contained in s as specified by style and provider. + /// value is null. + /// + /// style is not a System.Globalization.NumberStyles value. -or- style is the + /// System.Globalization.NumberStyles.AllowHexSpecifier value. + /// + /// value is not in the correct format. + /// value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue. + public static Half Parse(string value, NumberStyles style, IFormatProvider provider) + { + return (Half)float.Parse(value, style, provider); + } + /// + /// Converts the string representation of a number to its System.Half equivalent. + /// A return value indicates whether the conversion succeeded or failed. + /// + /// The string representation of the number to convert. + /// + /// When this method returns, contains the System.Half number that is equivalent + /// to the numeric value contained in value, if the conversion succeeded, or is zero + /// if the conversion failed. The conversion fails if the s parameter is null, + /// is not a number in a valid format, or represents a number less than System.Half.MinValue + /// or greater than System.Half.MaxValue. This parameter is passed uninitialized. + /// + /// true if s was converted successfully; otherwise, false. + public static bool TryParse(string value, out Half result) + { + float f; + if (float.TryParse(value, out f)) + { + result = (Half)f; + return true; + } + + result = new Half(); + return false; + } + /// + /// Converts the string representation of a number to its System.Half equivalent + /// using the specified style and culture-specific format. A return value indicates + /// whether the conversion succeeded or failed. + /// + /// The string representation of the number to convert. + /// + /// A bitwise combination of System.Globalization.NumberStyles values that indicates + /// the permitted format of value. A typical value to specify is System.Globalization.NumberStyles.Number. + /// + /// An System.IFormatProvider object that supplies culture-specific parsing information about value. + /// + /// When this method returns, contains the System.Half number that is equivalent + /// to the numeric value contained in value, if the conversion succeeded, or is zero + /// if the conversion failed. The conversion fails if the s parameter is null, + /// is not in a format compliant with style, or represents a number less than + /// System.Half.MinValue or greater than System.Half.MaxValue. This parameter is passed uninitialized. + /// + /// true if s was converted successfully; otherwise, false. + /// + /// style is not a System.Globalization.NumberStyles value. -or- style + /// is the System.Globalization.NumberStyles.AllowHexSpecifier value. + /// + public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Half result) + { + bool parseResult = false; + float f; + if (float.TryParse(value, style, provider, out f)) + { + result = (Half)f; + parseResult = true; + } + else + { + result = new Half(); + } + + return parseResult; + } + /// + /// Converts the numeric value of this instance to its equivalent string representation. + /// + /// A string that represents the value of this instance. + public override string ToString() + { + return ((float)this).ToString(CultureInfo.InvariantCulture); + } + /// + /// Converts the numeric value of this instance to its equivalent string representation + /// using the specified culture-specific format information. + /// + /// An System.IFormatProvider that supplies culture-specific formatting information. + /// The string representation of the value of this instance as specified by provider. + public string ToString(IFormatProvider formatProvider) + { + return ((float)this).ToString(formatProvider); + } + /// + /// Converts the numeric value of this instance to its equivalent string representation, using the specified format. + /// + /// A numeric format string. + /// The string representation of the value of this instance as specified by format. + public string ToString(string format) + { + return ((float)this).ToString(format, CultureInfo.InvariantCulture); + } + /// + /// Converts the numeric value of this instance to its equivalent string representation + /// using the specified format and culture-specific format information. + /// + /// A numeric format string. + /// An System.IFormatProvider that supplies culture-specific formatting information. + /// The string representation of the value of this instance as specified by format and provider. + /// format is invalid. + public string ToString(string format, IFormatProvider formatProvider) + { + return ((float)this).ToString(format, formatProvider); + } + #endregion + + #region IConvertible Members + float IConvertible.ToSingle(IFormatProvider provider) + { + return (float)this; + } + TypeCode IConvertible.GetTypeCode() + { + return GetTypeCode(); + } + bool IConvertible.ToBoolean(IFormatProvider provider) + { + return Convert.ToBoolean((float)this); + } + byte IConvertible.ToByte(IFormatProvider provider) + { + return Convert.ToByte((float)this); + } + char IConvertible.ToChar(IFormatProvider provider) + { + throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "Char")); + } + DateTime IConvertible.ToDateTime(IFormatProvider provider) + { + throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "DateTime")); + } + decimal IConvertible.ToDecimal(IFormatProvider provider) + { + return Convert.ToDecimal((float)this); + } + double IConvertible.ToDouble(IFormatProvider provider) + { + return Convert.ToDouble((float)this); + } + short IConvertible.ToInt16(IFormatProvider provider) + { + return Convert.ToInt16((float)this); + } + int IConvertible.ToInt32(IFormatProvider provider) + { + return Convert.ToInt32((float)this); + } + long IConvertible.ToInt64(IFormatProvider provider) + { + return Convert.ToInt64((float)this); + } + sbyte IConvertible.ToSByte(IFormatProvider provider) + { + return Convert.ToSByte((float)this); + } + string IConvertible.ToString(IFormatProvider provider) + { + return Convert.ToString((float)this, CultureInfo.InvariantCulture); + } + object IConvertible.ToType(Type conversionType, IFormatProvider provider) + { + return (((float)this) as IConvertible).ToType(conversionType, provider); + } + ushort IConvertible.ToUInt16(IFormatProvider provider) + { + return Convert.ToUInt16((float)this); + } + uint IConvertible.ToUInt32(IFormatProvider provider) + { + return Convert.ToUInt32((float)this); + } + ulong IConvertible.ToUInt64(IFormatProvider provider) + { + return Convert.ToUInt64((float)this); + } + #endregion + } +} diff --git a/AssetStudio/Math/HalfHelper.cs b/AssetStudio/Math/HalfHelper.cs new file mode 100644 index 0000000..3020f98 --- /dev/null +++ b/AssetStudio/Math/HalfHelper.cs @@ -0,0 +1,211 @@ +using System.Runtime.InteropServices; + +namespace System +{ + /// + /// 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 + { + private static uint[] mantissaTable = GenerateMantissaTable(); + private static uint[] exponentTable = GenerateExponentTable(); + private static ushort[] offsetTable = GenerateOffsetTable(); + private static ushort[] baseTable = GenerateBaseTable(); + private static sbyte[] shiftTable = GenerateShiftTable(); + + // Transforms the subnormal representation to a normalized one. + private static uint ConvertMantissa(int i) + { + uint m = (uint)(i << 13); // Zero pad mantissa bits + uint e = 0; // Zero exponent + + // While not normalized + while ((m & 0x00800000) == 0) + { + e -= 0x00800000; // Decrement exponent (1<<23) + m <<= 1; // Shift mantissa + } + m &= unchecked((uint)~0x00800000); // Clear leading 1 bit + e += 0x38800000; // Adjust bias ((127-14)<<23) + return m | e; // Return combined number + } + + private static uint[] GenerateMantissaTable() + { + uint[] mantissaTable = new uint[2048]; + mantissaTable[0] = 0; + for (int i = 1; i < 1024; i++) + { + mantissaTable[i] = ConvertMantissa(i); + } + for (int i = 1024; i < 2048; i++) + { + mantissaTable[i] = (uint)(0x38000000 + ((i - 1024) << 13)); + } + + return mantissaTable; + } + private static uint[] GenerateExponentTable() + { + uint[] exponentTable = new uint[64]; + exponentTable[0] = 0; + for (int i = 1; i < 31; i++) + { + exponentTable[i] = (uint)(i << 23); + } + exponentTable[31] = 0x47800000; + exponentTable[32] = 0x80000000; + for (int i = 33; i < 63; i++) + { + exponentTable[i] = (uint)(0x80000000 + ((i - 32) << 23)); + } + exponentTable[63] = 0xc7800000; + + return exponentTable; + } + private static ushort[] GenerateOffsetTable() + { + ushort[] offsetTable = new ushort[64]; + offsetTable[0] = 0; + for (int i = 1; i < 32; i++) + { + offsetTable[i] = 1024; + } + offsetTable[32] = 0; + for (int i = 33; i < 64; i++) + { + offsetTable[i] = 1024; + } + + return offsetTable; + } + private static ushort[] GenerateBaseTable() + { + ushort[] baseTable = new ushort[512]; + for (int i = 0; i < 256; ++i) + { + sbyte e = (sbyte)(127 - i); + if (e > 24) + { // Very small numbers map to zero + baseTable[i | 0x000] = 0x0000; + baseTable[i | 0x100] = 0x8000; + } + else if (e > 14) + { // Small numbers map to denorms + baseTable[i | 0x000] = (ushort)(0x0400 >> (18 + e)); + baseTable[i | 0x100] = (ushort)((0x0400 >> (18 + e)) | 0x8000); + } + else if (e >= -15) + { // Normal numbers just lose precision + baseTable[i | 0x000] = (ushort)((15 - e) << 10); + baseTable[i | 0x100] = (ushort)(((15 - e) << 10) | 0x8000); + } + else if (e > -128) + { // Large numbers map to Infinity + baseTable[i | 0x000] = 0x7c00; + baseTable[i | 0x100] = 0xfc00; + } + else + { // Infinity and NaN's stay Infinity and NaN's + baseTable[i | 0x000] = 0x7c00; + baseTable[i | 0x100] = 0xfc00; + } + } + + return baseTable; + } + private static sbyte[] GenerateShiftTable() + { + sbyte[] shiftTable = new sbyte[512]; + for (int i = 0; i < 256; ++i) + { + sbyte e = (sbyte)(127 - i); + if (e > 24) + { // Very small numbers map to zero + shiftTable[i | 0x000] = 24; + shiftTable[i | 0x100] = 24; + } + else if (e > 14) + { // Small numbers map to denorms + shiftTable[i | 0x000] = (sbyte)(e - 1); + shiftTable[i | 0x100] = (sbyte)(e - 1); + } + else if (e >= -15) + { // Normal numbers just lose precision + shiftTable[i | 0x000] = 13; + shiftTable[i | 0x100] = 13; + } + else if (e > -128) + { // Large numbers map to Infinity + shiftTable[i | 0x000] = 24; + shiftTable[i | 0x100] = 24; + } + else + { // Infinity and NaN's stay Infinity and NaN's + shiftTable[i | 0x000] = 13; + shiftTable[i | 0x100] = 13; + } + } + + return shiftTable; + } + + /*public static unsafe float HalfToSingle(Half half) + { + uint result = mantissaTable[offsetTable[half.value >> 10] + (half.value & 0x3ff)] + exponentTable[half.value >> 10]; + return *((float*)&result); + } + public static unsafe Half SingleToHalf(float single) + { + uint value = *((uint*)&single); + + ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); + return Half.ToHalf(result); + }*/ + public static float HalfToSingle(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)); + } + public static Half Abs(Half half) + { + return Half.ToHalf((ushort)(half.value & 0x7fff)); + } + + public static bool IsNaN(Half half) + { + return ((half.value & 0x7fff) > 0x7c00); + } + public static bool IsInfinity(Half half) + { + return ((half.value & 0x7fff) == 0x7c00); + } + public static bool IsPositiveInfinity(Half half) + { + return (half.value == 0x7c00); + } + public static bool IsNegativeInfinity(Half half) + { + return (half.value == 0xfc00); + } + } +} diff --git a/AssetStudio/Math/Matrix4x4f.cs b/AssetStudio/Math/Matrix4x4f.cs new file mode 100644 index 0000000..40c2e35 --- /dev/null +++ b/AssetStudio/Math/Matrix4x4f.cs @@ -0,0 +1,241 @@ +using System; +using System.Runtime.InteropServices; + +namespace AssetStudio +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct Matrix4x4 : IEquatable + { + public float M00; + public float M10; + public float M20; + public float M30; + + public float M01; + public float M11; + public float M21; + public float M31; + + public float M02; + public float M12; + public float M22; + public float M32; + + public float M03; + public float M13; + public float M23; + public float M33; + + public Matrix4x4(float[] values) + { + if (values == null) + throw new ArgumentNullException(nameof(values)); + if (values.Length != 16) + throw new ArgumentOutOfRangeException(nameof(values), "There must be sixteen and only sixteen input values for Matrix."); + + M00 = values[0]; + M10 = values[1]; + M20 = values[2]; + M30 = values[3]; + + M01 = values[4]; + M11 = values[5]; + M21 = values[6]; + M31 = values[7]; + + M02 = values[8]; + M12 = values[9]; + M22 = values[10]; + M32 = values[11]; + + M03 = values[12]; + M13 = values[13]; + M23 = values[14]; + M33 = values[15]; + } + + public float this[int row, int column] + { + get => this[row + column * 4]; + + set => this[row + column * 4] = value; + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: return M00; + case 1: return M10; + case 2: return M20; + case 3: return M30; + case 4: return M01; + case 5: return M11; + case 6: return M21; + case 7: return M31; + case 8: return M02; + case 9: return M12; + case 10: return M22; + case 11: return M32; + case 12: return M03; + case 13: return M13; + case 14: return M23; + case 15: return M33; + default: throw new IndexOutOfRangeException("Invalid matrix index!"); + } + } + + set + { + switch (index) + { + case 0: M00 = value; break; + case 1: M10 = value; break; + case 2: M20 = value; break; + case 3: M30 = value; break; + case 4: M01 = value; break; + case 5: M11 = value; break; + case 6: M21 = value; break; + case 7: M31 = value; break; + case 8: M02 = value; break; + case 9: M12 = value; break; + case 10: M22 = value; break; + case 11: M32 = value; break; + case 12: M03 = value; break; + case 13: M13 = value; break; + case 14: M23 = value; break; + case 15: M33 = value; break; + default: throw new IndexOutOfRangeException("Invalid matrix index!"); + } + } + } + + public override int GetHashCode() + { + return GetColumn(0).GetHashCode() ^ (GetColumn(1).GetHashCode() << 2) ^ (GetColumn(2).GetHashCode() >> 2) ^ (GetColumn(3).GetHashCode() >> 1); + } + + public override bool Equals(object other) + { + if (!(other is Matrix4x4)) + return false; + return Equals((Matrix4x4)other); + } + + public bool Equals(Matrix4x4 other) + { + return GetColumn(0).Equals(other.GetColumn(0)) + && GetColumn(1).Equals(other.GetColumn(1)) + && GetColumn(2).Equals(other.GetColumn(2)) + && GetColumn(3).Equals(other.GetColumn(3)); + } + + public Vector4 GetColumn(int index) + { + switch (index) + { + case 0: return new Vector4(M00, M10, M20, M30); + case 1: return new Vector4(M01, M11, M21, M31); + case 2: return new Vector4(M02, M12, M22, M32); + case 3: return new Vector4(M03, M13, M23, M33); + default: throw new IndexOutOfRangeException("Invalid column index!"); + } + } + + public Vector4 GetRow(int index) + { + switch (index) + { + case 0: return new Vector4(M00, M01, M02, M03); + case 1: return new Vector4(M10, M11, M12, M13); + case 2: return new Vector4(M20, M21, M22, M23); + case 3: return new Vector4(M30, M31, M32, M33); + default: throw new IndexOutOfRangeException("Invalid row index!"); + } + } + + public static Matrix4x4 operator *(Matrix4x4 lhs, Matrix4x4 rhs) + { + Matrix4x4 res; + res.M00 = lhs.M00 * rhs.M00 + lhs.M01 * rhs.M10 + lhs.M02 * rhs.M20 + lhs.M03 * rhs.M30; + res.M01 = lhs.M00 * rhs.M01 + lhs.M01 * rhs.M11 + lhs.M02 * rhs.M21 + lhs.M03 * rhs.M31; + res.M02 = lhs.M00 * rhs.M02 + lhs.M01 * rhs.M12 + lhs.M02 * rhs.M22 + lhs.M03 * rhs.M32; + res.M03 = lhs.M00 * rhs.M03 + lhs.M01 * rhs.M13 + lhs.M02 * rhs.M23 + lhs.M03 * rhs.M33; + + res.M10 = lhs.M10 * rhs.M00 + lhs.M11 * rhs.M10 + lhs.M12 * rhs.M20 + lhs.M13 * rhs.M30; + res.M11 = lhs.M10 * rhs.M01 + lhs.M11 * rhs.M11 + lhs.M12 * rhs.M21 + lhs.M13 * rhs.M31; + res.M12 = lhs.M10 * rhs.M02 + lhs.M11 * rhs.M12 + lhs.M12 * rhs.M22 + lhs.M13 * rhs.M32; + res.M13 = lhs.M10 * rhs.M03 + lhs.M11 * rhs.M13 + lhs.M12 * rhs.M23 + lhs.M13 * rhs.M33; + + res.M20 = lhs.M20 * rhs.M00 + lhs.M21 * rhs.M10 + lhs.M22 * rhs.M20 + lhs.M23 * rhs.M30; + res.M21 = lhs.M20 * rhs.M01 + lhs.M21 * rhs.M11 + lhs.M22 * rhs.M21 + lhs.M23 * rhs.M31; + res.M22 = lhs.M20 * rhs.M02 + lhs.M21 * rhs.M12 + lhs.M22 * rhs.M22 + lhs.M23 * rhs.M32; + res.M23 = lhs.M20 * rhs.M03 + lhs.M21 * rhs.M13 + lhs.M22 * rhs.M23 + lhs.M23 * rhs.M33; + + res.M30 = lhs.M30 * rhs.M00 + lhs.M31 * rhs.M10 + lhs.M32 * rhs.M20 + lhs.M33 * rhs.M30; + res.M31 = lhs.M30 * rhs.M01 + lhs.M31 * rhs.M11 + lhs.M32 * rhs.M21 + lhs.M33 * rhs.M31; + res.M32 = lhs.M30 * rhs.M02 + lhs.M31 * rhs.M12 + lhs.M32 * rhs.M22 + lhs.M33 * rhs.M32; + res.M33 = lhs.M30 * rhs.M03 + lhs.M31 * rhs.M13 + lhs.M32 * rhs.M23 + lhs.M33 * rhs.M33; + + return res; + } + + public static bool operator ==(Matrix4x4 lhs, Matrix4x4 rhs) + { + return lhs.GetColumn(0) == rhs.GetColumn(0) + && lhs.GetColumn(1) == rhs.GetColumn(1) + && lhs.GetColumn(2) == rhs.GetColumn(2) + && lhs.GetColumn(3) == rhs.GetColumn(3); + } + + public static bool operator !=(Matrix4x4 lhs, Matrix4x4 rhs) + { + return !(lhs == rhs); + } + + public static Matrix4x4 Scale(Vector3 vector) + { + Matrix4x4 m; + m.M00 = vector.X; m.M01 = 0F; m.M02 = 0F; m.M03 = 0F; + m.M10 = 0F; m.M11 = vector.Y; m.M12 = 0F; m.M13 = 0F; + m.M20 = 0F; m.M21 = 0F; m.M22 = vector.Z; m.M23 = 0F; + m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F; + return m; + } + + public static Matrix4x4 Translate(Vector3 vector) + { + Matrix4x4 m; + m.M00 = 1F; m.M01 = 0F; m.M02 = 0F; m.M03 = vector.X; + m.M10 = 0F; m.M11 = 1F; m.M12 = 0F; m.M13 = vector.Y; + m.M20 = 0F; m.M21 = 0F; m.M22 = 1F; m.M23 = vector.Z; + m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F; + return m; + } + + public static Matrix4x4 Rotate(Quaternion q) + { + float x = q.X * 2.0F; + float y = q.Y * 2.0F; + float z = q.Z * 2.0F; + float xx = q.X * x; + float yy = q.Y * y; + float zz = q.Z * z; + float xy = q.X * y; + float xz = q.X * z; + float yz = q.Y * z; + float wx = q.W * x; + float wy = q.W * y; + float wz = q.W * z; + + Matrix4x4 m; + m.M00 = 1.0f - (yy + zz); m.M10 = xy + wz; m.M20 = xz - wy; m.M30 = 0.0F; + m.M01 = xy - wz; m.M11 = 1.0f - (xx + zz); m.M21 = yz + wx; m.M31 = 0.0F; + m.M02 = xz + wy; m.M12 = yz - wx; m.M22 = 1.0f - (xx + yy); m.M32 = 0.0F; + m.M03 = 0.0F; m.M13 = 0.0F; m.M23 = 0.0F; m.M33 = 1.0F; + return m; + } + } +} diff --git a/AssetStudio/Math/Quaternion.cs b/AssetStudio/Math/Quaternion.cs new file mode 100644 index 0000000..5633ed6 --- /dev/null +++ b/AssetStudio/Math/Quaternion.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.InteropServices; + +namespace AssetStudio +{ + [StructLayout(LayoutKind.Sequential)] + public struct Quaternion : IEquatable + { + public float X; + public float Y; + public float Z; + public float W; + + public Quaternion(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: return X; + case 1: return Y; + case 2: return Z; + case 3: return W; + default: throw new IndexOutOfRangeException("Invalid Quaternion index!"); + } + } + + set + { + switch (index) + { + case 0: X = value; break; + case 1: Y = value; break; + case 2: Z = value; break; + case 3: W = value; break; + default: throw new IndexOutOfRangeException("Invalid Quaternion index!"); + } + } + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ (Y.GetHashCode() << 2) ^ (Z.GetHashCode() >> 2) ^ (W.GetHashCode() >> 1); + } + + public override bool Equals(object other) + { + if (!(other is Quaternion)) + return false; + return Equals((Quaternion)other); + } + + public bool Equals(Quaternion other) + { + return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); + } + } +} diff --git a/AssetStudio/Math/Vector2.cs b/AssetStudio/Math/Vector2.cs new file mode 100644 index 0000000..18e9268 --- /dev/null +++ b/AssetStudio/Math/Vector2.cs @@ -0,0 +1,150 @@ +using System; +using System.Runtime.InteropServices; + +namespace AssetStudio +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct Vector2 : IEquatable + { + public float X; + public float Y; + + public Vector2(float x, float y) + { + X = x; + Y = y; + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: return X; + case 1: return Y; + default: + throw new IndexOutOfRangeException("Invalid Vector2 index!"); + } + } + + set + { + switch (index) + { + case 0: X = value; break; + case 1: Y = value; break; + default: + throw new IndexOutOfRangeException("Invalid Vector2 index!"); + } + } + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ (Y.GetHashCode() << 2); + } + + public override bool Equals(object other) + { + if (!(other is Vector2)) + return false; + return Equals((Vector2)other); + } + + public bool Equals(Vector2 other) + { + return X.Equals(other.X) && Y.Equals(other.Y); + } + + public void Normalize() + { + var length = Length(); + if (length > kEpsilon) + { + var invNorm = 1.0f / length; + X *= invNorm; + Y *= invNorm; + } + else + { + X = 0; + Y = 0; + } + } + + public float Length() + { + return (float)Math.Sqrt(LengthSquared()); + } + + public float LengthSquared() + { + return X * X + Y * Y; + } + + public static Vector2 Zero => new Vector2(); + + public static Vector2 operator +(Vector2 a, Vector2 b) + { + return new Vector2(a.X + b.X, a.Y + b.Y); + } + + public static Vector2 operator -(Vector2 a, Vector2 b) + { + return new Vector2(a.X - b.X, a.Y - b.Y); + } + + public static Vector2 operator *(Vector2 a, Vector2 b) + { + return new Vector2(a.X * b.X, a.Y * b.Y); + } + + public static Vector2 operator /(Vector2 a, Vector2 b) + { + return new Vector2(a.X / b.X, a.Y / b.Y); + } + + public static Vector2 operator -(Vector2 a) + { + return new Vector2(-a.X, -a.Y); + } + + public static Vector2 operator *(Vector2 a, float d) + { + return new Vector2(a.X * d, a.Y * d); + } + + public static Vector2 operator *(float d, Vector2 a) + { + return new Vector2(a.X * d, a.Y * d); + } + + public static Vector2 operator /(Vector2 a, float d) + { + return new Vector2(a.X / d, a.Y / d); + } + + public static bool operator ==(Vector2 lhs, Vector2 rhs) + { + return (lhs - rhs).LengthSquared() < kEpsilon * kEpsilon; + } + + public static bool operator !=(Vector2 lhs, Vector2 rhs) + { + return !(lhs == rhs); + } + + public static implicit operator Vector3(Vector2 v) + { + return new Vector3(v.X, v.Y, 0); + } + + public static implicit operator Vector4(Vector2 v) + { + return new Vector4(v.X, v.Y, 0.0F, 0.0F); + } + + private const float kEpsilon = 0.00001F; + } +} diff --git a/AssetStudio/Math/Vector3.cs b/AssetStudio/Math/Vector3.cs new file mode 100644 index 0000000..9bd5c4b --- /dev/null +++ b/AssetStudio/Math/Vector3.cs @@ -0,0 +1,146 @@ +using System; +using System.Runtime.InteropServices; + +namespace AssetStudio +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct Vector3 : IEquatable + { + public float X; + public float Y; + public float Z; + + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: return X; + case 1: return Y; + case 2: return Z; + default: + throw new IndexOutOfRangeException("Invalid Vector3 index!"); + } + } + + set + { + switch (index) + { + case 0: X = value; break; + case 1: Y = value; break; + case 2: Z = value; break; + default: + throw new IndexOutOfRangeException("Invalid Vector3 index!"); + } + } + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ (Y.GetHashCode() << 2) ^ (Z.GetHashCode() >> 2); + } + + public override bool Equals(object other) + { + if (!(other is Vector3)) + return false; + return Equals((Vector3)other); + } + + public bool Equals(Vector3 other) + { + return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); + } + + public void Normalize() + { + var length = Length(); + if (length > kEpsilon) + { + var invNorm = 1.0f / length; + X *= invNorm; + Y *= invNorm; + Z *= invNorm; + } + else + { + X = 0; + Y = 0; + Z = 0; + } + } + + public float Length() + { + return (float)Math.Sqrt(LengthSquared()); + } + + public float LengthSquared() + { + return X * X + Y * Y + Z * Z; + } + + public static Vector3 Zero => new Vector3(); + + public static Vector3 operator +(Vector3 a, Vector3 b) + { + return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + public static Vector3 operator -(Vector3 a, Vector3 b) + { + return new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + public static Vector3 operator -(Vector3 a) + { + return new Vector3(-a.X, -a.Y, -a.Z); + } + + public static Vector3 operator *(Vector3 a, float d) + { + return new Vector3(a.X * d, a.Y * d, a.Z * d); + } + + public static Vector3 operator *(float d, Vector3 a) + { + return new Vector3(a.X * d, a.Y * d, a.Z * d); + } + + public static Vector3 operator /(Vector3 a, float d) + { + return new Vector3(a.X / d, a.Y / d, a.Z / d); + } + + public static bool operator ==(Vector3 lhs, Vector3 rhs) + { + return (lhs - rhs).LengthSquared() < kEpsilon * kEpsilon; + } + + public static bool operator !=(Vector3 lhs, Vector3 rhs) + { + return !(lhs == rhs); + } + + public static implicit operator Vector2(Vector3 v) + { + return new Vector2(v.X, v.Y); + } + + public static implicit operator Vector4(Vector3 v) + { + return new Vector4(v.X, v.Y, v.Z, 0.0F); + } + + private const float kEpsilon = 0.00001F; + } +} diff --git a/AssetStudio/Math/Vector4.cs b/AssetStudio/Math/Vector4.cs new file mode 100644 index 0000000..ed4dc7a --- /dev/null +++ b/AssetStudio/Math/Vector4.cs @@ -0,0 +1,163 @@ +using System; +using System.Runtime.InteropServices; + +namespace AssetStudio +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct Vector4 : IEquatable + { + public float X; + public float Y; + public float Z; + public float W; + + public Vector4(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Vector4(Vector3 value, float w) + { + X = value.X; + Y = value.Y; + Z = value.Z; + W = w; + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: return X; + case 1: return Y; + case 2: return Z; + case 3: return W; + default: throw new IndexOutOfRangeException("Invalid Vector4 index!"); + } + } + + set + { + switch (index) + { + case 0: X = value; break; + case 1: Y = value; break; + case 2: Z = value; break; + case 3: W = value; break; + default: throw new IndexOutOfRangeException("Invalid Vector4 index!"); + } + } + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ (Y.GetHashCode() << 2) ^ (Z.GetHashCode() >> 2) ^ (W.GetHashCode() >> 1); + } + + public override bool Equals(object other) + { + if (!(other is Vector4)) + return false; + return Equals((Vector4)other); + } + + public bool Equals(Vector4 other) + { + return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); + } + + public void Normalize() + { + var length = Length(); + if (length > kEpsilon) + { + var invNorm = 1.0f / length; + X *= invNorm; + Y *= invNorm; + Z *= invNorm; + W *= invNorm; + } + else + { + X = 0; + Y = 0; + Z = 0; + W = 0; + } + } + + public float Length() + { + return (float)Math.Sqrt(LengthSquared()); + } + + public float LengthSquared() + { + return X * X + Y * Y + Z * Z + W * W; + } + + public static Vector4 Zero => new Vector4(); + + public static Vector4 operator +(Vector4 a, Vector4 b) + { + return new Vector4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); + } + + public static Vector4 operator -(Vector4 a, Vector4 b) + { + return new Vector4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); + } + + public static Vector4 operator -(Vector4 a) + { + return new Vector4(-a.X, -a.Y, -a.Z, -a.W); + } + + public static Vector4 operator *(Vector4 a, float d) + { + return new Vector4(a.X * d, a.Y * d, a.Z * d, a.W * d); + } + + public static Vector4 operator *(float d, Vector4 a) + { + return new Vector4(a.X * d, a.Y * d, a.Z * d, a.W * d); + } + + public static Vector4 operator /(Vector4 a, float d) + { + return new Vector4(a.X / d, a.Y / d, a.Z / d, a.W / d); + } + + public static bool operator ==(Vector4 lhs, Vector4 rhs) + { + return (lhs - rhs).LengthSquared() < kEpsilon * kEpsilon; + } + + public static bool operator !=(Vector4 lhs, Vector4 rhs) + { + return !(lhs == rhs); + } + + public static implicit operator Vector2(Vector4 v) + { + return new Vector2(v.X, v.Y); + } + + public static implicit operator Vector3(Vector4 v) + { + return new Vector3(v.X, v.Y, v.Z); + } + + public static implicit operator Color(Vector4 v) + { + return new Color(v.X, v.Y, v.Z, v.W); + } + + private const float kEpsilon = 0.00001F; + } +} diff --git a/AssetStudioFBX/AssetStudioFBX.h b/AssetStudioFBX/AssetStudioFBX.h index 0e04841..3cbb0b6 100644 --- a/AssetStudioFBX/AssetStudioFBX.h +++ b/AssetStudioFBX/AssetStudioFBX.h @@ -9,7 +9,6 @@ using namespace System; using namespace System::Collections::Generic; using namespace System::IO; using namespace System::Runtime::InteropServices; -using namespace SharpDX; #define WITH_MARSHALLED_STRING(name,str,block)\ { \ diff --git a/AssetStudioFBX/AssetStudioFBX.vcxproj b/AssetStudioFBX/AssetStudioFBX.vcxproj index 8dde759..ef3e2f4 100644 --- a/AssetStudioFBX/AssetStudioFBX.vcxproj +++ b/AssetStudioFBX/AssetStudioFBX.vcxproj @@ -140,12 +140,6 @@ - - ..\AssetStudio\Libraries\SharpDX.dll - - - ..\AssetStudio\Libraries\SharpDX.Mathematics.dll - diff --git a/AssetStudioFBX/AssetStudioFBXExporter.cpp b/AssetStudioFBX/AssetStudioFBXExporter.cpp index b0244fa..aefa6c5 100644 --- a/AssetStudioFBX/AssetStudioFBXExporter.cpp +++ b/AssetStudioFBX/AssetStudioFBXExporter.cpp @@ -409,7 +409,7 @@ namespace AssetStudio for (int j = 0; j < vertexList->Count; j++) { ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j]; - lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.Red, vert->Colour.Green, vert->Colour.Blue, vert->Colour.Alpha)); + lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A)); } } @@ -451,22 +451,22 @@ namespace AssetStudio else { FbxString lShadingName = "Phong"; - Color4 diffuse = mat->Diffuse; - Color4 ambient = mat->Ambient; - Color4 emissive = mat->Emissive; - Color4 specular = mat->Specular; - Color4 reflection = mat->Reflection; + Color diffuse = mat->Diffuse; + Color ambient = mat->Ambient; + Color emissive = mat->Emissive; + Color specular = mat->Specular; + Color reflection = mat->Reflection; pMat = FbxSurfacePhong::Create(pScene, pMatName); - pMat->Diffuse.Set(FbxDouble3(diffuse.Red, diffuse.Green, diffuse.Blue)); - pMat->DiffuseFactor.Set(FbxDouble(diffuse.Alpha)); - pMat->Ambient.Set(FbxDouble3(ambient.Red, ambient.Green, ambient.Blue)); - pMat->AmbientFactor.Set(FbxDouble(ambient.Alpha)); - pMat->Emissive.Set(FbxDouble3(emissive.Red, emissive.Green, emissive.Blue)); - pMat->EmissiveFactor.Set(FbxDouble(emissive.Alpha)); - pMat->Specular.Set(FbxDouble3(specular.Red, specular.Green, specular.Blue)); - pMat->SpecularFactor.Set(FbxDouble(specular.Alpha)); - pMat->Reflection.Set(FbxDouble3(reflection.Red, reflection.Green, reflection.Blue)); - pMat->ReflectionFactor.Set(FbxDouble(reflection.Alpha)); + pMat->Diffuse.Set(FbxDouble3(diffuse.R, diffuse.G, diffuse.B)); + pMat->DiffuseFactor.Set(FbxDouble(diffuse.A)); + pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B)); + pMat->AmbientFactor.Set(FbxDouble(ambient.A)); + pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B)); + pMat->EmissiveFactor.Set(FbxDouble(emissive.A)); + pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B)); + pMat->SpecularFactor.Set(FbxDouble(specular.A)); + pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B)); + pMat->ReflectionFactor.Set(FbxDouble(reflection.A)); pMat->Shininess.Set(FbxDouble(mat->Shininess)); pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency)); pMat->ShadingModel.Set(lShadingName); diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index 8b00a11..6dc677d 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -16,6 +16,8 @@ using AssetStudio; using static AssetStudioGUI.Studio; using Object = AssetStudio.Object; using Font = AssetStudio.Font; +using Vector3 = OpenTK.Vector3; +using Vector4 = OpenTK.Vector4; namespace AssetStudioGUI { @@ -1449,7 +1451,7 @@ namespace AssetStudioGUI private void InitOpenTK() { ChangeGLSize(glControl1.Size); - GL.ClearColor(Color.CadetBlue); + GL.ClearColor(System.Drawing.Color.CadetBlue); pgmID = GL.CreateProgram(); LoadShader("vs", ShaderType.VertexShader, pgmID, out int vsID); LoadShader("fs", ShaderType.FragmentShader, pgmID, out int fsID); diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj index a579872..6569151 100644 --- a/AssetStudioUtility/AssetStudioUtility.csproj +++ b/AssetStudioUtility/AssetStudioUtility.csproj @@ -59,15 +59,9 @@ ..\AssetStudio\Libraries\SharpDX.D3DCompiler.dll - - ..\AssetStudio\Libraries\SharpDX.Mathematics.dll - - - ..\AssetStudio\Libraries\System.Half.dll - diff --git a/AssetStudioUtility/ModelConverter.cs b/AssetStudioUtility/ModelConverter.cs index 17fc5b1..165d1fc 100644 --- a/AssetStudioUtility/ModelConverter.cs +++ b/AssetStudioUtility/ModelConverter.cs @@ -4,7 +4,6 @@ using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; -using SharpDX; namespace AssetStudio { @@ -308,11 +307,11 @@ namespace AssetStudio { if (mesh.m_Colors.Length == mesh.m_VertexCount * 3) { - ((ImportedVertexWithColour)iVertex).Colour = new Color4(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f); + ((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f); } else { - ((ImportedVertexWithColour)iVertex).Colour = new Color4(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]); + ((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]); } } //UV @@ -364,8 +363,9 @@ namespace AssetStudio //Bone if (sMesh.m_Bones.Length > 0) { - iMesh.BoneList = new List(sMesh.m_Bones.Length); - for (int i = 0; i < sMesh.m_Bones.Length; i++) + var boneMax = Math.Min(sMesh.m_Bones.Length, mesh.m_BindPose.Length); + iMesh.BoneList = new List(boneMax); + for (int i = 0; i < boneMax; i++) { var bone = new ImportedBone(); if (sMesh.m_Bones[i].TryGet(out var m_Transform)) @@ -374,8 +374,8 @@ namespace AssetStudio } if (!string.IsNullOrEmpty(bone.Path)) { - var convert = Matrix.Scaling(new Vector3(-1, 1, 1)); - bone.Matrix = convert * Matrix.Transpose(mesh.m_BindPose[i]) * convert; + var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); + bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } @@ -391,8 +391,8 @@ namespace AssetStudio bone.Path = FixBonePath(path); if (!string.IsNullOrEmpty(bone.Path)) { - var convert = Matrix.Scaling(new Vector3(-1, 1, 1)); - bone.Matrix = convert * Matrix.Transpose(mesh.m_BindPose[i]) * convert; + var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); + bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } diff --git a/AssetStudioUtility/SpriteHelper.cs b/AssetStudioUtility/SpriteHelper.cs index c60b5cf..48e3416 100644 --- a/AssetStudioUtility/SpriteHelper.cs +++ b/AssetStudioUtility/SpriteHelper.cs @@ -4,8 +4,6 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; -using SharpDX; -using RectangleF = System.Drawing.RectangleF; namespace AssetStudio { @@ -73,7 +71,7 @@ namespace AssetStudio { path.AddPolygon(p); } - using (var matr = new System.Drawing.Drawing2D.Matrix()) + using (var matr = new Matrix()) { if (m_Sprite.m_Pivot == Vector2.Zero) //5.4.2 down {