Refactor: BLI_path_util (part 2)
[blender.git] / source / gameengine / GamePlayer / ghost / GPG_ghost.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * Start up of the Blender Player on GHOST.
27  */
28
29 /** \file gameengine/GamePlayer/ghost/GPG_ghost.cpp
30  *  \ingroup player
31  */
32
33
34 #include <iostream>
35 #include <math.h>
36
37 #ifdef __linux__
38 #ifdef __alpha__
39 #include <signal.h>
40 #endif /* __alpha__ */
41 #endif /* __linux__ */
42
43 #include "KX_KetsjiEngine.h"
44 #include "KX_PythonInit.h"
45 #include "KX_PythonMain.h"
46
47 /**********************************
48 * Begin Blender include block
49 **********************************/
50 #ifdef __cplusplus
51 extern "C"
52 {
53 #endif  // __cplusplus
54 #include "MEM_guardedalloc.h"
55 #include "MEM_CacheLimiterC-Api.h"
56
57 #include "BLI_threads.h"
58 #include "BLI_mempool.h"
59 #include "BLI_blenlib.h"
60
61 #include "DNA_scene_types.h"
62 #include "DNA_userdef_types.h"
63
64 #include "BLO_readfile.h"
65 #include "BLO_runtime.h"
66
67 #include "BKE_appdir.h"
68 #include "BKE_blender.h"
69 #include "BKE_depsgraph.h"
70 #include "BKE_global.h"
71 #include "BKE_icons.h"
72 #include "BKE_image.h"
73 #include "BKE_node.h"
74 #include "BKE_report.h"
75 #include "BKE_library.h"
76 #include "BKE_modifier.h"
77 #include "BKE_text.h"
78 #include "BKE_sound.h"
79
80 #include "IMB_imbuf.h"
81 #include "IMB_moviecache.h"
82         
83 // For BLF
84 #include "BLF_api.h"
85 #include "BLF_translation.h"
86 extern int datatoc_bfont_ttf_size;
87 extern char datatoc_bfont_ttf[];
88 extern int datatoc_bmonofont_ttf_size;
89 extern char datatoc_bmonofont_ttf[];
90
91 #ifdef __cplusplus
92 }
93 #endif // __cplusplus
94
95 #include "GPU_draw.h"
96
97 /**********************************
98 * End Blender include block
99 **********************************/
100
101 #include "BL_System.h"
102 #include "GPG_Application.h"
103
104 #include "GHOST_ISystem.h"
105 #include "RAS_IRasterizer.h"
106
107 #include "BKE_main.h"
108
109 #include "RNA_define.h"
110
111 #ifdef WIN32
112 #include <windows.h>
113 #if !defined(DEBUG)
114 #include <wincon.h>
115 #endif // !defined(DEBUG)
116 #endif // WIN32
117
118 #ifdef WITH_SDL_DYNLOAD
119 #  include "sdlew.h"
120 #endif
121
122 const int kMinWindowWidth = 100;
123 const int kMinWindowHeight = 100;
124
125 static void mem_error_cb(const char *errorStr)
126 {
127         fprintf(stderr, "%s", errorStr);
128         fflush(stderr);
129 }
130
131 // library.c will only free window managers with a callback function.
132 // We don't actually use a wmWindowManager, but loading a blendfile
133 // loads wmWindows, so we need to free those.
134 static void wm_free(bContext *C, wmWindowManager *wm)
135 {
136         BLI_freelistN(&wm->windows);
137 }
138
139 #ifdef WIN32
140 typedef enum {
141         SCREEN_SAVER_MODE_NONE = 0,
142         SCREEN_SAVER_MODE_PREVIEW,
143         SCREEN_SAVER_MODE_SAVER,
144         SCREEN_SAVER_MODE_CONFIGURATION,
145         SCREEN_SAVER_MODE_PASSWORD,
146 } ScreenSaverMode;
147
148 static ScreenSaverMode scr_saver_mode = SCREEN_SAVER_MODE_NONE;
149 static HWND scr_saver_hwnd = NULL;
150
151 static BOOL scr_saver_init(int argc, char **argv) 
152 {
153         scr_saver_mode = SCREEN_SAVER_MODE_NONE;
154         scr_saver_hwnd = NULL;
155         BOOL ret = false;
156
157         int len = ::strlen(argv[0]);
158         if (len > 4 && !::stricmp(".scr", argv[0] + len - 4))
159         {
160                 scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION;
161                 ret = true;
162                 if (argc >= 2)
163                 {
164                         if (argc >= 3)
165                         {
166                                 scr_saver_hwnd = (HWND) ::atoi(argv[2]);
167                         }
168                         if (!::stricmp("/c", argv[1]))
169                         {
170                                 scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION;
171                                 if (scr_saver_hwnd == NULL)
172                                         scr_saver_hwnd = ::GetForegroundWindow();
173                         }
174                         else if (!::stricmp("/s", argv[1]))
175                         {
176                                 scr_saver_mode = SCREEN_SAVER_MODE_SAVER;
177                         }
178                         else if (!::stricmp("/a", argv[1]))
179                         {
180                                 scr_saver_mode = SCREEN_SAVER_MODE_PASSWORD;
181                         }
182                         else if (!::stricmp("/p", argv[1])
183                                  || !::stricmp("/l", argv[1]))
184                         {
185                                 scr_saver_mode = SCREEN_SAVER_MODE_PREVIEW;
186                         }
187                 }
188         }
189         return ret;
190 }
191
192 #endif /* WIN32 */
193
194 static void usage(const char* program, bool isBlenderPlayer)
195 {
196         const char * consoleoption;
197         const char * example_filename = "";
198         const char * example_pathname = "";
199
200 #ifdef _WIN32
201         consoleoption = "[-c] ";
202 #else
203         consoleoption = "";
204 #endif
205
206         if (isBlenderPlayer) {
207                 example_filename = "filename.blend";
208 #ifdef _WIN32
209                 example_pathname = "c:\\";
210 #else
211                 example_pathname = "/home/user/";
212 #endif
213         }
214         printf("\n");
215         printf("usage:   %s [--options] %s\n\n", program, example_filename);
216         printf("Available options are: [-w [w h l t]] [-f [fw fh fb ff]] %s[-g gamengineoptions] ", consoleoption);
217         printf("[-s stereomode] [-m aasamples]\n");
218         printf("Optional parameters must be passed in order.\n");
219         printf("Default values are set in the blend file.\n\n");
220         printf("  -h: Prints this command summary\n\n");
221         printf("  -w: display in a window\n");
222         printf("       --Optional parameters--\n"); 
223         printf("       w = window width\n");
224         printf("       h = window height\n");
225         printf("       l = window left coordinate\n");
226         printf("       t = window top coordinate\n");
227         printf("       Note: To define 'w' or 'h', both must be used.");
228         printf("Also, to define 'l' or 't', all four parameters must be used.\n");
229         printf("       Example: -w   or  -w 500 300  or  -w 500 300 0 0\n\n");
230         printf("  -f: start game in fullscreen mode\n");
231         printf("       --Optional parameters--\n");
232         printf("       fw = fullscreen mode pixel width    (use 0 to detect automatically)\n");
233         printf("       fh = fullscreen mode pixel height   (use 0 to detect automatically)\n");
234         printf("       fb = fullscreen mode bits per pixel (default unless set in the blend file: 32)\n");
235         printf("       ff = fullscreen mode frequency      (default unless set in the blend file: 60)\n");
236         printf("       Note: To define 'fw'' or 'fh'', both must be used.\n");
237         printf("       Example: -f  or  -f 1024 768  or  -f 0 0 16  or  -f 1024 728 16 30\n\n");
238         printf("  -s: start player in stereoscopy mode (requires 3D capable hardware)\n");
239         printf("       stereomode: nostereo         (default unless stereo is set in the blend file)\n");
240         printf("                   anaglyph         (Red-Blue glasses)\n");
241         printf("                   sidebyside       (Left Right)\n");
242         printf("                   syncdoubling     (Above Below)\n");
243         printf("                   3dtvtopbottom    (Squashed Top-Bottom for passive glasses)\n");
244         printf("                   interlace        (Interlace horizontally)\n");
245         printf("                   vinterlace       (Vertical interlace for autostereo display)\n");
246         printf("                   hwpageflip       (Quad buffered shutter glasses)\n");
247         printf("       Example: -s sidebyside  or  -s vinterlace\n\n");
248         printf("  -D: start player in dome mode\n");
249         printf("       --Optional parameters--\n");
250         printf("       angle    = field of view in degrees\n");
251         printf("       tilt     = tilt angle in degrees\n");
252         printf("       warpdata = a file to use for warping the image (absolute path)\n");
253         printf("       mode: fisheye                (Fisheye)\n");
254         printf("             truncatedfront         (Front-Truncated)\n");
255         printf("             truncatedrear          (Rear-Truncated)\n");
256         printf("             cubemap                (Cube Map)\n");
257         printf("             sphericalpanoramic     (Spherical Panoramic)\n");
258         printf("       Example: -D  or  -D mode cubemap\n\n");
259         printf("  -m: maximum anti-aliasing (eg. 2,4,8,16)\n\n");
260         printf("  -i: parent window's ID\n\n");
261 #ifdef _WIN32
262         printf("  -c: keep console window open\n\n");
263 #endif
264         printf("  -d: turn debugging on\n\n");
265         printf("  -g: game engine options:\n\n");
266         printf("       Name                       Default      Description\n");
267         printf("       ------------------------------------------------------------------------\n");
268         printf("       fixedtime                      0         \"Enable all frames\"\n");
269         printf("       nomipmap                       0         Disable mipmaps\n");
270         printf("       show_framerate                 0         Show the frame rate\n");
271         printf("       show_properties                0         Show debug properties\n");
272         printf("       show_profile                   0         Show profiling information\n");
273         printf("       blender_material               0         Enable material settings\n");
274         printf("       ignore_deprecation_warnings    1         Ignore deprecation warnings\n");
275         printf("\n");
276         printf("  - : all arguments after this are ignored, allowing python to access them from sys.argv\n");
277         printf("\n");
278         printf("example: %s -w 320 200 10 10 -g noaudio %s%s\n", program, example_pathname, example_filename);
279         printf("example: %s -g show_framerate = 0 %s%s\n", program, example_pathname, example_filename);
280         printf("example: %s -i 232421 -m 16 %s%s\n\n", program, example_pathname, example_filename);
281 }
282
283 static void get_filename(int argc, char **argv, char *filename)
284 {
285 #ifdef __APPLE__
286         /* On Mac we park the game file (called game.blend) in the application bundle.
287          * The executable is located in the bundle as well.
288          * Therefore, we can locate the game relative to the executable.
289          */
290         int srclen = ::strlen(argv[0]);
291         int len = 0;
292         char *gamefile = NULL;
293         
294         filename[0] = '\0';
295
296         if (argc > 1) {
297                 if (BLI_exists(argv[argc-1])) {
298                         BLI_strncpy(filename, argv[argc-1], FILE_MAX);
299                 }
300         }
301         
302         srclen -= ::strlen("MacOS/blenderplayer");
303         if (srclen > 0) {
304                 len = srclen + ::strlen("Resources/game.blend"); 
305                 gamefile = new char [len + 1];
306                 ::strcpy(gamefile, argv[0]);
307                 ::strcpy(gamefile + srclen, "Resources/game.blend");
308                 //::printf("looking for file: %s\n", filename);
309                 
310                 if (BLI_exists(gamefile))
311                         BLI_strncpy(filename, gamefile, FILE_MAX);
312
313                 delete [] gamefile;
314         }
315         
316 #else
317         filename[0] = '\0';
318
319         if (argc > 1)
320                 BLI_strncpy(filename, argv[argc-1], FILE_MAX);
321 #endif // !_APPLE
322 }
323
324 static BlendFileData *load_game_data(const char *progname, char *filename = NULL, char *relativename = NULL)
325 {
326         ReportList reports;
327         BlendFileData *bfd = NULL;
328
329         BKE_reports_init(&reports, RPT_STORE);
330         
331         /* try to load ourself, will only work if we are a runtime */
332         if (BLO_is_a_runtime(progname)) {
333                 bfd= BLO_read_runtime(progname, &reports);
334                 if (bfd) {
335                         bfd->type= BLENFILETYPE_RUNTIME;
336                         BLI_strncpy(bfd->main->name, progname, sizeof(bfd->main->name));
337                 }
338         } else {
339                 bfd= BLO_read_from_file(progname, &reports);
340         }
341         
342         if (!bfd && filename) {
343                 bfd = load_game_data(filename);
344                 if (!bfd) {
345                         printf("Loading %s failed: ", filename);
346                         BKE_reports_print(&reports, RPT_ERROR);
347                 }
348         }
349
350         BKE_reports_clear(&reports);
351         
352         return bfd;
353 }
354
355 static bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exitcode, STR_String &exitstring, GlobalSettings *gs)
356 {
357         bool run = true;
358         system->processEvents(false);
359         system->dispatchEvents();
360         app->EngineNextFrame();
361         if ((exitcode = app->getExitRequested())) {
362                 run = false;
363                 exitstring = app->getExitString();
364                 *gs = *app->getGlobalSettings();
365         }
366         return run;
367 }
368
369 struct GPG_NextFrameState {
370         GHOST_ISystem* system;
371         GPG_Application *app;
372         GlobalSettings *gs;
373 } gpg_nextframestate;
374
375 static int GPG_PyNextFrame(void *state0)
376 {
377         GPG_NextFrameState *state = (GPG_NextFrameState *) state0;
378         int exitcode;
379         STR_String exitstring;
380         bool run = GPG_NextFrame(state->system, state->app, exitcode, exitstring, state->gs);
381         if (run) return 0;  
382         else {
383                 if (exitcode) 
384                         fprintf(stderr, "Exit code %d: %s\n", exitcode, exitstring.ReadPtr());
385                 return 1;
386         }
387 }
388
389 int main(int argc, char** argv)
390 {
391         int i;
392         int argc_py_clamped= argc; /* use this so python args can be added after ' - ' */
393         bool error = false;
394         SYS_SystemHandle syshandle = SYS_GetSystem();
395         bool fullScreen = false;
396         bool fullScreenParFound = false;
397         bool windowParFound = false;
398 #ifdef WIN32
399         bool closeConsole = true;
400 #endif
401         RAS_IRasterizer::StereoMode stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
402         bool stereoWindow = false;
403         bool stereoParFound = false;
404         int stereoFlag = STEREO_NOSTEREO;
405         int domeFov = -1;
406         int domeTilt = -200;
407         int domeMode = 0;
408         char* domeWarp = NULL;
409         Text *domeText  = NULL;
410         int windowLeft = 100;
411         int windowTop = 100;
412         int windowWidth = 640;
413         int windowHeight = 480;
414         GHOST_TUns32 fullScreenWidth = 0;
415         GHOST_TUns32 fullScreenHeight= 0;
416         int fullScreenBpp = 32;
417         int fullScreenFrequency = 60;
418         GHOST_TEmbedderWindowID parentWindow = 0;
419         bool isBlenderPlayer = false; //true when lauching from blender or command line. false for bundled player
420         int validArguments=0;
421         bool samplesParFound = false;
422         GHOST_TUns16 aasamples = 0;
423         
424 #ifdef __linux__
425 #ifdef __alpha__
426         signal (SIGFPE, SIG_IGN);
427 #endif /* __alpha__ */
428 #endif /* __linux__ */
429
430 #ifdef WITH_SDL_DYNLOAD
431         sdlewInit();
432 #endif
433
434         BKE_appdir_program_path_init(argv[0]);
435         BKE_tempdir_init(NULL);
436         
437         // We don't use threads directly in the BGE, but we need to call this so things like
438         // freeing up GPU_Textures works correctly.
439         BLI_threadapi_init();
440
441         RNA_init();
442
443         init_nodesystem();
444         
445         initglobals();
446
447         U.gameflags |= USER_DISABLE_VBO;
448         // We load our own G.main, so free the one that initglobals() gives us
449         BKE_main_free(G.main);
450         G.main = NULL;
451
452         MEM_CacheLimiter_set_disabled(true);
453         IMB_init();
454         BKE_images_init();
455         BKE_modifier_init();
456         DAG_init();
457
458 #ifdef WITH_FFMPEG
459         IMB_ffmpeg_init();
460 #endif
461
462         // Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c)
463         BLF_init(11, U.dpi);
464         BLF_lang_init();
465         BLF_lang_set("");
466
467         BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
468         if (blf_mono_font == -1)
469                 blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char*)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
470
471         // Parse command line options
472 #if defined(DEBUG)
473         printf("argv[0] = '%s'\n", argv[0]);
474 #endif
475
476 #ifdef WIN32
477         if (scr_saver_init(argc, argv))
478         {
479                 switch (scr_saver_mode)
480                 {
481                 case SCREEN_SAVER_MODE_CONFIGURATION:
482                         MessageBox(scr_saver_hwnd, "This screen saver has no options that you can set", "Screen Saver", MB_OK);
483                         break;
484                 case SCREEN_SAVER_MODE_PASSWORD:
485                         /* This is W95 only, which we currently do not support.
486                          * Fall-back to normal screen saver behavior in that case... */
487                 case SCREEN_SAVER_MODE_SAVER:
488                         fullScreen = true;
489                         fullScreenParFound = true;
490                         break;
491
492                 case SCREEN_SAVER_MODE_PREVIEW:
493                         /* This will actually be handled somewhere below... */
494                         break;
495                 }
496         }
497 #endif
498         // XXX add the ability to change this values to the command line parsing.
499         U.mixbufsize = 2048;
500         U.audiodevice = 2;
501         U.audiorate = 44100;
502         U.audioformat = 0x24;
503         U.audiochannels = 2;
504
505         // XXX this one too
506         U.anisotropic_filter = 2;
507         // enable fast mipmap generation
508         U.use_gpu_mipmap = 1;
509
510         sound_init_once();
511
512         set_free_windowmanager_cb(wm_free);
513
514         /* if running blenderplayer the last argument can't be parsed since it has to be the filename. else it is bundled */
515         isBlenderPlayer = !BLO_is_a_runtime(argv[0]);
516         if (isBlenderPlayer)
517                 validArguments = argc - 1;
518         else
519                 validArguments = argc;
520
521
522         /* Parsing command line arguments (can be set from WM_OT_blenderplayer_start) */
523 #if defined(DEBUG)
524                 printf("Parsing command line arguments...\n");
525                 printf("Num of arguments is: %i\n", validArguments-1); //-1 because i starts at 1
526 #endif
527
528         for (i = 1; (i < validArguments) && !error 
529 #ifdef WIN32
530                 && scr_saver_mode == SCREEN_SAVER_MODE_NONE
531 #endif
532                 ;)
533
534         {
535 #if defined(DEBUG)
536                 printf("argv[%d] = '%s'\n", i, argv[i]);
537 #endif
538                 if (argv[i][0] == '-')
539                 {
540                         /* ignore all args after " - ", allow python to have own args */
541                         if (argv[i][1]=='\0') {
542                                 argc_py_clamped= i;
543                                 break;
544                         }
545                         
546                         switch (argv[i][1])
547                         {
548                         case 'g': //game engine options (show_framerate, fixedtime, etc)
549                         {
550                                 i++;
551                                 if (i <= validArguments)
552                                 {
553                                         char* paramname = argv[i];
554                                         // Check for single value versus assignment
555                                         if (i+1 <= validArguments && (*(argv[i+1]) == '='))
556                                         {
557                                                 i++;
558                                                 if (i + 1 <= validArguments)
559                                                 {
560                                                         i++;
561                                                         // Assignment
562                                                         SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i]));
563                                                         SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i]));
564                                                         SYS_WriteCommandLineString(syshandle, paramname, argv[i]);
565 #if defined(DEBUG)
566                                                         printf("%s = '%s'\n", paramname, argv[i]);
567 #endif
568                                                         i++;
569                                                 }
570                                                 else
571                                                 {
572                                                         error = true;
573                                                         printf("error: argument assignment %s without value.\n", paramname);
574                                                 }
575                                         }
576                                         else
577                                         {
578 //                                              SYS_WriteCommandLineInt(syshandle, argv[i++], 1);
579                                         }
580                                 }
581                                 break;
582                         }
583                         case 'd': //debug on
584                         {
585                                 i++;
586                                 G.debug |= G_DEBUG;
587                                 MEM_set_memory_debug();
588 #ifdef DEBUG
589                                 BLI_mempool_set_memory_debug();
590 #endif
591                                 break;
592                         }
593                         case 'f': //fullscreen mode
594                         {
595                                 i++;
596                                 fullScreen = true;
597                                 fullScreenParFound = true;
598                                 if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
599                                 {
600                                         fullScreenWidth = atoi(argv[i++]);
601                                         fullScreenHeight = atoi(argv[i++]);
602                                         if ((i + 1) <= validArguments && argv[i][0] != '-')
603                                         {
604                                                 fullScreenBpp = atoi(argv[i++]);
605                                                 if ((i + 1) <= validArguments && argv[i][0] != '-')
606                                                         fullScreenFrequency = atoi(argv[i++]);
607                                         }
608                                 }
609                                 else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
610                                 {
611                                         error = true;
612                                         printf("error: to define fullscreen width or height, both options must be used.\n");
613                                 }
614                                 break;
615                         }
616                         case 'w': //display in a window
617                         {
618                                 i++;
619                                 fullScreen = false;
620                                 windowParFound = true;
621
622                                 // Parse window position and size options
623                                 if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
624                                 {
625                                         windowWidth = atoi(argv[i++]);
626                                         windowHeight = atoi(argv[i++]);
627
628                                         if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
629                                         {
630                                                 windowLeft = atoi(argv[i++]);
631                                                 windowTop = atoi(argv[i++]);
632                                         }
633                                         else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
634                                         {
635                                                 error = true;
636                                                 printf("error: to define the window left or right coordinates, both options must be used.\n");
637                                         }
638                                 }
639                                 else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
640                                 {
641                                         error = true;
642                                         printf("error: to define the window's width or height, both options must be used.\n");
643                                 }
644                                 break;
645                         }
646                         case 'h': //display help
647                         {
648                                 usage(argv[0], isBlenderPlayer);
649                                 return 0;
650                                 break;
651                         }
652                         case 'i': //parent window ID
653                         {
654                                 i++;
655                                 if ( (i + 1) <= validArguments )
656                                         parentWindow = atoi(argv[i++]);
657                                 else {
658                                         error = true;
659                                         printf("error: too few options for parent window argument.\n");
660                                 }
661 #if defined(DEBUG)
662                                 printf("XWindows ID = %d\n", parentWindow);
663 #endif // defined(DEBUG)
664                                 break;
665                         }
666                         case 'm': //maximum anti-aliasing (eg. 2,4,8,16)
667                         {
668                                 i++;
669                                 samplesParFound = true;
670                                 if ((i+1) <= validArguments )
671                                         aasamples = atoi(argv[i++]);
672                                 else
673                                 {
674                                         error = true;
675                                         printf("error: No argument supplied for -m");
676                                 }
677                                 break;
678                         }
679                         case 'c': //keep console (windows only)
680                         {
681                                 i++;
682 #ifdef WIN32
683                                 closeConsole = false;
684 #endif
685                                 break;
686                         }
687                         case 's': //stereo mode
688                         {
689                                 i++;
690                                 if ((i + 1) <= validArguments)
691                                 {
692                                         stereoParFound = true;
693                                         stereoFlag = STEREO_ENABLED;
694
695                                         if (!strcmp(argv[i], "nostereo"))  // may not be redundant if the file has different setting
696                                         {
697                                                 stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
698                                                 stereoFlag = STEREO_NOSTEREO;
699                                         }
700
701                                         // only the hardware pageflip method needs a stereo window
702                                         else if (!strcmp(argv[i], "hwpageflip")) {
703                                                 stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
704                                                 stereoWindow = true;
705                                         }
706                                         else if (!strcmp(argv[i], "syncdoubling"))
707                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;
708
709                                         else if (!strcmp(argv[i], "3dtvtopbottom"))
710                                                 stereomode = RAS_IRasterizer::RAS_STEREO_3DTVTOPBOTTOM;
711
712                                         else if (!strcmp(argv[i], "anaglyph"))
713                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ANAGLYPH;
714
715                                         else if (!strcmp(argv[i], "sidebyside"))
716                                                 stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE;
717
718                                         else if (!strcmp(argv[i], "interlace"))
719                                                 stereomode = RAS_IRasterizer::RAS_STEREO_INTERLACED;
720
721                                         else if (!strcmp(argv[i], "vinterlace"))
722                                                 stereomode = RAS_IRasterizer::RAS_STEREO_VINTERLACE;
723
724 #if 0
725 //                                      // future stuff
726 //                                      else if (!strcmp(argv[i], "stencil")
727 //                                              stereomode = RAS_STEREO_STENCIL;
728 #endif
729                                         else
730                                         {
731                                                 error = true;
732                                                 printf("error: stereomode '%s' unrecognized.\n", argv[i]);
733                                         }
734
735                                         i++;
736                                 }
737                                 else
738                                 {
739                                         error = true;
740                                         printf("error: too few options for stereo argument.\n");
741                                 }
742                                 break;
743                         }
744                         case 'D': //dome mode
745                         {
746                                 stereoFlag = STEREO_DOME;
747                                 stereomode = RAS_IRasterizer::RAS_STEREO_DOME;
748                                 i++;
749                                 if ((i + 1) <= validArguments)
750                                 {
751                                         if (!strcmp(argv[i], "angle")) {
752                                                 i++;
753                                                 domeFov = atoi(argv[i++]);
754                                         }
755                                         if (!strcmp(argv[i], "tilt")) {
756                                                 i++;
757                                                 domeTilt = atoi(argv[i++]);
758                                         }
759                                         if (!strcmp(argv[i], "warpdata")) {
760                                                 i++;
761                                                 domeWarp = argv[i++];
762                                         }
763                                         if (!strcmp(argv[i], "mode")) {
764                                                 i++;
765                                                 if (!strcmp(argv[i], "fisheye"))
766                                                         domeMode = DOME_FISHEYE;
767                                                         
768                                                 else if (!strcmp(argv[i], "truncatedfront"))
769                                                         domeMode = DOME_TRUNCATED_FRONT;
770                                                         
771                                                 else if (!strcmp(argv[i], "truncatedrear"))
772                                                         domeMode = DOME_TRUNCATED_REAR;
773                                                         
774                                                 else if (!strcmp(argv[i], "cubemap"))
775                                                         domeMode = DOME_ENVMAP;
776                                                         
777                                                 else if (!strcmp(argv[i], "sphericalpanoramic"))
778                                                         domeMode = DOME_PANORAM_SPH;
779
780                                                 else
781                                                         printf("error: %s is not a valid dome mode.\n", argv[i]);
782                                         }
783                                         i++;
784                                 }
785                                 break;
786                         }
787                         default:  //not recognized
788                         {
789                                 printf("Unknown argument: %s\n", argv[i++]);
790                                 break;
791                         }
792                         }
793                 }
794                 else
795                 {
796                         i++;
797                 }
798         }
799
800         if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight))
801         {
802                 error = true;
803                 printf("error: window size too small.\n");
804         }
805         
806         if (error )
807         {
808                 usage(argv[0], isBlenderPlayer);
809                 return 0;
810         }
811
812 #ifdef WIN32
813         if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION)
814 #endif
815         {
816                 // Create the system
817                 if (GHOST_ISystem::createSystem() == GHOST_kSuccess) {
818                         GHOST_ISystem* system = GHOST_ISystem::getSystem();
819                         assertd(system);
820                         
821                         if (!fullScreenWidth || !fullScreenHeight)
822                                 system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight);
823                         // process first batch of events. If the user
824                         // drops a file on top off the blenderplayer icon, we
825                         // receive an event with the filename
826                         
827                         system->processEvents(0);
828                         
829                         // this bracket is needed for app (see below) to get out
830                         // of scope before GHOST_ISystem::disposeSystem() is called.
831                         {
832                                 int exitcode = KX_EXIT_REQUEST_NO_REQUEST;
833                                 STR_String exitstring = "";
834                                 GPG_Application app(system);
835                                 bool firstTimeRunning = true;
836                                 char filename[FILE_MAX];
837                                 char pathname[FILE_MAX];
838                                 char *titlename;
839
840                                 get_filename(argc_py_clamped, argv, filename);
841                                 if (filename[0])
842                                         BLI_path_cwd(filename);
843                                 
844
845                                 // fill the GlobalSettings with the first scene files
846                                 // those may change during the game and persist after using Game Actuator
847                                 GlobalSettings gs;
848
849                                 do {
850                                         // Read the Blender file
851                                         BlendFileData *bfd;
852                                         
853                                         // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
854                                         if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME)
855                                         {
856                                                 char basedpath[FILE_MAX];
857                                                 
858                                                 // base the actuator filename relative to the last file
859                                                 BLI_strncpy(basedpath, exitstring.Ptr(), sizeof(basedpath));
860                                                 BLI_path_abs(basedpath, pathname);
861                                                 
862                                                 bfd = load_game_data(basedpath);
863
864                                                 if (!bfd) {
865                                                         // just add "//" in front of it
866                                                         char temppath[FILE_MAX] = "//";
867                                                         BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2);
868
869                                                         BLI_path_abs(temppath, pathname);
870                                                         bfd = load_game_data(temppath);
871                                                 }
872                                         }
873                                         else {
874                                                 bfd = load_game_data(BKE_appdir_program_path(), filename[0]? filename: NULL);
875                                         }
876
877 #if defined(DEBUG)
878                                         printf("Game data loaded from %s\n", filename);
879 #endif
880                                         
881                                         if (!bfd) {
882                                                 usage(argv[0], isBlenderPlayer);
883                                                 error = true;
884                                                 exitcode = KX_EXIT_REQUEST_QUIT_GAME;
885                                         }
886                                         else {
887                                                 /* Setting options according to the blend file if not overriden in the command line */
888 #ifdef WIN32
889 #if !defined(DEBUG)
890                                                 if (closeConsole) {
891                                                         system->toggleConsole(0); // Close a console window
892                                                 }
893 #endif // !defined(DEBUG)
894 #endif // WIN32
895                                                 Main *maggie = bfd->main;
896                                                 Scene *scene = bfd->curscene;
897                                                 G.main = maggie;
898
899                                                 if (firstTimeRunning) {
900                                                         G.fileflags  = bfd->fileflags;
901
902                                                         gs.matmode= scene->gm.matmode;
903                                                         gs.glslflag= scene->gm.flag;
904                                                 }
905
906                                                 //Seg Fault; icon.c gIcons == 0
907                                                 BKE_icons_init(1);
908                                                 
909                                                 titlename = maggie->name;
910                                                 
911                                                 // Check whether the game should be displayed full-screen
912                                                 if ((!fullScreenParFound) && (!windowParFound)) {
913                                                         // Only use file settings when command line did not override
914                                                         if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) {
915                                                                 //printf("fullscreen option found in Blender file\n");
916                                                                 fullScreen = true;
917                                                                 fullScreenWidth= scene->gm.xplay;
918                                                                 fullScreenHeight= scene->gm.yplay;
919                                                                 fullScreenFrequency= scene->gm.freqplay;
920                                                                 fullScreenBpp = scene->gm.depth;
921                                                         }
922                                                         else
923                                                         {
924                                                                 fullScreen = false;
925                                                                 windowWidth = scene->gm.xplay;
926                                                                 windowHeight = scene->gm.yplay;
927                                                         }
928                                                 }
929                                                 
930                                                 
931                                                 // Check whether the game should be displayed in stereo (dome included)
932                                                 if (!stereoParFound) {
933                                                         // Only use file settings when command line did not override
934                                                         if (scene->gm.stereoflag == STEREO_ENABLED) {
935                                                                 stereomode = (RAS_IRasterizer::StereoMode) scene->gm.stereomode;
936                                                                 if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
937                                                                         stereoWindow = true;
938                                                         }
939                                                 }
940                                                 else {
941                                                         scene->gm.stereoflag = STEREO_ENABLED;
942                                                 }
943
944                                                 if (!samplesParFound)
945                                                         aasamples = scene->gm.aasamples;
946
947                                                 // Dome specific settings
948                                                 if (stereoFlag == STEREO_DOME) {
949                                                         stereomode = RAS_IRasterizer::RAS_STEREO_DOME;
950                                                         scene->gm.stereoflag = STEREO_DOME;
951                                                         if (domeFov > 89)
952                                                                 scene->gm.dome.angle = domeFov;
953                                                         if (domeTilt > -180)
954                                                                 scene->gm.dome.tilt = domeTilt;
955                                                         if (domeMode > 0)
956                                                                 scene->gm.dome.mode = domeMode;
957                                                         if (domeWarp) {
958                                                                 //XXX to do: convert relative to absolute path
959                                                                 domeText= BKE_text_load(G.main, domeWarp, "");
960                                                                 if (!domeText)
961                                                                         printf("error: invalid warpdata text file - %s\n", domeWarp);
962                                                                 else
963                                                                         scene->gm.dome.warptext = domeText;
964                                                         }
965                                                 }
966                                                 
967                                                 //                                      GPG_Application app (system, maggie, startscenename);
968                                                 app.SetGameEngineData(maggie, scene, &gs, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */
969                                                 BLI_strncpy(pathname, maggie->name, sizeof(pathname));
970                                                 if (G.main != maggie) {
971                                                         BLI_strncpy(G.main->name, maggie->name, sizeof(G.main->name));
972                                                 }
973 #ifdef WITH_PYTHON
974                                                 setGamePythonPath(G.main->name);
975 #endif
976                                                 if (firstTimeRunning) {
977                                                         firstTimeRunning = false;
978
979                                                         if (fullScreen) {
980 #ifdef WIN32
981                                                                 if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER)
982                                                                 {
983                                                                         app.startScreenSaverFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
984                                                                                                        stereoWindow, stereomode, aasamples);
985                                                                 }
986                                                                 else
987 #endif
988                                                                 {
989                                                                         app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
990                                                                                             stereoWindow, stereomode, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
991                                                                 }
992                                                         }
993                                                         else
994                                                         {
995 #ifdef __APPLE__
996                                                                 // on Mac's we'll show the executable name instead of the 'game.blend' name
997                                                                 char tempname[1024], *appstring;
998                                                                 ::strcpy(tempname, titlename);
999                                                                 
1000                                                                 appstring = strstr(tempname, ".app/");
1001                                                                 if (appstring) {
1002                                                                         appstring[2] = 0;
1003                                                                         titlename = &tempname[0];
1004                                                                 }
1005 #endif
1006                                                                 // Strip the path so that we have the name of the game file
1007                                                                 STR_String path = titlename;
1008 #ifndef WIN32
1009                                                                 vector<STR_String> parts = path.Explode('/');
1010 #else  // WIN32
1011                                                                 vector<STR_String> parts = path.Explode('\\');
1012 #endif // WIN32                        
1013                                                                 STR_String title;
1014                                                                 if (parts.size()) {
1015                                                                         title = parts[parts.size()-1];
1016                                                                         parts = title.Explode('.');
1017                                                                         if (parts.size() > 1)
1018                                                                         {
1019                                                                                 title = parts[0];
1020                                                                         }
1021                                                                 }
1022                                                                 else {
1023                                                                         title = "blenderplayer";
1024                                                                 }
1025 #ifdef WIN32
1026                                                                 if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW)
1027                                                                 {
1028                                                                         app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode, aasamples);
1029                                                                 }
1030                                                                 else
1031 #endif
1032                                                                 {
1033                                                                         if (parentWindow != 0)
1034                                                                                 app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples);
1035                                                                         else
1036                                                                                 app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
1037                                                                                                 stereoWindow, stereomode, aasamples);
1038
1039                                                                         if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
1040                                                                                 GPU_set_mipmap(0);
1041                                                                         }
1042
1043                                                                         GPU_set_anisotropic(U.anisotropic_filter);
1044                                                                         GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
1045                                                                 }
1046                                                         }
1047                                                 }
1048                                                 else {
1049                                                         app.StartGameEngine(stereomode);
1050                                                         exitcode = KX_EXIT_REQUEST_NO_REQUEST;
1051                                                 }
1052                                                 
1053                                                 // Add the application as event consumer
1054                                                 system->addEventConsumer(&app);
1055                                                 
1056                                                 // Enter main loop
1057                                                 bool run = true;
1058                                                 char *python_main = NULL;
1059                                                 pynextframestate.state = NULL;
1060                                                 pynextframestate.func = NULL;
1061 #ifdef WITH_PYTHON
1062                                                 python_main = KX_GetPythonMain(scene);
1063 #endif // WITH_PYTHON
1064                                                 if (python_main) {
1065                                                         char *python_code = KX_GetPythonCode(maggie, python_main);
1066                                                         if (python_code) {
1067 #ifdef WITH_PYTHON
1068                                                                 gpg_nextframestate.system = system;
1069                                                                 gpg_nextframestate.app = &app;
1070                                                                 gpg_nextframestate.gs = &gs;
1071                                                                 pynextframestate.state = &gpg_nextframestate;
1072                                                                 pynextframestate.func = &GPG_PyNextFrame;
1073
1074                                                                 printf("Yielding control to Python script '%s'...\n", python_main);
1075                                                                 PyRun_SimpleString(python_code);
1076                                                                 printf("Exit Python script '%s'\n", python_main);
1077 #endif // WITH_PYTHON
1078                                                                 MEM_freeN(python_code);
1079                                                         }
1080                                                         else {
1081                                                                 fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data block named '%s'\n", python_main);
1082                                                         }
1083                                                 }
1084                                                 else {
1085                                                         while (run) {
1086                                                                 run = GPG_NextFrame(system, &app, exitcode, exitstring, &gs);
1087                                                         }
1088                                                 }
1089                                                 app.StopGameEngine();
1090
1091                                                 /* 'app' is freed automatic when out of scope.
1092                                                  * removal is needed else the system will free an already freed value */
1093                                                 system->removeEventConsumer(&app);
1094
1095                                                 BLO_blendfiledata_free(bfd);
1096                                                 /* G.main == bfd->main, it gets referenced in free_nodesystem so we can't have a dangling pointer */
1097                                                 G.main = NULL;
1098                                                 if (python_main) MEM_freeN(python_main);
1099                                         }
1100                                 } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME);
1101                         }
1102
1103                         // Seg Fault; icon.c gIcons == 0
1104                         BKE_icons_free();
1105
1106                         // Dispose the system
1107                         GHOST_ISystem::disposeSystem();
1108                 }
1109                 else {
1110                         error = true;
1111                         printf("error: couldn't create a system.\n");
1112                 }
1113         }
1114
1115         /* refer to WM_exit_ext() and free_blender(),
1116          * these are not called in the player but we need to match some of there behavior here,
1117          * if the order of function calls or blenders state isn't matching that of blender proper,
1118          * we may get troubles later on */
1119
1120         free_nodesystem();
1121
1122         // Cleanup
1123         RNA_exit();
1124         BLF_exit();
1125
1126 #ifdef WITH_INTERNATIONAL
1127         BLF_free_unifont();
1128         BLF_free_unifont_mono();
1129         BLF_lang_free();
1130 #endif
1131
1132         IMB_exit();
1133         BKE_images_exit();
1134         DAG_exit();
1135         IMB_moviecache_destruct();
1136
1137         SYS_DeleteSystem(syshandle);
1138
1139         int totblock= MEM_get_memory_blocks_in_use();
1140         if (totblock!=0) {
1141                 printf("Error Totblock: %d\n",totblock);
1142                 MEM_set_error_callback(mem_error_cb);
1143                 MEM_printmemlist();
1144         }
1145
1146         BKE_tempdir_session_purge();
1147
1148         return error ? -1 : 0;
1149 }