Initial commit

This commit is contained in:
Eagle517
2025-02-17 23:17:30 -06:00
commit 7cad314c94
4726 changed files with 1145203 additions and 0 deletions

Binary file not shown.

View 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

View 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(" ");
}

View 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);
}
}
}

View 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

View 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

View 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_

View 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);

View 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;
}

Binary file not shown.

View 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");
}

View 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__ */

View 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();
}

View 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(" ");
}

View 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));
}

View 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;
}

View 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

View 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, &notblock);
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;
}

File diff suppressed because it is too large Load Diff

View 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_

View 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);
}

View 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().");
}

View 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;
}
*/

View 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

View 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 &lt)
{
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 );
}

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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_

Binary file not shown.