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