/// <summary> /// Compress position to integers and push it to the buffer, required bytes count: <see cref="PositionRequiredBytes"/> /// </summary> /// <param name="bytesStack">Buffer where position will be pushed</param> /// <param name="position">Position to be compressed and pushed</param> public static void PushCompressedPosition(this BytesStack bytesStack, Vector3 position) { //Reverse order when writing to stack //Always use little-endian so compression and decompression are machines independent var z = CompressPositionZ(position.z); if (!BitConverter.IsLittleEndian) { z = SwapEndianness(z); } bytesStack.PushInt(z, PositionZRequiredBytes); var y = CompressPositionY(position.y); if (!BitConverter.IsLittleEndian) { y = SwapEndianness(y); } bytesStack.PushInt(y, PositionYRequiredBytes); var x = CompressPositionX(position.x); if (!BitConverter.IsLittleEndian) { x = SwapEndianness(x); } bytesStack.PushInt(x, PositionXRequiredBytes); }
/// <summary> /// Compress vector3 to integers and push it to the buffer /// </summary> /// <param name="bytesStack">Buffer where vector3 will be pushed</param> /// <param name="vector3">Vector3 to be compressed and pushed</param> /// <param name="minElementValue">Minimal value of the encoded vector3</param> /// <param name="maxElementValue">Maximal value of the encoded vector3</param> /// <param name="bytesPerElement">Bytes count that will be used per each element</param> public static void PushCompressedVector3(this BytesStack bytesStack, Vector3 vector3, float minElementValue, float maxElementValue, int bytesPerElement) { //Reverse order when writing to stack //Always use little-endian so compression and decompression are machines independent var z = CompressFloatToInt(vector3.z, minElementValue, maxElementValue, bytesPerElement); if (!BitConverter.IsLittleEndian) { z = SwapEndianness(z); } bytesStack.PushInt(z, bytesPerElement); var y = CompressFloatToInt(vector3.y, minElementValue, maxElementValue, bytesPerElement); if (!BitConverter.IsLittleEndian) { y = SwapEndianness(y); } bytesStack.PushInt(y, bytesPerElement); var x = CompressFloatToInt(vector3.x, minElementValue, maxElementValue, bytesPerElement); if (!BitConverter.IsLittleEndian) { x = SwapEndianness(x); } bytesStack.PushInt(x, bytesPerElement); }
/// <summary> /// Compress color to integers and push it to the buffer /// </summary> /// <param name="bytesStack">Buffer where color will be pushed</param> /// <param name="color">Color to be compressed and pushed</param> /// <param name="bytesPerElement">Bytes count that will be used per each element</param> public static void PushCompressedColor(this BytesStack bytesStack, Color color, int bytesPerElement) { //Reverse order when writing to stack //Always use little-endian so compression and decompression are machines independent var a = CompressFloatToInt(color.a, 0.0f, 1.0f, bytesPerElement); if (!BitConverter.IsLittleEndian) { a = SwapEndianness(a); } bytesStack.PushInt(a, bytesPerElement); var b = CompressFloatToInt(color.b, 0.0f, 1.0f, bytesPerElement); if (!BitConverter.IsLittleEndian) { b = SwapEndianness(b); } bytesStack.PushInt(b, bytesPerElement); var g = CompressFloatToInt(color.g, 0.0f, 1.0f, bytesPerElement); if (!BitConverter.IsLittleEndian) { g = SwapEndianness(g); } bytesStack.PushInt(g, bytesPerElement); var r = CompressFloatToInt(color.r, 0.0f, 1.0f, bytesPerElement); if (!BitConverter.IsLittleEndian) { r = SwapEndianness(r); } bytesStack.PushInt(r, bytesPerElement); }
/// <summary> /// Compress rotation to integers and push it to the buffer, required bytes count: <see cref="RotationPrecision"/> /// </summary> /// <param name="bytesStack">Buffer where rotation will be pushed</param> /// <param name="rotation">Rotation to be compressed and pushed</param> public static void PushCompressedRotation(this BytesStack bytesStack, Quaternion rotation) { //Algorithm based on the "smallest three" method described at: //http://gafferongames.com/networked-physics/snapshot-compression/ var maxIndex = (byte)0; var maxValue = float.MinValue; var sign = 1f; // Find the maximum element in the quaternion for (var i = 0; i < 4; i++) { var element = rotation[i]; var abs = Mathf.Abs(rotation[i]); if (!(abs > maxValue)) { continue; } // Maximum element is always compressed as positive, all other elements are negated if needed sign = (element < 0) ? -1 : 1; maxIndex = (byte)i; maxValue = abs; } // If the maximum element is approximately equal to 1.0f all other elements are approximately equal to 0.0f and does not have to be encoded if (Mathf.Approximately(maxValue, 1.0f)) { //Use 4-7 indexes to determine which element is maximum and it is approximately equal to 1.0f bytesStack.PushInt(maxIndex + 4, 1); return; } //Reverse order when writing to stack // Compress and encode only smallest three Quaternion components as little endian integers if (maxIndex != 3) { var w = CompressFloatToInt(rotation.w * sign, -1.0f, 1.0f, DefaultBytesForCompressedFloat); if (!BitConverter.IsLittleEndian) { w = SwapEndianness(w); } bytesStack.PushInt(w, DefaultBytesForCompressedFloat); } if (maxIndex != 2) { var z = CompressFloatToInt(rotation.z * sign, -1.0f, 1.0f, DefaultBytesForCompressedFloat); if (!BitConverter.IsLittleEndian) { z = SwapEndianness(z); } bytesStack.PushInt(z, DefaultBytesForCompressedFloat); } if (maxIndex != 1) { var y = CompressFloatToInt(rotation.y * sign, -1.0f, 1.0f, DefaultBytesForCompressedFloat); if (!BitConverter.IsLittleEndian) { y = SwapEndianness(y); } bytesStack.PushInt(y, DefaultBytesForCompressedFloat); } if (maxIndex != 0) { var x = CompressFloatToInt(rotation.x * sign, -1.0f, 1.0f, DefaultBytesForCompressedFloat); if (!BitConverter.IsLittleEndian) { x = SwapEndianness(x); } bytesStack.PushInt(x, DefaultBytesForCompressedFloat); } bytesStack.PushInt(BitConverter.IsLittleEndian ? maxIndex : SwapEndianness(maxIndex), 1); }
/// <summary> /// Pushes the enum integer value with minimum required bytes /// </summary> /// <param name="bytesStack">Buffer where enum is pushed</param> /// <param name="intValue">Enum value casted to integer</param> /// <typeparam name="T">Enum type</typeparam> public static void PushEnum <T>(this BytesStack bytesStack, int intValue) where T : IComparable, IConvertible, IFormattable { bytesStack.PushInt(intValue, RequiredBytes <T>()); }