1 /////////////////////////////////////////
2 //
3 //   OpenLieroX
4 //
5 //   Auxiliary Software class library
6 //
7 //   based on the work of JasonB
8 //   enhanced by Dark Charlie and Albert Zeyer
9 //
10 //   code under LGPL
11 //
12 /////////////////////////////////////////
13 
14 
15 // Auxiliary library
16 // Created 12/11/01
17 // By Jason Boettcher
18 
19 #ifdef _MSC_VER
20 #pragma warning(disable: 4996)
21 #endif
22 
23 
24 #include <iomanip>
25 #include <time.h>
26 #include <SDL.h>
27 #include <SDL_syswm.h>
28 #ifdef REAL_OPENGL
29 #include <SDL_opengl.h>
30 #endif
31 #include <cstdlib>
32 #include <sstream>
33 #include <cstring>
34 
35 #if defined(__APPLE__)
36 #include <mach/host_info.h>
37 #include <mach/mach_host.h>
38 #include <mach/mach_init.h>
39 #include <sys/sysctl.h>
40 #include <mach/mach_traps.h>
41 #elif defined(WIN32) || defined(WIN64)
42 #include <windows.h>
43 #else
44 #include <cstdio>
45 #include <unistd.h>
46 #endif
47 
48 #ifdef __FREEBSD__
49 #include <sys/sysctl.h>
50 #include <vm/vm_param.h>
51 #include <sys/vmmeter.h>
52 #endif
53 
54 #ifndef WIN32
55 #include <sys/types.h>
56 #include <sys/resource.h>
57 #include <unistd.h>
58 #endif
59 
60 #include "Cache.h"
61 #include "Debug.h"
62 #include "AuxLib.h"
63 #include "Error.h"
64 #include "DeprecatedGUI/Menu.h"
65 #include "GfxPrimitives.h"
66 #include "FindFile.h"
67 #include "InputEvents.h"
68 #include "StringUtils.h"
69 #include "Sounds.h"
70 #include "Version.h"
71 #include "Timer.h"
72 #include "types.h"
73 #include "CClient.h"
74 #include "CServer.h"
75 #include "Geometry.h"
76 #include "Touchscreen.h"
77 
78 
79 Null null;	// Used in timer class
80 
81 // Config file
82 std::string	ConfigFile;
83 
84 // Screen
85 
86 SDL_Surface* videoSurface = NULL;
87 
88 
89 SDL_PixelFormat defaultFallbackFormat =
90 	{
91          NULL, //SDL_Palette *palette;
92          32, //Uint8  BitsPerPixel;
93          4, //Uint8  BytesPerPixel;
94          0, 0, 0, 0, //Uint8  Rloss, Gloss, Bloss, Aloss;
95          24, 16, 8, 0, //Uint8  Rshift, Gshift, Bshift, Ashift;
96          0xff000000, 0xff0000, 0xff00, 0xff, //Uint32 Rmask, Gmask, Bmask, Amask;
97          0, //Uint32 colorkey;
98          255 //Uint8  alpha;
99 	};
100 
101 SDL_PixelFormat* mainPixelFormat = &defaultFallbackFormat;
102 
103 
104 ///////////////////
105 // Initialize the standard Auxiliary Library
InitializeAuxLib(const std::string & config,int bpp,int vidflags)106 int InitializeAuxLib(const std::string& config, int bpp, int vidflags)
107 {
108 	// We have already loaded all options from the config file at this time.
109 
110 #ifdef linux
111 	//XInitThreads();	// We should call this before any SDL video stuff and window creation
112 #endif
113 
114 
115 	ConfigFile=config;
116 
117 	if(getenv("SDL_VIDEODRIVER"))
118 		notes << "SDL_VIDEODRIVER=" << getenv("SDL_VIDEODRIVER") << endl;
119 
120 	// Solves problem with FPS in fullscreen
121 #ifdef WIN32
122 	if(!getenv("SDL_VIDEODRIVER")) {
123 		notes << "SDL_VIDEODRIVER not set, setting to directx" << endl;
124 		putenv((char*)"SDL_VIDEODRIVER=directx");
125 	}
126 #endif
127 
128 	// Initialize SDL
129 	int SDLflags = SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE;
130 	if(!bDedicated) {
131 		SDLflags |= SDL_INIT_VIDEO;
132 	} else {
133 		hints << "DEDICATED MODE" << endl;
134 		bDisableSound = true;
135 		bJoystickSupport = false;
136 	}
137 
138 	if(SDL_Init(SDLflags) == -1) {
139 		errors << "Failed to initialize the SDL system!\nErrorMsg: " << std::string(SDL_GetError()) << endl;
140 #ifdef WIN32
141 		// retry it with any available video driver
142 		unsetenv("SDL_VIDEODRIVER");
143 		if(SDL_Init(SDLflags) != -1)
144 			hints << "... but we have success with the any driver" << endl;
145 		// retry with windib
146 		else if(putenv((char*)"SDL_VIDEODRIVER=windib") == 0 && SDL_Init(SDLflags) != -1)
147 			hints << "... but we have success with the windib driver" << endl;
148 		else
149 #endif
150 		return false;
151 	}
152 
153 #ifndef DISABLE_JOYSTICK
154 	if(bJoystickSupport) {
155 		if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
156 			warnings << "WARNING: couldn't init joystick subystem: " << SDL_GetError() << endl;
157 			bJoystickSupport = false;
158 		}
159 	}
160 #endif
161 
162 	if(!bDedicated && !SetVideoMode())
163 		return false;
164 
165     // Enable the system events
166     SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
167 	SDL_EventState(SDL_VIDEOEXPOSE, SDL_ENABLE);
168 
169 	// Enable unicode and key repeat
170 	SDL_EnableUNICODE(1);
171 	SDL_EnableKeyRepeat(200,20);
172 
173 
174     if( !bDisableSound ) {
175 	    // Initialize sound
176 		//if(!InitSoundSystem(22050, 1, 512)) {
177 		if(!InitSoundSystem(44100, 1, 512)) {
178 		    warnings << "Failed the initialize the sound system" << endl;
179 			bDisableSound = true;
180 		}
181     }
182 	if(bDisableSound) {
183 		notes << "soundsystem completly disabled" << endl;
184 		tLXOptions->bSoundOn = false;
185 	}
186 
187 	if( tLXOptions->bSoundOn ) {
188 		StartSoundSystem();
189 	}
190 	else
191 		StopSoundSystem();
192 
193 
194 	// Give a seed to the random number generator
195 	srand((unsigned int)time(NULL));
196 
197 	if(!bDedicated) {
198 		SmartPointer<SDL_Surface> bmpIcon = LoadGameImage("data/icon.png", true);
199 		if(bmpIcon.get())
200 			SDL_WM_SetIcon(bmpIcon.get(), NULL);
201 	}
202 
203 	InitEventQueue();
204 
205 	// Initialize the keyboard & mouse
206 	InitEventSystem();
207 
208 	// Initialize timers
209 	InitializeTimers();
210 
211 #ifdef DEBUG
212 	// Cache
213 	InitCacheDebug();
214 #endif
215 
216 
217 	return true;
218 }
219 
220 
221 #ifdef REAL_OPENGL
222 static void OGL_init();
223 #endif
224 
225 ///////////////////
226 // Set the video mode
SetVideoMode()227 bool SetVideoMode()
228 {
229 	if(bDedicated) {
230 		notes << "SetVideoMode: dedicated mode, ignoring" << endl;
231 		return true; // ignore this case
232 	}
233 
234 	if (!tLXOptions)  {
235 		warnings << "SetVideoMode: Don't know what video mode to set, ignoring" << endl;
236 		return false;
237 	}
238 
239 	bool resetting = false;
240 
241 	// Check if already running
242 	if (VideoPostProcessor::videoSurface())  {
243 		resetting = true;
244 		notes << "resetting video mode" << endl;
245 
246 		// seems to be a win-only problem, it works without problems here under MacOSX
247 #ifdef WIN32
248 		// using hw surfaces?
249 		if ((VideoPostProcessor::videoSurface()->flags & SDL_HWSURFACE) != 0) {
250 			warnings << "cannot change video mode because current mode uses hardware surfaces" << endl;
251 			// TODO: you would have to reset whole game, this is not enough!
252 			// The problem is in all allocated surfaces - they are hardware and when you switch
253 			// to window, you will most probably get software rendering
254 			// Also, hardware surfaces are freed from the video memory when reseting video mode
255 			// so you would first have to convert all surfaces to software and then perform this
256 			// TODO: in menu_options, restart the game also for fullscreen-change if hw surfaces are currently used
257 			return false;
258 		}
259 #endif
260 	} else {
261 		notes << "setting video mode" << endl;
262 	}
263 
264 	// uninit first to ensure that the video thread is not running
265 	VideoPostProcessor::uninit();
266 
267 	bool HardwareAcceleration = false;
268 	int DoubleBuf = false;
269 	int vidflags = 0;
270 
271 	// it is faster with doublebuffering in hardware accelerated mode
272 	// also, it seems that it's possible that there are effects in hardware mode with double buf disabled
273 	// Use doublebuf when hardware accelerated
274 	if (HardwareAcceleration)
275 		DoubleBuf = true;
276 
277 	// Check that the bpp is valid
278 	switch (tLXOptions->iColourDepth) {
279 	case 0:
280 	case 16:
281 	case 24:
282 	case 32:
283 		break;
284 	default: tLXOptions->iColourDepth = 16;
285 	}
286 	notes << "ColorDepth: " << tLXOptions->iColourDepth << endl;
287 
288 	// BlueBeret's addition (2007): OpenGL support
289 	bool opengl = tLXOptions->bOpenGL;
290 
291 	// Initialize the video
292 	if(tLXOptions->bFullscreen)  {
293 		vidflags |= SDL_FULLSCREEN;
294 	}
295 
296 	if (opengl) {
297 		vidflags |= SDL_OPENGL;
298 #ifndef REAL_OPENGL
299 		vidflags |= SDL_OPENGLBLIT; // SDL will behave like normally
300 #endif
301 		// HINT: it seems that with OGL activated, SDL_SetVideoMode will already set the OGL depth size
302 		// though this main pixel format of the screen surface was always 32 bit for me in OGL under MacOSX
303 		//#ifndef MACOSX
304 		/*
305 		 short colorbitsize = (tLXOptions->iColourDepth==16) ? 5 : 8;
306 		 SDL_GL_SetAttribute (SDL_GL_RED_SIZE,   colorbitsize);
307 		 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, colorbitsize);
308 		 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE,  colorbitsize);
309 		 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, colorbitsize);
310 		 //SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, tLXOptions->iColourDepth);
311 		 */
312 		//#endif
313 		//SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE,  8);
314 		//SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
315 		//SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 32);
316 		SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); // always use double buffering in OGL mode
317 	}
318 
319 	if(HardwareAcceleration)  {
320 		vidflags |= SDL_HWSURFACE | SDL_HWPALETTE | SDL_HWACCEL;
321 		// Most (perhaps all) systems use software drawing for their stuff (windows etc.)
322 		// Because of that we cannot have hardware accelerated support in window - OS screen
323 		// is software surface. How would you make the window hardware, if it's on the screen?
324 		// Anyway, SDL takes care of this by istelf and disables the flag when needed
325 		iSurfaceFormat = SDL_HWSURFACE;
326 	}
327 	else  {
328 		vidflags |= SDL_SWSURFACE;
329 		iSurfaceFormat = SDL_SWSURFACE;
330 	}
331 
332 	if(DoubleBuf && !opengl)
333 		vidflags |= SDL_DOUBLEBUF;
334 
335 #ifdef WIN32
336 	UnSubclassWindow();  // Unsubclass before doing anything with the window
337 #endif
338 
339 
340 #ifdef WIN32
341 	// Reset the video subsystem under WIN32, else we get a "Could not reset OpenGL context" error when switching mode
342 	if (opengl && tLX)  {  // Don't reset when we're setting up the mode for first time (OpenLieroX not yet initialized)
343 		SDL_QuitSubSystem(SDL_INIT_VIDEO);
344 		SDL_InitSubSystem(SDL_INIT_VIDEO);
345 	}
346 #endif
347 
348 	VideoPostProcessor::init();
349 	int scrW = VideoPostProcessor::get()->screenWidth();
350 	int scrH = VideoPostProcessor::get()->screenHeight();
351 setvideomode:
352 	if( SDL_SetVideoMode(scrW, scrH, tLXOptions->iColourDepth, vidflags) == NULL) {
353 		if (resetting)  {
354 			errors << "Failed to reset video mode"
355 					<< " (ErrorMsg: " << SDL_GetError() << "),"
356 					<< " let's wait a bit and retry" << endl;
357 			SDL_Delay(500);
358 			resetting = false;
359 			goto setvideomode;
360 		}
361 
362 		if(tLXOptions->iColourDepth != 0) {
363 			errors << "Failed to use " << tLXOptions->iColourDepth << " bpp"
364 					<< " (ErrorMsg: " << SDL_GetError() << "),"
365 					<< " trying automatic bpp detection ..." << endl;
366 			tLXOptions->iColourDepth = 0;
367 			goto setvideomode;
368 		}
369 
370 		if(vidflags & SDL_OPENGL) {
371 			errors << "Failed to use OpenGL"
372 					<< " (ErrorMsg: " << SDL_GetError() << "),"
373 					<< " trying without ..." << endl;
374 			vidflags &= ~(SDL_OPENGL | SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_HWPALETTE | SDL_HWACCEL);
375 			goto setvideomode;
376 		}
377 
378 		if(vidflags & SDL_FULLSCREEN) {
379 			errors << "Failed to set full screen video mode "
380 					<< scrW << "x" << scrH << "x" << tLXOptions->iColourDepth
381 					<< " (ErrorMsg: " << SDL_GetError() << "),"
382 					<< " trying window mode ..." << endl;
383 			vidflags &= ~SDL_FULLSCREEN;
384 			goto setvideomode;
385 		}
386 
387 		SystemError("Failed to set the video mode " + itoa(scrW) + "x" + itoa(scrH) + "x" + itoa(tLXOptions->iColourDepth) + "\nErrorMsg: " + std::string(SDL_GetError()));
388 		return false;
389 	}
390 
391 	SDL_WM_SetCaption(GetGameVersion().asHumanString().c_str(),NULL);
392 	SDL_ShowCursor(SDL_DISABLE);
393 
394 #ifdef WIN32
395 	// Hint: Reset the mouse state - this should avoid the mouse staying pressed
396 	GetMouse()->Button = 0;
397 	GetMouse()->Down = 0;
398 	GetMouse()->FirstDown = 0;
399 	GetMouse()->Up = 0;
400 
401 	if (!tLXOptions->bFullscreen)  {
402 		SubclassWindow();
403 	}
404 #endif
405 
406 	SetupTouchscreenControls();
407 	SetTouchscreenControlsShown(false);
408 
409 	// Set the change mode flag
410 	if (tLX)
411 		tLX->bVideoModeChanged = true;
412 
413 #ifdef REAL_OPENGL
414 	if((SDL_GetVideoSurface()->flags & SDL_OPENGL)) {
415 		static SDL_PixelFormat OGL_format32 =
416 		{
417 			NULL, //SDL_Palette *palette;
418 			32, //Uint8  BitsPerPixel;
419 			4, //Uint8  BytesPerPixel;
420 			0, 0, 0, 0, //Uint8  Rloss, Gloss, Bloss, Aloss;
421 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
422 			0, 8, 16, 24, //Uint8  Rshift, Gshift, Bshift, Ashift;
423 			0x000000FF,
424 			0x0000FF00,
425 			0x00FF0000,
426 			0xFF000000,
427 #else
428 			24, 16, 8, 0, //Uint8  Rshift, Gshift, Bshift, Ashift;
429 			0xFF000000,
430 			0x00FF0000,
431 			0x0000FF00,
432 			0x000000FF,
433 #endif
434 			0, //Uint32 colorkey;
435 			255 //Uint8  alpha;
436 		};
437 		// some GFX stuff in OLX seems very slow when this is used
438 		// (probably the blit from alpha surf to this format is slow)
439 	/*	static SDL_PixelFormat OGL_format24 =
440 		{
441 			NULL, //SDL_Palette *palette;
442 			24, //Uint8  BitsPerPixel;
443 			3, //Uint8  BytesPerPixel;
444 			0, 0, 0, 0, //Uint8  Rloss, Gloss, Bloss, Aloss;
445 			#if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks
446 			0, 8, 16, 0, //Uint8  Rshift, Gshift, Bshift, Ashift;
447 			0x000000FF,
448 			0x0000FF00,
449 			0x00FF0000,
450 			0x00000000,
451 			#else
452 			16, 8, 0, 0, //Uint8  Rshift, Gshift, Bshift, Ashift;
453 			0x00FF0000,
454 			0x0000FF00,
455 			0x000000FF,
456 			0x00000000,
457 			#endif
458 			0, //Uint32 colorkey;
459 			255 //Uint8  alpha;
460 		}; */
461 		//if(tLXOptions->iColourDepth == 32)
462 			mainPixelFormat = &OGL_format32;
463 		//else
464 		//	mainPixelFormat = &OGL_format24;
465 	} else
466 #endif
467 		mainPixelFormat = SDL_GetVideoSurface()->format;
468 	DumpPixelFormat(mainPixelFormat);
469 	if(SDL_GetVideoSurface()->flags & SDL_DOUBLEBUF)
470 		notes << "using doublebuffering" << endl;
471 
472 	// Correct the surface format according to SDL
473 #ifdef REAL_OPENGL
474 	if(((SDL_GetVideoSurface()->flags & SDL_OPENGL) != 0)) {
475 		iSurfaceFormat = SDL_SWSURFACE;
476 	} else
477 #endif
478 	if((SDL_GetVideoSurface()->flags & SDL_HWSURFACE) != 0)  {
479 		iSurfaceFormat = SDL_HWSURFACE;
480 		notes << "using hardware surfaces" << endl;
481 	}
482 	else {
483 		iSurfaceFormat = SDL_SWSURFACE; // HINT: under MacOSX, it doesn't seem to make any difference in performance
484 		if (HardwareAcceleration)
485 			hints << "Unable to use hardware surfaces, falling back to software." << endl;
486 		notes << "using software surfaces" << endl;
487 	}
488 
489 	if(SDL_GetVideoSurface()->flags & SDL_OPENGL) {
490 		hints << "using OpenGL" << endl;
491 
492 #ifdef REAL_OPENGL
493 		OGL_init();
494 #else
495 		FillSurface(SDL_GetVideoSurface(), Color(0, 0, 0));
496 #endif
497 	}
498 	else
499 		FillSurface(SDL_GetVideoSurface(), Color(0, 0, 0));
500 
501 	VideoPostProcessor::get()->resetVideo();
502 
503 	notes << "video mode was set successfully" << endl;
504 	return true;
505 }
506 
507 #ifdef WIN32
508 //////////////////////
509 // Get the window handle
GetWindowHandle()510 HWND GetWindowHandle()
511 {
512 	SDL_SysWMinfo info;
513 	SDL_VERSION(&info.version);
514 	if(!SDL_GetWMInfo(&info))
515 		return 0;
516 
517 	return info.window;
518 }
519 #endif
520 
521 
CapFPS()522 void CapFPS() {
523 	const TimeDiff fMaxFrameTime = TimeDiff( (tLXOptions->nMaxFPS > 0) ? (1.0f / (float)tLXOptions->nMaxFPS) : 0.0f );
524 	const AbsTime currentTime = GetTime();
525 	// tLX->currentTime is old time
526 
527 	// Cap the FPS
528 	if(currentTime - tLX->currentTime < fMaxFrameTime)
529 		SDL_Delay((Uint32)(fMaxFrameTime - (currentTime - tLX->currentTime)).milliseconds());
530 	else
531 		// do at least one small break, else it's possible that we never receive signals from our OS
532 		SDL_Delay(1);
533 }
534 
535 
536 // Screenshot structure
537 struct screenshot_t {
538 	std::string sDir;
539 	std::string	sData;
540 };
541 
542 struct ScreenshotQueue {
543 	std::list<screenshot_t> queue;
544 	SDL_mutex* mutex;
ScreenshotQueueScreenshotQueue545 	ScreenshotQueue() : mutex(NULL) { mutex = SDL_CreateMutex(); }
~ScreenshotQueueScreenshotQueue546 	~ScreenshotQueue() { SDL_DestroyMutex(mutex); mutex = NULL; }
547 };
548 
549 static ScreenshotQueue screenshotQueue;
550 
PushScreenshot(const std::string & dir,const std::string & data)551 void PushScreenshot(const std::string& dir, const std::string& data) {
552 	screenshot_t scr; scr.sDir = dir; scr.sData = data;
553 	ScopedLock lock(screenshotQueue.mutex);
554 	screenshotQueue.queue.push_back(scr);
555 }
556 
557 static void TakeScreenshot(const std::string& scr_path, const std::string& additional_data);
558 
559 ////////////////
560 // Process any screenshots
ProcessScreenshots()561 void ProcessScreenshots()
562 {
563 	std::list<screenshot_t> scrs;
564 	{
565 		ScopedLock lock(screenshotQueue.mutex);
566 		scrs.swap(screenshotQueue.queue);
567 	}
568 
569 	// Process all the screenhots in the queue
570 	for (std::list<screenshot_t>::iterator it = scrs.begin(); it != scrs.end(); it++)  {
571 		TakeScreenshot(it->sDir, it->sData);
572 	}
573 }
574 
575 
576 
577 
578 #ifdef REAL_OPENGL
579 
OGL_createTexture()580 static GLuint OGL_createTexture() {
581 	GLuint textureid;
582 
583 	// create one texture name
584 	glGenTextures(1, &textureid);
585 
586 	// tell opengl to use the generated texture name
587 	glBindTexture(GL_TEXTURE_2D, textureid);
588 
589 	// these affect how this texture is drawn later on...
590 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
591 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
592 
593 	return textureid;
594 }
595 
OGL_setupScreenForSingleTexture(GLuint textureid,int w,int h)596 static void OGL_setupScreenForSingleTexture(GLuint textureid, int w, int h) {
597 
598 	glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_POLYGON_BIT);
599 	glDisable(GL_DEPTH_TEST);
600 	glDisable (GL_LIGHTING);
601 	glDisable (GL_LINE_SMOOTH);
602 	glDisable (GL_CULL_FACE);
603 	glEnable (GL_BLEND);
604 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
605 	glViewport(0, 0, w, h);
606 	glMatrixMode (GL_PROJECTION);
607 	glPushMatrix ();
608 	glLoadIdentity ();
609 	glOrtho (0, (GLdouble)w, 0, (GLdouble)h, -1, 1);
610 	glMatrixMode (GL_MODELVIEW);
611 	glPushMatrix ();
612 	glLoadIdentity ();
613 
614 	glEnable(GL_TEXTURE_2D);
615 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
616 	glBindTexture (GL_TEXTURE_2D, textureid);
617 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
618 
619 	int x = 0, y = 0;
620 	glPushMatrix ();
621 	glTranslated (x, y, 0);
622 	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
623 
624 	int realw = 1; while(realw < 640) realw <<= 1;
625 	int realh = 1; while(realh < 480) realh <<= 1;
626 	float texW = 640 / (float)realw;
627 	float texH = 480 / (float)realh;
628 
629 	glBegin(GL_QUADS);
630 	{
631 		glTexCoord2f (0, 0);
632 		glVertex2i (0, h);
633 		glTexCoord2f (texW, 0);
634 		glVertex2i (w, h);
635 		glTexCoord2f (texW, texH);
636 		glVertex2i (w, 0);
637 		glTexCoord2f (0, texH);
638 		glVertex2i (0, 0);
639 	}
640 	glEnd();
641 
642 	glPopMatrix ();
643 
644 	/* Leave "2D mode" */
645 	glMatrixMode (GL_PROJECTION);
646 	glPopMatrix ();
647 	glMatrixMode (GL_MODELVIEW);
648 	glPopMatrix();
649 	glPopAttrib();
650 
651 }
652 
653 static GLuint OGL_screenBuf = 0;
654 
OGL_init()655 static void OGL_init() {
656 	glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set black background
657 
658 	OGL_screenBuf = OGL_createTexture();
659 }
660 
OGL_draw(SDL_Surface * src)661 static void OGL_draw(SDL_Surface* src) {
662 	// tell opengl to use the generated texture name
663 	glBindTexture(GL_TEXTURE_2D, OGL_screenBuf);
664 
665 	int mode = 0;
666 	if(src->format->BytesPerPixel == 3)
667 		mode = GL_RGB;
668 	else
669 		mode = GL_RGBA;
670 
671 	// this reads from the sdl surface and puts it into an opengl texture
672 	glTexImage2D(GL_TEXTURE_2D, 0, mode, src->w, src->h, 0, mode, GL_UNSIGNED_BYTE, src->pixels);
673 
674 	int w = VideoPostProcessor::get()->screenWidth();
675 	int h = VideoPostProcessor::get()->screenHeight();
676 	OGL_setupScreenForSingleTexture(OGL_screenBuf, w, h);
677 }
678 #endif
679 
680 
681 
682 // ---------------- VideoPostProcessor ---------------------------------------------------------
683 
684 VideoPostProcessor voidVideoPostProcessor; // this one does nothing
685 
686 SDL_Surface* VideoPostProcessor::m_videoSurface = NULL;
687 SDL_Surface* VideoPostProcessor::m_videoBufferSurface = NULL;
688 VideoPostProcessor* VideoPostProcessor::instance = &voidVideoPostProcessor;
689 
690 ///////////////////
691 // Flip the screen
flipRealVideo()692 void flipRealVideo() {
693 	SDL_Surface* psScreen = SDL_GetVideoSurface();
694 	if(psScreen == NULL) return;
695 
696 	//TestCircleDrawing(psScreen);
697 	//TestPolygonDrawing(psScreen);
698 	//DrawLoadingAni(psScreen, 320, 260, 50, 50, Color(128,128,128), Color(128,128,128,128), LAT_CIRCLES);
699 	//DrawLoadingAni(psScreen, 320, 260, 10, 10, Color(255,0,0), Color(0,255,0), LAT_CAKE);
700 
701 #ifdef REAL_OPENGL
702 	if((psScreen->flags & SDL_OPENGL))
703 		glFlush();
704 	else
705 #endif
706 		SDL_Flip( psScreen );
707 
708 	if(psScreen->flags & SDL_OPENGL)
709 		SDL_GL_SwapBuffers();
710 }
711 
712 // base class for your video post processor
713 // this base manages the video surface and its buffer
714 class BasicVideoPostProcessor : public VideoPostProcessor {
715 public:
716 	SmartPointer<SDL_Surface> m_screenBuf[2];
717 
resetVideo()718 	virtual void resetVideo() {
719 		// IMPORTANT: Don't reallocate if we already have the buffers.
720 		// If we would do, the old surfaces would get deleted. This is bad
721 		// because other threads could use it right now.
722 		if(m_screenBuf[0].get()) return;
723 
724 		// create m_screenBuf here to ensure that we have initialised the correct surface parameters like pixel format
725 #ifdef REAL_OPENGL
726 		if((SDL_GetVideoSurface()->flags & SDL_OPENGL)) {
727 			// get smallest power-of-2 dimension which is bigger than src
728 			int w = 1; while(w < 640) w <<= 1;
729 			int h = 1; while(h < 480) h <<= 1;
730 			m_screenBuf[0] = gfxCreateSurface(w, h);
731 			m_screenBuf[1] = gfxCreateSurface(w, h);
732 		} else
733 #endif
734 		{
735 			m_screenBuf[0] = gfxCreateSurface(640, 480);
736 			m_screenBuf[1] = gfxCreateSurface(640, 480);
737 		}
738 
739 		m_videoSurface = m_screenBuf[0].get();
740 		m_videoBufferSurface = m_screenBuf[1].get();
741 	}
742 };
743 
744 // There is one usage of this: If you want to let OLX manage the double buffering.
745 // In this case, all the flipping and copying is done in the video thread.
746 // Without a post processor, the flipping is done in the main thread.
747 // There are some rare situations where the flipping of the screen surface is slow
748 // and in this situations, it can be faster to use this dummy post processor.
749 class DummyVideoPostProc : public BasicVideoPostProcessor {
750 public:
DummyVideoPostProc()751 	DummyVideoPostProc() {
752 		notes << "using Dummy video post processor" << endl;
753 	}
754 
processToScreen()755 	virtual void processToScreen() {
756 #ifdef REAL_OPENGL
757 		if((SDL_GetVideoSurface()->flags & SDL_OPENGL)) {
758 			OGL_draw(m_videoBufferSurface);
759 		}
760 		else
761 #endif
762 			DrawImageAdv(SDL_GetVideoSurface(), m_videoBufferSurface, 0, 0, 0, 0, 640, 480);
763 	}
764 
765 };
766 
767 class StretchHalfPostProc : public BasicVideoPostProcessor {
768 public:
769 	static const int W = 320;
770 	static const int H = 240;
771 
StretchHalfPostProc()772 	StretchHalfPostProc() {
773 		notes << "using StretchHalf video post processor" << endl;
774 	}
775 
processToScreen()776 	virtual void processToScreen() {
777 		DrawImageScaleHalf(SDL_GetVideoSurface(), m_videoBufferSurface);
778 		//DrawImageResizedAdv(SDL_GetVideoSurface(), m_videoBufferSurface, 0, 0, 0, 0, 640, 480, W, H);
779 		//DrawImageResampledAdv(SDL_GetVideoSurface(), m_videoBufferSurface, 0, 0, 0, 0, 640, 480, W, H);
780 	}
781 
screenWidth()782 	virtual int screenWidth() { return W; }
screenHeight()783 	virtual int screenHeight() { return H; }
784 
785 };
786 
787 class Scale2XPostProc : public BasicVideoPostProcessor {
788 public:
789 	static const int W = 640 * 2;
790 	static const int H = 480 * 2;
791 
Scale2XPostProc()792 	Scale2XPostProc() {
793 		notes << "using Scale2x video post processor" << endl;
794 	}
795 
processToScreen()796 	virtual void processToScreen() {
797 		DrawImageScale2x(SDL_GetVideoSurface(), m_videoBufferSurface, 0, 0, 0, 0, 640, 480);
798 	}
799 
screenWidth()800 	virtual int screenWidth() { return W; }
screenHeight()801 	virtual int screenHeight() { return H; }
802 
803 };
804 
805 
806 
807 
808 // IMPORTANT: this has to be called from main thread!
process()809 void VideoPostProcessor::process() {
810 	ProcessScreenshots();
811 	VideoPostProcessor::get()->processToScreen();
812 }
813 
cloneBuffer()814 void VideoPostProcessor::cloneBuffer() {
815 	// TODO: don't hardcode screen width/height here
816 	DrawImageAdv(m_videoBufferSurface, m_videoSurface, 0, 0, 0, 0, 640, 480);
817 }
818 
init()819 void VideoPostProcessor::init() {
820 	notes << "VideoPostProcessor initialisation ... ";
821 
822 	std::string vppName = tLXOptions->sVideoPostProcessor;
823 	TrimSpaces(vppName); stringlwr(vppName);
824 	if(vppName == "stretchhalf")
825 		instance = new StretchHalfPostProc();
826 	else if(vppName == "scale2x")
827 		instance = new Scale2XPostProc();
828 	else if(vppName == "dummy")
829 		instance = new DummyVideoPostProc();
830 	else {
831 		if(vppName != "")
832 			notes << "\"" << tLXOptions->sVideoPostProcessor << "\" unknown; ";
833 		// notes << "none used, drawing directly on screen" << endl;
834 		//instance = &voidVideoPostProcessor;
835 		instance = new DummyVideoPostProc();
836 	}
837 }
838 
uninit()839 void VideoPostProcessor::uninit() {
840 	if(instance != &voidVideoPostProcessor && instance != NULL)
841 		delete instance;
842 	instance = &voidVideoPostProcessor;
843 
844 	m_videoSurface = NULL; // should never be used before resetVideo() is called
845 }
846 
847 
848 
transformCoordinates_ScreenToVideo(int & x,int & y)849 void VideoPostProcessor::transformCoordinates_ScreenToVideo( int& x, int& y ) {
850 	x = (int)((float)x * 640.0f / (float)get()->screenWidth());
851 	y = (int)((float)y * 480.0f / (float)get()->screenHeight());
852 }
853 
854 
855 // ---------------------------------------------------------------------------------------------
856 
857 
858 
859 
860 
861 ///////////////////
862 // Shutdown the standard Auxiliary Library
ShutdownAuxLib()863 void ShutdownAuxLib()
864 {
865 #ifdef WIN32
866 	UnSubclassWindow();
867 #endif
868 
869 	// free all cached stuff like surfaces and sounds
870 	// HINT: we have to do it before we uninit the specific engines
871 	cCache.Clear();
872 
873 	VideoPostProcessor::uninit();
874 	// quit video at this point to not get stuck in a fullscreen not responding game in case that it crashes in further quitting
875 	// in the case it wasn't inited at this point, this also doesn't hurt
876 	SDL_QuitSubSystem( SDL_INIT_VIDEO );
877 
878 	QuitSoundSystem();
879 
880 	// Shutdown the error system
881 	EndError();
882 
883 #ifdef WIN32
884 	UnSubclassWindow();
885 #endif
886 
887 	// Shutdown the SDL system
888 	// HINT: Sometimes we get a segfault here. Because
889 	// all important stuff is already closed and save here, it's not that
890 	// important to do any more cleanup.
891 #if SDLMIXER_WORKAROUND_RESTART == 1
892 	if(bRestartGameAfterQuit)
893 		// quit everything but audio
894 		SDL_QuitSubSystem( SDL_WasInit(0) & (~SDL_INIT_AUDIO) );
895 	else
896 #endif
897 		SDL_Quit();
898 }
899 
900 
901 
902 
903 
904 ///////////////////
905 // Return the config filename
GetConfigFile()906 std::string GetConfigFile()
907 {
908 	return ConfigFile;
909 }
910 
911 
912 //////////////////
913 // Helper funtion for screenshot taking
GetPicName(const std::string & prefix,size_t i,const std::string & ext)914 static std::string GetPicName(const std::string& prefix, size_t i, const std::string& ext)
915 {
916 	return prefix + (i == 0 ? std::string("") : itoa(i)) + ext;
917 }
918 
919 
920 ////////////////////
921 // Helper function for TakeScreenshot
GetScreenshotFileName(const std::string & scr_path,const std::string & extension)922 static std::string GetScreenshotFileName(const std::string& scr_path, const std::string& extension)
923 {
924 	std::string path = scr_path;
925 
926 	// Append a slash if not present
927 	if (path[path.size() - 1] != '/' && path[path.size() - 1] != '\\')  {
928 		path += '/';
929 	}
930 
931 
932 	std::string filePrefix = GetDateTimeFilename();
933 	filePrefix += "-";
934 	if( tLX )
935 	{
936 		if( tLX->iGameType == GME_LOCAL )
937 			filePrefix += "local";
938 		else if( tLX->iGameType == GME_HOST && cServer )
939 			filePrefix += cServer->getName();
940 		else if( cClient )
941 			filePrefix += cClient->getServerName();
942 	}
943 
944 	// Make filename more fileststem-friendly
945 	if( filePrefix.size() > 64 )
946 		filePrefix.resize(64);
947 
948 #define S_LETTER_UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
949 #define S_LETTER_LOWER "abcdefghijklmnopqrstuvwxyz"
950 #define S_LETTER S_LETTER_UPPER S_LETTER_LOWER
951 #define S_NUMBER "0123456789"
952 #define S_SYMBOL ". -_&+"	// No "\\" symbol, no tab.
953 #define S_VALID_FILENAME S_LETTER_UPPER S_LETTER_LOWER S_NUMBER S_SYMBOL
954 	while( filePrefix.find_first_not_of(S_VALID_FILENAME) != std::string::npos )
955 		filePrefix[ filePrefix.find_first_not_of(S_VALID_FILENAME) ] = '-';
956 
957 	static const size_t step = 256; // Step; after how many files we check if the filename still exists
958 
959 	// We start at range from 1 to step
960 	size_t lower_bound = 0;
961 	size_t upper_bound = step;
962 
963 	std::string fullname(path + GetPicName(filePrefix, upper_bound, extension));
964 
965 	// Find a raw range of where the screenshot filename could be
966 	// For example: between lierox1000.png and lierox1256.png
967 	while (IsFileAvailable(fullname, false))  {
968 		lower_bound = upper_bound;
969 		upper_bound += step;
970 
971 		fullname = path + GetPicName(filePrefix, upper_bound, extension);
972 	}
973 
974 	// First file?
975 	if (!IsFileAvailable(path + GetPicName(filePrefix, lower_bound, extension)))
976 		return path + GetPicName(filePrefix, lower_bound, extension);
977 
978 	// Use binary search on the given range to find the exact file name
979 	size_t i = (lower_bound + upper_bound) / 2;
980 	while (true)  {
981 		if (IsFileAvailable(path + GetPicName(filePrefix, i, extension), false))  {
982 			// If the current (i) filename exists, but the i+1 does not, we're done
983 			if (!IsFileAvailable(path + GetPicName(filePrefix, i + 1, extension)))
984 				return path + GetPicName(filePrefix, i + 1, extension);
985 			else  {
986 				// The filename is somewhere in the interval (i, upper_bound)
987 				lower_bound = i;
988 				i = (lower_bound + upper_bound) / 2;
989 			}
990 		} else {
991 			// The filename is somewhere in the interval (lower_bound, i)
992 			upper_bound = i;
993 			i = (lower_bound + upper_bound) / 2;
994 		}
995 	}
996 
997 	return ""; // Should not happen
998 }
999 
1000 ///////////////////
1001 // Take a screenshot
TakeScreenshot(const std::string & scr_path,const std::string & additional_data)1002 static void TakeScreenshot(const std::string& scr_path, const std::string& additional_data)
1003 {
1004 	if (scr_path.empty()) // Check
1005 		return;
1006 
1007 	notes << "Save screenshot to " << scr_path << endl;
1008 
1009 	std::string	extension;
1010 
1011 	// Set the extension
1012 	switch (tLXOptions->iScreenshotFormat)  {
1013 	case FMT_BMP: extension = ".bmp"; break;
1014 	case FMT_PNG: extension = ".png"; break;
1015 	case FMT_JPG: extension = ".jpg"; break;
1016 	case FMT_GIF: extension = ".gif"; break;
1017 	default: extension = ".png";
1018 	}
1019 
1020 	// Save the surface
1021 	SaveSurface(VideoPostProcessor::videoBufferSurface(), GetScreenshotFileName(scr_path, extension),
1022 		tLXOptions->iScreenshotFormat, additional_data);
1023 }
1024 
1025 #ifdef WIN32
1026 LONG wpOriginal;
1027 bool Subclassed = false;
1028 
1029 ////////////////////
1030 // Subclass the window (control the incoming Windows messages)
SubclassWindow()1031 void SubclassWindow()
1032 {
1033 	if (Subclassed)
1034 		return;
1035 
1036 #pragma warning(disable:4311)  // Temporarily disable, the typecast is OK here
1037 	wpOriginal = SetWindowLong(GetWindowHandle(),GWL_WNDPROC,(LONG)(&WindowProc));
1038 #pragma warning(default:4311) // Enable the warning
1039 	Subclassed = true;
1040 }
1041 
1042 ////////////////////
1043 // Remove the subclassing
UnSubclassWindow()1044 void UnSubclassWindow()
1045 {
1046 	if (!Subclassed)
1047 		return;
1048 
1049 	SetWindowLong(GetWindowHandle(),GWL_WNDPROC, wpOriginal);
1050 
1051 	Subclassed = false;
1052 }
1053 
1054 /////////////////////
1055 // Subclass callback
WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1056 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1057 {
1058 	// Ignore the unwanted messages
1059 	switch (uMsg)  {
1060 	case WM_ENTERMENULOOP:
1061 		return 0;
1062 	case WM_INITMENU:
1063 		return 0;
1064 	case WM_MENUSELECT:
1065 		return 0;
1066 	case WM_SYSKEYUP:
1067 		return 0;
1068 	}
1069 
1070 #pragma warning(disable:4312)
1071 	return CallWindowProc((WNDPROC)wpOriginal,hwnd,uMsg,wParam,lParam);
1072 #pragma warning(default:4312)
1073 }
1074 
1075 //////////////////////
1076 // unsetenv for WIN32, taken from libc source
unsetenv(const char * name)1077 int unsetenv(const char *name)
1078 {
1079   size_t len;
1080   char **ep;
1081 
1082   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
1083     {
1084       return -1;
1085     }
1086 
1087   len = strlen (name);
1088 
1089   ep = _environ;
1090   while (*ep != NULL)
1091     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
1092       {
1093 	/* Found it.  Remove this pointer by moving later ones back.  */
1094 	char **dp = ep;
1095 
1096 	do
1097 	  dp[0] = dp[1];
1098 	while (*dp++);
1099 	/* Continue the loop in case NAME appears again.  */
1100       }
1101     else
1102       ++ep;
1103 
1104   return 0;
1105 }
1106 #endif
1107 
1108 
1109 
1110 
1111 #ifdef DEBUG
1112 #include "CClient.h"
1113 
1114 // TODO: move this to console (it was only nec. via chat because we didn't had the console globally before)
1115 // HINT: This is called atm from CClientNetEngine::SendText().
1116 // HINT: This is just a hack to do some testing in lobby or whatever.
1117 // WARNING: These stuff is not intended to be stable, it's only for testing!
1118 // HINT: Don't rely on this. If we allow the console later somehow in the lobby,
1119 // this debug stuff will probably move there.
HandleDebugCommand(const std::string & text)1120 bool HandleDebugCommand(const std::string& text) {
1121 	if(text.size() >= 3 && text.substr(0,3) == "///") {
1122 		cClient->getChatbox()->AddText("DEBUG COMMAND", tLX->clNotice, TXT_NOTICE, tLX->currentTime);
1123 
1124 		std::string cmd = text.substr(3);
1125 		stringlwr(cmd);
1126 
1127 		if(cmd == "reconnect") {
1128 			notes << "DEBUG CMD: reconnect local client to " << cClient->getServerAddress() << endl;
1129 			cClient->Connect(cClient->getServerAddress());
1130 		} else if(cmd == "msgbox") {
1131 			Menu_MessageBox("Test",
1132 							"This is a very long text, a very long text, a very long text, a very long text, "
1133 							"a very long text, a very long text, a very long text, a very long text, a very long text, "
1134 							"a very long text, a very long text, a very long text, a very long text, a very long text, "
1135 							"a very long text, a very long text, a very long text, a very long text, a very long text.\n"
1136 							"Yes really, this text is very long, very long, very long, very long, very long, "
1137 							"very very long, very very long, very very long, very very long, very very long.",
1138 							DeprecatedGUI::LMB_OK);
1139 		} else if(cmd == "register") {
1140 			cServer->RegisterServer();
1141 		} else
1142 			notes << "DEBUG CMD unknown" << endl;
1143 
1144 		return true;
1145 	}
1146 	return false;
1147 }
1148 #endif
1149 
1150 
1151 
1152 //////////////////
1153 // Gives a name to the thread
1154 // Code taken from http://www.codeproject.com/KB/threads/Name_threads_in_debugger.aspx
setCurThreadName(const std::string & name)1155 void setCurThreadName(const std::string& name)
1156 {
1157 #ifdef _MSC_VER // Currently only for MSVC, haven't found a Windows-general way (I doubt there is one)
1158 	typedef struct tagTHREADNAME_INFO
1159 	{
1160 		DWORD dwType; // Must be 0x1000.
1161 		LPCSTR szName; // Pointer to name (in user addr space).
1162 		DWORD dwThreadID; // Thread ID (-1=caller thread).
1163 		DWORD dwFlags; // Reserved for future use, must be zero.
1164 	} THREADNAME_INFO;
1165 
1166 	THREADNAME_INFO info;
1167 	{
1168 		info.dwType = 0x1000;
1169 		info.szName = name.c_str();
1170 		info.dwThreadID = (DWORD)-1;
1171 		info.dwFlags = 0;
1172 	}
1173 
1174 	__try
1175 	{
1176 		RaiseException( 0x406D1388 /* MSVC EXCEPTION */, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
1177 	}
1178 	__except (EXCEPTION_CONTINUE_EXECUTION)
1179 	{
1180 	}
1181 #else
1182 	// TODO: similar for other systems
1183 #endif
1184 }
1185 
setCurThreadPriority(float p)1186 void setCurThreadPriority(float p) {
1187 #ifdef WIN32
1188 
1189 #elif defined(__APPLE__)
1190 	//int curp = getpriority(PRIO_DARWIN_THREAD, 0);
1191 	//int newp = p >= 0 ? 0 : 1;
1192 	//notes << "curp:" << curp << ", newp:" << newp << endl;
1193 	//setpriority(PRIO_DARWIN_THREAD, 0, newp);
1194 #endif
1195 }
1196 
1197 
1198 
GetFreeSysMemory()1199 size_t GetFreeSysMemory() {
1200 #if defined(__APPLE__)
1201 	vm_statistics_data_t page_info;
1202 	vm_size_t pagesize;
1203 	mach_msg_type_number_t count;
1204 	kern_return_t kret;
1205 
1206 	pagesize = 0;
1207 	kret = host_page_size (mach_host_self(), &pagesize);
1208 	count = HOST_VM_INFO_COUNT;
1209 
1210 	kret = host_statistics (mach_host_self(), HOST_VM_INFO,(host_info_t)&page_info, &count);
1211 	return page_info.free_count * pagesize;
1212 #elif defined(__WIN64__)
1213 	MEMORYSTATUSEX memStatex;
1214 	memStatex.dwLength = sizeof (memStatex);
1215 	::GlobalMemoryStatusEx (&memStatex);
1216 	return memStatex.ullAvailPhys;
1217 #elif defined(__WIN32__)
1218 	MEMORYSTATUS memStatus;
1219 	memStatus.dwLength = sizeof(MEMORYSTATUS);
1220 	::GlobalMemoryStatus(&memStatus);
1221 	return memStatus.dwAvailPhys;
1222 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1223 	return sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE);
1224 #elif defined(__FREEBSD__)
1225 	int vm_vmtotal[] = { CTL_VM, VM_METER };
1226 	struct vmtotal vmdata;
1227 
1228 	size_t len = sizeof(vmdata);
1229         int result = sysctl(vm_vmtotal, sizeof(vm_vmtotal) / sizeof(*vm_vmtotal), &vmdata, &len, NULL, 0);
1230 	if(result != 0) return 0;
1231 
1232 	return vmdata.t_free * sysconf(_SC_PAGESIZE);
1233 #elif defined(__linux__)
1234 
1235 	// get it from /proc/meminfo
1236 	FILE *fp = fopen("/proc/meminfo", "r");
1237 	if ( fp )
1238 	{
1239 		unsigned long freeMem = 0;
1240 		unsigned long buffersMem = 0;
1241 		unsigned long cachedMem = 0;
1242 		struct SearchTerm { const char* name; unsigned long* var; };
1243 		SearchTerm terms[] = { {"MemFree:", &freeMem}, {"Buffers:", &buffersMem}, {"Cached:", &cachedMem} };
1244 
1245 		char buf[1024];
1246 		int n = fread(buf, sizeof(char), sizeof(buf) - 1, fp);
1247 		buf[sizeof(buf)-1] = '\0';
1248 		if(n > 0) {
1249 			for(unsigned int i = 0; i < sizeof(terms) / sizeof(SearchTerm); ++i) {
1250 				char* p = strstr(buf, terms[i].name);
1251 				if(p) {
1252 					p += strlen(terms[i].name);
1253 					*terms[i].var = strtoul(p, NULL, 10);
1254 				}
1255 			}
1256 		}
1257 
1258 		fclose(fp);
1259 		// it's written in KB in meminfo
1260 		return ((size_t)freeMem + (size_t)buffersMem + (size_t)cachedMem) * 1024;
1261 	}
1262 
1263 	return 0;
1264 #else
1265 #warning No GetFreeSysMemory implementation for this arch/sys
1266 	return 50 * 1024 * 1024; // return 50 MB (really randomly made up, but helps for cache system)
1267 #endif
1268 }
1269 
1270 
1271 
setupInputs()1272 void lierox_t::setupInputs() {
1273 	if(!tLXOptions) {
1274 		errors << "lierox_t::setupInputs: tLXOptions not set" << endl;
1275 		return;
1276 	}
1277 
1278 	// Setup global keys
1279 	cTakeScreenshot.Setup(tLXOptions->sGeneralControls[SIN_SCREENSHOTS]);
1280 	cSwitchMode.Setup(tLXOptions->sGeneralControls[SIN_SWITCHMODE]);
1281 	cIrcChat.Setup(tLXOptions->sGeneralControls[SIN_IRCCHAT]);
1282 	cConsoleToggle.Setup(tLXOptions->sGeneralControls[SIN_CONSOLETOGGLE]);
1283 
1284 	if(cClient)
1285 		cClient->SetupGameInputs();
1286 	else
1287 		warnings << "lierox_t::setupInputs: cClient not set" << endl;
1288 }
1289 
isAnyControlKeyDown() const1290 bool lierox_t::isAnyControlKeyDown() const {
1291 	return cTakeScreenshot.isDown() || cSwitchMode.isDown() || cIrcChat.isDown() || cConsoleToggle.isDown();
1292 }
1293 
1294 
1295 
GetDateTimeText()1296 std::string GetDateTimeText()
1297 {
1298 	time_t t = time(NULL);
1299 
1300 	if (t == (time_t)-1)
1301 		return "TIME-ERROR1";
1302 
1303 	char* timeCstr = ctime(&t);
1304 	if(timeCstr == NULL)
1305 		return "TIME-ERROR2";
1306 
1307 	std::string timeStr(timeCstr);
1308 	TrimSpaces(timeStr);
1309 	return timeStr;
1310 }
1311 
GetDateTimeFilename()1312 std::string GetDateTimeFilename()
1313 {
1314 	// Add date and server name to screenshot filename
1315 	time_t curtime1 = time(NULL);
1316 	if (curtime1 == (time_t)-1)
1317 		return "TIME-ERROR1";
1318 	struct tm *curtime = localtime(&curtime1);
1319 	if (curtime == NULL)
1320 		return "TIME-ERROR2";
1321 	char filePrefixTime[200] = {0};
1322 	strftime(filePrefixTime, sizeof(filePrefixTime), "%Y%m%d-%H%M", curtime);
1323 	return filePrefixTime;
1324 }
1325 
EnableSystemMouseCursor(bool enable)1326 void EnableSystemMouseCursor(bool enable)
1327 {
1328 	if( bDedicated )
1329 		return;
1330 	struct EnableMouseCursor: public Action
1331 	{
1332 		bool Enable;
1333 
1334 		EnableMouseCursor(bool b): Enable(b) {};
1335 		int handle()
1336 		{
1337 			SDL_ShowCursor(Enable ? SDL_ENABLE : SDL_DISABLE ); // Should be called from main thread, or you'll get race condition with libX11
1338 			return 0;
1339 		}
1340 	};
1341 	doActionInMainThread( new EnableMouseCursor(enable) );
1342 };
1343