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