Added the runtime fullscreen options.
[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("  -w: display in a window\n");
111         printf("  -p: specify window position\n");
112         printf("       l = window left coordinate\n");
113         printf("       t = window top coordinate\n");
114         printf("       w = window width\n");
115         printf("       h = window height\n");
116 /*      printf("  -f: start game in full screen mode\n");
117         printf("       fw = full screen mode pixel width\n");
118         printf("       fh = full screen mode pixel height\n");
119         printf("       fb = full screen mode bits per pixel\n");
120         printf("       ff = full screen mode frequency\n"); */
121         printf("  -s: start player in stereo\n");
122         printf("       stereomode = hwpageflip or syncdoubling depending on the type of stereo you want\n");
123 #ifdef _WIN32
124         printf("  -c: keep console window open\n");
125 #endif
126         printf("\n");
127         printf("example: %s -p 10 10 320 200 -g noaudio c:\\loadtest.blend\n", program);
128 }
129
130 char *get_filename(int argc, char **argv) {
131 #ifdef __APPLE__
132 /* On Mac we park the game file (called game.blend) in the application bundle.
133 * The executable is located in the bundle as well.
134 * Therefore, we can locate the game relative to the executable.
135         */
136         int srclen = ::strlen(argv[0]);
137         int len = 0;
138         char *filename = NULL;
139         
140         if (argc > 1) {
141                 if (BLI_exists(argv[argc-1])) {
142                         len = ::strlen(argv[argc-1]);
143                         filename = new char [len + 1];
144                         ::strcpy(filename, argv[argc-1]);
145                         return(filename);
146                 }
147                 if (::strncmp(argv[argc-1], "-psn_", 5)==0) {
148                         static char firstfilebuf[512];
149                         if (GHOST_HACK_getFirstFile(firstfilebuf)) {
150                                 len = ::strlen(firstfilebuf);
151                                 filename = new char [len + 1];
152                                 ::strcpy(filename, firstfilebuf);
153                                 return(filename);
154                         }
155                 }                        
156         }
157         
158         srclen -= ::strlen("MacOS/blenderplayer");
159         if (srclen > 0) {
160                 len = srclen + ::strlen("Resources/game.blend"); 
161                 filename = new char [len + 1];
162                 ::strcpy(filename, argv[0]);
163                 ::strcpy(filename + srclen, "Resources/game.blend");
164                 //::printf("looking for file: %s\n", filename);
165                 
166                 if (BLI_exists(filename)) {
167                         return (filename);
168                 }
169         }
170         
171         return(NULL);
172 #else
173         return (argc>1)?argv[argc-1]:NULL;
174 #endif // !_APPLE
175 }
176
177 static BlendFileData *load_game_data(char *progname, char *filename = NULL) {
178         BlendReadError error;
179         BlendFileData *bfd = NULL;
180         
181         /* try to load ourself, will only work if we are a runtime */
182         if (blo_is_a_runtime(progname)) {
183                 bfd= blo_read_runtime(progname, &error);
184                 if (bfd) {
185                         bfd->type= BLENFILETYPE_RUNTIME;
186                         strcpy(bfd->main->name, progname);
187                 }
188         } else {
189                 bfd= BLO_read_from_file(progname, &error);
190         }
191         
192         /*
193         if (bfd && bfd->type == BLENFILETYPE_BLEND) {
194                 BLO_blendfiledata_free(bfd);
195                 bfd = NULL;
196                 error = BRE_NOT_A_PUBFILE;
197         }
198         */
199         
200         if (!bfd && filename) {
201                 bfd = load_game_data(filename);
202                 if (!bfd) {
203                         printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
204                 }
205         }
206         
207         return bfd;
208 }
209
210 int main(int argc, char** argv)
211 {
212         int i;
213         bool error = false;
214         SYS_SystemHandle syshandle = SYS_GetSystem();
215         bool fullScreen = false;
216         bool fullScreenParFound = false;
217         bool windowParFound = false;
218         bool closeConsole = true;
219         int stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
220         bool stereoWindow = false;
221         bool stereoParFound = false;
222         int windowLeft = 100;
223         int windowTop = 100;
224         int windowWidth = 640;
225         int windowHeight = 480;
226         GHOST_TUns32 fullScreenWidth = 0;
227         GHOST_TUns32 fullScreenHeight= 0;
228         int fullScreenBpp = 16;
229         int fullScreenFrequency = 60;
230         
231 #ifdef __linux__
232 #ifdef __alpha__
233         signal (SIGFPE, SIG_IGN);
234 #endif /* __alpha__ */
235 #endif /* __linux__ */
236         BLI_where_am_i(bprogname, argv[0]);
237         
238 #ifdef __APPLE__
239     // Can't use Carbon right now because of double defined type ID (In Carbon.h and DNA_ID.h, sigh)
240     /*
241     IBNibRef            nibRef;
242     WindowRef           window;
243     OSStatus            err;
244         
245           // Create a Nib reference passing the name of the nib file (without the .nib extension)
246           // CreateNibReference only searches into the application bundle.
247           err = ::CreateNibReference(CFSTR("main"), &nibRef);
248           if (err) return -1;
249           
250                 // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
251                 // object. This name is set in InterfaceBuilder when the nib is created.
252                 err = ::SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
253                 if (err) return -1;
254                 
255                   // We don't need the nib reference anymore.
256                   ::DisposeNibReference(nibRef);
257     */
258 #endif // __APPLE__
259         
260         GEN_init_messaging_system();
261         
262         // Parse command line options
263 #ifndef NDEBUG
264         printf("argv[0] = '%s'\n", argv[0]);
265 #endif
266         for (i = 1; (i < argc) && !error; i++)
267         {
268 #ifndef NDEBUG
269                 printf("argv[%d] = '%s'\n", i, argv[i]);
270 #endif
271                 
272                 if (argv[i][0] == '-')
273                 {
274                         switch (argv[i][1])
275                         {
276                         case 'g':
277                                 // Parse game options
278                                 {
279                                         i++;
280                                         if (i < argc)
281                                         {
282                                                 char* paramname = argv[i];
283                                                 // Check for single value versus assignment
284                                                 if (i+1 < argc && (*(argv[i+1]) == '='))
285                                                 {
286                                                         i++;
287                                                         if (i + 1 < argc)
288                                                         {
289                                                                 i++;
290                                                                 // Assignment
291                                                                 SYS_WriteCommandLineString(syshandle, paramname, argv[i]);
292                                                         }
293                                                         else
294                                                         {
295                                                                 error = true;
296                                                                 printf("error: argument assignment %s without value.\n", paramname);
297                                                         }
298                                                 }
299                                                 else
300                                                 {
301                                                         SYS_WriteCommandLineInt(syshandle, argv[i], 1);
302                                                 }
303                                         }
304                                 }
305                                 break;
306                                 
307                         case 'p':
308                                 // Parse window position and size options
309                                 if (argv[i][2] == 0) {
310                                         i++;
311                                         if ((i + 4) < argc)
312                                         {
313                                                 windowLeft = atoi(argv[i++]);
314                                                 windowTop = atoi(argv[i++]);
315                                                 windowWidth = atoi(argv[i++]);
316                                                 windowHeight = atoi(argv[i]);
317                                                 windowParFound = true;
318                                         }
319                                         else
320                                         {
321                                                 error = true;
322                                                 printf("error: too few options for window argument.\n");
323                                         }
324                                 }
325                                 break;
326                                 
327                         case 'w':
328                                 // Parse window position and size options
329                                 {
330                                         fullScreen = false;
331                                                 fullScreenParFound = true;
332                                         i++;
333                                 }
334                                 break;
335                         case 'c':
336                                 i++;
337                                 closeConsole = false;
338                                 break;
339                         case 's':  // stereo
340                                 i++;
341                                 if ((i + 1) < argc)
342                                 {
343                                         if(!strcmp(argv[i], "nostereo"))  // ok, redundant but clear
344                                                 stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
345                                         
346                                         // only the hardware pageflip method needs a stereo window
347                                         if(!strcmp(argv[i], "hwpageflip")) {
348                                                 stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
349                                                 stereoWindow = true;
350                                         }
351                                         if(!strcmp(argv[i], "syncdoubling"))
352                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;
353 #if 0
354                                         // future stuff
355                                         if(strcmp(argv[i], "stencil")
356                                                 stereomode = RAS_STEREO_STENCIL;
357 #endif
358                                         
359                                         i++;
360                                         stereoParFound = true;
361                                 }
362                                 else
363                                 {
364                                         error = true;
365                                         printf("error: too few options for stereo argument.\n");
366                                 }
367                                 break;
368                         }
369                 }
370                 else
371                 {
372                 }
373         }
374         
375         if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight))
376         {
377                 error = true;
378                 printf("error: window size too small.\n");
379         }
380         
381         if (error)
382         {
383                 usage(argv[0]);
384         }
385         else
386         {
387 #ifdef __APPLE__
388                 //SYS_WriteCommandLineInt(syshandle, "show_framerate", 1);
389                 SYS_WriteCommandLineInt(syshandle, "nomipmap", 1);
390                 //fullScreen = false;           // Can't use full screen
391 #endif
392                 if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0))
393                 {
394                         GPC_PolygonMaterial::SetMipMappingEnabled(0);
395                 }
396                 
397                 // Create the system
398                 if (GHOST_ISystem::createSystem() == GHOST_kSuccess)
399                 {
400                         GHOST_ISystem* system = GHOST_ISystem::getSystem();
401                         assertd(system);
402                         
403                         system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight);
404                         // process first batch of events. If the user
405                         // drops a file on top off the blenderplayer icon, we 
406                         // recieve an event with the filename
407                         
408                         system->processEvents(0);
409                         
410                         // this bracket is needed for app (see below) to get out
411                         // of scope before GHOST_ISystem::disposeSystem() is called.
412                         {
413                                 int exitcode = KX_EXIT_REQUEST_NO_REQUEST;
414                                 STR_String exitstring = "";
415                                 GPG_Application app(system, NULL, exitstring);
416                                 bool firstTimeRunning = true;
417                                 
418                                 do
419                                 {
420                                         // Read the Blender file
421                                         char *filename = get_filename(argc, argv);
422                                         char *titlename;
423                                         char pathname[160];
424                                         BlendFileData *bfd;
425                                         
426                                         // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
427                                         if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME)
428                                         {
429                                                 char basedpath[160];
430                                                 
431                                                 // base the actuator filename with respect
432                                                 // to the original file working directory
433                                                 strcpy(basedpath, exitstring.Ptr());
434                                                 BLI_convertstringcode(basedpath, pathname, 0);
435                                                 
436                                                 bfd = load_game_data(basedpath);
437                                         }
438                                         else
439                                         {
440                                                 bfd = load_game_data(argv[0], filename);
441                                         }
442                                         
443                                         //::printf("game data loaded from %s\n", filename);
444                                         
445                                         if (!bfd) {
446                                                 usage(argv[0]);
447                                                 error = true;
448                                                 exitcode = KX_EXIT_REQUEST_QUIT_GAME;
449                                         } 
450                                         else 
451                                         {
452 #ifdef WIN32
453 #ifdef NDEBUG
454                                                 if (closeConsole)
455                                                 {
456                                                         ::FreeConsole();    // Close a console window
457                                                 }
458 #endif // NDEBUG
459 #endif // WIN32
460                                                 Main *maggie = bfd->main;
461                                                 Scene *scene = bfd->curscene;
462                                                 strcpy (pathname, maggie->name);
463                                                 char *startscenename = scene->id.name + 2;
464                                                 
465                                                 titlename = maggie->name;
466                                                 
467                                                 // Check whether the game should be displayed full-screen
468                                                 if ((!fullScreenParFound) && (!windowParFound))
469                                                 {
470                                                         // Only use file settings when command line did not override
471                                                         if (scene->r.fullscreen) {
472                                                                 //printf("fullscreen option found in Blender file\n");
473                                                                 fullScreen = true;
474                                                                 fullScreenWidth= scene->r.xplay;
475                                                                 fullScreenHeight= scene->r.yplay;
476                                                                 fullScreenFrequency= scene->r.freqplay;
477                                                                 fullScreenBpp = scene->r.depth;
478                                                         }
479                                                         else
480                                                         {
481                                                                 fullScreen = false;
482                                                                 windowWidth = scene->r.xplay;
483                                                                 windowHeight = scene->r.yplay;
484                                                         }
485                                                 }
486                                                 
487                                                 
488                                                 // Check whether the game should be displayed in stereo
489                                                 if (!stereoParFound)
490                                                 {
491                                                         if(scene->r.stereomode == RAS_IRasterizer::RAS_STEREO_NOSTEREO)  // ok, redundant but clear
492                                                                 stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
493                                                         
494                                                         // only the hardware pageflip method needs a stereo window
495                                                         if(scene->r.stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) {
496                                                                 stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
497                                                                 stereoWindow = true;
498                                                         }
499                                                         if(scene->r.stereomode == RAS_IRasterizer::RAS_STEREO_ABOVEBELOW)
500                                                                 stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;
501 #if 0
502                                                         // future stuff
503                                                         if(scene->r.stereomode == RAS_IRasterizer::RAS_STEREO_STENCIL)
504                                                                 stereomode = RAS_STEREO_STENCIL;
505 #endif
506                                                 }
507                                                 
508                                                 //                                      GPG_Application app (system, maggie, startscenename);
509                                                 app.SetGameEngineData(maggie, startscenename);
510                                                 
511                                                 if (firstTimeRunning)
512                                                 {
513                                                         firstTimeRunning = false;
514                                                         
515                                                         if (fullScreen)
516                                                         {
517                                                                 app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
518                                                                         stereoWindow, stereomode);
519                                                         }
520                                                         else
521                                                         {
522 #ifdef __APPLE__
523                                                                 // on Mac's we'll show the executable name instead of the 'game.blend' name
524                                                                 char tempname[1024], *appstring;
525                                                                 ::strcpy(tempname, titlename);
526                                                                 
527                                                                 appstring = strstr(tempname, ".app/");
528                                                                 if (appstring) {
529                                                                         appstring[2] = 0;
530                                                                         titlename = &tempname[0];
531                                                                 }
532 #endif
533                                                                 // Strip the path so that we have the name of the game file
534                                                                 STR_String path = titlename;
535 #ifndef WIN32
536                                                                 vector<STR_String> parts = path.Explode('/');
537 #else  // WIN32
538                                                                 vector<STR_String> parts = path.Explode('\\');
539 #endif // WIN32                        
540                                                                 STR_String title;
541                                                                 if (parts.size())
542                                                                 {
543                                                                         title = parts[parts.size()-1];
544                                                                         parts = title.Explode('.');
545                                                                         if (parts.size() > 1)
546                                                                         {
547                                                                                 title = parts[0];
548                                                                         }
549                                                                 }
550                                                                 else
551                                                                 {
552                                                                         title = "blenderplayer";
553                                                                 }
554                                                                 app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
555                                                                         stereoWindow, stereomode);
556                                                         }
557                                                 }
558                                                 else
559                                                 {
560                                                         app.StartGameEngine(stereomode);
561                                                         exitcode = KX_EXIT_REQUEST_NO_REQUEST;
562                                                 }
563                                                 
564                                                 // Add the application as event consumer
565                                                 system->addEventConsumer(&app);
566                                                 
567                                                 // Enter main loop
568                                                 bool run = true;
569                                                 while (run)
570                                                 {
571                                                         system->processEvents(false);
572                                                         system->dispatchEvents();
573                                                         if ((exitcode = app.getExitRequested()))
574                                                         {
575                                                                 run = false;
576                                                                 exitstring = app.getExitString();
577                                                         }
578                                                 }
579                                                 app.StopGameEngine();
580                                                 BLO_blendfiledata_free(bfd);
581                                                 
582 #ifdef __APPLE__
583                                                 if (filename) {
584                                                         delete [] filename;
585                                                 }
586 #endif // __APPLE__
587                                         }
588                                 } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME);
589                         }
590                         // Dispose the system
591                         GHOST_ISystem::disposeSystem();
592                 } else {
593                         error = true;
594                         printf("error: couldn't create a system.\n");
595                 }
596         }
597         
598         return error ? -1 : 0;
599 }
600
601