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