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