forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			164 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
 | 
						|
using System;
 | 
						|
using UnityEngine;
 | 
						|
 | 
						|
namespace FishNet.Serializing.Helping
 | 
						|
{
 | 
						|
    public static class Quaternion32Compression
 | 
						|
    {
 | 
						|
        private const float Maximum = +1.0f / 1.414214f;
 | 
						|
 | 
						|
        private const int BitsPerAxis = 10;
 | 
						|
        private const int LargestComponentShift = BitsPerAxis * 3;
 | 
						|
        private const int AShift = BitsPerAxis * 2;
 | 
						|
        private const int BShift = BitsPerAxis * 1;
 | 
						|
        private const int IntScale = (1 << (BitsPerAxis - 1)) - 1;
 | 
						|
        private const int IntMask = (1 << BitsPerAxis) - 1;
 | 
						|
 | 
						|
        public static uint Compress(Quaternion quaternion)
 | 
						|
        {
 | 
						|
            float absX = Mathf.Abs(quaternion.x);
 | 
						|
            float absY = Mathf.Abs(quaternion.y);
 | 
						|
            float absZ = Mathf.Abs(quaternion.z);
 | 
						|
            float absW = Mathf.Abs(quaternion.w);
 | 
						|
 | 
						|
            ComponentType largestComponent = ComponentType.X;
 | 
						|
            float largestAbs = absX;
 | 
						|
            float largest = quaternion.x;
 | 
						|
            
 | 
						|
            if (absY > largestAbs)
 | 
						|
            {
 | 
						|
                largestAbs = absY;
 | 
						|
                largestComponent = ComponentType.Y;
 | 
						|
                largest = quaternion.y;
 | 
						|
            }
 | 
						|
            if (absZ > largestAbs)
 | 
						|
            {
 | 
						|
                largestAbs = absZ;
 | 
						|
                largestComponent = ComponentType.Z;
 | 
						|
                largest = quaternion.z;
 | 
						|
            }
 | 
						|
            if (absW > largestAbs)
 | 
						|
            {
 | 
						|
                largestComponent = ComponentType.W;
 | 
						|
                largest = quaternion.w;
 | 
						|
            }
 | 
						|
 | 
						|
            float a = 0;
 | 
						|
            float b = 0;
 | 
						|
            float c = 0;
 | 
						|
            switch (largestComponent)
 | 
						|
            {
 | 
						|
                case ComponentType.X:
 | 
						|
                    a = quaternion.y;
 | 
						|
                    b = quaternion.z;
 | 
						|
                    c = quaternion.w;
 | 
						|
                    break;
 | 
						|
                case ComponentType.Y:
 | 
						|
                    a = quaternion.x;
 | 
						|
                    b = quaternion.z;
 | 
						|
                    c = quaternion.w;
 | 
						|
                    break;
 | 
						|
                case ComponentType.Z:
 | 
						|
                    a = quaternion.x;
 | 
						|
                    b = quaternion.y;
 | 
						|
                    c = quaternion.w;
 | 
						|
                    break;
 | 
						|
                case ComponentType.W:
 | 
						|
                    a = quaternion.x;
 | 
						|
                    b = quaternion.y;
 | 
						|
                    c = quaternion.z;
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
 | 
						|
            if (largest < 0)
 | 
						|
            {
 | 
						|
                a = -a;
 | 
						|
                b = -b;
 | 
						|
                c = -c;
 | 
						|
            }
 | 
						|
 | 
						|
            uint integerA = ScaleToUint(a);
 | 
						|
            uint integerB = ScaleToUint(b);
 | 
						|
            uint integerC = ScaleToUint(c);
 | 
						|
 | 
						|
            return (((uint)largestComponent) << LargestComponentShift) | (integerA << AShift) | (integerB << BShift) | integerC;
 | 
						|
        }
 | 
						|
 | 
						|
        private static uint ScaleToUint(float v)
 | 
						|
        {
 | 
						|
            float normalized = v / Maximum;
 | 
						|
            return (uint)Mathf.RoundToInt(normalized * IntScale) & IntMask;
 | 
						|
        }
 | 
						|
 | 
						|
        private static float ScaleToFloat(uint v)
 | 
						|
        {
 | 
						|
            float unscaled = v * Maximum / IntScale;
 | 
						|
 | 
						|
            if (unscaled > Maximum)
 | 
						|
                unscaled -= Maximum * 2;
 | 
						|
            return unscaled;
 | 
						|
        }
 | 
						|
 | 
						|
        public static Quaternion Decompress(uint compressed)
 | 
						|
        {
 | 
						|
            var largestComponentType = (ComponentType)(compressed >> LargestComponentShift);
 | 
						|
            uint integerA = (compressed >> AShift) & IntMask;
 | 
						|
            uint integerB = (compressed >> BShift) & IntMask;
 | 
						|
            uint integerC = compressed & IntMask;
 | 
						|
 | 
						|
            float a = ScaleToFloat(integerA);
 | 
						|
            float b = ScaleToFloat(integerB);
 | 
						|
            float c = ScaleToFloat(integerC);
 | 
						|
 | 
						|
            Quaternion rotation;
 | 
						|
            switch (largestComponentType)
 | 
						|
            {
 | 
						|
                case ComponentType.X:
 | 
						|
                    // (?) y z w
 | 
						|
                    rotation.y = a;
 | 
						|
                    rotation.z = b;
 | 
						|
                    rotation.w = c;
 | 
						|
                    rotation.x = Mathf.Sqrt(1 - rotation.y * rotation.y
 | 
						|
                                               - rotation.z * rotation.z
 | 
						|
                                               - rotation.w * rotation.w);
 | 
						|
                    break;
 | 
						|
                case ComponentType.Y:
 | 
						|
                    // x (?) z w
 | 
						|
                    rotation.x = a;
 | 
						|
                    rotation.z = b;
 | 
						|
                    rotation.w = c;
 | 
						|
                    rotation.y = Mathf.Sqrt(1 - rotation.x * rotation.x
 | 
						|
                                               - rotation.z * rotation.z
 | 
						|
                                               - rotation.w * rotation.w);
 | 
						|
                    break;
 | 
						|
                case ComponentType.Z:
 | 
						|
                    // x y (?) w
 | 
						|
                    rotation.x = a;
 | 
						|
                    rotation.y = b;
 | 
						|
                    rotation.w = c;
 | 
						|
                    rotation.z = Mathf.Sqrt(1 - rotation.x * rotation.x
 | 
						|
                                               - rotation.y * rotation.y
 | 
						|
                                               - rotation.w * rotation.w);
 | 
						|
                    break;
 | 
						|
                case ComponentType.W:
 | 
						|
                    // x y z (?)
 | 
						|
                    rotation.x = a;
 | 
						|
                    rotation.y = b;
 | 
						|
                    rotation.z = c;
 | 
						|
                    rotation.w = Mathf.Sqrt(1 - rotation.x * rotation.x
 | 
						|
                                               - rotation.y * rotation.y
 | 
						|
                                               - rotation.z * rotation.z);
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    // Should never happen!
 | 
						|
                    throw new ArgumentOutOfRangeException("Unknown rotation component type: " +
 | 
						|
                                                          largestComponentType);
 | 
						|
            }
 | 
						|
 | 
						|
            return rotation;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
}
 |