// 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;
}
}
}