added -h to the commandline args to print usage.
[blender.git] / source / gameengine / GamePlayer / ghost / GPG_ghost.cpp
1 /**
2 * $Id$
3 *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31 * Start up of the Blender Player on GHOST.
32 */
33
34 #include <iostream>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef __linux__
42 #ifdef __alpha__
43 #include <signal.h>
44 #endif /* __alpha__ */
45 #endif /* __linux__ */
46
47 #ifdef __APPLE__
48 // Can't use Carbon right now because of double defined type ID (In Carbon.h and DNA_ID.h, sigh)
49 //#include <Carbon/Carbon.h>
50 //#include <CFBundle.h>
51 #endif // __APPLE__
52 #include "GEN_messaging.h"
53 #include "KX_KetsjiEngine.h"
54
55 /**********************************
56 * Begin Blender include block
57 **********************************/
58 #ifdef __cplusplus
59 extern "C"
60 {
61 #endif  // __cplusplus
62         
63 #include "BLI_blenlib.h"
64 #include "DNA_scene_types.h"
65 #include "BLO_readfile.h"
66 #include "BLO_readblenfile.h"
67         
68         int GHOST_HACK_getFirstFile(char buf[]);
69         
70 #ifdef __cplusplus
71 }
72 #endif // __cplusplus
73 /**********************************
74 * End Blender include block
75 **********************************/
76
77 #include "SYS_System.h"
78 #include "GPG_Application.h"
79 #include "GPC_PolygonMaterial.h"
80
81 #include "GHOST_ISystem.h"
82 #include "RAS_IRasterizer.h"
83
84 #include "BKE_main.h"
85 #include "BKE_utildefines.h"
86
87 #ifdef WIN32
88 #ifdef NDEBUG
89 #include <windows.h>
90 #include <wincon.h>
91 #endif // NDEBUG
92 #endif // WIN32
93
94 const int kMinWindowWidth = 100;
95 const int kMinWindowHeight = 100;
96
97 char bprogname[FILE_MAXDIR+FILE_MAXFILE];
98
99 void usage(char* program)
100 {
101         char * consoleoption;
102 #ifdef _WIN32
103         consoleoption = "-c ";
104 #else
105         consoleoption = "";
106 #endif
107         
108         printf("usage:   %s [-w [-p l t w h]] %s[-g gamengineoptions] "
109                 "[-s stereomode] filename.blend\n", program, consoleoption);
110         printf("  -h: Prints this command summary\n");
111         printf("  -w: display in a window\n");
112         printf("  -p: specify window position\n");
113         printf("       l = window left coordinate\n");
114         printf("       t = window top coordinate\n");
115         printf("       w = window width\n");
116         printf("       h = window height\n");
117         printf("  -f: start game in full screen mode\n");
118         printf("       fw = full screen mode pixel width\n");
119         printf("       fh = full screen mode pixel height\n");
120         printf("       fb = full screen mode bits per pixel\n");
121         printf("       ff = full screen mode frequency\n");
122         printf("  -s: start player in stereo\n");
123         printf("       stereomode: hwpageflip       (Quad buffered shutter glasses)\n");
124         printf("                   syncdoubling     (Above Below)\n");
125         printf("                   sidebyside       (Left Right)\n");
126         printf("                   anaglyph         (Red-Blue glasses)\n");
127         printf("                             depending on the type of stereo you want\n");
128 #ifdef _WIN32
129         printf("  -c: keep console window open\n");
130 #endif
131         printf("  -g: game engine options:\n");
132         printf("       Name            Default      Description\n");
133         printf("       ----------------------------------------\n");
134         printf("       fixedtime          0         Do the same timestep each frame \"Enable all frames\"\n");
135         printf("       nomipmap           0         Disable mipmaps\n");
136         printf("       show_framerate     0         Show the frame rate\n");
137         printf("       show_properties    0         Show debug properties\n");
138         printf("       show_profile       0         Show profiling information\n");
139         printf("       vertexarrays       1         Enable vertex arrays\n");
140         printf("\n");
141         printf("example: %s -p 10 10 320 200 -g noaudio c:\\loadtest.blend\n", program);
142         printf("example: %s -g vertexarrays = 0 c:\\loadtest.blend\n", program);
143 }
144
145 char *get_filename(int argc, char **argv) {
146 #ifdef __APPLE__
147 /* On Mac we park the game file (called game.blend) in the application bundle.
148 * The executable is located in the bundle as well.
149 * Therefore, we can locate the game relative to the executable.
150         */
151         int srclen = ::strlen(argv[0]);
152         int len = 0;
153         char *filename = NULL;
154         
155         if (argc > 1) {
156                 if (BLI_exists(argv[argc-1])) {
157                         len = ::strlen(argv[argc-1]);
158                         filename = new char [len + 1];
159                         ::strcpy(filename, argv[argc-1]);
160                         return(filename);
161                 }
162                 if (::strncmp(argv[argc-1], "-psn_", 5)==0) {
163                         static char firstfilebuf[512];
164                         if (GHOST_HACK_getFirstFile(firstfilebuf)) {
165                                 len = ::strlen(firstfilebuf);
166                                 filename = new char [len + 1];
167                                 ::strcpy(filename, firstfilebuf);
168                                 return(filename);
169                         }
170                 }                        
171         }
172         
173         srclen -= ::strlen("MacOS/blenderplayer");
174         if (srclen > 0) {
175                 len = srclen + ::strlen("Resources/game.blend"); 
176                 filename = new char [len + 1];
177                 ::strcpy(filename, argv[0]);
178                 ::strcpy(filename + srclen, "Resources/game.blend");
179                 //::printf("looking for file: %s\n", filename);
180                 
181                 if (BLI_exists(filename)) {
182                         return (filename);
183                 }
184         }
185         
186         return(NULL);
187 #else
188         return (argc>1)?argv[argc-1]:NULL;
189 #endif // !_APPLE
190 }
191
192 static BlendFileData *load_game_data(char *progname, char *filename = NULL) {
193         BlendReadError error;
194         BlendFileData *bfd = NULL;
195         
196         /* try to load ourself, will only work if we are a runtime */
197         if (blo_is_a_runtime(progname)) {
198                 bfd= blo_read_runtime(progname, &error);
199                 if (bfd) {
200                         bfd->type= BLENFILETYPE_RUNTIME;
201                         strcpy(bfd->main->name, progname);
202                 }
203         } else {
204                 bfd= BLO_read_from_file(progname, &error);
205         }
206         
207         /*
208         if (bfd && bfd->type == BLENFILETYPE_BLEND) {
209                 BLO_blendfiledata_free(bfd);
210                 bfd = NULL;
211                 error = BRE_NOT_A_PUBFILE;
212         }
213         */
214         
215         if (!bfd && filename) {
216                 bfd = load_game_data(filename);
217                 if (!bfd) {
218                         printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
219                 }
220         }
221         
222         return bfd;
223 }
224
225 int main(int argc, char** argv)
226 {
227         int i;
228         bool error = false;
229         SYS_SystemHandle syshandle = SYS_GetSystem();
230         bool fullScreen = false;
231         bool fullScreenParFound = false;
232         bool windowParFound = false;
233         bool closeConsole = true;
234         RAS_IRasterizer::StereoMode stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
235         bool stereoWindow = false;
236         bool stereoParFound = false;
237         int windowLeft = 100;
238         int windowTop = 100;
239         int windowWidth = 640;
240         int windowHeight = 480;
241         GHOST_TUns32 fullScreenWidth = 0;
242         GHOST_TUns32 fullScreenHeight= 0;
243         int fullScreenBpp = 32;
244         int fullScreenFrequency = 60;
245         
246 #ifdef __linux__
247 #ifdef __alpha__
248         signal (SIGFPE, SIG_IGN);
249 #endif /* __alpha__ */
250 #endif /* __linux__ */
251         BLI_where_am_i(bprogname, argv[0]);
252         
253 #ifdef __APPLE__
254     // Can't use Carbon right now because of double defined type ID (In Carbon.h and DNA_ID.h, sigh)
255     /*
256     IBNibRef            nibRef;
257     WindowRef           window;
258     OSStatus            err;
259         
260           // Create a Nib reference passing the name of the nib file (without the .nib extension)
261           // CreateNibReference only searches into the application bundle.
262           err = ::CreateNibReference(CFSTR("main"), &nibRef);
263           if (err) return -1;
264           
265                 // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
266                 // object. This name is set in InterfaceBuilder when the nib is created.
267                 err = ::SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
268                 if (err) return -1;
269                 
270                   // We don't need the nib reference anymore.
271                   ::DisposeNibReference(nibRef);
272     */
273 #endif // __APPLE__
274         
275         GEN_init_messaging_system();
276         
277         // Parse command line options
278 #ifndef NDEBUG
279         printf("argv[0] = '%s'\n", argv[0]);
280 #endif
281         for (i = 1; (i < argc) && !error;)
282         {
283 #ifndef NDEBUG
284                 printf("argv[%d] = '%s'\n", i, argv[i]);
285 #endif
286                 if (argv[i][0] == '-')
287                 {
288                         switch (argv[i][1])
289                         {
290                         case 'g':
291                                 // Parse game options
292                                 {
293                                         i++;
294                                         if (i < argc)
295                                         {
296                                                 char* paramname = argv[i];
297                                                 // Check for single value versus assignment
298                                                 if (i+1 < argc && (*(argv[i+1]) == '='))
299                                                 {
300                                                         i++;
301                                                         if (i + 1 < argc)
302                                                         {
303                                                                 i++;
304                                                                 // Assignment
305                                                                 SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i]));
306                                                                 SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i]));
307                                                                 SYS_WriteCommandLineString(syshandle, paramname, argv[i]);
308 #ifndef NDEBUG
309                                                                 printf("%s = '%s'\n", paramname, argv[i]);
310 #endif
311                                                                 i++;
312                                                         }
313                                                         else
314                                                         {
315                                                                 error = true;
316                                                                 printf("error: argument assignment %s without value.\n", paramname);
317                                                         }
318                                                 }
319                                                 else
320                                                 {
321                                                         SYS_WriteCommandLineInt(syshandle, argv[i++], 1);
322                                                 }
323                                         }
324                                 }
325                                 break;
326                                 
327                         case 'p':
328                                 // Parse window position and size options
329                                 if (argv[i][2] == 0) {
330                                         i++;
331                                         if ((i + 4) < argc)
332                                         {
333                                                 windowLeft = atoi(argv[i++]);
334                                                 windowTop = atoi(argv[i++]);
335                                                 windowWidth = atoi(argv[i++]);
336                                                 windowHeight = atoi(argv[i++]);
337                                                 windowParFound = true;
338                                         }
339                                         else
340                                         {
341                                                 error = true;
342                                                 printf("error: too few options for window argument.\n");
343                                         }
344                                 }
345                                 break;
346                         case 'f':
347                                 i++;
348                                 fullScreen = true;
349                                 fullScreenParFound = true;
350                                 if ((i + 2) < argc && argv[i][0] != '-' && argv[i+1][0] != '-')
351                                 {
352                                         fullScreenWidth = atoi(argv[i++]);
353                                         fullScreenHeight = atoi(argv[i++]);
354                                         if ((i + 1) < argc && argv[i][0] != '-')
355                                         {
356                                                 fullScreenBpp = atoi(argv[i++]);
357                                                 if ((i + 1) < argc && argv[i][0] != '-')
358                                                         fullScreenFrequency = atoi(argv[i++]);
359                                         }
360                                 }
361                                 break;
362                         case 'w':
363                                 // Parse window position and size options
364                                 {
365                                         fullScreen = false;
366                                         fullScreenParFound = true;
367                                         i++;
368                                 }
369                                 break;
370                         case 'h':
371                                 usage(argv[0]);
372                                 return 0;
373                                 break;
374                         case 'c':
375                                 i++;
376                                 closeConsole = false;
377                                 break;
378                         case 's':  // stereo
379                                 i++;
380                                 if ((i + 1) < argc)
381                                 {
382                                         if(!strcmp(argv[i], "nostereo"))  // ok, redundant but clear
383                                                 stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
384                                         
385                                         // only the hardware pageflip method needs a stereo window
386                                         if(!strcmp(argv[i], "hwpageflip")) {
387                                                 stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
388                                                 stereoWindow = true;
389                                         }
390                                         if(!strcmp(argv[i], "syncdoubling"))
391                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;
392                                         
393                                         if(!strcmp(argv[i], "anaglyph"))
394                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ANAGLYPH;
395                                         
396                                         if(!strcmp(argv[i], "sidebyside"))
397                                                 stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE;
398 #if 0
399                                         // future stuff
400                                         if(strcmp(argv[i], "stencil")
401                                                 stereomode = RAS_STEREO_STENCIL;
402 #endif
403                                         
404                                         i++;
405                                         stereoParFound = true;
406                                 }
407                                 else
408                                 {
409                                         error = true;
410                                         printf("error: too few options for stereo argument.\n");
411                                 }
412                                 break;
413                         default:
414                                 printf("Unkown argument: %s\n", argv[i++]);
415                                 break;
416                         }
417                 }
418                 else
419                 {
420                         i++;
421                 }
422         }
423         
424         if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight))
425         {
426                 error = true;
427                 printf("error: window size too small.\n");
428         }
429         
430         if (error)
431         {
432                 usage(argv[0]);
433         }
434         else
435         {
436 #ifdef __APPLE__
437                 //SYS_WriteCommandLineInt(syshandle, "show_framerate", 1);
438                 SYS_WriteCommandLineInt(syshandle, "nomipmap", 1);
439                 //fullScreen = false;           // Can't use full screen
440 #endif
441                 if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0))
442                 {
443                         GPC_PolygonMaterial::SetMipMappingEnabled(0);
444                 }
445                 
446                 // Create the system
447                 if (GHOST_ISystem::createSystem() == GHOST_kSuccess)
448                 {
449                         GHOST_ISystem* system = GHOST_ISystem::getSystem();
450                         assertd(system);
451                         
452                         if (!fullScreenWidth || !fullScreenHeight)
453                                 system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight);
454                         // process first batch of events. If the user
455                         // drops a file on top off the blenderplayer icon, we 
456                         // recieve an event with the filename
457                         
458                         system->processEvents(0);
459                         
460                         // this bracket is needed for app (see below) to get out
461                         // of scope before GHOST_ISystem::disposeSystem() is called.
462                         {
463                                 int exitcode = KX_EXIT_REQUEST_NO_REQUEST;
464                                 STR_String exitstring = "";
465                                 GPG_Application app(system, NULL, exitstring);
466                                 bool firstTimeRunning = true;
467                                 
468                                 do
469                                 {
470                                         // Read the Blender file
471                                         char *filename = get_filename(argc, argv);
472                                         char *titlename;
473                                         char pathname[160];
474                                         BlendFileData *bfd;
475                                         
476                                         // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
477                                         if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME)
478                                         {
479                                                 char basedpath[160];
480                                                 
481                                                 // base the actuator filename with respect
482                                                 // to the original file working directory
483                                                 strcpy(basedpath, exitstring.Ptr());
484                                                 BLI_convertstringcode(basedpath, pathname, 0);
485                                                 
486                                                 bfd = load_game_data(basedpath);
487                                         }
488                                         else
489                                         {
490                                                 bfd = load_game_data(argv[0], filename);
491                                         }
492                                         
493                                         //::printf("game data loaded from %s\n", filename);
494                                         
495                                         if (!bfd) {
496                                                 usage(argv[0]);
497                                                 error = true;
498                                                 exitcode = KX_EXIT_REQUEST_QUIT_GAME;
499                                         } 
500                                         else 
501                                         {
502 #ifdef WIN32
503 #ifdef NDEBUG
504                                                 if (closeConsole)
505                                                 {
506                                                         ::FreeConsole();    // Close a console window
507                                                 }
508 #endif // NDEBUG
509 #endif // WIN32
510                                                 Main *maggie = bfd->main;
511                                                 Scene *scene = bfd->curscene;
512                                                 strcpy (pathname, maggie->name);
513                                                 char *startscenename = scene->id.name + 2;
514                                                 
515                                                 titlename = maggie->name;
516                                                 
517                                                 // Check whether the game should be displayed full-screen
518                                                 if ((!fullScreenParFound) && (!windowParFound))
519                                                 {
520                                                         // Only use file settings when command line did not override
521                                                         if (scene->r.fullscreen) {
522                                                                 //printf("fullscreen option found in Blender file\n");
523                                                                 fullScreen = true;
524                                                                 fullScreenWidth= scene->r.xplay;
525                                                                 fullScreenHeight= scene->r.yplay;
526                                                                 fullScreenFrequency= scene->r.freqplay;
527                                                                 fullScreenBpp = scene->r.depth;
528                                                         }
529                                                         else
530                                                         {
531                                                                 fullScreen = false;
532                                                                 windowWidth = scene->r.xplay;
533                                                                 windowHeight = scene->r.yplay;
534                                                         }
535                                                 }
536                                                 
537                                                 
538                                                 // Check whether the game should be displayed in stereo
539                                                 if (!stereoParFound)
540                                                 {
541                                                         stereomode = (RAS_IRasterizer::StereoMode) scene->r.stereomode;
542                                                         if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
543                                                                 stereoWindow = true;
544                                                 }
545                                                 
546                                                 //                                      GPG_Application app (system, maggie, startscenename);
547                                                 app.SetGameEngineData(maggie, startscenename);
548                                                 
549                                                 if (firstTimeRunning)
550                                                 {
551                                                         firstTimeRunning = false;
552                                                         
553                                                         if (fullScreen)
554                                                         {
555                                                                 app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
556                                                                         stereoWindow, stereomode);
557                                                         }
558                                                         else
559                                                         {
560 #ifdef __APPLE__
561                                                                 // on Mac's we'll show the executable name instead of the 'game.blend' name
562                                                                 char tempname[1024], *appstring;
563                                                                 ::strcpy(tempname, titlename);
564                                                                 
565                                                                 appstring = strstr(tempname, ".app/");
566                                                                 if (appstring) {
567                                                                         appstring[2] = 0;
568                                                                         titlename = &tempname[0];
569                                                                 }
570 #endif
571                                                                 // Strip the path so that we have the name of the game file
572                                                                 STR_String path = titlename;
573 #ifndef WIN32
574                                                                 vector<STR_String> parts = path.Explode('/');
575 #else  // WIN32
576                                                                 vector<STR_String> parts = path.Explode('\\');
577 #endif // WIN32                        
578                                                                 STR_String title;
579                                                                 if (parts.size())
580                                                                 {
581                                                                         title = parts[parts.size()-1];
582                                                                         parts = title.Explode('.');
583                                                                         if (parts.size() > 1)
584                                                                         {
585                                                                                 title = parts[0];
586                                                                         }
587                                                                 }
588                                                                 else
589                                                                 {
590                                                                         title = "blenderplayer";
591                                                                 }
592                                                                 app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
593                                                                         stereoWindow, stereomode);
594                                                         }
595                                                 }
596                                                 else
597                                                 {
598                                                         app.StartGameEngine(stereomode);
599                                                         exitcode = KX_EXIT_REQUEST_NO_REQUEST;
600                                                 }
601                                                 
602                                                 // Add the application as event consumer
603                                                 system->addEventConsumer(&app);
604                                                 
605                                                 // Enter main loop
606                                                 bool run = true;
607                                                 while (run)
608                                                 {
609                                                         system->processEvents(false);
610                                                         system->dispatchEvents();
611                                                         if ((exitcode = app.getExitRequested()))
612                                                         {
613                                                                 run = false;
614                                                                 exitstring = app.getExitString();
615                                                         }
616                                                 }
617                                                 app.StopGameEngine();
618                                                 BLO_blendfiledata_free(bfd);
619                                                 
620 #ifdef __APPLE__
621                                                 if (filename) {
622                                                         delete [] filename;
623                                                 }
624 #endif // __APPLE__
625                                         }
626                                 } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME);
627                         }
628                         // Dispose the system
629                         GHOST_ISystem::disposeSystem();
630                 } else {
631                         error = true;
632                         printf("error: couldn't create a system.\n");
633                 }
634         }
635         
636         return error ? -1 : 0;
637 }
638
639