1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2017, assimp team |
7 | |
8 | |
9 | All rights reserved. |
10 | |
11 | Redistribution and use of this software in source and binary forms, |
12 | with or without modification, are permitted provided that the following |
13 | conditions are met: |
14 | |
15 | * Redistributions of source code must retain the above |
16 | copyright notice, this list of conditions and the |
17 | following disclaimer. |
18 | |
19 | * Redistributions in binary form must reproduce the above |
20 | copyright notice, this list of conditions and the |
21 | following disclaimer in the documentation and/or other |
22 | materials provided with the distribution. |
23 | |
24 | * Neither the name of the assimp team, nor the names of its |
25 | contributors may be used to endorse or promote products |
26 | derived from this software without specific prior |
27 | written permission of the assimp team. |
28 | |
29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | --------------------------------------------------------------------------- |
41 | */ |
42 | |
43 | /** @file qnan.h |
44 | * @brief Some utilities for our dealings with qnans. |
45 | * |
46 | * @note Some loaders use qnans to mark invalid values tempoarily, also |
47 | * Assimp explicitly enforces undefined normals to be set to qnan. |
48 | * qnan utilities are available in standard libraries (C99 for example) |
49 | * but last time I checked compiler coverage was so bad that I decided |
50 | * to reinvent the wheel. |
51 | */ |
52 | |
53 | #ifndef AI_QNAN_H_INCLUDED |
54 | #define AI_QNAN_H_INCLUDED |
55 | |
56 | #include <assimp/defs.h> |
57 | #include <limits> |
58 | #include <stdint.h> |
59 | |
60 | // --------------------------------------------------------------------------- |
61 | /** Data structure to represent the bit pattern of a 32 Bit |
62 | * IEEE 754 floating-point number. */ |
63 | union _IEEESingle |
64 | { |
65 | float Float; |
66 | struct |
67 | { |
68 | uint32_t Frac : 23; |
69 | uint32_t Exp : 8; |
70 | uint32_t Sign : 1; |
71 | } IEEE; |
72 | }; |
73 | |
74 | // --------------------------------------------------------------------------- |
75 | /** Data structure to represent the bit pattern of a 64 Bit |
76 | * IEEE 754 floating-point number. */ |
77 | union _IEEEDouble |
78 | { |
79 | double Double; |
80 | struct |
81 | { |
82 | uint64_t Frac : 52; |
83 | uint64_t Exp : 11; |
84 | uint64_t Sign : 1; |
85 | } IEEE; |
86 | }; |
87 | |
88 | // --------------------------------------------------------------------------- |
89 | /** Check whether a given float is qNaN. |
90 | * @param in Input value */ |
91 | AI_FORCE_INLINE bool is_qnan(float in) |
92 | { |
93 | // the straightforward solution does not work: |
94 | // return (in != in); |
95 | // compiler generates code like this |
96 | // load <in> to <register-with-different-width> |
97 | // compare <register-with-different-width> against <in> |
98 | |
99 | // FIXME: Use <float> stuff instead? I think fpclassify needs C99 |
100 | return (reinterpret_cast<_IEEESingle*>(&in)->IEEE.Exp == (1u << 8)-1 && |
101 | reinterpret_cast<_IEEESingle*>(&in)->IEEE.Frac); |
102 | } |
103 | |
104 | // --------------------------------------------------------------------------- |
105 | /** Check whether a given double is qNaN. |
106 | * @param in Input value */ |
107 | AI_FORCE_INLINE bool is_qnan(double in) |
108 | { |
109 | // the straightforward solution does not work: |
110 | // return (in != in); |
111 | // compiler generates code like this |
112 | // load <in> to <register-with-different-width> |
113 | // compare <register-with-different-width> against <in> |
114 | |
115 | // FIXME: Use <float> stuff instead? I think fpclassify needs C99 |
116 | return (reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Exp == (1u << 11)-1 && |
117 | reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Frac); |
118 | } |
119 | |
120 | // --------------------------------------------------------------------------- |
121 | /** @brief check whether a float is either NaN or (+/-) INF. |
122 | * |
123 | * Denorms return false, they're treated like normal values. |
124 | * @param in Input value */ |
125 | AI_FORCE_INLINE bool is_special_float(float in) |
126 | { |
127 | return (reinterpret_cast<_IEEESingle*>(&in)->IEEE.Exp == (1u << 8)-1); |
128 | } |
129 | |
130 | // --------------------------------------------------------------------------- |
131 | /** @brief check whether a double is either NaN or (+/-) INF. |
132 | * |
133 | * Denorms return false, they're treated like normal values. |
134 | * @param in Input value */ |
135 | AI_FORCE_INLINE bool is_special_float(double in) |
136 | { |
137 | return (reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Exp == (1u << 11)-1); |
138 | } |
139 | |
140 | // --------------------------------------------------------------------------- |
141 | /** Check whether a float is NOT qNaN. |
142 | * @param in Input value */ |
143 | template<class TReal> |
144 | AI_FORCE_INLINE bool is_not_qnan(TReal in) |
145 | { |
146 | return !is_qnan(in); |
147 | } |
148 | |
149 | // --------------------------------------------------------------------------- |
150 | /** @brief Get a fresh qnan. */ |
151 | AI_FORCE_INLINE ai_real get_qnan() |
152 | { |
153 | return std::numeric_limits<ai_real>::quiet_NaN(); |
154 | } |
155 | |
156 | #endif // !! AI_QNAN_H_INCLUDED |
157 | |