added everything
This commit is contained in:
162
engine/platformMacCarb/macCarbAlerts.cc
Executable file
162
engine/platformMacCarb/macCarbAlerts.cc
Executable file
@ -0,0 +1,162 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platformSemaphore.h"
|
||||
#include "platform/platformVideo.h"
|
||||
#include "platform/platformThread.h"
|
||||
#include "console/console.h"
|
||||
#include "platformMacCarb/macCarbEvents.h"
|
||||
|
||||
// Carbon alerts must be displayed from the main thead, because only the main
|
||||
// thread recieves user events.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Puts the main thread in a modal state & shows the alert.
|
||||
// This should only be called from the main thread.
|
||||
//-----------------------------------------------------------------------------
|
||||
void MacCarbRunAlertMain()
|
||||
{
|
||||
// show the alert - this will return when the user hits a button.
|
||||
DialogItemIndex hit;
|
||||
|
||||
OSStatus err = RunStandardAlert(platState.alertDlg,NULL,&hit);
|
||||
if(err!=noErr)
|
||||
Con::printf("RunStandardAlert error = %d, 0x%x", err, err);
|
||||
|
||||
platState.alertHit = hit;
|
||||
Semaphore::releaseSemaphore(platState.alertSemaphore);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Ensures that our alert windows will be shown above the main window.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void _MacCarbSetAlertWindowLevel()
|
||||
{
|
||||
SetWindowGroupLevel( GetWindowGroupOfClass(kAlertWindowClass), kTAlertWindowLevel);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static void _MacCarbSendAlertToMainThread(DialogRef alert)
|
||||
{
|
||||
// create & post an event - this will tell the RAEL thread to display an alert.
|
||||
platState.alertDlg = alert;
|
||||
if(Thread::getCurrentThreadId() == platState.firstThreadId)
|
||||
MacCarbRunAlertMain();
|
||||
else
|
||||
{
|
||||
MacCarbSendTorqueEventToMain( kEventTorqueAlert);
|
||||
}
|
||||
// wait for the alert semaphore
|
||||
Semaphore::acquireSemaphore(platState.alertSemaphore);
|
||||
platState.alertDlg = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Convenience function to encapsulate creating a DialogRef for an alert
|
||||
//-----------------------------------------------------------------------------
|
||||
static DialogRef _MacCarbCreateAlert( const char* error, const char* message, CFStringRef okText, CFStringRef cancelText )
|
||||
{
|
||||
if(platState.headless)
|
||||
return NULL;
|
||||
|
||||
DialogRef alert;
|
||||
AlertStdCFStringAlertParamRec params;
|
||||
CFStringRef cfError, cfMessage;
|
||||
|
||||
GetStandardAlertDefaultParams(¶ms, kStdCFStringAlertVersionOne);
|
||||
if(okText)
|
||||
params.defaultText = okText;
|
||||
if(cancelText)
|
||||
{
|
||||
params.cancelText = cancelText;
|
||||
params.cancelButton = kAlertStdAlertCancelButton;
|
||||
}
|
||||
|
||||
cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingUTF8);
|
||||
cfMessage = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8);
|
||||
|
||||
OSStatus err=CreateStandardAlert(kAlertStopAlert, cfError, cfMessage, ¶ms, &alert);
|
||||
if(err!=noErr)
|
||||
Con::printf("CreateStandardAlert error = %d, 0x%x", err, err);
|
||||
return alert;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Convenience function for putting the app in a modal state & showing an alert
|
||||
//-----------------------------------------------------------------------------
|
||||
static S32 _MacCarbRunAlert( DialogRef alert )
|
||||
{
|
||||
if(platState.headless)
|
||||
return kAlertStdAlertCancelButton;
|
||||
|
||||
// prep to show the event - be sure we dont obscure it or eat it's events.
|
||||
MacCarbRemoveCarbonEventHandlers();
|
||||
_MacCarbSetAlertWindowLevel();
|
||||
MacCarbSetHideCursor(false);
|
||||
if(Video::isFullScreen() && platState.captureDisplay)
|
||||
{
|
||||
ShowMenuBar();
|
||||
aglSetDrawable(platState.ctx, NULL);
|
||||
}
|
||||
|
||||
_MacCarbSendAlertToMainThread(alert);
|
||||
|
||||
// go back to normal Torque operations...
|
||||
if(Video::isFullScreen() && platState.captureDisplay)
|
||||
{
|
||||
HideMenuBar();
|
||||
aglSetFullScreen(platState.ctx, Video::getResolution().w, Video::getResolution().h, 0, 0);
|
||||
}
|
||||
MacCarbInstallCarbonEventHandlers();
|
||||
MacCarbCheckHideCursor();
|
||||
|
||||
return platState.alertHit;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Platform::AlertOK(const char *windowTitle, const char *message)
|
||||
{
|
||||
DialogRef alert = _MacCarbCreateAlert(windowTitle, message,NULL,NULL);
|
||||
_MacCarbRunAlert(alert);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
|
||||
{
|
||||
DialogRef alert = _MacCarbCreateAlert(windowTitle, message,NULL,CFSTR("Cancel"));
|
||||
S32 hit = _MacCarbRunAlert(alert);
|
||||
return ( hit == kAlertStdAlertOKButton );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::AlertRetry(const char *windowTitle, const char *message)
|
||||
{
|
||||
DialogRef alert = _MacCarbCreateAlert(windowTitle, message,CFSTR("Retry"),CFSTR("Cancel"));
|
||||
S32 hit = _MacCarbRunAlert(alert);
|
||||
return ( hit == kAlertStdAlertOKButton );
|
||||
}
|
||||
|
||||
// paxorr - remove this when no longer needed.
|
||||
//-----------------------------------------------------------------------------
|
||||
ConsoleFunction( testAlert, void, 1,3,"[title],[mesage]")
|
||||
{
|
||||
const char *title = "The penguin is missing!";
|
||||
const char *message = "Perhaps the salmon of doubt ate him.";
|
||||
if(argc>1)
|
||||
title = argv[1];
|
||||
if(argc>2)
|
||||
message = argv[2];
|
||||
|
||||
Platform::AlertOK(title,message);
|
||||
Con::errorf("Returned from AlertOK");
|
||||
bool ok = Platform::AlertOKCancel(title,message);
|
||||
Con::errorf("Returned from AlertCancel, hit %s", ok?"OK":"Cancel");
|
||||
ok = Platform::AlertRetry(title,message);
|
||||
Con::errorf("Returned from AlertRetry, hit %s", ok?"Retry":"Cancel");
|
||||
|
||||
DialogRef alert = _MacCarbCreateAlert("Test","testing alternate cancel texts",NULL,CFSTR("cry havok!"));
|
||||
_MacCarbRunAlert(alert);
|
||||
}
|
15
engine/platformMacCarb/macCarbAlerts.h
Executable file
15
engine/platformMacCarb/macCarbAlerts.h
Executable file
@ -0,0 +1,15 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Puts the current thread in a modal state & shows the alert.
|
||||
/// This should only be called from the main thread.
|
||||
/// If you call it from any other thread, bad things will happen. So don't.
|
||||
/// The 'main thread' here means the program's thread zero. The first thread.
|
||||
/// In multithreaded Torque, this is NOT the game loop thread.
|
||||
/// On the Mac, events and alerts have to happen in thread zero.
|
||||
//-----------------------------------------------------------------------------
|
||||
void MacCarbRunAlertMain();
|
||||
|
24
engine/platformMacCarb/macCarbAudio.cc
Executable file
24
engine/platformMacCarb/macCarbAudio.cc
Executable file
@ -0,0 +1,24 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platformAL.h"
|
||||
|
||||
namespace Audio
|
||||
{
|
||||
|
||||
/*! The MacOS X build links against the OpenAL framework.
|
||||
It can be built to use either an internal framework, or the system framework.
|
||||
Since OpenAL is weak-linked in at compile time, we don't need to init anything.
|
||||
Stub it out...
|
||||
*/
|
||||
bool OpenALDLLInit() { return true; }
|
||||
|
||||
/*! Stubbed out, see the note on OpenALDLLInit().
|
||||
*/
|
||||
void OpenALDLLShutdown() { }
|
||||
|
||||
|
||||
} // namespace Audio
|
297
engine/platformMacCarb/macCarbCPUInfo.cc
Executable file
297
engine/platformMacCarb/macCarbCPUInfo.cc
Executable file
@ -0,0 +1,297 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "console/console.h"
|
||||
#include "core/stringTable.h"
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach/machine.h>
|
||||
#include <math.h>
|
||||
|
||||
// The Gestalt() API will no longer be updated, so this code should migrate to
|
||||
// the unix sysctl() and sysctlbyname() API. This is the current doctrine from Apple, dec 2005.
|
||||
|
||||
// Thanks to Gary "ChunkyKs" Briggs for contributing the sysctl() code patch.
|
||||
|
||||
Platform::SystemInfo_struct Platform::SystemInfo;
|
||||
static char* _MacCarbGetMachineName();
|
||||
static void _MacCarbGetCpuTypeAndFeatures(U32 *type, char **typeString, U32 *features);
|
||||
static void _MacCarbGetBasicHWInfo(U32 *osVersion, U64 *cpuMhz, U32 *numCpus, U64 *memMbSize);
|
||||
|
||||
void Processor::init()
|
||||
{
|
||||
U32 osVersion;
|
||||
U64 cpuMhz;
|
||||
U32 numCpus;
|
||||
U64 memMbSize;
|
||||
|
||||
U32 cpuType;
|
||||
char* cpuTypeString;
|
||||
U32 cpuFeatures;
|
||||
|
||||
Con::printf("System & Processor Information:");
|
||||
|
||||
// Get the mac model identifier, just for fun...
|
||||
char *machineName = _MacCarbGetMachineName();
|
||||
|
||||
// get data about the machine out of sysctl and Gestalt ...
|
||||
_MacCarbGetBasicHWInfo(&osVersion, &cpuMhz, &numCpus, &memMbSize);
|
||||
_MacCarbGetCpuTypeAndFeatures(&cpuType, &cpuTypeString, &cpuFeatures);
|
||||
|
||||
// Set Torque's processor mhz var. This is reported to master servers.
|
||||
Platform::SystemInfo.processor.mhz = cpuMhz;
|
||||
|
||||
// Set Torque's processor type var.
|
||||
// Don't use special code paths based on this var, instead you should use the
|
||||
// processor properties bits: Platform::SystemInfo.processor.properties
|
||||
Platform::SystemInfo.processor.type = cpuType;
|
||||
|
||||
// Set Torque's processor name var.
|
||||
Platform::SystemInfo.processor.name = StringTable->insert(cpuTypeString);
|
||||
|
||||
// Set Torques processor properties.
|
||||
// These should determine what special code paths we use.
|
||||
Platform::SystemInfo.processor.properties = cpuFeatures;
|
||||
|
||||
// Make pretty strings...
|
||||
char freqString[32];
|
||||
if(cpuMhz >= 1000)
|
||||
dSprintf(freqString, 32, "%2.3g GHz", cpuMhz / 1000.0f);
|
||||
else
|
||||
dSprintf(freqString, 32, "%i MHz", cpuMhz);
|
||||
|
||||
char coresString[32] = "single core";
|
||||
if(numCpus > 1)
|
||||
dSprintf(coresString, 32, "%i cores", numCpus);
|
||||
|
||||
char memString[32];
|
||||
if(memMbSize >= 1024)
|
||||
dSprintf(memString, 32, "%2.1f GB", memMbSize / 1024.0f);
|
||||
else
|
||||
dSprintf(memString, 32, "%i MB", memMbSize);
|
||||
|
||||
// Dump info to console
|
||||
Con::printf(" Mac OS X %x.%x.%x", (osVersion>>8), (osVersion&0xFF)>>4, (osVersion&0x0F));
|
||||
Con::printf(" %s RAM", memString);
|
||||
Con::printf(" %s %s (%s)", freqString, machineName, coresString);
|
||||
Con::printf(" %s Architecture", cpuTypeString);
|
||||
if(Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
|
||||
Con::printf(" MMX detected");
|
||||
if(Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
|
||||
Con::printf(" SSE detected");
|
||||
if(Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
|
||||
Con::printf(" Altivec detected");
|
||||
|
||||
Con::printf(" ");
|
||||
}
|
||||
|
||||
static char* _MacCarbGetMachineName()
|
||||
{
|
||||
// data from: http://www.cocoadev.com/index.pl?MacintoshModels
|
||||
// and http://www.theapplemuseum.com/index.php?id=36#
|
||||
// and 10.4.8's /System/Library/SystemProfiler/SPPlatformReporter.spreporter/Contents/Resources/SPMachineTypes.plist
|
||||
char* _unknownMac = "unknown Mac model";
|
||||
char* _macNames[][2] = {
|
||||
{ "AAPL,Gossamer", "PowerMacG3Series" },
|
||||
{ "AAPL,PowerBook1998", "PowerBookG3Series" },
|
||||
{ "AAPL,PowerMac G3", "PowerMacG3" },
|
||||
{ "ADP2,1" , "Developer Transition Kit" },
|
||||
{ "iMac,1" , "iMac" },
|
||||
{ "iMac4,1" , "iMac Core Duo" },
|
||||
{ "iMac4,2" , "iMac (Core Duo, mid 2006)" },
|
||||
{ "iMac5,1" , "iMac (Core 2 Duo)" },
|
||||
{ "iMac6,1" , "iMac (24-inch Core 2 Duo)" },
|
||||
{ "MacBook1,1" , "MacBook (Core Duo)" },
|
||||
{ "MacBook2,1" , "MacBook (Core 2 Duo)" },
|
||||
{ "MacBookPro1,1" , "MacBook Pro (15-inch Core Duo)" },
|
||||
{ "MacBookPro1,2" , "MacBook Pro (17-inch Core Duo)" },
|
||||
{ "MacBookPro2,1" , "MacBook Pro (17-inch Core 2 Duo)" },
|
||||
{ "MacBookPro2,2" , "MacBook Pro (15-inch Core 2 Duo)" },
|
||||
{ "Macmini1,1" , "Mac mini (Core Duo/Solo)" },
|
||||
{ "MacPro1,1" , "Mac Pro (Quad Xeon)" },
|
||||
{ "MacPro1,1,Quad" , "Mac Pro (Quad Xeon)" },
|
||||
{ "PowerBook1,1" , "PowerBook G3" },
|
||||
{ "PowerBook2,1" , "iBook" },
|
||||
{ "PowerBook2,2" , "iBook (FireWire)" },
|
||||
{ "PowerBook3,1" , "PowerBook G3 (FireWire)" },
|
||||
{ "PowerBook3,2" , "PowerBook G4" },
|
||||
{ "PowerBook3,3" , "PowerBook G4 (Gigabit Ethernet)" },
|
||||
{ "PowerBook3,4" , "PowerBook G4 (DVI)" },
|
||||
{ "PowerBook3,5" , "PowerBook G4 (867, 1 GHz)" },
|
||||
{ "PowerBook4,1" , "iBook G3" },
|
||||
{ "PowerBook4,2" , "iBook G3" },
|
||||
{ "PowerBook4,3" , "iBook G3" },
|
||||
{ "PowerBook4,4" , "iBook" },
|
||||
{ "PowerBook5,1" , "PowerBook G4 (17-inch)" },
|
||||
{ "PowerBook5,2" , "PowerBook G4 (15-inch FW800)" },
|
||||
{ "PowerBook5,3" , "PowerBook G4 (17-inch 1.33 GHz)" },
|
||||
{ "PowerBook5,4" , "PowerBook G4 (15-inch 1.5/1.33 GHz)" },
|
||||
{ "PowerBook5,5" , "PowerBook G4 (17-inch 1.5 GHz)" },
|
||||
{ "PowerBook5,6" , "PowerBook G4 (15-inch 1.67/1.5 GHz)" },
|
||||
{ "PowerBook5,7" , "PowerBook G4 (17-inch 1.67 GHz)" },
|
||||
{ "PowerBook5,8" , "PowerBook G4 (Double-Layer SD, 15-inch)" },
|
||||
{ "PowerBook5,9" , "PowerBook G4 (Double-Layer SD, 17-inch)" },
|
||||
{ "PowerBook6,1" , "PowerBook G4 (12-inch)" },
|
||||
{ "PowerBook6,2" , "PowerBook G4 (12-inch DVI)" },
|
||||
{ "PowerBook6,3" , "iBook G4" },
|
||||
{ "PowerBook6,4" , "PowerBook G4 (12-inch 1.33 GHz)" },
|
||||
{ "PowerBook6,5" , "iBook G4" },
|
||||
{ "PowerBook6,7" , "iBook G4" },
|
||||
{ "PowerBook6,8" , "PowerBook G4 (12-inch 1.5 GHz)" },
|
||||
{ "PowerMac1,1" , "Power Macintosh G3 (B&W)" },
|
||||
{ "PowerMac1,2" , "Power Macintosh G4 (PCI-Graphics)" },
|
||||
{ "PowerMac2,1" , "iMac (Slot-Loading)" },
|
||||
{ "PowerMac2,2" , "iMac (2000)" },
|
||||
{ "PowerMac3,1" , "Power Macintosh G4 (AGP-Graphics)" },
|
||||
{ "PowerMac3,2" , "Power Macintosh G4 (AGP-Graphics)" },
|
||||
{ "PowerMac3,3" , "Power Macintosh G4 (Gigabit Ethernet)" },
|
||||
{ "PowerMac3,4" , "Power Macintosh G4 (Digital Audio)" },
|
||||
{ "PowerMac3,5" , "Power Macintosh G4 (Quick Silver)" },
|
||||
{ "PowerMac3,6" , "Power Macintosh G4 (Mirrored Drive Doors)" },
|
||||
{ "PowerMac4,1" , "iMac (2001)" },
|
||||
{ "PowerMac4,2" , "iMac (Flat Panel)" },
|
||||
{ "PowerMac4,4" , "eMac G3" },
|
||||
{ "PowerMac4,5" , "iMac (17-inch Flat Panel)" },
|
||||
{ "PowerMac5,1" , "Power Macintosh G4 Cube" },
|
||||
{ "PowerMac5,2" , "Power Macintosh G4 Cube" },
|
||||
{ "PowerMac6,1" , "iMac (USB 2.0)" },
|
||||
{ "PowerMac6,3" , "iMac (20-inch Flat Panel)" },
|
||||
{ "PowerMac6,4" , "eMac (USB 2.0)" },
|
||||
{ "PowerMac7,2" , "Power Macintosh G5" },
|
||||
{ "PowerMac7,3" , "Power Macintosh G5" },
|
||||
{ "PowerMac8,1" , "iMac G5" },
|
||||
{ "PowerMac8,2" , "iMac G5 (Ambient Light Sensor)" },
|
||||
{ "PowerMac9,1" , "Power Macintosh G5 (Late 2004)" },
|
||||
{ "PowerMac10,1" , "Mac mini" },
|
||||
{ "PowerMac10,2" , "Mac mini (Late 2005)" },
|
||||
{ "PowerMac11,2" , "Power Macintosh G5 (PCIe)" },
|
||||
{ "PowerMac11,2,Quad", "Power Macintosh G5 Quad" },
|
||||
{ "PowerMac12,1" , "iMac G5 (iSight)" },
|
||||
{ "RackMac1,1" , "Xserve G4" },
|
||||
{ "RackMac1,2" , "Xserve G4 (Slot-Loading)" },
|
||||
{ "RackMac3,1" , "Xserve G5" },
|
||||
{ NULL , NULL }
|
||||
};
|
||||
|
||||
char macModel[MAXPATHLEN];
|
||||
U32 macModelLen = MAXPATHLEN;
|
||||
|
||||
macModel[macModelLen-1] = '\0';
|
||||
sysctlbyname("hw.model", &macModel, &macModelLen, NULL, 0);
|
||||
|
||||
for(int i=0; _macNames[i][0] != NULL; i++)
|
||||
{
|
||||
if(!strcmp(_macNames[i][0], macModel))
|
||||
return _macNames[i][1];
|
||||
}
|
||||
#if defined(TORQUE_DEBUG)
|
||||
Con::warnf("Unknown mac model. Add a definition to _MacCarbGetMachineName() for %s.", macModel);
|
||||
#endif
|
||||
return _unknownMac;
|
||||
}
|
||||
|
||||
void _MacCarbGetBasicHWInfo(U32 *osVersion, U64 *cpuMhz, U32 *numCpus, U64 *memMbSize)
|
||||
{
|
||||
U32 u64size = sizeof(U64);
|
||||
U32 u32size = sizeof(U32);
|
||||
|
||||
// Get MacOSX version #
|
||||
// Gestalt is still the only simple way to get the system version number, as of Jan 2007
|
||||
Gestalt(gestaltSystemVersion, osVersion);
|
||||
|
||||
// Get system mem
|
||||
sysctlbyname("hw.memsize", memMbSize, &u64size, NULL, 0);
|
||||
*memMbSize /= 1024 * 1024;
|
||||
|
||||
// Get cpu clock speed
|
||||
sysctlbyname("hw.cpufrequency", cpuMhz, &u64size, NULL, 0);
|
||||
// sometimes the frequency is not a pretty number, so round it.
|
||||
*cpuMhz = mCeil((float)(*cpuMhz)/(1000*1000));
|
||||
|
||||
// Get the # of processors or cores we have available
|
||||
sysctlbyname("hw.ncpu", numCpus, &u32size, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
void _MacCarbGetCpuTypeAndFeatures(U32 *type, char **typeString, U32 *features)
|
||||
{
|
||||
int err;
|
||||
U32 cputype;
|
||||
U32 cpusubtype;
|
||||
U32 cpufeature;
|
||||
|
||||
U32 u64size = sizeof(U64);
|
||||
U32 u32size = sizeof(U32);
|
||||
|
||||
char *torqueCpuString;
|
||||
U32 torqueCpuType;
|
||||
U32 torqueCpuFeatures;
|
||||
|
||||
// Identify the cpu
|
||||
err = sysctlbyname("hw.cputype", &cputype, &u32size, NULL, 0);
|
||||
err |= sysctlbyname("hw.cpusubtype", &cpusubtype, &u32size, NULL, 0);
|
||||
AssertWarn(err == 0, "Couldn't detect CPU type. Assuming generic x86.");
|
||||
|
||||
// determine the processor type & name
|
||||
switch(cputype) {
|
||||
case CPU_TYPE_X86:
|
||||
case CPU_TYPE_X86_64:
|
||||
torqueCpuString = "x86";
|
||||
torqueCpuType = CPU_X86Compatible;
|
||||
break;
|
||||
case CPU_TYPE_POWERPC64:
|
||||
case CPU_TYPE_POWERPC:
|
||||
switch(cpusubtype)
|
||||
{
|
||||
case CPU_SUBTYPE_POWERPC_970:
|
||||
torqueCpuString = "G5";
|
||||
torqueCpuType = CPU_PowerPC_G5;
|
||||
break;
|
||||
case CPU_SUBTYPE_POWERPC_7400:
|
||||
case CPU_SUBTYPE_POWERPC_7450:
|
||||
torqueCpuString = "G4";
|
||||
torqueCpuType = CPU_PowerPC_G4;
|
||||
break;
|
||||
case CPU_SUBTYPE_POWERPC_750:
|
||||
torqueCpuString = "G3";
|
||||
torqueCpuType = CPU_PowerPC_G3;
|
||||
break;
|
||||
default:
|
||||
torqueCpuString = "PowerPC";
|
||||
torqueCpuType = CPU_PowerPC_Unknown;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
torqueCpuString = "unknown";
|
||||
torqueCpuType = CPU_X86Compatible;
|
||||
}
|
||||
|
||||
// Get CPU features. These should determine what special code paths we use.
|
||||
torqueCpuFeatures = 0;
|
||||
switch(torqueCpuType) {
|
||||
case CPU_X86Compatible:
|
||||
err = sysctlbyname("hw.optional.mmx", &cpufeature, &u32size, NULL, 0);
|
||||
if(!err && cpufeature)
|
||||
torqueCpuFeatures |= CPU_PROP_MMX;
|
||||
|
||||
err = sysctlbyname("hw.optional.sse", &cpufeature, &u32size, NULL, 0);
|
||||
if(!err && cpufeature)
|
||||
torqueCpuFeatures |= CPU_PROP_SSE;
|
||||
|
||||
break;
|
||||
case CPU_PowerPC_G5:
|
||||
case CPU_PowerPC_G4:
|
||||
err = sysctlbyname("hw.optional.altivec", &cpufeature, &u32size, NULL, 0);
|
||||
if(!err && cpufeature)
|
||||
torqueCpuFeatures |= CPU_PROP_ALTIVEC;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// return data
|
||||
*type = torqueCpuType;
|
||||
*typeString = torqueCpuString;
|
||||
*features = torqueCpuFeatures;
|
||||
}
|
85
engine/platformMacCarb/macCarbCompat.10.2.cc
Executable file
85
engine/platformMacCarb/macCarbCompat.10.2.cc
Executable file
@ -0,0 +1,85 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/// To target MacOS 10.2, you need to modify some global project build settings.
|
||||
/// The default is to target 10.3, as that provides the best feature set and behavior in torque.
|
||||
/// MACOSX_DEPLOYMENT_TARGET_ppc = 10.2
|
||||
/// SDKROOT_ppc = /Developer/SDKs/MacOSX10.2.8.sdk
|
||||
|
||||
/// for more info on cross development with xcode, see:
|
||||
/// http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development/UniversalBinaries/chapter_4_section_1.html
|
||||
#include <AvailabilityMacros.h>
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1030
|
||||
|
||||
|
||||
#define NO_REDEFINE_10_2_COMPAT
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platformMacCarb/macCarbEvents.h"
|
||||
#include "platform/platformThread.h"
|
||||
|
||||
S32 (* TransitionWindowWithOptions_ptr) (void*, U32, U32, const void*, bool, void*) = NULL;
|
||||
|
||||
bool (* CGCursorIsVisible_ptr) () = NULL;
|
||||
U32 (* CGDisplayHideCursor_ptr) (U32) = NULL;
|
||||
U32 (* CGDisplayShowCursor_ptr) (U32) = NULL;
|
||||
|
||||
|
||||
// Replaces the transitions under 10.2.
|
||||
// Our implementation does not perform transitions, it just sends the events
|
||||
// that torque expects.
|
||||
S32 TransitionWindowWithOptions_compat( void* theWind, U32, U32 transition,
|
||||
const void*, bool, TransitionWindowOptions*)
|
||||
{
|
||||
if(transition == kWindowHideTransitionAction)
|
||||
{
|
||||
HideWindow(theWind);
|
||||
MacCarbSendTorqueEventToMain(kEventTorqueReleaseWindow, theWind);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(theWind);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sgCursorHidden = false;
|
||||
bool CGCursorIsVisible_compat()
|
||||
{
|
||||
return sgCursorHidden;
|
||||
}
|
||||
|
||||
U32 CGDisplayHideCursor_compat(U32)
|
||||
{
|
||||
AssertFatal(Thread::getCurrentThreadId() == platState.firstThreadId,
|
||||
"Cannot call Mac Carbon toolbox routines from any thread but the first thread.");
|
||||
HideCursor();
|
||||
sgCursorHidden = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 CGDisplayShowCursor_compat(U32)
|
||||
{
|
||||
AssertFatal(Thread::getCurrentThreadId() == platState.firstThreadId,
|
||||
"Cannot call Mac Carbon toolbox routines from any thread but the first thread.");
|
||||
ShowCursor();
|
||||
sgCursorHidden = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MacCarbInit1020CompatInit()
|
||||
{
|
||||
#define INIT_COMPAT_FUNC( a ) \
|
||||
a##_ptr = a; \
|
||||
if( a == NULL ) \
|
||||
a##_ptr = a##_compat
|
||||
|
||||
INIT_COMPAT_FUNC(CGCursorIsVisible);
|
||||
INIT_COMPAT_FUNC(CGDisplayHideCursor);
|
||||
INIT_COMPAT_FUNC(CGDisplayShowCursor);
|
||||
INIT_COMPAT_FUNC(TransitionWindowWithOptions);
|
||||
#undef INIT_COMPAT_FUNC
|
||||
}
|
||||
|
||||
|
||||
#endif //MAC_OS_X_VERSION_MIN_REQUIRED < 1030
|
56
engine/platformMacCarb/macCarbCompat.10.2.h
Executable file
56
engine/platformMacCarb/macCarbCompat.10.2.h
Executable file
@ -0,0 +1,56 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// macCarbCompat.10.2.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBCOMPAT_10_2_H_
|
||||
#define _MACCARBCOMPAT_10_2_H_
|
||||
|
||||
/// MacCarbInit1020CompatInit sets up function pointers for stubs to functions
|
||||
/// that are unavailable in 10.2, if we're running on 10.2
|
||||
void MacCarbInit1020CompatInit();
|
||||
|
||||
// Gestalt values introduced in 10.3+ frameworks.
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
|
||||
#define gestaltCPUG47447 0x0112
|
||||
#define gestaltCPU970 0x0139
|
||||
#endif
|
||||
|
||||
// Some agl flags introduced in 10.3+
|
||||
#define AGL_COLOR_FLOAT 58
|
||||
#define AGL_MULTISAMPLE 59
|
||||
#define AGL_SUPERSAMPLE 60
|
||||
#define AGL_SAMPLE_ALPHA 61
|
||||
|
||||
// Window transitions, introduced in 10.3+
|
||||
#define TransitionWindowOptions TransitionWindowOptions_compat
|
||||
typedef struct TransitionWindowOptions_compat {
|
||||
U32 version;
|
||||
double duration;
|
||||
void* parentWindowOfSheet;
|
||||
void* userData;
|
||||
};
|
||||
//const U32 kEventWindowTransitionCompleted = 89;
|
||||
//const U32 kWindowFadeTransitionEffect = 4;
|
||||
//const U32 kEventParamWindowTransitionAction = 'wtac';
|
||||
//const U32 typeWindowTransitionAction = 'wtac';
|
||||
|
||||
// replacements for functions not implemented in 10.2:
|
||||
|
||||
extern S32 (* TransitionWindowWithOptions_ptr) (void*, U32, U32, const void*, bool, void*);
|
||||
|
||||
extern bool (* CGCursorIsVisible_ptr) ();
|
||||
extern U32 (* CGDisplayHideCursor_ptr) (U32);
|
||||
extern U32 (* CGDisplayShowCursor_ptr) (U32);
|
||||
|
||||
#ifndef NO_REDEFINE_10_2_COMPAT
|
||||
#define CGCursorIsVisible CGCursorIsVisible_ptr
|
||||
#define CGDisplayHideCursor CGDisplayHideCursor_ptr
|
||||
#define CGDisplayShowCursor CGDisplayShowCursor_ptr
|
||||
#define TransitionWindowWithOptions TransitionWindowWithOptions_ptr
|
||||
#endif
|
||||
|
||||
#endif // _MACCARBCOMPAT_10_2_H_
|
159
engine/platformMacCarb/macCarbConsole.cc
Executable file
159
engine/platformMacCarb/macCarbConsole.cc
Executable file
@ -0,0 +1,159 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platformMacCarb/macCarbConsole.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "platform/platformThread.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// TODO: convert this to use ncurses.
|
||||
|
||||
static void _MacCarbConsolePrintPrompt();
|
||||
|
||||
MacConsole *gConsole = NULL;
|
||||
|
||||
ConsoleFunction(enableWinConsole, void, 2, 2, "(bool enable)")
|
||||
{
|
||||
argc;
|
||||
if (gConsole)
|
||||
gConsole->enable(dAtob(argv[1]));
|
||||
}
|
||||
|
||||
static void macConsoleConsumer(ConsoleLogEntry::Level, const char *line)
|
||||
{
|
||||
if (gConsole)
|
||||
gConsole->processConsoleLine(line);
|
||||
}
|
||||
|
||||
static void macConsoleInputLoopThread(S32 *arg)
|
||||
{
|
||||
if(!gConsole)
|
||||
return;
|
||||
gConsole->inputLoop();
|
||||
}
|
||||
|
||||
void MacConsole::create()
|
||||
{
|
||||
gConsole = new MacConsole();
|
||||
}
|
||||
|
||||
void MacConsole::destroy()
|
||||
{
|
||||
if (gConsole)
|
||||
delete gConsole;
|
||||
gConsole = NULL;
|
||||
}
|
||||
|
||||
void MacConsole::enable(bool enabled)
|
||||
{
|
||||
if (gConsole == NULL)
|
||||
return;
|
||||
|
||||
bool conIsAlive = consoleThread && consoleThread->isAlive();
|
||||
if(consoleThread && !conIsAlive)
|
||||
delete consoleThread;
|
||||
|
||||
consoleEnabled = enabled;
|
||||
if(consoleEnabled)
|
||||
{
|
||||
if(!conIsAlive)
|
||||
{
|
||||
printf("Initializing Console...\n");
|
||||
new Thread((ThreadRunFunction)macConsoleInputLoopThread,0,true);
|
||||
printf("Console Initialized.\n");
|
||||
|
||||
_MacCarbConsolePrintPrompt();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Deactivating Console.");
|
||||
}
|
||||
}
|
||||
|
||||
bool MacConsole::isEnabled()
|
||||
{
|
||||
if ( !gConsole )
|
||||
return false;
|
||||
|
||||
return gConsole->consoleEnabled;
|
||||
}
|
||||
|
||||
|
||||
MacConsole::MacConsole()
|
||||
{
|
||||
consoleEnabled = platState.headless;
|
||||
clearInBuf();
|
||||
consoleThread = NULL;
|
||||
|
||||
Con::addConsumer(macConsoleConsumer);
|
||||
}
|
||||
|
||||
MacConsole::~MacConsole()
|
||||
{
|
||||
Con::removeConsumer(macConsoleConsumer);
|
||||
}
|
||||
|
||||
void MacConsole::processConsoleLine(const char *consoleLine)
|
||||
{
|
||||
if(consoleEnabled)
|
||||
{
|
||||
printf("%s\n", consoleLine);
|
||||
}
|
||||
}
|
||||
|
||||
void MacConsole::clearInBuf()
|
||||
{
|
||||
dMemset(inBuf, 0, MaxConsoleLineSize);
|
||||
inBufPos=0;
|
||||
}
|
||||
|
||||
void MacConsole::inputLoop()
|
||||
{
|
||||
Con::printf("Console Input Thread Started");
|
||||
unsigned char c;
|
||||
while(consoleEnabled)
|
||||
{
|
||||
c = fgetc(stdin);
|
||||
if(feof(stdin) || ferror(stdin))
|
||||
{
|
||||
clearerr(stdin);
|
||||
Platform::sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == '\n')
|
||||
{
|
||||
// exec the line
|
||||
dStrcpy(postEvent.data, inBuf);
|
||||
postEvent.size = ConsoleEventHeaderSize + dStrlen(inBuf) + 1;
|
||||
Con::printf("=> %s",postEvent.data);
|
||||
Game->postEvent(postEvent);
|
||||
// clear the buffer
|
||||
clearInBuf();
|
||||
_MacCarbConsolePrintPrompt();
|
||||
}
|
||||
else
|
||||
{
|
||||
// add it to the buffer.
|
||||
inBuf[inBufPos++] = c;
|
||||
// if we're full, clear & warn.
|
||||
if(inBufPos >= MaxConsoleLineSize-1)
|
||||
{
|
||||
clearInBuf();
|
||||
Con::warnf("Line too long, discarding this command: %s", inBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
Con::printf("Console Input Thread Stopped");
|
||||
}
|
||||
|
||||
static void _MacCarbConsolePrintPrompt()
|
||||
{
|
||||
printf("%s", Con::getVariable("Con::Prompt"));
|
||||
}
|
43
engine/platformMacCarb/macCarbConsole.h
Executable file
43
engine/platformMacCarb/macCarbConsole.h
Executable file
@ -0,0 +1,43 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBCONSOLE_H_
|
||||
#define _MACCARBCONSOLE_H_
|
||||
|
||||
#include "console/console.h"
|
||||
#include "platform/event.h"
|
||||
|
||||
class Thread;
|
||||
|
||||
class MacConsole
|
||||
{
|
||||
private:
|
||||
bool consoleEnabled;
|
||||
Thread* consoleThread;
|
||||
|
||||
U32 inBufPos;
|
||||
char inBuf[MaxConsoleLineSize];
|
||||
ConsoleEvent postEvent;
|
||||
|
||||
void clearInBuf();
|
||||
|
||||
public:
|
||||
static void create();
|
||||
static void destroy();
|
||||
static bool isEnabled();
|
||||
|
||||
MacConsole();
|
||||
~MacConsole();
|
||||
void enable(bool);
|
||||
|
||||
void processConsoleLine(const char *consoleLine);
|
||||
|
||||
void inputLoop();
|
||||
|
||||
};
|
||||
|
||||
extern MacConsole *gConsole;
|
||||
|
||||
#endif
|
1057
engine/platformMacCarb/macCarbEvents.cc
Executable file
1057
engine/platformMacCarb/macCarbEvents.cc
Executable file
File diff suppressed because it is too large
Load Diff
42
engine/platformMacCarb/macCarbEvents.h
Executable file
42
engine/platformMacCarb/macCarbEvents.h
Executable file
@ -0,0 +1,42 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/// Hides the mouse cursor when the mouse is locked, when we are in fullscreen
|
||||
/// mode, and when the cursor is inside the window bounds.
|
||||
/// Optionally takes the cursor location, in window local coords.
|
||||
void MacCarbCheckHideCursor(S32 x=-1, S32 y=-1);
|
||||
|
||||
/// Hides or shows the system mouse cursor, regardless of the mouse position,
|
||||
/// and tracks the hidden state.
|
||||
void MacCarbSetHideCursor(bool shouldHide);
|
||||
|
||||
/// Install event handlers on the current window & on the app.
|
||||
void MacCarbInstallCarbonEventHandlers(void);
|
||||
|
||||
/// Remove all event handlers, except the alert event handlers.
|
||||
void MacCarbRemoveCarbonEventHandlers(void);
|
||||
|
||||
/// Install event handlers for custom Torque inter-thread communication.
|
||||
/// This must be called before starting multithreaded execution in main().
|
||||
void MacCarbInstallTorqueCarbonEventHandlers(void);
|
||||
|
||||
/// create an event of class kEventClassTorque, and send it to the main thread
|
||||
void MacCarbSendTorqueEventToMain( U32 eventKind, void* userData = NULL );
|
||||
|
||||
/// event type for alerts. The event class is an arbitrary val, it must not collide w/ kEventApp* .
|
||||
const U32 kEventClassTorque = 'TORQ';
|
||||
const U32 kEventTorqueAlert = 1;
|
||||
const U32 kEventTorqueFadeInWindow = 2;
|
||||
const U32 kEventTorqueFadeOutWindow = 3;
|
||||
const U32 kEventTorqueReleaseWindow = 4;
|
||||
const U32 kEventTorqueShowMenuBar = 5;
|
||||
|
||||
const U32 kEventParamTorqueData = 'tDAT'; // typeVoidPtr void*
|
||||
//const U32 kEventParamTorqueSemaphorePtr = 'tSEM'; // typeVoidPtr void*
|
||||
//const U32 kEventParamTorqueDialogRef = 'tDRF'; // typeDialogRef DialogRef
|
||||
//const U32 kEventParamTorqueHitPtr = 'tHIT'; // typeVoidPtr U32*
|
||||
//const U32 typeDialogRef = 'dlog'; // oddly, not provided in Frameworks.
|
||||
|
899
engine/platformMacCarb/macCarbFileio.cc
Executable file
899
engine/platformMacCarb/macCarbFileio.cc
Executable file
@ -0,0 +1,899 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "core/fileio.h"
|
||||
#include "core/tVector.h"
|
||||
#include "core/stringTable.h"
|
||||
#include "console/console.h"
|
||||
#include "platform/profiler.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <utime.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
//TODO: file io still needs some work...
|
||||
|
||||
// this is the main working dir path.
|
||||
static StringTableEntry cwd = NULL;
|
||||
|
||||
#define MAX_MAC_PATH_LONG 2048
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(TORQUE_OS_MAC_OSX)
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#else
|
||||
#include <CFBundle.h>
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool dFileDelete(const char * name)
|
||||
{
|
||||
if(!name )
|
||||
return(false);
|
||||
|
||||
if (dStrlen(name) > MAX_MAC_PATH_LONG)
|
||||
Con::warnf("dFileDelete: Filename length is pretty long...");
|
||||
|
||||
return(remove(name) == 0); // remove returns 0 on success
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool dFileTouch(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
// set file at path's modification and access times to now.
|
||||
return( utimes( path, NULL) == 0); // utimes returns 0 on success.
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructors & Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// After construction, the currentStatus will be Closed and the capabilities
|
||||
// will be 0.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::File()
|
||||
: currentStatus(Closed), capability(0)
|
||||
{
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// insert a copy constructor here... (currently disabled)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
File::~File()
|
||||
{
|
||||
close();
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Open a file in the mode specified by openMode (Read, Write, or ReadWrite).
|
||||
// Truncate the file if the mode is either Write or ReadWrite and truncate is
|
||||
// true.
|
||||
//
|
||||
// Sets capability appropriate to the openMode.
|
||||
// Returns the currentStatus of the file.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::open(const char *filename, const AccessMode openMode)
|
||||
{
|
||||
if (dStrlen(filename) > MAX_MAC_PATH_LONG)
|
||||
Con::warnf("File::open: Filename length is pretty long...");
|
||||
|
||||
// Close the file if it was already open...
|
||||
if (currentStatus != Closed)
|
||||
close();
|
||||
|
||||
// create the appropriate type of file...
|
||||
switch (openMode)
|
||||
{
|
||||
case Read:
|
||||
handle = (void *)fopen(filename, "rb"); // read only
|
||||
break;
|
||||
case Write:
|
||||
handle = (void *)fopen(filename, "wb"); // write only
|
||||
break;
|
||||
case ReadWrite:
|
||||
handle = (void *)fopen(filename, "ab+"); // write(append) and read
|
||||
break;
|
||||
case WriteAppend:
|
||||
handle = (void *)fopen(filename, "ab"); // write(append) only
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "File::open: bad access mode");
|
||||
}
|
||||
|
||||
// handle not created successfully
|
||||
if (handle == NULL)
|
||||
return setStatus();
|
||||
|
||||
// successfully created file, so set the file capabilities...
|
||||
switch (openMode)
|
||||
{
|
||||
case Read:
|
||||
capability = FileRead;
|
||||
break;
|
||||
case Write:
|
||||
case WriteAppend:
|
||||
capability = FileWrite;
|
||||
break;
|
||||
case ReadWrite:
|
||||
capability = FileRead | FileWrite;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "File::open: bad access mode");
|
||||
}
|
||||
|
||||
// must set the file status before setting the position.
|
||||
currentStatus = Ok;
|
||||
|
||||
if (openMode == ReadWrite)
|
||||
setPosition(0);
|
||||
|
||||
// success!
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get the current position of the file pointer.
|
||||
//-----------------------------------------------------------------------------
|
||||
U32 File::getPosition() const
|
||||
{
|
||||
AssertFatal(currentStatus != Closed , "File::getPosition: file closed");
|
||||
AssertFatal(handle != NULL, "File::getPosition: invalid file handle");
|
||||
|
||||
return ftell((FILE*)handle);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set the position of the file pointer.
|
||||
// Absolute and relative positioning is supported via the absolutePos
|
||||
// parameter.
|
||||
//
|
||||
// If positioning absolutely, position MUST be positive - an IOError results if
|
||||
// position is negative.
|
||||
// Position can be negative if positioning relatively, however positioning
|
||||
// before the start of the file is an IOError.
|
||||
//
|
||||
// Returns the currentStatus of the file.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::setPosition(S32 position, bool absolutePos)
|
||||
{
|
||||
AssertFatal(Closed != currentStatus, "File::setPosition: file closed");
|
||||
AssertFatal(handle != NULL, "File::setPosition: invalid file handle");
|
||||
|
||||
if (currentStatus != Ok && currentStatus != EOS )
|
||||
return currentStatus;
|
||||
|
||||
U32 finalPos;
|
||||
if(absolutePos)
|
||||
{
|
||||
// absolute position
|
||||
AssertFatal(0 <= position, "File::setPosition: negative absolute position");
|
||||
// position beyond EOS is OK
|
||||
fseek((FILE*)handle, position, SEEK_SET);
|
||||
finalPos = ftell((FILE*)handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// relative position
|
||||
AssertFatal((getPosition() + position) >= 0, "File::setPosition: negative relative position");
|
||||
// position beyond EOS is OK
|
||||
fseek((FILE*)handle, position, SEEK_CUR);
|
||||
finalPos = ftell((FILE*)handle);
|
||||
}
|
||||
|
||||
// ftell returns -1 on error. set error status
|
||||
if (0xffffffff == finalPos)
|
||||
return setStatus();
|
||||
|
||||
// success, at end of file
|
||||
else if (finalPos >= getSize())
|
||||
return currentStatus = EOS;
|
||||
|
||||
// success!
|
||||
else
|
||||
return currentStatus = Ok;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get the size of the file in bytes.
|
||||
// It is an error to query the file size for a Closed file, or for one with an
|
||||
// error status.
|
||||
//-----------------------------------------------------------------------------
|
||||
U32 File::getSize() const
|
||||
{
|
||||
AssertWarn(Closed != currentStatus, "File::getSize: file closed");
|
||||
AssertFatal(handle != NULL, "File::getSize: invalid file handle");
|
||||
|
||||
if (Ok == currentStatus || EOS == currentStatus)
|
||||
{
|
||||
struct stat statData;
|
||||
|
||||
if(fstat(fileno((FILE*)handle), &statData) != 0)
|
||||
return 0;
|
||||
|
||||
// return the size in bytes
|
||||
return statData.st_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Flush the file.
|
||||
// It is an error to flush a read-only file.
|
||||
// Returns the currentStatus of the file.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::flush()
|
||||
{
|
||||
AssertFatal(Closed != currentStatus, "File::flush: file closed");
|
||||
AssertFatal(handle != NULL, "File::flush: invalid file handle");
|
||||
AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file");
|
||||
|
||||
if (fflush((FILE*)handle) != 0)
|
||||
return setStatus();
|
||||
else
|
||||
return currentStatus = Ok;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Close the File.
|
||||
//
|
||||
// Returns the currentStatus
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::close()
|
||||
{
|
||||
// check if it's already closed...
|
||||
if (Closed == currentStatus)
|
||||
return currentStatus;
|
||||
|
||||
// it's not, so close it...
|
||||
if (handle != NULL)
|
||||
{
|
||||
if (fclose((FILE*)handle) != 0)
|
||||
return setStatus();
|
||||
}
|
||||
handle = NULL;
|
||||
return currentStatus = Closed;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Self-explanatory.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::getStatus() const
|
||||
{
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets and returns the currentStatus when an error has been encountered.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::setStatus()
|
||||
{
|
||||
const char* err = strerror(errno);
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES: // permission denied
|
||||
currentStatus = IOError;
|
||||
break;
|
||||
case EBADF: // Bad File Pointer
|
||||
case EINVAL: // Invalid argument
|
||||
case ENOENT: // file not found
|
||||
case ENAMETOOLONG:
|
||||
default:
|
||||
currentStatus = UnknownError;
|
||||
}
|
||||
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets and returns the currentStatus to status.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::setStatus(File::Status status)
|
||||
{
|
||||
return currentStatus = status;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Read from a file.
|
||||
// The number of bytes to read is passed in size, the data is returned in src.
|
||||
// The number of bytes read is available in bytesRead if a non-Null pointer is
|
||||
// provided.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::read(U32 size, char *dst, U32 *bytesRead)
|
||||
{
|
||||
AssertFatal(Closed != currentStatus, "File::read: file closed");
|
||||
AssertFatal(handle != NULL, "File::read: invalid file handle");
|
||||
AssertFatal(NULL != dst, "File::read: NULL destination pointer");
|
||||
AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability");
|
||||
AssertWarn(0 != size, "File::read: size of zero");
|
||||
|
||||
if (Ok != currentStatus || 0 == size)
|
||||
return currentStatus;
|
||||
|
||||
// read from stream
|
||||
U32 nBytes = fread(dst, 1, size, (FILE*)handle);
|
||||
|
||||
// did we hit the end of the stream?
|
||||
if( nBytes != size)
|
||||
currentStatus = EOS;
|
||||
|
||||
// if bytesRead is a valid pointer, send number of bytes read there.
|
||||
if(bytesRead)
|
||||
*bytesRead = nBytes;
|
||||
|
||||
// successfully read size bytes
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write to a file.
|
||||
// The number of bytes to write is passed in size, the data is passed in src.
|
||||
// The number of bytes written is available in bytesWritten if a non-Null
|
||||
// pointer is provided.
|
||||
//-----------------------------------------------------------------------------
|
||||
File::Status File::write(U32 size, const char *src, U32 *bytesWritten)
|
||||
{
|
||||
AssertFatal(Closed != currentStatus, "File::write: file closed");
|
||||
AssertFatal(handle != NULL, "File::write: invalid file handle");
|
||||
AssertFatal(NULL != src, "File::write: NULL source pointer");
|
||||
AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability");
|
||||
AssertWarn(0 != size, "File::write: size of zero");
|
||||
|
||||
if ((Ok != currentStatus && EOS != currentStatus) || 0 == size)
|
||||
return currentStatus;
|
||||
|
||||
// write bytes to the stream
|
||||
U32 nBytes = fwrite(src, 1, size,(FILE*)handle);
|
||||
|
||||
// if we couldn't write everything, we've got a problem. set error status.
|
||||
if(nBytes != size)
|
||||
setStatus();
|
||||
|
||||
// if bytesWritten is a valid pointer, put number of bytes read there.
|
||||
if(bytesWritten)
|
||||
*bytesWritten = nBytes;
|
||||
|
||||
// return current File status, whether good or ill.
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Self-explanatory.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool File::hasCapability(Capability cap) const
|
||||
{
|
||||
return (0 != (U32(cap) & capability));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b)
|
||||
{
|
||||
if(a > b)
|
||||
return 1;
|
||||
if(a < b)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// either time param COULD be null.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::getFileTimes(const char *path, FileTime *createTime, FileTime *modifyTime)
|
||||
{
|
||||
// MacOSX is NOT guaranteed to be running off a HFS volume,
|
||||
// and UNIX does not keep a record of a file's creation time anywhere.
|
||||
// So instead of creation time we return changed time,
|
||||
// just like the Linux platform impl does.
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
struct stat statData;
|
||||
|
||||
if (stat(path, &statData) == -1)
|
||||
return false;
|
||||
|
||||
if(createTime)
|
||||
*createTime = statData.st_ctime;
|
||||
|
||||
if(modifyTime)
|
||||
*modifyTime = statData.st_mtime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::createPath(const char *file)
|
||||
{
|
||||
Con::warnf("creating path %s",file);
|
||||
// if the path exists, we're done.
|
||||
struct stat statData;
|
||||
if( stat(file, &statData) == 0 )
|
||||
{
|
||||
return true; // exists, rejoice.
|
||||
}
|
||||
|
||||
// get the parent path.
|
||||
// we're not using basename because it's not thread safe.
|
||||
U32 len = dStrlen(file);
|
||||
char parent[len];
|
||||
bool isDirPath = false;
|
||||
|
||||
dStrncpy(parent,file,len);
|
||||
parent[len] = '\0';
|
||||
if(parent[len - 1] == '/')
|
||||
{
|
||||
parent[len - 1] = '\0'; // cut off the trailing slash, if there is one
|
||||
isDirPath = true; // we got a trailing slash, so file is a directory.
|
||||
}
|
||||
|
||||
// recusively create the parent path.
|
||||
// only recurse if newpath has a slash that isn't a leading slash.
|
||||
char *slash = dStrrchr(parent,'/');
|
||||
if( slash && slash != parent)
|
||||
{
|
||||
// snip the path just after the last slash.
|
||||
slash[1] = '\0';
|
||||
// recusively create the parent path. fail if parent path creation failed.
|
||||
if(!Platform::createPath(parent))
|
||||
return false;
|
||||
}
|
||||
|
||||
// create *file if it is a directory path.
|
||||
if(isDirPath)
|
||||
{
|
||||
// try tocreate the directory
|
||||
if( mkdir(file, 0777) != 0) // app may reside in global apps dir, and so must be writable to all.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::cdFileExists(const char *filePath, const char *volumeName, S32 serialNum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// helper func for getWorkingDirectory
|
||||
bool isMainDotCsPresent(char *dir)
|
||||
{
|
||||
char maincsbuf[MAX_MAC_PATH_LONG];
|
||||
char *maincsname = "/main.cs";
|
||||
U32 len = dStrlen(dir) + dStrlen(maincsname);
|
||||
AssertISV(len < MAX_MAC_PATH_LONG, "Sorry, path is too long, I can't run from this folder.");
|
||||
|
||||
dSprintf(maincsbuf,MAX_MAC_PATH_LONG,"%s%s", dir, maincsname);
|
||||
|
||||
return Platform::isFile(maincsbuf);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Finds and sets the current working directory.
|
||||
/// Torque tries to automatically detect whether you have placed the game files
|
||||
/// inside or outside the application's bundle. It checks for the presence of
|
||||
/// the file 'main.cs'. If it finds it, Torque will assume that the other game
|
||||
/// files are there too. If Torque does not see 'main.cs' inside its bundle, it
|
||||
/// will assume the files are outside the bundle.
|
||||
/// Since you probably don't want to copy the game files into the app every time
|
||||
/// you build, you will want to leave them outside the bundle for development.
|
||||
///
|
||||
/// Placing all content inside the application bundle gives a much better user
|
||||
/// experience when you distribute your app.
|
||||
StringTableEntry Platform::getWorkingDirectory()
|
||||
{
|
||||
if(!cwd)
|
||||
{
|
||||
char cwd_buf[MAX_MAC_PATH_LONG];
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
|
||||
|
||||
bool inside = true;
|
||||
bool outside = false;
|
||||
bool done = false;
|
||||
|
||||
while(!done)
|
||||
{
|
||||
// first look for game content inside the application bundle.
|
||||
// then we look outside the bundle
|
||||
// then we assume it's a tool, and the "bundle" = the binary file.
|
||||
CFURLRef workingUrl;
|
||||
if(inside)
|
||||
workingUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault,bundleUrl,CFSTR("Contents/Resources"),true);
|
||||
else if(outside)
|
||||
workingUrl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, bundleUrl);
|
||||
else
|
||||
{
|
||||
workingUrl = bundleUrl;
|
||||
CFRetain(workingUrl); // so that we can release bundleUrl twice.
|
||||
}
|
||||
|
||||
CFStringRef workingString = CFURLCopyFileSystemPath(workingUrl, kCFURLPOSIXPathStyle);
|
||||
CFMutableStringRef normalizedString = CFStringCreateMutableCopy(NULL, 0, workingString);
|
||||
CFStringNormalize(normalizedString,kCFStringNormalizationFormC);
|
||||
CFStringGetCString(normalizedString, cwd_buf, sizeof(cwd_buf)-1, kCFStringEncodingUTF8);
|
||||
|
||||
// if we dont see main.cs inside the bundle, try again looking outside
|
||||
// we're done if we find it, or if we find it neither inside or outside.
|
||||
if( isMainDotCsPresent(cwd_buf) || ( !inside && !outside))
|
||||
done = true;
|
||||
|
||||
if(inside)
|
||||
inside = false, outside = true;
|
||||
else if(outside)
|
||||
outside = false;
|
||||
|
||||
CFRelease(workingUrl);
|
||||
CFRelease(workingString);
|
||||
CFRelease(normalizedString);
|
||||
}
|
||||
|
||||
//CFRelease(mainBundle); // apple docs say to release this, but that causes a sigsegv(11)
|
||||
CFRelease(bundleUrl);
|
||||
|
||||
chdir(cwd_buf); // set the current working directory.
|
||||
|
||||
if(StringTable)
|
||||
cwd = StringTable->insert(cwd_buf);
|
||||
}
|
||||
|
||||
return cwd;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
StringTableEntry Platform::getExecutableName()
|
||||
{
|
||||
char path_buf[MAX_MAC_PATH_LONG];
|
||||
// get a cfurl to the executable name
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
|
||||
|
||||
// get a cfstring of just the app name
|
||||
CFStringRef workingString = CFURLCopyLastPathComponent(bundleUrl);
|
||||
CFMutableStringRef normalizedString = CFStringCreateMutableCopy(NULL, 0, workingString);
|
||||
CFStringNormalize(normalizedString,kCFStringNormalizationFormC);
|
||||
CFStringGetCString(normalizedString, path_buf, sizeof(path_buf)-1, kCFStringEncodingUTF8);
|
||||
|
||||
CFRelease(bundleUrl);
|
||||
CFRelease(workingString);
|
||||
CFRelease(normalizedString);
|
||||
|
||||
return StringTable->insert(path_buf);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::isFile(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
// make sure we can stat the file
|
||||
struct stat statData;
|
||||
if( stat(path, &statData) < 0 )
|
||||
return false;
|
||||
|
||||
// now see if it's a regular file
|
||||
if( (statData.st_mode & S_IFMT) == S_IFREG)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::isDirectory(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
// make sure we can stat the file
|
||||
struct stat statData;
|
||||
if( stat(path, &statData) < 0 )
|
||||
return false;
|
||||
|
||||
// now see if it's a directory
|
||||
if( (statData.st_mode & S_IFMT) == S_IFDIR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
S32 Platform::getFileSize(const char* pFilePath)
|
||||
{
|
||||
S32 size;
|
||||
if (!pFilePath || !*pFilePath)
|
||||
return 0;
|
||||
|
||||
struct stat statData;
|
||||
if( stat(pFilePath, &statData) < 0 )
|
||||
return 0;
|
||||
|
||||
// and return it's size in bytes
|
||||
return (S32)statData.st_size;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::isSubDirectory(const char *pathParent, const char *pathSub)
|
||||
{
|
||||
char fullpath[MAX_MAC_PATH_LONG];
|
||||
dStrcpyl(fullpath, MAX_MAC_PATH_LONG, pathParent, "/", pathSub, NULL);
|
||||
return isDirectory((const char *)fullpath);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// utility for platform::hasSubDirectory() and platform::dumpDirectories()
|
||||
// ensures that the entry is a directory, and isnt on the ignore lists.
|
||||
inline bool isGoodDirectory(dirent* entry)
|
||||
{
|
||||
return (entry->d_type == DT_DIR // is a dir
|
||||
&& dStrcmp(entry->d_name,".") != 0 // not here
|
||||
&& dStrcmp(entry->d_name,"..") != 0 // not parent
|
||||
&& !Platform::isExcludedDirectory(entry->d_name)); // not excluded
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::hasSubDirectory(const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
dirent *entry;
|
||||
|
||||
dir = opendir(path);
|
||||
if(!dir)
|
||||
return false; // we got a bad path, so no, it has no subdirectory.
|
||||
|
||||
while( entry = readdir(dir))
|
||||
{
|
||||
if(isGoodDirectory(entry) )
|
||||
{
|
||||
closedir(dir);
|
||||
return true; // we have a subdirectory, that isnt on the exclude list.
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return false; // either this dir had no subdirectories, or they were all on the exclude list.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool recurseDumpDirectories(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
|
||||
{
|
||||
DIR *dir;
|
||||
dirent *entry;
|
||||
U32 len = dStrlen(basePath) + dStrlen(path) + 2;
|
||||
char pathbuf[len];
|
||||
|
||||
// construct the file path
|
||||
dSprintf(pathbuf, len, "%s/%s", basePath, path);
|
||||
pathbuf[len] = '\0';
|
||||
|
||||
// be sure it opens.
|
||||
dir = opendir(pathbuf);
|
||||
if(!dir)
|
||||
return false;
|
||||
|
||||
// look inside the current directory
|
||||
while( entry = readdir(dir))
|
||||
{
|
||||
// we just want directories.
|
||||
if(!isGoodDirectory(entry))
|
||||
continue;
|
||||
|
||||
// TODO: better unicode file name handling
|
||||
// // Apple's file system stores unicode file names in decomposed form.
|
||||
// // ATSUI will not reliably draw out just the accent character by itself,
|
||||
// // so our text renderer has no chance of rendering decomposed form unicode.
|
||||
// // We have to convert the entry name to precomposed normalized form.
|
||||
// CFStringRef cfdname = CFStringCreateWithCString(NULL,entry->d_name,kCFStringEncodingUTF8);
|
||||
// CFMutableStringRef cfentryName = CFStringCreateMutableCopy(NULL,0,cfdname);
|
||||
// CFStringNormalize(cfentryName,kCFStringNormalizationFormC);
|
||||
//
|
||||
// U32 entryNameLen = CFStringGetLength(cfentryName) * 4 + 1;
|
||||
// char entryName[entryNameLen];
|
||||
// CFStringGetCString(cfentryName, entryName, entryNameLen, kCFStringEncodingUTF8);
|
||||
// entryName[entryNameLen-1] = NULL; // sometimes, CFStringGetCString() doesn't null terminate.
|
||||
// CFRelease(cfentryName);
|
||||
// CFRelease(cfdname);
|
||||
|
||||
// construct the new path string, we'll need this below.
|
||||
U32 newpathlen = dStrlen(path) + dStrlen(entry->d_name) + 2;
|
||||
char newpath[newpathlen];
|
||||
if(dStrlen(path) > 0) // prevent extra slashes in the path
|
||||
dSprintf(newpath, newpathlen,"%s/%s",path,entry->d_name);
|
||||
else
|
||||
dStrncpy(newpath,entry->d_name, newpathlen);
|
||||
newpath[newpathlen] = '\0';
|
||||
|
||||
// we have a directory, add it to the list.
|
||||
if( noBasePath )
|
||||
directoryVector.push_back(StringTable->insert(newpath));
|
||||
else {
|
||||
U32 fullpathlen = dStrlen(basePath) + dStrlen(newpath) + 2;
|
||||
char fullpath[fullpathlen];
|
||||
dSprintf(fullpath,fullpathlen,"%s/%s",basePath,newpath);
|
||||
fullpath[fullpathlen] = '\0';
|
||||
|
||||
directoryVector.push_back(StringTable->insert(fullpath));
|
||||
}
|
||||
|
||||
// and recurse into it, unless we've run out of depth
|
||||
if( depth != 0) // passing a val of -1 as the recurse depth means go forever
|
||||
recurseDumpDirectories(basePath, newpath, directoryVector, depth-1, noBasePath);
|
||||
}
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::dumpDirectories(const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
|
||||
{
|
||||
PROFILE_START(dumpDirectories);
|
||||
int len = dStrlen(path);
|
||||
char newpath[len];
|
||||
|
||||
dStrncpy(newpath,path,len);
|
||||
newpath[len] = '\0';
|
||||
if(newpath[len - 1] == '/')
|
||||
newpath[len - 1] = '\0'; // cut off the trailing slash, if there is one
|
||||
|
||||
bool ret = recurseDumpDirectories(newpath, "", directoryVector, depth, noBasePath);
|
||||
PROFILE_END();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool recurseDumpPath(const char* curPath, Vector<Platform::FileInfo>& fileVector, U32 depth)
|
||||
{
|
||||
DIR *dir;
|
||||
dirent *entry;
|
||||
|
||||
// be sure it opens.
|
||||
dir = opendir(curPath);
|
||||
if(!dir)
|
||||
return false;
|
||||
|
||||
// look inside the current directory
|
||||
while( entry = readdir(dir))
|
||||
{
|
||||
// construct the full file path. we need this to get the file size and to recurse
|
||||
U32 len = dStrlen(curPath) + entry->d_namlen + 2;
|
||||
char pathbuf[len];
|
||||
dSprintf( pathbuf, len, "%s/%s", curPath, entry->d_name);
|
||||
pathbuf[len] = '\0';
|
||||
|
||||
// ok, deal with directories and files seperately.
|
||||
if( entry->d_type == DT_DIR )
|
||||
{
|
||||
if( depth == 0)
|
||||
continue;
|
||||
|
||||
// filter out dirs we dont want.
|
||||
if( !isGoodDirectory(entry) )
|
||||
continue;
|
||||
|
||||
// recurse into the dir
|
||||
recurseDumpPath( pathbuf, fileVector, depth-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//add the file entry to the list
|
||||
// unlike recurseDumpDirectories(), we need to return more complex info here.
|
||||
U32 fileSize = Platform::getFileSize(pathbuf);
|
||||
fileVector.increment();
|
||||
Platform::FileInfo& rInfo = fileVector.last();
|
||||
rInfo.pFullPath = StringTable->insert(curPath);
|
||||
rInfo.pFileName = StringTable->insert(entry->d_name);
|
||||
rInfo.fileSize = fileSize;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::dumpPath(const char *path, Vector<Platform::FileInfo>& fileVector, S32 depth)
|
||||
{
|
||||
PROFILE_START(dumpPath);
|
||||
int len = dStrlen(path);
|
||||
char newpath[len+1];
|
||||
|
||||
dStrncpy(newpath,path,len);
|
||||
newpath[len] = '\0'; // null terminate
|
||||
if(newpath[len - 1] == '/')
|
||||
newpath[len - 1] = '\0'; // cut off the trailing slash, if there is one
|
||||
|
||||
bool ret = recurseDumpPath( newpath, fileVector, depth);
|
||||
PROFILE_END();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(TORQUE_DEBUG)
|
||||
ConsoleFunction(testHasSubdir,void,2,2,"tests platform::hasSubDirectory") {
|
||||
Con::printf("testing %s",argv[1]);
|
||||
Platform::addExcludedDirectory(".svn");
|
||||
if(Platform::hasSubDirectory(argv[1]))
|
||||
Con::printf(" has subdir");
|
||||
else
|
||||
Con::printf(" does not have subdir");
|
||||
}
|
||||
|
||||
ConsoleFunction(testDumpDirectories,void,4,4,"testDumpDirectories('path', int depth, bool noBasePath)") {
|
||||
Vector<StringTableEntry> paths;
|
||||
S32 depth = dAtoi(argv[2]);
|
||||
bool noBasePath = dAtob(argv[3]);
|
||||
|
||||
Platform::addExcludedDirectory(".svn");
|
||||
|
||||
Platform::dumpDirectories(argv[1],paths,dAtoi(argv[2]),dAtob(argv[3]));
|
||||
|
||||
Con::printf("Dumping directories starting from %s with depth %i", argv[1],depth);
|
||||
|
||||
for(Vector<StringTableEntry>::iterator itr = paths.begin(); itr != paths.end(); itr++) {
|
||||
Con::printf(*itr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ConsoleFunction(testDumpPaths, void, 3, 3, "testDumpPaths('path', int depth)")
|
||||
{
|
||||
Vector<Platform::FileInfo> files;
|
||||
S32 depth = dAtoi(argv[2]);
|
||||
|
||||
Platform::addExcludedDirectory(".svn");
|
||||
|
||||
Platform::dumpPath(argv[1], files, depth);
|
||||
|
||||
for(Vector<Platform::FileInfo>::iterator itr = files.begin(); itr != files.end(); itr++) {
|
||||
Con::printf("%s/%s",itr->pFullPath, itr->pFileName);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ConsoleFunction(testFileTouch, bool , 2,2, "testFileTouch('path')")
|
||||
{
|
||||
return dFileTouch(argv[1]);
|
||||
}
|
||||
|
||||
ConsoleFunction(testGetFileTimes, bool, 2,2, "testGetFileTimes('path')")
|
||||
{
|
||||
FileTime create, modify;
|
||||
bool ok;
|
||||
ok = Platform::getFileTimes(argv[1],&create, &modify);
|
||||
Con::printf("%s Platform::getFileTimes %i, %i", ok ? "+OK" : "-FAIL", create, modify);
|
||||
}
|
||||
|
||||
#endif
|
252
engine/platformMacCarb/macCarbFont.cc
Executable file
252
engine/platformMacCarb/macCarbFont.cc
Executable file
@ -0,0 +1,252 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platformMacCarb/macCarbFont.h"
|
||||
#include "dgl/gFont.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "Math/mRect.h"
|
||||
#include "console/console.h"
|
||||
#include "core/unicode.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// New Unicode capable font class.
|
||||
PlatformFont *createPlatformFont(const char *name, U32 size, U32 charset /* = TGE_ANSI_CHARSET */)
|
||||
{
|
||||
PlatformFont *retFont = new MacCarbFont;
|
||||
|
||||
if(retFont->create(name, size, charset))
|
||||
return retFont;
|
||||
|
||||
delete retFont;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
MacCarbFont::MacCarbFont()
|
||||
{
|
||||
mStyle = NULL;
|
||||
mLayout = NULL;
|
||||
mColorSpace = NULL;
|
||||
}
|
||||
|
||||
MacCarbFont::~MacCarbFont()
|
||||
{
|
||||
// apple docs say we should dispose the layout first.
|
||||
ATSUDisposeTextLayout(mLayout);
|
||||
ATSUDisposeStyle(mStyle);
|
||||
CGColorSpaceRelease(mColorSpace);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool MacCarbFont::create( const char *name, U32 size, U32 charset)
|
||||
{
|
||||
// create and cache the style and layout.
|
||||
// based on apple sample code at http://developer.apple.com/qa/qa2001/qa1027.html
|
||||
|
||||
// note: charset is ignored on mac. -- we don't need it to get the right chars.
|
||||
// But do we need it to translate encodings? hmm...
|
||||
|
||||
CFStringRef cfsName;
|
||||
ATSUFontID atsuFontID;
|
||||
ATSFontRef atsFontRef;
|
||||
Fixed atsuSize;
|
||||
ATSURGBAlphaColor black;
|
||||
ATSFontMetrics fontMetrics;
|
||||
U32 scaledSize;
|
||||
|
||||
// Look up the font. We need it in 2 differnt formats, for differnt Apple APIs.
|
||||
cfsName = CFStringCreateWithCString( kCFAllocatorDefault, name, kCFStringEncodingUTF8);
|
||||
if(!cfsName)
|
||||
Con::errorf("Error: could not make a cfstring out of \"%s\" ",name);
|
||||
|
||||
atsFontRef = ATSFontFindFromName( cfsName, kATSOptionFlagsDefault);
|
||||
atsuFontID = FMGetFontFromATSFontRef( atsFontRef);
|
||||
|
||||
// make sure we found it. ATSFontFindFromName() appears to return 0 if it cant find anything. Apple docs contain no info on error returns.
|
||||
if( !atsFontRef || !atsuFontID )
|
||||
{
|
||||
Con::errorf("MacCarbFont::create - could not load font -%s-",name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// adjust the size. win dpi = 96, mac dpi = 72. 72/96 = .75
|
||||
// Interestingly enough, 0.75 is not what makes things the right size.
|
||||
scaledSize = size - 2 - (int)((float)size * 0.1);
|
||||
mSize = scaledSize;
|
||||
|
||||
// Set up the size and color. We send these to ATSUSetAttributes().
|
||||
atsuSize = IntToFixed(scaledSize);
|
||||
black.red = black.green = black.blue = black.alpha = 1.0;
|
||||
|
||||
// Three parrallel arrays for setting up font, size, and color attributes.
|
||||
ATSUAttributeTag theTags[] = { kATSUFontTag, kATSUSizeTag, kATSURGBAlphaColorTag};
|
||||
ByteCount theSizes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(ATSURGBAlphaColor) };
|
||||
ATSUAttributeValuePtr theValues[] = { &atsuFontID, &atsuSize, &black };
|
||||
|
||||
// create and configure the style object.
|
||||
ATSUCreateStyle(&mStyle);
|
||||
ATSUSetAttributes( mStyle, 3, theTags, theSizes, theValues );
|
||||
|
||||
// create the layout object,
|
||||
ATSUCreateTextLayout(&mLayout);
|
||||
// we'll bind the layout to a bitmap context when we actually draw.
|
||||
// ATSUSetTextPointerLocation() - will set the text buffer
|
||||
// ATSUSetLayoutControls() - will set the cg context.
|
||||
|
||||
// get font metrics, save our baseline and height
|
||||
ATSFontGetHorizontalMetrics(atsFontRef, kATSOptionFlagsDefault, &fontMetrics);
|
||||
mBaseline = scaledSize * fontMetrics.ascent;
|
||||
mHeight = scaledSize * ( fontMetrics.ascent - fontMetrics.descent + fontMetrics.leading ) + 1;
|
||||
|
||||
// cache our grey color space, so we dont have to re create it every time.
|
||||
mColorSpace = CGColorSpaceCreateDeviceGray();
|
||||
|
||||
// and finally cache the font's name. We use this to cheat some antialiasing options below.
|
||||
mName = StringTable->insert(name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool MacCarbFont::isValidChar(const UTF8 *str) const
|
||||
{
|
||||
// since only low order characters are invalid, and since those characters
|
||||
// are single codeunits in UTF8, we can safely cast here.
|
||||
return isValidChar((UTF16)*str);
|
||||
}
|
||||
|
||||
bool MacCarbFont::isValidChar( const UTF16 ch) const
|
||||
{
|
||||
// We cut out the ASCII control chars here. Only printable characters are valid.
|
||||
// 0x20 == 32 == space
|
||||
if( ch < 0x20 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PlatformFont::CharInfo& MacCarbFont::getCharInfo(const UTF8 *str) const
|
||||
{
|
||||
return getCharInfo(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
|
||||
}
|
||||
|
||||
PlatformFont::CharInfo& MacCarbFont::getCharInfo(const UTF16 ch) const
|
||||
{
|
||||
// We use some static data here to avoid re allocating the same variable in a loop.
|
||||
// this func is primarily called by GFont::loadCharInfo(),
|
||||
Rect imageRect;
|
||||
CGContextRef imageCtx;
|
||||
U32 bitmapDataSize;
|
||||
ATSUTextMeasurement tbefore, tafter, tascent, tdescent;
|
||||
OSStatus err;
|
||||
|
||||
// 16 bit character buffer for the ATUSI calls.
|
||||
// -- hey... could we cache this at the class level, set style and loc *once*,
|
||||
// then just write to this buffer and clear the layout cache, to speed up drawing?
|
||||
static UniChar chUniChar[1];
|
||||
chUniChar[0] = ch;
|
||||
|
||||
// Declare and clear out the CharInfo that will be returned.
|
||||
static PlatformFont::CharInfo c;
|
||||
dMemset(&c, 0, sizeof(c));
|
||||
|
||||
// prep values for GFont::addBitmap()
|
||||
c.bitmapIndex = 0;
|
||||
c.xOffset = 0;
|
||||
c.yOffset = 0;
|
||||
|
||||
// put the text in the layout.
|
||||
// we've hardcoded a string length of 1 here, but this could work for longer strings... (hint hint)
|
||||
// note: ATSUSetTextPointerLocation() also clears the previous cached layout information.
|
||||
ATSUSetTextPointerLocation( mLayout, chUniChar, 0, 1, 1);
|
||||
ATSUSetRunStyle( mLayout, mStyle, 0,1);
|
||||
|
||||
// get the typographic bounds. this tells us how characters are placed relative to other characters.
|
||||
ATSUGetUnjustifiedBounds( mLayout, 0, 1, &tbefore, &tafter, &tascent, &tdescent);
|
||||
c.xIncrement = FixedToInt(tafter);
|
||||
|
||||
// find out how big of a bitmap we'll need.
|
||||
// as a bonus, we also get the origin where we should draw, encoded in the Rect.
|
||||
ATSUMeasureTextImage( mLayout, 0, 1, 0, 0, &imageRect);
|
||||
U32 xFudge = 2;
|
||||
U32 yFudge = 1;
|
||||
c.width = imageRect.right - imageRect.left + xFudge; // add 2 because small fonts don't always have enough room
|
||||
c.height = imageRect.bottom - imageRect.top + yFudge;
|
||||
c.xOrigin = imageRect.left; // dist x0 -> center line
|
||||
c.yOrigin = -imageRect.top; // dist y0 -> base line
|
||||
|
||||
// kick out early if the character is undrawable
|
||||
if( c.width == xFudge || c.height == yFudge)
|
||||
return c;
|
||||
|
||||
// allocate a greyscale bitmap and clear it.
|
||||
bitmapDataSize = c.width * c.height;
|
||||
c.bitmapData = new U8[bitmapDataSize];
|
||||
dMemset(c.bitmapData,0x00,bitmapDataSize);
|
||||
|
||||
// get a graphics context on the bitmap
|
||||
imageCtx = CGBitmapContextCreate( c.bitmapData, c.width, c.height, 8, c.width, mColorSpace, kCGImageAlphaNone);
|
||||
if(!imageCtx) {
|
||||
Con::errorf("Error: failed to create a graphics context on the CharInfo bitmap! Drawing a blank block.");
|
||||
c.xIncrement = c.width;
|
||||
dMemset(c.bitmapData,0x0F,bitmapDataSize);
|
||||
return c;
|
||||
}
|
||||
|
||||
// Turn off antialiasing for monospaced console fonts. yes, this is cheating.
|
||||
if(mSize < 12 && ( dStrstr(mName,"Monaco")!=NULL || dStrstr(mName,"Courier")!=NULL ))
|
||||
CGContextSetShouldAntialias(imageCtx, false);
|
||||
|
||||
// Set up drawing options for the context.
|
||||
// Since we're not going straight to the screen, we need to adjust accordingly
|
||||
CGContextSetShouldSmoothFonts(imageCtx, false);
|
||||
CGContextSetRenderingIntent(imageCtx, kCGRenderingIntentAbsoluteColorimetric);
|
||||
CGContextSetInterpolationQuality( imageCtx, kCGInterpolationNone);
|
||||
CGContextSetGrayFillColor( imageCtx, 1.0, 1.0);
|
||||
CGContextSetTextDrawingMode( imageCtx, kCGTextFill);
|
||||
|
||||
// tell ATSUI to substitute fonts as needed for missing glyphs
|
||||
ATSUSetTransientFontMatching(mLayout, true);
|
||||
|
||||
// set up three parrallel arrays for setting up attributes.
|
||||
// this is how most options in ATSUI are set, by passing arrays of options.
|
||||
ATSUAttributeTag theTags[] = { kATSUCGContextTag };
|
||||
ByteCount theSizes[] = { sizeof(CGContextRef) };
|
||||
ATSUAttributeValuePtr theValues[] = { &imageCtx };
|
||||
|
||||
// bind the layout to the context.
|
||||
ATSUSetLayoutControls( mLayout, 1, theTags, theSizes, theValues );
|
||||
|
||||
// Draw the character!
|
||||
int yoff = c.height < 3 ? 1 : 0; // kludge for 1 pixel high characters, such as '-' and '_'
|
||||
int xoff = 1;
|
||||
err = ATSUDrawText( mLayout, 0, 1, IntToFixed(-imageRect.left + xoff), IntToFixed(imageRect.bottom + yoff ) );
|
||||
CGContextRelease(imageCtx);
|
||||
|
||||
if(err != noErr) {
|
||||
Con::errorf("Error: could not draw the character! Drawing a blank box.");
|
||||
dMemset(c.bitmapData,0x0F,bitmapDataSize);
|
||||
}
|
||||
|
||||
|
||||
#if TORQUE_DEBUG
|
||||
// Con::printf("Font Metrics: Rect = %2i %2i %2i %2i Char= %C, 0x%x Size= %i, Baseline= %i, Height= %i",imageRect.top, imageRect.bottom, imageRect.left, imageRect.right,ch,ch, mSize,mBaseline, mHeight);
|
||||
// Con::printf("Font Bounds: left= %2i right= %2i Char= %C, 0x%x Size= %i",FixedToInt(tbefore), FixedToInt(tafter), ch,ch, mSize);
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The following code snippet demonstrates how to get the elusive GlyphIDs,
|
||||
// which are needed when you want to do various complex and arcane things
|
||||
// with ATSUI and CoreGraphics.
|
||||
//
|
||||
// ATSUGlyphInfoArray glyphinfoArr;
|
||||
// ATSUGetGlyphInfo( mLayout, kATSUFromTextBeginning, kATSUToTextEnd,sizeof(ATSUGlyphInfoArray), &glyphinfoArr);
|
||||
// ATSUGlyphInfo glyphinfo = glyphinfoArr.glyphs[0];
|
||||
// Con::printf(" Glyphinfo: screenX= %i, idealX=%f, deltaY=%f", glyphinfo.screenX, glyphinfo.idealX, glyphinfo.deltaY);
|
57
engine/platformMacCarb/macCarbFont.h
Executable file
57
engine/platformMacCarb/macCarbFont.h
Executable file
@ -0,0 +1,57 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include "platform/platformFont.h"
|
||||
|
||||
|
||||
class MacCarbFont : public PlatformFont
|
||||
{
|
||||
private:
|
||||
// Caches style, layout and colorspace data to speed up character drawing.
|
||||
// TODO: style colors
|
||||
ATSUStyle mStyle;
|
||||
ATSUTextLayout mLayout;
|
||||
CGColorSpaceRef mColorSpace;
|
||||
|
||||
// Cache the baseline and height for the getter methods below.
|
||||
U32 mHeight; // distance between lines
|
||||
U32 mBaseline; // distance from drawing point to typographic baseline,
|
||||
// think of the drawing point as the upper left corner of a text box.
|
||||
// note: 'baseline' is synonymous with 'ascent' in Torque.
|
||||
|
||||
// Cache the size and name requested in create()
|
||||
U32 mSize;
|
||||
StringTableEntry mName;
|
||||
|
||||
public:
|
||||
MacCarbFont();
|
||||
virtual ~MacCarbFont();
|
||||
|
||||
/// Look up the requested font, cache style, layout, colorspace, and some metrics.
|
||||
virtual bool create( const char* name, U32 size, U32 charset = TGE_ANSI_CHARSET);
|
||||
|
||||
/// Determine if the character requested is a drawable character, or if it should be ignored.
|
||||
virtual bool isValidChar( const UTF16 ch) const;
|
||||
virtual bool isValidChar( const UTF8 *str) const;
|
||||
|
||||
/// Get some vertical data on the font at large. Useful for drawing multiline text, and sizing text boxes.
|
||||
virtual U32 getFontHeight() const;
|
||||
virtual U32 getFontBaseLine() const;
|
||||
|
||||
// Draw the character to a temporary bitmap, and fill the CharInfo with various text metrics.
|
||||
virtual PlatformFont::CharInfo &getCharInfo(const UTF16 ch) const;
|
||||
virtual PlatformFont::CharInfo &getCharInfo(const UTF8 *str) const;
|
||||
};
|
||||
|
||||
inline U32 MacCarbFont::getFontHeight() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
inline U32 MacCarbFont::getFontBaseLine() const
|
||||
{
|
||||
return mBaseline;
|
||||
}
|
BIN
engine/platformMacCarb/macCarbGG.icns
Executable file
BIN
engine/platformMacCarb/macCarbGG.icns
Executable file
Binary file not shown.
297
engine/platformMacCarb/macCarbGL.cc
Executable file
297
engine/platformMacCarb/macCarbGL.cc
Executable file
@ -0,0 +1,297 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Many OSX frameworks include OpenTransport, and OT's new operator conflicts
|
||||
// with our redefinition of 'new', so we have to pre-include platformMacCarb.h,
|
||||
// which contains the workaround.
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platformMacCarb/platformGL.h"
|
||||
#include "platformMacCarb/macCarbUtil.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
GLState gGLState;
|
||||
|
||||
bool gOpenGLDisablePT = false;
|
||||
bool gOpenGLDisableCVA = false;
|
||||
bool gOpenGLDisableTEC = false;
|
||||
bool gOpenGLDisableARBMT = false;
|
||||
bool gOpenGLDisableFC = true; //false;
|
||||
bool gOpenGLDisableTCompress = false;
|
||||
bool gOpenGLNoEnvColor = false;
|
||||
float gOpenGLGammaCorrection = 0.5;
|
||||
bool gOpenGLNoDrawArraysAlpha = false;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// These stubs are legacy stuff for the d3d wrapper layer.
|
||||
// The code that requires these stubs should probably be ifdef'd out of any non w32 build
|
||||
//-----------------------------------------------------------------------------
|
||||
GLboolean glAvailableVertexBufferEXT() { return(false); }
|
||||
GLint glAllocateVertexBufferEXT(GLsizei size, GLint format, GLboolean preserve) { return(0); }
|
||||
void* glLockVertexBufferEXT(GLint handle, GLsizei size) { return(NULL); }
|
||||
void glUnlockVertexBufferEXT(GLint handle) {}
|
||||
void glSetVertexBufferEXT(GLint handle) {}
|
||||
void glOffsetVertexBufferEXT(GLint handle, GLuint offset) {}
|
||||
void glFillVertexBufferEXT(GLint handle, GLint first, GLsizei count) {}
|
||||
void glFreeVertexBufferEXT(GLint handle) {}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// helper function for getGLCapabilities.
|
||||
// returns a new CGL context for platState.hDisplay
|
||||
CGLContextObj getContextForCapsCheck()
|
||||
{
|
||||
// silently create an opengl context on the current display, so that
|
||||
// we can get valid renderer and capability info
|
||||
// some of the following code is from:
|
||||
// http://developer.apple.com/technotes/tn2002/tn2080.html#TAN55
|
||||
|
||||
// From the CG display id, we can create a pixel format & context
|
||||
// and with that context we can check opengl capabilities
|
||||
CGOpenGLDisplayMask cglDisplayMask = CGDisplayIDToOpenGLDisplayMask(platState.cgDisplay);
|
||||
CGLPixelFormatAttribute attribs[] = {kCGLPFADisplayMask, (CGLPixelFormatAttribute)cglDisplayMask, (CGLPixelFormatAttribute) NULL};
|
||||
|
||||
// create the pixel format. we will not use numPixelFormats, but the docs
|
||||
// do not say we're allowed to pass NULL for the 3rd arg.
|
||||
long numPixelFormats = 0;
|
||||
CGLPixelFormatObj pixelFormat = NULL;
|
||||
CGLChoosePixelFormat(attribs, &pixelFormat, &numPixelFormats);
|
||||
|
||||
if(pixelFormat)
|
||||
{
|
||||
// create a context. we don't need the pixel format once the context is created.
|
||||
CGLContextObj ctx;
|
||||
CGLCreateContext( pixelFormat, NULL, &ctx );
|
||||
CGLDestroyPixelFormat( pixelFormat );
|
||||
|
||||
if(ctx)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// if we can't get a good context, we can't check caps... this won't be good.
|
||||
Con::errorf("I could not create a cgl context on the display for gl capabilities checking!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find out which extensions are available for this renderer.
|
||||
void getGLCapabilities( )
|
||||
{
|
||||
OSStatus err = 0;
|
||||
|
||||
AssertFatal(platState.cgDisplay, "getGLCapabilities() was called before a monitor was chosen!");
|
||||
|
||||
// silently create an opengl context on the current display,
|
||||
// so that we can get valid renderer and capability info.
|
||||
// we save off the current context so that we can silently restore it.
|
||||
// the user should not be aware of this little shuffle.
|
||||
CGLContextObj curr_ctx = CGLGetCurrentContext ();
|
||||
CGLContextObj temp_ctx = getContextForCapsCheck();
|
||||
|
||||
if(!temp_ctx)
|
||||
{
|
||||
Con::errorf("OpenGL may not be set up correctly!");
|
||||
return;
|
||||
}
|
||||
|
||||
CGLSetCurrentContext(temp_ctx);
|
||||
|
||||
// Get the OpenGL info strings we'll need
|
||||
const char* pVendString = (const char*) glGetString( GL_VENDOR );
|
||||
const char* pRendString = (const char*) glGetString( GL_RENDERER );
|
||||
const char* pVersString = (const char*) glGetString( GL_VERSION );
|
||||
const char* pExtString = (const char*) glGetString( GL_EXTENSIONS );
|
||||
|
||||
// Output some driver info to the console:
|
||||
Con::printf( "OpenGL driver information:" );
|
||||
if ( pVendString )
|
||||
Con::printf( " Vendor: %s", pVendString );
|
||||
if ( pRendString )
|
||||
Con::printf( " Renderer: %s", pRendString );
|
||||
if ( pVersString )
|
||||
Con::printf( " Version: %s", pVersString );
|
||||
|
||||
// pre-clear the structure
|
||||
dMemset(&gGLState, 0, sizeof(gGLState));
|
||||
|
||||
if(pExtString)
|
||||
{
|
||||
// EXT_paletted_texture ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_EXT_paletted_texture") != NULL)
|
||||
gGLState.suppPalettedTexture = true;
|
||||
|
||||
// EXT_compiled_vertex_array ========================================
|
||||
gGLState.suppLockedArrays = false;
|
||||
if (dStrstr(pExtString, (const char*)"GL_EXT_compiled_vertex_array") != NULL)
|
||||
gGLState.suppLockedArrays = true;
|
||||
|
||||
// ARB_multitexture ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_ARB_multitexture") != NULL)
|
||||
gGLState.suppARBMultitexture = true;
|
||||
|
||||
// EXT_blend_color
|
||||
if(dStrstr(pExtString, (const char*)"GL_EXT_blend_color") != NULL)
|
||||
gGLState.suppEXTblendcolor = true;
|
||||
|
||||
// EXT_blend_minmax
|
||||
if(dStrstr(pExtString, (const char*)"GL_EXT_blend_minmax") != NULL)
|
||||
gGLState.suppEXTblendminmax = true;
|
||||
|
||||
// NV_vertex_array_range ========================================
|
||||
// does not appear to be supported by apple, at all. ( as of 10.4.3 )
|
||||
// GL_APPLE_vertex_array_range is similar, and may be nearly identical.
|
||||
if (dStrstr(pExtString, (const char*)"GL_NV_vertex_array_range") != NULL)
|
||||
gGLState.suppVertexArrayRange = true;
|
||||
|
||||
|
||||
// EXT_fog_coord ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_EXT_fog_coord") != NULL)
|
||||
gGLState.suppFogCoord = true;
|
||||
|
||||
// ARB_texture_compression ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_ARB_texture_compression") != NULL)
|
||||
gGLState.suppTextureCompression = true;
|
||||
|
||||
// 3DFX_texture_compression_FXT1 ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_3DFX_texture_compression_FXT1") != NULL)
|
||||
gGLState.suppFXT1 = true;
|
||||
|
||||
// EXT_texture_compression_S3TC ========================================
|
||||
if (dStrstr(pExtString, (const char*)"GL_EXT_texture_compression_s3tc") != NULL)
|
||||
gGLState.suppS3TC = true;
|
||||
|
||||
// EXT_vertex_buffer ========================================
|
||||
// This extension is deprecated, and not supported by Apple. ( 10.4.3 )
|
||||
// Instead, the ARB Vertex Buffer extension is supported.
|
||||
// The new extension has a different API, so TGE should be updated to use it.
|
||||
if (dStrstr(pExtString, (const char*)"GL_EXT_vertex_buffer") != NULL)
|
||||
gGLState.suppVertexBuffer = true;
|
||||
|
||||
// Anisotropic filtering ========================================
|
||||
gGLState.suppTexAnisotropic = (dStrstr(pExtString, (const char*)"GL_EXT_texture_filter_anisotropic") != NULL);
|
||||
if (gGLState.suppTexAnisotropic)
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGLState.maxAnisotropy);
|
||||
|
||||
// Binary states, i.e., no supporting functions ========================================
|
||||
// NOTE:
|
||||
// Some of these have multiple representations, via EXT and|or ARB and|or NV and|or SGIS ... etc.
|
||||
// Check all relative versions.
|
||||
|
||||
gGLState.suppPackedPixels = (dStrstr(pExtString, (const char*)"GL_EXT_packed_pixels") != NULL);
|
||||
gGLState.suppPackedPixels |= (dStrstr(pExtString, (const char*)"GL_APPLE_packed_pixel") != NULL);
|
||||
|
||||
gGLState.suppTextureEnvCombine = (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_combine") != NULL);
|
||||
gGLState.suppTextureEnvCombine|= (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_combine") != NULL);
|
||||
|
||||
gGLState.suppEdgeClamp = (dStrstr(pExtString, (const char*)"GL_EXT_texture_edge_clamp") != NULL);
|
||||
gGLState.suppEdgeClamp |= (dStrstr(pExtString, (const char*)"GL_SGIS_texture_edge_clamp") != NULL);
|
||||
gGLState.suppEdgeClamp |= (dStrstr(pExtString, (const char*)"GL_ARB_texture_border_clamp") != NULL);
|
||||
|
||||
gGLState.suppTexEnvAdd = (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_add") != NULL);
|
||||
gGLState.suppTexEnvAdd |= (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_add") != NULL);
|
||||
|
||||
}
|
||||
|
||||
// Texture combine units ========================================
|
||||
if (gGLState.suppARBMultitexture)
|
||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gGLState.maxTextureUnits);
|
||||
else
|
||||
gGLState.maxTextureUnits = 1;
|
||||
|
||||
// Swap interval ========================================
|
||||
// Mac inherently supports a swap interval via AGL-set-integer.
|
||||
gGLState.suppSwapInterval = true;
|
||||
|
||||
// FSAA support, TODO: check for ARB multisample support
|
||||
// multisample support should be checked via CGL
|
||||
gGLState.maxFSAASamples = 4;
|
||||
|
||||
// dump found extensions to the console...
|
||||
Con::printf("OpenGL Init: Enabled Extensions");
|
||||
if (gGLState.suppARBMultitexture) Con::printf(" ARB_multitexture (Max Texture Units: %d)", gGLState.maxTextureUnits);
|
||||
if (gGLState.suppEXTblendcolor) Con::printf(" EXT_blend_color");
|
||||
if (gGLState.suppEXTblendminmax) Con::printf(" EXT_blend_minmax");
|
||||
if (gGLState.suppPalettedTexture) Con::printf(" EXT_paletted_texture");
|
||||
if (gGLState.suppLockedArrays) Con::printf(" EXT_compiled_vertex_array");
|
||||
if (gGLState.suppVertexArrayRange) Con::printf(" NV_vertex_array_range");
|
||||
if (gGLState.suppTextureEnvCombine) Con::printf(" EXT_texture_env_combine");
|
||||
if (gGLState.suppPackedPixels) Con::printf(" EXT_packed_pixels");
|
||||
if (gGLState.suppFogCoord) Con::printf(" EXT_fog_coord");
|
||||
if (gGLState.suppTextureCompression) Con::printf(" ARB_texture_compression");
|
||||
if (gGLState.suppS3TC) Con::printf(" EXT_texture_compression_s3tc");
|
||||
if (gGLState.suppFXT1) Con::printf(" 3DFX_texture_compression_FXT1");
|
||||
if (gGLState.suppTexEnvAdd) Con::printf(" (ARB|EXT)_texture_env_add");
|
||||
if (gGLState.suppTexAnisotropic) Con::printf(" EXT_texture_filter_anisotropic (Max anisotropy: %f)", gGLState.maxAnisotropy);
|
||||
if (gGLState.suppSwapInterval) Con::printf(" Vertical Sync");
|
||||
if (gGLState.maxFSAASamples) Con::printf(" ATI_FSAA");
|
||||
|
||||
Con::warnf("OpenGL Init: Disabled Extensions");
|
||||
if (!gGLState.suppARBMultitexture) Con::warnf(" ARB_multitexture");
|
||||
if (!gGLState.suppEXTblendcolor) Con::warnf(" EXT_blend_color");
|
||||
if (!gGLState.suppEXTblendminmax) Con::warnf(" EXT_blend_minmax");
|
||||
if (!gGLState.suppPalettedTexture) Con::warnf(" EXT_paletted_texture");
|
||||
if (!gGLState.suppLockedArrays) Con::warnf(" EXT_compiled_vertex_array");
|
||||
if (!gGLState.suppVertexArrayRange) Con::warnf(" NV_vertex_array_range");
|
||||
if (!gGLState.suppTextureEnvCombine) Con::warnf(" EXT_texture_env_combine");
|
||||
if (!gGLState.suppPackedPixels) Con::warnf(" EXT_packed_pixels");
|
||||
if (!gGLState.suppFogCoord) Con::warnf(" EXT_fog_coord");
|
||||
if (!gGLState.suppTextureCompression) Con::warnf(" ARB_texture_compression");
|
||||
if (!gGLState.suppS3TC) Con::warnf(" EXT_texture_compression_s3tc");
|
||||
if (!gGLState.suppFXT1) Con::warnf(" 3DFX_texture_compression_FXT1");
|
||||
if (!gGLState.suppTexEnvAdd) Con::warnf(" (ARB|EXT)_texture_env_add");
|
||||
if (!gGLState.suppTexAnisotropic) Con::warnf(" EXT_texture_filter_anisotropic");
|
||||
if (!gGLState.suppSwapInterval) Con::warnf(" Vertical Sync");
|
||||
if (!gGLState.maxFSAASamples) Con::warnf(" ATI_FSAA");
|
||||
Con::printf("");
|
||||
|
||||
// Set some console variables:
|
||||
Con::setBoolVariable( "$FogCoordSupported", gGLState.suppFogCoord );
|
||||
Con::setBoolVariable( "$TextureCompressionSupported", gGLState.suppTextureCompression );
|
||||
Con::setBoolVariable( "$AnisotropySupported", gGLState.suppTexAnisotropic );
|
||||
Con::setBoolVariable( "$PalettedTextureSupported", gGLState.suppPalettedTexture );
|
||||
Con::setBoolVariable( "$SwapIntervalSupported", gGLState.suppSwapInterval );
|
||||
|
||||
if (!gGLState.suppPalettedTexture && Con::getBoolVariable("$pref::OpenGL::forcePalettedTexture",false))
|
||||
{
|
||||
Con::setBoolVariable("$pref::OpenGL::forcePalettedTexture", false);
|
||||
Con::setBoolVariable("$pref::OpenGL::force16BitTexture", true);
|
||||
}
|
||||
|
||||
// get fsaa samples. default to normal, no antialiasing
|
||||
// TODO: clamp this against ARB_multisample capabilities.
|
||||
gFSAASamples = Con::getIntVariable("$pref::OpenGL::numFSAASamples", 1);
|
||||
|
||||
// done. silently restore the old cgl context.
|
||||
CGLSetCurrentContext(curr_ctx);
|
||||
CGLDestroyContext(temp_ctx);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Change FSAA level.
|
||||
/// Currently, this will only work for ATI Radeon chipsets.
|
||||
/// On other chipsets, this has no effect.
|
||||
/// Pass in 1 for normal/no-AA, 2 for 2x-AA, 4 for 4x-AA.
|
||||
//-----------------------------------------------------------------------------
|
||||
void dglSetFSAASamples(GLint aasamp)
|
||||
{
|
||||
if (gGLState.maxFSAASamples<2) return;
|
||||
|
||||
// fix out of range values
|
||||
if (aasamp<1) aasamp = 1;
|
||||
else
|
||||
if (aasamp==3) aasamp = 2;
|
||||
else
|
||||
if (aasamp>4) aasamp = 4;
|
||||
|
||||
aglSetInteger(platState.ctx, ATI_FSAA_LEVEL, (const long*)&aasamp);
|
||||
|
||||
Con::printf(">>Number of FSAA samples is now [%d].", aasamp);
|
||||
Con::setIntVariable("$pref::OpenGL::numFSAASamples", aasamp);
|
||||
|
||||
// Apperantly, we used to apply some Bling for tradeshows.
|
||||
// it might be fun to reimplement this.
|
||||
if (Con::getIntVariable("$pref::TradeshowDemo", 0))
|
||||
Con::executef(2, "setFSAABadge", aasamp>1?"true":"false");
|
||||
}
|
920
engine/platformMacCarb/macCarbInput.cc
Executable file
920
engine/platformMacCarb/macCarbInput.cc
Executable file
@ -0,0 +1,920 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platformInput.h"
|
||||
#include "platform/event.h"
|
||||
#include "console/console.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "core/unicode.h"
|
||||
|
||||
// headers for clipboard access
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
|
||||
// Static class variables:
|
||||
InputManager* Input::smManager;
|
||||
bool Input::smActive;
|
||||
|
||||
bool gInputEnabled = false;
|
||||
bool gMouseEnabled = false;
|
||||
bool gKBEnabled = false;
|
||||
bool gMouseActive = false;
|
||||
bool gKBActive = false;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions. Should migrate to an InputManager object at some point.
|
||||
bool enableKeyboard(void);
|
||||
void disableKeyboard(void);
|
||||
bool activateKeyboard(void);
|
||||
void deactivateKeyboard(void);
|
||||
bool enableMouse(void);
|
||||
void disableMouse(void);
|
||||
bool activateMouse(void);
|
||||
void deactivateMouse(void);
|
||||
|
||||
|
||||
|
||||
static void fillAsciiTable();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// This function gets the standard ASCII code corresponding to our key code
|
||||
// and the existing modifier key state.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
struct AsciiData
|
||||
{
|
||||
struct KeyData
|
||||
{
|
||||
U16 ascii;
|
||||
bool isDeadChar;
|
||||
};
|
||||
|
||||
KeyData upper;
|
||||
KeyData lower;
|
||||
KeyData goofy;
|
||||
};
|
||||
|
||||
|
||||
#define NUM_KEYS ( KEY_OEM_102 + 1 )
|
||||
#define KEY_FIRST KEY_ESCAPE
|
||||
static AsciiData AsciiTable[NUM_KEYS];
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void Input::init()
|
||||
{
|
||||
OSStatus status = noErr;
|
||||
|
||||
Con::printf( "Input Init:" );
|
||||
destroy();
|
||||
|
||||
smManager = NULL;
|
||||
smActive = false;
|
||||
|
||||
// set up the object that tells the system we want unicode input
|
||||
InterfaceTypeList tsmDocTypeList = { kUnicodeDocument };
|
||||
NewTSMDocument( 1, tsmDocTypeList, &platState.tsmDoc, NULL);
|
||||
UseInputWindow( platState.tsmDoc, true);
|
||||
|
||||
// stop the double-cursor thing
|
||||
Con::setBoolVariable("$pref::Gui::noClampTorqueCursorToWindow", true);
|
||||
|
||||
// enable main input
|
||||
Input::enable();
|
||||
|
||||
|
||||
|
||||
Con::printf( "" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( isJoystickDetected, bool, 1, 1, "Always false on the MAC." )
|
||||
{
|
||||
/*
|
||||
argc; argv;
|
||||
return( DInputDevice::joystickDetected() );
|
||||
*/
|
||||
return(false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( getJoystickAxes, const char*, 2, 2, "(handle instance)" )
|
||||
{
|
||||
|
||||
return( "" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void fillAsciiTable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
U16 Input::getKeyCode( U16 asciiCode )
|
||||
{
|
||||
U16 keyCode = 0;
|
||||
U16 i;
|
||||
|
||||
// This is done three times so the lowerkey will always
|
||||
// be found first. Some foreign keyboards have duplicate
|
||||
// chars on some keys.
|
||||
for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
|
||||
{
|
||||
if ( AsciiTable[i].lower.ascii == asciiCode )
|
||||
{
|
||||
keyCode = i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
|
||||
{
|
||||
if ( AsciiTable[i].upper.ascii == asciiCode )
|
||||
{
|
||||
keyCode = i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
|
||||
{
|
||||
if ( AsciiTable[i].goofy.ascii == asciiCode )
|
||||
{
|
||||
keyCode = i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return( keyCode );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
U16 Input::getAscii( U16 keyCode, KEY_STATE keyState )
|
||||
{
|
||||
if ( keyCode >= NUM_KEYS )
|
||||
return 0;
|
||||
|
||||
switch ( keyState )
|
||||
{
|
||||
case STATE_LOWER:
|
||||
return AsciiTable[keyCode].lower.ascii;
|
||||
case STATE_UPPER:
|
||||
return AsciiTable[keyCode].upper.ascii;
|
||||
case STATE_GOOFY:
|
||||
return AsciiTable[keyCode].goofy.ascii;
|
||||
default:
|
||||
return(0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::destroy()
|
||||
{
|
||||
#ifdef LOG_INPUT
|
||||
if ( gInputLog )
|
||||
{
|
||||
log( "*** CLOSING LOG ***\n" );
|
||||
CloseHandle( gInputLog );
|
||||
gInputLog = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// turn us off.
|
||||
if (gInputEnabled)
|
||||
disable();
|
||||
|
||||
/*
|
||||
if ( smManager && smManager->isEnabled() )
|
||||
{
|
||||
smManager->disable();
|
||||
delete smManager;
|
||||
smManager = NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Input::enable()
|
||||
{
|
||||
//Con::printf( "[]Input::enable." );
|
||||
|
||||
gInputEnabled = true;
|
||||
|
||||
// if ( smManager && !smManager->isEnabled() )
|
||||
// return( smManager->enable() );
|
||||
|
||||
enableMouse();
|
||||
//enableKeyboard();
|
||||
|
||||
return( gInputEnabled );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::disable()
|
||||
{
|
||||
//Con::printf( "[]Input::disable." );
|
||||
|
||||
gInputEnabled = false;
|
||||
|
||||
// if ( smManager && smManager->isEnabled() )
|
||||
// smManager->disable();
|
||||
|
||||
disableMouse();
|
||||
//disableKeyboard();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::activate()
|
||||
{
|
||||
smActive = true;
|
||||
|
||||
enableMouse();
|
||||
// enableKeyboard();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::deactivate()
|
||||
{
|
||||
//Con::printf( "[]Input::deactivate." );
|
||||
|
||||
deactivateMouse();
|
||||
//deactivateKeyboard();
|
||||
|
||||
smActive = false;
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::reactivate()
|
||||
{
|
||||
// don't think mac needs to do anything right now!!!!!! TBD
|
||||
|
||||
// This is soo hacky...
|
||||
// SetForegroundWindow( winState.appWindow );
|
||||
// PostMessage( winState.appWindow, WM_ACTIVATE, WA_ACTIVE, NULL );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Input::isEnabled()
|
||||
{
|
||||
// if ( smManager )
|
||||
// return smManager->isEnabled();
|
||||
|
||||
return(gInputEnabled);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Input::isActive()
|
||||
{
|
||||
return smActive;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::process()
|
||||
{
|
||||
if (!smActive || !gInputEnabled)
|
||||
return;
|
||||
|
||||
if (!gMouseEnabled || !gMouseActive)
|
||||
return;
|
||||
|
||||
|
||||
// if ( smManager && smManager->isEnabled() && smActive )
|
||||
// smManager->process();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
InputManager* Input::getManager()
|
||||
{
|
||||
return( smManager );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#pragma message("input remap table might need tweaking - rumors of ibooks having diff virt keycodes, might need intermediate remap...")
|
||||
static U8 VcodeRemap[256] =
|
||||
{
|
||||
KEY_A, // 0x00
|
||||
KEY_S, // 0x01
|
||||
KEY_D, // 0x02
|
||||
KEY_F, // 0x03
|
||||
KEY_H, // 0x04
|
||||
KEY_G, // 0x05
|
||||
KEY_Z, // 0x06
|
||||
KEY_X, // 0x07
|
||||
KEY_C, // 0x08
|
||||
KEY_V, // 0x09
|
||||
KEY_Y, // 0x0A // this is questionable - not normal Y code
|
||||
KEY_B, // 0x0B
|
||||
KEY_Q, // 0x0C
|
||||
KEY_W, // 0x0D
|
||||
KEY_E, // 0x0E
|
||||
KEY_R, // 0x0F
|
||||
KEY_Y, // 0x10
|
||||
KEY_T, // 0x11
|
||||
KEY_1, // 0x12
|
||||
KEY_2, // 0x13
|
||||
KEY_3, // 0x14
|
||||
KEY_4, // 0x15
|
||||
KEY_6, // 0x16
|
||||
KEY_5, // 0x17
|
||||
KEY_EQUALS, // 0x18
|
||||
KEY_9, // 0x19
|
||||
KEY_7, // 0x1A
|
||||
KEY_MINUS, // 0x1B
|
||||
KEY_8, // 0x1C
|
||||
KEY_0, // 0x1D
|
||||
KEY_RBRACKET, // 0x1E
|
||||
KEY_O, // 0x1F
|
||||
KEY_U, // 0x20
|
||||
KEY_LBRACKET, // 0x21
|
||||
KEY_I, // 0x22
|
||||
KEY_P, // 0x23
|
||||
KEY_RETURN, // 0x24
|
||||
KEY_L, // 0x25
|
||||
KEY_J, // 0x26
|
||||
KEY_APOSTROPHE, // 0x27
|
||||
KEY_K, // 0x28
|
||||
KEY_SEMICOLON, // 0x29
|
||||
KEY_BACKSLASH, // 0x2A
|
||||
KEY_COMMA, // 0x2B
|
||||
KEY_SLASH, // 0x2C
|
||||
KEY_N, // 0x2D
|
||||
KEY_M, // 0x2E
|
||||
KEY_PERIOD, // 0x2F
|
||||
KEY_TAB, // 0x30
|
||||
KEY_SPACE, // 0x31
|
||||
KEY_TILDE, // 0x32
|
||||
KEY_BACKSPACE, // 0x33
|
||||
0, // 0x34 //?
|
||||
KEY_ESCAPE, // 0x35
|
||||
0, // 0x36 //?
|
||||
KEY_ALT, // 0x37 // best mapping for mac Cmd key
|
||||
KEY_LSHIFT, // 0x38
|
||||
KEY_CAPSLOCK, // 0x39
|
||||
KEY_MAC_OPT, // 0x3A // direct map mac Option key -- better than KEY_WIN_WINDOWS
|
||||
KEY_CONTROL, // 0x3B
|
||||
KEY_RSHIFT, // 0x3C
|
||||
0, // 0x3D
|
||||
0, // 0x3E
|
||||
0, // 0x3F
|
||||
0, // 0x40
|
||||
KEY_DECIMAL, // 0x41
|
||||
0, // 0x42
|
||||
KEY_MULTIPLY, // 0x43
|
||||
0, // 0x44
|
||||
KEY_ADD, // 0x45
|
||||
KEY_SUBTRACT, // 0x46 // secondary code?
|
||||
KEY_NUMLOCK, // 0x47 // also known as Clear on mac...
|
||||
KEY_SEPARATOR, // 0x48 // secondary code? for KPEqual
|
||||
0, // 0x49
|
||||
0, // 0x4A
|
||||
KEY_DIVIDE, // 0x4B
|
||||
KEY_NUMPADENTER, // 0x4C
|
||||
KEY_DIVIDE, // 0x4D // secondary code?
|
||||
KEY_SUBTRACT, // 0x4E
|
||||
0, // 0x4F
|
||||
0, // 0x50
|
||||
KEY_SEPARATOR, // 0x51 // WHAT IS SEP? This is KPEqual on mac.
|
||||
KEY_NUMPAD0, // 0x52
|
||||
KEY_NUMPAD1, // 0x53
|
||||
KEY_NUMPAD2, // 0x54
|
||||
KEY_NUMPAD3, // 0x55
|
||||
KEY_NUMPAD4, // 0x56
|
||||
KEY_NUMPAD5, // 0x57
|
||||
KEY_NUMPAD6, // 0x58
|
||||
KEY_NUMPAD7, // 0x59
|
||||
0, // 0x5A
|
||||
KEY_NUMPAD8, // 0x5B
|
||||
KEY_NUMPAD9, // 0x5C
|
||||
0, // 0x5D
|
||||
0, // 0x5E
|
||||
0, // 0x5F
|
||||
KEY_F5, // 0x60
|
||||
KEY_F6, // 0x61
|
||||
KEY_F7, // 0x62
|
||||
KEY_F3, // 0x63
|
||||
KEY_F8, // 0x64
|
||||
KEY_F9, // 0x65
|
||||
0, // 0x66
|
||||
KEY_F11, // 0x67
|
||||
0, // 0x68
|
||||
KEY_PRINT, // 0x69
|
||||
0, // 0x6A
|
||||
KEY_SCROLLLOCK, // 0x6B
|
||||
0, // 0x6C
|
||||
KEY_F10, // 0x6D
|
||||
0, // 0x6E
|
||||
KEY_F12, // 0x6F
|
||||
0, // 0x70
|
||||
KEY_PAUSE, // 0x71
|
||||
KEY_INSERT, // 0x72 // also known as mac Help
|
||||
KEY_HOME, // 0x73
|
||||
KEY_PAGE_UP, // 0x74
|
||||
KEY_DELETE, // 0x75 // FwdDel
|
||||
KEY_F4, // 0x76
|
||||
KEY_END, // 0x77
|
||||
KEY_F2, // 0x78
|
||||
KEY_PAGE_DOWN, // 0x79
|
||||
KEY_F1, // 0x7A
|
||||
KEY_LEFT, // 0x7B
|
||||
KEY_RIGHT, // 0x7C
|
||||
KEY_DOWN, // 0x7D
|
||||
KEY_UP, // 0x7E
|
||||
0, // 0x7F
|
||||
0, // 0x80
|
||||
0, // 0x81
|
||||
0, // 0x82
|
||||
0, // 0x83
|
||||
0, // 0x84
|
||||
0, // 0x85
|
||||
0, // 0x86
|
||||
0, // 0x87
|
||||
0, // 0x88
|
||||
0, // 0x89
|
||||
0, // 0x8A
|
||||
0, // 0x8B
|
||||
0, // 0x8C
|
||||
0, // 0x8D
|
||||
0, // 0x8E
|
||||
0, // 0x8F
|
||||
|
||||
0, // 0x90
|
||||
0, // 0x91
|
||||
0, // 0x92
|
||||
0, // 0x93
|
||||
0, // 0x94
|
||||
0, // 0x95
|
||||
0, // 0x96
|
||||
0, // 0x97
|
||||
0, // 0x98
|
||||
0, // 0x99
|
||||
0, // 0x9A
|
||||
0, // 0x9B
|
||||
0, // 0x9C
|
||||
0, // 0x9D
|
||||
0, // 0x9E
|
||||
0, // 0x9F
|
||||
|
||||
0, // 0xA0
|
||||
0, // 0xA1
|
||||
0, // 0xA2
|
||||
0, // 0xA3
|
||||
0, // 0xA4
|
||||
0, // 0xA5
|
||||
0, // 0xA6
|
||||
0, // 0xA7
|
||||
0, // 0xA8
|
||||
0, // 0xA9
|
||||
0, // 0xAA
|
||||
0, // 0xAB
|
||||
0, // 0xAC
|
||||
0, // 0xAD
|
||||
0, // 0xAE
|
||||
0, // 0xAF
|
||||
0, // 0xB0
|
||||
0, // 0xB1
|
||||
0, // 0xB2
|
||||
0, // 0xB3
|
||||
0, // 0xB4
|
||||
0, // 0xB5
|
||||
0, // 0xB6
|
||||
0, // 0xB7
|
||||
0, // 0xB8
|
||||
0, // 0xB9
|
||||
0, // 0xBA
|
||||
0, // 0xBB
|
||||
0, // 0xBC
|
||||
0, // 0xBD
|
||||
0, // 0xBE
|
||||
0, // 0xBF
|
||||
0, // 0xC0
|
||||
0, // 0xC1
|
||||
0, // 0xC2
|
||||
0, // 0xC3
|
||||
0, // 0xC4
|
||||
0, // 0xC5
|
||||
0, // 0xC6
|
||||
0, // 0xC7
|
||||
0, // 0xC8
|
||||
0, // 0xC9
|
||||
0, // 0xCA
|
||||
0, // 0xCB
|
||||
0, // 0xCC
|
||||
0, // 0xCD
|
||||
0, // 0xCE
|
||||
0, // 0xCF
|
||||
0, // 0xD0
|
||||
0, // 0xD1
|
||||
0, // 0xD2
|
||||
0, // 0xD3
|
||||
0, // 0xD4
|
||||
0, // 0xD5
|
||||
0, // 0xD6
|
||||
0, // 0xD7
|
||||
0, // 0xD8
|
||||
0, // 0xD9
|
||||
0, // 0xDA
|
||||
0, // 0xDB
|
||||
0, // 0xDC
|
||||
0, // 0xDD
|
||||
0, // 0xDE
|
||||
0, // 0xDF
|
||||
0, // 0xE0
|
||||
0, // 0xE1
|
||||
0, // 0xE2
|
||||
0, // 0xE3
|
||||
0, // 0xE4
|
||||
|
||||
0, // 0xE5
|
||||
|
||||
0, // 0xE6
|
||||
0, // 0xE7
|
||||
0, // 0xE8
|
||||
0, // 0xE9
|
||||
0, // 0xEA
|
||||
0, // 0xEB
|
||||
0, // 0xEC
|
||||
0, // 0xED
|
||||
0, // 0xEE
|
||||
0, // 0xEF
|
||||
|
||||
0, // 0xF0
|
||||
0, // 0xF1
|
||||
0, // 0xF2
|
||||
0, // 0xF3
|
||||
0, // 0xF4
|
||||
0, // 0xF5
|
||||
|
||||
0, // 0xF6
|
||||
0, // 0xF7
|
||||
0, // 0xF8
|
||||
0, // 0xF9
|
||||
0, // 0xFA
|
||||
0, // 0xFB
|
||||
0, // 0xFC
|
||||
0, // 0xFD
|
||||
0, // 0xFE
|
||||
0 // 0xFF
|
||||
};
|
||||
|
||||
|
||||
U8 TranslateOSKeyCode(U8 vcode)
|
||||
{
|
||||
return VcodeRemap[vcode];
|
||||
}
|
||||
|
||||
#pragma mark ---- Clipboard functions ----
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* Platform::getClipboard()
|
||||
{
|
||||
// mac clipboards can contain multiple items,
|
||||
// and each item can be in several differnt flavors,
|
||||
// such as unicode or plaintext or pdf, etc.
|
||||
// scan through the clipboard, and return the 1st piece of actual text.
|
||||
ScrapRef clip;
|
||||
char *retBuf = "";
|
||||
OSStatus err = noErr;
|
||||
char *dataBuf = "";
|
||||
|
||||
// get a local ref to the system clipboard
|
||||
GetScrapByName( kScrapClipboardScrap, kScrapGetNamedScrap, &clip );
|
||||
|
||||
|
||||
// First try to get unicode data, then try to get plain text data.
|
||||
Size dataSize = 0;
|
||||
bool plaintext = false;
|
||||
err = GetScrapFlavorSize(clip, kScrapFlavorTypeUnicode, &dataSize);
|
||||
if( err != noErr || dataSize <= 0)
|
||||
{
|
||||
Con::errorf("some error getting unicode clip");
|
||||
plaintext = true;
|
||||
err = GetScrapFlavorSize(clip, kScrapFlavorTypeText, &dataSize);
|
||||
}
|
||||
|
||||
// kick out if we don't have any data.
|
||||
if( err != noErr || dataSize <= 0)
|
||||
{
|
||||
Con::errorf("no data, kicking out. size = %i",dataSize);
|
||||
return "";
|
||||
}
|
||||
|
||||
if( err == noErr && dataSize > 0 )
|
||||
{
|
||||
// ok, we've got something! allocate a buffer and copy it in.
|
||||
char buf[dataSize+1];
|
||||
dMemset(buf, 0, dataSize+1);
|
||||
dataBuf = buf;
|
||||
// plain text needs no conversion.
|
||||
// unicode data needs to be converted to normalized utf-8 format.
|
||||
if(plaintext)
|
||||
{
|
||||
GetScrapFlavorData(clip, kScrapFlavorTypeText, &dataSize, &buf);
|
||||
retBuf = Con::getReturnBuffer(dataSize + 1);
|
||||
dMemcpy(retBuf,buf,dataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetScrapFlavorData(clip, kScrapFlavorTypeUnicode, &dataSize, &buf);
|
||||
|
||||
// normalize
|
||||
CFStringRef cfBuf = CFStringCreateWithBytes(NULL, (const UInt8*)buf, dataSize, kCFStringEncodingUnicode, false);
|
||||
CFMutableStringRef normBuf = CFStringCreateMutableCopy(NULL, 0, cfBuf);
|
||||
CFStringNormalize(normBuf, kCFStringNormalizationFormC);
|
||||
|
||||
// convert to utf-8
|
||||
U32 normBufLen = CFStringGetLength(normBuf);
|
||||
U32 retBufLen = CFStringGetMaximumSizeForEncoding(normBufLen,kCFStringEncodingUTF8) + 1; // +1 for the null terminator
|
||||
retBuf = Con::getReturnBuffer(retBufLen);
|
||||
CFStringGetCString( normBuf, retBuf, retBufLen, kCFStringEncodingUTF8);
|
||||
CFStringRef newCFstring = CFStringCreateWithBytes(NULL, retBuf, dStrlen(retBuf), kCFStringEncodingUTF8, false);
|
||||
dataSize = retBufLen;
|
||||
}
|
||||
|
||||
// manually null terminate, just in case.
|
||||
retBuf[dataSize] = 0;
|
||||
}
|
||||
|
||||
// return the data, or the empty string if we did not find any data.
|
||||
return retBuf;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::setClipboard(const char *text)
|
||||
{
|
||||
ScrapRef clip;
|
||||
U32 textSize;
|
||||
OSStatus err = noErr;
|
||||
|
||||
// make sure we have something to copy
|
||||
textSize = dStrlen(text);
|
||||
if(textSize == 0)
|
||||
return false;
|
||||
|
||||
// get a local ref to the system clipboard
|
||||
GetScrapByName( kScrapClipboardScrap, kScrapClearNamedScrap, &clip );
|
||||
|
||||
// put the data on the clipboard as text
|
||||
err = PutScrapFlavor( clip, kScrapFlavorTypeText, kScrapFlavorMaskNone, textSize, text);
|
||||
|
||||
// put the data on the clipboard as unicode
|
||||
const UTF16 *utf16Data = convertUTF8toUTF16(text);
|
||||
err |= PutScrapFlavor( clip, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
|
||||
dStrlen(utf16Data) * sizeof(UTF16), utf16Data);
|
||||
delete [] utf16Data;
|
||||
|
||||
// and see if we were successful.
|
||||
if( err == noErr )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#pragma mark -
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool enableKeyboard()
|
||||
{
|
||||
if ( !gInputEnabled )
|
||||
return( false );
|
||||
|
||||
if ( gKBEnabled && gKBActive )
|
||||
return( true );
|
||||
|
||||
gKBEnabled = true;
|
||||
if ( Input::isActive() )
|
||||
gKBEnabled = activateKeyboard();
|
||||
|
||||
if ( gKBEnabled )
|
||||
{
|
||||
Con::printf( "Hardware-direct keyboard enabled." );
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Keyboard enabled.\n" );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::warnf( "Hardware-direct keyboard failed to enable!" );
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Keyboard failed to enable!\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
return( gKBEnabled );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void disableKeyboard()
|
||||
{
|
||||
if ( !gInputEnabled || !gKBEnabled )
|
||||
return;
|
||||
|
||||
deactivateKeyboard();
|
||||
gKBEnabled = false;
|
||||
|
||||
Con::printf( "Hardware-direct keyboard disabled." );
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Keyboard disabled.\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool activateKeyboard()
|
||||
{
|
||||
if ( !gInputEnabled || !Input::isActive() || !gKBEnabled )
|
||||
return( false );
|
||||
|
||||
OSStatus status = noErr;
|
||||
if (status==noErr)
|
||||
gKBActive = true;
|
||||
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( gKBActive ? "Keyboard activated.\n" : "Keyboard failed to activate!\n" );
|
||||
#endif
|
||||
return( gKBActive );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void deactivateKeyboard()
|
||||
{
|
||||
if ( gInputEnabled && gKBActive )
|
||||
{
|
||||
OSStatus status = noErr;
|
||||
gKBActive = false;
|
||||
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Keyboard deactivated.\n" );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool enableMouse()
|
||||
{
|
||||
if ( !gInputEnabled )
|
||||
return( false );
|
||||
|
||||
if ( gMouseEnabled && gMouseActive )
|
||||
return( true );
|
||||
|
||||
gMouseEnabled = activateMouse();
|
||||
|
||||
bool hwMouse = false;
|
||||
|
||||
// if (gMouseEnabled)
|
||||
// Con::printf( "%s %s", hwMouse?"Hardware-direct mouse":"Basic mouse capture", "enabled.");
|
||||
// else
|
||||
// Con::warnf( "%s %s", hwMouse?"Hardware-direct mouse":"Basic mouse capture", "failed to enable!");
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Mouse %s.\n", gMouseEnabled?"enabled":"failed to enable");
|
||||
#endif
|
||||
|
||||
return( gMouseEnabled );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void disableMouse()
|
||||
{
|
||||
if ( !gInputEnabled || !gMouseEnabled )
|
||||
return;
|
||||
|
||||
deactivateMouse();
|
||||
gMouseEnabled = false;
|
||||
|
||||
bool hwMouse = false;
|
||||
Con::printf( "%s disabled", hwMouse?"Hardware-direct mouse":"Basic mouse capture");
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Mouse disabled.\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool activateMouse()
|
||||
{
|
||||
if ( !gInputEnabled || !Input::isActive() || !gMouseEnabled )
|
||||
return( false );
|
||||
|
||||
if (gMouseActive)
|
||||
return(true);
|
||||
|
||||
gMouseActive = true;
|
||||
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( gMouseActive ? "Mouse activated.\n" : "Mouse failed to activate!\n" );
|
||||
#endif
|
||||
return( gMouseActive );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void deactivateMouse()
|
||||
{
|
||||
// Con::printf( ">> dm one. %s %s %s", gInputEnabled?"true":"false", gMouseActive?"true":"false");
|
||||
if ( !gInputEnabled || !gMouseActive ) return;
|
||||
|
||||
gMouseActive = false;
|
||||
|
||||
// Con::printf( ">> dm two." );
|
||||
|
||||
#ifdef LOG_INPUT
|
||||
Input::log( "Mouse deactivated.\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( enableMouse, bool, 1, 1, "enableMouse()" )
|
||||
{
|
||||
return( enableMouse() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( disableMouse, void, 1, 1, "disableMouse()" )
|
||||
{
|
||||
disableMouse();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void printInputState(void)
|
||||
{
|
||||
if ( gInputEnabled )
|
||||
{
|
||||
Con::printf( "Low-level input system is enabled." );
|
||||
|
||||
Con::printf( "- Keyboard is %sabled and %sactive.",
|
||||
gKBEnabled ? "en" : "dis",
|
||||
gKBActive ? "" : "in" );
|
||||
Con::printf( "- Mouse is %sabled and %sactive.",
|
||||
gMouseEnabled ? "en" : "dis",
|
||||
gMouseActive ? "" : "in" );
|
||||
/*
|
||||
Con::printf( "- Joystick is %sabled and %sactive.",
|
||||
gJoystickEnabled() ? "en" : "dis",
|
||||
gJoystickActive() ? "" : "in" );
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::printf( "Low-level input system is disabled." );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( echoInputState, void, 1, 1, "echoInputState()" )
|
||||
{
|
||||
printInputState();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( toggleInputState, void, 1, 1, "toggleInputState()" )
|
||||
{
|
||||
if (gInputEnabled)
|
||||
Input::disable();
|
||||
else
|
||||
Input::enable();
|
||||
|
||||
printInputState();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( deactivateKeyboard, void, 1, 1, "deactivateKeyboard();")
|
||||
{
|
||||
// these are only useful on the windows side. They deal with some vagaries of win32 DirectInput.
|
||||
}
|
||||
|
||||
ConsoleFunction( activateKeyboard, void, 1, 1, "activateKeyboard();")
|
||||
{
|
||||
// these are only useful on the windows side. They deal with some vagaries of win32 DirectInput.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Input::setCursorPos(S32 x, S32 y)
|
||||
{
|
||||
if (!platState.appWindow )
|
||||
return;
|
||||
|
||||
Rect r;
|
||||
Point targetPoint;
|
||||
GrafPtr savePort;
|
||||
|
||||
// get the center of the window
|
||||
GetWindowBounds(platState.appWindow, kWindowContentRgn, &r);
|
||||
targetPoint.h = r.left + x;
|
||||
targetPoint.v = r.top + y;
|
||||
|
||||
CGDirectDisplayID displayID = platState.cgDisplay;
|
||||
|
||||
CGRect bounds = CGDisplayBounds(displayID);
|
||||
CGPoint cgWndCenter;
|
||||
cgWndCenter.x = targetPoint.h + bounds.origin.x;
|
||||
cgWndCenter.y = targetPoint.v + bounds.origin.y;
|
||||
CGSetLocalEventsSuppressionInterval(0);
|
||||
CGDisplayMoveCursorToPoint(displayID, cgWndCenter);
|
||||
CGSetLocalEventsSuppressionInterval(0.25);
|
||||
}
|
243
engine/platformMacCarb/macCarbMain.cc
Executable file
243
engine/platformMacCarb/macCarbMain.cc
Executable file
@ -0,0 +1,243 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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);
|
||||
|
||||
}
|
138
engine/platformMacCarb/macCarbMath.cc
Executable file
138
engine/platformMacCarb/macCarbMath.cc
Executable file
@ -0,0 +1,138 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
#include "math/mMath.h"
|
||||
#include "terrain/blender.h"
|
||||
|
||||
extern void mInstallLibrary_C();
|
||||
extern void mInstallLibrary_Vec();
|
||||
extern void mInstall_Library_SSE();
|
||||
extern void mInstallLibrary_ASM();
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
ConsoleFunction( MathInit, void, 1, 10, "([DETECT|C|VEC|SSE])")
|
||||
{
|
||||
U32 properties = CPU_PROP_C; // C entensions are always used
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
Math::init(0);
|
||||
return;
|
||||
}
|
||||
for (argc--, argv++; argc; argc--, argv++)
|
||||
{
|
||||
if (dStricmp(*argv, "DETECT") == 0) {
|
||||
Math::init(0);
|
||||
return;
|
||||
}
|
||||
if (dStricmp(*argv, "C") == 0) {
|
||||
properties |= CPU_PROP_C;
|
||||
continue;
|
||||
}
|
||||
if (dStricmp(*argv, "VEC") == 0) {
|
||||
properties |= CPU_PROP_ALTIVEC;
|
||||
continue;
|
||||
}
|
||||
if (dStricmp(*argv, "SSE") == 0) {
|
||||
properties |= CPU_PROP_SSE;
|
||||
continue;
|
||||
}
|
||||
Con::printf("Error: MathInit(): ignoring unknown math extension '%s'", *argv);
|
||||
}
|
||||
Math::init(properties);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Math::init(U32 properties)
|
||||
{
|
||||
if (!properties)
|
||||
// detect what's available
|
||||
properties = Platform::SystemInfo.processor.properties;
|
||||
else
|
||||
// Make sure we're not asking for anything that's not supported
|
||||
properties &= Platform::SystemInfo.processor.properties;
|
||||
|
||||
Con::printf("Math Init:");
|
||||
Con::printf(" Installing Standard C extensions");
|
||||
mInstallLibrary_C();
|
||||
|
||||
if(Platform::SystemInfo.processor.type == CPU_X86Compatible)
|
||||
{
|
||||
Con::printf(" Installing Assembly extensions");
|
||||
mInstallLibrary_ASM();
|
||||
}
|
||||
|
||||
#if defined(__VEC__)
|
||||
Blender::smUseVecBlender = false;
|
||||
if (properties & CPU_PROP_ALTIVEC)
|
||||
{
|
||||
Con::printf(" Installing Altivec extensions");
|
||||
mInstallLibrary_Vec();
|
||||
Blender::smUseVecBlender = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (properties & CPU_PROP_SSE)
|
||||
{
|
||||
Con::printf(" Installing SSE extensions");
|
||||
mInstall_Library_SSE();
|
||||
}
|
||||
|
||||
Con::printf(" ");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
F32 Platform::getRandom()
|
||||
{
|
||||
return platState.platRandom.randF();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Intel asm math
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(i386)
|
||||
|
||||
static S32 m_mulDivS32_ASM(S32 a, S32 b, S32 c)
|
||||
{ // a * b / c
|
||||
S32 r;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"imul %2\n"
|
||||
"idiv %3\n"
|
||||
: "=a" (r) : "a" (a) , "b" (b) , "c" (c)
|
||||
);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static U32 m_mulDivU32_ASM(S32 a, S32 b, U32 c)
|
||||
{ // a * b / c
|
||||
S32 r;
|
||||
__asm__ __volatile__(
|
||||
"mov $0, %%edx\n"
|
||||
"mul %2\n"
|
||||
"div %3\n"
|
||||
: "=a" (r) : "a" (a) , "b" (b) , "c" (c)
|
||||
);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void mInstallLibrary_ASM()
|
||||
{
|
||||
// stubbed out for ppc builds
|
||||
#if defined(i386)
|
||||
m_mulDivS32 = m_mulDivS32_ASM;
|
||||
m_mulDivU32 = m_mulDivU32_ASM;
|
||||
#endif
|
||||
}
|
57
engine/platformMacCarb/macCarbMemory.cc
Executable file
57
engine/platformMacCarb/macCarbMemory.cc
Executable file
@ -0,0 +1,57 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//--------------------------------------
|
||||
#ifdef new
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
void* FN_CDECL operator new(dsize_t dt, void* ptr)
|
||||
{
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void* dRealMalloc(dsize_t in_size)
|
||||
{
|
||||
return malloc(in_size);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void dRealFree(void* in_pFree)
|
||||
{
|
||||
free(in_pFree);
|
||||
}
|
||||
|
||||
|
||||
void* dMemcpy(void *dst, const void *src, dsize_t size)
|
||||
{
|
||||
return memcpy(dst,src,size);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void* dMemmove(void *dst, const void *src, dsize_t size)
|
||||
{
|
||||
return memmove(dst,src,size);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void* dMemset(void *dst, int c, dsize_t size)
|
||||
{
|
||||
return memset(dst,c,size);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
int dMemcmp(const void *ptr1, const void *ptr2, dsize_t len)
|
||||
{
|
||||
return(memcmp(ptr1, ptr2, len));
|
||||
}
|
84
engine/platformMacCarb/macCarbMutex.cc
Executable file
84
engine/platformMacCarb/macCarbMutex.cc
Executable file
@ -0,0 +1,84 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "platform/platform.h"
|
||||
#include "platform/platformMutex.h"
|
||||
#include "platform/platformThread.h"
|
||||
|
||||
// TODO: examine & dump errno if pthread_* funcs fail. ( only in debug build )
|
||||
|
||||
typedef struct MacCarbMutex
|
||||
{
|
||||
pthread_mutex_t mMutex;
|
||||
bool locked;
|
||||
U32 lockedByThread;
|
||||
};
|
||||
|
||||
void* Mutex::createMutex(void)
|
||||
{
|
||||
bool ok;
|
||||
MacCarbMutex *m = new MacCarbMutex();
|
||||
pthread_mutexattr_t attr;
|
||||
ok = pthread_mutexattr_init(&attr);
|
||||
ok = pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
ok = pthread_mutex_init(&(m->mMutex),&attr);
|
||||
AssertFatal(ok == 0, "Mutex::createMutex() failed: pthread_mutex_init() failed.");
|
||||
|
||||
m->locked = false;
|
||||
m->lockedByThread = 0;
|
||||
|
||||
return (void*)m;
|
||||
}
|
||||
|
||||
void Mutex::destroyMutex(void* mutex)
|
||||
{
|
||||
bool ok;
|
||||
MacCarbMutex *m = (MacCarbMutex*)mutex;
|
||||
ok = pthread_mutex_destroy( &(m->mMutex) );
|
||||
AssertFatal(ok == 0, "Mutex::destroyMutex() failed: pthread_mutex_destroy() failed.");
|
||||
delete mutex;
|
||||
}
|
||||
|
||||
bool Mutex::lockMutex( void *mutex, bool block)
|
||||
{
|
||||
int ok;
|
||||
MacCarbMutex *m = (MacCarbMutex*)mutex;
|
||||
|
||||
if(block)
|
||||
{
|
||||
ok = pthread_mutex_lock( &(m->mMutex) );
|
||||
AssertFatal( ok != EINVAL, "Mutex::lockMutex() failed: invalid mutex.");
|
||||
AssertFatal( ok != EDEADLK, "Mutex::lockMutex() failed: system detected a deadlock!");
|
||||
AssertFatal( ok == 0, "Mutex::lockMutex() failed: pthread_mutex_lock() failed -- unknown reason.");
|
||||
}
|
||||
else {
|
||||
ok = pthread_mutex_trylock( &(m->mMutex) );
|
||||
// returns EBUSY if mutex was locked by another thread,
|
||||
// returns EINVAL if mutex was not a valid mutex pointer,
|
||||
// returns 0 if lock succeeded.
|
||||
AssertFatal( ok != EINVAL, "Mutex::lockMutex(non blocking) failed: invalid mutex.");
|
||||
if( ok != 0 )
|
||||
return false;
|
||||
|
||||
AssertFatal( ok == 0, "Mutex::lockMutex(non blocking) failed: pthread_mutex_trylock() failed -- unknown reason.");
|
||||
}
|
||||
|
||||
m->locked = true;
|
||||
m->lockedByThread = Thread::getCurrentThreadId();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::unlockMutex( void *mutex)
|
||||
{
|
||||
bool ok;
|
||||
MacCarbMutex *m = (MacCarbMutex*)mutex;
|
||||
ok = pthread_mutex_unlock( &(m->mMutex) );
|
||||
AssertFatal( ok == 0, "Mutex::unlockMutex() failed: pthread_mutex_unlock() failed.");
|
||||
m->locked = false;
|
||||
m->lockedByThread = 0;
|
||||
}
|
57
engine/platformMacCarb/macCarbNPatch.h
Executable file
57
engine/platformMacCarb/macCarbNPatch.h
Executable file
@ -0,0 +1,57 @@
|
||||
// macCarbNPatch.h
|
||||
//
|
||||
// mac specific implementation(s) of NPatch functionality
|
||||
// since each platform might use slightly diff methods to control.
|
||||
|
||||
// current Mac NPatches is ATI TRUFORM implementation, accessed on OS9 via a
|
||||
// back door method. OSX tests for the ATIX extension.
|
||||
|
||||
#if !defined(TORQUE_OS_MAC_OSX)
|
||||
#define AGLSETINT_NPATCH_FLAG ((unsigned long)500)
|
||||
#define AGLSETINT_NPATCH_LOD ((unsigned long)501)
|
||||
#define AGLSETINT_NPATCH_POINTINTERP ((unsigned long)502)
|
||||
#define AGLSETINT_NPATCH_NORMALINTERP ((unsigned long)503)
|
||||
#endif
|
||||
|
||||
// for the moment, this seems to be the best roundup of
|
||||
// the npatch extensions on the PC.
|
||||
|
||||
#ifndef GL_ATIX_pn_triangles
|
||||
#define GL_ATIX_pn_triangles 1
|
||||
#define GL_PN_TRIANGLES_ATIX 0x6090
|
||||
#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATIX 0x6091
|
||||
#define GL_PN_TRIANGLES_POINT_MODE_ATIX 0x6092
|
||||
#define GL_PN_TRIANGLES_NORMAL_MODE_ATIX 0x6093
|
||||
#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATIX 0x6094
|
||||
#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATIX 0x6095
|
||||
#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATIX 0x6096
|
||||
#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATIX 0x6097
|
||||
#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATIX 0x6098
|
||||
|
||||
#if defined(TORQUE_OS_MAC_OSX) // for the moment...
|
||||
extern void glPNTrianglesiATIX(GLenum pname, GLint param);
|
||||
extern void glPNTrianglesfATIX(GLenum pname, GLfloat param);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void (*PFNGLPNTRIANGLESIATIPROC)(GLenum pname, GLint param);
|
||||
//typedef void (APIENTRY *PFNGLPNTRIANGLESFATIPROC)(GLenum pname, GLfloat param);
|
||||
|
||||
#define GL_NPATCH_EXT_STRING "GL_ATIX_pn_triangles"
|
||||
#define GL_NPATCH_SETINT_STRING "glPNTrianglesiATIX"
|
||||
typedef PFNGLPNTRIANGLESIATIPROC PFNNPatchSetInt;
|
||||
|
||||
#define GETINT_NPATCH_MAX_LEVEL GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATIX
|
||||
|
||||
#define GL_NPATCH_FLAG GL_PN_TRIANGLES_ATIX
|
||||
|
||||
#define SETINT_NPATCH_LOD GL_PN_TRIANGLES_TESSELATION_LEVEL_ATIX
|
||||
|
||||
#define SETINT_NPATCH_POINTINTERP GL_PN_TRIANGLES_POINT_MODE_ATIX
|
||||
#define SETINT_NPATCH_NORMALINTERP GL_PN_TRIANGLES_NORMAL_MODE_ATIX
|
||||
|
||||
#define NPATCH_POINTINTERP_MIN GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATIX
|
||||
#define NPATCH_POINTINTERP_MAX GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATIX
|
||||
|
||||
#define NPATCH_NORMALINTERP_MIN GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATIX
|
||||
#define NPATCH_NORMALINTERP_MAX GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATIX
|
845
engine/platformMacCarb/macCarbNet.cc
Executable file
845
engine/platformMacCarb/macCarbNet.cc
Executable file
@ -0,0 +1,845 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
//
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Touch-ups by William Taysom
|
||||
|
||||
|
||||
#include "PlatformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platform.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/platformNetAsync.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
// Header clean-up by William Taysom
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
// IPX fixes from William Taysom.
|
||||
#define IPX_NODE_LEN 6
|
||||
|
||||
// for 10.2 compatability...
|
||||
#ifndef socklen_t
|
||||
#define socklen_t unsigned int
|
||||
#endif
|
||||
|
||||
struct sockaddr_ipx
|
||||
{
|
||||
sa_family_t sipx_family;
|
||||
U16 sipx_port;
|
||||
U32 sipx_network;
|
||||
unsigned char sipx_node[IPX_NODE_LEN];
|
||||
U8 sipx_type;
|
||||
unsigned char sipx_zero; /* 16 byte fill */
|
||||
};
|
||||
// end wtaysom changes (May 26, 2004)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "console/console.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "core/fileStream.h"
|
||||
#include "core/tVector.h"
|
||||
|
||||
static Net::Error getLastError();
|
||||
static S32 defaultPort = 28000;
|
||||
static S32 netPort = 0;
|
||||
static int ipxSocket = InvalidSocket;
|
||||
static int udpSocket = InvalidSocket;
|
||||
|
||||
// local enum for socket states for polled sockets
|
||||
enum SocketState
|
||||
{
|
||||
InvalidState,
|
||||
Connected,
|
||||
ConnectionPending,
|
||||
Listening,
|
||||
NameLookupRequired
|
||||
};
|
||||
|
||||
// the Socket structure helps us keep track of the
|
||||
// above states
|
||||
struct Socket
|
||||
{
|
||||
Socket()
|
||||
{
|
||||
fd = InvalidSocket;
|
||||
state = InvalidState;
|
||||
remoteAddr[0] = 0;
|
||||
remotePort = -1;
|
||||
}
|
||||
|
||||
NetSocket fd;
|
||||
S32 state;
|
||||
char remoteAddr[256];
|
||||
S32 remotePort;
|
||||
};
|
||||
|
||||
// list of polled sockets
|
||||
static Vector<Socket*> gPolledSockets;
|
||||
|
||||
static Socket* addPolledSocket(NetSocket& fd, S32 state,
|
||||
char* remoteAddr = NULL, S32 port = -1)
|
||||
{
|
||||
Socket* sock = new Socket();
|
||||
sock->fd = fd;
|
||||
sock->state = state;
|
||||
if (remoteAddr)
|
||||
dStrcpy(sock->remoteAddr, remoteAddr);
|
||||
if (port != -1)
|
||||
sock->remotePort = port;
|
||||
gPolledSockets.push_back(sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
enum {
|
||||
MaxConnections = 1024,
|
||||
};
|
||||
|
||||
|
||||
bool netSocketWaitForWritable(NetSocket fd, S32 timeoutMs)
|
||||
{
|
||||
fd_set writefds;
|
||||
timeval timeout;
|
||||
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET( fd, &writefds );
|
||||
|
||||
timeout.tv_sec = timeoutMs / 1000;
|
||||
timeout.tv_usec = ( timeoutMs % 1000 ) * 1000;
|
||||
|
||||
if( select(fd + 1, NULL, &writefds, NULL, &timeout) > 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Net::init()
|
||||
{
|
||||
NetAsync::startAsync();
|
||||
return(true);
|
||||
}
|
||||
|
||||
void Net::shutdown()
|
||||
{
|
||||
while (gPolledSockets.size() > 0)
|
||||
closeConnectTo(gPolledSockets[0]->fd);
|
||||
|
||||
closePort();
|
||||
NetAsync::stopAsync();
|
||||
}
|
||||
|
||||
static void netToIPSocketAddress(const NetAddress *address, struct sockaddr_in *sockAddr)
|
||||
{
|
||||
dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
|
||||
sockAddr->sin_family = AF_INET;
|
||||
sockAddr->sin_port = htons(address->port);
|
||||
char tAddr[20];
|
||||
dSprintf(tAddr, 20, "%d.%d.%d.%d\n", address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3]);
|
||||
//fprintf(stdout,"netToIPSocketAddress(): %s\n",tAddr);fflush(NULL);
|
||||
sockAddr->sin_addr.s_addr = inet_addr(tAddr);
|
||||
}
|
||||
|
||||
static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
|
||||
{
|
||||
address->type = NetAddress::IPAddress;
|
||||
address->port = htons(sockAddr->sin_port);
|
||||
char *tAddr;
|
||||
tAddr = inet_ntoa(sockAddr->sin_addr);
|
||||
//fprintf(stdout,"IPSocketToNetAddress(): %s\n",tAddr);fflush(NULL);
|
||||
U8 nets[4];
|
||||
nets[0] = atoi(strtok(tAddr, "."));
|
||||
nets[1] = atoi(strtok(NULL, "."));
|
||||
nets[2] = atoi(strtok(NULL, "."));
|
||||
nets[3] = atoi(strtok(NULL, "."));
|
||||
//fprintf(stdout,"0 = %d, 1 = %d, 2 = %d, 3 = %d\n", nets[0], nets[1], nets[2], nets[3]);
|
||||
address->netNum[0] = nets[0];
|
||||
address->netNum[1] = nets[1];
|
||||
address->netNum[2] = nets[2];
|
||||
address->netNum[3] = nets[3];
|
||||
}
|
||||
|
||||
static void netToIPXSocketAddress(const NetAddress *address, sockaddr_ipx *sockAddr)
|
||||
{
|
||||
dMemset(sockAddr, 0, sizeof(sockaddr_ipx));
|
||||
sockAddr->sipx_family = AF_INET;
|
||||
sockAddr->sipx_port = htons(address->port);
|
||||
sockAddr->sipx_network = address->netNum[0];
|
||||
sockAddr->sipx_node[0] = address->nodeNum[0];
|
||||
sockAddr->sipx_node[1] = address->nodeNum[1];
|
||||
sockAddr->sipx_node[2] = address->nodeNum[2];
|
||||
sockAddr->sipx_node[3] = address->nodeNum[3];
|
||||
sockAddr->sipx_node[4] = address->nodeNum[4];
|
||||
sockAddr->sipx_node[5] = address->nodeNum[5];
|
||||
}
|
||||
|
||||
NetSocket Net::openListenPort(U16 port)
|
||||
{
|
||||
if(Game->isJournalReading())
|
||||
{
|
||||
U32 ret;
|
||||
Game->journalRead(&ret);
|
||||
return NetSocket(ret);
|
||||
}
|
||||
NetSocket sock = openSocket();
|
||||
if (sock == InvalidSocket)
|
||||
{
|
||||
Con::errorf("Unable to open listen socket: %s", strerror(errno));
|
||||
return InvalidSocket;
|
||||
}
|
||||
|
||||
if (bind(sock, port) != NoError)
|
||||
{
|
||||
Con::errorf("Unable to bind port %d: %s", port, strerror(errno));
|
||||
::close(sock);
|
||||
return InvalidSocket;
|
||||
}
|
||||
if (listen(sock, 4) != NoError)
|
||||
{
|
||||
Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));
|
||||
::close(sock);
|
||||
return InvalidSocket;
|
||||
}
|
||||
|
||||
setBlocking(sock, false);
|
||||
addPolledSocket(sock, Listening);
|
||||
if (Game->isJournalWriting())
|
||||
Game->journalWrite(U32(sock));
|
||||
return sock;
|
||||
}
|
||||
|
||||
NetSocket Net::openConnectTo(const char *addressString)
|
||||
{
|
||||
if(!dStrnicmp(addressString, "ipx:", 4))
|
||||
return InvalidSocket;
|
||||
if(!dStrnicmp(addressString, "ip:", 3))
|
||||
addressString += 3; // eat off the ip:
|
||||
char remoteAddr[256];
|
||||
dStrcpy(remoteAddr, addressString);
|
||||
|
||||
char *portString = dStrchr(remoteAddr, ':');
|
||||
|
||||
U16 port;
|
||||
if(portString)
|
||||
{
|
||||
*portString++ = 0;
|
||||
port = htons(dAtoi(portString));
|
||||
}
|
||||
else
|
||||
port = htons(defaultPort);
|
||||
|
||||
if(!dStricmp(remoteAddr, "broadcast"))
|
||||
return InvalidSocket;
|
||||
|
||||
if(Game->isJournalReading())
|
||||
{
|
||||
U32 ret;
|
||||
Game->journalRead(&ret);
|
||||
return NetSocket(ret);
|
||||
}
|
||||
NetSocket sock = openSocket();
|
||||
setBlocking(sock, false);
|
||||
|
||||
sockaddr_in ipAddr;
|
||||
dMemset(&ipAddr, 0, sizeof(ipAddr));
|
||||
|
||||
if (inet_aton(remoteAddr, &ipAddr.sin_addr) != 0)
|
||||
{
|
||||
ipAddr.sin_port = port;
|
||||
ipAddr.sin_family = AF_INET;
|
||||
if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1 &&
|
||||
errno != EINPROGRESS)
|
||||
{
|
||||
Con::errorf("Error connecting %s: %s",
|
||||
addressString, strerror(errno));
|
||||
::close(sock);
|
||||
sock = InvalidSocket;
|
||||
}
|
||||
if(sock != InvalidSocket) {
|
||||
// add this socket to our list of polled sockets
|
||||
addPolledSocket(sock, ConnectionPending);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to do an asynchronous name lookup. first, add the socket
|
||||
// to the polled list
|
||||
addPolledSocket(sock, NameLookupRequired, remoteAddr, port);
|
||||
// queue the lookup
|
||||
gNetAsync.queueLookup(remoteAddr, sock);
|
||||
}
|
||||
if(Game->isJournalWriting())
|
||||
Game->journalWrite(U32(sock));
|
||||
return sock;
|
||||
}
|
||||
|
||||
void Net::closeConnectTo(NetSocket sock)
|
||||
{
|
||||
if(Game->isJournalReading())
|
||||
return;
|
||||
|
||||
// if this socket is in the list of polled sockets, remove it
|
||||
for (int i = 0; i < gPolledSockets.size(); ++i)
|
||||
if (gPolledSockets[i]->fd == sock)
|
||||
{
|
||||
delete gPolledSockets[i];
|
||||
gPolledSockets.erase(i);
|
||||
break;
|
||||
}
|
||||
|
||||
closeSocket(sock);
|
||||
}
|
||||
|
||||
Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, int bufferSize)
|
||||
{
|
||||
if(Game->isJournalReading())
|
||||
{
|
||||
U32 e;
|
||||
Game->journalRead(&e);
|
||||
|
||||
return (Net::Error) e;
|
||||
}
|
||||
Net::Error e = send(socket, buffer, bufferSize);
|
||||
if(Game->isJournalWriting())
|
||||
Game->journalWrite(U32(e));
|
||||
return e;
|
||||
}
|
||||
|
||||
bool Net::openPort(S32 port)
|
||||
{
|
||||
if(udpSocket != InvalidSocket)
|
||||
close(udpSocket);
|
||||
if(ipxSocket != InvalidSocket)
|
||||
close(ipxSocket);
|
||||
|
||||
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ipxSocket = socket(AF_IPX, SOCK_DGRAM, 0);
|
||||
|
||||
if(udpSocket != InvalidSocket)
|
||||
{
|
||||
Net::Error error;
|
||||
error = bind(udpSocket, port);
|
||||
if(error == NoError)
|
||||
error = setBufferSize(udpSocket, 32768);
|
||||
if(error == NoError)
|
||||
error = setBroadcast(udpSocket, true);
|
||||
if(error == NoError)
|
||||
error = setBlocking(udpSocket, false);
|
||||
if(error == NoError)
|
||||
Con::printf("UDP initialized on port %d", port);
|
||||
else
|
||||
{
|
||||
close(udpSocket);
|
||||
udpSocket = InvalidSocket;
|
||||
Con::printf("Unable to initialize UDP - error %d", error);
|
||||
}
|
||||
}
|
||||
if(ipxSocket != InvalidSocket)
|
||||
{
|
||||
Net::Error error = NoError;
|
||||
sockaddr_ipx ipxAddress;
|
||||
memset((char *)&ipxAddress, 0, sizeof(ipxAddress));
|
||||
ipxAddress.sipx_family = AF_IPX;
|
||||
ipxAddress.sipx_port = htons(port);
|
||||
S32 err = ::bind(ipxSocket, (struct sockaddr *)&ipxAddress, sizeof(ipxAddress));
|
||||
if(err)
|
||||
error = getLastError();
|
||||
if(error == NoError)
|
||||
error = setBufferSize(ipxSocket, 32768);
|
||||
if(error == NoError)
|
||||
error = setBroadcast(ipxSocket, true);
|
||||
if(error == NoError)
|
||||
error = setBlocking(ipxSocket, false);
|
||||
if(error == NoError)
|
||||
Con::printf("IPX initialized on port %d", port);
|
||||
else
|
||||
{
|
||||
close(ipxSocket);
|
||||
ipxSocket = InvalidSocket;
|
||||
Con::printf("Unable to initialize IPX - error %d", error);
|
||||
}
|
||||
}
|
||||
netPort = port;
|
||||
return ipxSocket != InvalidSocket || udpSocket != InvalidSocket;
|
||||
}
|
||||
|
||||
void Net::closePort()
|
||||
{
|
||||
if(ipxSocket != InvalidSocket)
|
||||
close(ipxSocket);
|
||||
if(udpSocket != InvalidSocket)
|
||||
close(udpSocket);
|
||||
}
|
||||
|
||||
Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
|
||||
{
|
||||
if(Game->isJournalReading())
|
||||
return NoError;
|
||||
|
||||
if(address->type == NetAddress::IPAddress)
|
||||
{
|
||||
sockaddr_in ipAddr;
|
||||
netToIPSocketAddress(address, &ipAddr);
|
||||
if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
|
||||
(sockaddr *) &ipAddr, sizeof(sockaddr_in)) == -1)
|
||||
return getLastError();
|
||||
else
|
||||
return NoError;
|
||||
}
|
||||
}
|
||||
|
||||
void Net::process()
|
||||
{
|
||||
sockaddr sa;
|
||||
|
||||
PacketReceiveEvent receiveEvent;
|
||||
for(;;)
|
||||
{
|
||||
U32 addrLen = sizeof(sa);
|
||||
S32 bytesRead = -1;
|
||||
if(udpSocket != InvalidSocket)
|
||||
bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
|
||||
if(bytesRead == -1 && ipxSocket != InvalidSocket)
|
||||
{
|
||||
addrLen = sizeof(sa);
|
||||
bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
|
||||
}
|
||||
|
||||
if(bytesRead == -1)
|
||||
break;
|
||||
|
||||
if(sa.sa_family == AF_INET)
|
||||
IPSocketToNetAddress((sockaddr_in *) &sa, &receiveEvent.sourceAddress);
|
||||
else
|
||||
continue;
|
||||
|
||||
NetAddress &na = receiveEvent.sourceAddress;
|
||||
if(na.type == NetAddress::IPAddress &&
|
||||
na.netNum[0] == 127 &&
|
||||
na.netNum[1] == 0 &&
|
||||
na.netNum[2] == 0 &&
|
||||
na.netNum[3] == 1 &&
|
||||
na.port == netPort)
|
||||
continue;
|
||||
if(bytesRead <= 0)
|
||||
continue;
|
||||
receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead;
|
||||
Game->postEvent(receiveEvent);
|
||||
}
|
||||
|
||||
// process the polled sockets. This blob of code performs functions
|
||||
// similar to WinsockProc in winNet.cc
|
||||
|
||||
if (gPolledSockets.size() == 0)
|
||||
return;
|
||||
|
||||
static ConnectedNotifyEvent notifyEvent;
|
||||
static ConnectedAcceptEvent acceptEvent;
|
||||
static ConnectedReceiveEvent cReceiveEvent;
|
||||
|
||||
S32 optval;
|
||||
socklen_t optlen = sizeof(S32);
|
||||
S32 bytesRead;
|
||||
Net::Error err;
|
||||
bool removeSock = false;
|
||||
Socket *currentSock = NULL;
|
||||
sockaddr_in ipAddr;
|
||||
NetSocket incoming = InvalidSocket;
|
||||
char out_h_addr[1024];
|
||||
int out_h_length = 0;
|
||||
|
||||
for (S32 i = 0; i < gPolledSockets.size();
|
||||
/* no increment, this is done at end of loop body */)
|
||||
{
|
||||
removeSock = false;
|
||||
currentSock = gPolledSockets[i];
|
||||
switch (currentSock->state)
|
||||
{
|
||||
case InvalidState:
|
||||
Con::errorf("Error, InvalidState socket in polled sockets list");
|
||||
break;
|
||||
case ConnectionPending:
|
||||
notifyEvent.tag = currentSock->fd;
|
||||
// see if it is now connected
|
||||
if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR,
|
||||
&optval, &optlen) == -1)
|
||||
{
|
||||
Con::errorf("Error getting socket options: %s", strerror(errno));
|
||||
notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
|
||||
Game->postEvent(notifyEvent);
|
||||
removeSock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optval == EINPROGRESS)
|
||||
// still connecting...
|
||||
break;
|
||||
|
||||
if (optval == 0)
|
||||
{
|
||||
// poll for writable status to be sure we're connected.
|
||||
bool ready = netSocketWaitForWritable(currentSock->fd,0);
|
||||
if(!ready)
|
||||
break;
|
||||
|
||||
// connected.
|
||||
notifyEvent.state = ConnectedNotifyEvent::Connected;
|
||||
Game->postEvent(notifyEvent);
|
||||
currentSock->state = Connected;
|
||||
}
|
||||
else
|
||||
{
|
||||
// some kind of error
|
||||
Con::errorf("Error connecting: %s", strerror(errno));
|
||||
notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
|
||||
Game->postEvent(notifyEvent);
|
||||
removeSock = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Connected:
|
||||
bytesRead = 0;
|
||||
// try to get some data
|
||||
err = Net::recv(currentSock->fd, cReceiveEvent.data, MaxPacketDataSize, &bytesRead);
|
||||
if(err == Net::NoError)
|
||||
{
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
// got some data, post it
|
||||
cReceiveEvent.tag = currentSock->fd;
|
||||
cReceiveEvent.size = ConnectedReceiveEventHeaderSize +
|
||||
bytesRead;
|
||||
Game->postEvent(cReceiveEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// zero bytes read means EOF
|
||||
if (bytesRead < 0)
|
||||
// ack! this shouldn't happen
|
||||
Con::errorf("Unexpected error on socket: %s",
|
||||
strerror(errno));
|
||||
|
||||
notifyEvent.tag = currentSock->fd;
|
||||
notifyEvent.state = ConnectedNotifyEvent::Disconnected;
|
||||
Game->postEvent(notifyEvent);
|
||||
removeSock = true;
|
||||
}
|
||||
}
|
||||
else if (err != Net::NoError && err != Net::WouldBlock)
|
||||
{
|
||||
Con::errorf("Error reading from socket: %s", strerror(errno));
|
||||
notifyEvent.tag = currentSock->fd;
|
||||
notifyEvent.state = ConnectedNotifyEvent::Disconnected;
|
||||
Game->postEvent(notifyEvent);
|
||||
removeSock = true;
|
||||
}
|
||||
break;
|
||||
case NameLookupRequired:
|
||||
// is the lookup complete?
|
||||
if (!gNetAsync.checkLookup(
|
||||
currentSock->fd, out_h_addr, &out_h_length,
|
||||
sizeof(out_h_addr)))
|
||||
break;
|
||||
|
||||
notifyEvent.tag = currentSock->fd;
|
||||
if (out_h_length == -1)
|
||||
{
|
||||
Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);
|
||||
notifyEvent.state = ConnectedNotifyEvent::DNSFailed;
|
||||
removeSock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to connect
|
||||
dMemcpy(&(ipAddr.sin_addr.s_addr), out_h_addr, out_h_length);
|
||||
ipAddr.sin_port = currentSock->remotePort;
|
||||
ipAddr.sin_family = AF_INET;
|
||||
if(::connect(currentSock->fd, (struct sockaddr *)&ipAddr,
|
||||
sizeof(ipAddr)) == -1)
|
||||
{
|
||||
if (errno == EINPROGRESS)
|
||||
{
|
||||
notifyEvent.state = ConnectedNotifyEvent::DNSResolved;
|
||||
currentSock->state = ConnectionPending;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::errorf("Error connecting to %s: %s",
|
||||
currentSock->remoteAddr, strerror(errno));
|
||||
notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
|
||||
removeSock = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
notifyEvent.state = ConnectedNotifyEvent::Connected;
|
||||
currentSock->state = Connected;
|
||||
}
|
||||
}
|
||||
Game->postEvent(notifyEvent);
|
||||
break;
|
||||
case Listening:
|
||||
incoming =
|
||||
Net::accept(currentSock->fd, &acceptEvent.address);
|
||||
if(incoming != InvalidSocket)
|
||||
{
|
||||
acceptEvent.portTag = currentSock->fd;
|
||||
acceptEvent.connectionTag = incoming;
|
||||
setBlocking(incoming, false);
|
||||
addPolledSocket(incoming, Connected);
|
||||
Game->postEvent(acceptEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// only increment index if we're not removing the connection, since
|
||||
// the removal will shift the indices down by one
|
||||
if (removeSock)
|
||||
closeConnectTo(currentSock->fd);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
NetSocket Net::openSocket()
|
||||
{
|
||||
int retSocket;
|
||||
retSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if(retSocket == InvalidSocket)
|
||||
return InvalidSocket;
|
||||
else
|
||||
return retSocket;
|
||||
}
|
||||
|
||||
Net::Error Net::closeSocket(NetSocket socket)
|
||||
{
|
||||
if(socket != InvalidSocket)
|
||||
{
|
||||
if(!close(socket))
|
||||
return NoError;
|
||||
else
|
||||
return getLastError();
|
||||
}
|
||||
else
|
||||
return NotASocket;
|
||||
}
|
||||
|
||||
Net::Error Net::connect(NetSocket socket, const NetAddress *address)
|
||||
{
|
||||
if(address->type != NetAddress::IPAddress)
|
||||
return WrongProtocolType;
|
||||
sockaddr_in socketAddress;
|
||||
netToIPSocketAddress(address, &socketAddress);
|
||||
if(!::connect(socket, (sockaddr *) &socketAddress, sizeof(socketAddress)))
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::listen(NetSocket socket, S32 backlog)
|
||||
{
|
||||
if(!::listen(socket, backlog))
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
|
||||
{
|
||||
sockaddr_in socketAddress;
|
||||
U32 addrLen = sizeof(socketAddress);
|
||||
|
||||
int retVal = ::accept(acceptSocket, (sockaddr *) &socketAddress, &addrLen);
|
||||
if(retVal != InvalidSocket)
|
||||
{
|
||||
IPSocketToNetAddress(&socketAddress, remoteAddress);
|
||||
return retVal;
|
||||
}
|
||||
return InvalidSocket;
|
||||
}
|
||||
|
||||
Net::Error Net::bind(NetSocket socket, U16 port)
|
||||
{
|
||||
S32 error;
|
||||
|
||||
sockaddr_in socketAddress;
|
||||
dMemset((char *)&socketAddress, 0, sizeof(socketAddress));
|
||||
socketAddress.sin_family = AF_INET;
|
||||
// It's entirely possible that there are two NIC cards.
|
||||
// We let the user specify which one the server runs on.
|
||||
|
||||
// thanks to [TPG]P1aGu3 for the name
|
||||
const char* serverIP = Con::getVariable( "Pref::Net::BindAddress" );
|
||||
// serverIP is guaranteed to be non-0.
|
||||
AssertFatal( serverIP, "serverIP is NULL!" );
|
||||
|
||||
if( serverIP[0] != '\0' ) {
|
||||
// we're not empty
|
||||
socketAddress.sin_addr.s_addr = inet_addr( serverIP );
|
||||
|
||||
if( socketAddress.sin_addr.s_addr != INADDR_NONE ) {
|
||||
Con::printf( "Binding server port to %s", serverIP );
|
||||
} else {
|
||||
Con::warnf( ConsoleLogEntry::General,
|
||||
"inet_addr() failed for %s while binding!",
|
||||
serverIP );
|
||||
socketAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
} else {
|
||||
Con::printf( "Binding server port to default IP" );
|
||||
socketAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
socketAddress.sin_port = htons(port);
|
||||
error = ::bind(socket, (sockaddr *) &socketAddress, sizeof(socketAddress));
|
||||
|
||||
if(!error)
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
|
||||
{
|
||||
S32 error;
|
||||
error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
|
||||
if(!error)
|
||||
error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
|
||||
if(!error)
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
|
||||
{
|
||||
S32 bc = broadcast;
|
||||
S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
|
||||
if(!error)
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
|
||||
{
|
||||
int notblock = !blockingIO;
|
||||
S32 error = ioctl(socket, FIONBIO, ¬block);
|
||||
if(!error)
|
||||
return NoError;
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
|
||||
{
|
||||
errno = 0;
|
||||
S32 bytesWritten = ::send(socket, (const char*)buffer, bufferSize, 0);
|
||||
if(bytesWritten == -1)
|
||||
Con::errorf("Could not write to socket. Error: %s",strerror(errno));
|
||||
|
||||
return getLastError();
|
||||
}
|
||||
|
||||
Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead)
|
||||
{
|
||||
*bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0);
|
||||
if(*bytesRead == -1)
|
||||
return getLastError();
|
||||
return NoError;
|
||||
}
|
||||
|
||||
bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
|
||||
{
|
||||
if((a1->type != a2->type) ||
|
||||
(*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
|
||||
(a1->port != a2->port))
|
||||
return false;
|
||||
|
||||
if(a1->type == NetAddress::IPAddress)
|
||||
return true;
|
||||
for(S32 i = 0; i < 6; i++)
|
||||
if(a1->nodeNum[i] != a2->nodeNum[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Net::stringToAddress(const char *addressString, NetAddress *address)
|
||||
{
|
||||
// assume IP if it doesn't have ipx: at the front.
|
||||
|
||||
if(!dStrnicmp(addressString, "ip:", 3))
|
||||
addressString += 3; // eat off the ip:
|
||||
|
||||
sockaddr_in ipAddr;
|
||||
char remoteAddr[256];
|
||||
if(strlen(addressString) > 255)
|
||||
return false;
|
||||
|
||||
dStrcpy(remoteAddr, addressString);
|
||||
|
||||
char *portString = dStrchr(remoteAddr, ':');
|
||||
if(portString)
|
||||
*portString++ = '\0';
|
||||
|
||||
struct hostent *hp;
|
||||
if(!dStricmp(remoteAddr, "broadcast"))
|
||||
ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
||||
else
|
||||
{
|
||||
if (inet_aton(remoteAddr,&ipAddr.sin_addr) == 0) // error
|
||||
{
|
||||
if((hp = gethostbyname(remoteAddr)) == 0)
|
||||
return false;
|
||||
else
|
||||
memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr));
|
||||
}
|
||||
}
|
||||
if(portString)
|
||||
ipAddr.sin_port = htons(dAtoi(portString));
|
||||
else
|
||||
ipAddr.sin_port = htons(defaultPort);
|
||||
ipAddr.sin_family = AF_INET;
|
||||
IPSocketToNetAddress(&ipAddr, address);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Net::addressToString(const NetAddress *address, char addressString[256])
|
||||
{
|
||||
if(address->type == NetAddress::IPAddress)
|
||||
{
|
||||
sockaddr_in ipAddr;
|
||||
netToIPSocketAddress(address, &ipAddr);
|
||||
|
||||
if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST))
|
||||
dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
|
||||
else
|
||||
dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr),
|
||||
ntohs(ipAddr.sin_port));
|
||||
// dSprintf(addressString, 256, "IP:%d:%d", ipAddr.sin_addr.s_addr,
|
||||
// ntohs(ipAddr.sin_port));
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d",
|
||||
address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3],
|
||||
address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5],
|
||||
address->port);
|
||||
}
|
||||
}
|
||||
|
||||
Net::Error getLastError()
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
return Net::WouldBlock;
|
||||
if (errno == 0)
|
||||
return Net::NoError;
|
||||
|
||||
return Net::UnknownError;
|
||||
}
|
819
engine/platformMacCarb/macCarbOGLVideo.cc
Executable file
819
engine/platformMacCarb/macCarbOGLVideo.cc
Executable file
@ -0,0 +1,819 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//
|
||||
// Portions taken from OpenGL Full Screen.c sample from Apple Computer, Inc.
|
||||
// (that's where many of the lead helper functions originated from, but code
|
||||
// has been significantly changed & revised.)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platformMacCarb/platformGL.h"
|
||||
#include "platformMacCarb/maccarbOGLVideo.h"
|
||||
#include "console/console.h"
|
||||
#include "math/mPoint.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "console/ast.h"
|
||||
#include "core/fileStream.h"
|
||||
#include "platformMacCarb/macCarbUtil.h"
|
||||
#include "platformMacCarb/macCarbEvents.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
// TODO: Card Profiling code isn't doing anything.
|
||||
|
||||
AGLContext agl_ctx;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// prototypes and globals -- !!!!!!TBD - globals should mostly go away, into platState.
|
||||
//-----------------------------------------------------------------------------------------
|
||||
GLenum dumpAGLDebugStr (void);
|
||||
GLenum dumpGLDebugStr (void);
|
||||
|
||||
void dumpPixelFormatList(AGLPixelFormat fmt);
|
||||
|
||||
#pragma mark -
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// if error dump agl errors to debugger string, return error
|
||||
//-----------------------------------------------------------------------------------------
|
||||
GLenum dumpAGLDebugStr (void)
|
||||
{
|
||||
GLenum err = aglGetError();
|
||||
if (err != AGL_NO_ERROR)
|
||||
Con::errorf ((char *)aglErrorString(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// if error dump gl errors to debugger string, return error
|
||||
//-----------------------------------------------------------------------------------------
|
||||
GLenum dumpGLDebugStr (void)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (GL_NO_ERROR != err)
|
||||
Con::errorf ((char *)gluErrorString(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Creates a dummy AGL context, so that naughty objects that call OpenGL before the window
|
||||
// exists will not crash the game.
|
||||
// If for some reason we fail to get a default contet, assert -- something's very wrong.
|
||||
//-----------------------------------------------------------------------------------------
|
||||
void initDummyAgl(void)
|
||||
{
|
||||
short i = 0;
|
||||
GLint attrib[64];
|
||||
AGLPixelFormat fmt;
|
||||
AGLContext ctx;
|
||||
|
||||
// clear the existing agl context
|
||||
if(platState.ctx != NULL)
|
||||
aglDestroyContext(platState.ctx);
|
||||
platState.ctx = NULL;
|
||||
agl_ctx = NULL;
|
||||
|
||||
// set up an attribute array for the pixel format.
|
||||
attrib [i++] = AGL_RGBA; // red green blue and alpha
|
||||
attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
|
||||
attrib [i++] = AGL_NONE; // terminate the list.
|
||||
|
||||
// choose a pixel format that works for any current display device, and matches
|
||||
// the attributes above as closely as possible.
|
||||
fmt = aglChoosePixelFormat(NULL, 0, attrib);
|
||||
dumpAGLDebugStr ();
|
||||
AssertFatal(fmt, "Could not find a valid default pixel format in initDummyAgl()");
|
||||
|
||||
|
||||
dumpPixelFormatList(fmt);
|
||||
|
||||
// create an agl context. NULL = don't share resouces with any other context.
|
||||
ctx = aglCreateContext (fmt, NULL);
|
||||
dumpAGLDebugStr ();
|
||||
AssertFatal(ctx, "Could not create a default agl context in initDummyAgl()");
|
||||
|
||||
// make gl calls go to our dummy context
|
||||
if (!aglSetCurrentContext (ctx))
|
||||
{
|
||||
dumpAGLDebugStr ();
|
||||
AssertFatal(false,"Could not set a default agl context as the current context.");
|
||||
}
|
||||
|
||||
// pixel format is no longer needed once the context has been created
|
||||
aglDestroyPixelFormat(fmt);
|
||||
|
||||
platState.ctx = ctx;
|
||||
agl_ctx = ctx; // maintain up aglMacro.h context
|
||||
|
||||
}
|
||||
|
||||
GDHandle allDevs[32];
|
||||
U32 nAllDevs;
|
||||
|
||||
AGLPixelFormat findValidPixelFormat(bool fullscreen, U32 bpp, U32 samples, bool recovery = true)
|
||||
{
|
||||
AssertWarn(bpp==16 || bpp==32 || bpp==0, "An unusual bit depth was requested in findValidPixelFormat(). clamping to 16|32");
|
||||
if(bpp)
|
||||
bpp = bpp > 16 ? 32 : 16;
|
||||
|
||||
AssertWarn(samples <= 6, "An unusual multisample depth was requested in findValidPixelFormat(). clamping to 0...6");
|
||||
samples = samples > 6 ? 6 : samples;
|
||||
|
||||
// create an agl pixel format
|
||||
int i = 0;
|
||||
GLint attr[64];
|
||||
AGLPixelFormat fmt;
|
||||
|
||||
// basic hardware accelerated format options
|
||||
attr[i++] = AGL_RGBA; // red green blue and alpha format
|
||||
attr[i++] = AGL_DOUBLEBUFFER; // double buffered format
|
||||
attr[i++] = AGL_ACCELERATED; // ask for hardware acceleration
|
||||
attr[i++] = AGL_NO_RECOVERY; // prohibit use of a software rendering fallback
|
||||
// request fullscreen capable format if needed
|
||||
if(fullscreen)
|
||||
attr[i++] = AGL_FULLSCREEN;
|
||||
|
||||
if(bpp != 0)
|
||||
{
|
||||
// native pixel formats are argb 1555 & argb 8888.
|
||||
U32 colorbits = 0;
|
||||
U32 alphabits = 0;
|
||||
if(bpp == 16)
|
||||
{
|
||||
colorbits = 5; // ARGB 1555
|
||||
alphabits = 1;
|
||||
}
|
||||
else if(bpp == 32)
|
||||
colorbits = alphabits = 8; // ARGB 8888
|
||||
|
||||
attr[i++] = AGL_DEPTH_SIZE;
|
||||
attr[i++] = bpp;
|
||||
attr[i++] = AGL_PIXEL_SIZE;
|
||||
attr[i++] = bpp;
|
||||
|
||||
attr[i++] = AGL_RED_SIZE;
|
||||
attr[i++] = colorbits;
|
||||
attr[i++] = AGL_GREEN_SIZE;
|
||||
attr[i++] = colorbits;
|
||||
attr[i++] = AGL_BLUE_SIZE;
|
||||
attr[i++] = colorbits;
|
||||
attr[i++] = AGL_ALPHA_SIZE;
|
||||
attr[i++] = alphabits;
|
||||
}
|
||||
|
||||
if(samples != 0)
|
||||
{
|
||||
attr[i++] = AGL_SAMPLE_BUFFERS_ARB; // number of multisample buffers
|
||||
attr[i++] = 1; // currently only 1 is supported
|
||||
attr[i++] = AGL_SAMPLES_ARB; // number of samples per pixel
|
||||
attr[i++] = samples + samples % 2; // must be 2, 4, 6 ...
|
||||
}
|
||||
|
||||
attr[i++] = AGL_NONE; // null-terminate the list
|
||||
|
||||
fmt = aglChoosePixelFormat(&platState.hDisplay, 1, attr);
|
||||
dumpAGLDebugStr();
|
||||
|
||||
if(!fmt && recovery)
|
||||
{
|
||||
// recovery.
|
||||
// first try ignoring samples. then try ignoring the bit depth.
|
||||
// we'll try the following order:
|
||||
// specified bit depth, specified multisample depth
|
||||
// specified bit depth, lower/no multisample
|
||||
// any bit depth, specified multisample depth
|
||||
// any bit depth, lower/no multisample
|
||||
|
||||
// downgrade multisample, trying for a valid format
|
||||
for(int fewerSamples = samples - 1; !fmt && fewerSamples >=0; fewerSamples--)
|
||||
{
|
||||
Con::errorf("error selecting pixel format, trying again with %s, bpp=%i, multisample level=%i",
|
||||
fullscreen ? "fullscreen" : "windowed", bpp, fewerSamples);
|
||||
fmt = findValidPixelFormat(fullscreen, bpp, fewerSamples, false);
|
||||
}
|
||||
|
||||
// allow any bit depth, send in requested multisample level, and ALLOW RECOVERY.
|
||||
// if this attempt fails, we'll hit the above 'downgrade multisample' block in the recursion.
|
||||
if(!fmt && bpp != 0)
|
||||
{
|
||||
Con::warnf("error selecting pixel format, trying again with %s, bpp=%i, multisample level=%i",
|
||||
fullscreen ? "fullscreen" : "windowed", 0, samples);
|
||||
fmt = findValidPixelFormat(fullscreen, 0, samples, true);
|
||||
}
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
void dumpPixelFormat(AGLPixelFormat fmt)
|
||||
{
|
||||
Con::printf(" ------------------------------------------------------------");
|
||||
Con::printf("Describing pixel format 0x%x", fmt);
|
||||
GLint val;
|
||||
#define DumpAGLPixelFormatAttr(attr) \
|
||||
aglDescribePixelFormat(fmt, AGL_##attr, &val); \
|
||||
dumpAGLDebugStr(); \
|
||||
Con::printf(" %20s %4i", #attr ,val);
|
||||
|
||||
DumpAGLPixelFormatAttr(ALL_RENDERERS);
|
||||
DumpAGLPixelFormatAttr(BUFFER_SIZE);
|
||||
DumpAGLPixelFormatAttr(LEVEL);
|
||||
DumpAGLPixelFormatAttr(RGBA);
|
||||
DumpAGLPixelFormatAttr(DOUBLEBUFFER)
|
||||
DumpAGLPixelFormatAttr(STEREO);
|
||||
DumpAGLPixelFormatAttr(AUX_BUFFERS);
|
||||
DumpAGLPixelFormatAttr(GREEN_SIZE);
|
||||
DumpAGLPixelFormatAttr(RED_SIZE);
|
||||
DumpAGLPixelFormatAttr(BLUE_SIZE);
|
||||
DumpAGLPixelFormatAttr(ALPHA_SIZE);
|
||||
DumpAGLPixelFormatAttr(DEPTH_SIZE);
|
||||
DumpAGLPixelFormatAttr(STENCIL_SIZE);
|
||||
DumpAGLPixelFormatAttr(ACCUM_RED_SIZE);
|
||||
DumpAGLPixelFormatAttr(ACCUM_GREEN_SIZE);
|
||||
DumpAGLPixelFormatAttr(ACCUM_BLUE_SIZE);
|
||||
DumpAGLPixelFormatAttr(ACCUM_ALPHA_SIZE);
|
||||
|
||||
DumpAGLPixelFormatAttr(PIXEL_SIZE);
|
||||
DumpAGLPixelFormatAttr(MINIMUM_POLICY);
|
||||
DumpAGLPixelFormatAttr(MAXIMUM_POLICY);
|
||||
DumpAGLPixelFormatAttr(OFFSCREEN);
|
||||
DumpAGLPixelFormatAttr(FULLSCREEN);
|
||||
DumpAGLPixelFormatAttr(SAMPLE_BUFFERS_ARB);
|
||||
DumpAGLPixelFormatAttr(SAMPLES_ARB);
|
||||
DumpAGLPixelFormatAttr(AUX_DEPTH_STENCIL);
|
||||
DumpAGLPixelFormatAttr(COLOR_FLOAT);
|
||||
DumpAGLPixelFormatAttr(MULTISAMPLE);
|
||||
DumpAGLPixelFormatAttr(SUPERSAMPLE);
|
||||
DumpAGLPixelFormatAttr(SAMPLE_ALPHA);
|
||||
|
||||
#undef DumpAGLPixelFormatAttr
|
||||
Con::printf(" ------------------------------------------------------------");
|
||||
}
|
||||
|
||||
void dumpPixelFormatList(AGLPixelFormat fmt)
|
||||
{
|
||||
Con::printf("Dumping list of pixel formats:");
|
||||
while(fmt!=NULL)
|
||||
{
|
||||
dumpPixelFormat(fmt);
|
||||
fmt = aglNextPixelFormat(fmt);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
//------------------------------------------------------------------------------
|
||||
OpenGLDevice::OpenGLDevice()
|
||||
{
|
||||
// Set the device name:
|
||||
mDeviceName = "OpenGL";
|
||||
|
||||
// macs games are not generally full screen only
|
||||
mFullScreenOnly = false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void OpenGLDevice::initDevice()
|
||||
{
|
||||
// pick a monitor to run on
|
||||
enumMonitors();
|
||||
|
||||
// choose a monitor at save it in the plat state
|
||||
platState.hDisplay = chooseMonitor();
|
||||
platState.cgDisplay = MacCarbGetCGDisplayFromQDDisplay(platState.hDisplay);
|
||||
|
||||
// figure out & cache what Resolution's this card-monitor combo can support
|
||||
enumDisplayModes(platState.cgDisplay);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Fill Vector<Resolution> mResoultionList with list of supported modes
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::enumDisplayModes(CGDirectDisplayID display)
|
||||
{
|
||||
mResolutionList.clear();
|
||||
|
||||
// get the display, and the list of all available modes.
|
||||
CFArrayRef modeArray = CGDisplayAvailableModes(display);
|
||||
if(!modeArray)
|
||||
{
|
||||
// we're probably in headless mode. still, best not to leave the list emtpy.
|
||||
Resolution headless( 640, 480, 32 );
|
||||
mResolutionList.push_back( headless );
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = CFArrayGetCount(modeArray);
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
// get this mode.
|
||||
CFNumberRef num;
|
||||
int width, height, bpp;
|
||||
CFDictionaryRef mode = (CFDictionaryRef) CFArrayGetValueAtIndex(modeArray,i);
|
||||
|
||||
// get width
|
||||
num = CFDictionaryGetValue( mode, kCGDisplayWidth );
|
||||
CFNumberGetValue(num, kCFNumberLongType,&width);
|
||||
|
||||
// get height
|
||||
num = CFDictionaryGetValue( mode, kCGDisplayHeight );
|
||||
CFNumberGetValue(num, kCFNumberLongType,&height);
|
||||
|
||||
// get bpp
|
||||
num = CFDictionaryGetValue( mode, kCGDisplayBitsPerPixel );
|
||||
CFNumberGetValue(num, kCFNumberLongType,&bpp);
|
||||
|
||||
// add to the list
|
||||
if( bpp != 8 )
|
||||
{
|
||||
Resolution newRes( width, height, bpp );
|
||||
mResolutionList.push_back( newRes );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // fill it with some standard sizes for a machine, just to have them available.
|
||||
// Point sizes[4] = {{640,480},{800,600},{1024,768},{1280,1024}};
|
||||
// for(int i=0; i<4; i++)
|
||||
// {
|
||||
// // Point is { short v, short h }, so we have to reverse the h and v here, sorry for any confusion.
|
||||
// Resolution newRes16( sizes[i].v, sizes[i].h, 16 );
|
||||
// Resolution newRes32( sizes[i].v, sizes[i].h, 32 );
|
||||
// mResolutionList.push_back( newRes16 );
|
||||
// mResolutionList.push_back( newRes32 );
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Fill mMonitorList with list of supported modes
|
||||
// Guaranteed to include at least the main device.
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::enumMonitors()
|
||||
{
|
||||
// DMGetFirstScreenDevice() et al are deprecated as of 10.4, but we need them
|
||||
// for AGL, which operates on GDHandle's for displays.
|
||||
// As far as I know, you can get a CGDirectDisplayID from a GDHandle,
|
||||
// but not the other way around.
|
||||
mMonitorList.clear();
|
||||
GDHandle dev = DMGetFirstScreenDevice( true );
|
||||
nAllDevs = 0;
|
||||
while( dev )
|
||||
{
|
||||
Con::printf( " active displays = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
|
||||
mMonitorList.push_back(dev);
|
||||
allDevs[nAllDevs++] = dev;
|
||||
dev = DMGetNextScreenDevice( dev, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Chooses a monitor based on $pref, on the results of tors(), & on the
|
||||
// current window's screen.
|
||||
//------------------------------------------------------------------------------
|
||||
GDHandle OpenGLDevice::chooseMonitor()
|
||||
{
|
||||
// TODO: choose monitor based on which one contains most of the window.
|
||||
// NOTE: do not call cleanup before calling choose, or we won't have a window to consider.
|
||||
AssertFatal(!mMonitorList.empty(), "Cannot choose a monitor if the list is empty!");
|
||||
|
||||
U32 monNum = Con::getIntVariable("$pref::Video::monitorNum", 0);
|
||||
if(monNum >= mMonitorList.size())
|
||||
{
|
||||
Con::errorf("invalid monitor number %i", monNum);
|
||||
monNum = 0;
|
||||
Con::setIntVariable("$pref::Video::monitorNum", 0);
|
||||
}
|
||||
Con::printf("using display 0x%x", mMonitorList[monNum]);
|
||||
return mMonitorList[monNum];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Activate
|
||||
// this is called once, as a result of createCanvas() in scripts.
|
||||
// dumps OpenGL driver info for the current screen
|
||||
// creates an initial window via setScreenMode
|
||||
bool OpenGLDevice::activate( U32 width, U32 height, U32 bpp, bool fullScreen )
|
||||
{
|
||||
Con::printf( " OpenGLDevice activating..." );
|
||||
|
||||
// Never unload a code module. This makes destroying & recreating contexts faster.
|
||||
aglConfigure(AGL_RETAIN_RENDERERS, GL_TRUE);
|
||||
|
||||
// gets opengl rendering capabilities of the screen pointed to by platState.hDisplay
|
||||
// sets up dgl with the capabilities info, & reports opengl status.
|
||||
getGLCapabilities();
|
||||
|
||||
// Create the window or capture fullscreen
|
||||
if(!setScreenMode( width, height, bpp, fullScreen, true, false ))
|
||||
return false;
|
||||
|
||||
// set the displayDevice pref to "OpenGL"
|
||||
Con::setVariable( "$pref::Video::displayDevice", mDeviceName );
|
||||
|
||||
// set vertical sync now because it doesnt need setting every time we setScreenMode()
|
||||
setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// returns TRUE if textures need resurrecting in future...
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::cleanupContextAndWindow()
|
||||
{
|
||||
bool needResurrect = false;
|
||||
|
||||
Con::printf( "Cleaning up the display device..." );
|
||||
|
||||
// Delete the rendering context and it's specific data.
|
||||
if (platState.ctx)
|
||||
{
|
||||
// The OpenGL texture handles are specific to each context.
|
||||
// We'll need to get new ones for a new context, so kill the texture manager to clear 'em.
|
||||
if (!Video::smNeedResurrect)
|
||||
{
|
||||
Con::printf( "Killing the texture manager..." );
|
||||
Game->textureKill();
|
||||
needResurrect = true;
|
||||
}
|
||||
|
||||
// make the agl context not-current, which stops openGL calls from going anywhere.
|
||||
Con::printf( "Clearing the current AGL context..." );
|
||||
aglSetCurrentContext(NULL);
|
||||
#if defined(USE_AGL_MACRO)
|
||||
agl_ctx = NULL; // maintain aglMacro.h context
|
||||
#endif
|
||||
|
||||
// detatch the agl context from it's window
|
||||
Con::printf( "Clearing the current drawable..." );
|
||||
aglSetDrawable(platState.ctx, NULL);
|
||||
|
||||
// delete the context
|
||||
Con::printf( "Deleting the rendering context..." );
|
||||
aglDestroyContext(platState.ctx);
|
||||
|
||||
// clear our handle to the context
|
||||
platState.ctx = NULL;
|
||||
}
|
||||
|
||||
// delete the app window if it exists
|
||||
if ( platState.appWindow )
|
||||
{
|
||||
Con::printf( "Destroying the window..." );
|
||||
MacCarbFadeAndReleaseWindow(platState.appWindow);
|
||||
platState.appWindow = NULL;
|
||||
}
|
||||
|
||||
// clear the Resolution state, so setScreenMode() will know not to early-out.
|
||||
smCurrentRes = Resolution(0,0,0);
|
||||
|
||||
return(needResurrect);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void OpenGLDevice::shutdown()
|
||||
{
|
||||
Con::printf( "Shutting down the OpenGL display device..." );
|
||||
|
||||
// clean up the context, the window, and kill the texture manager
|
||||
cleanupContextAndWindow();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This is the real workhorse function of the DisplayDevice...
|
||||
//
|
||||
bool OpenGLDevice::setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt, bool repaint )
|
||||
{
|
||||
Con::printf(" set screen mode %i x %i x %i, %s, %s, %s",width, height, bpp,
|
||||
fullScreen ? "fullscreen" : "windowed",
|
||||
forceIt ? "force it" : "dont force it",
|
||||
repaint ? "repaint" : "dont repaint"
|
||||
);
|
||||
|
||||
// validation, early outs --------------------------------------------------
|
||||
// sanity check. some scripts are liable to pass in bad values.
|
||||
if(!bpp)
|
||||
bpp = platState.desktopBitsPixel;
|
||||
|
||||
Resolution newRes = Resolution(width, height, bpp);
|
||||
|
||||
// if no values changing and we're not forcing a change, kick out. prevents thrashing.
|
||||
if(!forceIt && smIsFullScreen == fullScreen && smCurrentRes == newRes)
|
||||
return(true);
|
||||
|
||||
// we have a new context, this is now safe to do:
|
||||
// delete any contexts or windows that exist, and kill the texture manager.
|
||||
bool needResurrect = cleanupContextAndWindow();
|
||||
|
||||
Con::printf( ">> Attempting to change display settings to %s %dx%dx%d...",
|
||||
fullScreen?"fullscreen":"windowed", newRes.w, newRes.h, newRes.bpp );
|
||||
|
||||
// monitor selection -------------------------------------------------------
|
||||
// set our preferred monitor. default is the screen that has the menu bar.
|
||||
GDHandle prevDisplay = platState.hDisplay;
|
||||
platState.hDisplay = chooseMonitor();
|
||||
platState.cgDisplay = MacCarbGetCGDisplayFromQDDisplay(platState.hDisplay);
|
||||
AssertFatal(platState.hDisplay,"We chose a null monitor? Panic!");
|
||||
|
||||
// if we're changing screens, we must know what the new one is capable of
|
||||
if(prevDisplay != platState.hDisplay)
|
||||
{
|
||||
enumDisplayModes(platState.cgDisplay);
|
||||
getGLCapabilities();
|
||||
}
|
||||
|
||||
// create an agl rendering context ------------------------------------------
|
||||
AGLPixelFormat fmt = NULL;
|
||||
AGLContext ctx = NULL;
|
||||
|
||||
// select pixel format. fall back to more generic options until we get something.
|
||||
fmt = findValidPixelFormat(fullScreen, bpp, 0);
|
||||
AssertFatal(fmt, "We utterly failed to choose a valid AGL pixel format.");
|
||||
|
||||
// print out the pixel format list we got.
|
||||
//dumpPixelFormatList(fmt);
|
||||
|
||||
// create the agl rendering context
|
||||
ctx = aglCreateContext(fmt, NULL);
|
||||
dumpAGLDebugStr();
|
||||
AssertISV( ctx, "We could not create a valid AGL rendering context.");
|
||||
if(!ctx)
|
||||
return false;
|
||||
|
||||
// format is not needed once we have a context.
|
||||
aglDestroyPixelFormat(fmt);
|
||||
|
||||
if(fullScreen && platState.captureDisplay)
|
||||
{
|
||||
// capture main display & go to full screen mode
|
||||
// TODO: allow frequency selection?
|
||||
aglSetFullScreen(ctx, newRes.w, newRes.h, 0, 0);
|
||||
dumpAGLDebugStr();
|
||||
Con::printf("set AGL fullscreen");
|
||||
MacCarbShowMenuBar(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a window, get it's drawable, and attach our context to the window
|
||||
bool isFullscreenWindow = (fullScreen && !platState.captureDisplay);
|
||||
platState.appWindow = MacCarbCreateOpenGLWindow( platState.hDisplay, newRes.w, newRes.h, isFullscreenWindow );
|
||||
if(!platState.appWindow)
|
||||
{
|
||||
Con::errorf("OpenGLDevice::setScreenMode - Failed to create a new window!");
|
||||
return false;
|
||||
}
|
||||
CGrafPtr drawable = GetWindowPort(platState.appWindow);
|
||||
aglSetDrawable(ctx, drawable);
|
||||
dumpAGLDebugStr();
|
||||
Con::printf("Set up AGL windowed support");
|
||||
}
|
||||
|
||||
// send opengl commands to this context.
|
||||
aglSetCurrentContext(ctx);
|
||||
#if defined(USE_AGL_MACRO)
|
||||
agl_ctx = ctx; // maintain aglMacro.h context
|
||||
#endif
|
||||
// save the context
|
||||
platState.ctx = ctx;
|
||||
|
||||
// clear out garbage from the gl window.
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT );
|
||||
Con::printf("Cleared gl buffers");
|
||||
|
||||
// set opengl options & other options ---------------------------------------
|
||||
// ensure data is packed tightly in memory. this defaults to 4.
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
// TODO: set gl arb multisample enable & hint
|
||||
dglSetFSAASamples(gFSAASamples);
|
||||
// set vertical sync
|
||||
setVerticalSync(!Con::getBoolVariable( "$pref::Video::disableVerticalSync" ));
|
||||
|
||||
// set torque variables ----------------------------------------------------
|
||||
// save window size for dgl
|
||||
Platform::setWindowSize( newRes.w, newRes.h );
|
||||
// update smIsFullScreen and pref
|
||||
smIsFullScreen = fullScreen;
|
||||
Con::setBoolVariable( "$pref::Video::fullScreen", smIsFullScreen );
|
||||
// save resolution
|
||||
smCurrentRes = newRes;
|
||||
// save resolution to prefs
|
||||
char buf[32];
|
||||
if(fullScreen)
|
||||
{
|
||||
dSprintf( buf, sizeof(buf), "%d %d %d", newRes.w, newRes.h, newRes.bpp);
|
||||
Con::setVariable("$pref::Video::resolution", buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
dSprintf( buf, sizeof(buf), "%d %d", newRes.w, newRes.h);
|
||||
Con::setVariable("$pref::Video::windowedRes", buf);
|
||||
}
|
||||
|
||||
// fade the window into existance, asynchronously
|
||||
if(platState.appWindow)
|
||||
MacCarbFadeInWindow(platState.appWindow);
|
||||
|
||||
|
||||
// begin rendering again ----------------------------------------------------
|
||||
if( needResurrect )
|
||||
{
|
||||
// Reload the textures gl names
|
||||
Con::printf( "Resurrecting the texture manager..." );
|
||||
Game->textureResurrect();
|
||||
}
|
||||
|
||||
// reattach the event handlers to the new window.
|
||||
MacCarbRemoveCarbonEventHandlers();
|
||||
MacCarbInstallCarbonEventHandlers();
|
||||
|
||||
if( repaint )
|
||||
Con::evaluate( "resetCanvas();" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void OpenGLDevice::swapBuffers()
|
||||
{
|
||||
if (platState.ctx)
|
||||
aglSwapBuffers(platState.ctx);
|
||||
#if defined(TORQUE_DEBUG)
|
||||
if(gOutlineEnabled)
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* OpenGLDevice::getDriverInfo()
|
||||
{
|
||||
// Prepare some driver info for the console:
|
||||
const char* vendorString = (const char*) glGetString( GL_VENDOR );
|
||||
const char* rendererString = (const char*) glGetString( GL_RENDERER );
|
||||
const char* versionString = (const char*) glGetString( GL_VERSION );
|
||||
const char* extensionsString = (const char*) glGetString( GL_EXTENSIONS );
|
||||
|
||||
U32 bufferLen = ( vendorString ? dStrlen( vendorString ) : 0 )
|
||||
+ ( rendererString ? dStrlen( rendererString ) : 0 )
|
||||
+ ( versionString ? dStrlen( versionString ) : 0 )
|
||||
+ ( extensionsString ? dStrlen( extensionsString ) : 0 )
|
||||
+ 4;
|
||||
|
||||
char* returnString = Con::getReturnBuffer( bufferLen );
|
||||
dSprintf( returnString, bufferLen, "%s\t%s\t%s\t%s",
|
||||
( vendorString ? vendorString : "" ),
|
||||
( rendererString ? rendererString : "" ),
|
||||
( versionString ? versionString : "" ),
|
||||
( extensionsString ? extensionsString : "" ) );
|
||||
|
||||
return( returnString );
|
||||
}
|
||||
|
||||
typedef struct MacCarbGamma
|
||||
{
|
||||
F32 r, g, b;
|
||||
F32 scale;
|
||||
};
|
||||
|
||||
static MacCarbGamma _MacGamma;
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::getGammaCorrection(F32 &g)
|
||||
{
|
||||
// rgb gamma exponents
|
||||
CGGammaValue red,green,blue;
|
||||
// rgb min & max gamma. we'll ignore these for the present.
|
||||
CGGammaValue rm, rx, gm, gx, bm, bx;
|
||||
// grab the gamma values
|
||||
CGDirectDisplayID display = platState.cgDisplay;
|
||||
CGGetDisplayTransferByFormula(display, &rm, &rx, &red, &gm, &gx, &green, &bm, &bx, &blue);
|
||||
|
||||
// save the original gamma vals, and the current scale.
|
||||
static bool once = true;
|
||||
if(once)
|
||||
{
|
||||
once = false;
|
||||
_MacGamma.r = red;
|
||||
_MacGamma.g = green;
|
||||
_MacGamma.b = blue;
|
||||
_MacGamma.scale = 1.0;
|
||||
}
|
||||
|
||||
g = _MacGamma.scale;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::setGammaCorrection(F32 g)
|
||||
{
|
||||
// revert to default colorsync settings if g approaches 1.0
|
||||
F32 epsilon = 0.01f;
|
||||
if( mFabs(g - 1.0) <= epsilon )
|
||||
{
|
||||
CGDisplayRestoreColorSyncSettings();
|
||||
return false;
|
||||
}
|
||||
|
||||
// rgb gamma exponents
|
||||
CGGammaValue red,green,blue;
|
||||
// rgb min & max gamma. we'll ignore these for the present.
|
||||
CGGammaValue rm, rx, gm, gx, bm, bx;
|
||||
CGGetDisplayTransferByFormula(platState.cgDisplay, &rm, &rx, &red, &gm, &gx, &green, &bm, &bx, &blue);
|
||||
// scale the original gamma values.
|
||||
red = _MacGamma.r * g;
|
||||
green = _MacGamma.g * g;
|
||||
blue = _MacGamma.b * g;
|
||||
_MacGamma.scale = g;
|
||||
// set the gamma.
|
||||
CGSetDisplayTransferByFormula(platState.cgDisplay, rm, rx, red, gm, gx, green, bm, bx, blue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool OpenGLDevice::setVerticalSync( bool on )
|
||||
{
|
||||
if (!platState.ctx)
|
||||
return false;
|
||||
|
||||
bool ret = aglSetInteger(platState.ctx, AGL_SWAP_INTERVAL, (GLint*)&on);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
DisplayDevice* OpenGLDevice::create()
|
||||
{
|
||||
// set up a dummy default agl context.
|
||||
// this will be replaced later with the window's context,
|
||||
// but we need agl_ctx to be valid at all times,
|
||||
// since some things try to make gl calls before the device is activated.
|
||||
initDummyAgl();
|
||||
|
||||
// create the DisplayDevice
|
||||
OpenGLDevice* newOGLDevice = new OpenGLDevice();
|
||||
|
||||
// gather monitor & resolution info
|
||||
// delegated out to initDevice() in case the display config changes.
|
||||
newOGLDevice->initDevice();
|
||||
|
||||
return newOGLDevice;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
Resolution Video::getDesktopResolution()
|
||||
{
|
||||
Resolution res;
|
||||
Rect r = (**platState.hDisplay).gdRect;
|
||||
res.w = r.right - r.left;
|
||||
res.h = r.bottom - r.top;
|
||||
res.bpp = (**(**platState.hDisplay).gdPMap).pixelSize;
|
||||
|
||||
platState.desktopWidth = res.w;
|
||||
platState.desktopHeight = res.h;
|
||||
platState.desktopBitsPixel = res.bpp;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
ConsoleFunction( dumpDisplayIDs, void, 1,1, "")
|
||||
{
|
||||
Con::errorf("=-== Dumping display ids =-==");
|
||||
GDHandle dev = GetMainDevice();
|
||||
Con::printf("main display GetMainDevice = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
|
||||
|
||||
dev = DMGetFirstScreenDevice( true );
|
||||
Con::printf( "first active display = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
|
||||
while( ( dev = DMGetNextScreenDevice( dev, true)) != NULL)
|
||||
{
|
||||
Con::printf( " active displays = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
|
||||
}
|
||||
|
||||
|
||||
CGDirectDisplayID mainid = CGMainDisplayID();
|
||||
Con::printf("main display CGMainDisplayID = 0x%x", mainid);
|
||||
|
||||
CGDirectDisplayID lastDisplay, displayArray[64] ;
|
||||
CGDisplayCount numDisplays ;
|
||||
|
||||
CGGetActiveDisplayList( 64, displayArray, &numDisplays );
|
||||
for(int i=0; i< numDisplays; i++)
|
||||
{
|
||||
mainid = displayArray[i];
|
||||
Con::printf(" CG active display list CGMainDisplayID = 0x%x", mainid);
|
||||
|
||||
}
|
||||
}
|
||||
|
49
engine/platformMacCarb/macCarbOGLVideo.h
Executable file
49
engine/platformMacCarb/macCarbOGLVideo.h
Executable file
@ -0,0 +1,49 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBOGLVIDEO_H_
|
||||
#define _MACCARBOGLVIDEO_H_
|
||||
|
||||
#include "platform/platformVideo.h"
|
||||
|
||||
class OpenGLDevice : public DisplayDevice
|
||||
{
|
||||
private:
|
||||
|
||||
/// Handles to all the devices ( monitors ) attached to the system.
|
||||
Vector<GDHandle> mMonitorList;
|
||||
/// Gamma value
|
||||
F32 mGamma;
|
||||
|
||||
|
||||
/// Fills mResolutionList with a list of valid resolutions for a particular screen
|
||||
bool enumDisplayModes(CGDirectDisplayID hDevice);
|
||||
/// Fills mMonitorList with all available monitors
|
||||
bool enumMonitors();
|
||||
/// Chooses a monitor based on $pref::the results of enumMontors()
|
||||
GDHandle chooseMonitor();
|
||||
/// Cleans up the opengl context, and destroys the rendering window
|
||||
bool cleanupContextAndWindow();
|
||||
|
||||
public:
|
||||
OpenGLDevice();
|
||||
static DisplayDevice* create();
|
||||
|
||||
/// The following are inherited from DisplayDevice
|
||||
void initDevice();
|
||||
bool activate( U32 width, U32 height, U32 bpp, bool fullScreen );
|
||||
|
||||
void shutdown();
|
||||
|
||||
bool setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt = false, bool repaint = true );
|
||||
void swapBuffers();
|
||||
|
||||
const char* getDriverInfo();
|
||||
bool getGammaCorrection(F32 &g);
|
||||
bool setGammaCorrection(F32 g);
|
||||
bool setVerticalSync( bool on );
|
||||
};
|
||||
|
||||
#endif // _MACCARBOGLVIDEO_H_
|
220
engine/platformMacCarb/macCarbOutlineGL.cc
Executable file
220
engine/platformMacCarb/macCarbOutlineGL.cc
Executable file
@ -0,0 +1,220 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// The debug render modes are only built in a debug build,
|
||||
// partially because a release build should not need them
|
||||
// and partially because using aglMacro.h or cglMacro.h would prevent us from
|
||||
// playing this little function-pointer-hijacking trick
|
||||
#if defined(TORQUE_DEBUG)
|
||||
|
||||
#define NO_REDEFINE_GL_FUNCS
|
||||
|
||||
#include "platformMacCarb/platformGL.h"
|
||||
#include "console/console.h"
|
||||
|
||||
bool gOutlineEnabled = false;
|
||||
|
||||
void (* glDrawElementsProcPtr) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
|
||||
void (* glDrawArraysProcPtr) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;
|
||||
void (* glNormDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
|
||||
void (* glNormDrawArrays) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;
|
||||
|
||||
|
||||
/// A utility for the outline drawing routines
|
||||
static U32 getIndex(GLenum type, const void *indices, U32 i)
|
||||
{
|
||||
if(type == GL_UNSIGNED_BYTE)
|
||||
return ((U8 *) indices)[i];
|
||||
else if(type == GL_UNSIGNED_SHORT)
|
||||
return ((U16 *) indices)[i];
|
||||
else
|
||||
return ((U32 *) indices)[i];
|
||||
}
|
||||
|
||||
void glOutlineDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
|
||||
{
|
||||
if(mode == GL_POLYGON)
|
||||
mode = GL_LINE_LOOP;
|
||||
|
||||
if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)
|
||||
glDrawElements( mode, count, type, indices );
|
||||
else
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
if(mode == GL_TRIANGLE_STRIP)
|
||||
{
|
||||
U32 i;
|
||||
for(i = 0; i < count - 1; i++)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i));
|
||||
glArrayElement(getIndex(type, indices, i + 1));
|
||||
if(i + 2 != count)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i));
|
||||
glArrayElement(getIndex(type, indices, i + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == GL_TRIANGLE_FAN)
|
||||
{
|
||||
for(U32 i = 1; i < count; i ++)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, 0));
|
||||
glArrayElement(getIndex(type, indices, i));
|
||||
if(i != count - 1)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i));
|
||||
glArrayElement(getIndex(type, indices, i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == GL_TRIANGLES)
|
||||
{
|
||||
for(U32 i = 3; i <= count; i += 3)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i - 3));
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
glArrayElement(getIndex(type, indices, i - 3));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
}
|
||||
}
|
||||
else if(mode == GL_QUADS)
|
||||
{
|
||||
for(U32 i = 4; i <= count; i += 4)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i - 4));
|
||||
glArrayElement(getIndex(type, indices, i - 3));
|
||||
glArrayElement(getIndex(type, indices, i - 3));
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
glArrayElement(getIndex(type, indices, i - 4));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
}
|
||||
}
|
||||
else if(mode == GL_QUAD_STRIP)
|
||||
{
|
||||
if(count < 4)
|
||||
return;
|
||||
glArrayElement(getIndex(type, indices, 0));
|
||||
glArrayElement(getIndex(type, indices, 1));
|
||||
for(U32 i = 4; i <= count; i += 2)
|
||||
{
|
||||
glArrayElement(getIndex(type, indices, i - 4));
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
|
||||
glArrayElement(getIndex(type, indices, i - 3));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
|
||||
glArrayElement(getIndex(type, indices, i - 2));
|
||||
glArrayElement(getIndex(type, indices, i - 1));
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void glOutlineDrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
{
|
||||
if(mode == GL_POLYGON)
|
||||
mode = GL_LINE_LOOP;
|
||||
|
||||
if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)
|
||||
glDrawArrays( mode, first, count );
|
||||
else
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
if(mode == GL_TRIANGLE_STRIP)
|
||||
{
|
||||
U32 i;
|
||||
for(i = 0; i < count - 1; i++)
|
||||
{
|
||||
glArrayElement(first + i);
|
||||
glArrayElement(first + i + 1);
|
||||
if(i + 2 != count)
|
||||
{
|
||||
glArrayElement(first + i);
|
||||
glArrayElement(first + i + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == GL_TRIANGLE_FAN)
|
||||
{
|
||||
for(U32 i = 1; i < count; i ++)
|
||||
{
|
||||
glArrayElement(first);
|
||||
glArrayElement(first + i);
|
||||
if(i != count - 1)
|
||||
{
|
||||
glArrayElement(first + i);
|
||||
glArrayElement(first + i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == GL_TRIANGLES)
|
||||
{
|
||||
for(U32 i = 3; i <= count; i += 3)
|
||||
{
|
||||
glArrayElement(first + i - 3);
|
||||
glArrayElement(first + i - 2);
|
||||
glArrayElement(first + i - 2);
|
||||
glArrayElement(first + i - 1);
|
||||
glArrayElement(first + i - 3);
|
||||
glArrayElement(first + i - 1);
|
||||
}
|
||||
}
|
||||
else if(mode == GL_QUADS)
|
||||
{
|
||||
for(U32 i = 4; i <= count; i += 4)
|
||||
{
|
||||
glArrayElement(first + i - 4);
|
||||
glArrayElement(first + i - 3);
|
||||
glArrayElement(first + i - 3);
|
||||
glArrayElement(first + i - 2);
|
||||
glArrayElement(first + i - 2);
|
||||
glArrayElement(first + i - 1);
|
||||
glArrayElement(first + i - 4);
|
||||
glArrayElement(first + i - 1);
|
||||
}
|
||||
}
|
||||
else if(mode == GL_QUAD_STRIP)
|
||||
{
|
||||
if(count < 4)
|
||||
return;
|
||||
glArrayElement(first + 0);
|
||||
glArrayElement(first + 1);
|
||||
for(U32 i = 4; i <= count; i += 2)
|
||||
{
|
||||
glArrayElement(first + i - 4);
|
||||
glArrayElement(first + i - 2);
|
||||
|
||||
glArrayElement(first + i - 3);
|
||||
glArrayElement(first + i - 1);
|
||||
|
||||
glArrayElement(first + i - 2);
|
||||
glArrayElement(first + i - 1);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleFunction(GLEnableOutline,void,2,2,"GLEnableOutline( true | false ) - sets whether to render wireframe")
|
||||
{
|
||||
gOutlineEnabled = dAtob(argv[1]);
|
||||
if(gOutlineEnabled)
|
||||
{
|
||||
glDrawElementsProcPtr = glOutlineDrawElements;
|
||||
glDrawArraysProcPtr = glOutlineDrawArrays;
|
||||
Con::printf("swapped to outline mode funcs");
|
||||
} else {
|
||||
glDrawElementsProcPtr = glDrawElements;
|
||||
glDrawArraysProcPtr = glDrawArrays;
|
||||
Con::printf("swapped to normal funcs");
|
||||
}
|
||||
}
|
||||
#endif
|
33
engine/platformMacCarb/macCarbOutlineGL.h
Executable file
33
engine/platformMacCarb/macCarbOutlineGL.h
Executable file
@ -0,0 +1,33 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __MACCARBOUTLINE__
|
||||
#define __MACCARBOUTLINE__
|
||||
|
||||
#if defined(TORQUE_DEBUG)
|
||||
#ifndef __GL_OUTLINE_FUNCS__
|
||||
#define __GL_OUTLINE_FUNCS__
|
||||
|
||||
extern bool gOutlineEnabled;
|
||||
|
||||
extern void (* glDrawElementsProcPtr) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
|
||||
extern void (* glDrawArraysProcPtr) (GLenum mode, GLint first, GLsizei count);
|
||||
|
||||
void glOutlineDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
|
||||
void glOutlineDrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
|
||||
extern void (* glNormDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
|
||||
extern void (* glNormDrawArrays) (GLenum mode, GLint first, GLsizei count);
|
||||
|
||||
#ifndef NO_REDEFINE_GL_FUNCS
|
||||
#define glDrawElements glDrawElementsProcPtr
|
||||
#define glDrawArrays glDrawArraysProcPtr
|
||||
#else
|
||||
#warning glDrawElements and glDrawArrays not redefined
|
||||
#endif // NO_REDEFINE_GL_FUNCS
|
||||
#endif // __GL_OUTLINE_FUNCS__
|
||||
#endif // TORQUE_DEBUG
|
||||
|
||||
#endif // __MACCARBOUTLINE__
|
65
engine/platformMacCarb/macCarbProcessControl.cc
Executable file
65
engine/platformMacCarb/macCarbProcessControl.cc
Executable file
@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "platformMacCarb/macCarbEvents.h"
|
||||
|
||||
|
||||
void Platform::postQuitMessage(const U32 in_quitVal)
|
||||
{
|
||||
// guard against multiple quit messages. Quit event flow gets complex.
|
||||
if(platState.quit)
|
||||
return;
|
||||
|
||||
platState.quit = true;
|
||||
Event quitEvent;
|
||||
quitEvent.type = QuitEventType;
|
||||
|
||||
Game->postEvent(quitEvent);
|
||||
|
||||
MacCarbRemoveCarbonEventHandlers();
|
||||
}
|
||||
|
||||
void Platform::debugBreak()
|
||||
{
|
||||
DebugStr("\pDEBUG_BREAK!");
|
||||
}
|
||||
|
||||
void Platform::forceShutdown(S32 returnValue)
|
||||
{
|
||||
exit(returnValue);
|
||||
}
|
||||
|
||||
void Platform::restartInstance()
|
||||
{
|
||||
// execl() leaves open file descriptors open, that's the main reason it's not
|
||||
// used here. We want to start fresh.
|
||||
|
||||
if( Game->isRunning() )
|
||||
{
|
||||
Con::errorf("The game is still running, we cant relaunch now!");
|
||||
return;
|
||||
}
|
||||
// get the path to the torque executable
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
CFURLRef execURL = CFBundleCopyExecutableURL(mainBundle);
|
||||
CFStringRef execString = CFURLCopyFileSystemPath(execURL, kCFURLPOSIXPathStyle);
|
||||
|
||||
// append ampersand so that we can launch without blocking.
|
||||
// encase in quotes so that spaces in the path are accepted.
|
||||
CFMutableStringRef mut = CFStringCreateMutableCopy(NULL, 0, execString);
|
||||
CFStringInsert(mut, 0, CFSTR("\""));
|
||||
CFStringAppend(mut, CFSTR("\" & "));
|
||||
|
||||
U32 len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(mut), kCFStringEncodingUTF8);
|
||||
char *execCString = new char[len+1];
|
||||
CFStringGetCString(mut, execCString, len, kCFStringEncodingUTF8);
|
||||
execCString[len] = '\0';
|
||||
|
||||
Con::printf("---- %s -----",execCString);
|
||||
system(execCString);
|
||||
}
|
100
engine/platformMacCarb/macCarbSemaphore.cc
Executable file
100
engine/platformMacCarb/macCarbSemaphore.cc
Executable file
@ -0,0 +1,100 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// platformSemaphore.h does not ask for any inter process communication,
|
||||
// and the posix semaphores require a file to be created on disk.
|
||||
// which could create annoyances if the appication crashes...
|
||||
// so we'll just roll our own semaphore here.
|
||||
|
||||
// note: this is not a bulletproof solution to the starving problem...
|
||||
// see: The Little Book of Semapores, by Allen B. Downey, at http://greenteapress.com/semaphores/
|
||||
|
||||
#include <pthread.h>
|
||||
#include "platform/platform.h"
|
||||
#include "platform/platformSemaphore.h"
|
||||
|
||||
|
||||
|
||||
typedef struct MacCarbSemaphore
|
||||
{
|
||||
pthread_mutex_t mDarkroom;
|
||||
// pthread_mutex_t mFoyer; // second lock, to help control starving.
|
||||
pthread_cond_t mCond;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
void * Semaphore::createSemaphore(U32 initialCount)
|
||||
{
|
||||
bool ok;
|
||||
MacCarbSemaphore *semaphore = new MacCarbSemaphore();
|
||||
ok = pthread_mutex_init(&semaphore->mDarkroom,NULL);
|
||||
AssertFatal(ok == 0,"Create semaphore failed at creating mutex mDarkroom.");
|
||||
// ok = pthread_mutex_init(&semaphore->mFoyer,NULL);
|
||||
// AssertFatal(ok != 0,"Create semaphore failed at creating mutex mFoyer.");
|
||||
ok = pthread_cond_init(&semaphore->mCond,NULL);
|
||||
AssertFatal(ok == 0,"Create semaphore failed at creating condition mCond.");
|
||||
|
||||
semaphore->count = initialCount;
|
||||
|
||||
return((void*)semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::destroySemaphore(void * semaphore)
|
||||
{
|
||||
MacCarbSemaphore *sem = static_cast<MacCarbSemaphore*>(semaphore);
|
||||
pthread_mutex_destroy(&sem->mDarkroom);
|
||||
// pthread_mutex_destroy(sem->mFoyer);
|
||||
pthread_cond_destroy(&sem->mCond);
|
||||
|
||||
delete sem;
|
||||
}
|
||||
|
||||
bool Semaphore::acquireSemaphore(void * semaphore, bool block)
|
||||
{
|
||||
bool ok;
|
||||
AssertFatal(semaphore, "Semaphore::acquireSemaphore: invalid semaphore");
|
||||
MacCarbSemaphore *sem = static_cast<MacCarbSemaphore*>(semaphore);
|
||||
|
||||
ok = pthread_mutex_lock(&sem->mDarkroom);
|
||||
AssertFatal(ok == 0,"Mutex Lock failed on mDarkroom in acquireSemaphore().");
|
||||
|
||||
if(sem->count <= 0 && !block) {
|
||||
ok = pthread_mutex_unlock(&sem->mDarkroom);
|
||||
AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when not blocking in acquireSemaphore().");
|
||||
return false;
|
||||
}
|
||||
|
||||
while( sem->count <= 0 ) {
|
||||
ok = pthread_cond_wait(&sem->mCond, &sem->mDarkroom); // releases mDarkroom while blocked.
|
||||
AssertFatal(ok == 0,"Waiting on mCond failed in acquireSemaphore().");
|
||||
}
|
||||
|
||||
sem->count--;
|
||||
|
||||
ok = pthread_mutex_unlock(&sem->mDarkroom);
|
||||
AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when leaving acquireSemaphore().");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Semaphore::releaseSemaphore(void * semaphore)
|
||||
{
|
||||
bool ok;
|
||||
AssertFatal(semaphore, "Semaphore::releaseSemaphore: invalid semaphore");
|
||||
MacCarbSemaphore *sem = static_cast<MacCarbSemaphore*>(semaphore);
|
||||
|
||||
ok = pthread_mutex_lock(&sem->mDarkroom);
|
||||
AssertFatal(ok == 0,"Mutex Lock failed on mDarkroom in releaseSemaphore().");
|
||||
|
||||
sem->count++;
|
||||
if(sem->count > 0) {
|
||||
ok = pthread_cond_signal(&sem->mCond);
|
||||
AssertFatal(ok == 0,"Signaling mCond failed in releaseSemaphore().");
|
||||
}
|
||||
|
||||
ok = pthread_mutex_unlock(&sem->mDarkroom);
|
||||
AssertFatal(ok == 0,"Mutex Unlock failed on mDarkroom when leaving releaseSemaphore().");
|
||||
}
|
335
engine/platformMacCarb/macCarbStrings.cc
Executable file
335
engine/platformMacCarb/macCarbStrings.cc
Executable file
@ -0,0 +1,335 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "console/console.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
char *dStrdup_r(const char *src, const char *file, dsize_t line)
|
||||
{
|
||||
char *buffer = (char *) dMalloc_r(dStrlen(src) + 1, file, line);
|
||||
dStrcpy(buffer, src);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *dStrnew(const char *src)
|
||||
{
|
||||
char *buffer = new char[dStrlen(src) + 1];
|
||||
dStrcpy(buffer, src);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* dStrcat(char *dst, const char *src)
|
||||
{
|
||||
return strcat(dst,src);
|
||||
}
|
||||
|
||||
char* dStrncat(char *dst, const char *src, dsize_t len)
|
||||
{
|
||||
return strncat(dst,src,len);
|
||||
}
|
||||
|
||||
// concatenates a list of src's onto the end of dst
|
||||
// the list of src's MUST be terminated by a NULL parameter
|
||||
// dStrcatl(dst, sizeof(dst), src1, src2, NULL);
|
||||
char* dStrcatl(char *dst, dsize_t dstSize, ...)
|
||||
{
|
||||
const char* src;
|
||||
char *p = dst;
|
||||
|
||||
AssertFatal(dstSize > 0, "dStrcatl: destination size is set zero");
|
||||
dstSize--; // leave room for string termination
|
||||
|
||||
// find end of dst
|
||||
while (dstSize && *p++)
|
||||
dstSize--;
|
||||
|
||||
va_list args;
|
||||
va_start(args, dstSize);
|
||||
|
||||
// concatenate each src to end of dst
|
||||
while ( (src = va_arg(args, const char*)) != NULL )
|
||||
while( dstSize && *src )
|
||||
{
|
||||
*p++ = *src++;
|
||||
dstSize--;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// make sure the string is terminated
|
||||
*p = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
// copy a list of src's into dst
|
||||
// the list of src's MUST be terminated by a NULL parameter
|
||||
// dStrccpyl(dst, sizeof(dst), src1, src2, NULL);
|
||||
char* dStrcpyl(char *dst, dsize_t dstSize, ...)
|
||||
{
|
||||
const char* src;
|
||||
char *p = dst;
|
||||
|
||||
AssertFatal(dstSize > 0, "dStrcpyl: destination size is set zero");
|
||||
dstSize--; // leave room for string termination
|
||||
|
||||
va_list args;
|
||||
va_start(args, dstSize);
|
||||
|
||||
// concatenate each src to end of dst
|
||||
while ( (src = va_arg(args, const char*)) != NULL )
|
||||
while( dstSize && *src )
|
||||
{
|
||||
*p++ = *src++;
|
||||
dstSize--;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// make sure the string is terminated
|
||||
*p = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
int dStrcmp(const char *str1, const char *str2)
|
||||
{
|
||||
return strcmp(str1, str2);
|
||||
}
|
||||
|
||||
int dStrcmp( const UTF16 *str1, const UTF16 *str2)
|
||||
{
|
||||
int ret;
|
||||
const UTF16 *a, *b;
|
||||
a = str1;
|
||||
b = str2;
|
||||
|
||||
while( *a && *b && (ret = *a - *b) == 0)
|
||||
a++, b++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int dStricmp(const char *str1, const char *str2)
|
||||
{
|
||||
char c1, c2;
|
||||
while (1)
|
||||
{
|
||||
c1 = tolower(*str1++);
|
||||
c2 = tolower(*str2++);
|
||||
if (c1 < c2) return -1;
|
||||
if (c1 > c2) return 1;
|
||||
if (c1 == 0) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int dStrncmp(const char *str1, const char *str2, dsize_t len)
|
||||
{
|
||||
return strncmp(str1, str2, len);
|
||||
}
|
||||
|
||||
int dStrnicmp(const char *str1, const char *str2, dsize_t len)
|
||||
{
|
||||
return strncasecmp( str1, str2, len );
|
||||
}
|
||||
|
||||
|
||||
char* dStrcpy(char *dst, const char *src)
|
||||
{
|
||||
return strcpy(dst,src);
|
||||
}
|
||||
|
||||
char* dStrncpy(char *dst, const char *src, dsize_t len)
|
||||
{
|
||||
return strncpy(dst,src,len);
|
||||
}
|
||||
|
||||
dsize_t dStrlen(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
return 0;
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
|
||||
char* dStrupr(char *str)
|
||||
{
|
||||
char* saveStr = str;
|
||||
while (*str)
|
||||
{
|
||||
*str = toupper(*str);
|
||||
str++;
|
||||
}
|
||||
return saveStr;
|
||||
}
|
||||
|
||||
|
||||
char* dStrlwr(char *str)
|
||||
{
|
||||
char* saveStr = str;
|
||||
while (*str)
|
||||
{
|
||||
*str = tolower(*str);
|
||||
str++;
|
||||
}
|
||||
return saveStr;
|
||||
}
|
||||
|
||||
|
||||
char* dStrchr(char *str, int c)
|
||||
{
|
||||
return strchr(str,c);
|
||||
}
|
||||
|
||||
|
||||
const char* dStrchr(const char *str, int c)
|
||||
{
|
||||
return strchr(str,c);
|
||||
}
|
||||
|
||||
const char* dStrrchr(const char *str, int c)
|
||||
{
|
||||
return strrchr(str,c);
|
||||
}
|
||||
|
||||
|
||||
char* dStrrchr(char *str, int c)
|
||||
{
|
||||
return strrchr(str,c);
|
||||
}
|
||||
|
||||
dsize_t dStrspn(const char *str, const char *set)
|
||||
{
|
||||
return(strspn(str, set));
|
||||
}
|
||||
|
||||
dsize_t dStrcspn(const char *str, const char *set)
|
||||
{
|
||||
return strcspn(str, set);
|
||||
}
|
||||
|
||||
|
||||
char* dStrstr(char *str1, char *str2)
|
||||
{
|
||||
return strstr(str1,str2);
|
||||
}
|
||||
|
||||
char* dStrstr(const char *str1, const char *str2)
|
||||
{
|
||||
return strstr(str1,str2);
|
||||
}
|
||||
|
||||
char* dStrtok(char *str, const char *sep)
|
||||
{
|
||||
return strtok(str, sep);
|
||||
}
|
||||
|
||||
|
||||
int dAtoi(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
return 0;
|
||||
return atoi(str);
|
||||
}
|
||||
|
||||
|
||||
float dAtof(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
return 0;
|
||||
return atof(str);
|
||||
}
|
||||
|
||||
bool dAtob(const char *str)
|
||||
{
|
||||
return !dStricmp(str, "true") || !dStricmp(str, "1") || (0!=dAtoi(str));
|
||||
}
|
||||
|
||||
bool dIsalnum(const char c)
|
||||
{
|
||||
return isalnum(c);
|
||||
}
|
||||
|
||||
bool dIsalpha(const char c)
|
||||
{
|
||||
return(isalpha(c));
|
||||
}
|
||||
|
||||
bool dIsspace(const char c)
|
||||
{
|
||||
return(isspace(c));
|
||||
}
|
||||
|
||||
bool dIsdigit(const char c)
|
||||
{
|
||||
return(isdigit(c));
|
||||
}
|
||||
|
||||
void dPrintf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
}
|
||||
|
||||
int dVprintf(const char *format, void *arglist)
|
||||
{
|
||||
S32 len = vprintf(format, (char*)arglist);
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int dSprintf(char *buffer, dsize_t bufferSize, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
S32 len = vsnprintf(buffer, bufferSize, format, args);
|
||||
|
||||
AssertFatal( len < bufferSize, "dSprintf wrote to more memory than the specified buffer size" );
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int dVsprintf(char *buffer, dsize_t bufferSize, const char *format, void *arglist)
|
||||
{
|
||||
S32 len = vsnprintf(buffer, bufferSize, format, (char*)arglist);
|
||||
|
||||
AssertFatal( len < bufferSize, "dVsprintf wrote to more memory than the specified buffer size" );
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int dSscanf(const char *buffer, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
return vsscanf(buffer, format, args);
|
||||
}
|
||||
|
||||
int dFflushStdout()
|
||||
{
|
||||
return fflush(stdout);
|
||||
}
|
||||
|
||||
int dFflushStderr()
|
||||
{
|
||||
return fflush(stderr);
|
||||
}
|
||||
|
||||
void dQsort(void *base, U32 nelem, U32 width, int (QSORT_CALLBACK *fcmp)(const void *, const void *))
|
||||
{
|
||||
qsort(base, nelem, width, fcmp);
|
||||
}
|
400
engine/platformMacCarb/macCarbThread.cc
Executable file
400
engine/platformMacCarb/macCarbThread.cc
Executable file
@ -0,0 +1,400 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <pthread.h>
|
||||
#include "platform/platformThread.h"
|
||||
#include "platform/platformSemaphore.h"
|
||||
#include "platform/platformMutex.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static U32 Thread::gMainThread = 0;
|
||||
|
||||
struct MacThreadData
|
||||
{
|
||||
ThreadRunFunction mRunFunc;
|
||||
S32 mRunArg;
|
||||
Thread * mThread;
|
||||
pthread_mutex_t mMutt;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Function: ThreadRunHandler
|
||||
// Summary: Calls Thread::run() with the thread's specified run argument.
|
||||
// Neccesary because Thread::run() is provided as a non-threaded
|
||||
// way to execute the thread's run function. So we have to keep
|
||||
// track of the thread's lock here.
|
||||
static void *ThreadRunHandler(void * arg)
|
||||
{
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(arg);
|
||||
|
||||
threadData->mThread->run(threadData->mRunArg);
|
||||
pthread_mutex_unlock(&(threadData->mMutt));
|
||||
// we could delete the Thread here, if it wants to be auto-deleted...
|
||||
return NULL;
|
||||
// this is where the created pthread will die.
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Thread::Thread(ThreadRunFunction func, S32 arg, bool start_thread)
|
||||
{
|
||||
MacThreadData * threadData = new MacThreadData();
|
||||
threadData->mRunFunc = func;
|
||||
threadData->mRunArg = arg;
|
||||
threadData->mThread = this;
|
||||
pthread_mutex_init(&(threadData->mMutt),NULL);
|
||||
|
||||
|
||||
mData = reinterpret_cast<void*>(threadData);
|
||||
if (start_thread)
|
||||
start();
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
join();
|
||||
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
pthread_mutex_destroy(&(threadData->mMutt));
|
||||
delete threadData;
|
||||
}
|
||||
|
||||
void Thread::start()
|
||||
{
|
||||
if(isAlive())
|
||||
return;
|
||||
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
// cause start to block out other pthreads from using this Thread, at least until ThreadRunHandler exits.
|
||||
pthread_mutex_lock(&(threadData->mMutt));
|
||||
|
||||
pthread_t threadID;
|
||||
pthread_create(&threadID, NULL, ThreadRunHandler, mData);
|
||||
}
|
||||
|
||||
bool Thread::join()
|
||||
{
|
||||
if(!isAlive())
|
||||
return(false);
|
||||
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
pthread_mutex_lock(&(threadData->mMutt));
|
||||
pthread_mutex_unlock(&(threadData->mMutt));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Thread::run(S32 arg)
|
||||
{
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
if(threadData->mRunFunc)
|
||||
threadData->mRunFunc(arg);
|
||||
}
|
||||
|
||||
bool Thread::isAlive()
|
||||
{
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
|
||||
if( pthread_mutex_trylock(&(threadData->mMutt)) == 0 )
|
||||
{
|
||||
pthread_mutex_unlock(&(threadData->mMutt));
|
||||
return false; // we got the lock, it aint alive.
|
||||
}
|
||||
else
|
||||
return true; // we could not get the lock, it must be alive.
|
||||
}
|
||||
|
||||
U32 Thread::getCurrentThreadId()
|
||||
{
|
||||
return (U32)pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::compareThreads(U32 thread1, U32 thread2)
|
||||
{
|
||||
return pthread_equal(thread1, thread2);
|
||||
}
|
||||
|
||||
U32 Thread::getMainThread()
|
||||
{
|
||||
return gMainThread;
|
||||
}
|
||||
|
||||
void Thread::setMainThread()
|
||||
{
|
||||
gMainThread = Thread::getCurrentThreadId();
|
||||
}
|
||||
|
||||
bool Thread::isMainThread()
|
||||
{
|
||||
#ifdef TORQUE_MULTITHREAD
|
||||
return Thread::compareThreads(gMainThread, Thread::getCurrentThreadId());
|
||||
#else
|
||||
// If we're single threaded we're always in the main thread.
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void *gMut1 = Mutex::createMutex();
|
||||
|
||||
#define TORQUE_MAC_THREAD_TESTS
|
||||
#if defined(TORQUE_MAC_THREAD_TESTS)
|
||||
|
||||
// -- the following is a set of tests to check thread sync facilities.
|
||||
// the 2 different ways of starting threads, by subclassing Thread,
|
||||
// and by using a (ThreadRunFunc*)(), are both demonstrated here.
|
||||
#include "gui/core/guiControl.h"
|
||||
|
||||
class TestThread : public Thread
|
||||
{
|
||||
public:
|
||||
volatile bool dienow;
|
||||
TestThread(ThreadRunFunction func, S32 arg, bool start_thread) : Thread(func,arg,start_thread)
|
||||
{
|
||||
dienow = false;
|
||||
}
|
||||
virtual void run(S32 arg)
|
||||
{
|
||||
int r;
|
||||
U32 time = Platform::getRealMilliseconds();
|
||||
Con::printf("thread %i starting",arg);
|
||||
while(!this->dienow) // will be set true by mothership thread
|
||||
{
|
||||
Mutex::lockMutex(gMut1);
|
||||
GuiControl *ctrl = new GuiControl();
|
||||
r = ((float)rand() / RAND_MAX ) * 10;
|
||||
Platform::sleep(r);
|
||||
delete ctrl;
|
||||
Mutex::unlockMutex(gMut1);
|
||||
}
|
||||
time = Platform::getRealMilliseconds() - time;
|
||||
Con::printf("thread %i exec time: %i",arg,time);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void mothership(S32 arg)
|
||||
{
|
||||
Con::printf("mothership started with arg %i",arg);
|
||||
int r;
|
||||
U32 time = Platform::getRealMilliseconds();
|
||||
TestThread* thread[arg];
|
||||
// create some threads, randomly sleep or delete one.
|
||||
Mutex::lockMutex(gMut1);
|
||||
for(int i=0; i < arg; i++)
|
||||
{
|
||||
|
||||
Con::printf("starting thread %i",i+1);
|
||||
thread[i] = new TestThread((ThreadRunFunction)NULL, i+1, true);
|
||||
r = ((float)rand() / RAND_MAX ) * 10;
|
||||
Platform::sleep(r);
|
||||
|
||||
}
|
||||
Mutex::unlockMutex(gMut1);
|
||||
|
||||
for(int i=0; i < arg; i++)
|
||||
{
|
||||
r = ((float)rand() / RAND_MAX ) * 10;
|
||||
Platform::sleep(r);
|
||||
thread[i]->dienow=true;
|
||||
delete thread[i];
|
||||
}
|
||||
time = Platform::getRealMilliseconds() - time;
|
||||
Con::printf("mothership exec time: %i",time);
|
||||
}
|
||||
|
||||
|
||||
ConsoleFunction(TestThreads,void,1,3,"TestThreads([number of motherships], [number of threads per mothership]); Launches threads, all competing for the same mutex.")
|
||||
{
|
||||
int nThreads = 1;
|
||||
int nMotherships = 1;
|
||||
if(argc>=2) {
|
||||
nThreads = dAtoi(argv[1]);
|
||||
}
|
||||
|
||||
if(argc>=3) {
|
||||
nMotherships = dAtoi(argv[2]);
|
||||
}
|
||||
|
||||
bool semStateTest1, semStateTest2, semIndepTest;
|
||||
|
||||
// check whether we can acquire a newly made semaphore
|
||||
semStateTest1 = true;
|
||||
void* sem = Semaphore::createSemaphore();
|
||||
void* sem2 = Semaphore::createSemaphore();
|
||||
if(Semaphore::acquireSemaphore(sem,false)) {
|
||||
semStateTest1 = true;
|
||||
} else
|
||||
semStateTest1 = false;
|
||||
|
||||
if(Semaphore::acquireSemaphore(sem2,false)) {
|
||||
semStateTest2 = true;
|
||||
} else
|
||||
semStateTest2 = false;
|
||||
|
||||
// if we failed to acquire new semaphores, test whether semaphores are independant.
|
||||
semIndepTest = true;
|
||||
if(!semStateTest1 && !semStateTest2) {
|
||||
Semaphore::releaseSemaphore(sem); // release one,
|
||||
if(Semaphore::acquireSemaphore(sem2,false)) // try to acquire the other ( that we know we can't acquire yet )
|
||||
semIndepTest = false; // we really should not be able to get this semaphore
|
||||
else
|
||||
semIndepTest = true;
|
||||
}
|
||||
|
||||
Con::errorf("-------------- Semaphore test Results ------------");
|
||||
if(!semStateTest1)
|
||||
Con::errorf("New Semaphore Aqcuire test 1 failed.");
|
||||
else
|
||||
Con::printf("New Semaphore Aqcuire test 1 passed.");
|
||||
|
||||
if(!semStateTest2)
|
||||
Con::errorf("New Semaphore Aqcuire test 2 failed.");
|
||||
else
|
||||
Con::printf("New Semaphore Aqcuire test 2 passed.");
|
||||
|
||||
if(!semIndepTest)
|
||||
Con::errorf("Semaphores are NOT INDEPENDANT!!! - This is bad.");
|
||||
else
|
||||
Con::errorf("Semaphore Independance test passed.");
|
||||
|
||||
|
||||
Con::printf("starting concurrent threads...");
|
||||
Mutex::lockMutex(gMut1);
|
||||
for(int i=0; i < nMotherships; i++) {
|
||||
// memory leak here: because we dont keeep refs to the mothership Threads, we cannot delete them.
|
||||
Con::printf("starting a mothership");
|
||||
Thread *t = new Thread((ThreadRunFunction)mothership,nThreads,true);
|
||||
}
|
||||
Mutex::unlockMutex(gMut1);
|
||||
}
|
||||
|
||||
class SemTestThread : public Thread
|
||||
{
|
||||
static void* mSem;
|
||||
static void* mMut;
|
||||
static int mCounter;
|
||||
static int mThreadCount;
|
||||
|
||||
int threadNum;
|
||||
public:
|
||||
static void init()
|
||||
{
|
||||
mSem = Semaphore::createSemaphore(0);
|
||||
mMut = Mutex::createMutex();
|
||||
Mutex::lockMutex(mMut);
|
||||
mCounter = 0;
|
||||
mThreadCount = 0;
|
||||
Mutex::unlockMutex(mMut);
|
||||
|
||||
}
|
||||
|
||||
static void dump()
|
||||
{
|
||||
Mutex::lockMutex(mMut);
|
||||
Con::printf("Dumping... counter = %i", mCounter);
|
||||
Con::printf(" nthreads = %i", mThreadCount);
|
||||
Mutex::unlockMutex(mMut);
|
||||
|
||||
}
|
||||
static void touch()
|
||||
{
|
||||
Semaphore::releaseSemaphore(mSem);
|
||||
}
|
||||
|
||||
void run(S32)
|
||||
{
|
||||
Mutex::lockMutex(mMut);
|
||||
threadNum = mThreadCount++;
|
||||
Mutex::unlockMutex(mMut);
|
||||
|
||||
// Con::printf("testsem thread %i started",threadNum);
|
||||
Semaphore::acquireSemaphore(mSem);
|
||||
// Con::printf("testsem thread %i got semaphore", threadNum);
|
||||
Mutex::lockMutex(mMut);
|
||||
// Con::printf("testsem thread %i got mutex", threadNum);
|
||||
mCounter++;
|
||||
// Con::printf("counter = %i, by thread %i", mCounter, threadNum);
|
||||
Mutex::unlockMutex(mMut);
|
||||
Semaphore::releaseSemaphore(mSem);
|
||||
Con::printf("testsem thread %i ending",threadNum);
|
||||
}
|
||||
};
|
||||
|
||||
void* SemTestThread::mSem;
|
||||
void* SemTestThread::mMut;
|
||||
int SemTestThread::mCounter;
|
||||
int SemTestThread::mThreadCount;
|
||||
|
||||
|
||||
ConsoleFunction( testSemaphores, void, 1, 3, "")
|
||||
{
|
||||
int nThreads = 1;
|
||||
if(argc >= 2)
|
||||
nThreads = dAtoi(argv[1]);
|
||||
|
||||
int nTouches = 0;
|
||||
if(argc >= 3)
|
||||
nTouches = dAtoi(argv[2]);
|
||||
|
||||
SemTestThread::init();
|
||||
Con::printf("starting %i threads", nThreads);
|
||||
for(int i = 0; i < nThreads; i++)
|
||||
{
|
||||
new SemTestThread();
|
||||
}
|
||||
|
||||
SemTestThread::dump();
|
||||
|
||||
for(int i =0; i<nTouches; i++)
|
||||
{
|
||||
SemTestThread::touch();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ConsoleFunction( touchSem, void, 1,1, "")
|
||||
{
|
||||
|
||||
SemTestThread::touch();
|
||||
}
|
||||
|
||||
ConsoleFunction( dumpSem, void, 1, 1, "")
|
||||
{
|
||||
SemTestThread::dump();
|
||||
}
|
||||
|
||||
#endif // TORQUE_MAC_THREAD_TESTS
|
||||
|
||||
|
||||
class PlatformThreadStorage
|
||||
{
|
||||
public:
|
||||
pthread_key_t mThreadKey;
|
||||
};
|
||||
|
||||
ThreadStorage::ThreadStorage()
|
||||
{
|
||||
mThreadStorage = (PlatformThreadStorage *) mStorage;
|
||||
constructInPlace(mThreadStorage);
|
||||
|
||||
pthread_key_create(&mThreadStorage->mThreadKey, NULL);
|
||||
}
|
||||
|
||||
ThreadStorage::~ThreadStorage()
|
||||
{
|
||||
pthread_key_delete(mThreadStorage->mThreadKey);
|
||||
}
|
||||
|
||||
void *ThreadStorage::get()
|
||||
{
|
||||
return pthread_getspecific(mThreadStorage->mThreadKey);
|
||||
}
|
||||
|
||||
void ThreadStorage::set(void *value)
|
||||
{
|
||||
pthread_setspecific(mThreadStorage->mThreadKey, value);
|
||||
}
|
||||
|
106
engine/platformMacCarb/macCarbTime.cc
Executable file
106
engine/platformMacCarb/macCarbTime.cc
Executable file
@ -0,0 +1,106 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#pragma message("time code needs eval -- may not be accurate in all cases, and might cause performance hit.")
|
||||
|
||||
//--------------------------------------
|
||||
void Platform::getLocalTime(LocalTime <)
|
||||
{
|
||||
struct tm systime;
|
||||
time_t long_time;
|
||||
|
||||
/// Get time as long integer.
|
||||
time( &long_time );
|
||||
/// Convert to local time, thread safe.
|
||||
localtime_r( &long_time, &systime );
|
||||
|
||||
/// Fill the return struct
|
||||
lt.sec = systime.tm_sec;
|
||||
lt.min = systime.tm_min;
|
||||
lt.hour = systime.tm_hour;
|
||||
lt.month = systime.tm_mon;
|
||||
lt.monthday = systime.tm_mday;
|
||||
lt.weekday = systime.tm_wday;
|
||||
lt.year = systime.tm_year;
|
||||
lt.yearday = systime.tm_yday;
|
||||
lt.isdst = systime.tm_isdst;
|
||||
}
|
||||
|
||||
/// Gets the time in seconds since the Epoch
|
||||
U32 Platform::getTime()
|
||||
{
|
||||
time_t epoch_time;
|
||||
time( &epoch_time );
|
||||
return epoch_time;
|
||||
}
|
||||
|
||||
/// Gets the time in milliseconds since some epoch. In this case, system start time.
|
||||
/// Storing milisec in a U32 overflows every 49.71 days
|
||||
U32 Platform::getRealMilliseconds()
|
||||
{
|
||||
// Duration is a S32 value.
|
||||
// if negative, it is in microseconds.
|
||||
// if positive, it is in milliseconds.
|
||||
Duration durTime = AbsoluteToDuration(UpTime());
|
||||
U32 ret;
|
||||
if( durTime < 0 )
|
||||
ret = durTime / -1000;
|
||||
else
|
||||
ret = durTime;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U32 Platform::getVirtualMilliseconds()
|
||||
{
|
||||
return platState.currentTime;
|
||||
}
|
||||
|
||||
void Platform::advanceTime(U32 delta)
|
||||
{
|
||||
platState.currentTime += delta;
|
||||
}
|
||||
|
||||
/// Asks the operating system to put the process to sleep for at least ms milliseconds
|
||||
void Platform::sleep(U32 ms)
|
||||
{
|
||||
// note: this will overflow if you want to sleep for more than 49 days. just so ye know.
|
||||
usleep( ms * 1000 );
|
||||
}
|
||||
|
||||
#pragma mark ---- TimeManager ----
|
||||
//--------------------------------------
|
||||
static void _MacCarbUpdateSleepTicks()
|
||||
{
|
||||
if( platState.backgrounded )
|
||||
platState.sleepTicks = Platform::getBackgroundSleepTime();
|
||||
else
|
||||
platState.sleepTicks = sgTimeManagerProcessInterval;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void TimeManager::process()
|
||||
{
|
||||
_MacCarbUpdateSleepTicks();
|
||||
|
||||
U32 curTime = Platform::getRealMilliseconds(); // GTC returns Milliseconds, FYI.
|
||||
S32 elapsedTime = curTime - platState.lastTimeTick;
|
||||
|
||||
if(elapsedTime <= platState.sleepTicks)
|
||||
{
|
||||
Platform::sleep(platState.sleepTicks - elapsedTime);
|
||||
}
|
||||
|
||||
platState.lastTimeTick = Platform::getRealMilliseconds();
|
||||
|
||||
TimeEvent event;
|
||||
event.elapsedTime = elapsedTime;
|
||||
Game->postEvent(event);
|
||||
}
|
152
engine/platformMacCarb/macCarbUtil.cc
Executable file
152
engine/platformMacCarb/macCarbUtil.cc
Executable file
@ -0,0 +1,152 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "macCarbUtil.h"
|
||||
//#include <CoreServices/CoreServices.h>
|
||||
#include "console/console.h"
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Function name: LoadPrivateFrameworksBundle
|
||||
// Summary: Looks in the application's Frameworks folder for a framework,
|
||||
// and loads it if it finds it.
|
||||
// Adpoted from a forum post by David 'FenrirWolf' Grace.
|
||||
//-------------------------------------------------------------------------------
|
||||
bool LoadPrivateFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) {
|
||||
// Looks in the application bundle for a framework, and loads it if it finds it.
|
||||
|
||||
CFURLRef privFrameworksURL, bundleURL;
|
||||
if(!( privFrameworksURL = CFBundleCopyPrivateFrameworksURL( CFBundleGetMainBundle() )) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(!( bundleURL = CFURLCreateCopyAppendingPathComponent(NULL, privFrameworksURL, framework, false)) ) {
|
||||
CFRelease(privFrameworksURL);
|
||||
return false;
|
||||
}
|
||||
|
||||
*bundlePtr = CFBundleCreate(NULL, bundleURL);
|
||||
if (*bundlePtr && CFBundleLoadExecutable( *bundlePtr ) ) {
|
||||
//found it under the apps private framework
|
||||
CFRelease(privFrameworksURL);
|
||||
CFRelease(bundleURL);
|
||||
return true;
|
||||
}
|
||||
|
||||
CFRelease(privFrameworksURL);
|
||||
CFRelease(bundleURL);
|
||||
if(*bundlePtr != NULL)
|
||||
CFRelease(*bundlePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Function name: LoadFrameworksBundle
|
||||
// Summary: Looks for a framework first in the app then the system,
|
||||
// and loads it if it finds it.
|
||||
// Adopted from Apple "CallMachOFramework" sample application
|
||||
//-------------------------------------------------------------------------------
|
||||
bool LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr)
|
||||
{
|
||||
const int numLocs = 5;
|
||||
short vols[numLocs] = {kOnAppropriateDisk,
|
||||
kOnAppropriateDisk,
|
||||
kOnAppropriateDisk,
|
||||
kLocalDomain,
|
||||
kLocalDomain};
|
||||
|
||||
OSType folderType[numLocs] = {kPrivateFrameworksFolderType,
|
||||
kFrameworksFolderType,
|
||||
kApplicationSupportFolderType,
|
||||
kFrameworksFolderType,
|
||||
kDomainLibraryFolderType};
|
||||
OSStatus err;
|
||||
FSRef frameworksFolderRef;
|
||||
CFURLRef baseURL;
|
||||
CFURLRef bundleURL;
|
||||
|
||||
if (bundlePtr==NULL)
|
||||
return false;
|
||||
|
||||
*bundlePtr = NULL;
|
||||
|
||||
// Look in the application's Frameworks folder before looking in the system
|
||||
if( LoadPrivateFrameworkBundle(framework, bundlePtr) )
|
||||
return true; // Yay! We found it, so return true...
|
||||
// Otherwise, fall through to Torques usual bundle load logic
|
||||
|
||||
|
||||
baseURL = NULL;
|
||||
bundleURL = NULL;
|
||||
|
||||
for (int i = 0; i<numLocs; i++)
|
||||
{
|
||||
err = FSFindFolder(vols[i], folderType[i], true, &frameworksFolderRef);
|
||||
if (err == noErr) {
|
||||
baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef);
|
||||
if (baseURL == NULL) {
|
||||
err = coreFoundationUnknownErr;
|
||||
}
|
||||
}
|
||||
if (err == noErr) {
|
||||
bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false);
|
||||
if (bundleURL == NULL) {
|
||||
err = coreFoundationUnknownErr;
|
||||
}
|
||||
}
|
||||
if (err == noErr) {
|
||||
*bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
|
||||
if (*bundlePtr == NULL) {
|
||||
err = coreFoundationUnknownErr;
|
||||
}
|
||||
}
|
||||
if (err == noErr) {
|
||||
if ( ! CFBundleLoadExecutable( *bundlePtr ) ) {
|
||||
err = coreFoundationUnknownErr;
|
||||
}
|
||||
else // GOT IT!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
if (err != noErr && *bundlePtr != NULL)
|
||||
{
|
||||
CFRelease(*bundlePtr);
|
||||
*bundlePtr = NULL;
|
||||
}
|
||||
if (bundleURL != NULL)
|
||||
CFRelease(bundleURL);
|
||||
if (baseURL != NULL)
|
||||
CFRelease(baseURL);
|
||||
|
||||
return err == noErr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Converts a QuickDraw displayID to a Core Graphics displayID.
|
||||
// Different Mac APIs need different displayID types. The conversion is trivial
|
||||
// on 10.3+, but ugly on 10.2, so we wrap it here.
|
||||
//-----------------------------------------------------------------------------
|
||||
CGDirectDisplayID MacCarbGetCGDisplayFromQDDisplay(GDHandle hDisplay)
|
||||
{
|
||||
// 10.2 doesn't have QDGetCGDirectDisplayID, so we roll our own.
|
||||
// this is adapted from http://developer.apple.com/samplecode/glut/listing116.html
|
||||
#if defined(TORQUE_MAC_HAS_QDGETCGDIRECTDISPLAYID)
|
||||
CGDirectDisplayID display = QDGetCGDirectDisplayID(hDisplay);
|
||||
#else
|
||||
Rect qdRect = (**hDisplay).gdRect;
|
||||
CGRect cgRect = CGRectMake(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
|
||||
CGDisplayCount nDisplays;
|
||||
CGDirectDisplayID displays[32];
|
||||
CGGetDisplaysWithRect(cgRect, 32, displays, &nDisplays);
|
||||
// TODO: this may not work well when video mirroring is on. check it & see.
|
||||
CGDirectDisplayID display = displays[0];
|
||||
#endif
|
||||
return display;
|
||||
}
|
||||
|
22
engine/platformMacCarb/macCarbUtil.h
Executable file
22
engine/platformMacCarb/macCarbUtil.h
Executable file
@ -0,0 +1,22 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBUTIL_H_
|
||||
#define _MACCARBUTIL_H_
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
/// Looks in the app's Frameworks folder for a framework and loads it if it finds it.
|
||||
bool LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr);
|
||||
/// Looks for a framework first in the app then the system, and loads it if it finds it.
|
||||
bool LoadPrivateFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr);
|
||||
|
||||
/// Converts a QuickDraw displayID to a Core Graphics displayID.
|
||||
/// Different Mac APIs need different displayID types. The conversion is trivial
|
||||
/// on 10.3+, but ugly on 10.2, so we wrap it here.
|
||||
CGDirectDisplayID MacCarbGetCGDisplayFromQDDisplay(GDHandle hDisplay);
|
||||
|
||||
#endif // _MACCARBUTIL_H_
|
433
engine/platformMacCarb/macCarbWindow.cc
Executable file
433
engine/platformMacCarb/macCarbWindow.cc
Executable file
@ -0,0 +1,433 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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*");
|
||||
}
|
||||
|
||||
|
||||
|
52
engine/platformMacCarb/macCarb_common_prefix.h
Executable file
52
engine/platformMacCarb/macCarb_common_prefix.h
Executable file
@ -0,0 +1,52 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//------------------------------
|
||||
//maccarb_common_prefix.h
|
||||
//------------------------------
|
||||
|
||||
#define TORQUE_OS_MAC_CARB 1 // always defined right now...
|
||||
|
||||
#if defined(TORQUE_OS_MAC_OSX)
|
||||
//#define Z_PREFIX // OSX comes with zlib, so generate unique symbols.
|
||||
#endif
|
||||
|
||||
// defines for the mac headers to activate proper Carbon codepaths.
|
||||
#define TARGET_API_MAC_CARBON 1 // apple carbon header flag to take right defpaths.
|
||||
//#define OTCARBONAPPLICATION 1 // means we can use the old-style funcnames
|
||||
|
||||
// determine the OS version we're building on...
|
||||
// MAC_OS_X_VERSION_MAX_ALLOWED will have the local OSX version,
|
||||
// or it will have the version of OSX for the sdk we're cross compiling with.
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
// Pasteboards were introduced in 10.3, and are not available before 10.3
|
||||
// QDGetCGDirectDisplayID was introduced in 10.3, but there is a manual workaround.
|
||||
// There's a bug in some versions of Xcode, such that MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
// is not set correctly, and so we cannot properly use the weak-linking feature.
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1030
|
||||
#define TORQUE_MAC_HAS_PASTEBOARD
|
||||
#define TORQUE_MAC_HAS_QDGETCGDIRECTDISPLAYID
|
||||
#endif
|
||||
|
||||
// Some features we're currently using were introduced in 10.3, or 10.4.
|
||||
// We'll define them, or provide stubs for them, in the case that we are on 10.2
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED <= 1020
|
||||
#include "platformMacCarb/macCarbCompat.10.2.h"
|
||||
#else
|
||||
#define MacCarbInit1020CompatInit() // stub it out
|
||||
#endif
|
||||
|
||||
// Some features we're currently using were introduced in 10.4.
|
||||
// for now, it's just a few values, so we define them here.
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED <= 1030
|
||||
#define gestaltCPU970FX 0x013C
|
||||
#define gestaltCPUPentium4 'i5iv'
|
||||
#define CPU_TYPE_X86 ((cpu_type_t) 7)
|
||||
#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
|
||||
#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64)
|
||||
#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
|
||||
|
||||
#endif
|
51
engine/platformMacCarb/macPathCopy.mm
Executable file
51
engine/platformMacCarb/macPathCopy.mm
Executable file
@ -0,0 +1,51 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
|
||||
bool dPathCopy(const char* source, const char* dest, bool nooverwrite)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSFileManager *manager = [NSFileManager defaultManager];
|
||||
|
||||
NSString *nsource = [manager stringWithFileSystemRepresentation:source length:dStrlen(source)];
|
||||
NSString *ndest = [manager stringWithFileSystemRepresentation:dest length:dStrlen(dest)];
|
||||
|
||||
if(! [manager fileExistsAtPath:nsource])
|
||||
{
|
||||
Con::errorf("dPathCopy: no file exists at %s",source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if( [manager fileExistsAtPath:ndest] )
|
||||
{
|
||||
if(nooverwrite)
|
||||
{
|
||||
Con::errorf("dPathCopy: file already exists at %s",dest);
|
||||
return false;
|
||||
}
|
||||
Con::warnf("Deleting files at path: %s", dest);
|
||||
bool deleted = [manager removeFileAtPath:ndest handler:nil];
|
||||
if(!deleted)
|
||||
{
|
||||
Con::errorf("Copy failed! Could not delete files at path: %s", dest);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = [manager copyPath:nsource toPath:ndest handler:nil];
|
||||
[pool release];
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
ConsoleFunction( dPathCopy, void, 3,3, "2 args.")
|
||||
{
|
||||
dPathCopy(argv[1], argv[2]);
|
||||
}
|
214
engine/platformMacCarb/platformGL.h
Executable file
214
engine/platformMacCarb/platformGL.h
Executable file
@ -0,0 +1,214 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PLATFORMGL_H_
|
||||
#define _PLATFORMGL_H_
|
||||
|
||||
/// We use the standard Apple OpenGL framework headers.
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#include <OpenGL/glext.h>
|
||||
|
||||
/// Using aglMacro.h gives us signifigant performance gains in opengl immediate mode ( glVertex etc )
|
||||
#if !defined(TORQUE_DEBUG)
|
||||
#define USE_AGL_MACRO
|
||||
#endif
|
||||
|
||||
#if defined(USE_AGL_MACRO)
|
||||
#if !defined(AGLContext)
|
||||
typedef struct __AGLContextRec *AGLContext;
|
||||
#endif
|
||||
#include <AGL/aglMacro.h>
|
||||
extern AGLContext agl_ctx;
|
||||
#endif
|
||||
|
||||
/// Allows outline mode drawing via a function pointer swapping trick.
|
||||
/// Must be included AFTER all the OpenGL headers.
|
||||
#include "platformMacCarb/macCarbOutlineGL.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// This is legacy stuff for the d3d wrapper layer.
|
||||
// The code that requires these stubs should probably be ifdef'd out of any non w32 build
|
||||
//------------------------------------------------------------------------------
|
||||
extern GLboolean glAvailableVertexBufferEXT();
|
||||
extern GLint glAllocateVertexBufferEXT(GLsizei size, GLint format, GLboolean preserve);
|
||||
extern void* glLockVertexBufferEXT(GLint handle, GLsizei size);
|
||||
extern void glUnlockVertexBufferEXT(GLint handle);
|
||||
extern void glSetVertexBufferEXT(GLint handle);
|
||||
extern void glOffsetVertexBufferEXT(GLint handle, GLuint offset);
|
||||
extern void glFillVertexBufferEXT(GLint handle, GLint first, GLsizei count);
|
||||
extern void glFreeVertexBufferEXT(GLint handle);
|
||||
// these are extensions for glAllocateVertexBufferEXT
|
||||
#define GL_V12MTVFMT_EXT 0x8702
|
||||
#define GL_V12MTNVFMT_EXT 0x8703
|
||||
#define GL_V12FTVFMT_EXT 0x8704
|
||||
#define GL_V12FMTVFMT_EXT 0x8705
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// make sure this is defined, as we need to use it when around.
|
||||
// some versions of OSX only define the SGIS version ( same hexcode )
|
||||
#ifndef GL_CLAMP_TO_EDGE_EXT
|
||||
#define GL_CLAMP_TO_EDGE_EXT 0x812F
|
||||
#endif
|
||||
|
||||
/// GL state information.
|
||||
struct GLState
|
||||
{
|
||||
bool suppARBMultitexture;
|
||||
bool suppEXTblendcolor;
|
||||
bool suppEXTblendminmax;
|
||||
bool suppPackedPixels;
|
||||
bool suppTexEnvAdd;
|
||||
bool suppLockedArrays;
|
||||
|
||||
bool suppTextureEnvCombine;
|
||||
bool suppVertexArrayRange;
|
||||
bool suppFogCoord;
|
||||
bool suppEdgeClamp;
|
||||
|
||||
bool suppTextureCompression;
|
||||
bool suppS3TC;
|
||||
bool suppFXT1;
|
||||
bool suppTexAnisotropic;
|
||||
|
||||
bool suppPalettedTexture;
|
||||
bool suppVertexBuffer;
|
||||
bool suppSwapInterval;
|
||||
|
||||
GLint maxFSAASamples;
|
||||
|
||||
unsigned int triCount[4];
|
||||
unsigned int primCount[4];
|
||||
unsigned int primMode; // 0-3
|
||||
|
||||
GLfloat maxAnisotropy;
|
||||
GLint maxTextureUnits;
|
||||
|
||||
bool isDirect3D;
|
||||
};
|
||||
|
||||
extern GLState gGLState;
|
||||
|
||||
extern bool gOpenGLDisablePT;
|
||||
extern bool gOpenGLDisableCVA;
|
||||
extern bool gOpenGLDisableTEC;
|
||||
extern bool gOpenGLDisableARBMT;
|
||||
extern bool gOpenGLDisableFC;
|
||||
extern bool gOpenGLDisableTCompress;
|
||||
extern bool gOpenGLNoEnvColor;
|
||||
extern float gOpenGLGammaCorrection;
|
||||
extern bool gOpenGLNoDrawArraysAlpha;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Inline state getters for dgl
|
||||
//------------------------------------------------------------------------------
|
||||
inline void dglSetRenderPrimType(unsigned int type)
|
||||
{
|
||||
gGLState.primMode = type;
|
||||
}
|
||||
|
||||
inline void dglClearPrimMetrics()
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
gGLState.triCount[i] = gGLState.primCount[i] = 0;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportPalettedTexture()
|
||||
{
|
||||
return gGLState.suppPalettedTexture && (gOpenGLDisablePT == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportCompiledVertexArray()
|
||||
{
|
||||
return gGLState.suppLockedArrays && (gOpenGLDisableCVA == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportTextureEnvCombine()
|
||||
{
|
||||
return gGLState.suppTextureEnvCombine && (gOpenGLDisableTEC == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportARBMultitexture()
|
||||
{
|
||||
return gGLState.suppARBMultitexture && (gOpenGLDisableARBMT == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportEXTBlendColor()
|
||||
{
|
||||
return gGLState.suppEXTblendcolor;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportEXTBlendMinMax()
|
||||
{
|
||||
return gGLState.suppEXTblendminmax;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportVertexArrayRange()
|
||||
{
|
||||
return gGLState.suppVertexArrayRange;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportFogCoord()
|
||||
{
|
||||
return gGLState.suppFogCoord && (gOpenGLDisableFC == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportEdgeClamp()
|
||||
{
|
||||
return gGLState.suppEdgeClamp;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportTextureCompression()
|
||||
{
|
||||
return gGLState.suppTextureCompression && (gOpenGLDisableTCompress == false);
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportS3TC()
|
||||
{
|
||||
return gGLState.suppS3TC;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportFXT1()
|
||||
{
|
||||
return gGLState.suppFXT1;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportTexEnvAdd()
|
||||
{
|
||||
return gGLState.suppTexEnvAdd;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportTexAnisotropy()
|
||||
{
|
||||
return gGLState.suppTexAnisotropic;
|
||||
}
|
||||
|
||||
inline bool dglDoesSupportVertexBuffer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline GLfloat dglGetMaxAnisotropy()
|
||||
{
|
||||
return gGLState.maxAnisotropy;
|
||||
}
|
||||
|
||||
inline GLint dglGetMaxTextureUnits()
|
||||
{
|
||||
if (dglDoesSupportARBMultitexture())
|
||||
return gGLState.maxTextureUnits;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// For radeon cards we can do fast FSAA mode switching.
|
||||
/// Sets Full Scene Anti-Aliasing (FSAA) samples ( 1x, 2x, 4x ) via aglSetInteger()
|
||||
//------------------------------------------------------------------------------
|
||||
#define ATI_FSAA_LEVEL ((unsigned long)510)
|
||||
void dglSetFSAASamples(GLint aasamp);
|
||||
|
||||
#endif // _PLATFORMGL_H_
|
132
engine/platformMacCarb/platformMacCarb.h
Executable file
132
engine/platformMacCarb/platformMacCarb.h
Executable file
@ -0,0 +1,132 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PLATFORMMACCARB_H_
|
||||
#define _PLATFORMMACCARB_H_
|
||||
|
||||
/// NOTE: Placing system headers before Torque's platform.h will work around the Torque-Redefines-New problems.
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AGL/agl.h>
|
||||
#include "platform/platform.h"
|
||||
#include "math/mMath.h"
|
||||
|
||||
|
||||
class MacCarbPlatState
|
||||
{
|
||||
public:
|
||||
GDHandle hDisplay;
|
||||
CGDirectDisplayID cgDisplay;
|
||||
|
||||
bool captureDisplay;
|
||||
bool fadeWindows;
|
||||
|
||||
WindowPtr appWindow;
|
||||
char appWindowTitle[256];
|
||||
WindowGroupRef torqueWindowGroup;
|
||||
|
||||
bool quit;
|
||||
|
||||
AGLContext ctx;
|
||||
bool ctxNeedsUpdate;
|
||||
bool headless;
|
||||
|
||||
S32 desktopBitsPixel;
|
||||
S32 desktopWidth;
|
||||
S32 desktopHeight;
|
||||
U32 currentTime;
|
||||
|
||||
U32 osVersion;
|
||||
|
||||
TSMDocumentID tsmDoc;
|
||||
bool tsmActive;
|
||||
|
||||
U32 firstThreadId;
|
||||
U32 torqueThreadId;
|
||||
|
||||
void* alertSemaphore;
|
||||
S32 alertHit;
|
||||
DialogRef alertDlg;
|
||||
EventQueueRef mainEventQueue;
|
||||
|
||||
MRandomLCG platRandom;
|
||||
|
||||
bool mouseLocked;
|
||||
bool backgrounded;
|
||||
bool minimized;
|
||||
|
||||
S32 sleepTicks;
|
||||
S32 lastTimeTick;
|
||||
|
||||
Point2I windowSize;
|
||||
|
||||
U32 appReturn;
|
||||
|
||||
U32 argc;
|
||||
char** argv;
|
||||
|
||||
|
||||
|
||||
MacCarbPlatState();
|
||||
};
|
||||
|
||||
/// Global singleton that encapsulates a lot of mac platform state & globals.
|
||||
extern MacCarbPlatState platState;
|
||||
|
||||
/// @name Misc Mac Plat Functions
|
||||
/// Functions that are used by multiple files in the mac plat, but too trivial
|
||||
/// to require their own header file.
|
||||
/// @{
|
||||
/// Fills gGLState with info about this gl renderer's capabilities.
|
||||
void getGLCapabilities(void);
|
||||
|
||||
/// Creates a new mac window, of a particular size, centered on the screen.
|
||||
/// If a fullScreen window is requested, then the window is created without
|
||||
/// decoration, in front of all other normal windows AND BEHIND asian text input methods.
|
||||
/// This path to a fullScreen window allows asian text input methods to work
|
||||
/// in full screen mode, because it avoids capturing the display.
|
||||
WindowPtr MacCarbCreateOpenGLWindow( GDHandle hDevice, U32 width, U32 height, bool fullScreen );
|
||||
|
||||
/// Asnychronously fade a window into existence, and set menu bar visibility.
|
||||
/// The fading can be turned off via the preference $pref::mac::fadeWindows.
|
||||
/// It also sends itself to the main thread if it is called on any other thread.
|
||||
void MacCarbFadeInWindow( WindowPtr window );
|
||||
|
||||
/// Asnychronously fade a window out of existence. The window will be destroyed
|
||||
/// when the fade is complete.
|
||||
/// The fading can be turned off via the preference $pref::mac::fadeWindows.
|
||||
/// It also sends itself to the main thread if it is called on any other thread.
|
||||
void MacCarbFadeAndReleaseWindow( WindowPtr window );
|
||||
|
||||
/// Manage Mac MenuBar visibility.
|
||||
/// If show is true the menubar is shown, if false the menubar is hidden.
|
||||
/// It sends itself to the main thread if it is called on any other thread.
|
||||
void MacCarbShowMenuBar(bool show);
|
||||
|
||||
/// Translates a Mac keycode to a Torque keycode
|
||||
U8 TranslateOSKeyCode(U8 vcode);
|
||||
/// @}
|
||||
|
||||
/// @name Misc Mac Plat constants
|
||||
/// @{
|
||||
|
||||
/// earlier versions of OSX don't have these convinience macros, so manually stick them here.
|
||||
#ifndef IntToFixed
|
||||
#define IntToFixed(a) ((Fixed)(a) <<16)
|
||||
#define FixedToInt(a) ((short)(((Fixed)(a) + fixed1/2) >> 16))
|
||||
#endif
|
||||
|
||||
/// window level constants
|
||||
const U32 kTAlertWindowLevel = CGShieldingWindowLevel() - 1;
|
||||
const U32 kTUtilityWindowLevel = CGShieldingWindowLevel() - 2;
|
||||
const U32 kTFullscreenWindowLevel = CGShieldingWindowLevel() - 3;
|
||||
|
||||
/// mouse wheel sensitivity factor
|
||||
const S32 kTMouseWheelMagnificationFactor = 25;
|
||||
|
||||
/// @}
|
||||
|
||||
#endif //_PLATFORMMACCARB_H_
|
||||
|
BIN
engine/platformMacCarb/torqueDemo.icns
Executable file
BIN
engine/platformMacCarb/torqueDemo.icns
Executable file
Binary file not shown.
Reference in New Issue
Block a user