244 lines
7.7 KiB
C++
Executable File
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);
|
|
|
|
}
|