// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; 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(Float3 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(Float4 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(Float4 value) { return new FloatR10G10B10A2(value); } /// /// Performs an implicit conversion from to . /// /// The value to be converted. /// The converted value. public static implicit operator Float4(FloatR10G10B10A2 value) { return value.ToFloat4(); } /// /// 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; } /// /// Returns a that represents this instance. /// /// A that represents this instance. public override string ToString() { return ToFloat4().ToString(); } /// /// 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) { return obj is FloatR10G10B10A2 other && value == other.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 Float3. /// /// Float3 value public Float3 ToFloat3() { Float3 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 Float4. /// /// Float4 value public Float4 ToFloat4() { Float4 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; } } }