// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using System.Globalization; using System.Runtime.InteropServices; namespace FlaxEngine { /// /// Packed vector, layout: R:10 bytes, G:10 bytes, B:10 bytes, A:2 bytes, all values are stored as floats in range [0;1] /// [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct FloatR10G10B10A2 { private uint value; /// /// Initializes a new instance of the structure. /// /// The floating point value that should be stored in R component (10 bit format). /// The floating point value that should be stored in G component (10 bit format). /// The floating point value that should be stored in B component (10 bit format). /// The floating point value that should be stored in A component (2 bit format). public FloatR10G10B10A2(float x, float y, float z, float w) { value = Pack(x, y, z, w); } /// /// Initializes a new instance of the structure. /// /// The floating point value that should be stored in 10 bit format. /// The floating point value that should be stored in alpha component (2 bit format). public FloatR10G10B10A2(Vector3 value, float w = 0) { this.value = Pack(value.X, value.Y, value.Z, w); } /// /// Initializes a new instance of the structure. /// /// The floating point value that should be stored in 10 bit format. public FloatR10G10B10A2(Vector4 value) { this.value = Pack(value.X, value.Y, value.Z, value.W); } /// /// Gets or sets the raw 32 bit value used to back this vector. /// public uint RawValue { get => value; set => this.value = value; } /// /// Gets the R component. /// public float R => (value & 0x3FF) / 1023.0f; /// /// Gets the G component. /// public float G => ((value >> 10) & 0x3FF) / 1023.0f; /// /// Gets the B component. /// public float B => ((value >> 20) & 0x3FF) / 1023.0f; /// /// Gets the A component. /// public float A => (value >> 30) / 3.0f; /// /// Performs an explicit conversion from to . /// /// The value to be converted. /// The converted value. public static explicit operator FloatR10G10B10A2(Vector4 value) { return new FloatR10G10B10A2(value); } /// /// Performs an implicit conversion from to . /// /// The value to be converted. /// The converted value. public static implicit operator Vector4(FloatR10G10B10A2 value) { return value.ToVector4(); } /// /// Tests for equality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has the same value as ; otherwise, false. public static bool operator ==(FloatR10G10B10A2 left, FloatR10G10B10A2 right) { return left.value == right.value; } /// /// Tests for inequality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has a different value than ; otherwise, false. public static bool operator !=(FloatR10G10B10A2 left, FloatR10G10B10A2 right) { return left.value != right.value; } /// /// Converts the value of the object to its equivalent string representation. /// /// The string representation of the value of this instance. public override string ToString() { Vector4 num = this; return num.ToString(CultureInfo.CurrentCulture); } /// /// Returns the hash code for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return value.GetHashCode(); } /// /// Determines whether the specified object instances are considered equal. /// /// /// /// true if is the same instance as or if both are null references or if value1.Equals(value2) returns true; otherwise, false. public static bool Equals(ref FloatR10G10B10A2 value1, ref FloatR10G10B10A2 value2) { return value1.value == value2.value; } /// /// Returns a value that indicates whether the current instance is equal to the specified object. /// /// Object to make the comparison with. /// true if the current instance is equal to the specified object; false otherwise. public bool Equals(FloatR10G10B10A2 other) { return other.value == value; } /// /// Returns a value that indicates whether the current instance is equal to a specified object. /// /// Object to make the comparison with. /// true if the current instance is equal to the specified object; false otherwise. public override bool Equals(object obj) { if (obj == null || obj.GetType() != GetType()) { return false; } var v = (FloatR10G10B10A2)obj; return v.value == value; } private static uint Pack(float x, float y, float z, float w) { x = Mathf.Saturate(x); y = Mathf.Saturate(y); z = Mathf.Saturate(z); w = Mathf.Saturate(w); x = Mathf.Round(x * 1023.0f); y = Mathf.Round(y * 1023.0f); z = Mathf.Round(z * 1023.0f); w = Mathf.Round(w * 3.0f); return ((uint)w << 30) | (((uint)z & 0x3FF) << 20) | (((uint)y & 0x3FF) << 10) | (((uint)x & 0x3FF)); } /// /// Unpacks vector to Vector3. /// /// Vector3 value public Vector3 ToVector3() { Vector3 vectorOut; uint tmp = value & 0x3FF; vectorOut.X = tmp / 1023.0f; tmp = (value >> 10) & 0x3FF; vectorOut.Y = tmp / 1023.0f; tmp = (value >> 20) & 0x3FF; vectorOut.Z = tmp / 1023.0f; return vectorOut; } /// /// Unpacks vector to Vector4. /// /// Vector4 value public Vector4 ToVector4() { Vector4 vectorOut; uint tmp = value & 0x3FF; vectorOut.X = tmp / 1023.0f; tmp = (value >> 10) & 0x3FF; vectorOut.Y = tmp / 1023.0f; tmp = (value >> 20) & 0x3FF; vectorOut.Z = tmp / 1023.0f; vectorOut.W = (value >> 30) / 3.0f; return vectorOut; } } }