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