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