mirror of https://github.com/SixLabors/ImageSharp
27 changed files with 4537 additions and 15 deletions
@ -0,0 +1,153 @@ |
|||
// <copyright file="Alpha8.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing a single 8 bit normalized W values that is ranging from 0 to 1.
|
|||
/// </summary>
|
|||
public struct Alpha8 : IPackedPixel<byte>, IEquatable<Alpha8> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Alpha8"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="alpha">The alpha component</param>
|
|||
public Alpha8(float alpha) |
|||
{ |
|||
this.PackedValue = Pack(alpha); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public byte PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Alpha8"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Alpha8"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Alpha8"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Alpha8 left, Alpha8 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Alpha8"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Alpha8"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Alpha8"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Alpha8 left, Alpha8 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(0, 0, 0, this.PackedValue / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackedValue = w; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = 0; |
|||
bytes[startIndex + 2] = 0; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = 0; |
|||
bytes[startIndex + 2] = 0; |
|||
bytes[startIndex + 3] = this.PackedValue; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = 0; |
|||
bytes[startIndex + 2] = 0; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = 0; |
|||
bytes[startIndex + 2] = 0; |
|||
bytes[startIndex + 3] = this.PackedValue; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares an object with the packed vector.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to compare.</param>
|
|||
/// <returns>True if the object is equal to the packed vector.</returns>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Alpha8) && this.Equals((Alpha8)obj); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares another Alpha8 packed vector with the packed vector.
|
|||
/// </summary>
|
|||
/// <param name="other">The Alpha8 packed vector to compare.</param>
|
|||
/// <returns>True if the packed vectors are equal.</returns>
|
|||
public bool Equals(Alpha8 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a string representation of the packed vector.
|
|||
/// </summary>
|
|||
/// <returns>A string representation of the packed vector.</returns>
|
|||
public override string ToString() |
|||
{ |
|||
return (this.PackedValue / 255F).ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs a <see cref="float"/> into a byte.
|
|||
/// </summary>
|
|||
/// <param name="alpha">The float containing the value to pack.</param>
|
|||
/// <returns>The <see cref="byte"/> containing the packed values.</returns>
|
|||
private static byte Pack(float alpha) |
|||
{ |
|||
return (byte)Math.Round(alpha.Clamp(0, 1) * 255F); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,170 @@ |
|||
// <copyright file="Bgr565.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits.
|
|||
/// </summary>
|
|||
public struct Bgr565 : IPackedPixel<ushort>, IEquatable<Bgr565> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
public Bgr565(float x, float y, float z) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector containing the components for the packed value.
|
|||
/// </param>
|
|||
public Bgr565(Vector3 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ushort PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgr565"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgr565"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgr565"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Bgr565 left, Bgr565 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgr565"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgr565"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgr565"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Bgr565 left, Bgr565 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector3"/>.
|
|||
/// The vector components are typically expanded in least to greatest significance order.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector3"/>.</returns>
|
|||
public Vector3 ToVector3() |
|||
{ |
|||
return new Vector3( |
|||
((this.PackedValue >> 11) & 0x1F) * (1F / 31F), |
|||
((this.PackedValue >> 5) & 0x3F) * (1F / 63F), |
|||
(this.PackedValue & 0x1F) * (1F / 31F)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.ToVector3(), 1F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Bgr565) && this.Equals((Bgr565)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Bgr565 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector3().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
|
|||
private static ushort Pack(float x, float y, float z) |
|||
{ |
|||
return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) | |
|||
(((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) | |
|||
((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,164 @@ |
|||
// <copyright file="Bgra4444.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing unsigned normalized values, ranging from 0 to 1, using 4 bits each for x, y, z, and w.
|
|||
/// </summary>
|
|||
public struct Bgra4444 : IPackedPixel<ushort>, IEquatable<Bgra4444> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra4444"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
public Bgra4444(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra4444"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the components for the packed vector.</param>
|
|||
public Bgra4444(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ushort PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgra4444"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgra4444"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgra4444"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Bgra4444 left, Bgra4444 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgra4444"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgra4444"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgra4444"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Bgra4444 left, Bgra4444 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
const float Max = 1 / 15F; |
|||
|
|||
return new Vector4( |
|||
((this.PackedValue >> 8) & 0x0F) * Max, |
|||
((this.PackedValue >> 4) & 0x0F) * Max, |
|||
(this.PackedValue & 0x0F) * Max, |
|||
((this.PackedValue >> 12) & 0x0F) * Max); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Bgra4444) && this.Equals((Bgra4444)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Bgra4444 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector4().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
|
|||
private static ushort Pack(float x, float y, float z, float w) |
|||
{ |
|||
return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | |
|||
(((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | |
|||
(((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | |
|||
((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,171 @@ |
|||
// <copyright file="Bgra5551.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit.
|
|||
/// </summary>
|
|||
public struct Bgra5551 : IPackedPixel<ushort>, IEquatable<Bgra5551> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra5551"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
public Bgra5551(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra5551"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector containing the components for the packed vector.
|
|||
/// </param>
|
|||
public Bgra5551(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ushort PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgra5551"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgra5551"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgra5551"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Bgra5551 left, Bgra5551 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Bgra5551"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Bgra5551"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Bgra5551"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Bgra5551 left, Bgra5551 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
((this.PackedValue >> 10) & 0x1F) / 31F, |
|||
((this.PackedValue >> 5) & 0x1F) / 31F, |
|||
((this.PackedValue >> 0) & 0x1F) / 31F, |
|||
(this.PackedValue >> 15) & 0x01); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Bgra5551) && this.Equals((Bgra5551)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Bgra5551 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a string representation of the packed vector.
|
|||
/// </summary>
|
|||
/// <returns>A string representation of the packed vector.</returns>
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector4().ToString(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a hash code of the packed vector.
|
|||
/// </summary>
|
|||
/// <returns>The hash code for the packed vector.</returns>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
|
|||
private static ushort Pack(float x, float y, float z, float w) |
|||
{ |
|||
return (ushort)( |
|||
(((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) | |
|||
(((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) | |
|||
(((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) | |
|||
(((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,177 @@ |
|||
// <copyright file="Byte4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 8-bit unsigned integer values, ranging from 0 to 255.
|
|||
/// </summary>
|
|||
public struct Byte4 : IPackedPixel<uint>, IEquatable<Byte4> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Byte4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// A vector containing the initial values for the components of the Byte4 structure.
|
|||
/// </param>
|
|||
public Byte4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(ref vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Byte4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
public Byte4(float x, float y, float z, float w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w); |
|||
this.PackedValue = Pack(ref vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Byte4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Byte4"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Byte4"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Byte4 left, Byte4 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Byte4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Byte4"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Byte4"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Byte4 left, Byte4 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the packed representation from a Vector4.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector to create the packed representation from.</param>
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(ref vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a Vector4.
|
|||
/// </summary>
|
|||
/// <returns>The expanded vector.</returns>
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
this.PackedValue & 0xFF, |
|||
(this.PackedValue >> 0x8) & 0xFF, |
|||
(this.PackedValue >> 0x10) & 0xFF, |
|||
(this.PackedValue >> 0x18) & 0xFF); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Byte4) && this.Equals((Byte4)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Byte4 other) |
|||
{ |
|||
return this == other; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a string representation of the current instance.
|
|||
/// </summary>
|
|||
/// <returns>String that represents the object.</returns>
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("x8"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs a vector into a uint.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the values to pack.</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(ref Vector4 vector) |
|||
{ |
|||
const float Max = 255F; |
|||
const float Min = 0F; |
|||
|
|||
// Clamp the value between min and max values
|
|||
uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF; |
|||
uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; |
|||
uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; |
|||
uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; |
|||
|
|||
return byte4 | byte3 | byte2 | byte1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,160 @@ |
|||
// <copyright file="HalfSingle.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing a single 16 bit floating point value.
|
|||
/// </summary>
|
|||
public struct HalfSingle : IPackedPixel<ushort>, IEquatable<HalfSingle> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half vector value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(0.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HalfSingle"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="single">The single component.</param>
|
|||
public HalfSingle(float single) |
|||
{ |
|||
this.PackedValue = HalfTypeHelper.Pack(single); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ushort PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfSingle"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfSingle"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfSingle"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(HalfSingle left, HalfSingle right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfSingle"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfSingle"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfSingle"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(HalfSingle left, HalfSingle right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="float"/>.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="float"/>.</returns>
|
|||
public float ToSingle() |
|||
{ |
|||
return HalfTypeHelper.Unpack(this.PackedValue); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = HalfTypeHelper.Pack(vector.X); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.ToSingle(), 0, 0, 1); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= MaxBytes; |
|||
vector += Half; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is HalfSingle) && this.Equals((HalfSingle)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(HalfSingle other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToSingle().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,144 @@ |
|||
// <copyright file="HalfTypeHelper.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Helper methods for packing and unpacking floating point values
|
|||
/// </summary>
|
|||
internal class HalfTypeHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Packs a <see cref="float"/> into an <see cref="ushort"/>
|
|||
/// </summary>
|
|||
/// <param name="value">The float to pack</param>
|
|||
/// <returns>The <see cref="ushort"/></returns>
|
|||
internal static ushort Pack(float value) |
|||
{ |
|||
Uif uif = new Uif { F = value }; |
|||
return Pack(uif.I); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs an <see cref="int"/> into a <see cref="ushort"/>
|
|||
/// </summary>
|
|||
/// <param name="value">The integer to pack.</param>
|
|||
/// <returns>The <see cref="ushort"/></returns>
|
|||
internal static ushort Pack(int value) |
|||
{ |
|||
int s = (value >> 16) & 0x00008000; |
|||
int e = ((value >> 23) & 0x000000ff) - (127 - 15); |
|||
int m = value & 0x007fffff; |
|||
|
|||
if (e <= 0) |
|||
{ |
|||
if (e < -10) |
|||
{ |
|||
return (ushort)s; |
|||
} |
|||
|
|||
m = m | 0x00800000; |
|||
|
|||
int t = 14 - e; |
|||
int a = (1 << (t - 1)) - 1; |
|||
int b = (m >> t) & 1; |
|||
|
|||
m = (m + a + b) >> t; |
|||
|
|||
return (ushort)(s | m); |
|||
} |
|||
|
|||
if (e == 0xff - (127 - 15)) |
|||
{ |
|||
if (m == 0) |
|||
{ |
|||
return (ushort)(s | 0x7c00); |
|||
} |
|||
|
|||
m >>= 13; |
|||
return (ushort)(s | 0x7c00 | m | ((m == 0) ? 1 : 0)); |
|||
} |
|||
|
|||
m = m + 0x00000fff + ((m >> 13) & 1); |
|||
|
|||
if ((m & 0x00800000) != 0) |
|||
{ |
|||
m = 0; |
|||
e += 1; |
|||
} |
|||
|
|||
if (e > 30) |
|||
{ |
|||
return (ushort)(s | 0x7c00); |
|||
} |
|||
|
|||
return (ushort)(s | (e << 10) | (m >> 13)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Unpacks a <see cref="ushort"/> into a <see cref="float"/>.
|
|||
/// </summary>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <returns>The <see cref="float"/>.</returns>
|
|||
internal static float Unpack(ushort value) |
|||
{ |
|||
uint result; |
|||
uint mantissa = (uint)(value & 1023); |
|||
uint exponent = 0xfffffff2; |
|||
|
|||
if ((value & -33792) == 0) |
|||
{ |
|||
if (mantissa != 0) |
|||
{ |
|||
while ((mantissa & 1024) == 0) |
|||
{ |
|||
exponent--; |
|||
mantissa = mantissa << 1; |
|||
} |
|||
mantissa &= 0xfffffbff; |
|||
result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); |
|||
} |
|||
else |
|||
{ |
|||
result = (uint)((value & 0x8000) << 16); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); |
|||
} |
|||
|
|||
Uif uif = new Uif { U = result }; |
|||
return uif.F; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Maps the position of number types in memory
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Explicit)] |
|||
private struct Uif |
|||
{ |
|||
/// <summary>
|
|||
/// The float.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public float F; |
|||
|
|||
/// <summary>
|
|||
/// The integer.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public int I; |
|||
|
|||
/// <summary>
|
|||
/// The unsigned integer.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public uint U; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,187 @@ |
|||
// <copyright file="HalfVector2.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing two 16-bit floating-point values.
|
|||
/// </summary>
|
|||
public struct HalfVector2 : IPackedPixel<uint>, IEquatable<HalfVector2> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half vector value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(0.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HalfVector2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
public HalfVector2(float x, float y) |
|||
{ |
|||
this.PackedValue = Pack(x, y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HalfVector2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">A vector containing the initial values for the components.</param>
|
|||
public HalfVector2(Vector2 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfVector2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfVector2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfVector2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(HalfVector2 left, HalfVector2 right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfVector2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfVector2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfVector2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(HalfVector2 left, HalfVector2 right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector2"/>.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector2"/>.</returns>
|
|||
public Vector2 ToVector2() |
|||
{ |
|||
Vector2 vector; |
|||
vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); |
|||
vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); |
|||
return vector; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
Vector2 vector = this.ToVector2(); |
|||
return new Vector4(vector.X, vector.Y, 0F, 1F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= MaxBytes; |
|||
vector += Half; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector2().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is HalfVector2) && this.Equals((HalfVector2)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(HalfVector2 other) |
|||
{ |
|||
return this.PackedValue.Equals(other.PackedValue); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y) |
|||
{ |
|||
uint num2 = HalfTypeHelper.Pack(x); |
|||
uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); |
|||
return num2 | num; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,182 @@ |
|||
// <copyright file="HalfVector4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 16-bit floating-point values.
|
|||
/// </summary>
|
|||
public struct HalfVector4 : IPackedPixel<ulong>, IEquatable<HalfVector4> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half vector value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(0.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HalfVector4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
/// <param name="z">The z-component.</param>
|
|||
/// <param name="w">The w-component.</param>
|
|||
public HalfVector4(float x, float y, float z, float w) |
|||
{ |
|||
var vector = new Vector4(x, y, z, w); |
|||
this.PackedValue = PackHelper(ref vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HalfVector4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">A vector containing the initial values for the components</param>
|
|||
public HalfVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = PackHelper(ref vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ulong PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfVector2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfVector2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfVector2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(HalfVector4 left, HalfVector4 right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="HalfVector2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="HalfVector2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="HalfVector2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(HalfVector4 left, HalfVector4 right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = PackHelper(ref vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
HalfTypeHelper.Unpack((ushort)this.PackedValue), |
|||
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)), |
|||
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x20)), |
|||
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30))); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= MaxBytes; |
|||
vector += Half; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector4().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is HalfVector4) && this.Equals((HalfVector4)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(HalfVector4 other) |
|||
{ |
|||
return this.PackedValue.Equals(other.PackedValue); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs a <see cref="Vector4"/> into a <see cref="ulong"/>.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the values to pack.</param>
|
|||
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
|
|||
private static ulong PackHelper(ref Vector4 vector) |
|||
{ |
|||
ulong num4 = HalfTypeHelper.Pack(vector.X); |
|||
ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; |
|||
ulong num2 = (ulong)HalfTypeHelper.Pack(vector.Z) << 0x20; |
|||
ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; |
|||
return num4 | num3 | num2 | num1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,199 @@ |
|||
// <copyright file="NormalizedByte2.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed packed pixel type containing two 8-bit signed normalized values, ranging from −1 to 1.
|
|||
/// </summary>
|
|||
public struct NormalizedByte2 : IPackedPixel<ushort>, IEquatable<NormalizedByte2> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Round = new Vector4(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public NormalizedByte2(Vector2 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
public NormalizedByte2(float x, float y) |
|||
{ |
|||
this.PackedValue = Pack(x, y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ushort PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedByte2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedByte2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedByte2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedByte2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector2"/>.
|
|||
/// The vector components are typically expanded in least to greatest significance order.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector2"/>.</returns>
|
|||
public Vector2 ToVector2() |
|||
{ |
|||
return new Vector2( |
|||
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, |
|||
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.ToVector2(), 0F, 1F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w); |
|||
vector -= Round; |
|||
vector -= Half; |
|||
vector -= Round; |
|||
vector /= Half; |
|||
this.PackFromVector4(vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= Half; |
|||
vector += Round; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = 0; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = 0; |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is NormalizedByte2) && this.Equals((NormalizedByte2)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(NormalizedByte2 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("X"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
|
|||
private static ushort Pack(float x, float y) |
|||
{ |
|||
int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; |
|||
int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; |
|||
|
|||
return (ushort)(byte2 | byte1); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,197 @@ |
|||
// <copyright file="NormalizedByte4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 8-bit signed normalized values, ranging from −1 to 1.
|
|||
/// </summary>
|
|||
public struct NormalizedByte4 : IPackedPixel<uint>, IEquatable<NormalizedByte4> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Round = new Vector4(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public NormalizedByte4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
/// <param name="z">The z-component.</param>
|
|||
/// <param name="w">The w-component.</param>
|
|||
public NormalizedByte4(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedByte4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedByte4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedByte4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedByte4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, |
|||
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F, |
|||
(sbyte)((this.PackedValue >> 16) & 0xFF) / 127F, |
|||
(sbyte)((this.PackedValue >> 24) & 0xFF) / 127F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w); |
|||
vector -= Round; |
|||
vector -= Half; |
|||
vector -= Round; |
|||
vector /= Half; |
|||
this.PackFromVector4(vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= Half; |
|||
vector += Round; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is NormalizedByte4) && this.Equals((NormalizedByte4)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(NormalizedByte4 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("X"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y, float z, float w) |
|||
{ |
|||
uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; |
|||
uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; |
|||
uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16; |
|||
uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24; |
|||
|
|||
return byte4 | byte3 | byte2 | byte1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
// <copyright file="NormalizedShort2.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing two 16-bit signed normalized values, ranging from −1 to 1.
|
|||
/// </summary>
|
|||
public struct NormalizedShort2 : IPackedPixel<uint>, IEquatable<NormalizedShort2> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Round = new Vector4(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public NormalizedShort2(Vector2 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
public NormalizedShort2(float x, float y) |
|||
{ |
|||
this.PackedValue = Pack(x, y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedShort2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedShort2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedShort2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedShort2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.ToVector2(), 0, 1); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w); |
|||
vector -= Round; |
|||
vector -= Half; |
|||
vector -= Round; |
|||
vector /= Half; |
|||
this.PackFromVector4(vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= Half; |
|||
vector += Round; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = 0; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = 0; |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector2"/>.
|
|||
/// The vector components are typically expanded in least to greatest significance order.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector2"/>.</returns>
|
|||
public Vector2 ToVector2() |
|||
{ |
|||
const float MaxVal = 0x7FFF; |
|||
|
|||
return new Vector2( |
|||
(short)(this.PackedValue & 0xFFFF) / MaxVal, |
|||
(short)(this.PackedValue >> 0x10) / MaxVal); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is NormalizedShort2) && this.Equals((NormalizedShort2)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(NormalizedShort2 other) |
|||
{ |
|||
return this.PackedValue.Equals(other.PackedValue); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("X"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y) |
|||
{ |
|||
const float MaxPos = 0x7FFF; |
|||
const float MinNeg = -MaxPos; |
|||
|
|||
// Clamp the value between min and max values
|
|||
// Round rather than truncate.
|
|||
uint word2 = (uint)((int)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); |
|||
uint word1 = (uint)(((int)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); |
|||
|
|||
return word2 | word1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,203 @@ |
|||
// <copyright file="NormalizedShort4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 16-bit signed normalized values, ranging from −1 to 1.
|
|||
/// </summary>
|
|||
public struct NormalizedShort4 : IPackedPixel<ulong>, IEquatable<NormalizedShort4> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Round = new Vector4(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public NormalizedShort4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
/// <param name="z">The z-component.</param>
|
|||
/// <param name="w">The w-component.</param>
|
|||
public NormalizedShort4(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ulong PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedShort4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedShort4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="NormalizedShort4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="NormalizedShort4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
const float MaxVal = 0x7FFF; |
|||
|
|||
return new Vector4( |
|||
(short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxVal, |
|||
(short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxVal, |
|||
(short)((this.PackedValue >> 0x20) & 0xFFFF) / MaxVal, |
|||
(short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxVal); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w); |
|||
vector -= Round; |
|||
vector -= Half; |
|||
vector -= Round; |
|||
vector /= Half; |
|||
this.PackFromVector4(vector); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector *= Half; |
|||
vector += Round; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is NormalizedShort4) && this.Equals((NormalizedShort4)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(NormalizedShort4 other) |
|||
{ |
|||
return this.PackedValue.Equals(other.PackedValue); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("X"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ulong"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
|
|||
private static ulong Pack(float x, float y, float z, float w) |
|||
{ |
|||
const float MaxPos = 0x7FFF; |
|||
const float MinNeg = -MaxPos; |
|||
|
|||
// Clamp the value between min and max values
|
|||
ulong word4 = ((ulong)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; |
|||
ulong word3 = ((ulong)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; |
|||
ulong word2 = ((ulong)(float)Math.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; |
|||
ulong word1 = ((ulong)(float)Math.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; |
|||
|
|||
return word4 | word3 | word2 | word1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,276 @@ |
|||
// <copyright file="PackedPixelConverterHelper.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Assists with the conversion of known packed pixel formats from one to another.
|
|||
/// </summary>
|
|||
internal static class PackedPixelConverterHelper |
|||
{ |
|||
/// <summary>
|
|||
/// A non operative function. Simply returns the original vector.
|
|||
/// </summary>
|
|||
private static readonly Func<Vector4, Vector4> Noop = vector4 => vector4; |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct scaling function for the given types The compute scale function.
|
|||
/// </summary>
|
|||
/// <param name="scaleFunc">The scale function.</param>
|
|||
/// <typeparam name="TColor">The source pixel format.</typeparam>
|
|||
/// <typeparam name="TColor2">The target pixel format.</typeparam>
|
|||
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
|||
public static Func<Vector4, Vector4> ComputeScaleFunction<TColor, TColor2>(Func<Vector4, Vector4> scaleFunc) |
|||
{ |
|||
// Custom type with a custom function.
|
|||
if (scaleFunc != null) |
|||
{ |
|||
return scaleFunc; |
|||
} |
|||
|
|||
Type source = typeof(TColor); |
|||
Type target = typeof(TColor2); |
|||
|
|||
// Standard to offset
|
|||
if (IsStandardNormalizedType(source)) |
|||
{ |
|||
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) |
|||
{ |
|||
// Expand the range then offset the center down.
|
|||
return vector4 => (2F * vector4) - Vector4.One; |
|||
} |
|||
|
|||
if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) |
|||
{ |
|||
return v => (65534 * v) - new Vector4(32767); |
|||
} |
|||
} |
|||
|
|||
// Normalized offsets. All four components.
|
|||
if (IsOffsetNormalizedType(source)) |
|||
{ |
|||
return FromOffsetNormalizedType(target); |
|||
} |
|||
|
|||
// Offset. All four components.
|
|||
if (IsOffsetType(source)) |
|||
{ |
|||
return FromOffsetType(target); |
|||
} |
|||
|
|||
// Normalized offsets. First component pair only.
|
|||
if (IsOffsetTwoComponentNormalizedType(source)) |
|||
{ |
|||
return FromOffsetTwoComponentNormalizedType(target); |
|||
} |
|||
|
|||
// Offsets. First component pair only.
|
|||
if (IsOffsetTwoComponentType(source)) |
|||
{ |
|||
return FromOffsetTwoComponentType(target); |
|||
} |
|||
|
|||
return Noop; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct conversion function to convert from types having vector values representing all four components
|
|||
/// ranging from -1 to 1.
|
|||
/// </summary>
|
|||
/// <param name="target">The target type</param>
|
|||
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
|||
private static Func<Vector4, Vector4> FromOffsetNormalizedType(Type target) |
|||
{ |
|||
if (IsStandardNormalizedType(target)) |
|||
{ |
|||
// Compress the range then offset the center up.
|
|||
return vector4 => (vector4 / 2F) + new Vector4(.5F); |
|||
} |
|||
|
|||
if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) |
|||
{ |
|||
// Multiply out the range, two component won't read the last two values.
|
|||
return vector4 => (vector4 * 32767F); |
|||
} |
|||
|
|||
return Noop; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct conversion function to convert from types having vector values representing all four components
|
|||
/// ranging from -32767 to 32767.
|
|||
/// </summary>
|
|||
/// <param name="target">The target type</param>
|
|||
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
|||
private static Func<Vector4, Vector4> FromOffsetType(Type target) |
|||
{ |
|||
if (IsStandardNormalizedType(target)) |
|||
{ |
|||
// Compress the range then offset the center up.
|
|||
return vector4 => (vector4 / 65534) + new Vector4(.5F); |
|||
} |
|||
|
|||
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) |
|||
{ |
|||
// Compress the range. Two component won't read the last two values.
|
|||
return vector4 => (vector4 / 32767); |
|||
} |
|||
|
|||
return Noop; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -1 to 1.
|
|||
/// and the second component pair ranging from 0 to 1.
|
|||
/// </summary>
|
|||
/// <param name="target">The target type</param>
|
|||
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
|||
private static Func<Vector4, Vector4> FromOffsetTwoComponentNormalizedType(Type target) |
|||
{ |
|||
if (IsStandardNormalizedType(target)) |
|||
{ |
|||
return vector4 => |
|||
{ |
|||
// Compress the range then offset the center up for first pair.
|
|||
Vector4 v = (vector4 / 2F) + new Vector4(.5F); |
|||
return new Vector4(v.X, v.Y, 0, 1); |
|||
}; |
|||
} |
|||
|
|||
if (IsOffsetNormalizedType(target)) |
|||
{ |
|||
// Copy the first two components and set second pair to 0 and 1 equivalent.
|
|||
return vector4 => new Vector4(vector4.X, vector4.Y, -1, 1); |
|||
} |
|||
|
|||
if (IsOffsetTwoComponentType(target)) |
|||
{ |
|||
// Multiply. Two component won't read the last two values.
|
|||
return vector4 => (vector4 * 32767); |
|||
} |
|||
|
|||
if (IsOffsetType(target)) |
|||
{ |
|||
return vector4 => |
|||
{ |
|||
// Multiply the first two components and set second pair to 0 and 1 equivalent.
|
|||
Vector4 v = vector4 * 32767; |
|||
return new Vector4(v.X, v.Y, -32767, 32767); |
|||
}; |
|||
} |
|||
|
|||
return Noop; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -32767 to 32767.
|
|||
/// and the second component pair ranging from 0 to 1.
|
|||
/// </summary>
|
|||
/// <param name="target">The target type</param>
|
|||
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
|||
private static Func<Vector4, Vector4> FromOffsetTwoComponentType(Type target) |
|||
{ |
|||
if (IsStandardNormalizedType(target)) |
|||
{ |
|||
return vector4 => |
|||
{ |
|||
Vector4 v = (vector4 / 65534) + new Vector4(.5F); |
|||
return new Vector4(v.X, v.Y, 0, 1); |
|||
}; |
|||
} |
|||
|
|||
if (IsOffsetType(target)) |
|||
{ |
|||
// Copy the first two components and set second pair to 0 and 1 equivalent.
|
|||
return vector4 => new Vector4(vector4.X, vector4.Y, -32767, 32767); |
|||
} |
|||
|
|||
if (IsOffsetNormalizedType(target)) |
|||
{ |
|||
return vector4 => |
|||
{ |
|||
// Divide the first two components and set second pair to 0 and 1 equivalent.
|
|||
Vector4 v = vector4 / 32767; |
|||
return new Vector4(v.X, v.Y, -1, 1); |
|||
}; |
|||
} |
|||
|
|||
if (IsOffsetTwoComponentNormalizedType(target)) |
|||
{ |
|||
// Divide. Two component won't read the last two values.
|
|||
return vector4 => (vector4 / 32767); |
|||
} |
|||
|
|||
return Noop; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the type as having vector component values ranging from 0 to 1.
|
|||
/// </summary>
|
|||
/// <param name="type">The type to test.</param>
|
|||
/// <returns>The <see cref="bool"/></returns>
|
|||
private static bool IsStandardNormalizedType(Type type) |
|||
{ |
|||
return type == typeof(Color) |
|||
|| type == typeof(Bgr565) |
|||
|| type == typeof(Bgra4444) |
|||
|| type == typeof(Bgra5551) |
|||
|| type == typeof(Byte4) |
|||
|| type == typeof(HalfSingle) |
|||
|| type == typeof(HalfVector2) |
|||
|| type == typeof(HalfVector4) |
|||
|| type == typeof(Rg32) |
|||
|| type == typeof(Rgba1010102) |
|||
|| type == typeof(Rgba64); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the type as having vector values representing the first component pair ranging from -1 to 1.
|
|||
/// and the second component pair ranging from 0 to 1.
|
|||
/// </summary>
|
|||
/// <param name="type">The type to test.</param>
|
|||
/// <returns>The <see cref="bool"/></returns>
|
|||
private static bool IsOffsetTwoComponentNormalizedType(Type type) |
|||
{ |
|||
return type == typeof(NormalizedByte2) |
|||
|| type == typeof(NormalizedShort2); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the type as having vector values representing all four components ranging from -1 to 1.
|
|||
/// </summary>
|
|||
/// <param name="type">The type to test.</param>
|
|||
/// <returns>The <see cref="bool"/></returns>
|
|||
private static bool IsOffsetNormalizedType(Type type) |
|||
{ |
|||
return type == typeof(NormalizedByte4) |
|||
|| type == typeof(NormalizedShort4); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the type as having vector values representing the first component pair ranging from -32767 to 32767.
|
|||
/// and the second component pair ranging from 0 to 1.
|
|||
/// </summary>
|
|||
/// <param name="type">The type to test.</param>
|
|||
/// <returns>The <see cref="bool"/></returns>
|
|||
private static bool IsOffsetTwoComponentType(Type type) |
|||
{ |
|||
return type == typeof(Short2); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the type as having vector values representing all four components ranging from -32767 to 32767.
|
|||
/// </summary>
|
|||
/// <param name="type">The type to test.</param>
|
|||
/// <returns>The <see cref="bool"/></returns>
|
|||
private static bool IsOffsetType(Type type) |
|||
{ |
|||
return type == typeof(Short4); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
Pixel formats adapted and extended from: |
|||
|
|||
https://github.com/MonoGame/MonoGame |
|||
@ -0,0 +1,173 @@ |
|||
// <copyright file="Rg32.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing two 16-bit unsigned normalized values ranging from 0 to 1.
|
|||
/// </summary>
|
|||
public struct Rg32 : IPackedPixel<uint>, IEquatable<Rg32>, IPackedVector |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rg32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
public Rg32(float x, float y) |
|||
{ |
|||
this.PackedValue = Pack(x, y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rg32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public Rg32(Vector2 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rg32"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rg32"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rg32"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Rg32 left, Rg32 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rg32"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rg32"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rg32"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Rg32 left, Rg32 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector2"/>.
|
|||
/// The vector components are typically expanded in least to greatest significance order.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector2"/>.</returns>
|
|||
public Vector2 ToVector2() |
|||
{ |
|||
return new Vector2( |
|||
(this.PackedValue & 0xFFFF) / 65535F, |
|||
((this.PackedValue >> 16) & 0xFFFF) / 65535F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4(this.ToVector2(), 0F, 1F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)vector.Z; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.X; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)vector.X; |
|||
bytes[startIndex + 1] = (byte)vector.Y; |
|||
bytes[startIndex + 2] = (byte)vector.Z; |
|||
bytes[startIndex + 3] = (byte)vector.W; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Rg32) && this.Equals((Rg32)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Rg32 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector2().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y) |
|||
{ |
|||
return (uint)( |
|||
((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | |
|||
(((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,172 @@ |
|||
// <copyright file="Rgba1010102.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
|
|||
/// The x, y and z components use 10 bits, and the w component uses 2 bits.
|
|||
/// </summary>
|
|||
public struct Rgba1010102 : IPackedPixel<uint>, IEquatable<Rgba1010102>, IPackedVector |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
public Rgba1010102(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public Rgba1010102(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba1010102"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rgba1010102"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rgba1010102"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Rgba1010102 left, Rgba1010102 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba1010102"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rgba1010102"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rgba1010102"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Rgba1010102 left, Rgba1010102 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
((this.PackedValue >> 0) & 0x03FF) / 1023F, |
|||
((this.PackedValue >> 10) & 0x03FF) / 1023F, |
|||
((this.PackedValue >> 20) & 0x03FF) / 1023F, |
|||
((this.PackedValue >> 30) & 0x03) / 3F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Rgba1010102) && this.Equals((Rgba1010102)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Rgba1010102 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector4().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y, float z, float w) |
|||
{ |
|||
return (uint)( |
|||
(((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | |
|||
(((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | |
|||
(((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | |
|||
(((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,170 @@ |
|||
// <copyright file="Rgba64.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 1.
|
|||
/// </summary>
|
|||
public struct Rgba64 : IPackedPixel<ulong>, IEquatable<Rgba64>, IPackedVector |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
public Rgba64(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the components values.</param>
|
|||
public Rgba64(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ulong PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba64"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rgba64"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rgba64"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Rgba64 left, Rgba64 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba64"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Rgba64"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Rgba64"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Rgba64 left, Rgba64 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
(this.PackedValue & 0xFFFF) / 65535F, |
|||
((this.PackedValue >> 16) & 0xFFFF) / 65535F, |
|||
((this.PackedValue >> 32) & 0xFFFF) / 65535F, |
|||
((this.PackedValue >> 48) & 0xFFFF) / 65535F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
this.PackFromVector4(new Vector4(x, y, z, w) / 255F); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4() * 255F; |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Rgba64) && this.Equals((Rgba64)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Rgba64 other) |
|||
{ |
|||
return this.PackedValue == other.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToVector4().ToString(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="ulong"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
|
|||
private static ulong Pack(float x, float y, float z, float w) |
|||
{ |
|||
return (ulong)Math.Round(x.Clamp(0, 1) * 65535F) | |
|||
((ulong)Math.Round(y.Clamp(0, 1) * 65535F) << 16) | |
|||
((ulong)Math.Round(z.Clamp(0, 1) * 65535F) << 32) | |
|||
((ulong)Math.Round(w.Clamp(0, 1) * 65535F) << 48); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,200 @@ |
|||
// <copyright file="Short2.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing two 16-bit signed integer values.
|
|||
/// </summary>
|
|||
public struct Short2 : IPackedPixel<uint>, IEquatable<Short2> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector2 MaxBytes = new Vector2(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector2 Half = new Vector2(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector2 Round = new Vector2(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Short2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the component values.</param>
|
|||
public Short2(Vector2 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Short2"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
public Short2(float x, float y) |
|||
{ |
|||
this.PackedValue = Pack(x, y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public uint PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Short2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Short2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Short2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Short2 left, Short2 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Short2"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Short2"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Short2"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Short2 left, Short2 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector2 vector = new Vector2(x, y) / 255; |
|||
vector *= 65534; |
|||
vector -= new Vector2(32767); |
|||
this.PackedValue = Pack(vector.X, vector.Y); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector2 vector = this.ToVector2(); |
|||
vector /= 65534; |
|||
vector *= 255; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = 0; |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = 0; |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = 0; |
|||
bytes[startIndex + 3] = 255; |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a <see cref="Vector2"/>.
|
|||
/// The vector components are typically expanded in least to greatest significance order.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Vector2"/>.</returns>
|
|||
public Vector2 ToVector2() |
|||
{ |
|||
return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Short2) && this.Equals((Short2)obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Equals(Short2 other) |
|||
{ |
|||
return this == other; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("x8"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|||
private static uint Pack(float x, float y) |
|||
{ |
|||
// Largest two byte positive number 0xFFFF >> 1;
|
|||
const float MaxPos = 0x7FFF; |
|||
const float MinNeg = ~(int)MaxPos; |
|||
|
|||
// Clamp the value between min and max values
|
|||
uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF; |
|||
uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; |
|||
|
|||
return word2 | word1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,216 @@ |
|||
// <copyright file="Short4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 16-bit signed integer values.
|
|||
/// </summary>
|
|||
public struct Short4 : IPackedPixel<ulong>, IEquatable<Short4> |
|||
{ |
|||
/// <summary>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new Vector4(255); |
|||
|
|||
/// <summary>
|
|||
/// The half the maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new Vector4(127); |
|||
|
|||
/// <summary>
|
|||
/// The vector value used for rounding.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Round = new Vector4(.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Short4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">A vector containing the initial values for the components.</param>
|
|||
public Short4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Short4"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component.</param>
|
|||
/// <param name="y">The y-component.</param>
|
|||
/// <param name="z">The z-component.</param>
|
|||
/// <param name="w">The w-component.</param>
|
|||
public Short4(float x, float y, float z, float w) |
|||
{ |
|||
this.PackedValue = Pack(x, y, z, w); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public ulong PackedValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Short4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Short4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Short4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator ==(Short4 left, Short4 right) |
|||
{ |
|||
return left.PackedValue == right.PackedValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Short4"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Short4"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Short4"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
public static bool operator !=(Short4 left, Short4 right) |
|||
{ |
|||
return left.PackedValue != right.PackedValue; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Vector4( |
|||
(short)(this.PackedValue & 0xFFFF), |
|||
(short)((this.PackedValue >> 0x10) & 0xFFFF), |
|||
(short)((this.PackedValue >> 0x20) & 0xFFFF), |
|||
(short)((this.PackedValue >> 0x30) & 0xFFFF)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void PackFromBytes(byte x, byte y, byte z, byte w) |
|||
{ |
|||
Vector4 vector = new Vector4(x, y, z, w) / 255; |
|||
vector *= 65534; |
|||
vector -= new Vector4(32767); |
|||
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) |
|||
{ |
|||
Vector4 vector = this.ToVector4(); |
|||
vector /= 65534; |
|||
vector *= 255; |
|||
vector += Half; |
|||
vector += Round; |
|||
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
switch (componentOrder) |
|||
{ |
|||
case ComponentOrder.ZYX: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
break; |
|||
case ComponentOrder.ZYXW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
case ComponentOrder.XYZ: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
break; |
|||
case ComponentOrder.XYZW: |
|||
bytes[startIndex] = (byte)(float)Math.Round(vector.X); |
|||
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); |
|||
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); |
|||
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); |
|||
break; |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a value that indicates whether the current instance is equal to a specified object.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object with which to make the comparison.</param>
|
|||
/// <returns>true if the current instance is equal to the specified object; false otherwise.</returns>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is Short4) && this == (Short4)obj; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a value that indicates whether the current instance is equal to a specified object.
|
|||
/// </summary>
|
|||
/// <param name="other">The object with which to make the comparison.</param>
|
|||
/// <returns>true if the current instance is equal to the specified object; false otherwise.</returns>
|
|||
public bool Equals(Short4 other) |
|||
{ |
|||
return this == other; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the hash code for the current instance.
|
|||
/// </summary>
|
|||
/// <returns>Hash code for the instance.</returns>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return this.PackedValue.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a string representation of the current instance.
|
|||
/// </summary>
|
|||
/// <returns>String that represents the object.</returns>
|
|||
public override string ToString() |
|||
{ |
|||
return this.PackedValue.ToString("x16"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs the components into a <see cref="ulong"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-component</param>
|
|||
/// <param name="y">The y-component</param>
|
|||
/// <param name="z">The z-component</param>
|
|||
/// <param name="w">The w-component</param>
|
|||
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
|
|||
private static ulong Pack(float x, float y, float z, float w) |
|||
{ |
|||
// Largest two byte positive number 0xFFFF >> 1;
|
|||
const float MaxPos = 0x7FFF; |
|||
|
|||
// Two's complement
|
|||
const float MinNeg = ~(int)MaxPos; |
|||
|
|||
// Clamp the value between min and max values
|
|||
ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00; |
|||
ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; |
|||
ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20; |
|||
ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30; |
|||
|
|||
return word4 | word3 | word2 | word1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,841 @@ |
|||
// <copyright file="PackedPixelTests.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests.Colors |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using Xunit; |
|||
|
|||
/// <summary>
|
|||
/// The packed pixel tests.
|
|||
/// </summary>
|
|||
public class PackedPixelTests |
|||
{ |
|||
[Fact] |
|||
public void Alpha8() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal(0x0, new Alpha8(0F).PackedValue); |
|||
Assert.Equal(0xFF, new Alpha8(1F).PackedValue); |
|||
|
|||
// Test clamping.
|
|||
Assert.Equal(0x0, new Alpha8(-1234F).PackedValue); |
|||
Assert.Equal(0xFF, new Alpha8(1234F).PackedValue); |
|||
|
|||
// Test ordering
|
|||
Assert.Equal(124, new Alpha8(124F / 0xFF).PackedValue); |
|||
Assert.Equal(26, new Alpha8(0.1F).PackedValue); |
|||
|
|||
// Test ordering
|
|||
Vector4 vector = new Alpha8(.5F).ToVector4(); |
|||
|
|||
Assert.Equal(vector.X, 0); |
|||
Assert.Equal(vector.Y, 0); |
|||
Assert.Equal(vector.Z, 0); |
|||
Assert.Equal(vector.W, .5F, 2); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Alpha8(.5F).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 0, 0, 0 }); |
|||
|
|||
new Alpha8(.5F).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 0, 0, 0, 128 }); |
|||
|
|||
new Alpha8(.5F).ToBytes(rgb, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 0, 0 }); |
|||
|
|||
new Alpha8(.5F).ToBytes(rgb, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bgr565() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal(0x0, new Bgr565(Vector3.Zero).PackedValue); |
|||
Assert.Equal(0xFFFF, new Bgr565(Vector3.One).PackedValue); |
|||
|
|||
// Test ToVector3.
|
|||
Assert.True(Equal(Vector3.One, new Bgr565(Vector3.One).ToVector3())); |
|||
Assert.True(Equal(Vector3.Zero, new Bgr565(Vector3.Zero).ToVector3())); |
|||
Assert.True(Equal(Vector3.UnitX, new Bgr565(Vector3.UnitX).ToVector3())); |
|||
Assert.True(Equal(Vector3.UnitY, new Bgr565(Vector3.UnitY).ToVector3())); |
|||
Assert.True(Equal(Vector3.UnitZ, new Bgr565(Vector3.UnitZ).ToVector3())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3())); |
|||
Assert.True(Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3())); |
|||
|
|||
// Make sure the swizzle is correct.
|
|||
Assert.Equal(0xF800, new Bgr565(Vector3.UnitX).PackedValue); |
|||
Assert.Equal(0x07E0, new Bgr565(Vector3.UnitY).PackedValue); |
|||
Assert.Equal(0x001F, new Bgr565(Vector3.UnitZ).PackedValue); |
|||
|
|||
float x = 0.1F; |
|||
float y = -0.3F; |
|||
float z = 0.5F; |
|||
Assert.Equal(6160, new Bgr565(x, y, z).PackedValue); |
|||
|
|||
|
|||
// Test ordering
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Bgr565(x, y, z).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 25, 0, 132 }); |
|||
|
|||
new Bgr565(x, y, z).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 25, 0, 132, 255 }); |
|||
|
|||
new Bgr565(x, y, z).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 132, 0, 25 }); |
|||
|
|||
new Bgr565(x, y, z).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 132, 0, 25, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bgra4444() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal(0x0, new Bgra4444(Vector4.Zero).PackedValue); |
|||
Assert.Equal(0xFFFF, new Bgra4444(Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4.
|
|||
Assert.True(Equal(Vector4.One, new Bgra4444(Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.Zero, new Bgra4444(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitX, new Bgra4444(Vector4.UnitX).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitY, new Bgra4444(Vector4.UnitY).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitZ, new Bgra4444(Vector4.UnitZ).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitW, new Bgra4444(Vector4.UnitW).ToVector4())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4())); |
|||
|
|||
// Make sure the swizzle is correct.
|
|||
Assert.Equal(0x0F00, new Bgra4444(Vector4.UnitX).PackedValue); |
|||
Assert.Equal(0x00F0, new Bgra4444(Vector4.UnitY).PackedValue); |
|||
Assert.Equal(0x000F, new Bgra4444(Vector4.UnitZ).PackedValue); |
|||
Assert.Equal(0xF000, new Bgra4444(Vector4.UnitW).PackedValue); |
|||
|
|||
float x = 0.1f; |
|||
float y = -0.3f; |
|||
float z = 0.5f; |
|||
float w = -0.7f; |
|||
Assert.Equal(520, new Bgra4444(x, y, z, w).PackedValue); |
|||
|
|||
// Test ordering
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Bgra4444(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 34, 0, 136 }); |
|||
|
|||
new Bgra4444(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 34, 0, 136, 0 }); |
|||
|
|||
new Bgra4444(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 136, 0, 34 }); |
|||
|
|||
new Bgra4444(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 136, 0, 34, 0 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Bgra5551() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal(0x0, new Bgra5551(Vector4.Zero).PackedValue); |
|||
Assert.Equal(0xFFFF, new Bgra5551(Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.Zero, new Bgra5551(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Bgra5551(Vector4.One).ToVector4())); |
|||
|
|||
// Test clamping.
|
|||
Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); |
|||
Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); |
|||
|
|||
// Test Ordering
|
|||
float x = 0x1a; |
|||
float y = 0x16; |
|||
float z = 0xd; |
|||
float w = 0x1; |
|||
Assert.Equal(0xeacd, new Bgra5551(x / 0x1f, y / 0x1f, z / 0x1f, w).PackedValue); |
|||
x = 0.1f; |
|||
y = -0.3f; |
|||
z = 0.5f; |
|||
w = -0.7f; |
|||
Assert.Equal(3088, new Bgra5551(x, y, z, w).PackedValue); |
|||
|
|||
// Test ordering
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Bgra5551(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 24, 0, 131 }); |
|||
|
|||
new Bgra5551(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 24, 0, 131, 0 }); |
|||
|
|||
new Bgra5551(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 131, 0, 24 }); |
|||
|
|||
new Bgra5551(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 131, 0, 24, 0 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Byte4() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((uint)0x0, new Byte4(Vector4.Zero).PackedValue); |
|||
Assert.Equal(0xFFFFFFFF, new Byte4(Vector4.One * 255).PackedValue); |
|||
|
|||
// Test ToVector4.
|
|||
Assert.True(Equal(Vector4.One * 255, new Byte4(Vector4.One * 255).ToVector4())); |
|||
Assert.True(Equal(Vector4.Zero, new Byte4(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitX * 255, new Byte4(Vector4.UnitX * 255).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitY * 255, new Byte4(Vector4.UnitY * 255).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitZ * 255, new Byte4(Vector4.UnitZ * 255).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitW * 255, new Byte4(Vector4.UnitW * 255).ToVector4())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4())); |
|||
Assert.True(Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4())); |
|||
|
|||
// Test ordering
|
|||
float x = 0x2d; |
|||
float y = 0x36; |
|||
float z = 0x7b; |
|||
float w = 0x1a; |
|||
Assert.Equal((uint)0x1a7b362d, new Byte4(x, y, z, w).PackedValue); |
|||
|
|||
x = 127.5f; |
|||
y = -12.3f; |
|||
z = 0.5f; |
|||
w = -0.7f; |
|||
Assert.Equal((uint)128, new Byte4(x, y, z, w).PackedValue); |
|||
|
|||
// Test ordering
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Byte4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 128, 0, 0 }); |
|||
|
|||
new Byte4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 128, 0, 0, 0 }); |
|||
|
|||
new Byte4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 0, 128 }); |
|||
|
|||
new Byte4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void HalfSingle() |
|||
{ |
|||
// Test limits
|
|||
Assert.Equal(15360, new HalfSingle(1F).PackedValue); |
|||
Assert.Equal(0, new HalfSingle(0F).PackedValue); |
|||
Assert.Equal(48128, new HalfSingle(-1F).PackedValue); |
|||
|
|||
// Test values
|
|||
Assert.Equal(11878, new HalfSingle(0.1F).PackedValue); |
|||
Assert.Equal(46285, new HalfSingle(-0.3F).PackedValue); |
|||
|
|||
// Test ordering
|
|||
float x = .5F; |
|||
Assert.True(Equal(new Vector4(x, 0, 0, 1), new HalfSingle(x).ToVector4())); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new HalfSingle(x).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 128, 0, 0 }); |
|||
|
|||
new HalfSingle(x).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 128, 0, 0, 255 }); |
|||
|
|||
new HalfSingle(x).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 0, 128 }); |
|||
|
|||
new HalfSingle(x).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 0, 128, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void HalfVector2() |
|||
{ |
|||
// Test PackedValue
|
|||
Assert.Equal(0u, new HalfVector2(Vector2.Zero).PackedValue); |
|||
Assert.Equal(1006648320u, new HalfVector2(Vector2.One).PackedValue); |
|||
Assert.Equal(3033345638u, new HalfVector2(0.1f, -0.3f).PackedValue); |
|||
|
|||
// Test ToVector2
|
|||
Assert.True(Equal(Vector2.Zero, new HalfVector2(Vector2.Zero).ToVector2())); |
|||
Assert.True(Equal(Vector2.One, new HalfVector2(Vector2.One).ToVector2())); |
|||
Assert.True(Equal(Vector2.UnitX, new HalfVector2(Vector2.UnitX).ToVector2())); |
|||
Assert.True(Equal(Vector2.UnitY, new HalfVector2(Vector2.UnitY).ToVector2())); |
|||
|
|||
// Test ordering
|
|||
float x = .5F; |
|||
float y = .25F; |
|||
Assert.True(Equal(new Vector4(x, y, 0, 1), new HalfVector2(x, y).ToVector4())); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new HalfVector2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 128, 64, 0 }); |
|||
|
|||
new HalfVector2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 128, 64, 0, 255 }); |
|||
|
|||
new HalfVector2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 64, 128 }); |
|||
|
|||
new HalfVector2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 64, 128, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void HalfVector4() |
|||
{ |
|||
// Test PackedValue
|
|||
Assert.Equal(0uL, new HalfVector4(Vector4.Zero).PackedValue); |
|||
Assert.Equal(4323521613979991040uL, new HalfVector4(Vector4.One).PackedValue); |
|||
Assert.Equal(13547034390470638592uL, new HalfVector4(-Vector4.One).PackedValue); |
|||
Assert.Equal(15360uL, new HalfVector4(Vector4.UnitX).PackedValue); |
|||
Assert.Equal(1006632960uL, new HalfVector4(Vector4.UnitY).PackedValue); |
|||
Assert.Equal(65970697666560uL, new HalfVector4(Vector4.UnitZ).PackedValue); |
|||
Assert.Equal(4323455642275676160uL, new HalfVector4(Vector4.UnitW).PackedValue); |
|||
Assert.Equal(4035285078724390502uL, new HalfVector4(0.1f, 0.3f, 0.4f, 0.5f).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.Zero, new HalfVector4(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new HalfVector4(Vector4.One).ToVector4())); |
|||
Assert.True(Equal(-Vector4.One, new HalfVector4(-Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitX, new HalfVector4(Vector4.UnitX).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitY, new HalfVector4(Vector4.UnitY).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitZ, new HalfVector4(Vector4.UnitZ).ToVector4())); |
|||
Assert.True(Equal(Vector4.UnitW, new HalfVector4(Vector4.UnitW).ToVector4())); |
|||
|
|||
// Test ordering
|
|||
float x = .25F; |
|||
float y = .5F; |
|||
float z = .75F; |
|||
float w = 1F; |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new HalfVector4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 64, 128, 191 }); |
|||
|
|||
new HalfVector4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 64, 128, 191, 255 }); |
|||
|
|||
new HalfVector4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 191, 128, 64 }); |
|||
|
|||
new HalfVector4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 191, 128, 64, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizedByte2() |
|||
{ |
|||
// Test PackedValue
|
|||
Assert.Equal(0x0, new NormalizedByte2(Vector2.Zero).PackedValue); |
|||
Assert.Equal(0x7F7F, new NormalizedByte2(Vector2.One).PackedValue); |
|||
Assert.Equal(0x8181, new NormalizedByte2(-Vector2.One).PackedValue); |
|||
|
|||
// Test ToVector2
|
|||
Assert.True(Equal(Vector2.One, new NormalizedByte2(Vector2.One).ToVector2())); |
|||
Assert.True(Equal(Vector2.Zero, new NormalizedByte2(Vector2.Zero).ToVector2())); |
|||
Assert.True(Equal(-Vector2.One, new NormalizedByte2(-Vector2.One).ToVector2())); |
|||
Assert.True(Equal(Vector2.One, new NormalizedByte2(Vector2.One * 1234.0f).ToVector2())); |
|||
Assert.True(Equal(-Vector2.One, new NormalizedByte2(Vector2.One * -1234.0f).ToVector2())); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(new Vector4(1, 1, 0, 1), new NormalizedByte2(Vector2.One).ToVector4())); |
|||
Assert.True(Equal(new Vector4(0, 0, 0, 1), new NormalizedByte2(Vector2.Zero).ToVector4())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0.1f; |
|||
float y = -0.3f; |
|||
Assert.Equal(0xda0d, new NormalizedByte2(x, y).PackedValue); |
|||
NormalizedByte2 n = new NormalizedByte2(); |
|||
n.PackFromBytes(141, 90, 0, 0); |
|||
Assert.Equal(0xda0d, n.PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new NormalizedByte2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); |
|||
|
|||
new NormalizedByte2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 }); |
|||
|
|||
new NormalizedByte2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 90, 141 }); |
|||
|
|||
new NormalizedByte2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizedByte4() |
|||
{ |
|||
// Test PackedValue
|
|||
Assert.Equal((uint)0x0, new NormalizedByte4(Vector4.Zero).PackedValue); |
|||
Assert.Equal((uint)0x7F7F7F7F, new NormalizedByte4(Vector4.One).PackedValue); |
|||
Assert.Equal(0x81818181, new NormalizedByte4(-Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.One, new NormalizedByte4(Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.Zero, new NormalizedByte4(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(-Vector4.One, new NormalizedByte4(-Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new NormalizedByte4(Vector4.One * 1234.0f).ToVector4())); |
|||
Assert.True(Equal(-Vector4.One, new NormalizedByte4(Vector4.One * -1234.0f).ToVector4())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0.1f; |
|||
float y = -0.3f; |
|||
float z = 0.5f; |
|||
float w = -0.7f; |
|||
Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); |
|||
NormalizedByte4 n = new NormalizedByte4(); |
|||
n.PackFromBytes(141, 90, 192, 39); |
|||
Assert.Equal(0xA740DA0D, n.PackedValue); |
|||
|
|||
Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new NormalizedByte4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 141, 90, 192 }); |
|||
|
|||
new NormalizedByte4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 }); |
|||
|
|||
new NormalizedByte4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 192, 90, 141 }); |
|||
|
|||
new NormalizedByte4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 }); |
|||
|
|||
// http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8
|
|||
NormalizedByte4 r = new NormalizedByte4(); |
|||
r.PackFromBytes(9, 115, 202, 127); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); |
|||
|
|||
r.PackedValue = 0x7FCA7309; |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizedShort2() |
|||
{ |
|||
Assert.Equal((uint)0x0, new NormalizedShort2(Vector2.Zero).PackedValue); |
|||
Assert.Equal((uint)0x7FFF7FFF, new NormalizedShort2(Vector2.One).PackedValue); |
|||
Assert.Equal(0x80018001, new NormalizedShort2(-Vector2.One).PackedValue); |
|||
|
|||
Assert.True(Equal(Vector2.One, new NormalizedShort2(Vector2.One).ToVector2())); |
|||
Assert.True(Equal(Vector2.Zero, new NormalizedShort2(Vector2.Zero).ToVector2())); |
|||
Assert.True(Equal(-Vector2.One, new NormalizedShort2(-Vector2.One).ToVector2())); |
|||
Assert.True(Equal(Vector2.One, new NormalizedShort2(Vector2.One * 1234.0f).ToVector2())); |
|||
Assert.True(Equal(-Vector2.One, new NormalizedShort2(Vector2.One * -1234.0f).ToVector2())); |
|||
|
|||
Assert.True(Equal(new Vector4(1, 1, 0, 1), (new NormalizedShort2(Vector2.One)).ToVector4())); |
|||
Assert.True(Equal(new Vector4(0, 0, 0, 1), (new NormalizedShort2(Vector2.Zero)).ToVector4())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0.35f; |
|||
float y = -0.2f; |
|||
Assert.Equal(0xE6672CCC, new NormalizedShort2(x, y).PackedValue); |
|||
x = 0.1f; |
|||
y = -0.3f; |
|||
Assert.Equal(3650751693, new NormalizedShort2(x, y).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
NormalizedShort2 n = new NormalizedShort2(); |
|||
n.PackFromBytes(141, 90, 0, 0); |
|||
n.ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); |
|||
|
|||
// TODO: I don't think this can ever pass since the bytes are already truncated.
|
|||
// Assert.Equal(3650751693, n.PackedValue);
|
|||
|
|||
new NormalizedShort2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); |
|||
|
|||
new NormalizedShort2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 }); |
|||
|
|||
new NormalizedShort2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 90, 141 }); |
|||
|
|||
new NormalizedShort2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizedShort4() |
|||
{ |
|||
// Test PackedValue
|
|||
Assert.Equal((ulong)0x0, new NormalizedShort4(Vector4.Zero).PackedValue); |
|||
Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, new NormalizedShort4(Vector4.One).PackedValue); |
|||
Assert.Equal(0x8001800180018001, new NormalizedShort4(-Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.One, new NormalizedShort4(Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.Zero, new NormalizedShort4(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(-Vector4.One, new NormalizedShort4(-Vector4.One).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new NormalizedShort4(Vector4.One * 1234.0f).ToVector4())); |
|||
Assert.True(Equal(-Vector4.One, new NormalizedShort4(Vector4.One * -1234.0f).ToVector4())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0.1f; |
|||
float y = -0.3f; |
|||
float z = 0.5f; |
|||
float w = -0.7f; |
|||
Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); |
|||
Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new NormalizedShort4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 141, 90, 192 }); |
|||
|
|||
new NormalizedShort4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 }); |
|||
|
|||
new NormalizedShort4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 192, 90, 141 }); |
|||
|
|||
new NormalizedShort4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 }); |
|||
|
|||
NormalizedShort4 r = new NormalizedShort4(); |
|||
r.PackFromBytes(9, 115, 202, 127); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Rg32() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((uint)0x0, new Rg32(Vector2.Zero).PackedValue); |
|||
Assert.Equal(0xFFFFFFFF, new Rg32(Vector2.One).PackedValue); |
|||
|
|||
// Test ToVector2
|
|||
Assert.True(Equal(Vector2.Zero, new Rg32(Vector2.Zero).ToVector2())); |
|||
Assert.True(Equal(Vector2.One, new Rg32(Vector2.One).ToVector2())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2())); |
|||
Assert.True(Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0xb6dc; |
|||
float y = 0xA59f; |
|||
Assert.Equal(0xa59fb6dc, new Rg32(x / 0xffff, y / 0xffff).PackedValue); |
|||
x = 0.1f; |
|||
y = -0.3f; |
|||
Assert.Equal((uint)6554, new Rg32(x, y).PackedValue); |
|||
|
|||
// Test ordering
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Rg32(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 25, 0, 0 }); |
|||
|
|||
new Rg32(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 25, 0, 0, 255 }); |
|||
|
|||
new Rg32(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 0, 25 }); |
|||
|
|||
new Rg32(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 0, 25, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Rgba1010102() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((uint)0x0, new Rgba1010102(Vector4.Zero).PackedValue); |
|||
Assert.Equal(0xFFFFFFFF, new Rgba1010102(Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.Zero, new Rgba1010102(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Rgba1010102(Vector4.One).ToVector4())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector4.Zero, new Rgba1010102(Vector4.One * -1234.0f).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4())); |
|||
|
|||
// Test Ordering
|
|||
float x = 0x2db; |
|||
float y = 0x36d; |
|||
float z = 0x3b7; |
|||
float w = 0x1; |
|||
Assert.Equal((uint)0x7B7DB6DB, new Rgba1010102(x / 0x3ff, y / 0x3ff, z / 0x3ff, w / 3).PackedValue); |
|||
x = 0.1f; |
|||
y = -0.3f; |
|||
z = 0.5f; |
|||
w = -0.7f; |
|||
Assert.Equal((uint)536871014, new Rgba1010102(x, y, z, w).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Rgba1010102(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 25, 0, 128 }); |
|||
|
|||
new Rgba1010102(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); |
|||
|
|||
new Rgba1010102(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 128, 0, 25 }); |
|||
|
|||
new Rgba1010102(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 128, 0, 25, 0 }); |
|||
|
|||
// Alpha component accuracy will be awful.
|
|||
Rgba1010102 r = new Rgba1010102(); |
|||
r.PackFromBytes(25, 0, 128, 0); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Rgba64() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); |
|||
Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue); |
|||
|
|||
// Test ToVector4
|
|||
Assert.True(Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4())); |
|||
Assert.True(Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4())); |
|||
|
|||
// Test data ordering
|
|||
Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(((float)0x1EB8) / 0xffff, ((float)0x570A) / 0xffff, ((float)0x8F5C) / 0xffff, ((float)0xC7AD) / 0xffff).PackedValue); |
|||
Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0.12f, 0.34f, 0.56f, 0.78f).PackedValue); |
|||
|
|||
float x = 0.08f; |
|||
float y = 0.15f; |
|||
float z = 0.30f; |
|||
float w = 0.45f; |
|||
Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(x, y, z, w).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Rgba64(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 20, 38, 76 }); |
|||
|
|||
new Rgba64(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 }); |
|||
|
|||
new Rgba64(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 76, 38, 20 }); |
|||
|
|||
new Rgba64(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 76, 38, 20, 115 }); |
|||
|
|||
Rgba64 r = new Rgba64(); |
|||
r.PackFromBytes(20, 38, 76, 115); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Short2() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((uint)0x0, new Short2(Vector2.Zero).PackedValue); |
|||
Assert.Equal((uint)0x7FFF7FFF, new Short2(Vector2.One * 0x7FFF).PackedValue); |
|||
Assert.Equal(0x80008000, new Short2(Vector2.One * -0x8000).PackedValue); |
|||
|
|||
// Test ToVector2.
|
|||
Assert.True(Equal(Vector2.One * 0x7FFF, new Short2(Vector2.One * 0x7FFF).ToVector2())); |
|||
Assert.True(Equal(Vector2.Zero, new Short2(Vector2.Zero).ToVector2())); |
|||
Assert.True(Equal(Vector2.One * -0x8000, new Short2(Vector2.One * -0x8000).ToVector2())); |
|||
Assert.True(Equal(Vector2.UnitX * 0x7FFF, new Short2(Vector2.UnitX * 0x7FFF).ToVector2())); |
|||
Assert.True(Equal(Vector2.UnitY * 0x7FFF, new Short2(Vector2.UnitY * 0x7FFF).ToVector2())); |
|||
|
|||
// Test clamping.
|
|||
Assert.True(Equal(Vector2.One * 0x7FFF, new Short2(Vector2.One * 1234567.0f).ToVector2())); |
|||
Assert.True(Equal(Vector2.One * -0x8000, new Short2(Vector2.One * -1234567.0f).ToVector2())); |
|||
|
|||
// Test ToVector4.
|
|||
Assert.True(Equal(new Vector4(0x7FFF, 0x7FFF, 0, 1), (new Short2(Vector2.One * 0x7FFF)).ToVector4())); |
|||
Assert.True(Equal(new Vector4(0, 0, 0, 1), (new Short2(Vector2.Zero)).ToVector4())); |
|||
Assert.True(Equal(new Vector4(-0x8000, -0x8000, 0, 1), (new Short2(Vector2.One * -0x8000)).ToVector4())); |
|||
|
|||
// Test ordering
|
|||
float x = 0x2db1; |
|||
float y = 0x361d; |
|||
Assert.Equal((uint)0x361d2db1, new Short2(x, y).PackedValue); |
|||
x = 127.5f; |
|||
y = -5.3f; |
|||
Assert.Equal(4294639744, new Short2(x, y).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Short2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 128, 127, 0 }); |
|||
|
|||
new Short2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 128, 127, 0, 255 }); |
|||
|
|||
new Short2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 0, 127, 128 }); |
|||
|
|||
new Short2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 0, 127, 128, 255 }); |
|||
|
|||
Short2 r = new Short2(); |
|||
r.PackFromBytes(20, 38, 0, 255); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Short4() |
|||
{ |
|||
// Test the limits.
|
|||
Assert.Equal((ulong)0x0, new Short4(Vector4.Zero).PackedValue); |
|||
Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, new Short4(Vector4.One * 0x7FFF).PackedValue); |
|||
Assert.Equal(0x8000800080008000, new Short4(Vector4.One * -0x8000).PackedValue); |
|||
|
|||
// Test ToVector4.
|
|||
Assert.Equal(Vector4.One * 0x7FFF, new Short4(Vector4.One * 0x7FFF).ToVector4()); |
|||
Assert.Equal(Vector4.Zero, new Short4(Vector4.Zero).ToVector4()); |
|||
Assert.Equal(Vector4.One * -0x8000, new Short4(Vector4.One * -0x8000).ToVector4()); |
|||
Assert.Equal(Vector4.UnitX * 0x7FFF, new Short4(Vector4.UnitX * 0x7FFF).ToVector4()); |
|||
Assert.Equal(Vector4.UnitY * 0x7FFF, new Short4(Vector4.UnitY * 0x7FFF).ToVector4()); |
|||
Assert.Equal(Vector4.UnitZ * 0x7FFF, new Short4(Vector4.UnitZ * 0x7FFF).ToVector4()); |
|||
Assert.Equal(Vector4.UnitW * 0x7FFF, new Short4(Vector4.UnitW * 0x7FFF).ToVector4()); |
|||
|
|||
// Test clamping.
|
|||
Assert.Equal(Vector4.One * 0x7FFF, new Short4(Vector4.One * 1234567.0f).ToVector4()); |
|||
Assert.Equal(Vector4.One * -0x8000, new Short4(Vector4.One * -1234567.0f).ToVector4()); |
|||
|
|||
// Test Ordering
|
|||
float x = 0.1f; |
|||
float y = -0.3f; |
|||
float z = 0.5f; |
|||
float w = -0.7f; |
|||
Assert.Equal(18446462598732840960, new Short4(x, y, z, w).PackedValue); |
|||
|
|||
x = 11547; |
|||
y = 12653; |
|||
z = 29623; |
|||
w = 193; |
|||
Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue); |
|||
|
|||
byte[] rgb = new byte[3]; |
|||
byte[] rgba = new byte[4]; |
|||
byte[] bgr = new byte[3]; |
|||
byte[] bgra = new byte[4]; |
|||
|
|||
new Short4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); |
|||
Assert.Equal(rgb, new byte[] { 172, 177, 243 }); |
|||
|
|||
new Short4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 172, 177, 243, 128 }); |
|||
|
|||
new Short4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); |
|||
Assert.Equal(bgr, new byte[] { 243, 177, 172 }); |
|||
|
|||
new Short4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); |
|||
Assert.Equal(bgra, new byte[] { 243, 177, 172, 128 }); |
|||
|
|||
Short4 r = new Short4(); |
|||
r.PackFromBytes(20, 38, 0, 255); |
|||
r.ToBytes(rgba, 0, ComponentOrder.XYZW); |
|||
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); |
|||
} |
|||
|
|||
// Comparison helpers with small tolerance to allow for floating point rounding during computations.
|
|||
public static bool Equal(float a, float b) |
|||
{ |
|||
return Math.Abs(a - b) < 1e-5; |
|||
} |
|||
|
|||
public static bool Equal(Vector2 a, Vector2 b) |
|||
{ |
|||
return Equal(a.X, b.X) && Equal(a.Y, b.Y); |
|||
} |
|||
|
|||
public static bool Equal(Vector3 a, Vector3 b) |
|||
{ |
|||
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z); |
|||
} |
|||
|
|||
public static bool Equal(Vector4 a, Vector4 b) |
|||
{ |
|||
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue