915 lines
27 KiB
C++
Executable File
915 lines
27 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "console/console.h"
|
|
#include "core/fileStream.h"
|
|
#include "game/resource.h"
|
|
#include "game/version.h"
|
|
#include "math/mRandom.h"
|
|
#include "platformX86UNIX/platformX86UNIX.h"
|
|
#include "platformX86UNIX/x86UNIXStdConsole.h"
|
|
#include "platform/event.h"
|
|
#include "platform/gameInterface.h"
|
|
#include "platform/platform.h"
|
|
#include "platform/platformAL.h"
|
|
#include "platform/platformInput.h"
|
|
#include "platform/platformVideo.h"
|
|
#include "platform/profiler.h"
|
|
#include "platformX86UNIX/platformGL.h"
|
|
#include "platformX86UNIX/x86UNIXOGLVideo.h"
|
|
#include "platformX86UNIX/x86UNIXState.h"
|
|
|
|
#ifndef DEDICATED
|
|
#include "platformX86UNIX/x86UNIXMessageBox.h"
|
|
#include "platformX86UNIX/x86UNIXInputManager.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h> // fork, execvp, chdir
|
|
#include <time.h> // nanosleep
|
|
|
|
#ifndef DEDICATED
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xos.h>
|
|
|
|
#include <SDL/SDL.h>
|
|
#include <SDL/SDL_syswm.h>
|
|
#include <SDL/SDL_version.h>
|
|
#endif
|
|
|
|
x86UNIXPlatformState *x86UNIXState;
|
|
|
|
bool DisplayPtrManager::sgDisplayLocked = false;
|
|
LockFunc_t DisplayPtrManager::sgLockFunc = NULL;
|
|
LockFunc_t DisplayPtrManager::sgUnlockFunc = NULL;
|
|
|
|
static U32 lastTimeTick;
|
|
static MRandomLCG sgPlatRandom;
|
|
|
|
#ifndef DEDICATED
|
|
extern void InstallRedBookDevices();
|
|
extern void PollRedbookDevices();
|
|
extern bool InitOpenGL();
|
|
// This is called when some X client sends
|
|
// a selection event (e.g. SelectionRequest)
|
|
// to the window
|
|
extern void NotifySelectionEvent(XEvent& event);
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
static S32 ParseCommandLine(S32 argc, const char **argv,
|
|
Vector<char*>& newCommandLine)
|
|
{
|
|
x86UNIXState->setExePathName(argv[0]);
|
|
bool foundDedicated = false;
|
|
|
|
for ( int i=0; i < argc; i++ )
|
|
{
|
|
// look for platform specific args
|
|
if (dStrcmp(argv[i], "-version") == 0)
|
|
{
|
|
dPrintf("%s (built on %s)\n", getVersionString(), getCompileTimeString());
|
|
dPrintf("gcc: %s\n", __VERSION__);
|
|
return 1;
|
|
}
|
|
if (dStrcmp(argv[i], "-cdaudio") == 0)
|
|
{
|
|
x86UNIXState->setCDAudioEnabled(true);
|
|
continue;
|
|
}
|
|
if (dStrcmp(argv[i], "-dedicated") == 0)
|
|
{
|
|
foundDedicated = true;
|
|
// no continue because dedicated is also handled by script
|
|
}
|
|
if (dStrcmp(argv[i], "-dsleep") == 0)
|
|
{
|
|
x86UNIXState->setDSleep(true);
|
|
continue;
|
|
}
|
|
if (dStrcmp(argv[i], "-nohomedir") == 0)
|
|
{
|
|
x86UNIXState->setUseRedirect(false);
|
|
continue;
|
|
}
|
|
if (dStrcmp(argv[i], "-chdir") == 0)
|
|
{
|
|
if ( ++i >= argc )
|
|
{
|
|
dPrintf("Follow -chdir option with the desired working directory.\n");
|
|
return 1;
|
|
}
|
|
if (chdir(argv[i]) == -1)
|
|
{
|
|
dPrintf("Unable to chdir to %s: %s\n", argv[i], strerror(errno));
|
|
return 1;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// copy the arg into newCommandLine
|
|
int argLen = dStrlen(argv[i]) + 1;
|
|
char* argBuf = new char[argLen]; // this memory is deleted in main()
|
|
dStrncpy(argBuf, argv[i], argLen);
|
|
newCommandLine.push_back(argBuf);
|
|
}
|
|
x86UNIXState->setDedicated(foundDedicated);
|
|
#if defined(DEDICATED) && !defined(TORQUE_ENGINE)
|
|
if (!foundDedicated)
|
|
{
|
|
dPrintf("This is a dedicated server build. You must supply the -dedicated command line parameter.\n");
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void DetectWindowingSystem()
|
|
{
|
|
#ifndef DEDICATED
|
|
Display* dpy = XOpenDisplay(NULL);
|
|
if (dpy != NULL)
|
|
{
|
|
x86UNIXState->setXWindowsRunning(true);
|
|
XCloseDisplay(dpy);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static void InitWindow(const Point2I &initialSize, const char *name)
|
|
{
|
|
x86UNIXState->setWindowSize(initialSize);
|
|
x86UNIXState->setWindowName(name);
|
|
}
|
|
|
|
#ifndef DEDICATED
|
|
//------------------------------------------------------------------------------
|
|
static bool InitSDL()
|
|
{
|
|
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
|
return false;
|
|
|
|
atexit(SDL_Quit);
|
|
|
|
SDL_SysWMinfo sysinfo;
|
|
SDL_VERSION(&sysinfo.version);
|
|
if (SDL_GetWMInfo(&sysinfo) == 0)
|
|
return false;
|
|
|
|
x86UNIXState->setDisplayPointer(sysinfo.info.x11.display);
|
|
DisplayPtrManager::setDisplayLockFunction(sysinfo.info.x11.lock_func);
|
|
DisplayPtrManager::setDisplayUnlockFunction(sysinfo.info.x11.unlock_func);
|
|
|
|
DisplayPtrManager xdisplay;
|
|
Display* display = xdisplay.getDisplayPointer();
|
|
|
|
x86UNIXState->setScreenNumber(
|
|
DefaultScreen( display ) );
|
|
x86UNIXState->setScreenPointer(
|
|
DefaultScreenOfDisplay( display ) );
|
|
|
|
x86UNIXState->setDesktopSize(
|
|
(S32) DisplayWidth(
|
|
display,
|
|
x86UNIXState->getScreenNumber()),
|
|
(S32) DisplayHeight(
|
|
display,
|
|
x86UNIXState->getScreenNumber())
|
|
);
|
|
x86UNIXState->setDesktopBpp(
|
|
(S32) DefaultDepth(
|
|
display,
|
|
x86UNIXState->getScreenNumber()));
|
|
|
|
// indicate that we want sys WM messages
|
|
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static void ProcessSYSWMEvent(const SDL_Event& event)
|
|
{
|
|
XEvent& xevent = event.syswm.msg->event.xevent;
|
|
//Con::printf("xevent : %d", xevent.type);
|
|
switch (xevent.type)
|
|
{
|
|
case SelectionRequest:
|
|
// somebody wants our clipboard
|
|
NotifySelectionEvent(xevent);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static void SetAppState()
|
|
{
|
|
U8 state = SDL_GetAppState();
|
|
|
|
// if we're not active but we have appactive and inputfocus, set window
|
|
// active and reactivate input
|
|
if ((!x86UNIXState->windowActive() || !Input::isActive()) &&
|
|
state & SDL_APPACTIVE &&
|
|
state & SDL_APPINPUTFOCUS)
|
|
{
|
|
x86UNIXState->setWindowActive(true);
|
|
Input::reactivate();
|
|
}
|
|
// if we are active, but we don't have appactive or input focus,
|
|
// deactivate input (if window not locked) and clear windowActive
|
|
else if (x86UNIXState->windowActive() &&
|
|
!(state & SDL_APPACTIVE && state & SDL_APPINPUTFOCUS))
|
|
{
|
|
if (x86UNIXState->windowLocked())
|
|
Input::deactivate();
|
|
x86UNIXState->setWindowActive(false);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static S32 NumEventsPending()
|
|
{
|
|
static const int MaxEvents = 255;
|
|
static SDL_Event events[MaxEvents];
|
|
|
|
SDL_PumpEvents();
|
|
return SDL_PeepEvents(events, MaxEvents, SDL_PEEKEVENT, SDL_ALLEVENTS);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static void PrintSDLEventQueue()
|
|
{
|
|
static const int MaxEvents = 255;
|
|
static SDL_Event events[MaxEvents];
|
|
|
|
SDL_PumpEvents();
|
|
S32 numEvents = SDL_PeepEvents(
|
|
events, MaxEvents, SDL_PEEKEVENT, SDL_ALLEVENTS);
|
|
if (numEvents <= 0)
|
|
{
|
|
dPrintf("SDL Event Queue is empty\n");
|
|
return;
|
|
}
|
|
|
|
dPrintf("SDL Event Queue:\n");
|
|
for (int i = 0; i < numEvents; ++i)
|
|
{
|
|
const char *eventType;
|
|
switch (events[i].type)
|
|
{
|
|
case SDL_NOEVENT: eventType = "SDL_NOEVENT"; break;
|
|
case SDL_ACTIVEEVENT: eventType = "SDL_ACTIVEEVENT"; break;
|
|
case SDL_KEYDOWN: eventType = "SDL_KEYDOWN"; break;
|
|
case SDL_KEYUP: eventType = "SDL_KEYUP"; break;
|
|
case SDL_MOUSEMOTION: eventType = "SDL_MOUSEMOTION"; break;
|
|
case SDL_MOUSEBUTTONDOWN: eventType = "SDL_MOUSEBUTTONDOWN"; break;
|
|
case SDL_MOUSEBUTTONUP: eventType = "SDL_MOUSEBUTTONUP"; break;
|
|
case SDL_JOYAXISMOTION: eventType = "SDL_JOYAXISMOTION"; break;
|
|
case SDL_JOYBALLMOTION: eventType = "SDL_JOYBALLMOTION"; break;
|
|
case SDL_JOYHATMOTION: eventType = "SDL_JOYHATMOTION"; break;
|
|
case SDL_JOYBUTTONDOWN: eventType = "SDL_JOYBUTTONDOWN"; break;
|
|
case SDL_JOYBUTTONUP: eventType = "SDL_JOYBUTTONUP"; break;
|
|
case SDL_QUIT: eventType = "SDL_QUIT"; break;
|
|
case SDL_SYSWMEVENT: eventType = "SDL_SYSWMEVENT"; break;
|
|
case SDL_VIDEORESIZE: eventType = "SDL_VIDEORESIZE"; break;
|
|
case SDL_VIDEOEXPOSE: eventType = "SDL_VIDEOEXPOSE"; break;
|
|
/* Events SDL_USEREVENT through SDL_MAXEVENTS-1 are for your use */
|
|
case SDL_USEREVENT: eventType = "SDL_USEREVENT"; break;
|
|
default: eventType = "UNKNOWN!"; break;
|
|
}
|
|
dPrintf("Event %d: %s\n", i, eventType);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static bool ProcessMessages()
|
|
{
|
|
static const int MaxEvents = 255;
|
|
static const U32 Mask =
|
|
SDL_QUITMASK | SDL_VIDEORESIZEMASK | SDL_VIDEOEXPOSEMASK |
|
|
SDL_ACTIVEEVENTMASK | SDL_SYSWMEVENTMASK |
|
|
SDL_EVENTMASK(SDL_USEREVENT);
|
|
static SDL_Event events[MaxEvents];
|
|
|
|
SDL_PumpEvents();
|
|
S32 numEvents = SDL_PeepEvents(events, MaxEvents, SDL_GETEVENT, Mask);
|
|
if (numEvents == 0)
|
|
return true;
|
|
for (int i = 0; i < numEvents; ++i)
|
|
{
|
|
SDL_Event& event = events[i];
|
|
switch (event.type)
|
|
{
|
|
case SDL_QUIT:
|
|
return false;
|
|
break;
|
|
case SDL_VIDEORESIZE:
|
|
case SDL_VIDEOEXPOSE:
|
|
Game->refreshWindow();
|
|
break;
|
|
case SDL_USEREVENT:
|
|
if (event.user.code == TORQUE_SETVIDEOMODE)
|
|
{
|
|
SetAppState();
|
|
// SDL will send a motion event to restore the mouse position
|
|
// on the new window. Ignore that if the window is locked.
|
|
if (x86UNIXState->windowLocked())
|
|
{
|
|
SDL_Event tempEvent;
|
|
SDL_PeepEvents(&tempEvent, 1, SDL_GETEVENT,
|
|
SDL_MOUSEMOTIONMASK);
|
|
}
|
|
}
|
|
break;
|
|
case SDL_ACTIVEEVENT:
|
|
SetAppState();
|
|
break;
|
|
case SDL_SYSWMEVENT:
|
|
ProcessSYSWMEvent(event);
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// send a destroy window event to the window. assumes
|
|
// window is created.
|
|
void SendQuitEvent()
|
|
{
|
|
SDL_Event quitevent;
|
|
quitevent.type = SDL_QUIT;
|
|
SDL_PushEvent(&quitevent);
|
|
}
|
|
#endif // DEDICATED
|
|
|
|
//------------------------------------------------------------------------------
|
|
static inline void Sleep(int secs, int nanoSecs)
|
|
{
|
|
timespec sleeptime;
|
|
sleeptime.tv_sec = secs;
|
|
sleeptime.tv_nsec = nanoSecs;
|
|
nanosleep(&sleeptime, NULL);
|
|
}
|
|
|
|
#ifndef DEDICATED
|
|
struct AlertWinState
|
|
{
|
|
bool fullScreen;
|
|
bool cursorHidden;
|
|
bool inputGrabbed;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
void DisplayErrorAlert(const char* errMsg, bool showSDLError)
|
|
{
|
|
char fullErrMsg[2048];
|
|
dStrncpy(fullErrMsg, errMsg, sizeof(fullErrMsg));
|
|
|
|
if (showSDLError)
|
|
{
|
|
char* sdlerror = SDL_GetError();
|
|
if (sdlerror != NULL && dStrlen(sdlerror) > 0)
|
|
{
|
|
dStrcat(fullErrMsg, " (Error: ");
|
|
dStrcat(fullErrMsg, sdlerror);
|
|
dStrcat(fullErrMsg, ")");
|
|
}
|
|
}
|
|
|
|
Platform::AlertOK("Error", fullErrMsg);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
static inline void AlertDisableVideo(AlertWinState& state)
|
|
{
|
|
|
|
state.fullScreen = Video::isFullScreen();
|
|
state.cursorHidden = (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE);
|
|
state.inputGrabbed = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
|
|
|
|
if (state.fullScreen)
|
|
SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
|
|
if (state.cursorHidden)
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
if (state.inputGrabbed)
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static inline void AlertEnableVideo(AlertWinState& state)
|
|
{
|
|
if (state.fullScreen)
|
|
SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
|
|
if (state.cursorHidden)
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
if (state.inputGrabbed)
|
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
}
|
|
#endif // DEDICATED
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::AlertOK(const char *windowTitle, const char *message)
|
|
{
|
|
#ifndef DEDICATED
|
|
if (x86UNIXState->isXWindowsRunning())
|
|
{
|
|
AlertWinState state;
|
|
AlertDisableVideo(state);
|
|
|
|
DisplayPtrManager xdisplay;
|
|
XMessageBox mBox(xdisplay.getDisplayPointer());
|
|
mBox.alertOK(windowTitle, message);
|
|
|
|
AlertEnableVideo(state);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (Con::isActive() && StdConsole::isEnabled())
|
|
Con::printf("Alert: %s %s", windowTitle, message);
|
|
else
|
|
dPrintf("Alert: %s %s\n", windowTitle, message);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
|
|
{
|
|
#ifndef DEDICATED
|
|
if (x86UNIXState->isXWindowsRunning())
|
|
{
|
|
AlertWinState state;
|
|
AlertDisableVideo(state);
|
|
|
|
DisplayPtrManager xdisplay;
|
|
XMessageBox mBox(xdisplay.getDisplayPointer());
|
|
bool val =
|
|
mBox.alertOKCancel(windowTitle, message) == XMessageBox::OK;
|
|
|
|
AlertEnableVideo(state);
|
|
return val;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (Con::isActive() && StdConsole::isEnabled())
|
|
Con::printf("Alert: %s %s", windowTitle, message);
|
|
else
|
|
dPrintf("Alert: %s %s\n", windowTitle, message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Platform::AlertRetry(const char *windowTitle, const char *message)
|
|
{
|
|
#ifndef DEDICATED
|
|
if (x86UNIXState->isXWindowsRunning())
|
|
{
|
|
AlertWinState state;
|
|
AlertDisableVideo(state);
|
|
|
|
DisplayPtrManager xdisplay;
|
|
XMessageBox mBox(xdisplay.getDisplayPointer());
|
|
bool val =
|
|
mBox.alertRetryCancel(windowTitle, message) == XMessageBox::Retry;
|
|
|
|
AlertEnableVideo(state);
|
|
return val;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (Con::isActive() && StdConsole::isEnabled())
|
|
Con::printf("Alert: %s %s", windowTitle, message);
|
|
else
|
|
dPrintf("Alert: %s %s\n", windowTitle, message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Platform::excludeOtherInstances(const char *mutexName)
|
|
{
|
|
return AcquireProcessMutex(mutexName);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::enableKeyboardTranslation(void)
|
|
{
|
|
#ifndef DEDICATED
|
|
// JMQ: not sure if this is needed for i18n keyboards
|
|
//SDL_EnableUNICODE( 1 );
|
|
// SDL_EnableKeyRepeat(
|
|
// SDL_DEFAULT_REPEAT_DELAY,
|
|
// SDL_DEFAULT_REPEAT_INTERVAL);
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::disableKeyboardTranslation(void)
|
|
{
|
|
#ifndef DEDICATED
|
|
//SDL_EnableUNICODE( 0 );
|
|
// SDL_EnableKeyRepeat(0, 0);
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::setWindowLocked(bool locked)
|
|
{
|
|
#ifndef DEDICATED
|
|
x86UNIXState->setWindowLocked(locked);
|
|
|
|
UInputManager* uInputManager =
|
|
dynamic_cast<UInputManager*>( Input::getManager() );
|
|
|
|
if ( uInputManager && uInputManager->isEnabled() &&
|
|
Input::isActive() )
|
|
uInputManager->setWindowLocked(locked);
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::minimizeWindow()
|
|
{
|
|
#ifndef DEDICATED
|
|
if (x86UNIXState->windowCreated())
|
|
SDL_WM_IconifyWindow();
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::process()
|
|
{
|
|
PROFILE_START(XUX_PlatformProcess);
|
|
stdConsole->process();
|
|
|
|
if (x86UNIXState->windowCreated())
|
|
{
|
|
#ifndef DEDICATED
|
|
// process window events
|
|
PROFILE_START(XUX_ProcessMessages);
|
|
bool quit = !ProcessMessages();
|
|
PROFILE_END();
|
|
if(quit)
|
|
{
|
|
// generate a quit event
|
|
Event quitEvent;
|
|
quitEvent.type = QuitEventType;
|
|
Game->postEvent(quitEvent);
|
|
}
|
|
|
|
// process input events
|
|
PROFILE_START(XUX_InputProcess);
|
|
Input::process();
|
|
PROFILE_END();
|
|
|
|
// poll redbook state
|
|
PROFILE_START(XUX_PollRedbookDevices);
|
|
PollRedbookDevices();
|
|
PROFILE_END();
|
|
|
|
// if we're not the foreground window, sleep for 1 ms
|
|
if (!x86UNIXState->windowActive())
|
|
Sleep(0, getBackgroundSleepTime() * 1000000);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// no window
|
|
// if we're not in journal mode, sleep for 1 ms
|
|
// JMQ: since linux's minimum sleep latency seems to be 20ms, this can
|
|
// increase player pings by 10-20ms in the dedicated server. So
|
|
// you have to use -dsleep to enable it. the server sleeps anyway when
|
|
// there are no players connected.
|
|
// JMQ: recent kernels (such as RH 8.0 2.4.18) reduce the latency
|
|
// to 2-4 ms on average.
|
|
if (!Game->isJournalReading() && (x86UNIXState->getDSleep() ||
|
|
Con::getIntVariable("Server::PlayerCount") -
|
|
Con::getIntVariable("Server::BotCount") <= 0))
|
|
{
|
|
PROFILE_START(XUX_Sleep);
|
|
Sleep(0, getBackgroundSleepTime() * 1000000);
|
|
PROFILE_END();
|
|
}
|
|
}
|
|
|
|
#ifndef DEDICATED
|
|
#if 0
|
|
// JMQ: disabled this because it may fire mistakenly in some configurations.
|
|
// sdl's default event handling scheme should be enough.
|
|
// crude check to make sure that we're not loading up events. the sdl
|
|
// event queue should never have more than (say) 25 events in it at this
|
|
// point
|
|
const int MaxEvents = 25;
|
|
if (NumEventsPending() > MaxEvents)
|
|
{
|
|
PrintSDLEventQueue();
|
|
AssertFatal(false, "The SDL event queue has too many events!");
|
|
}
|
|
#endif
|
|
#endif
|
|
PROFILE_END();
|
|
}
|
|
|
|
// extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );
|
|
|
|
// #if defined(DEBUG) || defined(INTERNAL_RELEASE)
|
|
// static U32 stubCRC = 0;
|
|
// #else
|
|
// static U32 stubCRC = 0xEA63F56C;
|
|
// #endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
const Point2I &Platform::getWindowSize()
|
|
{
|
|
return x86UNIXState->getWindowSize();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::setWindowSize( U32 newWidth, U32 newHeight )
|
|
{
|
|
x86UNIXState->setWindowSize( (S32) newWidth, (S32) newHeight );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::shutdown()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::init()
|
|
{
|
|
// Set the platform variable for the scripts
|
|
Con::setVariable( "$platform", "x86UNIX" );
|
|
#if defined(__linux__)
|
|
Con::setVariable( "$platformUnixType", "Linux" );
|
|
#elif defined(__OpenBSD__)
|
|
Con::setVariable( "$platformUnixType", "OpenBSD" );
|
|
#else
|
|
Con::setVariable( "$platformUnixType", "Unknown" );
|
|
#endif
|
|
|
|
StdConsole::create();
|
|
|
|
#ifndef DEDICATED
|
|
// if we're not dedicated do more initialization
|
|
if (!x86UNIXState->isDedicated())
|
|
{
|
|
// init SDL
|
|
if (!InitSDL())
|
|
{
|
|
DisplayErrorAlert("Unable to initialize SDL.");
|
|
ImmediateShutdown(1);
|
|
}
|
|
|
|
// initialize input
|
|
Input::init();
|
|
|
|
// initialize redbook devices
|
|
if (x86UNIXState->getCDAudioEnabled())
|
|
InstallRedBookDevices();
|
|
|
|
Con::printf( "Video Init:" );
|
|
|
|
// load gl library
|
|
if (!GLLoader::OpenGLInit())
|
|
{
|
|
DisplayErrorAlert("Unable to initialize OpenGL.");
|
|
ImmediateShutdown(1);
|
|
}
|
|
|
|
// initialize video
|
|
Video::init();
|
|
if ( Video::installDevice( OpenGLDevice::create() ) )
|
|
Con::printf( " OpenGL display device detected." );
|
|
else
|
|
Con::printf( " OpenGL display device not detected." );
|
|
|
|
Con::printf(" ");
|
|
}
|
|
#endif
|
|
// if we are dedicated, do sleep timing and display results
|
|
if (x86UNIXState->isDedicated())
|
|
{
|
|
const S32 MaxSleepIter = 10;
|
|
U32 totalSleepTime = 0;
|
|
U32 start;
|
|
for (S32 i = 0; i < MaxSleepIter; ++i)
|
|
{
|
|
start = Platform::getRealMilliseconds();
|
|
Sleep(0, 1000000);
|
|
totalSleepTime += Platform::getRealMilliseconds() - start;
|
|
}
|
|
U32 average = static_cast<U32>(totalSleepTime / MaxSleepIter);
|
|
|
|
Con::printf("Sleep latency: %ums", average);
|
|
// dPrintf as well, since console output won't be visible yet
|
|
dPrintf("Sleep latency: %ums\n", average);
|
|
if (!x86UNIXState->getDSleep() && average < 10)
|
|
{
|
|
const char* msg = "Sleep latency ok, enabling dsleep for lower cpu " \
|
|
"utilization";
|
|
Con::printf("%s", msg);
|
|
dPrintf("%s\n", msg);
|
|
x86UNIXState->setDSleep(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::initWindow(const Point2I &initialSize, const char *name)
|
|
{
|
|
#ifndef DEDICATED
|
|
// initialize window
|
|
InitWindow(initialSize, name);
|
|
if (!InitOpenGL())
|
|
ImmediateShutdown(1);
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
F32 Platform::getRandom()
|
|
{
|
|
return sgPlatRandom.randF();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Web browser function:
|
|
//------------------------------------------------------------------------------
|
|
bool Platform::openWebBrowser( const char* webAddress )
|
|
{
|
|
if (!webAddress || dStrlen(webAddress)==0)
|
|
return false;
|
|
|
|
// look for a browser preference variable
|
|
// JMQTODO: be nice to implement some UI to customize this
|
|
const char* webBrowser = Con::getVariable("Pref::Unix::WebBrowser");
|
|
if (dStrlen(webBrowser) == 0)
|
|
webBrowser = NULL;
|
|
|
|
pid_t pid = fork();
|
|
if (pid == -1)
|
|
{
|
|
Con::printf("WARNING: Platform::openWebBrowser failed to fork");
|
|
return false;
|
|
}
|
|
else if (pid != 0)
|
|
{
|
|
// parent
|
|
if (Video::isFullScreen())
|
|
Video::toggleFullScreen();
|
|
|
|
return true;
|
|
}
|
|
else if (pid == 0)
|
|
{
|
|
// child
|
|
// try to exec konqueror, then netscape
|
|
char* argv[3];
|
|
argv[0] = "";
|
|
argv[1] = const_cast<char*>(webAddress);
|
|
argv[2] = 0;
|
|
|
|
int ok = -1;
|
|
|
|
// if execvp returns, it means it couldn't execute the program
|
|
if (webBrowser != NULL)
|
|
ok = execvp(webBrowser, argv);
|
|
|
|
ok = execvp("konqueror", argv);
|
|
ok = execvp("mozilla", argv);
|
|
ok = execvp("netscape", argv);
|
|
// use dPrintf instead of Con here since we're now in another process,
|
|
dPrintf("WARNING: Platform::openWebBrowser: couldn't launch a web browser\n");
|
|
_exit(-1);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Con::printf("WARNING: Platform::openWebBrowser: forking problem");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Login password routines:
|
|
//------------------------------------------------------------------------------
|
|
const char* Platform::getLoginPassword()
|
|
{
|
|
Con::printf("WARNING: Platform::getLoginPassword() is unimplemented");
|
|
return "";
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Platform::setLoginPassword( const char* password )
|
|
{
|
|
Con::printf("WARNING: Platform::setLoginPassword is unimplemented");
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void TimeManager::process()
|
|
{
|
|
U32 curTime = Platform::getRealMilliseconds();
|
|
TimeEvent event;
|
|
event.elapsedTime = curTime - lastTimeTick;
|
|
if(event.elapsedTime > sgTimeManagerProcessInterval)
|
|
{
|
|
lastTimeTick = curTime;
|
|
Game->postEvent(event);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
ConsoleFunction( getDesktopResolution, const char*, 1, 1,
|
|
"getDesktopResolution()" )
|
|
{
|
|
if (!x86UNIXState->windowCreated())
|
|
return "0 0 0";
|
|
|
|
char buffer[256];
|
|
char* returnString = Con::getReturnBuffer( dStrlen( buffer ) + 1 );
|
|
|
|
dSprintf( buffer, sizeof( buffer ), "%d %d %d",
|
|
x86UNIXState->getDesktopSize().x,
|
|
x86UNIXState->getDesktopSize().y,
|
|
x86UNIXState->getDesktopBpp() );
|
|
dStrcpy( returnString, buffer );
|
|
return( returnString );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Silly Korean registry key checker:
|
|
//------------------------------------------------------------------------------
|
|
ConsoleFunction( isKoreanBuild, bool, 1, 1, "isKoreanBuild()" )
|
|
{
|
|
Con::printf("WARNING: isKoreanBuild() is unimplemented");
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int main(S32 argc, const char **argv)
|
|
{
|
|
// init platform state
|
|
x86UNIXState = new x86UNIXPlatformState;
|
|
|
|
// parse the command line for unix-specific params
|
|
Vector<char *> newCommandLine;
|
|
S32 returnVal = ParseCommandLine(argc, argv, newCommandLine);
|
|
if (returnVal != 0)
|
|
return returnVal;
|
|
|
|
// init lastTimeTick for TimeManager::process()
|
|
lastTimeTick = Platform::getRealMilliseconds();
|
|
|
|
// init process control stuff
|
|
ProcessControlInit();
|
|
|
|
// check to see if X is running
|
|
DetectWindowingSystem();
|
|
|
|
// run the game
|
|
returnVal = Game->main(newCommandLine.size(),
|
|
const_cast<const char**>(newCommandLine.address()));
|
|
|
|
// dispose of command line
|
|
for(U32 i = 0; i < newCommandLine.size(); i++)
|
|
delete [] newCommandLine[i];
|
|
|
|
// dispose of state
|
|
delete x86UNIXState;
|
|
|
|
return returnVal;
|
|
}
|
|
void Platform::setWindowTitle( const char* title )
|
|
{
|
|
#ifndef DEDICATED
|
|
x86UNIXState->setWindowName(title);
|
|
SDL_WM_SetCaption(x86UNIXState->getWindowName(), NULL);
|
|
#endif
|
|
}
|
|
|
|
Resolution Video::getDesktopResolution()
|
|
{
|
|
Resolution Result;
|
|
Result.h = x86UNIXState->getDesktopSize().x;
|
|
Result.w = x86UNIXState->getDesktopSize().y;
|
|
Result.bpp = x86UNIXState->getDesktopBpp();
|
|
|
|
return Result;
|
|
}
|