1 // Copyright (C) 2002-2012 Nikolaus Gebhardt 2 // This file is part of the "Irrlicht Engine". 3 // For conditions of distribution and use, see copyright notice in irrlicht.h 4 5 #include "os.h" 6 #include "irrString.h" 7 #include "IrrCompileConfig.h" 8 #include "irrMath.h" 9 10 #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) 11 #include <SDL/SDL_endian.h> 12 #define bswap_16(X) SDL_Swap16(X) 13 #define bswap_32(X) SDL_Swap32(X) 14 #elif defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER > 1298) 15 #include <stdlib.h> 16 #define bswap_16(X) _byteswap_ushort(X) 17 #define bswap_32(X) _byteswap_ulong(X) 18 #if (_MSC_VER >= 1400) 19 #define localtime _localtime_s 20 #endif 21 #elif defined(_IRR_OSX_PLATFORM_) 22 #include <libkern/OSByteOrder.h> 23 #define bswap_16(X) OSReadSwapInt16(&X,0) 24 #define bswap_32(X) OSReadSwapInt32(&X,0) 25 #elif defined(__FreeBSD__) || defined(__OpenBSD__) 26 #include <sys/endian.h> 27 #define bswap_16(X) bswap16(X) 28 #define bswap_32(X) bswap32(X) 29 #elif !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__PPC__) && !defined(_IRR_WINDOWS_API_) 30 #include <byteswap.h> 31 #else 32 #define bswap_16(X) ((((X)&0xFF) << 8) | (((X)&0xFF00) >> 8)) 33 #define bswap_32(X) ( (((X)&0x000000FF)<<24) | (((X)&0xFF000000) >> 24) | (((X)&0x0000FF00) << 8) | (((X) &0x00FF0000) >> 8)) 34 #endif 35 36 namespace irr 37 { 38 namespace os 39 { byteswap(u16 num)40 u16 Byteswap::byteswap(u16 num) {return bswap_16(num);} byteswap(s16 num)41 s16 Byteswap::byteswap(s16 num) {return bswap_16(num);} byteswap(u32 num)42 u32 Byteswap::byteswap(u32 num) {return bswap_32(num);} byteswap(s32 num)43 s32 Byteswap::byteswap(s32 num) {return bswap_32(num);} byteswap(f32 num)44 f32 Byteswap::byteswap(f32 num) {u32 tmp=IR(num); tmp=bswap_32(tmp); return (FR(tmp));} 45 // prevent accidental byte swapping of chars byteswap(u8 num)46 u8 Byteswap::byteswap(u8 num) {return num;} byteswap(c8 num)47 c8 Byteswap::byteswap(c8 num) {return num;} 48 } 49 } 50 51 #if defined(_IRR_WINDOWS_API_) 52 // ---------------------------------------------------------------- 53 // Windows specific functions 54 // ---------------------------------------------------------------- 55 56 #ifdef _IRR_XBOX_PLATFORM_ 57 #include <xtl.h> 58 #else 59 #define WIN32_LEAN_AND_MEAN 60 #include <windows.h> 61 #include <time.h> 62 #endif 63 64 namespace irr 65 { 66 namespace os 67 { 68 //! prints a debuginfo string print(const c8 * message)69 void Printer::print(const c8* message) 70 { 71 #if defined (_WIN32_WCE ) 72 core::stringw tmp(message); 73 tmp += L"\n"; 74 OutputDebugStringW(tmp.c_str()); 75 #else 76 core::stringc tmp(message); 77 tmp += "\n"; 78 OutputDebugStringA(tmp.c_str()); 79 printf("%s", tmp.c_str()); 80 #endif 81 } 82 83 static LARGE_INTEGER HighPerformanceFreq; 84 static BOOL HighPerformanceTimerSupport = FALSE; 85 static BOOL MultiCore = FALSE; 86 initTimer(bool usePerformanceTimer)87 void Timer::initTimer(bool usePerformanceTimer) 88 { 89 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) 90 // workaround for hires timer on multiple core systems, bios bugs result in bad hires timers. 91 SYSTEM_INFO sysinfo; 92 GetSystemInfo(&sysinfo); 93 MultiCore = (sysinfo.dwNumberOfProcessors > 1); 94 #endif 95 if (usePerformanceTimer) 96 HighPerformanceTimerSupport = QueryPerformanceFrequency(&HighPerformanceFreq); 97 else 98 HighPerformanceTimerSupport = FALSE; 99 initVirtualTimer(); 100 } 101 getRealTime()102 u32 Timer::getRealTime() 103 { 104 if (HighPerformanceTimerSupport) 105 { 106 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) 107 // Avoid potential timing inaccuracies across multiple cores by 108 // temporarily setting the affinity of this process to one core. 109 DWORD_PTR affinityMask=0; 110 if(MultiCore) 111 affinityMask = SetThreadAffinityMask(GetCurrentThread(), 1); 112 #endif 113 LARGE_INTEGER nTime; 114 BOOL queriedOK = QueryPerformanceCounter(&nTime); 115 116 #if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) 117 // Restore the true affinity. 118 if(MultiCore) 119 (void)SetThreadAffinityMask(GetCurrentThread(), affinityMask); 120 #endif 121 if(queriedOK) 122 return u32((nTime.QuadPart) * 1000 / HighPerformanceFreq.QuadPart); 123 124 } 125 126 return GetTickCount(); 127 } 128 129 } // end namespace os 130 131 132 #else 133 134 // ---------------------------------------------------------------- 135 // linux/ansi version 136 // ---------------------------------------------------------------- 137 138 #include <stdio.h> 139 #include <time.h> 140 #include <sys/time.h> 141 142 namespace irr 143 { 144 namespace os 145 { 146 147 //! prints a debuginfo string 148 void Printer::print(const c8* message) 149 { 150 printf("%s\n", message); 151 } 152 153 void Timer::initTimer(bool usePerformanceTimer) 154 { 155 initVirtualTimer(); 156 } 157 158 u32 Timer::getRealTime() 159 { 160 timeval tv; 161 gettimeofday(&tv, 0); 162 return (u32)(tv.tv_sec * 1000) + (tv.tv_usec / 1000); 163 } 164 } // end namespace os 165 166 #endif // end linux / windows 167 168 namespace os 169 { 170 // The platform independent implementation of the printer 171 ILogger* Printer::Logger = 0; 172 log(const c8 * message,ELOG_LEVEL ll)173 void Printer::log(const c8* message, ELOG_LEVEL ll) 174 { 175 if (Logger) 176 Logger->log(message, ll); 177 } 178 log(const wchar_t * message,ELOG_LEVEL ll)179 void Printer::log(const wchar_t* message, ELOG_LEVEL ll) 180 { 181 if (Logger) 182 Logger->log(message, ll); 183 } 184 log(const c8 * message,const c8 * hint,ELOG_LEVEL ll)185 void Printer::log(const c8* message, const c8* hint, ELOG_LEVEL ll) 186 { 187 if (Logger) 188 Logger->log(message, hint, ll); 189 } 190 log(const c8 * message,const io::path & hint,ELOG_LEVEL ll)191 void Printer::log(const c8* message, const io::path& hint, ELOG_LEVEL ll) 192 { 193 if (Logger) 194 Logger->log(message, hint.c_str(), ll); 195 } 196 197 // our Randomizer is not really os specific, so we 198 // code one for all, which should work on every platform the same, 199 // which is desireable. 200 201 s32 Randomizer::seed = 0x0f0f0f0f; 202 203 //! generates a pseudo random number rand()204 s32 Randomizer::rand() 205 { 206 // (a*seed)%m with Schrage's method 207 seed = a * (seed%q) - r* (seed/q); 208 if (seed<0) 209 seed += m; 210 211 return seed; 212 } 213 214 //! generates a pseudo random number frand()215 f32 Randomizer::frand() 216 { 217 return rand()*(1.f/rMax); 218 } 219 randMax()220 s32 Randomizer::randMax() 221 { 222 return rMax; 223 } 224 225 //! resets the randomizer reset(s32 value)226 void Randomizer::reset(s32 value) 227 { 228 seed = value; 229 } 230 231 232 // ------------------------------------------------------ 233 // virtual timer implementation 234 235 f32 Timer::VirtualTimerSpeed = 1.0f; 236 s32 Timer::VirtualTimerStopCounter = 0; 237 u32 Timer::LastVirtualTime = 0; 238 u32 Timer::StartRealTime = 0; 239 u32 Timer::StaticTime = 0; 240 241 //! Get real time and date in calendar form getRealTimeAndDate()242 ITimer::RealTimeDate Timer::getRealTimeAndDate() 243 { 244 time_t rawtime; 245 time(&rawtime); 246 247 struct tm * timeinfo; 248 timeinfo = localtime(&rawtime); 249 250 // init with all 0 to indicate error 251 ITimer::RealTimeDate date={0}; 252 // at least Windows returns NULL on some illegal dates 253 if (timeinfo) 254 { 255 // set useful values if succeeded 256 date.Hour=(u32)timeinfo->tm_hour; 257 date.Minute=(u32)timeinfo->tm_min; 258 date.Second=(u32)timeinfo->tm_sec; 259 date.Day=(u32)timeinfo->tm_mday; 260 date.Month=(u32)timeinfo->tm_mon+1; 261 date.Year=(u32)timeinfo->tm_year+1900; 262 date.Weekday=(ITimer::EWeekday)timeinfo->tm_wday; 263 date.Yearday=(u32)timeinfo->tm_yday+1; 264 date.IsDST=timeinfo->tm_isdst != 0; 265 } 266 return date; 267 } 268 269 //! returns current virtual time getTime()270 u32 Timer::getTime() 271 { 272 if (isStopped()) 273 return LastVirtualTime; 274 275 return LastVirtualTime + (u32)((StaticTime - StartRealTime) * VirtualTimerSpeed); 276 } 277 278 //! ticks, advances the virtual timer tick()279 void Timer::tick() 280 { 281 StaticTime = getRealTime(); 282 } 283 284 //! sets the current virtual time setTime(u32 time)285 void Timer::setTime(u32 time) 286 { 287 StaticTime = getRealTime(); 288 LastVirtualTime = time; 289 StartRealTime = StaticTime; 290 } 291 292 //! stops the virtual timer stopTimer()293 void Timer::stopTimer() 294 { 295 if (!isStopped()) 296 { 297 // stop the virtual timer 298 LastVirtualTime = getTime(); 299 } 300 301 --VirtualTimerStopCounter; 302 } 303 304 //! starts the virtual timer startTimer()305 void Timer::startTimer() 306 { 307 ++VirtualTimerStopCounter; 308 309 if (!isStopped()) 310 { 311 // restart virtual timer 312 setTime(LastVirtualTime); 313 } 314 } 315 316 //! sets the speed of the virtual timer setSpeed(f32 speed)317 void Timer::setSpeed(f32 speed) 318 { 319 setTime(getTime()); 320 321 VirtualTimerSpeed = speed; 322 if (VirtualTimerSpeed < 0.0f) 323 VirtualTimerSpeed = 0.0f; 324 } 325 326 //! gets the speed of the virtual timer getSpeed()327 f32 Timer::getSpeed() 328 { 329 return VirtualTimerSpeed; 330 } 331 332 //! returns if the timer currently is stopped isStopped()333 bool Timer::isStopped() 334 { 335 return VirtualTimerStopCounter < 0; 336 } 337 initVirtualTimer()338 void Timer::initVirtualTimer() 339 { 340 StaticTime = getRealTime(); 341 StartRealTime = StaticTime; 342 } 343 344 } // end namespace os 345 } // end namespace irr 346 347 348