1 | // tPlatform.h  |
2 | //  |
3 | // Tacent platform defines, architecture, and endianness detection. The Tacent library has some preprocessor define  |
4 | // requirements. One of PLATFORM_NNN, ARCHITECTURE_NNN, and CONFIG_NNN need to be defined. If you haven't bothered  |
5 | // to define these in the project file with a /D switch, an attempt is made to define them automatically for you.  |
6 | //  |
7 | // Copyright (c) 2004-2006, 2015, 2017, 2020 Tristan Grimmer.  |
8 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
9 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
10 | //  |
11 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
12 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
13 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
14 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
15 | // PERFORMANCE OF THIS SOFTWARE.  |
16 |   |
17 | #pragma once  |
18 | #include <stdio.h>  |
19 | #include <stdlib.h>  |
20 | // No Tacent headers here. tPlatform.h is where the buck stops.  |
21 |   |
22 |   |
23 | // Attempt to auto-detect platform.  |
24 | #if (!defined(PLATFORM_WINDOWS) && !defined(PLATFORM_LINUX) && !defined(PLATFORM_MACOS) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_IOS))  |
25 | #if (defined(_M_AMD64) || defined(_M_IX86) || defined(_WIN32) || defined(_WIN64))  |
26 | #define PLATFORM_WINDOWS  |
27 | #elif defined(__linux__)  |
28 | #define PLATFORM_LINUX  |
29 | #endif  |
30 | #endif  |
31 |   |
32 |   |
33 | // Attempt to auto-detect archetecture.  |
34 | #if (!defined(ARCHITECTURE_X64) && !defined(ARCHITECTURE_X86) && !defined(ARCHITECTURE_ARM))  |
35 | #if (defined(_M_AMD64) || defined(_WIN64) || defined(__x86_64__))  |
36 | #define ARCHITECTURE_X64 // For x86_64  |
37 | #elif defined(__i386)  |
38 | #define ARCHITECTURE_X86  |
39 | #endif  |
40 | #endif  |
41 |   |
42 |   |
43 | // Debug and Release configurations are only autodetected on windows.  |
44 | #if (!defined(CONFIG_DEBUG) && !defined(CONFIG_DEVELOP) && !defined(CONFIG_PROFILE) && !defined(CONFIG_RELEASE) && !defined(CONFIG_SHIP))  |
45 | #if defined(_DEBUG)  |
46 | #define CONFIG_DEBUG  |
47 | #endif  |
48 | #if defined(NDEBUG)  |
49 | #define CONFIG_RELEASE  |
50 | #endif  |
51 | #endif  |
52 |   |
53 |   |
54 | // Turn off some annoying windows warnings.  |
55 | #if (defined(PLATFORM_WINDOWS) && !defined(_CRT_SECURE_NO_DEPRECATE))  |
56 | #define _CRT_SECURE_NO_DEPRECATE  |
57 | #endif  |
58 |   |
59 |   |
60 | // Sanity check. Required defines must be present.  |
61 | #if (!defined(PLATFORM_WINDOWS) && !defined(PLATFORM_LINUX) && !defined(PLATFORM_MACOS) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_IOS))  |
62 | #error You must define a supported platform.  |
63 | #endif  |
64 | #if (!defined(ARCHITECTURE_X64) && !defined(ARCHITECTURE_ARM))  |
65 | #error You must define a supported architecture.  |
66 | #endif  |
67 | #if (!defined(CONFIG_DEBUG) && !defined(CONFIG_DEVELOP) && !defined(CONFIG_PROFILE) && !defined(CONFIG_RELEASE) && !defined(CONFIG_SHIP))  |
68 | #error You must define a supported configuration.  |
69 | #endif  |
70 |   |
71 |   |
72 | // Define the endianness.  |
73 | #if (defined(PLATFORM_WINDOWS) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS) || defined(PLATFORM_ANDROID) || defined(PLATFORM_IOS))  |
74 | #define ENDIAN_LITTLE  |
75 | #else  |
76 | #define ENDIAN_BIG  |
77 | #endif  |
78 |   |
79 |   |
80 | #if defined(PLATFORM_WINDOWS)  |
81 | #include <xmmintrin.h>  |
82 | #endif  |
83 |   |
84 |   |
85 | // Many objects have a Pod member function that returns a plain-old-data version of itself. Useful for cases where POD  |
86 | // is required, like to printf functions.  |
87 | #define tPod(x) (x.Pod())  |
88 | #define tAlign16 __declspec(align(16))  |
89 | #define tIsAligned16(addr) ((uint64(addr) & 0xF) == 0)  |
90 |   |
91 |   |
92 | typedef unsigned char uchar;  |
93 | typedef signed char schar;  |
94 | typedef unsigned int uint;  |
95 | typedef unsigned short ushort;  |
96 | typedef unsigned long ulong;  |
97 |   |
98 |   |
99 | // Use the following integral types ONLY when you are relying on the specified number of bits. If you need more than  |
100 | // 64 use a tBitField.  |
101 | typedef signed char int8;  |
102 | typedef unsigned char uint8;  |
103 | typedef short int16;  |
104 | typedef unsigned short uint16;  |
105 | typedef int int32;  |
106 | typedef unsigned int uint32;  |
107 | typedef long long int int64;  |
108 | typedef unsigned long long int uint64;  |
109 |   |
110 |   |
111 | // Simple low-level file IO.  |
112 | typedef FILE* tFileHandle;  |
113 |   |
114 |   |
115 | enum class tPlatform  |
116 | {  |
117 | Invalid = -1,  |
118 | First,  |
119 | Windows = First,  |
120 | Linux, // Linux.  |
121 | MacOS, // Apple's desktop OS. It's no longer called OSX.  |
122 | Android, // Google Android.  |
123 | iOS, // Apple iOS.  |
124 | All, // Not counted as a separate platform.  |
125 | NumPlatforms = All  |
126 | };  |
127 |   |
128 | // Platforms as bitfields.  |
129 | enum tPlatformFlag  |
130 | {  |
131 | tPlatformFlag_None,  |
132 | tPlatformFlag_Windows = 1 << int(tPlatform::Windows),  |
133 | tPlatformFlag_Linux = 1 << int(tPlatform::Linux),  |
134 | tPlatformFlag_MacOS = 1 << int(tPlatform::MacOS),  |
135 | tPlatformFlag_Android = 1 << int(tPlatform::Android),  |
136 | tPlatformFlag_iOS = 1 << int(tPlatform::iOS),  |
137 | tPlatformFlag_All = 0xFFFFFFFF  |
138 | };  |
139 |   |
140 | struct tString;  |
141 | tPlatform tGetPlatform(); // Based on required platform defines.  |
142 | tPlatform tGetPlatform(const tString&);  |
143 | const char* tGetPlatformName(tPlatform);  |
144 | const char* tGetPlatformNameLong(tPlatform);  |
145 |   |
146 | enum class tArchitecture  |
147 | {  |
148 | Invalid = -1,  |
149 | x64, // Desktop (not Itanium) 64bit architecture. i.e. AMD64.  |
150 | A64, // Arm 64 bit. Also known as AArch64.  |
151 | NumArchitectures  |
152 | };  |
153 | tArchitecture tGetArchitecture(); // Based on defines.  |
154 | const char* tGetArchitectureName(tArchitecture);  |
155 | const char* tGetArchitectureNameLong(tArchitecture);  |
156 |   |
157 | enum class tEndianness  |
158 | {  |
159 | Invalid = -1,  |
160 | Big,  |
161 | Little  |
162 | };  |
163 |   |
164 | // If you want to know the endianness based on the platform define just test for ENDIAN_BIG or ENDIAN_LITTLE.  |
165 | tEndianness tGetEndianness(tPlatform); // Returns the native endianness of the tPlatform.  |
166 | tEndianness tGetEndianness(); // Performs a test on the current architecture.  |
167 |   |
168 | // These calls allow endianness swapping of variously sized types.  |
169 | template<typename T> inline T tGetSwapEndian(const T&);  |
170 | template<typename T> inline void tSwapEndian(T&);  |
171 | template<typename T> inline void tSwapEndian(T*, int numItems);  |
172 |   |
173 | // Converts to and from external data representation (XDR/Network) which is big-endian. Does not rely on the  |
174 | // PLATFORM define by performing an endianness test.  |
175 | template<typename T> inline T tNtoH(T val);  |
176 | template<typename T> inline T tHtoN(T val);  |
177 |   |
178 |   |
179 | // Implementation below this line.  |
180 |   |
181 |   |
182 | template<typename T> inline T tGetSwapEndian(const T& val)  |
183 | {  |
184 | union endianAccessor  |
185 | {  |
186 | T Data;  |
187 | uint8 Bytes[sizeof(T)];  |
188 | };  |
189 | endianAccessor& src = (endianAccessor&)val;  |
190 | endianAccessor dst;  |
191 | for (int d = 0; d < int(sizeof(T)); d++)  |
192 | dst.Bytes[d] = src.Bytes[sizeof(T) - d - 1];  |
193 |   |
194 | return dst.Data;  |
195 | }  |
196 |   |
197 |   |
198 | template<typename T> inline void tSwapEndian(T& val)  |
199 | {  |
200 | union endianAccessor  |
201 | {  |
202 | T Data;  |
203 | uint8 Bytes[sizeof(T)];  |
204 | };  |
205 | endianAccessor& srcDst = (endianAccessor&)val;  |
206 | int numBytes = sizeof(T);  |
207 | for (int s = 0; s < (numBytes >> 1); s++)  |
208 | {  |
209 | uint8& a = srcDst.Bytes[s];  |
210 | uint8& b = srcDst.Bytes[numBytes - 1 - s];  |
211 | uint8 t = a;  |
212 | a = b;  |
213 | b = t;  |
214 | }  |
215 | }  |
216 |   |
217 |   |
218 | template<typename T> inline void tSwapEndian(T* a, int numItems)  |
219 | {  |
220 | for (int i = 0; i < numItems; i++)  |
221 | tSwapEndian(a[i]);  |
222 | }  |
223 |   |
224 |   |
225 | inline tEndianness tGetEndianness()  |
226 | {  |
227 | union  |
228 | {  |
229 | uint8 c[2];  |
230 | uint16 u;  |
231 | } a;  |
232 |   |
233 | a.c[1] = 0;  |
234 | a.c[0] = 1;  |
235 |   |
236 | if (a.u == 1)  |
237 | return tEndianness::Little;  |
238 |   |
239 | return tEndianness::Big;  |
240 | }  |
241 |   |
242 |   |
243 | template<typename T> inline T tNtoH(T val)  |
244 | {  |
245 | if (tGetEndianness() == tEndianness::Big)  |
246 | return val;  |
247 |   |
248 | return tGetSwapEndian(val);  |
249 | }  |
250 |   |
251 |   |
252 | template<typename T> inline T tHtoN(T val)  |
253 | {  |
254 | return NtoH(val);  |
255 | }  |
256 |   |
257 |   |
258 | // These defines mitigate Windows all-capital naming ugliness.  |
259 | #ifdef PLATFORM_WINDOWS  |
260 | #define ApiEntry APIENTRY  |
261 | #define WinBitmap BITMAP  |
262 | #define WinBitmapInfo BITMAPINFO  |
263 | #define WinBitmapInfoHeader BITMAPINFOHEADER  |
264 | #define ColorRef COLORREF  |
265 | #define CreateStruct CREATESTRUCT  |
266 | #define dWord DWORD  |
267 | #define False FALSE  |
268 | #define FileTime FILETIME  |
269 | #define GlyphMetrics GLYPHMETRICS  |
270 | #define hBitmap HBITMAP  |
271 | #define hDc HDC  |
272 | #define hFont HFONT  |
273 | #define hGlrc HGLRC  |
274 | #define hPBufferARB HPBUFFERARB  |
275 | #define HiWord HIWORD  |
276 | #define hResult HRESULT  |
277 | #define hWinIcon HICON  |
278 | #define hWinCursor HCURSOR  |
279 | #define WindowHandle HWND  |
280 | #define IconInfo ICONINFO  |
281 | #define Infinite INFINITE  |
282 | #define ItemIdList ITEMIDLIST  |
283 | #define LargeInteger LARGE_INTEGER  |
284 | #define Long LONG  |
285 | #define LongPtr LONG_PTR  |
286 | #define LoWord LOWORD  |
287 | #define WinLParam LPARAM  |
288 | #define lpCItemIdList LPCITEMIDLIST  |
289 | #define lpCRect LPCRECT  |
290 | #define lpEnumIdList LPENUMIDLIST  |
291 | #define lpItemIdList LPITEMIDLIST  |
292 | #define lpMalloc LPMALLOC  |
293 | #define lpShellFolder LPSHELLFOLDER  |
294 | #define lpVoid LPVOID  |
295 | #define lResult LRESULT  |
296 | #define MakeWord MAKEWORD  |
297 | #define MaxPath MAX_PATH  |
298 | #define Nmhdr NMHDR  |
299 | #define OleChar OLECHAR  |
300 | #define PixelFormatDescriptor PIXELFORMATDESCRIPTOR  |
301 | #define Point POINT  |
302 | #ifndef MAX_PLUGIN  |
303 | #define Rect RECT  |
304 | #endif  |
305 | #define ShellFolder SHELLFOLDER  |
306 | #define ShFileInfo SHFILEINFO  |
307 | #define SystemTime SYSTEMTIME  |
308 | #define WinSize SIZE  |
309 | #define True TRUE  |
310 | #define tStr TSTR  |
311 | #define tChar TCHAR  |
312 | #define WaitFailed WAIT_FAILED  |
313 | #define WaitObject0 WAIT_OBJECT_0  |
314 | #define WaitTimeout WAIT_TIMEOUT  |
315 | #define Win32FindData WIN32_FIND_DATA  |
316 | #define WinApi WINAPI  |
317 | #define WinBool BOOL  |
318 | #define WinHandle HANDLE  |
319 | #define WinInstance HINSTANCE  |
320 | #define WinIntPtr INT_PTR  |
321 | #define WinMessage MSG  |
322 | #define WinProc PROC  |
323 | #define WinSocket SOCKET  |
324 | #define WinWord WORD  |
325 | #define WinCallback CALLBACK  |
326 | #define WinWParam WPARAM  |
327 | #define WsaData WSADATA  |
328 | #define WinUUID __uuidof  |
329 | #define CriticalSection CRITICAL_SECTION  |
330 | #define snprintf _snprintf  |
331 | inline bool WinSucceeded(long hresult) { return (hresult >= 0) ? true : false; }  |
332 | inline bool WinFailed(long hresult) { return (hresult < 0) ? true : false; }  |
333 | #endif  |
334 | |