Initial commit
This commit is contained in:
BIN
engine/platformMacCarb/macCarb.rsrc
Normal file
BIN
engine/platformMacCarb/macCarb.rsrc
Normal file
Binary file not shown.
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
|
157
engine/platformMacCarb/macCarbCPUInfo.cc
Executable file
157
engine/platformMacCarb/macCarbCPUInfo.cc
Executable file
@ -0,0 +1,157 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "PlatformMacCarb/platformMacCarb.h"
|
||||
#include "console/console.h"
|
||||
#include "Core/stringTable.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <Gestalt.h>
|
||||
|
||||
/* at some future time...
|
||||
#if (UNIVERSAL_INTERFACES_VERSION<0x0341) || (UNIVERSAL_INTERFACES_VERSION==0x0341 && UNIVERSAL_INTERFACES_SEED_VERSION<2) || (UNIVERSAL_INTERFACES_VERSION==0x0400) // since OSX base headers are earlier than 3.4.1
|
||||
// missing the new cpu type until carbonlib 1.5...
|
||||
#define gestaltCPUG47450 0x0110
|
||||
#endif
|
||||
*/
|
||||
|
||||
// possibly useful gestalts I haven't used yet:
|
||||
|
||||
// gestaltDisplayMgrVers = FOUR_CHAR_CODE('dplv') /* Display Manager version */
|
||||
// gestaltDisplayMgrAttr = FOUR_CHAR_CODE('dply'), /* Display Manager attributes */
|
||||
|
||||
// gestaltOSAttr = FOUR_CHAR_CODE('os '), /* o/s attributes */
|
||||
// gestaltSysZoneGrowable = 0, /* system heap is growable */
|
||||
// gestaltLaunchCanReturn = 1, /* can return from launch */
|
||||
// gestaltLaunchFullFileSpec = 2, /* can launch from full file spec */
|
||||
// gestaltLaunchControl = 3, /* launch control support available */
|
||||
// gestaltTempMemSupport = 4, /* temp memory support */
|
||||
// gestaltRealTempMemory = 5, /* temp memory handles are real */
|
||||
// gestaltTempMemTracked = 6, /* temporary memory handles are tracked */
|
||||
// gestaltIPCSupport = 7, /* IPC support is present */
|
||||
// gestaltSysDebuggerSupport = 8 /* system debugger support is present */
|
||||
|
||||
// gestaltPowerMgrAttr = FOUR_CHAR_CODE('powr'), /* power manager attributes */
|
||||
// gestaltPMgrExists = 0,
|
||||
// gestaltPMgrCPUIdle = 1,
|
||||
// gestaltPMgrSCC = 2,
|
||||
// gestaltPMgrSound = 3,
|
||||
// gestaltPMgrDispatchExists = 4,
|
||||
// gestaltPMgrSupportsAVPowerStateAtSleepWake = 5
|
||||
|
||||
// should add multiprocessing check
|
||||
// should add threadmgr check -- and we'll need optional code to do something diff.
|
||||
|
||||
Platform::SystemInfo_struct Platform::SystemInfo;
|
||||
|
||||
#define BASE_MHZ_SPEED 200
|
||||
|
||||
void Processor::init()
|
||||
{
|
||||
OSErr err;
|
||||
long raw, mhzSpeed = BASE_MHZ_SPEED;
|
||||
|
||||
Con::printf("System & Processor Information:");
|
||||
|
||||
err = Gestalt(gestaltSystemVersion, &raw);
|
||||
|
||||
Con::printf(" MacOS version: %x.%x.%x", (raw>>8), (raw&0xFF)>>4, (raw&0x0F));
|
||||
|
||||
err = Gestalt(gestaltCarbonVersion, &raw);
|
||||
if (err) raw = 0;
|
||||
if (raw==0)
|
||||
Con::printf(" No CarbonLib support.");
|
||||
else
|
||||
Con::printf(" CarbonLib version: %x.%x.%x", (raw>>8), (raw&0xFF)>>4, (raw&0x0F));
|
||||
|
||||
err = Gestalt(gestaltPhysicalRAMSize, &raw);
|
||||
raw /= (1024*1024); // MB
|
||||
Con::printf(" Physical RAM: %dMB", raw);
|
||||
err = Gestalt(gestaltLogicalRAMSize, &raw);
|
||||
raw /= (1024*1024); // MB
|
||||
Con::printf(" Logical RAM: %dMB", raw);
|
||||
|
||||
// this is known to have issues with some Processor Upgrade cards
|
||||
err = Gestalt(gestaltProcClkSpeed, &raw);
|
||||
if (err==noErr && raw)
|
||||
{
|
||||
mhzSpeed = (float)raw / 1000000.0f;
|
||||
if (mhzSpeed < BASE_MHZ_SPEED)
|
||||
{ // something drastically wrong.
|
||||
mhzSpeed = BASE_MHZ_SPEED;
|
||||
}
|
||||
}
|
||||
Platform::SystemInfo.processor.mhz = mhzSpeed;
|
||||
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_Unknown;
|
||||
err = Gestalt(gestaltNativeCPUtype, &raw);
|
||||
switch(raw)
|
||||
{
|
||||
case gestaltCPU601:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_601;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC 601");
|
||||
break;
|
||||
case gestaltCPU603e:
|
||||
case gestaltCPU603ev:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_603e;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC 603e");
|
||||
break;
|
||||
case gestaltCPU603:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_603;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC 603");
|
||||
break;
|
||||
case gestaltCPU604e:
|
||||
case gestaltCPU604ev:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_604e;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC 604e");
|
||||
break;
|
||||
case gestaltCPU604:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_604;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC 604");
|
||||
break;
|
||||
case gestaltCPU750: //G3
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_G3;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G3");
|
||||
break;
|
||||
case gestaltCPUG4:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_G4;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G4");
|
||||
break;
|
||||
/* at some point -- I these are either speedbump or the TiBooks or the new TiMacs
|
||||
// gestaltCPUVger = 0x0110, // Vger , Altivec
|
||||
// gestaltCPUApollo = 0x0111 // Apollo , Altivec
|
||||
case gestaltCPUVger:
|
||||
case gestaltCPUVger:
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_G4_FUTURE;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G4 FUTURE");
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
if (raw>gestaltCPUG4)
|
||||
{ // for now, ID it as a G4u
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_G4u;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("Unknown/PowerPC G4u ++");
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::SystemInfo.processor.type = CPU_PowerPC_Unknown;
|
||||
Platform::SystemInfo.processor.name = StringTable->insert("Unknown PowerPC");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Platform::SystemInfo.processor.properties = CPU_PROP_PPCMIN;
|
||||
err = Gestalt(gestaltPowerPCProcessorFeatures, &raw);
|
||||
if ((1 << gestaltPowerPCHasVectorInstructions) & (raw))
|
||||
Platform::SystemInfo.processor.properties |= CPU_PROP_ALTIVEC; // OR it in as they are flags...
|
||||
|
||||
Con::printf(" %s, %d Mhz", Platform::SystemInfo.processor.name, Platform::SystemInfo.processor.mhz);
|
||||
if (Platform::SystemInfo.processor.properties & CPU_PROP_PPCMIN)
|
||||
Con::printf(" FPU detected");
|
||||
if (Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
|
||||
Con::printf(" AltiVec detected");
|
||||
|
||||
Con::printf(" ");
|
||||
}
|
371
engine/platformMacCarb/macCarbConsole.cc
Executable file
371
engine/platformMacCarb/macCarbConsole.cc
Executable file
@ -0,0 +1,371 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#if USE_SIOUX
|
||||
#include <SIOUX.h>
|
||||
#else
|
||||
#if defined(TORQUE_OS_MAC_OSX)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreFoundation.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
//#define NO_CONSOLE 1 // to turn off all output.
|
||||
#define NO_CONSOLE 0
|
||||
#else
|
||||
#define NO_CONSOLE 0
|
||||
#endif
|
||||
|
||||
MacConsole *gConsole = NULL;
|
||||
|
||||
|
||||
ConsoleFunction(enableWinConsole, void, 2, 2, "(bool enable)")
|
||||
{
|
||||
argc;
|
||||
if (gConsole)
|
||||
gConsole->enable(dAtob(argv[1]));
|
||||
}
|
||||
|
||||
void MacConsole::create()
|
||||
{
|
||||
#if NO_CONSOLE
|
||||
gConsole = NULL;
|
||||
#else
|
||||
gConsole = new MacConsole();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MacConsole::destroy()
|
||||
{
|
||||
if (gConsole)
|
||||
delete gConsole;
|
||||
gConsole = NULL;
|
||||
}
|
||||
|
||||
void MacConsole::enable(bool enabled)
|
||||
{
|
||||
if (gConsole == NULL) return;
|
||||
|
||||
consoleEnabled = enabled;
|
||||
if(consoleEnabled)
|
||||
{
|
||||
// AllocConsole();
|
||||
printf("Console Initialized.\n");
|
||||
const char *title = Con::getVariable("Con::WindowTitle");
|
||||
if (title && *title)
|
||||
{
|
||||
unsigned char t2[256];
|
||||
str2p(title, t2);
|
||||
#if USE_SIOUX
|
||||
SIOUXSetTitle(t2);
|
||||
#endif
|
||||
}
|
||||
// stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
// stdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
// stdErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
//
|
||||
printf("%s", Con::getVariable("Con::Prompt"));
|
||||
}
|
||||
}
|
||||
|
||||
bool MacConsole::isEnabled()
|
||||
{
|
||||
if ( gConsole )
|
||||
return gConsole->consoleEnabled;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void macConsoleConsumer(ConsoleLogEntry::Level, const char *line)
|
||||
{
|
||||
if (gConsole)
|
||||
gConsole->processConsoleLine(line);
|
||||
}
|
||||
|
||||
MacConsole::MacConsole()
|
||||
{
|
||||
for (S32 iIndex = 0; iIndex < MAX_CMDS; iIndex ++)
|
||||
rgCmds[iIndex][0] = '\0';
|
||||
|
||||
iCmdIndex = 0;
|
||||
|
||||
consoleEnabled = false;
|
||||
|
||||
Con::addConsumer(macConsoleConsumer);
|
||||
|
||||
inpos = 0;
|
||||
|
||||
// !!!!TBD when system is overhauled...
|
||||
// lineOutput = true;
|
||||
lineOutput = false;
|
||||
|
||||
// Con::addVariable("MacConsoleEnabled", consoleEnableCallback, "false");
|
||||
|
||||
#if USE_SIOUX
|
||||
// set up the SIOUX stuff here for now.
|
||||
SIOUXSettings.standalone = false;
|
||||
SIOUXSettings.setupmenus = false;
|
||||
SIOUXSettings.initializeTB = false;
|
||||
SIOUXSettings.asktosaveonclose = false;
|
||||
SIOUXSettings.toppixel = 4 + 24; // why tie to GetMBarHeight(); ??
|
||||
SIOUXSettings.leftpixel = 4;
|
||||
SIOUXSettings.columns = 120;
|
||||
SIOUXSettings.rows = 40;
|
||||
#else
|
||||
// an apple sample showed this as a way to ready a std OSX console
|
||||
/*
|
||||
OSErr err;
|
||||
FSRef conAppFSRef;
|
||||
err = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.Console"), NULL, &conAppFSRef, NULL);
|
||||
if (err == noErr)
|
||||
{
|
||||
LSOpenFSRef(&conAppFSRef, NULL);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
MacConsole::~MacConsole()
|
||||
{
|
||||
Con::removeConsumer(macConsoleConsumer);
|
||||
}
|
||||
|
||||
void MacConsole::printf(const char *s, ...)
|
||||
{
|
||||
int bytes;
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
vprintf(s, args);
|
||||
// XXX See the Windows and LINUX versions for control-char-stripping ideas.
|
||||
// Basically we need to stick the output in a buffer so we can operate on
|
||||
// it before printing.
|
||||
}
|
||||
|
||||
void MacConsole::processConsoleLine(const char *consoleLine)
|
||||
{
|
||||
if(consoleEnabled)
|
||||
{
|
||||
inbuf[inpos] = 0;
|
||||
#if USE_SIOUX
|
||||
if (!lineOutput && inpos)
|
||||
printf("%c%s\n%s%s", '\r', consoleLine, Con::getVariable("Con::Prompt"), inbuf);
|
||||
else
|
||||
#endif
|
||||
printf("%s\n", consoleLine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool MacConsole::handleEvent(const EventRecord *msg)
|
||||
{
|
||||
if (consoleEnabled)
|
||||
{
|
||||
#if USE_SIOUX
|
||||
if (SIOUXHandleOneEvent((EventRecord*)msg))
|
||||
{
|
||||
if (msg->what==keyDown || msg->what==autoKey)
|
||||
{
|
||||
U8 ascii = msg->message & charCodeMask;
|
||||
U8 keyCode = TranslateOSKeyCode( (msg->message & keyCodeMask) >> 8 );
|
||||
process(keyCode, ascii);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
// on the mac, we call this after the console has consumed a keyboard event.
|
||||
void MacConsole::process(U8 keyCode, U8 ascii)
|
||||
{
|
||||
// for now, minimal processing.
|
||||
|
||||
if (consoleEnabled)
|
||||
{
|
||||
char outbuf[512];
|
||||
S32 outpos = 0;
|
||||
|
||||
switch (ascii)
|
||||
{
|
||||
// If no ASCII char, check if it's a handled virtual key
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
switch (keyCode)
|
||||
{
|
||||
// UP ARROW
|
||||
case KEY_UP:
|
||||
{
|
||||
// Go to the previous command in the cyclic array
|
||||
if ((-- iCmdIndex) < 0)
|
||||
iCmdIndex = MAX_CMDS - 1;
|
||||
|
||||
// If this command isn't empty ...
|
||||
if (rgCmds[iCmdIndex][0] != '\0')
|
||||
{
|
||||
// Obliterate current displayed text
|
||||
for (S32 i = outpos = 0; i < inpos; i ++)
|
||||
{
|
||||
outbuf[outpos ++] = '\b';
|
||||
outbuf[outpos ++] = ' ';
|
||||
outbuf[outpos ++] = '\b';
|
||||
}
|
||||
|
||||
// Copy command into command and display buffers
|
||||
for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos ++, outpos ++)
|
||||
{
|
||||
outbuf[outpos] = rgCmds[iCmdIndex][inpos];
|
||||
inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
|
||||
}
|
||||
}
|
||||
// If previous is empty, stay on current command
|
||||
else if ((++ iCmdIndex) >= MAX_CMDS)
|
||||
{
|
||||
iCmdIndex = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// DOWN ARROW
|
||||
case KEY_DOWN:
|
||||
{
|
||||
// Go to the next command in the command array, if
|
||||
// it isn't empty
|
||||
if (rgCmds[iCmdIndex][0] != '\0' && (++ iCmdIndex) >= MAX_CMDS)
|
||||
iCmdIndex = 0;
|
||||
|
||||
// Obliterate current displayed text
|
||||
for (S32 i = outpos = 0; i < inpos; i ++)
|
||||
{
|
||||
outbuf[outpos ++] = '\b';
|
||||
outbuf[outpos ++] = ' ';
|
||||
outbuf[outpos ++] = '\b';
|
||||
}
|
||||
|
||||
// Copy command into command and display buffers
|
||||
for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos ++, outpos ++)
|
||||
{
|
||||
outbuf[outpos] = rgCmds[iCmdIndex][inpos];
|
||||
inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// LEFT ARROW
|
||||
case KEY_LEFT:
|
||||
break;
|
||||
|
||||
// RIGHT ARROW
|
||||
case KEY_RIGHT:
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// backspace???
|
||||
case '\b':
|
||||
if(inpos > 0)
|
||||
{
|
||||
outbuf[outpos++] = '\b';
|
||||
outbuf[outpos++] = ' ';
|
||||
outbuf[outpos++] = '\b';
|
||||
inpos--;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
// In the output buffer, we're going to have to erase the current line (in case
|
||||
// we're cycling through various completions) and write out the whole input
|
||||
// buffer, so (inpos * 3) + complen <= 512. Should be OK. The input buffer is
|
||||
// also 512 chars long so that constraint will also be fine for the input buffer.
|
||||
{
|
||||
// Erase the current line.
|
||||
U32 i;
|
||||
for (i = 0; i < inpos; i++) {
|
||||
outbuf[outpos++] = '\b';
|
||||
outbuf[outpos++] = ' ';
|
||||
outbuf[outpos++] = '\b';
|
||||
}
|
||||
// Modify the input buffer with the completion.
|
||||
U32 maxlen = 512 - (inpos * 3);
|
||||
if (GetCurrentKeyModifiers() & shiftKeyBit) {
|
||||
inpos = Con::tabComplete(inbuf, inpos, maxlen, false);
|
||||
}
|
||||
else {
|
||||
inpos = Con::tabComplete(inbuf, inpos, maxlen, true);
|
||||
}
|
||||
|
||||
// Copy the input buffer to the output.
|
||||
for (i = 0; i < inpos; i++) {
|
||||
outbuf[outpos++] = inbuf[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// some kind of CR/LF
|
||||
case '\n':
|
||||
case '\r':
|
||||
// outbuf[outpos++] = '\r';
|
||||
outbuf[outpos++] = '\n';
|
||||
|
||||
inbuf[inpos] = 0;
|
||||
outbuf[outpos] = 0;
|
||||
|
||||
// for moment, don't echo final input, as SIOUX seems to be...
|
||||
// printf("%s", inbuf);
|
||||
|
||||
S32 eventSize;
|
||||
eventSize = ConsoleEventHeaderSize;
|
||||
|
||||
dStrcpy(postEvent.data, inbuf);
|
||||
postEvent.size = eventSize + dStrlen(inbuf) + 1;
|
||||
Game->postEvent(postEvent);
|
||||
|
||||
// If we've gone off the end of our array, wrap
|
||||
// back to the beginning
|
||||
if (iCmdIndex >= MAX_CMDS)
|
||||
iCmdIndex %= MAX_CMDS;
|
||||
|
||||
// Put the new command into the array
|
||||
strcpy(rgCmds[iCmdIndex ++], inbuf);
|
||||
|
||||
printf("%s", Con::getVariable("Con::Prompt"));
|
||||
inpos = outpos = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
inbuf[inpos++] = ascii;
|
||||
outbuf[outpos++] = ascii;
|
||||
break;
|
||||
}
|
||||
|
||||
if (outpos)
|
||||
{
|
||||
outbuf[outpos] = 0;
|
||||
printf("%s", outbuf);
|
||||
}
|
||||
}
|
||||
}
|
63
engine/platformMacCarb/macCarbConsole.h
Executable file
63
engine/platformMacCarb/macCarbConsole.h
Executable file
@ -0,0 +1,63 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBCONSOLE_H_
|
||||
#define _MACCARBCONSOLE_H_
|
||||
|
||||
#define MAX_CMDS 10
|
||||
#ifndef _CONSOLE_H_
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
#ifndef _EVENT_H_
|
||||
#include "Platform/event.h"
|
||||
#endif
|
||||
|
||||
#include <Events.h>
|
||||
|
||||
// this is where we determine whether to try and use raw STDIO, or whether
|
||||
// we try to base off of an external console library. SIOUX in MWERKS case.
|
||||
#if __MWERKS__
|
||||
#ifndef __MACH__
|
||||
#define USE_SIOUX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
class MacConsole
|
||||
{
|
||||
bool consoleEnabled;
|
||||
|
||||
ConsoleEvent postEvent;
|
||||
|
||||
char inbuf[512];
|
||||
S32 inpos;
|
||||
bool lineOutput;
|
||||
|
||||
char curTabComplete[512];
|
||||
S32 tabCompleteStart;
|
||||
|
||||
char rgCmds[MAX_CMDS][512];
|
||||
S32 iCmdIndex;
|
||||
|
||||
void printf(const char *s, ...);
|
||||
|
||||
public:
|
||||
static void create();
|
||||
static void destroy();
|
||||
static bool isEnabled();
|
||||
|
||||
MacConsole();
|
||||
~MacConsole();
|
||||
void enable(bool);
|
||||
|
||||
void processConsoleLine(const char *consoleLine);
|
||||
|
||||
bool handleEvent(const EventRecord *msg);
|
||||
void process(U8 keyCode, U8 ascii);
|
||||
};
|
||||
|
||||
extern MacConsole *gConsole;
|
||||
|
||||
#endif
|
873
engine/platformMacCarb/macCarbFileio.cc
Executable file
873
engine/platformMacCarb/macCarbFileio.cc
Executable file
@ -0,0 +1,873 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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>
|
||||
|
||||
#pragma message("todo: file io still needs some work...")
|
||||
|
||||
// this is the main working dir path.
|
||||
static StringTableEntry cwd = NULL;
|
||||
|
||||
#define MAX_MAC_PATH_LONG 2048
|
||||
// the str255 maxsize, allowing null termination and length byte.
|
||||
#define MAX_MAC_PATH 254
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#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 (Closed != currentStatus)
|
||||
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"); // impossible
|
||||
}
|
||||
|
||||
if (handle == NULL) // handle not created successfully
|
||||
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);
|
||||
|
||||
return currentStatus; // success!
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 (Ok != currentStatus && EOS != currentStatus)
|
||||
return currentStatus;
|
||||
|
||||
U32 finalPos;
|
||||
switch (absolutePos)
|
||||
{
|
||||
case true: // 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);
|
||||
break;
|
||||
case false: // relative position
|
||||
AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position");
|
||||
// position beyond EOS is OK
|
||||
fseek((FILE*)handle, position, SEEK_CUR);
|
||||
finalPos = ftell((FILE*)handle);
|
||||
}
|
||||
|
||||
if (0xffffffff == finalPos)
|
||||
return setStatus(); // unsuccessful
|
||||
else if (finalPos >= getSize())
|
||||
return currentStatus = EOS; // success, at end of file
|
||||
else
|
||||
return currentStatus = Ok; // success!
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
// this is not a very good way to do this
|
||||
U32 pos = ftell((FILE*)handle);
|
||||
fseek((FILE*)handle, 0, SEEK_END);
|
||||
U32 size = ftell((FILE*)handle);
|
||||
fseek((FILE*)handle, pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
else
|
||||
return 0; // unsuccessful
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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) == EOF)
|
||||
return setStatus(); // unsuccessful
|
||||
else
|
||||
return currentStatus = Ok; // success!
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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) == EOF)
|
||||
return setStatus(); // unsuccessful
|
||||
}
|
||||
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()
|
||||
{
|
||||
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;
|
||||
else
|
||||
{
|
||||
U32 lastBytes;
|
||||
U32 *bytes = (NULL == bytesRead) ? &lastBytes : bytesRead;
|
||||
if (fread(dst, size, 1, (FILE*)handle) != 1)
|
||||
{ // fread onlu reports the number of chunks read not bytes
|
||||
// so we don't know exactly how much was read
|
||||
*bytes = getPosition();
|
||||
return currentStatus = EOS; // end of stream
|
||||
}
|
||||
else
|
||||
{
|
||||
*bytes = size;
|
||||
return currentStatus = Ok; // unsuccessful
|
||||
}
|
||||
}
|
||||
return currentStatus = Ok; // successfully read size bytes
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
else
|
||||
{
|
||||
U32 lastBytes;
|
||||
U32 *bytes = (NULL == bytesWritten) ? &lastBytes : bytesWritten;
|
||||
if (fwrite(src, size, 1, (FILE*)handle) != 1)
|
||||
{ // fwrite onlu reports the number of chunks written not bytes
|
||||
// so we don't know exactly how much was written
|
||||
*bytes = getPosition();
|
||||
return setStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
*bytes = size;
|
||||
return currentStatus = Ok; // success!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 fStat;
|
||||
|
||||
if (stat(path, &fStat) == -1)
|
||||
return false;
|
||||
|
||||
if(createTime)
|
||||
*createTime = fStat.st_ctime;
|
||||
|
||||
if(modifyTime)
|
||||
*modifyTime = fStat.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 fStat;
|
||||
if( stat(file, &fStat) == 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; // !!!!!TBD
|
||||
}
|
||||
|
||||
|
||||
// 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 done = false;
|
||||
|
||||
while(!done)
|
||||
{
|
||||
// first look for game content inside the application bundle.
|
||||
CFURLRef workingUrl;
|
||||
if(inside)
|
||||
workingUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault,bundleUrl,CFSTR("Contents/Resources"),true);
|
||||
else
|
||||
workingUrl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, bundleUrl);
|
||||
|
||||
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're not looking inside.
|
||||
if(inside && ! isMainDotCsPresent(cwd_buf))
|
||||
{
|
||||
inside=false;
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
|
||||
CFRelease(workingUrl);
|
||||
CFRelease(workingString);
|
||||
CFRelease(normalizedString);
|
||||
}
|
||||
|
||||
//CFStringGetCString(workingString, cwd_buf, sizeof(cwd_buf)-1, kCFStringEncodingUTF8);
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::isFile(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
// make sure we can stat the file
|
||||
struct stat fStat;
|
||||
if( stat(path, &fStat) < 0 )
|
||||
return false;
|
||||
|
||||
// now see if it's a regular file
|
||||
if( (fStat.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 fStat;
|
||||
if( stat(path, &fStat) < 0 )
|
||||
return false;
|
||||
|
||||
// now see if it's a directory
|
||||
if( (fStat.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 fStat;
|
||||
if( stat(pFilePath, &fStat) < 0 )
|
||||
return 0;
|
||||
|
||||
// and return it's size in bytes
|
||||
return (S32)fStat.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(pathbuf));
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
ConsoleFunction(testFileDelete, bool, 2,2, "testFileDelete('path')")
|
||||
{
|
||||
return dFileDelete(argv[1]);
|
||||
}
|
||||
|
||||
#endif
|
12
engine/platformMacCarb/macCarbFileio.h
Normal file
12
engine/platformMacCarb/macCarbFileio.h
Normal file
@ -0,0 +1,12 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBFILEIO_H_
|
||||
#define _MACCARBFILEIO_H_
|
||||
|
||||
// only one exported func at the moment.
|
||||
void macGetHomeDirectory(void);
|
||||
|
||||
#endif // _MACCARBFILEIO_H_
|
435
engine/platformMacCarb/macCarbFont.cc
Executable file
435
engine/platformMacCarb/macCarbFont.cc
Executable file
@ -0,0 +1,435 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include "platformMacCarb/macCarbFont.h"
|
||||
#include "platformMacCarb/platformMacCarb.h"
|
||||
#include "dgl/gFont.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "Math/mRect.h"
|
||||
#include "console/console.h"
|
||||
#include "core/unicode.h"
|
||||
|
||||
#include <QDOffscreen.h>
|
||||
#include <Fonts.h>
|
||||
|
||||
static GWorldPtr fontgw = NULL;
|
||||
static Rect fontrect = {0,0,256,256};
|
||||
static short fontdepth = 32;
|
||||
static U8 rawmap[256*256];
|
||||
|
||||
|
||||
void createFontInit(void);
|
||||
void createFontShutdown(void);
|
||||
S32 CopyCharToRaw(U8 *raw, PixMapHandle pm, const Rect &r);
|
||||
|
||||
// !!!!! TBD this should be returning error, or raising exception...
|
||||
void createFontInit()
|
||||
{
|
||||
OSErr err = NewGWorld(&fontgw, fontdepth, &fontrect, NULL, NULL, keepLocal);
|
||||
AssertWarn(err==noErr, "Font system failed to initialize GWorld.");
|
||||
}
|
||||
|
||||
void createFontShutdown()
|
||||
{
|
||||
DisposeGWorld(fontgw);
|
||||
fontgw = NULL;
|
||||
}
|
||||
|
||||
U8 ColorAverage8(RGBColor &rgb)
|
||||
{
|
||||
return ((rgb.red>>8) + (rgb.green>>8) + (rgb.blue>>8)) / 3;
|
||||
}
|
||||
|
||||
S32 CopyCharToRaw(U8 *raw, PixMapHandle pmh, const Rect &r)
|
||||
{
|
||||
// walk the pixmap, copying into raw buffer.
|
||||
// we want bg black, fg white, which is opposite 'sign' from the pixmap (bg white, with black text)
|
||||
|
||||
// int off = GetPixRowBytes(pmh);
|
||||
// U32 *c = (U32*)GetPixBaseAddr(pmh);
|
||||
// U32 *p;
|
||||
|
||||
RGBColor rgb;
|
||||
|
||||
S32 i, j;
|
||||
U8 val, ca;
|
||||
S32 lastRow = -1;
|
||||
|
||||
for (i = r.left; i <= r.right; i++)
|
||||
{
|
||||
for (j = r.top; j <= r.bottom; j++)
|
||||
{
|
||||
// p = (U32*)(((U8*)c) + (j*off)); // since rowbytes is bytes not pixels, need to convert to byte * before doing the math...
|
||||
val = 0;
|
||||
// if (((*p)&0x00FFFFFF)==0) // then black pixel in current port, so want white in new buffer.
|
||||
GetCPixel(i, j, &rgb);
|
||||
if ((ca = ColorAverage8(rgb))<=250) // get's us some grays with a small slop factor.
|
||||
{
|
||||
val = 255 - ca; // flip sign, basically.
|
||||
lastRow = j; // track the last row in the rect that we actually saw an active pixel, finding descenders basically...
|
||||
}
|
||||
raw[i + (j<<8)] = val;
|
||||
// p++;
|
||||
}
|
||||
}
|
||||
|
||||
return(lastRow);
|
||||
}
|
||||
|
||||
GOldFont* createFont(const char *name, dsize_t size, U32 charset)
|
||||
{
|
||||
if(!name)
|
||||
return NULL;
|
||||
if(size < 1)
|
||||
return NULL;
|
||||
|
||||
bool wantsBold = false;
|
||||
short fontid;
|
||||
GetFNum(str2p(name), &fontid);
|
||||
if (fontid == 0)
|
||||
{
|
||||
// hmmm... see if it has "Bold" on the end. if so, remove it and try again.
|
||||
int len = dStrlen(name);
|
||||
if (len>4 && 0==dStricmp(name+len-4, "bold"))
|
||||
{
|
||||
char substr[128];
|
||||
dStrcpy(substr, name);
|
||||
len -= 5;
|
||||
substr[len] = 0; // new null termination.
|
||||
GetFNum(str2p(substr), &fontid);
|
||||
wantsBold = true;
|
||||
}
|
||||
|
||||
if (fontid == 0)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General,"Error creating font [%s (%d)] -- it doesn't exist on this machine.",name, size);
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Boolean aaWas;
|
||||
S16 aaSize;
|
||||
CGrafPtr savePort;
|
||||
GDHandle saveGD;
|
||||
GetGWorld(&savePort, &saveGD);
|
||||
|
||||
aaWas = IsAntiAliasedTextEnabled(&aaSize);
|
||||
SetAntiAliasedTextEnabled(true, 6);
|
||||
|
||||
RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF};
|
||||
RGBColor black = {0, 0, 0};
|
||||
PixMapHandle pmh;
|
||||
|
||||
SetGWorld(fontgw, NULL);
|
||||
PenNormal(); // reset pen attribs.
|
||||
// shouldn't really need to do this, right?
|
||||
RGBBackColor(&white);
|
||||
RGBForeColor(&black);
|
||||
|
||||
// set proper font.
|
||||
// mac fonts are coming out a bit bigger than PC - think PC is like 80-90dpi comparatively, vs 72dpi.
|
||||
// so, let's tweak here. 20=>16. 16=>13. 12=>9. 10=>7.
|
||||
TextSize(size - 2 - (int)((float)size * 0.1));
|
||||
TextFont(fontid);
|
||||
TextMode(srcCopy);
|
||||
if (wantsBold)
|
||||
TextFace(bold);
|
||||
|
||||
// get font info
|
||||
int cx, cy, ry, my;
|
||||
FontInfo fi;
|
||||
GetFontInfo(&fi); // gets us basic glyphs.
|
||||
cy = fi.ascent + fi.descent + fi.leading + 1; // !!!! HACK. Not per-char-specific.
|
||||
|
||||
pmh = GetGWorldPixMap(fontgw);
|
||||
|
||||
GOldFont *retFont = new GOldFont;
|
||||
|
||||
Rect b = {0,0,0,0};
|
||||
int drawBase = fi.ascent+1;
|
||||
int outBase = fi.ascent+fi.descent-1;
|
||||
for(S32 i = 32; i < 256; i++)
|
||||
{
|
||||
if (!LockPixels(pmh))
|
||||
{
|
||||
UpdateGWorld(&fontgw, fontdepth, &fontrect, NULL, NULL, keepLocal);
|
||||
pmh = GetGWorldPixMap(fontgw);
|
||||
// for now, assume we're good to go... TBD!!!!
|
||||
LockPixels(pmh);
|
||||
}
|
||||
|
||||
// clear the port.
|
||||
EraseRect(&fontrect);
|
||||
// reset position to left edge, bottom of line for this font style.
|
||||
MoveTo(0, drawBase);
|
||||
// draw char & calc its pixel width.
|
||||
DrawChar(i);
|
||||
cx = CharWidth(i);
|
||||
|
||||
b.right = cx+1;
|
||||
b.bottom = cy+1; // in case descenders drop too low, we want to catch the chars.
|
||||
ry = CopyCharToRaw(rawmap, pmh, b);
|
||||
|
||||
UnlockPixels(pmh);
|
||||
|
||||
if (ry<0) // bitmap was blank.
|
||||
{
|
||||
Con::printf("Blank character %c", i);
|
||||
if (cx)
|
||||
retFont->insertBitmap(i, rawmap, 0, 0, 0, 0, 0, cx);
|
||||
}
|
||||
else
|
||||
retFont->insertBitmap(i, rawmap, 256, cx+1, cy+1, 0, outBase, cx);
|
||||
}
|
||||
|
||||
retFont->pack(cy, outBase);
|
||||
|
||||
// if (actualChars==0)
|
||||
// Con::errorf(ConsoleLogEntry::General,"Error creating font: %s %d",name, size);
|
||||
|
||||
//clean up local vars
|
||||
if (aaWas)
|
||||
SetAntiAliasedTextEnabled(aaWas, aaSize);
|
||||
SetGWorld(savePort, saveGD);
|
||||
|
||||
return retFont;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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);
|
||||
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("Error: 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
|
||||
{
|
||||
return isValidChar(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
|
||||
|
||||
}
|
||||
|
||||
bool MacCarbFont::isValidChar( const UTF16 ch) const
|
||||
{
|
||||
// The expected behavior of this func is not well documented by the windows version,
|
||||
// and on the win side, is highly dependant on the font and code page.
|
||||
// Cutting out all the ASCII control chars seems like the right thing to do...
|
||||
// if you find a bug related to this assumption, please post a report.
|
||||
|
||||
// 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);
|
||||
c.width = imageRect.right - imageRect.left + 2; // add 2 because small fonts don't always have enough room
|
||||
c.height = imageRect.bottom - imageRect.top;
|
||||
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 == 0 || c.height == 0)
|
||||
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,0xa0F,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!
|
||||
err = ATSUDrawText( mLayout, 0, 1, IntToFixed(-imageRect.left+1), IntToFixed( imageRect.bottom ) );
|
||||
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 = %i %i %i %i 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= %i right= %i 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.
382
engine/platformMacCarb/macCarbGL.cc
Executable file
382
engine/platformMacCarb/macCarbGL.cc
Executable file
@ -0,0 +1,382 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/types.h"
|
||||
#if defined(TORQUE_OS_MAC_OSX)
|
||||
// AAAAAAAAARGGGH.
|
||||
// OSX Frameworks version of AGL.h includes CoreServices, which hits the
|
||||
// OpenTransport-has-a-new-but-platform.h-#defs-new-to-something-nonstandard
|
||||
// issue, so we need to pre-include OT here...
|
||||
#include <OpenTransport.h>
|
||||
#endif
|
||||
|
||||
#include "PlatformMacCarb/platformMacCarb.h"
|
||||
#include "PlatformMacCarb/platformGL.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include <AGL/agl.h>
|
||||
|
||||
GLState gGLState;
|
||||
|
||||
bool hwIsaRadeon = false; // for detecting Radeon-brand (R, R8500, R7500, R7200, etc...) boards.
|
||||
bool hwIsaR200 = false; // for detecting R200 (R8500, R8800, etc...) or later boards.
|
||||
|
||||
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;
|
||||
|
||||
// !!!!!TBD -- What to do about missing functions?? are they in 1.3???
|
||||
#define HANDLE_MISSING_EXTS 1
|
||||
#if HANDLE_MISSING_EXTS // until we decide how to actually implement these...
|
||||
|
||||
/*
|
||||
GLboolean mglAvailVB() { return(false); }
|
||||
GLint mglAllocVB(GLsizei size, GLint format, GLboolean preserve) { return(0); }
|
||||
void* mglLockVB(GLint handle, GLsizei size) { return(NULL); }
|
||||
void mglUnlockVB(GLint handle) {}
|
||||
void mglSetVB(GLint handle) {}
|
||||
void mglOffsetVB(GLint handle, GLuint offset) {}
|
||||
void mglFillVB(GLint handle, GLint first, GLsizei count) {}
|
||||
void mglFreeVB(GLint handle) {}
|
||||
void mglFogCP(GLenum type, GLsizei stride, const GLvoid *pointer) {}
|
||||
void mglColorTable(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) {}
|
||||
*/
|
||||
// maybe we don't need the extern C?
|
||||
#if GL_EXTERN_C
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
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) {}
|
||||
|
||||
// if the colortable stuff isn't declared, or we're building in PB but against < GL1.3, stub the colortable fn.
|
||||
#if !defined(GL_EXT_fog_coord) || !defined(__APPLE__) || !defined(GL_VERSION_1_3)
|
||||
void glFogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid *pointer) {}
|
||||
#endif
|
||||
|
||||
// if the colortable stuff isn't declared, or we're building in PB but against < GL1.3, stub the colortable fn.
|
||||
#if !defined(GL_EXT_paletted_texture) || !defined(__APPLE__) || !defined(GL_VERSION_1_3)
|
||||
void glColorTableEXT(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) {}
|
||||
#endif
|
||||
#if GL_EXTERN_C
|
||||
}
|
||||
#endif
|
||||
#endif // HANDLE_MISSING_EXTS
|
||||
|
||||
|
||||
// Load extensions. !!!TBD rename the darn function already.
|
||||
bool GL_EXT_Init( )
|
||||
{
|
||||
OSStatus err = 0;
|
||||
|
||||
// we only really need two of the strings.
|
||||
const char* pExtString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
|
||||
const char* pRendString = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
|
||||
// OpenGL Exists ========================================
|
||||
if (glBegin == (void *)kUnresolvedCFragSymbolAddress)
|
||||
{ // !!!!!!! TBD
|
||||
Con::printf("OpenGL Init: Failed to find OpenGL system library.");
|
||||
return(false);
|
||||
}
|
||||
|
||||
// pre-clear the structure!!!
|
||||
dMemset(&gGLState, 0, sizeof(gGLState));
|
||||
|
||||
// early hardware detection. // !!!TBD update for new boards.
|
||||
hwIsaRadeon = false;
|
||||
hwIsaR200 = false;
|
||||
if (pRendString && dStrstr(pRendString, (const char*)"ATI ") != NULL)
|
||||
{ // we know we're on an ATI renderer at least. now, which one??
|
||||
// first, check for 8500 variations
|
||||
if (dStrstr(pRendString, (const char*)"ATI R-") != NULL // that way, we'll catch R-300...
|
||||
|| dStrstr(pRendString, (const char*)"ATI R200") != NULL
|
||||
|| dStrstr(pRendString, (const char*)"ATI Radeon 8") != NULL) // catch 8500, 8800, etc.
|
||||
{
|
||||
hwIsaR200 = true;
|
||||
hwIsaRadeon = true; // if is an R200, it's >= Radeon.
|
||||
}
|
||||
else // wasn't an R200+, let's just look for Radeon
|
||||
if (dStrstr(pRendString, (const char*)"ATI Radeon"))
|
||||
{
|
||||
hwIsaRadeon = true;
|
||||
}
|
||||
}
|
||||
|
||||
// EXT_paletted_texture ========================================
|
||||
// glColorTableEXT = NULL;
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_paletted_texture") != NULL)
|
||||
gGLState.suppPalettedTexture = true;
|
||||
else
|
||||
gGLState.suppPalettedTexture = false;
|
||||
|
||||
// EXT_compiled_vertex_array ========================================
|
||||
/*
|
||||
glLockArraysEXT = NULL;
|
||||
glUnlockArraysEXT = NULL;
|
||||
*/
|
||||
gGLState.suppLockedArrays = false;
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_compiled_vertex_array") != NULL)
|
||||
gGLState.suppLockedArrays = true;
|
||||
//actually, OS9 crashes too. Specifically in Shadow::render(), so I patched it there for now.
|
||||
// gOpenGLDisableCVA = true;
|
||||
// HMMMM. !!!!TBD -- looks like it crashes in terrain editor as well.
|
||||
|
||||
// ARB_multitexture ========================================
|
||||
/*
|
||||
glActiveTextureARB = NULL;
|
||||
glClientActiveTextureARB = NULL;
|
||||
glMultiTexCoord2fARB = NULL;
|
||||
glMultiTexCoord2fvARB = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_ARB_multitexture") != NULL)
|
||||
gGLState.suppARBMultitexture = true;
|
||||
else
|
||||
gGLState.suppARBMultitexture = false;
|
||||
|
||||
// EXT_blend_color
|
||||
if(pExtString && dStrstr(pExtString, (const char*)"GL_EXT_blend_color") != NULL)
|
||||
gGLState.suppEXTblendcolor = true;
|
||||
else
|
||||
gGLState.suppEXTblendcolor = false;
|
||||
|
||||
// EXT_blend_minmax
|
||||
if(pExtString && dStrstr(pExtString, (const char*)"GL_EXT_blend_minmax") != NULL)
|
||||
gGLState.suppEXTblendminmax = true;
|
||||
else
|
||||
gGLState.suppEXTblendminmax = false;
|
||||
|
||||
// NV_vertex_array_range ========================================
|
||||
/*
|
||||
glVertexArrayRangeNV = dllVertexArrayRangeNV = NULL;
|
||||
glFlushVertexArrayRangeNV = dllFlushVertexArrayRangeNV = NULL;
|
||||
*/
|
||||
/*
|
||||
wglAllocateMemoryNV = NULL;
|
||||
wglFreeMemoryNV = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_NV_vertex_array_range") != NULL)
|
||||
gGLState.suppVertexArrayRange = true;
|
||||
else
|
||||
gGLState.suppVertexArrayRange = false;
|
||||
|
||||
|
||||
// EXT_fog_coord ========================================
|
||||
/*
|
||||
glFogCoordfEXT = NULL;
|
||||
glFogCoordPointerEXT = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_fog_coord") != NULL)
|
||||
gGLState.suppFogCoord = true;
|
||||
else
|
||||
gGLState.suppFogCoord = false;
|
||||
|
||||
// ARB_texture_compression ========================================
|
||||
/*
|
||||
glCompressedTexImage3DARB = NULL;
|
||||
glCompressedTexImage2DARB = NULL;
|
||||
glCompressedTexImage1DARB = NULL;
|
||||
glCompressedTexSubImage3DARB = NULL;
|
||||
glCompressedTexSubImage2DARB = NULL;
|
||||
glCompressedTexSubImage1DARB = NULL;
|
||||
glGetCompressedTexImageARB = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_ARB_texture_compression") != NULL)
|
||||
gGLState.suppTextureCompression = true;
|
||||
else
|
||||
gGLState.suppTextureCompression = false;
|
||||
|
||||
|
||||
// 3DFX_texture_compression_FXT1 ========================================
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_3DFX_texture_compression_FXT1") != NULL)
|
||||
gGLState.suppFXT1 = true;
|
||||
else
|
||||
gGLState.suppFXT1 = false;
|
||||
|
||||
|
||||
// EXT_texture_compression_S3TC ========================================
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_texture_compression_s3tc") != NULL)
|
||||
gGLState.suppS3TC = true;
|
||||
else
|
||||
gGLState.suppS3TC = false;
|
||||
|
||||
|
||||
// WGL_3DFX_gamma_control ========================================
|
||||
/*
|
||||
qwglGetDeviceGammaRamp3DFX = NULL;
|
||||
qwglSetDeviceGammaRamp3DFX = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"WGL_3DFX_gamma_control" ) != NULL)
|
||||
{
|
||||
// qwglGetDeviceGammaRamp3DFX = (qwglGetDeviceGammaRamp3DFX_t) qwglGetProcAddress( "wglGetDeviceGammaRamp3DFX" );
|
||||
// qwglSetDeviceGammaRamp3DFX = (qwglSetDeviceGammaRamp3DFX_t) qwglGetProcAddress( "wglSetDeviceGammaRamp3DFX" );
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// EXT_vertex_buffer ========================================
|
||||
/*
|
||||
glAvailableVertexBufferEXT = NULL;
|
||||
glAllocateVertexBufferEXT = NULL;
|
||||
glLockVertexBufferEXT = NULL;
|
||||
glUnlockVertexBufferEXT = NULL;
|
||||
glSetVertexBufferEXT = NULL;
|
||||
glOffsetVertexBufferEXT = NULL;
|
||||
glFillVertexBufferEXT = NULL;
|
||||
glFreeVertexBufferEXT = NULL;
|
||||
*/
|
||||
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_vertex_buffer") != NULL)
|
||||
{
|
||||
gGLState.suppVertexBuffer = true;
|
||||
AssertWarn(gGLState.suppVertexBuffer == false, "We're assuming no vertex bufffer support on Mac for now!");
|
||||
}
|
||||
else
|
||||
gGLState.suppVertexBuffer = false;
|
||||
|
||||
// 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 = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_packed_pixels") != NULL) : false;
|
||||
gGLState.suppPackedPixels |= pExtString? (dStrstr(pExtString, (const char*)"GL_APPLE_packed_pixel") != NULL) : false;
|
||||
|
||||
gGLState.suppTextureEnvCombine = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_combine") != NULL) : false;
|
||||
gGLState.suppTextureEnvCombine|= pExtString? (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_combine") != NULL) : false;
|
||||
|
||||
gGLState.suppEdgeClamp = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_edge_clamp") != NULL) : false;
|
||||
// whoops. there's another things to check for.
|
||||
gGLState.suppEdgeClamp |= pExtString? (dStrstr(pExtString, (const char*)"GL_SGIS_texture_edge_clamp") != NULL) : false;
|
||||
gGLState.suppEdgeClamp |= pExtString? (dStrstr(pExtString, (const char*)"GL_ARB_texture_border_clamp") != NULL) : false;
|
||||
|
||||
gGLState.suppTexEnvAdd = pExtString? (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_add") != NULL) : false;
|
||||
gGLState.suppTexEnvAdd |= pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_add") != NULL) : false;
|
||||
|
||||
// Anisotropic filtering ========================================
|
||||
gGLState.suppTexAnisotropic = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_filter_anisotropic") != NULL) : false;
|
||||
if (gGLState.suppTexAnisotropic)
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGLState.maxAnisotropy);
|
||||
|
||||
|
||||
// Texture combine units ========================================
|
||||
if (gGLState.suppARBMultitexture)
|
||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gGLState.maxTextureUnits);
|
||||
else
|
||||
gGLState.maxTextureUnits = 1;
|
||||
|
||||
|
||||
// Swap interval ========================================
|
||||
// if (pExtString && dStrstr(pExtString, (const char*)"WGL_EXT_swap_control") != NULL)
|
||||
// gGLState.suppSwapInterval = true; //( qwglSwapIntervalEXT != NULL );
|
||||
// else
|
||||
// Mac inherently supports a swap interval AGL-set-integer extension.
|
||||
gGLState.suppSwapInterval = true;
|
||||
|
||||
|
||||
// FSAA support, currently Radeon++/ATI only.
|
||||
gGLState.maxFSAASamples = 0;
|
||||
if (hwIsaRadeon)
|
||||
{
|
||||
// default to off.
|
||||
gGLState.maxFSAASamples = 1;
|
||||
}
|
||||
|
||||
// console out all the extensions...
|
||||
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(" WGL_EXT_swap_control");
|
||||
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(" WGL_EXT_swap_control");
|
||||
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);
|
||||
}
|
||||
|
||||
if (gGLState.maxFSAASamples>1)
|
||||
{
|
||||
gFSAASamples = Con::getIntVariable("$pref::OpenGL::numFSAASamples", gGLState.maxFSAASamples<<1);
|
||||
dglSetFSAASamples(gFSAASamples);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this is currently only for Radeon++ ATI boards
|
||||
// pass in 1 for normal/no-AA, 2 for 2x-AA, 4 for 4x-AA.
|
||||
void dglSetFSAASamples(GLint aasamp)
|
||||
{
|
||||
if (gGLState.maxFSAASamples<2) return;
|
||||
if (!hwIsaRadeon) return; // sanity check.
|
||||
|
||||
// for the moment, don't assume values passed in are capped min/max.
|
||||
if (aasamp<1) aasamp = 1;
|
||||
else
|
||||
if (aasamp==3) aasamp = 2;
|
||||
else
|
||||
if (aasamp>4) aasamp = 4;
|
||||
|
||||
// !!!!TBD method for OSX invocation.
|
||||
aglSetInteger((AGLContext)platState.ctx, AGLSETINT_ATI_FSAA_SAMPLES, (const long*)&aasamp);
|
||||
|
||||
Con::printf(">>Number of FSAA samples is now [%d].", aasamp);
|
||||
Con::setIntVariable("$pref::OpenGL::numFSAASamples", aasamp);
|
||||
if (Con::getIntVariable("$pref::TradeshowDemo", 0))
|
||||
Con::executef(2, "setFSAABadge", aasamp>1?"true":"false");
|
||||
}
|
204
engine/platformMacCarb/macCarbHeaders.h
Normal file
204
engine/platformMacCarb/macCarbHeaders.h
Normal file
@ -0,0 +1,204 @@
|
||||
// >>> MODIFIED CARBON.H FOR DIRECT INCLUSION IN TORQUE CODEBASE
|
||||
// >>> INCLUDES MINIMUM-NECESSARY GENERAL-USE HEADERS.
|
||||
|
||||
#ifndef __MINCARBON__
|
||||
#define __MINCARBON__
|
||||
|
||||
//#ifndef __CORESERVICES__
|
||||
//#include <CoreServices.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __APPLICATIONSERVICES__
|
||||
//#include <ApplicationServices.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __EVENTS__
|
||||
#include <Events.h>
|
||||
#endif
|
||||
|
||||
#ifndef __PROCESSES__
|
||||
#include <Processes.h>
|
||||
#endif
|
||||
|
||||
#ifndef __NOTIFICATION__
|
||||
#include <Notification.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __DRAG__
|
||||
//#include <Drag.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ICONS__
|
||||
//#include <Icons.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __CONTROLS__
|
||||
#include <Controls.h>
|
||||
#endif
|
||||
|
||||
#ifndef __APPEARANCE__
|
||||
#include <Appearance.h>
|
||||
#endif
|
||||
|
||||
#ifndef __MACWINDOWS__
|
||||
#include <MacWindows.h>
|
||||
#endif
|
||||
|
||||
#ifndef __TEXTEDIT__
|
||||
#include <TextEdit.h>
|
||||
#endif
|
||||
|
||||
#ifndef __MENUS__
|
||||
#include <Menus.h>
|
||||
#endif
|
||||
|
||||
#ifndef __DIALOGS__
|
||||
#include <Dialogs.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __LISTS__
|
||||
//#include <Lists.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __CARBONEVENTS__
|
||||
//#include <CarbonEvents.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __TEXTSERVICES__
|
||||
//#include <TextServices.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __SCRAP__
|
||||
#include <Scrap.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __MACTEXTEDITOR__
|
||||
//#include <MacTextEditor.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __MACHELP__
|
||||
//#include <MacHelp.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __CONTROLDEFINITIONS__
|
||||
#include <ControlDefinitions.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __TSMTE__
|
||||
//#include <TSMTE.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __TRANSLATIONEXTENSIONS__
|
||||
//#include <TranslationExtensions.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __TRANSLATION__
|
||||
//#include <Translation.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __AEINTERACTION__
|
||||
//#include <AEInteraction.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __TYPESELECT__
|
||||
//#include <TypeSelect.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __INTERNETCONFIG__
|
||||
//#include <InternetConfig.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __SOUND__
|
||||
#include <Sound.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __OSA__
|
||||
//#include <OSA.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __OSACOMP__
|
||||
//#include <OSAComp.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __OSAGENERIC__
|
||||
//#include <OSAGeneric.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __APPLESCRIPT__
|
||||
//#include <AppleScript.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ASDEBUGGING__
|
||||
//#include <ASDebugging.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ASREGISTRY__
|
||||
//#include <ASRegistry.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __FINDERREGISTRY__
|
||||
//#include <FinderRegistry.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __PMAPPLICATION__
|
||||
//#include <PMApplication.h>
|
||||
//#endif
|
||||
|
||||
#ifndef __NAVIGATION__
|
||||
#include <Navigation.h>
|
||||
#endif
|
||||
|
||||
#ifndef __URLACCESS__
|
||||
#include <URLAccess.h>
|
||||
#endif
|
||||
|
||||
#ifndef __COLORPICKER__
|
||||
#include <ColorPicker.h>
|
||||
#endif
|
||||
|
||||
//#ifndef __CMCALIBRATOR__
|
||||
//#include <CMCalibrator.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __HTMLRENDERING__
|
||||
//#include <HTMLRendering.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __SPEECHRECOGNITION__
|
||||
//#include <SpeechRecognition.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __NSL__
|
||||
//#include <NSL.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __FINDBYCONTENT__
|
||||
//#include <FindByContent.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __KEYCHAINHI__
|
||||
//#include <KeychainHI.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __IBCARBONRUNTIME__
|
||||
//#include <IBCarbonRuntime.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __APPLEHELP__
|
||||
//#include <AppleHelp.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ICAAPPLICATION__
|
||||
//#include <ICAApplication.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ICADEVICE__
|
||||
//#include <ICADevice.h>
|
||||
//#endif
|
||||
|
||||
//#ifndef __ICACAMERA__
|
||||
//#include <ICACamera.h>
|
||||
//#endif
|
||||
|
||||
#endif /* __MINCARBON__ */
|
||||
|
907
engine/platformMacCarb/macCarbInput.cc
Executable file
907
engine/platformMacCarb/macCarbInput.cc
Executable file
@ -0,0 +1,907 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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"
|
||||
|
||||
// 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);
|
||||
|
||||
// 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()
|
||||
{
|
||||
//Con::printf( "[]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];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(TORQUE_MAC_HAS_PASTEBOARD)
|
||||
PasteboardRef getMacClipboard( void )
|
||||
{
|
||||
static PasteboardRef sClipboard = NULL;
|
||||
if( sClipboard == NULL )
|
||||
PasteboardCreate( kPasteboardClipboard, &sClipboard );
|
||||
return sClipboard;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clipboard functions
|
||||
const char* Platform::getClipboard()
|
||||
{
|
||||
#if defined(TORQUE_MAC_HAS_PASTEBOARD)
|
||||
// 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.
|
||||
ItemCount itemCount;
|
||||
PasteboardRef clip;
|
||||
|
||||
// get a local ref to the system clipboard
|
||||
clip = getMacClipboard();
|
||||
// sync it up with the system clipboard
|
||||
PasteboardSynchronize(clip);
|
||||
// and be sure there's something there...
|
||||
PasteboardGetItemCount( clip, &itemCount );
|
||||
if( itemCount < 1 )
|
||||
return "";
|
||||
|
||||
// loop through the pasteboard items.
|
||||
for( U32 i=1; i <= itemCount; i++)
|
||||
{
|
||||
CFIndex flavorCount;
|
||||
CFArrayRef flavorArray;
|
||||
PasteboardItemID itemID;
|
||||
|
||||
// get the flavors...
|
||||
PasteboardGetItemIdentifier(clip, i, &itemID);
|
||||
PasteboardCopyItemFlavors(clip, itemID, &flavorArray);
|
||||
flavorCount = CFArrayGetCount( flavorArray );
|
||||
|
||||
// and now, we loop through the flavors
|
||||
for( CFIndex flavor=0; flavor < flavorCount; flavor++ )
|
||||
{
|
||||
CFStringRef flavorName;
|
||||
CFDataRef flavorData;
|
||||
U32 dataSize;
|
||||
char* retBuf;
|
||||
// get the type string for this flavor;
|
||||
flavorName = (CFStringRef)CFArrayGetValueAtIndex(flavorArray, flavor);
|
||||
|
||||
// ok, if it's not plain text, we don't want it.
|
||||
if (! UTTypeConformsTo(flavorName, CFSTR("public.plain-text"))) // TODO: unicode
|
||||
continue;
|
||||
|
||||
// grab the data,
|
||||
PasteboardCopyItemFlavorData(clip, itemID, flavorName, &flavorData);
|
||||
|
||||
// and copy it to a buffer.
|
||||
dataSize = CFDataGetLength(flavorData);
|
||||
retBuf = Con::getReturnBuffer(dataSize+1); // +1 for the \0 terminator
|
||||
dStrncpy(retBuf, (const char*)CFDataGetBytePtr(flavorData), dataSize);
|
||||
retBuf[dataSize] = '\0';
|
||||
|
||||
// we're required to release the data ref.
|
||||
CFRelease(flavorData);
|
||||
|
||||
return retBuf;
|
||||
} // flavor loop
|
||||
} // items loop
|
||||
|
||||
#endif //TORQUE_MAC_HAS_PASTEBOARD
|
||||
// we didn't find anything, return empty string
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Platform::setClipboard(const char *text)
|
||||
{
|
||||
#if defined(TORQUE_MAC_HAS_PASTEBOARD)
|
||||
PasteboardRef clip;
|
||||
CFDataRef textData = NULL;
|
||||
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
|
||||
clip = getMacClipboard();
|
||||
// clear it, and sync it up with the system clipboard
|
||||
PasteboardClear(clip);
|
||||
PasteboardSynchronize(clip);
|
||||
|
||||
// prep the data for the clipboard.
|
||||
textData = CFDataCreate( kCFAllocatorDefault, (const UInt8*)text, textSize );
|
||||
// put the data on the clipboard and synchronize it.
|
||||
err = PasteboardPutItemFlavor( clip, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), textData, kPasteboardFlavorNoFlags );
|
||||
PasteboardSynchronize(clip);
|
||||
// and see if we were successful.
|
||||
if( err == noErr )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
// pasteboard not available on this os, so fail.
|
||||
return false;
|
||||
#endif // TORQUE_MAC_HAS_PASTEBOARD
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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()
|
||||
{
|
||||
// Con::printf( ">> em one." );
|
||||
if ( !gInputEnabled )
|
||||
return( false );
|
||||
|
||||
// Con::printf( ">> em two." );
|
||||
if ( gMouseEnabled && gMouseActive )
|
||||
return( true );
|
||||
|
||||
// Con::printf( ">> em three." );
|
||||
gMouseEnabled = true; //i.e., allowed. needed to call activate...
|
||||
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()
|
||||
{
|
||||
// Con::printf( ">> am one. %s %s %s", gInputEnabled?"true":"false", Input::isActive()?"true":"false", gMouseEnabled?"true":"false");
|
||||
if ( !gInputEnabled || !Input::isActive() || !gMouseEnabled )
|
||||
return( false );
|
||||
|
||||
if (gMouseActive)
|
||||
return(true); // we're already set up.
|
||||
|
||||
// Con::printf( ">> am two." );
|
||||
|
||||
gMouseActive = true;
|
||||
|
||||
// Con::printf( ">> am three." );
|
||||
|
||||
// Con::printf( ">> am four." );
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleFunction( permDisableMouse, void, 1, 1, "permDisableMouse()" )
|
||||
{
|
||||
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();
|
||||
}
|
66
engine/platformMacCarb/macCarbMath.cc
Executable file
66
engine/platformMacCarb/macCarbMath.cc
Executable file
@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "console/console.h"
|
||||
#include "Math/mMath.h"
|
||||
|
||||
|
||||
extern void mInstallLibrary_C();
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
ConsoleFunction( MathInit, void, 1, 10, "(DETECT|C|FPU)")
|
||||
{
|
||||
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, "FPU") == 0) {
|
||||
properties |= CPU_PROP_FPU;
|
||||
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 (properties & CPU_PROP_FPU)
|
||||
{
|
||||
Con::printf(" Installing FPU extensions");
|
||||
}
|
||||
Con::printf(" ");
|
||||
}
|
||||
|
||||
|
62
engine/platformMacCarb/macCarbMemory.cc
Executable file
62
engine/platformMacCarb/macCarbMemory.cc
Executable file
@ -0,0 +1,62 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
//#include "PlatformMacCarb/platformMacCarb.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//--------------------------------------
|
||||
#ifdef new
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
void* FN_CDECL operator new(dsize_t dt, void* ptr)
|
||||
{
|
||||
// if we're not going to clear to NULL, DON'T CLEAR IT AT ALL!!!
|
||||
#ifdef TORQUE_DEBUG
|
||||
dMemset(ptr, 0xFF, dt);
|
||||
#endif
|
||||
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 m;
|
||||
}
|
||||
|
||||
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
|
851
engine/platformMacCarb/macCarbNet.cc
Executable file
851
engine/platformMacCarb/macCarbNet.cc
Executable file
@ -0,0 +1,851 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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>
|
||||
|
||||
// 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);
|
||||
// sockAddr->sin_addr.s_addr = address->netNum[0]; // hopefully this will work.
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#if !defined(__FreeBSD__)
|
||||
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];
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Poll for write status. this blocks. should really
|
||||
// do this in a separate thread or set it up so that the data can
|
||||
// get queued and sent later
|
||||
// JMQTODO
|
||||
// The polling is here to work around a bug in the linux OS sockets:
|
||||
// when a socket is opened, it is for an instant not writeable, so
|
||||
// if you create one and immediately try to write to it, it kicks back an error.
|
||||
// that's inconvinent, so we poll for writeable status to work around that.
|
||||
if( netSocketWaitForWritable(socket, 1) ) // 1 millisec ought to be plenty...
|
||||
{
|
||||
|
||||
S32 error = ::send(socket, (const char*)buffer, bufferSize, 0);
|
||||
if(error != -1)
|
||||
return NoError;
|
||||
}
|
||||
|
||||
Con::errorf("Socket not ready to write!");
|
||||
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;
|
||||
return Net::UnknownError;
|
||||
}
|
1943
engine/platformMacCarb/macCarbOGLVideo.cc
Executable file
1943
engine/platformMacCarb/macCarbOGLVideo.cc
Executable file
File diff suppressed because it is too large
Load Diff
42
engine/platformMacCarb/macCarbOGLVideo.h
Executable file
42
engine/platformMacCarb/macCarbOGLVideo.h
Executable file
@ -0,0 +1,42 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MACCARBOGLVIDEO_H_
|
||||
#define _MACCARBOGLVIDEO_H_
|
||||
|
||||
#ifndef _PLATFORMVIDEO_H_
|
||||
#include "Platform/platformVideo.h"
|
||||
#endif
|
||||
|
||||
class OpenGLDevice : public DisplayDevice
|
||||
{
|
||||
bool mCanChangeGamma;
|
||||
bool mRestoreGamma;
|
||||
U16 mOriginalRamp[256*3];
|
||||
|
||||
public:
|
||||
OpenGLDevice();
|
||||
|
||||
bool enumDisplayModes(GDHandle hDevice);
|
||||
|
||||
void initDevice();
|
||||
bool activate( U32 width, U32 height, U32 bpp, bool fullScreen );
|
||||
|
||||
bool GLCleanupHelper();
|
||||
void shutdown();
|
||||
void destroy();
|
||||
|
||||
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 );
|
||||
|
||||
static DisplayDevice* create();
|
||||
};
|
||||
|
||||
#endif // _MACCARBOGLVIDEO_H_
|
27
engine/platformMacCarb/macCarbProcessControl.cc
Executable file
27
engine/platformMacCarb/macCarbProcessControl.cc
Executable file
@ -0,0 +1,27 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "PlatformMacCarb/platformMacCarb.h"
|
||||
|
||||
#pragma message("macCarbProcessControl: need to get the right OSX path here")
|
||||
#include "Processes.h"
|
||||
|
||||
void Platform::postQuitMessage(const U32 in_quitVal)
|
||||
{
|
||||
platState.quit = true;
|
||||
}
|
||||
|
||||
void Platform::debugBreak()
|
||||
{
|
||||
#pragma message("Platform::debugBreak [not yet perfect]")
|
||||
DebugStr("\pDEBUG_BREAK!");
|
||||
}
|
||||
|
||||
void Platform::forceShutdown(S32 returnValue)
|
||||
{
|
||||
#pragma message("Platform::forceShutdown [not yet perfect]")
|
||||
ExitToShell();
|
||||
//exit(returnValue);
|
||||
}
|
99
engine/platformMacCarb/macCarbSemaphore.cc
Executable file
99
engine/platformMacCarb/macCarbSemaphore.cc
Executable file
@ -0,0 +1,99 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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...
|
||||
|
||||
#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().");
|
||||
}
|
509
engine/platformMacCarb/macCarbStrings.cc
Executable file
509
engine/platformMacCarb/macCarbStrings.cc
Executable file
@ -0,0 +1,509 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
S32 i;
|
||||
char c1, c2;
|
||||
for (i=0; i<len; i++)
|
||||
{
|
||||
c1 = tolower(*str1++);
|
||||
c2 = tolower(*str2++);
|
||||
if (c1 < c2) return -1;
|
||||
if (c1 > c2) return 1;
|
||||
if (!c1) return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
/*dsize_t dStrlenUTF8_fast(const UTF8 *str)
|
||||
{
|
||||
// we do not run this through the operating system, because this method may be faster.
|
||||
int c = 0;
|
||||
for(; str; str = getNextUTF8Char(str))
|
||||
c++;
|
||||
|
||||
return c;
|
||||
}
|
||||
*/
|
||||
/*dsize_t dStrlenUTF8(const UTF8 *str)
|
||||
{
|
||||
CFStringRef cfstr;
|
||||
U32 cfstrlen;
|
||||
|
||||
if(!str)
|
||||
return 0;
|
||||
|
||||
cfstr = CFStringCreateWithCString( kCFAllocatorDefault, (char*)str, kCFStringEncodingUTF8);
|
||||
if(!cfstr)
|
||||
return 0;
|
||||
cfstrlen = CFStringGetLength(cfstr);
|
||||
CFRelease(cfstr);
|
||||
|
||||
return cfstrlen;
|
||||
|
||||
}
|
||||
*/
|
||||
/*dsize_t dStrlen(const UTF16 *str)
|
||||
{
|
||||
int i=0;
|
||||
while(str[i] != 0x0000) i++;
|
||||
|
||||
return i;
|
||||
|
||||
// slower than just counting wchars, but makes sure surrogate pairs are dealt with correctly.
|
||||
CFStringRef cfstr;
|
||||
U32 cfstrlen;
|
||||
|
||||
cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (char*)str, kCFStringEncodingUnicode);
|
||||
cfstrlen = CFStringGetLength(cfstr);
|
||||
CFRelease(cfstr);
|
||||
|
||||
return cfstrlen;
|
||||
}
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
return atoi(str);
|
||||
}
|
||||
|
||||
|
||||
float dAtof(const char *str)
|
||||
{
|
||||
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);
|
||||
|
||||
// to-do
|
||||
// The intended behavior is to zero-terminate and not allow the overflow
|
||||
return (len);
|
||||
}
|
||||
|
||||
int dSprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
S32 len = vsprintf(buffer, format, args);
|
||||
|
||||
#warning "need to added zero-term + overflow handling"
|
||||
// to-do
|
||||
// The intended behavior is to zero-terminate and not allow the overflow
|
||||
return (len);
|
||||
}
|
||||
|
||||
|
||||
int dVsprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, void *arglist)
|
||||
{
|
||||
S32 len = vsprintf(buffer, format, (char*)arglist);
|
||||
|
||||
#warning "need to added zero-term + overflow handling"
|
||||
// to-do
|
||||
// The intended behavior is to zero-terminate and not allow the overflow
|
||||
return (len);
|
||||
}
|
||||
|
||||
|
||||
int dSscanf(const char *buffer, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
// return __vsscanf(buffer, format, args);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Mac Strinng conversion routines
|
||||
U8* str2p(const char *str)
|
||||
{
|
||||
static U8 buffer[256];
|
||||
str2p(str, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
U8* str2p(const char *str, U8 *p)
|
||||
{
|
||||
AssertFatal(dStrlen(str) <= 255, "str2p:: Max Pascal String length exceeded (max=255).");
|
||||
U8 *dst = p+1;
|
||||
U8 *src = (U8*)str;
|
||||
*p = 0;
|
||||
while(*src != '\0')
|
||||
{
|
||||
*dst++ = *src++;
|
||||
(*p) += 1;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
char* p2str(U8 *p)
|
||||
{
|
||||
static char buffer[256];
|
||||
p2str(p, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
char* p2str(U8 *p, char *dst_str)
|
||||
{
|
||||
U8 len = *p++;
|
||||
char *src = (char*)p;
|
||||
char *dst = dst_str;
|
||||
while (len--)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
return dst_str;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Unicode string conversions
|
||||
//------------------------------------------------------------------------------
|
||||
/*UTF8 * convertUTF16toUTF8(const UTF16 *string, UTF8 *buffer, U32 bufsize)
|
||||
{
|
||||
PROFILE_START(convertUTF16toUTF8);
|
||||
// use a CFString to convert the unicode string.
|
||||
// CFStrings use a UTF16 based backing store.
|
||||
// the last kCFAllocatorNull parameter is a deallocator for the string passed in.
|
||||
// we pass the Null allocator so that string will not be klobbered.
|
||||
// note: on 10.4+, another constant, kCFStringEncodingUTF16 is available, and
|
||||
// it is an alias for kCFStringEncodingUnicode.
|
||||
// see: http://developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/Reference/chapter_2.2_section_1.html
|
||||
bool ok;
|
||||
CFStringRef cfstr;
|
||||
|
||||
U32 len = dStrlen(string);
|
||||
cfstr = CFStringCreateWithCharacters( kCFAllocatorDefault, string, len);
|
||||
//cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (const char*)string, kCFStringEncodingUnicode);
|
||||
AssertFatal(cfstr != NULL, "Unicode string conversion failed - couldn't make the CFString!");
|
||||
|
||||
ok = CFStringGetCString( cfstr, (char*)buffer, bufsize, kCFStringEncodingUTF8);
|
||||
CFRelease(cfstr);
|
||||
|
||||
AssertWarn( ok, "Unicode string conversion failed in convertUTF16toUTF8()");
|
||||
if( !ok ) {
|
||||
PROFILE_END();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer[bufsize-1] = 0x00;
|
||||
|
||||
PROFILE_END();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
UTF16 * convertUTF8toUTF16(const UTF8 *string, UTF16 *buffer, U32 bufsize)
|
||||
{
|
||||
// see above notes in convertUTF16toUTF8() for an explanation of the following.
|
||||
// what we do here is exactly the same process as above, but in reverse.
|
||||
PROFILE_START(convertUTF8toUTF16);
|
||||
bool ok;
|
||||
CFStringRef cfstr;
|
||||
if( !string || string[0] == '\0' )
|
||||
goto returnNull;
|
||||
|
||||
cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (char*)string, kCFStringEncodingUTF8);
|
||||
if(!cfstr)
|
||||
goto returnNull;
|
||||
|
||||
ok = CFStringGetCString( cfstr, (char*)buffer, bufsize*sizeof(UTF16), kCFStringEncodingUnicode);
|
||||
CFRelease(cfstr);
|
||||
|
||||
AssertWarn( ok, "Unicode string conversion failed or buffer was too small in convertUTF8toUTF16()");
|
||||
if( !ok )
|
||||
goto returnNull;
|
||||
|
||||
buffer[bufsize-1] = 0x000;
|
||||
|
||||
PROFILE_END();
|
||||
return buffer;
|
||||
|
||||
returnNull:
|
||||
PROFILE_END();
|
||||
return NULL;
|
||||
}
|
||||
*/
|
252
engine/platformMacCarb/macCarbThread.cc
Executable file
252
engine/platformMacCarb/macCarbThread.cc
Executable file
@ -0,0 +1,252 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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>
|
||||
|
||||
struct MacThreadData
|
||||
{
|
||||
ThreadRunFunction mRunFunc;
|
||||
S32 mRunArg;
|
||||
Thread * mThread;
|
||||
//void * mSemaphore;
|
||||
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);
|
||||
//Semaphore::releaseSemaphore(threadData->mSemaphore);
|
||||
pthread_mutex_unlock(&(threadData->mMutt));
|
||||
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;
|
||||
// threadData->mSemaphore = Semaphore::createSemaphore();
|
||||
pthread_mutex_init(&(threadData->mMutt),NULL);
|
||||
|
||||
|
||||
mData = reinterpret_cast<void*>(threadData);
|
||||
if (start_thread)
|
||||
start();
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
join();
|
||||
|
||||
MacThreadData * threadData = reinterpret_cast<MacThreadData*>(mData);
|
||||
//Semaphore::destroySemaphore(threadData->mSemaphore);
|
||||
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.
|
||||
//Semaphore::acquireSemaphore(threadData->mSemaphore);
|
||||
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);
|
||||
// return(Semaphore::acquireSemaphore(threadData->mSemaphore));
|
||||
pthread_mutex_lock(&(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);
|
||||
|
||||
//bool signal = Semaphore::acquireSemaphore(threadData->mSemaphore, false);
|
||||
if( pthread_mutex_trylock(&(threadData->mMutt)) == 0 )
|
||||
{
|
||||
//Semaphore::releaseSemaphore(threadData->mSemaphore);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
static void *gMut1 = Mutex::createMutex();
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
#endif // TORQUE_MAC_THREAD_TESTS
|
61
engine/platformMacCarb/macCarbTime.cc
Executable file
61
engine/platformMacCarb/macCarbTime.cc
Executable file
@ -0,0 +1,61 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "PlatformMacCarb/platformMacCarb.h"
|
||||
#include <time.h>
|
||||
#include <timer.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;
|
||||
|
||||
time( &long_time ); // Get time as long integer.
|
||||
systime = localtime( &long_time ); // Convert to local time.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
U32 Platform::getTime()
|
||||
{
|
||||
time_t long_time;
|
||||
time( &long_time );
|
||||
return long_time;
|
||||
}
|
||||
|
||||
U32 Platform::getRealMilliseconds()
|
||||
{
|
||||
UnsignedWide time;
|
||||
Microseconds(&time);
|
||||
return (time.hi*0x100000000LL)/1000 + (time.lo/1000);
|
||||
}
|
||||
|
||||
U32 Platform::getVirtualMilliseconds()
|
||||
{
|
||||
return platState.currentTime;
|
||||
}
|
||||
|
||||
void Platform::advanceTime(U32 delta)
|
||||
{
|
||||
platState.currentTime += delta;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
2486
engine/platformMacCarb/macCarbWindow.cc
Executable file
2486
engine/platformMacCarb/macCarbWindow.cc
Executable file
File diff suppressed because it is too large
Load Diff
32
engine/platformMacCarb/macCarb_common_prefix.h
Executable file
32
engine/platformMacCarb/macCarb_common_prefix.h
Executable file
@ -0,0 +1,32 @@
|
||||
//------------------------------
|
||||
//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
|
||||
|
||||
#ifndef CARBON_VERSION
|
||||
#if defined(TORQUE_OS_MAC_OSX)
|
||||
#define CARBON_VERSION 0x0120 // what carbon shipped with 10.0???? !!!!TBD
|
||||
#else
|
||||
#define CARBON_VERSION 0x0104 // the carbon version # we are targeting.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// MAC_OS_X_VERSION_10_3 == 1030 , and may not exist if we're pre 10.3, so use the raw value here
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
|
||||
#define TORQUE_MAC_HAS_PASTEBOARD
|
||||
#endif
|
19
engine/platformMacCarb/macCarb_debug_prefix.h
Normal file
19
engine/platformMacCarb/macCarb_debug_prefix.h
Normal file
@ -0,0 +1,19 @@
|
||||
//maccarb_debug_prefix.h
|
||||
|
||||
#include "maccarb_common_prefix.h"
|
||||
|
||||
// our defines
|
||||
#define TGE_DEBUG 1
|
||||
#define BUILD_SUFFIX "_DEBUG"
|
||||
#define DEBUG 1
|
||||
#define ENABLE_ASSERTS 1
|
||||
|
||||
// Mac uses C version of ITFDump code.
|
||||
#define ITFDUMP_NOASM 1
|
||||
|
||||
//#define USEASSEMBLYTERRBLEND 1
|
||||
|
||||
#define PNG_NO_READ_tIME 1
|
||||
#define PNG_NO_WRITE_TIME 1
|
||||
|
||||
#define NO_MILES_OPENAL 1
|
23
engine/platformMacCarb/macCarb_release_prefix.h
Normal file
23
engine/platformMacCarb/macCarb_release_prefix.h
Normal file
@ -0,0 +1,23 @@
|
||||
//maccarb_release_prefix.h
|
||||
|
||||
#include "maccarb_common_prefix.h"
|
||||
|
||||
// our defines
|
||||
#define TGE_RELEASE 1
|
||||
#define TGE_NO_ASSERTS 1
|
||||
#define BUILD_SUFFIX ""
|
||||
|
||||
// these should be off in a release build
|
||||
//#define DEBUG 1
|
||||
//#define ENABLE_ASSERTS 1
|
||||
|
||||
// Mac uses C version of ITFDump code.
|
||||
#define ITFDUMP_NOASM 1
|
||||
|
||||
//#define USEASSEMBLYTERRBLEND 1
|
||||
|
||||
#define PNG_NO_READ_tIME 1
|
||||
#define PNG_NO_WRITE_TIME 1
|
||||
|
||||
#define NO_MILES_OPENAL 1
|
||||
|
301
engine/platformMacCarb/platformGL.h
Executable file
301
engine/platformMacCarb/platformGL.h
Executable file
@ -0,0 +1,301 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PLATFORMGL_H_
|
||||
#define _PLATFORMGL_H_
|
||||
|
||||
// set npatch enable flag here. comment out if you don't want the features at all.
|
||||
#define ENABLE_NPATCH 1
|
||||
|
||||
// ON MAC, WE ARE USING THE STD APPLE OPENGL HDRS.
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#include <OpenGL/glext.h>
|
||||
|
||||
#if !defined(TORQUE_DEBUG)
|
||||
#if !defined(AGLContext)
|
||||
typedef struct __AGLContextRec *AGLContext;
|
||||
#endif
|
||||
#include <AGL/aglMacro.h>
|
||||
extern AGLContext agl_ctx;
|
||||
#endif
|
||||
|
||||
// TODO: switch this over the ARB vertex buffers. this is old stuff for the d3d layer.
|
||||
#ifndef GL_EXT_vertex_buffer
|
||||
// don't define it!
|
||||
//#define GL_EXT_vertex_buffer 1
|
||||
//#ifdef GL_GLEXT_PROTOTYPES
|
||||
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);
|
||||
//#endif /* GL_GLEXT_PROTOTYPES */
|
||||
typedef GLboolean (* PFNGLAVAILABLEVERTEXBUFFEREXTPROC) ();
|
||||
typedef GLint (* PFNGLALLOCATEVERTEXBUFFEREXTPROC) (GLsizei size, GLint format, GLboolean preserve);
|
||||
typedef void* (* PFNGLLOCKVERTEXBUFFEREXTPROC) (GLint handle, GLsizei size);
|
||||
typedef void (* PFNGLUNLOCKVERTEXBUFFEREXTPROC) (GLint handle);
|
||||
typedef void (* PFNGLSETVERTEXBUFFEREXTPROC) (GLint handle);
|
||||
typedef void (* PFNGLOFFSETVERTEXBUFFEREXTPROC) (GLint handle, GLuint offset);
|
||||
typedef void (* PFNGLFILLVERTEXBUFFEREXTPROC) (GLint handle, GLint first, GLsizei count);
|
||||
typedef void (* PFNGLFREEVERTEXBUFFEREXTPROC) (GLint handle);
|
||||
#endif // GL_EXT_vertex_buffer
|
||||
|
||||
#ifndef GL_EXT_fog_coord
|
||||
// don't define it!
|
||||
//#define GL_EXT_fog_coord 1
|
||||
extern void glFogCoordfEXT (GLfloat);
|
||||
extern void glFogCoordfvEXT (const GLfloat *);
|
||||
extern void glFogCoorddEXT (GLdouble);
|
||||
extern void glFogCoorddvEXT (const GLdouble *);
|
||||
extern void glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);
|
||||
#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
|
||||
#define GL_FOG_COORDINATE_EXT 0x8451
|
||||
#define GL_FRAGMENT_DEPTH_EXT 0x8452
|
||||
#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453
|
||||
#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454
|
||||
#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
|
||||
#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
|
||||
#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457
|
||||
#endif
|
||||
|
||||
// Apple in their infinite wisdom switched to the ARB version, but
|
||||
// didn't leave in backward-flagging for the old EXT version. UGH.
|
||||
#ifndef GL_EXT_texture_env_combine
|
||||
#define GL_EXT_texture_env_combine GL_ARB_texture_env_combine
|
||||
#define GL_COMBINE_EXT 0x8570
|
||||
#define GL_COMBINE_RGB_EXT 0x8571
|
||||
#define GL_COMBINE_ALPHA_EXT 0x8572
|
||||
#define GL_RGB_SCALE_EXT 0x8573
|
||||
#define GL_ADD_SIGNED_EXT 0x8574
|
||||
#define GL_INTERPOLATE_EXT 0x8575
|
||||
#define GL_CONSTANT_EXT 0x8576
|
||||
#define GL_PRIMARY_COLOR_EXT 0x8577
|
||||
#define GL_PREVIOUS_EXT 0x8578
|
||||
#define GL_SOURCE0_RGB_EXT 0x8580
|
||||
#define GL_SOURCE1_RGB_EXT 0x8581
|
||||
#define GL_SOURCE2_RGB_EXT 0x8582
|
||||
#define GL_SOURCE3_RGB_EXT 0x8583
|
||||
#define GL_SOURCE4_RGB_EXT 0x8584
|
||||
#define GL_SOURCE5_RGB_EXT 0x8585
|
||||
#define GL_SOURCE6_RGB_EXT 0x8586
|
||||
#define GL_SOURCE7_RGB_EXT 0x8587
|
||||
#define GL_SOURCE0_ALPHA_EXT 0x8588
|
||||
#define GL_SOURCE1_ALPHA_EXT 0x8589
|
||||
#define GL_SOURCE2_ALPHA_EXT 0x858A
|
||||
#define GL_SOURCE3_ALPHA_EXT 0x858B
|
||||
#define GL_SOURCE4_ALPHA_EXT 0x858C
|
||||
#define GL_SOURCE5_ALPHA_EXT 0x858D
|
||||
#define GL_SOURCE6_ALPHA_EXT 0x858E
|
||||
#define GL_SOURCE7_ALPHA_EXT 0x858F
|
||||
#define GL_OPERAND0_RGB_EXT 0x8590
|
||||
#define GL_OPERAND1_RGB_EXT 0x8591
|
||||
#define GL_OPERAND2_RGB_EXT 0x8592
|
||||
#define GL_OPERAND3_RGB_EXT 0x8593
|
||||
#define GL_OPERAND4_RGB_EXT 0x8594
|
||||
#define GL_OPERAND5_RGB_EXT 0x8595
|
||||
#define GL_OPERAND6_RGB_EXT 0x8596
|
||||
#define GL_OPERAND7_RGB_EXT 0x8597
|
||||
#define GL_OPERAND0_ALPHA_EXT 0x8598
|
||||
#define GL_OPERAND1_ALPHA_EXT 0x8599
|
||||
#define GL_OPERAND2_ALPHA_EXT 0x859A
|
||||
#define GL_OPERAND3_ALPHA_EXT 0x859B
|
||||
#define GL_OPERAND4_ALPHA_EXT 0x859C
|
||||
#define GL_OPERAND5_ALPHA_EXT 0x859D
|
||||
#define GL_OPERAND6_ALPHA_EXT 0x859E
|
||||
#define GL_OPERAND7_ALPHA_EXT 0x859F
|
||||
#endif
|
||||
|
||||
// these are the V12-custom extensions. really only useful in an external 3d driver.
|
||||
#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.
|
||||
#ifndef GL_CLAMP_TO_EDGE_EXT // should be, but apple only defined the SGIS version (same hexcode)
|
||||
#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;
|
||||
};
|
||||
|
||||
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 helpers.
|
||||
*/
|
||||
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 and up:
|
||||
#define AGLSETINT_ATI_FSAA_SAMPLES ((unsigned long)510) // set Full Scene Anti-Aliasing (FSAA) samples: 1x, 2x, 4x
|
||||
void dglSetFSAASamples(GLint aasamp);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(TORQUE_DEBUG)
|
||||
#ifndef __GL_OUTLINE_FUNCS__
|
||||
#define __GL_OUTLINE_FUNCS__
|
||||
|
||||
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
|
66
engine/platformMacCarb/platformMacCarb.h
Executable file
66
engine/platformMacCarb/platformMacCarb.h
Executable file
@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 <QD.h>
|
||||
#include "platform/platform.h"
|
||||
|
||||
|
||||
class MacCarbPlatState
|
||||
{
|
||||
public:
|
||||
GDHandle hDisplay;
|
||||
WindowPtr appWindow;
|
||||
|
||||
char appWindowTitle[256];
|
||||
bool quit;
|
||||
|
||||
void * ctx; // was an AGLContext -- but didn't want to inc AGL.h and all...
|
||||
|
||||
S32 desktopBitsPixel;
|
||||
S32 desktopWidth;
|
||||
S32 desktopHeight;
|
||||
U32 currentTime;
|
||||
|
||||
U32 osVersion;
|
||||
bool osX;
|
||||
|
||||
TSMDocumentID tsmDoc;
|
||||
bool tsmActive;
|
||||
|
||||
MacCarbPlatState();
|
||||
};
|
||||
|
||||
extern MacCarbPlatState platState;
|
||||
|
||||
extern bool GL_EXT_Init();
|
||||
|
||||
|
||||
extern WindowPtr CreateOpenGLWindow( GDHandle hDevice, U32 width, U32 height, bool fullScreen );
|
||||
extern WindowPtr CreateCurtain( GDHandle hDevice, U32 width, U32 height );
|
||||
|
||||
U32 GetMilliseconds();
|
||||
|
||||
U8* str2p(const char *str);
|
||||
U8* str2p(const char *str, U8 *dst_p);
|
||||
|
||||
char* p2str(U8 *p);
|
||||
char* p2str(U8 *p, char *dst_str);
|
||||
|
||||
U8 TranslateOSKeyCode(U8 vcode);
|
||||
|
||||
// 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
|
||||
|
||||
#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