184 lines
5.4 KiB
C#
Executable File
184 lines
5.4 KiB
C#
Executable File
/*
|
|
* Copyright (c) 2018 Stanislav Denisov
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
#if !(ENABLE_MONO || ENABLE_IL2CPP)
|
|
using System.Numerics;
|
|
#else
|
|
using UnityEngine;
|
|
#endif
|
|
|
|
namespace NetStack.Quantization {
|
|
public struct QuantizedVector2 {
|
|
public uint x;
|
|
public uint y;
|
|
|
|
public QuantizedVector2(uint x, uint y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
}
|
|
|
|
public struct QuantizedVector3 {
|
|
public uint x;
|
|
public uint y;
|
|
public uint z;
|
|
|
|
public QuantizedVector3(uint x, uint y, uint z) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
}
|
|
}
|
|
|
|
public struct QuantizedVector4 {
|
|
public uint x;
|
|
public uint y;
|
|
public uint z;
|
|
public uint w;
|
|
|
|
public QuantizedVector4(uint x, uint y, uint z, uint w) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
this.w = w;
|
|
}
|
|
}
|
|
|
|
public static class DeBruijn {
|
|
public static readonly int[] Lookup = new int[32] {
|
|
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
|
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
|
};
|
|
}
|
|
|
|
public class BoundedRange {
|
|
private readonly float minValue;
|
|
private readonly float maxValue;
|
|
private readonly float precision;
|
|
private readonly int requiredBits;
|
|
private readonly uint mask;
|
|
|
|
public BoundedRange(float minValue, float maxValue, float precision) {
|
|
this.minValue = minValue;
|
|
this.maxValue = maxValue;
|
|
this.precision = precision;
|
|
|
|
requiredBits = Log2((uint)((maxValue - minValue) * (1.0f / precision) + 0.5f)) + 1;
|
|
mask = (uint)((1L << requiredBits) - 1);
|
|
}
|
|
|
|
private int Log2(uint value) {
|
|
value |= value >> 1;
|
|
value |= value >> 2;
|
|
value |= value >> 4;
|
|
value |= value >> 8;
|
|
value |= value >> 16;
|
|
|
|
return DeBruijn.Lookup[(value * 0x07C4ACDDU) >> 27];
|
|
}
|
|
|
|
[MethodImpl(256)]
|
|
public uint Quantize(float value) {
|
|
if (value < minValue)
|
|
value = minValue;
|
|
else if (value > maxValue)
|
|
value = maxValue;
|
|
|
|
return (uint)((float)((value - minValue) * (1f / precision)) + 0.5f) & mask;
|
|
}
|
|
|
|
[MethodImpl(256)]
|
|
public float Dequantize(uint data) {
|
|
float adjusted = ((float)data * precision) + minValue;
|
|
|
|
if (adjusted < minValue)
|
|
adjusted = minValue;
|
|
else if (adjusted > maxValue)
|
|
adjusted = maxValue;
|
|
|
|
return adjusted;
|
|
}
|
|
|
|
public static QuantizedVector2 Quantize(Vector2 vector2, BoundedRange[] boundedRange) {
|
|
QuantizedVector2 data = default(QuantizedVector2);
|
|
|
|
#if ENABLE_MONO || ENABLE_IL2CPP
|
|
data.x = boundedRange[0].Quantize(vector2.x);
|
|
data.y = boundedRange[1].Quantize(vector2.y);
|
|
#else
|
|
data.x = boundedRange[0].Quantize(vector2.X);
|
|
data.y = boundedRange[1].Quantize(vector2.Y);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
public static QuantizedVector3 Quantize(Vector3 vector3, BoundedRange[] boundedRange) {
|
|
QuantizedVector3 data = default(QuantizedVector3);
|
|
|
|
#if ENABLE_MONO || ENABLE_IL2CPP
|
|
data.x = boundedRange[0].Quantize(vector3.x);
|
|
data.y = boundedRange[1].Quantize(vector3.y);
|
|
data.z = boundedRange[2].Quantize(vector3.z);
|
|
#else
|
|
data.x = boundedRange[0].Quantize(vector3.X);
|
|
data.y = boundedRange[1].Quantize(vector3.Y);
|
|
data.z = boundedRange[2].Quantize(vector3.Z);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
public static QuantizedVector4 Quantize(Vector4 vector4, BoundedRange[] boundedRange) {
|
|
QuantizedVector4 data = default(QuantizedVector4);
|
|
|
|
#if ENABLE_MONO || ENABLE_IL2CPP
|
|
data.x = boundedRange[0].Quantize(vector4.x);
|
|
data.y = boundedRange[1].Quantize(vector4.y);
|
|
data.z = boundedRange[2].Quantize(vector4.z);
|
|
data.w = boundedRange[3].Quantize(vector4.w);
|
|
#else
|
|
data.x = boundedRange[0].Quantize(vector4.X);
|
|
data.y = boundedRange[1].Quantize(vector4.Y);
|
|
data.z = boundedRange[2].Quantize(vector4.Z);
|
|
data.w = boundedRange[3].Quantize(vector4.W);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
public static Vector2 Dequantize(QuantizedVector2 data, BoundedRange[] boundedRange) {
|
|
return new Vector2(boundedRange[0].Dequantize(data.x), boundedRange[1].Dequantize(data.y));
|
|
}
|
|
|
|
public static Vector3 Dequantize(QuantizedVector3 data, BoundedRange[] boundedRange) {
|
|
return new Vector3(boundedRange[0].Dequantize(data.x), boundedRange[1].Dequantize(data.y), boundedRange[2].Dequantize(data.z));
|
|
}
|
|
|
|
public static Vector4 Dequantize(QuantizedVector4 data, BoundedRange[] boundedRange) {
|
|
return new Vector4(boundedRange[0].Dequantize(data.x), boundedRange[1].Dequantize(data.y), boundedRange[2].Dequantize(data.z), boundedRange[3].Dequantize(data.w));
|
|
}
|
|
}
|
|
} |