tge/engine/platformMacCarb/macCarbMain.cc
2017-04-17 06:17:10 -06:00

244 lines
7.7 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platformMacCarb/platformMacCarb.h"
#include "platformMacCarb/macCarbEvents.h"
#include "platform/platformThread.h"
#include "platform/gameInterface.h"
#include "core/fileio.h"
//-----------------------------------------------------------------------------
// _MacCarbRunTorqueMain() starts the Game.main() loop
//-----------------------------------------------------------------------------
static void _MacCarbRunTorqueMain()
{
platState.torqueThreadId = Thread::getCurrentThreadId();
platState.windowSize.set(0,0);
platState.lastTimeTick = Platform::getRealMilliseconds();
platState.appReturn = Game->main(platState.argc, platState.argv);
if(!platState.headless)
{
HICommand cmd;
dMemset(&cmd, 0, sizeof(HICommand));
cmd.commandID = kHICommandQuit;
ProcessHICommand( &cmd );
}
}
//-----------------------------------------------------------------------------
// Handler stub for bsd signals.
//-----------------------------------------------------------------------------
static void _MacCarbSignalHandler(int )
{
// we send the torque thread a SIGALRM to wake it up from usleep()
// when transitioning from background - forground.
}
//-----------------------------------------------------------------------------
// Thread subclass, for running Torque in multithreaded mode
//-----------------------------------------------------------------------------
class TorqueMainThread : public Thread
{
public:
TorqueMainThread() : Thread(NULL,0,false) { }
virtual void run(S32 arg)
{
signal(SIGALRM, _MacCarbSignalHandler);
_MacCarbRunTorqueMain();
}
};
//-----------------------------------------------------------------------------
// RunAppEventLoop Callback, for running Torque in single threaded mode
//-----------------------------------------------------------------------------
void _MacCarbRAELCallback(EventLoopTimerRef theTimer, void *userData)
{
_MacCarbRunTorqueMain();
}
#pragma mark -
//-----------------------------------------------------------------------------
// command line arg processing
//-----------------------------------------------------------------------------
#define KEYISDOWN(key) ((((unsigned char *)currKeyState)[key>>3] >> (key & 7)) & 1)
static bool _MacCarbCheckProcessTxtFileArgs()
{
// this is yucky, but the easiest way to ignore the cmd line args:
KeyMap currKeyState;
GetKeys(currKeyState);
if (KEYISDOWN(0x38)) // check shift key -- actually LShift.
return false;
else
return true;
}
//-----------------------------------------------------------------------------
static void _MacCarbGetTxtFileArgs(int &argc, char** argv, int maxargc)
{
argc = 0;
const U32 kMaxTextLen = 2048; // arbitrary
U32 textLen;
char* text = new char[kMaxTextLen];
// open the file, kick out if we can't
File cmdfile;
File::Status err = cmdfile.open("maccmdline.txt", cmdfile.Read);
if(err != File::Ok)
return;
// read in the first kMaxTextLen bytes, kick out if we get errors or no data
err = cmdfile.read(kMaxTextLen-1, text, &textLen);
if(!((err == File::Ok || err == File::EOS) || textLen > 0))
{
cmdfile.close();
return;
}
// null terminate
text[textLen++] = '\0';
// truncate to the 1st line of the file
for(int i = 0; i < textLen; i++)
{
if( text[i] == '\n' || text[i] == '\r' )
{
text[i] = '\0';
textLen = i+1;
break;
}
}
// tokenize the args with nulls, save them in argv, count them in argc
char* tok;
for(tok = dStrtok(text, " "); tok && argc < maxargc; tok = dStrtok(NULL, " "))
{
argv[argc++] = tok;
}
}
//-----------------------------------------------------------------------------
static void _MacCarbFilterCmdLineArgs( int &argc, char** argv)
{
// MacOSX gui apps get at least 2 args: the full path to their binary,
// and a process serial number, formed something like: "-psn_0_123456".
// Torque doesnt want to see the psn arg, so we strip it out.
int j = 0;
for(int i = 0; i < argc; i++)
{
if(dStrncmp(argv[i], "-psn", 4) != 0)
argv[j++] = argv[i];
if(dStrncmp(argv[i], "-headless", 9) == 0)
{
printf("entering headless mode\n");
platState.headless = true;
}
}
argc = j;
}
#pragma mark -
//-----------------------------------------------------------------------------
// main() - the real one - this is the actual program entry point.
//-----------------------------------------------------------------------------
S32 main(S32 argc, const char **argv)
{
const int kMaxCmdlineArgs = 32; // arbitrary
// get the actual command line args
S32 newArgc = argc;
char* newArgv[kMaxCmdlineArgs];
for(int i=0; i < argc && i < kMaxCmdlineArgs; i++)
newArgv[i] = argv[i];
if( _MacCarbCheckProcessTxtFileArgs() )
{
// get the text file args
S32 textArgc;
char* textArgv[kMaxCmdlineArgs];
_MacCarbGetTxtFileArgs(textArgc, textArgv, kMaxCmdlineArgs);
// merge them
int i=0;
while(i < textArgc && newArgc < kMaxCmdlineArgs)
newArgv[newArgc++] = textArgv[i++];
}
// filter them
_MacCarbFilterCmdLineArgs( newArgc, newArgv);
// store them in platState
platState.argc = newArgc;
platState.argv = newArgv;
MacCarbInit1020CompatInit();
// Headless mode is for sitations where torque must run as a command line
// tool, without a connection to the window server. Any windowing or event
// calls may crash the app if there is no window server, so we avoid them
// in headless mode.
if(!platState.headless)
{
InitCursor();
FlushEvents( everyEvent, 0 );
SetEventMask(everyEvent);
// push us to the front, just to be sure
ProcessSerialNumber psn = { 0, kCurrentProcess };
SetFrontProcess(&psn);
}
// save away OS version info into platState.
Gestalt(gestaltSystemVersion, (SInt32 *) &(platState.osVersion));
// Update the current working directory.
Platform::getWorkingDirectory();
// now, we prepare to hand off execution to torque & macosx.
platState.appReturn = 0;
platState.firstThreadId = Thread::getCurrentThreadId();
#if !defined(TORQUE_MULTITHREAD)
// Install a one-shot timer to run the game, then call RAEL to install
// the default application handler (which can't be called directly).
EventLoopTimerRef timer;
InstallEventLoopTimer(GetCurrentEventLoop(), 0, 0,
NewEventLoopTimerUPP(_MacCarbRAELCallback), NULL, &timer);
RunApplicationEventLoop();
#else
// Put the Torque application loop in one thread, and the event listener loop
// in the other thread. The event loop must use the process's initial thread.
// We need to cache a ref to the main event queue because GetMainEventQueue
// is not thread safe pre 10.4 .
platState.mainEventQueue = GetMainEventQueue();
// We need to install event handlers for interthread communication.
// Events and some system calls must happen in the process's initial thread.
MacCarbInstallTorqueCarbonEventHandlers();
TorqueMainThread mainLoop;
mainLoop.start();
if(!platState.headless)
{
//printf("starting RAEL\n");
RunApplicationEventLoop();
}
//printf("trying to join main loop...\n");
mainLoop.join();
//printf("main loop joined.\n");
#endif
InitCursor(); // don't leave it in a screwy state...
//printf("exiting...\n");
return(platState.appReturn);
}