Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
HalfUtils.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under MIT License. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2011 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 using System.Runtime.InteropServices;
24 
25 namespace SiliconStudio.Core.Mathematics
26 {
27  /// <summary>
28  /// Helper class to perform Half/Float conversion.
29  /// Code extract from paper : www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf by Jeroen van der Zijp
30  /// </summary>
31  internal class HalfUtils
32  {
33 
34  [StructLayout(LayoutKind.Explicit, Pack = 4)]
35  private struct FloatToUint
36  {
37  [FieldOffset(0)]
38  public uint uintValue;
39  [FieldOffset(0)]
40  public float floatValue;
41  }
42 
43  /// <summary>
44  /// Unpacks the specified h.
45  /// </summary>
46  /// <param name="h">The h.</param>
47  /// <returns></returns>
48  public static float Unpack(ushort h)
49  {
50  var conv = new FloatToUint();
51  conv.uintValue = HalfToFloatMantissaTable[HalfToFloatOffsetTable[h >> 10] + (((uint)h) & 0x3ff)] + HalfToFloatExponentTable[h >> 10];
52  return conv.floatValue;
53  }
54 
55  /// <summary>
56  /// Packs the specified f.
57  /// </summary>
58  /// <param name="f">The f.</param>
59  /// <returns></returns>
60  public static ushort Pack(float f)
61  {
62  FloatToUint conv = new FloatToUint();
63  conv.floatValue = f;
64  return (ushort)(FloatToHalfBaseTable[(conv.uintValue >> 23) & 0x1ff] + ((conv.uintValue & 0x007fffff) >> FloatToHalfShiftTable[(conv.uintValue >> 23) & 0x1ff]));
65  }
66 
67  static readonly uint[] HalfToFloatMantissaTable = new uint[2048];
68  static readonly uint[] HalfToFloatExponentTable = new uint[64];
69  static readonly uint[] HalfToFloatOffsetTable = new uint[64];
70  static readonly ushort[] FloatToHalfBaseTable = new ushort[512];
71  static readonly byte[] FloatToHalfShiftTable = new byte[512];
72 
73  static HalfUtils()
74  {
75  int i;
76 
77  // -------------------------------------------------------------------
78  // Half to Float tables
79  // -------------------------------------------------------------------
80 
81  // Mantissa table
82 
83  // 0 => 0
84  HalfToFloatMantissaTable[0] = 0;
85 
86  // Transform subnormal to normalized
87  for (i = 1; i < 1024; i++)
88  {
89  uint m = ((uint)i) << 13;
90  uint e = 0;
91 
92  while ((m & 0x00800000) == 0)
93  {
94  e -= 0x00800000;
95  m <<= 1;
96  }
97  m &= ~ 0x00800000U;
98  e += 0x38800000;
99  HalfToFloatMantissaTable[i] = m | e;
100  }
101 
102  // Normal case
103  for (i = 1024; i < 2048; i++)
104  HalfToFloatMantissaTable[i] = 0x38000000 + (((uint)(i - 1024)) << 13);
105 
106  // Exponent table
107 
108  // 0 => 0
109  HalfToFloatExponentTable[0] = 0;
110 
111  for (i = 1; i < 63; i++)
112  {
113  if (i < 31) // Positive Numbers
114  HalfToFloatExponentTable[i] = ((uint)i) << 23;
115  else // Negative Numbers
116  HalfToFloatExponentTable[i] = 0x80000000 + (((uint)(i - 32)) << 23);
117  }
118  HalfToFloatExponentTable[31] = 0x47800000;
119  HalfToFloatExponentTable[32] = 0x80000000;
120  HalfToFloatExponentTable[63] = 0xC7800000;
121 
122  // Offset table
123  HalfToFloatOffsetTable[0] = 0;
124  for (i = 1; i < 64; i++)
125  HalfToFloatOffsetTable[i] = 1024;
126  HalfToFloatOffsetTable[32] = 0;
127 
128  // -------------------------------------------------------------------
129  // Float to Half tables
130  // -------------------------------------------------------------------
131 
132  for (i = 0; i < 256; i++)
133  {
134  int e = i - 127;
135  if (e < -24)
136  { // Very small numbers map to zero
137  FloatToHalfBaseTable[i | 0x000] = 0x0000;
138  FloatToHalfBaseTable[i | 0x100] = 0x8000;
139  FloatToHalfShiftTable[i | 0x000] = 24;
140  FloatToHalfShiftTable[i | 0x100] = 24;
141  }
142  else if (e < -14)
143  { // Small numbers map to denorms
144  FloatToHalfBaseTable[i | 0x000] = (ushort)((0x0400 >> (-e - 14)));
145  FloatToHalfBaseTable[i | 0x100] = (ushort)((0x0400 >> (-e - 14)) | 0x8000);
146  FloatToHalfShiftTable[i | 0x000] = (byte)(-e - 1);
147  FloatToHalfShiftTable[i | 0x100] = (byte)(-e - 1);
148  }
149  else if (e <= 15)
150  { // Normal numbers just lose precision
151  FloatToHalfBaseTable[i | 0x000] = (ushort)(((e + 15) << 10));
152  FloatToHalfBaseTable[i | 0x100] = (ushort)(((e + 15) << 10) | 0x8000);
153  FloatToHalfShiftTable[i | 0x000] = 13;
154  FloatToHalfShiftTable[i | 0x100] = 13;
155  }
156  else if (e < 128)
157  { // Large numbers map to Infinity
158  FloatToHalfBaseTable[i | 0x000] = 0x7C00;
159  FloatToHalfBaseTable[i | 0x100] = 0xFC00;
160  FloatToHalfShiftTable[i | 0x000] = 24;
161  FloatToHalfShiftTable[i | 0x100] = 24;
162  }
163  else
164  { // Infinity and NaN's stay Infinity and NaN's
165  FloatToHalfBaseTable[i | 0x000] = 0x7C00;
166  FloatToHalfBaseTable[i | 0x100] = 0xFC00;
167  FloatToHalfShiftTable[i | 0x000] = 13;
168  FloatToHalfShiftTable[i | 0x100] = 13;
169  }
170  }
171  }
172  }
173 }