Last active
May 19, 2021 17:49
-
-
Save StagPoint/89c0bd378f446c843de79d946906ce96 to your computer and use it in GitHub Desktop.
Convert between floating point and integral types in C# / Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2016 StagPoint Software | |
// NOTE: C#-style unions (structs using FieldOffset to cause multiple fields to 'overlap' in memory) may not be allowed on | |
// some IL2CPP platforms? If you get a compile error related to using FieldOffset on your target platform, comment the | |
// following #define to force this code to use another method. | |
// | |
// The UnityEngine.Networking code on BitBucket uses (#if !INCLUDE_IL2CPP) to control whether to use unions, but that code | |
// may be out of date (Unity has so far failed to respond), but testing confirms that this method does work on at least one | |
// of the IL2CPP target platforms, so we've chosen a more explicit #define instead. | |
#define USE_UNION_FOR_CONVERSION | |
// If unions don't work on your target platform, the next best option is to use 'unsafe' code - https://msdn.microsoft.com/en-us/library/t2yzs44b.aspx | |
// If unsafe code is allowed on your target platform, you can allow unsafe code in Unity by following this link - http://answers.unity3d.com/answers/804152/view.html | |
// Once you have enabled Unity to use unsafe code, uncomment the following #define | |
//#define ALLOW_UNSAFE | |
namespace StagPoint.HoverNet | |
{ | |
using System; | |
using System.Runtime.InteropServices; | |
public static class FloatConversion | |
{ | |
#if USE_UNION_FOR_CONVERSION | |
public static uint ToInt32( float value ) | |
{ | |
var uf = new IntegerFloatUnion() { floatValue = value }; | |
return uf.intValue; | |
} | |
public static ulong ToInt64( double value ) | |
{ | |
var uf = new IntegerFloatUnion() { doubleValue = value }; | |
return uf.longValue; | |
} | |
public static float ToSingle( uint value ) | |
{ | |
var uf = new IntegerFloatUnion() { intValue = value }; | |
return uf.floatValue; | |
} | |
public static double ToDouble( ulong value ) | |
{ | |
var uf = new IntegerFloatUnion() { longValue = value }; | |
return uf.doubleValue; | |
} | |
/// <summary> | |
/// C#-style union used to convert between floating point and integral types, as an alternative to unsafe code. | |
/// This cannot be used with IL2CPP because the version of IL2CPP used by Unity does not convert FieldOffset, | |
/// or at least this is suggested in the Unity.Networking code available on BitBucket. | |
/// </summary> | |
[StructLayout( LayoutKind.Explicit )] | |
internal struct IntegerFloatUnion | |
{ | |
[FieldOffset( 0 )] | |
public float floatValue; | |
[FieldOffset( 0 )] | |
public uint intValue; | |
[FieldOffset( 0 )] | |
public double doubleValue; | |
[FieldOffset( 0 )] | |
public ulong longValue; | |
} | |
#elif ALLOW_UNSAFE | |
public static unsafe float ToSingle( uint value ) | |
{ | |
return *(float*)&value; | |
} | |
public static unsafe double ToDouble( ulong value ) | |
{ | |
return *(double*)&value; | |
} | |
public static unsafe uint ToInt32( float value ) | |
{ | |
return *(uint*)&value; | |
} | |
public static unsafe ulong ToInt64( double value ) | |
{ | |
return *(ulong*)&value; | |
} | |
#else // Cannot use unions, and ALLOW_UNSAFE is not defined. There is no choice but to allocate memory each time a value is converted. | |
#warning "Converting between floating point types and integral types for network transmission causes memory allocations on IL2CPP platforms due to limitations in IL2CPP" | |
public static float ToSingle( uint value ) | |
{ | |
return BitConverter.ToSingle( BitConverter.GetBytes( value ), 0 ); | |
} | |
public static double ToDouble( ulong value ) | |
{ | |
return BitConverter.ToDouble( BitConverter.GetBytes( value ), 0 ); | |
} | |
public static uint ToInt32( float value ) | |
{ | |
return BitConverter.ToUInt32( BitConverter.GetBytes( value ), 0 ); | |
} | |
public static ulong ToInt64( double value ) | |
{ | |
return BitConverter.ToUInt64( BitConverter.GetBytes( value ), 0 ); | |
} | |
#endif | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@benzsuankularb sorry for the very late reply, didn't realize that I would not get notifications for comments....
You would have to define ALLOW_UNSAFE yourself, there is no system define for it. You can just comment out line 10 and uncomment line 15.
For what it's worth for everyone else reading this, I always use the "unsafe" option personally, and the only reason that it's not the default in the code is because Unity makes it a bit of a pain to enable unsafe and that isn't the default option.