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