1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
6 #include "irrString.h"
\r
7 #include "IrrCompileConfig.h"
\r
10 #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
\r
11 #include <SDL/SDL_endian.h>
\r
12 #define bswap_16(X) SDL_Swap16(X)
\r
13 #define bswap_32(X) SDL_Swap32(X)
\r
14 #define bswap_64(X) SDL_Swap64(X)
\r
15 #elif defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER > 1298)
\r
17 #define bswap_16(X) _byteswap_ushort(X)
\r
18 #define bswap_32(X) _byteswap_ulong(X)
\r
19 #define bswap_64(X) _byteswap_uint64(X)
\r
20 #if (_MSC_VER >= 1400)
\r
21 #define localtime _localtime_s
\r
23 #elif defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_)
\r
24 #include <libkern/OSByteOrder.h>
\r
25 #define bswap_16(X) OSReadSwapInt16(&X,0)
\r
26 #define bswap_32(X) OSReadSwapInt32(&X,0)
\r
27 #define bswap_64(X) OSReadSwapInt64(&X,0)
\r
28 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
\r
29 #include <sys/endian.h>
\r
30 #define bswap_16(X) bswap16(X)
\r
31 #define bswap_32(X) bswap32(X)
\r
32 #define bswap_64(X) bswap64(X)
\r
33 #elif !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__PPC__) && !defined(_IRR_WINDOWS_API_)
\r
34 #include <byteswap.h>
\r
36 #define bswap_16(X) ((((X)&0xFF) << 8) | (((X)&0xFF00) >> 8))
\r
37 #define bswap_32(X) ((((X)&0x000000FF) << 24) | (((X)&0xFF000000) >> 24) | (((X)&0x0000FF00) << 8) | (((X) &0x00FF0000) >> 8))
\r
38 #define bswap_64(X) ((((X)&0x00000000000000FF) << 56) | (((X)&0xFF00000000000000) >> 56) | (((X)&0x000000000000FF00) << 40) | (((X)&0x00FF000000000000) >> 40) | (((X)&0x0000000000FF0000) << 24) | (((X)&0x0000FF0000000000) >> 24) | (((X)&0x00000000FF000000) << 8) | (((X) &0x000000FF00000000) >> 8))
\r
45 u16 Byteswap::byteswap(u16 num) {return bswap_16(num);}
\r
46 s16 Byteswap::byteswap(s16 num) {return bswap_16(num);}
\r
47 u32 Byteswap::byteswap(u32 num) {return bswap_32(num);}
\r
48 s32 Byteswap::byteswap(s32 num) {return bswap_32(num);}
\r
49 u64 Byteswap::byteswap(u64 num) {return bswap_64(num);}
\r
50 s64 Byteswap::byteswap(s64 num) {return bswap_64(num);}
\r
51 f32 Byteswap::byteswap(f32 num) {u32 tmp=IR(num); tmp=bswap_32(tmp); return (FR(tmp));}
\r
52 // prevent accidental byte swapping of chars
\r
53 u8 Byteswap::byteswap(u8 num) {return num;}
\r
54 c8 Byteswap::byteswap(c8 num) {return num;}
\r
58 #if defined(_IRR_WINDOWS_API_)
\r
59 // ----------------------------------------------------------------
\r
60 // Windows specific functions
\r
61 // ----------------------------------------------------------------
\r
63 #ifdef _IRR_XBOX_PLATFORM_
\r
66 #define WIN32_LEAN_AND_MEAN
\r
67 #include <windows.h>
\r
75 //! prints a debuginfo string
\r
76 void Printer::print(const c8* message, ELOG_LEVEL ll)
\r
78 #if defined (_WIN32_WCE )
\r
79 core::stringw tmp(message);
\r
81 OutputDebugStringW(tmp.c_str());
\r
83 core::stringc tmp(message);
\r
85 OutputDebugStringA(tmp.c_str());
\r
86 printf("%s", tmp.c_str());
\r
90 static LARGE_INTEGER HighPerformanceFreq;
\r
91 static BOOL HighPerformanceTimerSupport = FALSE;
\r
92 static BOOL MultiCore = FALSE;
\r
94 void Timer::initTimer(bool usePerformanceTimer)
\r
96 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_)
\r
97 // workaround for hires timer on multiple core systems, bios bugs result in bad hires timers.
\r
98 SYSTEM_INFO sysinfo;
\r
99 GetSystemInfo(&sysinfo);
\r
100 MultiCore = (sysinfo.dwNumberOfProcessors > 1);
\r
102 if (usePerformanceTimer)
\r
103 HighPerformanceTimerSupport = QueryPerformanceFrequency(&HighPerformanceFreq);
\r
105 HighPerformanceTimerSupport = FALSE;
\r
106 initVirtualTimer();
\r
109 u32 Timer::getRealTime()
\r
111 if (HighPerformanceTimerSupport)
\r
113 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_)
\r
114 // Avoid potential timing inaccuracies across multiple cores by
\r
115 // temporarily setting the affinity of this process to one core.
\r
116 DWORD_PTR affinityMask=0;
\r
118 affinityMask = SetThreadAffinityMask(GetCurrentThread(), 1);
\r
120 LARGE_INTEGER nTime;
\r
121 BOOL queriedOK = QueryPerformanceCounter(&nTime);
\r
123 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_)
\r
124 // Restore the true affinity.
\r
126 (void)SetThreadAffinityMask(GetCurrentThread(), affinityMask);
\r
129 return u32((nTime.QuadPart) * 1000 / HighPerformanceFreq.QuadPart);
\r
133 return GetTickCount();
\r
136 } // end namespace os
\r
139 #elif defined( _IRR_ANDROID_PLATFORM_ )
\r
141 // ----------------------------------------------------------------
\r
143 // ----------------------------------------------------------------
\r
145 #include <android/log.h>
\r
152 //! prints a debuginfo string
\r
153 void Printer::print(const c8* message, ELOG_LEVEL ll)
\r
155 android_LogPriority LogLevel = ANDROID_LOG_UNKNOWN;
\r
160 LogLevel = ANDROID_LOG_DEBUG;
\r
162 case ELL_INFORMATION:
\r
163 LogLevel = ANDROID_LOG_INFO;
\r
166 LogLevel = ANDROID_LOG_WARN;
\r
169 LogLevel = ANDROID_LOG_ERROR;
\r
171 default: // ELL_NONE
\r
172 LogLevel = ANDROID_LOG_VERBOSE;
\r
176 // Android logcat restricts log-output and cuts the rest of the message away. But we want it all.
\r
177 // On my device max-len is 1023 (+ 0 byte). Some websites claim a limit of 4096 so maybe different numbers on different devices.
\r
178 const size_t maxLogLen = 1023;
\r
179 size_t msgLen = strlen(message);
\r
181 while ( msgLen-start > maxLogLen )
\r
183 __android_log_print(LogLevel, "Irrlicht", "%.*s\n", maxLogLen, &message[start]);
\r
184 start += maxLogLen;
\r
186 __android_log_print(LogLevel, "Irrlicht", "%s\n", &message[start]);
\r
189 void Timer::initTimer(bool usePerformanceTimer)
\r
191 initVirtualTimer();
\r
194 u32 Timer::getRealTime()
\r
197 gettimeofday(&tv, 0);
\r
198 return (u32)(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
\r
200 } // end namespace os
\r
202 #elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
\r
204 // ----------------------------------------------------------------
\r
205 // emscripten version
\r
206 // ----------------------------------------------------------------
\r
208 #include <emscripten.h>
\r
210 #include <sys/time.h>
\r
217 //! prints a debuginfo string
\r
218 void Printer::print(const c8* message, ELOG_LEVEL ll)
\r
226 case ELL_INFORMATION:
\r
230 log_level=EM_LOG_WARN;
\r
233 log_level=EM_LOG_ERROR;
\r
235 default: // ELL_NONE
\r
239 emscripten_log(log_level, "%s", message); // Note: not adding \n as emscripten_log seems to do that already.
\r
242 void Timer::initTimer(bool usePerformanceTimer)
\r
244 initVirtualTimer();
\r
247 u32 Timer::getRealTime()
\r
249 double time = emscripten_get_now();
\r
250 return (u32)(time);
\r
252 } // end namespace os
\r
256 // ----------------------------------------------------------------
\r
257 // linux/ansi version
\r
258 // ----------------------------------------------------------------
\r
262 #include <sys/time.h>
\r
269 //! prints a debuginfo string
\r
270 void Printer::print(const c8* message, ELOG_LEVEL ll)
\r
272 printf("%s\n", message);
\r
275 void Timer::initTimer(bool usePerformanceTimer)
\r
277 initVirtualTimer();
\r
280 u32 Timer::getRealTime()
\r
283 gettimeofday(&tv, 0);
\r
284 return (u32)(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
\r
286 } // end namespace os
\r
288 #endif // end linux / emscripten / android / windows
\r
292 // The platform independent implementation of the printer
\r
293 ILogger* Printer::Logger = 0;
\r
295 void Printer::log(const c8* message, ELOG_LEVEL ll)
\r
298 Logger->log(message, ll);
\r
301 void Printer::log(const wchar_t* message, ELOG_LEVEL ll)
\r
304 Logger->log(message, ll);
\r
307 void Printer::log(const c8* message, const c8* hint, ELOG_LEVEL ll)
\r
310 Logger->log(message, hint, ll);
\r
313 void Printer::log(const c8* message, const io::path& hint, ELOG_LEVEL ll)
\r
316 Logger->log(message, hint.c_str(), ll);
\r
319 // our Randomizer is not really os specific, so we
\r
320 // code one for all, which should work on every platform the same,
\r
321 // which is desirable.
\r
323 s32 Randomizer::seed = 0x0f0f0f0f;
\r
325 //! generates a pseudo random number
\r
326 s32 Randomizer::rand()
\r
328 // (a*seed)%m with Schrage's method
\r
329 seed = a * (seed%q) - r* (seed/q);
\r
333 return seed-1; // -1 because we want it to start at 0
\r
336 //! generates a pseudo random number
\r
337 f32 Randomizer::frand()
\r
339 return rand()*(1.f/rMax);
\r
342 s32 Randomizer::randMax()
\r
347 //! resets the randomizer
\r
348 void Randomizer::reset(s32 value)
\r
352 else if ( value == 0 || value == m)
\r
359 // ------------------------------------------------------
\r
360 // virtual timer implementation
\r
362 f32 Timer::VirtualTimerSpeed = 1.0f;
\r
363 s32 Timer::VirtualTimerStopCounter = 0;
\r
364 u32 Timer::LastVirtualTime = 0;
\r
365 u32 Timer::StartRealTime = 0;
\r
366 u32 Timer::StaticTime = 0;
\r
368 //! Get real time and date in calendar form
\r
369 ITimer::RealTimeDate Timer::getRealTimeAndDate()
\r
374 struct tm * timeinfo;
\r
375 timeinfo = localtime(&rawtime);
\r
377 // init with all 0 to indicate error
\r
378 ITimer::RealTimeDate date;
\r
379 memset(&date, 0, sizeof(date));
\r
380 // at least Windows returns NULL on some illegal dates
\r
383 // set useful values if succeeded
\r
384 date.Hour=(u32)timeinfo->tm_hour;
\r
385 date.Minute=(u32)timeinfo->tm_min;
\r
386 date.Second=(u32)timeinfo->tm_sec;
\r
387 date.Day=(u32)timeinfo->tm_mday;
\r
388 date.Month=(u32)timeinfo->tm_mon+1;
\r
389 date.Year=(u32)timeinfo->tm_year+1900;
\r
390 date.Weekday=(ITimer::EWeekday)timeinfo->tm_wday;
\r
391 date.Yearday=(u32)timeinfo->tm_yday+1;
\r
392 date.IsDST=timeinfo->tm_isdst != 0;
\r
397 //! returns current virtual time
\r
398 u32 Timer::getTime()
\r
401 return LastVirtualTime;
\r
403 return LastVirtualTime + (u32)((StaticTime - StartRealTime) * VirtualTimerSpeed);
\r
406 //! ticks, advances the virtual timer
\r
409 StaticTime = getRealTime();
\r
412 //! sets the current virtual time
\r
413 void Timer::setTime(u32 time)
\r
415 StaticTime = getRealTime();
\r
416 LastVirtualTime = time;
\r
417 StartRealTime = StaticTime;
\r
420 //! stops the virtual timer
\r
421 void Timer::stopTimer()
\r
425 // stop the virtual timer
\r
426 LastVirtualTime = getTime();
\r
429 --VirtualTimerStopCounter;
\r
432 //! starts the virtual timer
\r
433 void Timer::startTimer()
\r
435 ++VirtualTimerStopCounter;
\r
439 // restart virtual timer
\r
440 setTime(LastVirtualTime);
\r
444 //! sets the speed of the virtual timer
\r
445 void Timer::setSpeed(f32 speed)
\r
447 setTime(getTime());
\r
449 VirtualTimerSpeed = speed;
\r
450 if (VirtualTimerSpeed < 0.0f)
\r
451 VirtualTimerSpeed = 0.0f;
\r
454 //! gets the speed of the virtual timer
\r
455 f32 Timer::getSpeed()
\r
457 return VirtualTimerSpeed;
\r
460 //! returns if the timer currently is stopped
\r
461 bool Timer::isStopped()
\r
463 return VirtualTimerStopCounter < 0;
\r
466 void Timer::initVirtualTimer()
\r
468 StaticTime = getRealTime();
\r
469 StartRealTime = StaticTime;
\r
472 } // end namespace os
\r
473 } // end namespace irr
\r