434 lines
13 KiB
C++
Executable File
434 lines
13 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platformMacCarb/platformMacCarb.h"
|
|
#include "platform/platformVideo.h"
|
|
#include "platformMacCarb/macCarbOGLVideo.h"
|
|
#include "platformMacCarb/macCarbConsole.h"
|
|
#include "platform/platformInput.h"
|
|
#include "platform/gameInterface.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "console/console.h"
|
|
#include "platformMacCarb/macCarbEvents.h"
|
|
#include "platform/platformThread.h"
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
#pragma mark ---- PlatState ----
|
|
MacCarbPlatState platState;
|
|
|
|
MacCarbPlatState::MacCarbPlatState()
|
|
{
|
|
hDisplay = NULL;
|
|
appWindow = NULL;
|
|
|
|
captureDisplay = true;
|
|
fadeWindows = true;
|
|
backgrounded = false;
|
|
minimized = false;
|
|
|
|
quit = false;
|
|
|
|
ctx = NULL;
|
|
headless = false;
|
|
|
|
// start with something reasonable.
|
|
desktopBitsPixel = 16;
|
|
desktopWidth = 1024;
|
|
desktopHeight = 768;
|
|
|
|
osVersion = 0;
|
|
|
|
dStrcpy(appWindowTitle, "Mac Torque Game Engine");
|
|
|
|
// Semaphore for alerts. We put the app in a modal state by blocking the main
|
|
// Torque thread until the RAEL thread allows it to continue.
|
|
alertSemaphore = Semaphore::createSemaphore(0);
|
|
alertDlg = NULL;
|
|
}
|
|
|
|
#pragma mark ---- Window stuff ----
|
|
const U32 kTFullscreenWindowAttrs = kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
|
|
const U32 kTDefaultWindowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute;
|
|
//------------------------------------------------------------------------------
|
|
WindowPtr MacCarbCreateOpenGLWindow( GDHandle hDevice, U32 width, U32 height, bool fullScreen )
|
|
{
|
|
WindowPtr w = NULL;
|
|
|
|
Rect rect;
|
|
Rect dRect;
|
|
|
|
// device bounds, eg: [top,left , bottom,right] = [0,0 , 768,1024]
|
|
dRect = (**hDevice).gdRect;
|
|
// center the window's rect in the display's rect.
|
|
rect.top = dRect.top + (dRect.bottom - dRect.top - height) / 2;
|
|
rect.left = dRect.left + (dRect.right - dRect.left - width) / 2;
|
|
rect.right = rect.left + width;
|
|
rect.bottom = rect.top + height;
|
|
|
|
OSStatus err;
|
|
WindowAttributes windAttr = 0L;
|
|
WindowClass windClass = kDocumentWindowClass;
|
|
|
|
if (fullScreen)
|
|
{
|
|
windAttr = kTFullscreenWindowAttrs;
|
|
windClass = kAltPlainWindowClass;
|
|
// Overlay windows can be used to make transperant windows,
|
|
// which are good for performing all kinds of cool tricks.
|
|
// windClass = kOverlayWindowClass;
|
|
// windAttr |= kWindowOpaqueForEventsAttribute;
|
|
}
|
|
else
|
|
{
|
|
windAttr = kTDefaultWindowAttrs;
|
|
}
|
|
|
|
err = CreateNewWindow(windClass, windAttr, &rect, &w);
|
|
AssertISV( err == noErr && w != NULL, "Failed to create a new window.");
|
|
|
|
// in windowed-fullscreen mode, we set the window's level to be
|
|
// in front of the blanking window
|
|
if (fullScreen)
|
|
{
|
|
// create a new group if ours doesn't already exist
|
|
if (platState.torqueWindowGroup==NULL)
|
|
CreateWindowGroup(NULL, &platState.torqueWindowGroup);
|
|
|
|
// place window in group
|
|
SetWindowGroup(w, platState.torqueWindowGroup);
|
|
|
|
// set window group level to one higher than blanking window.
|
|
SetWindowGroupLevel(platState.torqueWindowGroup, kTFullscreenWindowLevel);
|
|
}
|
|
|
|
platState.minimized = false;
|
|
|
|
RGBColor black;
|
|
dMemset(&black, 0, sizeof(RGBColor));
|
|
SetWindowContentColor( w, &black);
|
|
|
|
return(w);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Fade a window in, asynchronously.
|
|
void MacCarbFadeInWindow( WindowPtr window )
|
|
{
|
|
if(!IsValidWindowPtr(window))
|
|
return;
|
|
|
|
// bump this to the main thread if we're not on the main thread.
|
|
if(Thread::getCurrentThreadId() != platState.firstThreadId)
|
|
{
|
|
MacCarbSendTorqueEventToMain( kEventTorqueFadeInWindow, window );
|
|
return;
|
|
}
|
|
|
|
// set state on menubar & mouse cursor.
|
|
if(Video::isFullScreen())
|
|
{
|
|
HideMenuBar();
|
|
MacCarbSetHideCursor(true);
|
|
}
|
|
else
|
|
{
|
|
ShowMenuBar();
|
|
}
|
|
|
|
SelectWindow(window);
|
|
|
|
if(platState.fadeWindows)
|
|
{
|
|
TransitionWindowOptions t;
|
|
dMemset(&t, 0, sizeof(t));
|
|
TransitionWindowWithOptions( window, kWindowFadeTransitionEffect,
|
|
kWindowShowTransitionAction, NULL, true, &t);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(window);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Fade a window out, asynchronously. It will be released when the transition finishes.
|
|
void MacCarbFadeAndReleaseWindow( WindowPtr window )
|
|
{
|
|
if(!IsValidWindowPtr(window))
|
|
return;
|
|
|
|
if(Thread::getCurrentThreadId() != platState.firstThreadId && !platState.quit)
|
|
{
|
|
MacCarbSendTorqueEventToMain( kEventTorqueFadeOutWindow, window );
|
|
return;
|
|
}
|
|
|
|
if(platState.fadeWindows)
|
|
{
|
|
TransitionWindowOptions t;
|
|
dMemset(&t, 0, sizeof(t));
|
|
TransitionWindowWithOptions( window, kWindowFadeTransitionEffect,
|
|
kWindowHideTransitionAction, NULL, false, &t);
|
|
}
|
|
else
|
|
{
|
|
MacCarbSendTorqueEventToMain(kEventTorqueReleaseWindow, window);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Hide or show the menu bar.
|
|
void MacCarbShowMenuBar(bool show)
|
|
{
|
|
if(Thread::getCurrentThreadId() != platState.firstThreadId && !platState.quit)
|
|
{
|
|
MacCarbSendTorqueEventToMain( kEventTorqueShowMenuBar, (void*)show );
|
|
return;
|
|
}
|
|
|
|
if(show)
|
|
ShowMenuBar();
|
|
else
|
|
HideMenuBar();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DGL, the Gui, and TS use this for various purposes.
|
|
const Point2I &Platform::getWindowSize()
|
|
{
|
|
return platState.windowSize;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// save the window size, for DGL's use
|
|
void Platform::setWindowSize( U32 newWidth, U32 newHeight )
|
|
{
|
|
platState.windowSize.set( newWidth, newHeight );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Issue a minimize event. The standard handler will handle it.
|
|
void Platform::minimizeWindow()
|
|
{
|
|
HICommand cmd;
|
|
dMemset(&cmd, 0, sizeof(HICommand));
|
|
cmd.commandID = kHICommandMinimizeWindow;
|
|
ProcessHICommand( &cmd );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::setWindowTitle(const char* title )
|
|
{
|
|
if(!platState.appWindow)
|
|
return;
|
|
|
|
// set app window's title
|
|
CFStringRef cfsTitle = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
|
|
SetWindowTitleWithCFString(platState.appWindow, cfsTitle);
|
|
CFRelease(cfsTitle);
|
|
|
|
// save title in platstate
|
|
dStrncpy(platState.appWindowTitle, title, getMin((U32)dStrlen(title), sizeof(platState.appWindowTitle)));
|
|
}
|
|
|
|
|
|
#pragma mark ---- Init funcs ----
|
|
//------------------------------------------------------------------------------
|
|
void Platform::init()
|
|
{
|
|
// Set the platform variable for the scripts
|
|
Con::setVariable( "$platform", "macos" );
|
|
|
|
MacConsole::create();
|
|
if(gConsole && platState.headless == true)
|
|
gConsole->enable(true);
|
|
|
|
Input::init();
|
|
|
|
// allow users to specify whether to capture the display or not when going fullscreen
|
|
Con::addVariable("pref::mac::captureDisplay", TypeBool, &platState.captureDisplay);
|
|
Con::addVariable("pref::mac::fadeWindows", TypeBool, &platState.fadeWindows);
|
|
|
|
// create the opengl display device
|
|
DisplayDevice *dev = NULL;
|
|
Con::printf( "Video Init:" );
|
|
Video::init();
|
|
dev = OpenGLDevice::create();
|
|
if(dev)
|
|
Con::printf( " Accelerated OpenGL display device detected." );
|
|
else
|
|
Con::printf( " Accelerated OpenGL display device not detected." );
|
|
|
|
// and now we can install the device.
|
|
Video::installDevice(dev);
|
|
Con::printf( "" );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::shutdown()
|
|
{
|
|
setWindowLocked( false );
|
|
Video::destroy();
|
|
Input::destroy();
|
|
MacConsole::destroy();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Get the video settings from the prefs.
|
|
static void _MacCarbGetInitialRes(U32 &width, U32 &height, U32 &bpp, bool &fullScreen)
|
|
{
|
|
const char* resString;
|
|
char *tempBuf, *s;
|
|
|
|
// cache the desktop size of the selected screen in platState
|
|
Video::getDesktopResolution();
|
|
|
|
// load pref variables, properly choose windowed / fullscreen
|
|
fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
|
|
if (fullScreen)
|
|
resString = Con::getVariable( "$pref::Video::resolution" );
|
|
else
|
|
resString = Con::getVariable( "$pref::Video::windowedRes" );
|
|
|
|
// dStrtok is destructive, work on a copy...
|
|
tempBuf = new char[dStrlen( resString ) + 1];
|
|
dStrcpy( tempBuf, resString );
|
|
|
|
// set window size
|
|
//DAW: Added min size checks for windowSize
|
|
width = dAtoi( dStrtok( tempBuf, " x\0" ) );
|
|
if( ! width > 0 ) width = platState.windowSize.x;
|
|
|
|
height = dAtoi( dStrtok( NULL, " x\0") );
|
|
if( ! height > 0 ) height = platState.windowSize.y;
|
|
|
|
// bit depth
|
|
if (fullScreen)
|
|
{
|
|
s = dAtoi( dStrtok( NULL, "\0" ) );
|
|
if( ! bpp > 0 ) bpp = 16;
|
|
}
|
|
else
|
|
bpp = platState.desktopBitsPixel;
|
|
|
|
delete [] tempBuf;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Platform::initWindow(const Point2I &initialSize, const char *name)
|
|
{
|
|
dSprintf(platState.appWindowTitle, sizeof(platState.appWindowTitle), name);
|
|
|
|
// init the default window size
|
|
platState.windowSize = initialSize;
|
|
if( ! platState.windowSize.x > 0 ) platState.windowSize.x = 640;
|
|
if( ! platState.windowSize.y > 0 ) platState.windowSize.y = 480;
|
|
|
|
DisplayDevice::init();
|
|
|
|
bool fullScreen;
|
|
U32 width, height, bpp;
|
|
_MacCarbGetInitialRes(width, height, bpp, fullScreen);
|
|
|
|
// this will create a rendering context & window
|
|
bool ok = Video::setDevice( "OpenGL", width, height, bpp, fullScreen );
|
|
if ( ! ok )
|
|
{
|
|
AssertFatal( false, "Could not find a compatible display device!" );
|
|
}
|
|
|
|
if (platState.appWindow)
|
|
{
|
|
// install handlers to the given window.
|
|
EventTargetRef winTarg = GetWindowEventTarget(platState.appWindow);
|
|
}
|
|
MacCarbInstallCarbonEventHandlers();
|
|
}
|
|
|
|
#pragma mark ---- Platform utility funcs ----
|
|
//--------------------------------------
|
|
// Web browser function:
|
|
//--------------------------------------
|
|
bool Platform::openWebBrowser( const char* webAddress )
|
|
{
|
|
OSStatus err;
|
|
CFURLRef url = CFURLCreateWithBytes(NULL,(UInt8*)webAddress,dStrlen(webAddress),kCFStringEncodingASCII,NULL);
|
|
err = LSOpenCFURLRef(url,NULL);
|
|
CFRelease(url);
|
|
|
|
// kick out of fullscreen mode, so we can *see* the webpage!
|
|
if(Video::isFullScreen())
|
|
Video::toggleFullScreen();
|
|
|
|
return(err==noErr);
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark ---- Tests ----
|
|
|
|
ConsoleFunction(testWindowLevels,void,1,2,"testWindowLevels([lev to set]);")
|
|
{
|
|
SInt32 lev;
|
|
Con::printf(" Sheilding window level is %x",CGShieldingWindowLevel());
|
|
GetWindowGroupLevel(GetWindowGroupOfClass(kUtilityWindowClass),&lev);
|
|
Con::printf(" Utility window level is %x", lev);
|
|
GetWindowGroupLevel(GetWindowGroupOfClass(kUtilityWindowClass),&lev);
|
|
Con::printf(" Floating window level is %x", lev);
|
|
GetWindowGroupLevel(GetWindowGroupOfClass(kAlertWindowClass),&lev);
|
|
Con::printf(" Alert window level is %x", lev);
|
|
|
|
lev=1;
|
|
if(argc==2)
|
|
lev=dAtoi(argv[1]);
|
|
SetWindowGroupLevel( GetWindowGroupOfClass(kUtilityWindowClass), lev);
|
|
SetWindowGroupLevel( GetWindowGroupOfClass(kFloatingWindowClass), lev);
|
|
SetWindowGroupLevel( GetWindowGroupOfClass(kAlertWindowClass), lev);
|
|
}
|
|
|
|
|
|
ConsoleFunction( testSetWindowTitle, void, 2,4, "")
|
|
{
|
|
Platform::setWindowTitle(argv[1]);
|
|
}
|
|
|
|
ConsoleFunction( invertScreenColor, void, 1,1, "")
|
|
{
|
|
static bool inverted = false;
|
|
|
|
CGGammaValue reds[1024];
|
|
CGGammaValue greens[1024];
|
|
CGGammaValue blues[1024];
|
|
U32 numTableEntries;
|
|
|
|
CGGetDisplayTransferByTable( CGMainDisplayID(), 1024, reds, greens, blues, &numTableEntries);
|
|
|
|
CGGammaValue newReds[numTableEntries];
|
|
CGGammaValue newGreens[numTableEntries];
|
|
CGGammaValue newBlues[numTableEntries];
|
|
|
|
for(int i=0; i< numTableEntries; i++)
|
|
{
|
|
newReds[i] = reds[numTableEntries-1-i];
|
|
newGreens[i] = greens[numTableEntries-1-i];
|
|
newBlues[i] = blues[numTableEntries-1-i];
|
|
}
|
|
|
|
CGSetDisplayTransferByTable(CGMainDisplayID(), numTableEntries, newReds, newGreens, newBlues);
|
|
|
|
}
|
|
|
|
ConsoleFunction(testAsserts, void, 1,1,"")
|
|
{
|
|
AssertFatal(false,"Monsters in my OATMEAL.");
|
|
AssertWarn(false,"Oh sweet mercy, the PAIN... THE PAIN!");
|
|
AssertISV(false,"AAaaah! *GARGLE* *SPUTTER* *WET THUD*");
|
|
}
|
|
|
|
|
|
|