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