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