Itsa me, quake3io!

This commit is contained in:
Zachary Slater 2005-08-26 04:48:05 +00:00
parent dbe4ddb103
commit 5b755058f5
1409 changed files with 798983 additions and 798983 deletions

34
code/macosx/BuildRelease Normal file → Executable file
View file

@ -1,17 +1,17 @@
#!/bin/zsh
APPNAME="Quake3"
PACKAGENAME= Quake3
(cd $OMNI_SOURCE_ROOT; ./Build Quake3 install)
rm -rf "/tmp/$APPNAME"
mkdir "/tmp/$APPNAME"
cp "Read Me.rtf" "/tmp/$APPNAME"
cd /Users/Shared/$USER/InstalledProducts
gnutar cf - FAKK2.app | (cd "/tmp/$APPNAME"; gnutar xf -)
cd "/tmp/$APPNAME"
sudo ~bungi/Unix/bin/files2image $PACKAGENAME ./*
#!/bin/zsh
APPNAME="Quake3"
PACKAGENAME= Quake3
(cd $OMNI_SOURCE_ROOT; ./Build Quake3 install)
rm -rf "/tmp/$APPNAME"
mkdir "/tmp/$APPNAME"
cp "Read Me.rtf" "/tmp/$APPNAME"
cd /Users/Shared/$USER/InstalledProducts
gnutar cf - FAKK2.app | (cd "/tmp/$APPNAME"; gnutar xf -)
cd "/tmp/$APPNAME"
sudo ~bungi/Unix/bin/files2image $PACKAGENAME ./*

54
code/macosx/CGMouseDeltaFix.h Normal file → Executable file
View file

@ -1,27 +1,27 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import <ApplicationServices/ApplicationServices.h>
extern void CGFix_Initialize();
extern void CGFix_GetLastMouseDelta(CGMouseDelta *dx, CGMouseDelta *dy);
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import <ApplicationServices/ApplicationServices.h>
extern void CGFix_Initialize();
extern void CGFix_GetLastMouseDelta(CGMouseDelta *dx, CGMouseDelta *dy);

262
code/macosx/CGMouseDeltaFix.m Normal file → Executable file
View file

@ -1,131 +1,131 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "CGMouseDeltaFix.h"
#import "CGPrivateAPI.h"
#import <Foundation/Foundation.h>
#import <mach-o/dyld.h>
// We will try to automatically fall back to using the original CGGetLastMouseDelta when we are on a system new enough to have the fix. Any version of CoreGraphics past 1.93.0 will have the fixed version.
static BOOL originalVersionShouldWork = YES;
static CGMouseDelta CGFix_Mouse_DeltaX, CGFix_Mouse_DeltaY;
static void CGFix_NotificationCallback(CGSNotificationType note, CGSNotificationData data, CGSByteCount dataLength, CGSNotificationArg arg);
static CGSRegisterNotifyProcType registerNotifyProc = NULL;
void CGFix_Initialize()
{
NSAutoreleasePool *pool;
NSBundle *cgBundle;
NSString *version;
NSArray *components;
if (registerNotifyProc)
// We've already been called once and have registered our callbacks. If the original version works, this will be NULL, but we'll end up doing nothing (again, possibly).
return;
//NSLog(@"CGFix_Initialize\n");
pool = [[NSAutoreleasePool alloc] init];
cgBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework"];
if (!cgBundle) {
// If it's moved, it must be newer than what we know about and should work
//NSLog(@"No /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework\n");
goto done;
}
version = [[cgBundle infoDictionary] objectForKey: @"CFBundleShortVersionString"];
components = [version componentsSeparatedByString: @"."];
//NSLog(@"version = %@\n", version);
//NSLog(@"components = %@\n", components);
if ([components count] < 2)
// We don't understand this versioning scheme. Must have changed.
goto done;
if (![[components objectAtIndex: 0] isEqualToString: @"1"] || [[components objectAtIndex: 1] intValue] > 93)
// This version should be new enough to work
goto done;
// Look up the function pointer we need to register our callback.
if (!NSIsSymbolNameDefined("_CGSRegisterNotifyProc")) {
//NSLog(@"No _CGSRegisterNotifyProc\n");
goto done;
}
registerNotifyProc = NSAddressOfSymbol(NSLookupAndBindSymbol("_CGSRegisterNotifyProc"));
//NSLog(@"registerNotifyProc = 0x%08x", registerNotifyProc);
// Must not work if we got here
originalVersionShouldWork = NO;
// We want to catch all the events that could possible indicate mouse movement and sum them up
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationMouseMoved, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationLeftMouseDragged, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationRightMouseDragged, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationNotificationOtherMouseDragged, NULL);
done:
[pool release];
}
void CGFix_GetLastMouseDelta(CGMouseDelta *dx, CGMouseDelta *dy)
{
if (originalVersionShouldWork) {
CGGetLastMouseDelta(dx, dy);
return;
}
*dx = CGFix_Mouse_DeltaX;
*dy = CGFix_Mouse_DeltaY;
CGFix_Mouse_DeltaX = CGFix_Mouse_DeltaY = 0;
}
static void CGFix_NotificationCallback(CGSNotificationType note, CGSNotificationData data, CGSByteCount dataLength, CGSNotificationArg arg)
{
CGSEventRecordPtr event;
//fprintf(stderr, "CGFix_NotificationCallback(note=%d, date=0x%08x, dataLength=%d, arg=0x%08x)\n", note, data, dataLength, arg);
#ifdef DEBUG
if ((note != kCGSEventNotificationMouseMoved &&
note != kCGSEventNotificationLeftMouseDragged &&
note != kCGSEventNotificationRightMouseDragged &&
note != kCGSEventNotificationNotificationOtherMouseDragged) ||
dataLength != sizeof (CGSEventRecord))
fprintf(stderr, "Unexpected arguments to callback function CGFix_NotificationCallback(note=%d, date=0x%08x, dataLength=%d, arg=0x%08x)\n", note, data, dataLength, arg);
abort();
}
#endif
event = (CGSEventRecordPtr)data;
CGFix_Mouse_DeltaX += event->data.move.deltaX;
CGFix_Mouse_DeltaY += event->data.move.deltaY;
//fprintf(stderr, " dx += %d, dy += %d\n", event->data.move.deltaX, event->data.move.deltaY);
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "CGMouseDeltaFix.h"
#import "CGPrivateAPI.h"
#import <Foundation/Foundation.h>
#import <mach-o/dyld.h>
// We will try to automatically fall back to using the original CGGetLastMouseDelta when we are on a system new enough to have the fix. Any version of CoreGraphics past 1.93.0 will have the fixed version.
static BOOL originalVersionShouldWork = YES;
static CGMouseDelta CGFix_Mouse_DeltaX, CGFix_Mouse_DeltaY;
static void CGFix_NotificationCallback(CGSNotificationType note, CGSNotificationData data, CGSByteCount dataLength, CGSNotificationArg arg);
static CGSRegisterNotifyProcType registerNotifyProc = NULL;
void CGFix_Initialize()
{
NSAutoreleasePool *pool;
NSBundle *cgBundle;
NSString *version;
NSArray *components;
if (registerNotifyProc)
// We've already been called once and have registered our callbacks. If the original version works, this will be NULL, but we'll end up doing nothing (again, possibly).
return;
//NSLog(@"CGFix_Initialize\n");
pool = [[NSAutoreleasePool alloc] init];
cgBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework"];
if (!cgBundle) {
// If it's moved, it must be newer than what we know about and should work
//NSLog(@"No /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework\n");
goto done;
}
version = [[cgBundle infoDictionary] objectForKey: @"CFBundleShortVersionString"];
components = [version componentsSeparatedByString: @"."];
//NSLog(@"version = %@\n", version);
//NSLog(@"components = %@\n", components);
if ([components count] < 2)
// We don't understand this versioning scheme. Must have changed.
goto done;
if (![[components objectAtIndex: 0] isEqualToString: @"1"] || [[components objectAtIndex: 1] intValue] > 93)
// This version should be new enough to work
goto done;
// Look up the function pointer we need to register our callback.
if (!NSIsSymbolNameDefined("_CGSRegisterNotifyProc")) {
//NSLog(@"No _CGSRegisterNotifyProc\n");
goto done;
}
registerNotifyProc = NSAddressOfSymbol(NSLookupAndBindSymbol("_CGSRegisterNotifyProc"));
//NSLog(@"registerNotifyProc = 0x%08x", registerNotifyProc);
// Must not work if we got here
originalVersionShouldWork = NO;
// We want to catch all the events that could possible indicate mouse movement and sum them up
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationMouseMoved, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationLeftMouseDragged, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationRightMouseDragged, NULL);
registerNotifyProc( CGFix_NotificationCallback, kCGSEventNotificationNotificationOtherMouseDragged, NULL);
done:
[pool release];
}
void CGFix_GetLastMouseDelta(CGMouseDelta *dx, CGMouseDelta *dy)
{
if (originalVersionShouldWork) {
CGGetLastMouseDelta(dx, dy);
return;
}
*dx = CGFix_Mouse_DeltaX;
*dy = CGFix_Mouse_DeltaY;
CGFix_Mouse_DeltaX = CGFix_Mouse_DeltaY = 0;
}
static void CGFix_NotificationCallback(CGSNotificationType note, CGSNotificationData data, CGSByteCount dataLength, CGSNotificationArg arg)
{
CGSEventRecordPtr event;
//fprintf(stderr, "CGFix_NotificationCallback(note=%d, date=0x%08x, dataLength=%d, arg=0x%08x)\n", note, data, dataLength, arg);
#ifdef DEBUG
if ((note != kCGSEventNotificationMouseMoved &&
note != kCGSEventNotificationLeftMouseDragged &&
note != kCGSEventNotificationRightMouseDragged &&
note != kCGSEventNotificationNotificationOtherMouseDragged) ||
dataLength != sizeof (CGSEventRecord))
fprintf(stderr, "Unexpected arguments to callback function CGFix_NotificationCallback(note=%d, date=0x%08x, dataLength=%d, arg=0x%08x)\n", note, data, dataLength, arg);
abort();
}
#endif
event = (CGSEventRecordPtr)data;
CGFix_Mouse_DeltaX += event->data.move.deltaX;
CGFix_Mouse_DeltaY += event->data.move.deltaY;
//fprintf(stderr, " dx += %d, dy += %d\n", event->data.move.deltaX, event->data.move.deltaY);
}

370
code/macosx/CGPrivateAPI.h Normal file → Executable file
View file

@ -1,185 +1,185 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef unsigned long CGSNotificationType;
typedef void * CGSNotificationData;
typedef void * CGSNotificationArg;
typedef void * CGSWindowID;
typedef void * CGSConnectionID;
typedef unsigned long long CGSUInt64;
typedef long long CGSInt64;
typedef unsigned long CGSUInt32;
typedef long CGSInt32;
typedef unsigned short CGSUInt16;
typedef short CGSInt16;
typedef unsigned char CGSUInt8;
typedef char CGSInt8;
typedef float CGSFloat32;
typedef CGSUInt32 CGSByteCount;
typedef CGSUInt16 CGSEventRecordVersion;
typedef unsigned long CGSEventType;
typedef CGSUInt64 CGSEventRecordTime; /* nanosecond timer */
typedef unsigned long CGSEventFlag;
typedef CGSUInt32 CGSError;
typedef union {
struct { /* For mouse events */
CGSUInt8 subx; /* sub-pixel position for x */
CGSUInt8 suby; /* sub-pixel position for y */
CGSInt16 eventNum; /* unique identifier for this button */
CGSInt32 click; /* click state of this event */
CGSUInt8 pressure; /* pressure value: 0=none, 255=full */
CGSInt8 _reserved1;
CGSInt16 _reserved2;
CGSInt16 deltaX;
CGSInt16 deltaY;
CGSInt32 _padding[8];
} mouse;
struct { /* For pointer movement events */
CGSInt16 _obsolete_deltaX; /* Revert to subX, subY, eventNum */
CGSInt16 _obsolete_deltaY; /* for Gonzo 1H */
CGSInt32 click; /* click state of this event */
CGSUInt8 pressure; /* pressure value: 0=none, 255=full */
CGSInt8 _reserved1;
CGSInt16 _reserved2;
CGSInt16 deltaX;
CGSInt16 deltaY;
CGSInt32 _padding[8];
} move;
struct { /* For key-down and key-up events */
CGSInt16 reserved;
CGSInt16 repeat; /* for key-down: nonzero if really a repeat */
CGSUInt16 charSet; /* character set code */
CGSUInt16 charCode; /* character code in that set */
CGSUInt16 keyCode; /* device-dependent virtual key code */
CGSInt16 keyData; /* device-dependent info */
CGSInt16 specialKey; /* CPSSpecialKeyID if kCGSFlagsMaskSpecialKey is set */
CGSInt16 _pad;
CGSInt32 _padding[8];
} key;
struct { /* For mouse-entered and mouse-exited events */
CGSInt16 reserved;
CGSInt16 eventNum; /* unique identifier from mouse down event */
CGSInt32 trackingNum; /* unique identifier from settrackingrect */
CGSInt32 userData; /* unCGSInt32erpreted CGSInt32eger from settrackingrect */
CGSInt32 _padding[9];
} tracking;
struct { /* For process-related events */
CGSUInt16 notifyCode; /* CPSNotificationCodes in CPSProcesses.h */
CGSUInt16 flags; /* CPSEventFlags in CPSProcesses.h */
CGSUInt32 targetHiPSN; /* hiword of PSN */
CGSUInt32 targetLoPSN; /* loword of PSN */
CGSInt32 status; /* operation result */
CGSInt32 _padding[8];
} process;
struct { /* For scroll wheel events */
CGSInt16 deltaAxis1;
CGSInt16 deltaAxis2;
CGSInt16 deltaAxis3;
CGSInt16 reserved1;
CGSInt32 reserved2;
CGSInt32 _padding[9];
} scrollWheel;
struct {
CGSInt32 x; /* absolute x coordinate in tablet space at full tablet resolution */
CGSInt32 y; /* absolute y coordinate in tablet space at full tablet resolution */
CGSInt32 z; /* absolute z coordinate in tablet space at full tablet resolution */
CGSUInt16 buttons; /* one bit per button - bit 0 is first button - 1 = closed */
CGSUInt16 pressure; /* scaled pressure value; MAXPRESSURE=(2^16)-1, MINPRESSURE=0 */
struct {
CGSInt16 x; /* scaled tilt x value; range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
CGSInt16 y; /* scaled tilt y value; range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
} tilt;
CGSUInt16 rotation; /* Fixed-point representation of device rotation in a 10.6 format */
CGSInt16 tangentialPressure; /* tangential pressure on the device; range same as tilt */
CGSUInt16 deviceID; /* system-assigned unique device ID - matches to deviceID field in proximity event */
CGSInt16 vendor1; /* vendor-defined signed 16-bit integer */
CGSInt16 vendor2; /* vendor-defined signed 16-bit integer */
CGSInt16 vendor3; /* vendor-defined signed 16-bit integer */
CGSInt32 _padding[4];
} tablet;
struct {
CGSUInt16 vendorID; /* vendor-defined ID - typically will be USB vendor ID */
CGSUInt16 tabletID; /* vendor-defined tablet ID - typically will be USB product ID for the tablet */
CGSUInt16 pointerID; /* vendor-defined ID of the specific pointing device */
CGSUInt16 deviceID; /* system-assigned unique device ID - matches to deviceID field in tablet event */
CGSUInt16 systemTabletID; /* system-assigned unique tablet ID */
CGSUInt16 vendorPointerType; /* vendor-defined pointer type */
CGSUInt32 pointerSerialNumber; /* vendor-defined serial number of the specific pointing device */
CGSUInt64 uniqueID; /* vendor-defined unique ID for this pointer */
CGSUInt32 capabilityMask; /* mask representing the capabilities of the device */
CGSUInt8 pointerType; /* type of pointing device - enum to be defined */
CGSUInt8 enterProximity; /* non-zero = entering; zero = leaving */
CGSInt16 reserved1;
CGSInt32 _padding[4];
} proximity;
struct { /* For AppKit-defined, sys-defined, and app-defined events */
CGSInt16 reserved;
CGSInt16 subtype; /* event subtype for compound events */
union {
CGSFloat32 F[11]; /* for use in compound events */
CGSInt32 L[11]; /* for use in compound events */
CGSInt16 S[22]; /* for use in compound events */
CGSInt8 C[44]; /* for use in compound events */
} misc;
} compound;
} CGSEventRecordData;
struct _CGSEventRecord {
CGSEventRecordVersion major;
CGSEventRecordVersion minor;
CGSByteCount length; /* Length of complete event record */
CGSEventType type; /* An event type from above */
CGPoint location; /* Base coordinates (global), from upper-left */
CGPoint windowLocation; /* Coordinates relative to window */
CGSEventRecordTime time; /* nanoseconds since startup */
CGSEventFlag flags; /* key state flags */
CGSWindowID window; /* window number of assigned window */
CGSConnectionID connection; /* connection the event came from */
CGSEventRecordData data; /* type-dependent data: 40 bytes */
};
typedef struct _CGSEventRecord CGSEventRecord;
typedef CGSEventRecord *CGSEventRecordPtr;
typedef void (*CGSNotifyProcPtr)(CGSNotificationType type,
CGSNotificationData data,
CGSByteCount dataLength,
CGSNotificationArg arg);
// Define a type for the 'CGSRegisterNotifyProc' call. Don't reference it explicitly since we don't want link errors if Apple removes this private function.
typedef CGSError (*CGSRegisterNotifyProcType)(CGSNotifyProcPtr proc,
CGSNotificationType type,
CGSNotificationArg arg);
#define kCGSEventNotificationMouseMoved (710 + 5)
#define kCGSEventNotificationLeftMouseDragged (710 + 6)
#define kCGSEventNotificationRightMouseDragged (710 + 7)
#define kCGSEventNotificationNotificationOtherMouseDragged (710 + 27)
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef unsigned long CGSNotificationType;
typedef void * CGSNotificationData;
typedef void * CGSNotificationArg;
typedef void * CGSWindowID;
typedef void * CGSConnectionID;
typedef unsigned long long CGSUInt64;
typedef long long CGSInt64;
typedef unsigned long CGSUInt32;
typedef long CGSInt32;
typedef unsigned short CGSUInt16;
typedef short CGSInt16;
typedef unsigned char CGSUInt8;
typedef char CGSInt8;
typedef float CGSFloat32;
typedef CGSUInt32 CGSByteCount;
typedef CGSUInt16 CGSEventRecordVersion;
typedef unsigned long CGSEventType;
typedef CGSUInt64 CGSEventRecordTime; /* nanosecond timer */
typedef unsigned long CGSEventFlag;
typedef CGSUInt32 CGSError;
typedef union {
struct { /* For mouse events */
CGSUInt8 subx; /* sub-pixel position for x */
CGSUInt8 suby; /* sub-pixel position for y */
CGSInt16 eventNum; /* unique identifier for this button */
CGSInt32 click; /* click state of this event */
CGSUInt8 pressure; /* pressure value: 0=none, 255=full */
CGSInt8 _reserved1;
CGSInt16 _reserved2;
CGSInt16 deltaX;
CGSInt16 deltaY;
CGSInt32 _padding[8];
} mouse;
struct { /* For pointer movement events */
CGSInt16 _obsolete_deltaX; /* Revert to subX, subY, eventNum */
CGSInt16 _obsolete_deltaY; /* for Gonzo 1H */
CGSInt32 click; /* click state of this event */
CGSUInt8 pressure; /* pressure value: 0=none, 255=full */
CGSInt8 _reserved1;
CGSInt16 _reserved2;
CGSInt16 deltaX;
CGSInt16 deltaY;
CGSInt32 _padding[8];
} move;
struct { /* For key-down and key-up events */
CGSInt16 reserved;
CGSInt16 repeat; /* for key-down: nonzero if really a repeat */
CGSUInt16 charSet; /* character set code */
CGSUInt16 charCode; /* character code in that set */
CGSUInt16 keyCode; /* device-dependent virtual key code */
CGSInt16 keyData; /* device-dependent info */
CGSInt16 specialKey; /* CPSSpecialKeyID if kCGSFlagsMaskSpecialKey is set */
CGSInt16 _pad;
CGSInt32 _padding[8];
} key;
struct { /* For mouse-entered and mouse-exited events */
CGSInt16 reserved;
CGSInt16 eventNum; /* unique identifier from mouse down event */
CGSInt32 trackingNum; /* unique identifier from settrackingrect */
CGSInt32 userData; /* unCGSInt32erpreted CGSInt32eger from settrackingrect */
CGSInt32 _padding[9];
} tracking;
struct { /* For process-related events */
CGSUInt16 notifyCode; /* CPSNotificationCodes in CPSProcesses.h */
CGSUInt16 flags; /* CPSEventFlags in CPSProcesses.h */
CGSUInt32 targetHiPSN; /* hiword of PSN */
CGSUInt32 targetLoPSN; /* loword of PSN */
CGSInt32 status; /* operation result */
CGSInt32 _padding[8];
} process;
struct { /* For scroll wheel events */
CGSInt16 deltaAxis1;
CGSInt16 deltaAxis2;
CGSInt16 deltaAxis3;
CGSInt16 reserved1;
CGSInt32 reserved2;
CGSInt32 _padding[9];
} scrollWheel;
struct {
CGSInt32 x; /* absolute x coordinate in tablet space at full tablet resolution */
CGSInt32 y; /* absolute y coordinate in tablet space at full tablet resolution */
CGSInt32 z; /* absolute z coordinate in tablet space at full tablet resolution */
CGSUInt16 buttons; /* one bit per button - bit 0 is first button - 1 = closed */
CGSUInt16 pressure; /* scaled pressure value; MAXPRESSURE=(2^16)-1, MINPRESSURE=0 */
struct {
CGSInt16 x; /* scaled tilt x value; range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
CGSInt16 y; /* scaled tilt y value; range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
} tilt;
CGSUInt16 rotation; /* Fixed-point representation of device rotation in a 10.6 format */
CGSInt16 tangentialPressure; /* tangential pressure on the device; range same as tilt */
CGSUInt16 deviceID; /* system-assigned unique device ID - matches to deviceID field in proximity event */
CGSInt16 vendor1; /* vendor-defined signed 16-bit integer */
CGSInt16 vendor2; /* vendor-defined signed 16-bit integer */
CGSInt16 vendor3; /* vendor-defined signed 16-bit integer */
CGSInt32 _padding[4];
} tablet;
struct {
CGSUInt16 vendorID; /* vendor-defined ID - typically will be USB vendor ID */
CGSUInt16 tabletID; /* vendor-defined tablet ID - typically will be USB product ID for the tablet */
CGSUInt16 pointerID; /* vendor-defined ID of the specific pointing device */
CGSUInt16 deviceID; /* system-assigned unique device ID - matches to deviceID field in tablet event */
CGSUInt16 systemTabletID; /* system-assigned unique tablet ID */
CGSUInt16 vendorPointerType; /* vendor-defined pointer type */
CGSUInt32 pointerSerialNumber; /* vendor-defined serial number of the specific pointing device */
CGSUInt64 uniqueID; /* vendor-defined unique ID for this pointer */
CGSUInt32 capabilityMask; /* mask representing the capabilities of the device */
CGSUInt8 pointerType; /* type of pointing device - enum to be defined */
CGSUInt8 enterProximity; /* non-zero = entering; zero = leaving */
CGSInt16 reserved1;
CGSInt32 _padding[4];
} proximity;
struct { /* For AppKit-defined, sys-defined, and app-defined events */
CGSInt16 reserved;
CGSInt16 subtype; /* event subtype for compound events */
union {
CGSFloat32 F[11]; /* for use in compound events */
CGSInt32 L[11]; /* for use in compound events */
CGSInt16 S[22]; /* for use in compound events */
CGSInt8 C[44]; /* for use in compound events */
} misc;
} compound;
} CGSEventRecordData;
struct _CGSEventRecord {
CGSEventRecordVersion major;
CGSEventRecordVersion minor;
CGSByteCount length; /* Length of complete event record */
CGSEventType type; /* An event type from above */
CGPoint location; /* Base coordinates (global), from upper-left */
CGPoint windowLocation; /* Coordinates relative to window */
CGSEventRecordTime time; /* nanoseconds since startup */
CGSEventFlag flags; /* key state flags */
CGSWindowID window; /* window number of assigned window */
CGSConnectionID connection; /* connection the event came from */
CGSEventRecordData data; /* type-dependent data: 40 bytes */
};
typedef struct _CGSEventRecord CGSEventRecord;
typedef CGSEventRecord *CGSEventRecordPtr;
typedef void (*CGSNotifyProcPtr)(CGSNotificationType type,
CGSNotificationData data,
CGSByteCount dataLength,
CGSNotificationArg arg);
// Define a type for the 'CGSRegisterNotifyProc' call. Don't reference it explicitly since we don't want link errors if Apple removes this private function.
typedef CGSError (*CGSRegisterNotifyProcType)(CGSNotifyProcPtr proc,
CGSNotificationType type,
CGSNotificationArg arg);
#define kCGSEventNotificationMouseMoved (710 + 5)
#define kCGSEventNotificationLeftMouseDragged (710 + 6)
#define kCGSEventNotificationRightMouseDragged (710 + 7)
#define kCGSEventNotificationNotificationOtherMouseDragged (710 + 27)

292
code/macosx/GenerateQGL.pl Normal file → Executable file
View file

@ -1,146 +1,146 @@
#!/usr/bin/perl
open(INPUT_FILE, ">/tmp/input-$$.h") || die "$!";
print INPUT_FILE "#import <OpenGL/gl.h>\n";
close INPUT_FILE;
open(CPP, "cpp /tmp/input-$$.h|") || die "$!";
print "/**** This file is autogenerated. Run GenerateQGL.pl to update it ****/\n\n";
print "#ifdef QGL_LOG_GL_CALLS\n";
print "extern unsigned int QGLLogGLCalls;\n";
print "extern FILE *QGLDebugFile(void);\n";
print "#endif\n\n";
print "extern void QGLCheckError(const char *message);\n";
print "extern unsigned int QGLBeginStarted;\n\n";
print "// This has to be done to avoid infinite recursion between our glGetError wrapper and QGLCheckError()\n";
print "static inline GLenum _glGetError(void) {\n";
print " return glGetError();\n";
print "}\n\n";
@functionNames = ();
while (<CPP>) {
chop;
/^extern/ || next;
s/extern //;
print "// $_\n";
# This approach is necessary to deal with glGetString whos type isn't a single word
($type, $rest) = m/(.+)\s+(gl.*)/;
# print "type='$type'\n";
# print "rest='$rest'\n";
($name, $argString) = ($rest =~ m/(\w+).*\s*\((.*)\)/);
$isVoid = ($type =~ m/void/);
push(@functionNames, $name);
# print "name=$name\n";
# print "argString=$argString\n";
# print "argCount=$#args\n";
# Parse the argument list into two arrays, one of types and one of argument names
if ($argString =~ m/^void$/) {
@args = ();
} else {
@args = split(",", $argString);
}
@argTypes = ();
@argNames = ();
for $arg (@args) {
($argType, $argName) = ($arg =~ m/(.*[ \*])([_a-zA-Z0-9]+)/);
$argType =~ s/^ *//;
$argType =~ s/ *$//;
push(@argTypes, $argType);
push(@argNames, $argName);
# print "argType='$argType'\n";
# print "argName='$argName'\n";
}
print "static inline $type q$name($argString)\n";
print "{\n";
if (! $isVoid) {
print " $type returnValue;\n";
}
print "#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS)\n";
print " if (QGLLogGLCalls)\n";
print " fprintf(QGLDebugFile(), \"$name(";
if ($#argTypes >= 0) {
for ($i = 0; $i <= $#argTypes; $i++) {
$argType = $argTypes[$i];
$argName = $argNames[$i];
$_ = $argType;
if (/^GLenum$/ || /^GLuint$/ || /^GLbitfield$/) {
print "$argName=%lu";
} elsif (/^GLsizei$/ || /^GLint$/) {
print "$argName=%ld";
} elsif (/^GLfloat$/ || /^GLdouble$/ || /^GLclampf$/ || /^GLclampd$/) {
print "$argName=%f";
} elsif (/^GLbyte$/) {
print "$argName=%d";
} elsif (/^GLubyte$/) {
print "$argName=%u";
} elsif (/^GLshort$/) {
print "$argName=%d";
} elsif (/^GLushort$/) {
print "$argName=%u";
} elsif (/^GLboolean$/) {
print "$argName=%u";
} elsif (/\*$/) {
# TJW -- Later we should look at the count specified in the function name, look at the basic type and print out an array. Or we could just special case them...
print "$argName=%p";
} else {
print STDERR "Unknown type '$argType'\n";
exit(1);
}
print ", " if ($i != $#argTypes);
}
} else {
print "void";
}
print ")\\n\"";
print ", " if $#argTypes >= 0;
print join(", ", @argNames);
print ");\n";
print "#endif\n";
if (! $isVoid) {
print " returnValue = ";
} else {
print " ";
}
print "$name(" . join(", ", @argNames) . ");\n";
print "#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)\n";
if ($name eq "glBegin") {
print " QGLBeginStarted++;\n";
}
if ($name eq "glEnd") {
print " QGLBeginStarted--;\n";
}
print " if (!QGLBeginStarted)\n";
print " QGLCheckError(\"$name\");\n";
print "#endif\n";
if (! $isVoid) {
print " return returnValue;\n";
}
print "}\n\n";
}
print "// Prevent calls to the 'normal' GL functions\n";
for $name (@functionNames) {
print "#define $name CALL_THE_QGL_VERSION_OF_$name\n";
}
#!/usr/bin/perl
open(INPUT_FILE, ">/tmp/input-$$.h") || die "$!";
print INPUT_FILE "#import <OpenGL/gl.h>\n";
close INPUT_FILE;
open(CPP, "cpp /tmp/input-$$.h|") || die "$!";
print "/**** This file is autogenerated. Run GenerateQGL.pl to update it ****/\n\n";
print "#ifdef QGL_LOG_GL_CALLS\n";
print "extern unsigned int QGLLogGLCalls;\n";
print "extern FILE *QGLDebugFile(void);\n";
print "#endif\n\n";
print "extern void QGLCheckError(const char *message);\n";
print "extern unsigned int QGLBeginStarted;\n\n";
print "// This has to be done to avoid infinite recursion between our glGetError wrapper and QGLCheckError()\n";
print "static inline GLenum _glGetError(void) {\n";
print " return glGetError();\n";
print "}\n\n";
@functionNames = ();
while (<CPP>) {
chop;
/^extern/ || next;
s/extern //;
print "// $_\n";
# This approach is necessary to deal with glGetString whos type isn't a single word
($type, $rest) = m/(.+)\s+(gl.*)/;
# print "type='$type'\n";
# print "rest='$rest'\n";
($name, $argString) = ($rest =~ m/(\w+).*\s*\((.*)\)/);
$isVoid = ($type =~ m/void/);
push(@functionNames, $name);
# print "name=$name\n";
# print "argString=$argString\n";
# print "argCount=$#args\n";
# Parse the argument list into two arrays, one of types and one of argument names
if ($argString =~ m/^void$/) {
@args = ();
} else {
@args = split(",", $argString);
}
@argTypes = ();
@argNames = ();
for $arg (@args) {
($argType, $argName) = ($arg =~ m/(.*[ \*])([_a-zA-Z0-9]+)/);
$argType =~ s/^ *//;
$argType =~ s/ *$//;
push(@argTypes, $argType);
push(@argNames, $argName);
# print "argType='$argType'\n";
# print "argName='$argName'\n";
}
print "static inline $type q$name($argString)\n";
print "{\n";
if (! $isVoid) {
print " $type returnValue;\n";
}
print "#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS)\n";
print " if (QGLLogGLCalls)\n";
print " fprintf(QGLDebugFile(), \"$name(";
if ($#argTypes >= 0) {
for ($i = 0; $i <= $#argTypes; $i++) {
$argType = $argTypes[$i];
$argName = $argNames[$i];
$_ = $argType;
if (/^GLenum$/ || /^GLuint$/ || /^GLbitfield$/) {
print "$argName=%lu";
} elsif (/^GLsizei$/ || /^GLint$/) {
print "$argName=%ld";
} elsif (/^GLfloat$/ || /^GLdouble$/ || /^GLclampf$/ || /^GLclampd$/) {
print "$argName=%f";
} elsif (/^GLbyte$/) {
print "$argName=%d";
} elsif (/^GLubyte$/) {
print "$argName=%u";
} elsif (/^GLshort$/) {
print "$argName=%d";
} elsif (/^GLushort$/) {
print "$argName=%u";
} elsif (/^GLboolean$/) {
print "$argName=%u";
} elsif (/\*$/) {
# TJW -- Later we should look at the count specified in the function name, look at the basic type and print out an array. Or we could just special case them...
print "$argName=%p";
} else {
print STDERR "Unknown type '$argType'\n";
exit(1);
}
print ", " if ($i != $#argTypes);
}
} else {
print "void";
}
print ")\\n\"";
print ", " if $#argTypes >= 0;
print join(", ", @argNames);
print ");\n";
print "#endif\n";
if (! $isVoid) {
print " returnValue = ";
} else {
print " ";
}
print "$name(" . join(", ", @argNames) . ");\n";
print "#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)\n";
if ($name eq "glBegin") {
print " QGLBeginStarted++;\n";
}
if ($name eq "glEnd") {
print " QGLBeginStarted--;\n";
}
print " if (!QGLBeginStarted)\n";
print " QGLCheckError(\"$name\");\n";
print "#endif\n";
if (! $isVoid) {
print " return returnValue;\n";
}
print "}\n\n";
}
print "// Prevent calls to the 'normal' GL functions\n";
for $name (@functionNames) {
print "#define $name CALL_THE_QGL_VERSION_OF_$name\n";
}

0
code/macosx/Performance.rtf Normal file → Executable file
View file

80
code/macosx/Q3Controller.h Normal file → Executable file
View file

@ -1,40 +1,40 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import <AppKit/AppKit.h>
@interface Q3Controller : NSObject
{
IBOutlet NSPanel *bannerPanel;
}
#ifndef DEDICATED
- (IBAction)paste:(id)sender;
- (IBAction)requestTerminate:(id)sender;
- (void) showBanner;
#endif
- (void)quakeMain;
@end
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import <AppKit/AppKit.h>
@interface Q3Controller : NSObject
{
IBOutlet NSPanel *bannerPanel;
}
#ifndef DEDICATED
- (IBAction)paste:(id)sender;
- (IBAction)requestTerminate:(id)sender;
- (void) showBanner;
#endif
- (void)quakeMain;
@end

870
code/macosx/Q3Controller.m Normal file → Executable file
View file

@ -1,435 +1,435 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "Q3Controller.h"
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#include "client.h"
#include "macosx_local.h"
//#include "GameRanger SDK/gameranger.h"
#ifdef OMNI_TIMER
#import "macosx_timers.h"
#endif
#define MAX_ARGC 1024
static qboolean Sys_IsProcessingTerminationRequest = qfalse;
static void Sys_CreatePathToFile(NSString *path, NSDictionary *attributes);
@interface Q3Controller (Private)
- (void)quakeMain;
@end
@implementation Q3Controller
#ifndef DEDICATED
- (void)applicationDidFinishLaunching:(NSNotification *)notification;
{
NS_DURING {
[self quakeMain];
} NS_HANDLER {
Sys_Error("%@", [localException reason]);
} NS_ENDHANDLER;
Sys_Quit();
}
- (void)applicationDidUnhide:(NSNotification *)notification;
{
// Don't reactivate the game if we are asking whether to quit
if (Sys_IsProcessingTerminationRequest)
return;
if (!Sys_Unhide())
// Didn't work -- hide again so we should get another chance to unhide later
[NSApp hide: nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
{
int choice;
if (!Sys_IsHidden) {
// We're terminating via -terminate:
return NSTerminateNow;
}
// Avoid reactivating GL when we unhide due to this panel
Sys_IsProcessingTerminationRequest = qtrue;
choice = NSRunAlertPanel(nil, @"Quit without saving?", @"Don't Quit", @"Quit", nil);
Sys_IsProcessingTerminationRequest = qfalse;
if (choice == NSAlertAlternateReturn)
return NSTerminateNow;
// Make sure we get re-hidden
[NSApp hide:nil];
return NSTerminateCancel;
}
// Actions
- (IBAction)paste:(id)sender;
{
int shiftWasDown, insertWasDown;
unsigned int currentTime;
currentTime = Sys_Milliseconds();
// Save the original keyboard state
shiftWasDown = keys[K_SHIFT].down;
insertWasDown = keys[K_INS].down;
// Fake a Shift-Insert keyboard event
keys[K_SHIFT].down = qtrue;
Sys_QueEvent(currentTime, SE_KEY, K_INS, qtrue, 0, NULL);
Sys_QueEvent(currentTime, SE_KEY, K_INS, qfalse, 0, NULL);
// Restore the original keyboard state
keys[K_SHIFT].down = shiftWasDown;
keys[K_INS].down = insertWasDown;
}
extern void CL_Quit_f(void);
- (IBAction)requestTerminate:(id)sender;
{
Com_Quit_f();
// UI_QuitMenu();
}
- (void)showBanner;
{
static BOOL hasShownBanner = NO;
if (!hasShownBanner) {
cvar_t *showBanner;
hasShownBanner = YES;
showBanner = Cvar_Get("cl_showBanner", "1", 0);
if (showBanner->integer != 0) {
NSPanel *splashPanel;
NSImage *bannerImage;
NSRect bannerRect;
NSImageView *bannerImageView;
bannerImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"banner.jpg"]];
bannerRect = NSMakeRect(0.0, 0.0, [bannerImage size].width, [bannerImage size].height);
splashPanel = [[NSPanel alloc] initWithContentRect:bannerRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
bannerImageView = [[NSImageView alloc] initWithFrame:bannerRect];
[bannerImageView setImage:bannerImage];
[splashPanel setContentView:bannerImageView];
[bannerImageView release];
[splashPanel center];
[splashPanel setHasShadow:YES];
[splashPanel orderFront: nil];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.5]];
[splashPanel close];
[bannerImage release];
}
}
}
// Services
- (void)connectToServer:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedServer;
requestedServer = [pasteboard stringForType:NSStringPboardType];
if (requestedServer) {
Cbuf_AddText(va("connect %s\n", [requestedServer cString]));
return;
}
}
*error = @"Unable to connect to server: could not find string on pasteboard";
}
- (void)performCommand:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedCommand;
requestedCommand = [pasteboard stringForType:NSStringPboardType];
if (requestedCommand) {
Cbuf_AddText(va("%s\n", [requestedCommand cString]));
return;
}
}
*error = @"Unable to perform command: could not find string on pasteboard";
}
#endif
- (void)quakeMain;
{
NSAutoreleasePool *pool;
int argc = 0;
const char *argv[MAX_ARGC];
NSProcessInfo *processInfo;
NSArray *arguments;
unsigned int argumentIndex, argumentCount;
NSFileManager *defaultManager;
unsigned int commandLineLength;
NSString *installationPathKey, *installationPath;
char *cmdline;
BOOL foundDirectory;
NSString *appName, *demoAppName, *selectButton;
int count = 0;
pool = [[NSAutoreleasePool alloc] init];
[NSApp setServicesProvider:self];
processInfo = [NSProcessInfo processInfo];
arguments = [processInfo arguments];
argumentCount = [arguments count];
for (argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
NSString *arg;
arg = [arguments objectAtIndex:argumentIndex];
// Don't pass the Process Serial Number command line arg that the Window Server/Finder invokes us with
if ([arg hasPrefix: @"-psn_"])
continue;
argv[argc++] = strdup([arg cString]);
}
// Figure out where the level data is stored.
installationPathKey = @"RetailInstallationPath";
installationPath = [[NSUserDefaults standardUserDefaults] objectForKey:installationPathKey];
if (!installationPath) {
// Default to the directory containing the executable (which is where most users will want to put it
installationPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
}
#if !defined(DEDICATED)
appName = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"CFBundleName"];
#else
// We are hard coding the app name here since the dedicated server is a tool, not a app bundle and does not have access to the Info.plist that the client app does. Suck.
appName = @"Quake3";
#endif
demoAppName = appName;
while (YES) {
NSString *dataPath;
NSOpenPanel *openPanel;
int result;
foundDirectory = NO;
defaultManager = [NSFileManager defaultManager];
//NSLog(@"Candidate installation path = %@", installationPath);
dataPath = [installationPath stringByAppendingPathComponent: @"baseq3"];
if ([defaultManager fileExistsAtPath: dataPath]) {
// Check that the data directory contains at least one .pk3 file. We don't know what it will be named, so don't hard code a name (for example it might be named 'french.pk3' for a French release
NSArray *files;
unsigned int fileIndex;
files = [defaultManager directoryContentsAtPath: dataPath];
fileIndex = [files count];
while (fileIndex--) {
if ([[files objectAtIndex: fileIndex] hasSuffix: @"pk3"]) {
//NSLog(@"Found %@.", [files objectAtIndex: fileIndex]);
foundDirectory = YES;
break;
}
}
}
if (foundDirectory)
break;
#ifdef DEDICATED
break;
#warning TJW: We are hard coding the app name and default domain here since the dedicated server is a tool, not a app bundle and does not have access to the Info.plist that the client app does. Suck.
NSLog(@"Unable to determine installation directory. Please move the executable into the '%@' installation directory or add a '%@' key in the 'Q3DedicatedServer' defaults domain.", appName, installationPathKey, [[NSBundle mainBundle] bundleIdentifier]);
Sys_Quit();
exit(1);
#else
selectButton = @"Select Retail Installation...";
result = NSRunAlertPanel(demoAppName, @"You need to select the installation directory for %@ (not any directory inside of it -- the installation directory itself).", selectButton, @"Quit", nil, appName);
switch (result) {
case NSAlertDefaultReturn:
break;
default:
Sys_Quit();
break;
}
openPanel = [NSOpenPanel openPanel];
[openPanel setAllowsMultipleSelection:NO];
[openPanel setCanChooseDirectories:YES];
[openPanel setCanChooseFiles:NO];
result = [openPanel runModalForDirectory:nil file:nil];
if (result == NSOKButton) {
NSArray *filenames;
filenames = [openPanel filenames];
if ([filenames count] == 1) {
installationPath = [filenames objectAtIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:installationPath forKey:installationPathKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
#endif
}
// Create the application support directory if it doesn't exist already
do {
NSArray *results;
NSString *libraryPath, *homePath, *filePath;
NSDictionary *attributes;
results = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
if (![results count])
break;
libraryPath = [results objectAtIndex: 0];
homePath = [libraryPath stringByAppendingPathComponent: @"Application Support"];
homePath = [homePath stringByAppendingPathComponent: appName];
filePath = [homePath stringByAppendingPathComponent: @"foo"];
attributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithUnsignedInt: 0750], NSFilePosixPermissions, nil];
NS_DURING {
Sys_CreatePathToFile(filePath, attributes);
Sys_SetDefaultHomePath([homePath fileSystemRepresentation]);
} NS_HANDLER {
NSLog(@"Exception: %@", localException);
#ifndef DEDICATED
NSRunAlertPanel(nil, @"Unable to create '%@'. Please make sure that you have permission to write to this folder and re-run the game.", @"OK", nil, nil, homePath);
#endif
Sys_Quit();
} NS_ENDHANDLER;
} while(0);
// Provoke the CD scanning code into looking up the CD.
Sys_CheckCD();
// Let the filesystem know where our local install is
Sys_SetDefaultInstallPath([installationPath cString]);
cmdline = NULL;
#if 0
if (GRCheckFileForCmd()) {
GRGetWaitingCmd();
if (GRHasProperty( 'Exec' )) {
NSString *cfgPath, *grCfg;
cfgPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
cfgPath = [cfgPath stringByAppendingPathComponent: [NSString stringWithCString: GRGetPropertyStr( 'Exec' )]];
grCfg = [NSString stringWithContentsOfFile: cfgPath];
cmdline = malloc(strlen([grCfg cString])+1);
[grCfg getCString: cmdline];
}
}
#endif
if (!cmdline) {
// merge the command line, this is kinda silly
for (commandLineLength = 1, argumentIndex = 1; argumentIndex < argc; argumentIndex++)
commandLineLength += strlen(argv[argumentIndex]) + 1;
cmdline = malloc(commandLineLength);
*cmdline = '\0';
for (argumentIndex = 1; argumentIndex < argc; argumentIndex++) {
if (argumentIndex > 1)
strcat(cmdline, " ");
strcat(cmdline, argv[argumentIndex]);
}
}
Com_Printf("command line: %s\n", cmdline);
Com_Init(cmdline);
#ifndef DEDICATED
[NSApp activateIgnoringOtherApps:YES];
#endif
while (1) {
Com_Frame();
if ((count & 15)==0) {
// We should think about doing this less frequently than every frame
[pool release];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool release];
}
@end
// Creates any directories needed to be able to create a file at the specified path. Raises an exception on failure.
static void Sys_CreatePathToFile(NSString *path, NSDictionary *attributes)
{
NSArray *pathComponents;
unsigned int dirIndex, dirCount;
unsigned int startingIndex;
NSFileManager *manager;
manager = [NSFileManager defaultManager];
pathComponents = [path pathComponents];
dirCount = [pathComponents count] - 1;
startingIndex = 0;
for (dirIndex = startingIndex; dirIndex < dirCount; dirIndex++) {
NSString *partialPath;
BOOL fileExists;
partialPath = [NSString pathWithComponents:[pathComponents subarrayWithRange:NSMakeRange(0, dirIndex + 1)]];
// Don't use the 'fileExistsAtPath:isDirectory:' version since it doesn't traverse symlinks
fileExists = [manager fileExistsAtPath:partialPath];
if (!fileExists) {
if (![manager createDirectoryAtPath:partialPath attributes:attributes]) {
[NSException raise:NSGenericException format:@"Unable to create a directory at path: %@", partialPath];
}
} else {
NSDictionary *attributes;
attributes = [manager fileAttributesAtPath:partialPath traverseLink:YES];
if (![[attributes objectForKey:NSFileType] isEqualToString: NSFileTypeDirectory]) {
[NSException raise:NSGenericException format:@"Unable to write to path \"%@\" because \"%@\" is not a directory",
path, partialPath];
}
}
}
}
#ifdef DEDICATED
void S_ClearSoundBuffer( void ) {
}
#endif
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "Q3Controller.h"
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#include "client.h"
#include "macosx_local.h"
//#include "GameRanger SDK/gameranger.h"
#ifdef OMNI_TIMER
#import "macosx_timers.h"
#endif
#define MAX_ARGC 1024
static qboolean Sys_IsProcessingTerminationRequest = qfalse;
static void Sys_CreatePathToFile(NSString *path, NSDictionary *attributes);
@interface Q3Controller (Private)
- (void)quakeMain;
@end
@implementation Q3Controller
#ifndef DEDICATED
- (void)applicationDidFinishLaunching:(NSNotification *)notification;
{
NS_DURING {
[self quakeMain];
} NS_HANDLER {
Sys_Error("%@", [localException reason]);
} NS_ENDHANDLER;
Sys_Quit();
}
- (void)applicationDidUnhide:(NSNotification *)notification;
{
// Don't reactivate the game if we are asking whether to quit
if (Sys_IsProcessingTerminationRequest)
return;
if (!Sys_Unhide())
// Didn't work -- hide again so we should get another chance to unhide later
[NSApp hide: nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
{
int choice;
if (!Sys_IsHidden) {
// We're terminating via -terminate:
return NSTerminateNow;
}
// Avoid reactivating GL when we unhide due to this panel
Sys_IsProcessingTerminationRequest = qtrue;
choice = NSRunAlertPanel(nil, @"Quit without saving?", @"Don't Quit", @"Quit", nil);
Sys_IsProcessingTerminationRequest = qfalse;
if (choice == NSAlertAlternateReturn)
return NSTerminateNow;
// Make sure we get re-hidden
[NSApp hide:nil];
return NSTerminateCancel;
}
// Actions
- (IBAction)paste:(id)sender;
{
int shiftWasDown, insertWasDown;
unsigned int currentTime;
currentTime = Sys_Milliseconds();
// Save the original keyboard state
shiftWasDown = keys[K_SHIFT].down;
insertWasDown = keys[K_INS].down;
// Fake a Shift-Insert keyboard event
keys[K_SHIFT].down = qtrue;
Sys_QueEvent(currentTime, SE_KEY, K_INS, qtrue, 0, NULL);
Sys_QueEvent(currentTime, SE_KEY, K_INS, qfalse, 0, NULL);
// Restore the original keyboard state
keys[K_SHIFT].down = shiftWasDown;
keys[K_INS].down = insertWasDown;
}
extern void CL_Quit_f(void);
- (IBAction)requestTerminate:(id)sender;
{
Com_Quit_f();
// UI_QuitMenu();
}
- (void)showBanner;
{
static BOOL hasShownBanner = NO;
if (!hasShownBanner) {
cvar_t *showBanner;
hasShownBanner = YES;
showBanner = Cvar_Get("cl_showBanner", "1", 0);
if (showBanner->integer != 0) {
NSPanel *splashPanel;
NSImage *bannerImage;
NSRect bannerRect;
NSImageView *bannerImageView;
bannerImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"banner.jpg"]];
bannerRect = NSMakeRect(0.0, 0.0, [bannerImage size].width, [bannerImage size].height);
splashPanel = [[NSPanel alloc] initWithContentRect:bannerRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
bannerImageView = [[NSImageView alloc] initWithFrame:bannerRect];
[bannerImageView setImage:bannerImage];
[splashPanel setContentView:bannerImageView];
[bannerImageView release];
[splashPanel center];
[splashPanel setHasShadow:YES];
[splashPanel orderFront: nil];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.5]];
[splashPanel close];
[bannerImage release];
}
}
}
// Services
- (void)connectToServer:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedServer;
requestedServer = [pasteboard stringForType:NSStringPboardType];
if (requestedServer) {
Cbuf_AddText(va("connect %s\n", [requestedServer cString]));
return;
}
}
*error = @"Unable to connect to server: could not find string on pasteboard";
}
- (void)performCommand:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedCommand;
requestedCommand = [pasteboard stringForType:NSStringPboardType];
if (requestedCommand) {
Cbuf_AddText(va("%s\n", [requestedCommand cString]));
return;
}
}
*error = @"Unable to perform command: could not find string on pasteboard";
}
#endif
- (void)quakeMain;
{
NSAutoreleasePool *pool;
int argc = 0;
const char *argv[MAX_ARGC];
NSProcessInfo *processInfo;
NSArray *arguments;
unsigned int argumentIndex, argumentCount;
NSFileManager *defaultManager;
unsigned int commandLineLength;
NSString *installationPathKey, *installationPath;
char *cmdline;
BOOL foundDirectory;
NSString *appName, *demoAppName, *selectButton;
int count = 0;
pool = [[NSAutoreleasePool alloc] init];
[NSApp setServicesProvider:self];
processInfo = [NSProcessInfo processInfo];
arguments = [processInfo arguments];
argumentCount = [arguments count];
for (argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
NSString *arg;
arg = [arguments objectAtIndex:argumentIndex];
// Don't pass the Process Serial Number command line arg that the Window Server/Finder invokes us with
if ([arg hasPrefix: @"-psn_"])
continue;
argv[argc++] = strdup([arg cString]);
}
// Figure out where the level data is stored.
installationPathKey = @"RetailInstallationPath";
installationPath = [[NSUserDefaults standardUserDefaults] objectForKey:installationPathKey];
if (!installationPath) {
// Default to the directory containing the executable (which is where most users will want to put it
installationPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
}
#if !defined(DEDICATED)
appName = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"CFBundleName"];
#else
// We are hard coding the app name here since the dedicated server is a tool, not a app bundle and does not have access to the Info.plist that the client app does. Suck.
appName = @"Quake3";
#endif
demoAppName = appName;
while (YES) {
NSString *dataPath;
NSOpenPanel *openPanel;
int result;
foundDirectory = NO;
defaultManager = [NSFileManager defaultManager];
//NSLog(@"Candidate installation path = %@", installationPath);
dataPath = [installationPath stringByAppendingPathComponent: @"baseq3"];
if ([defaultManager fileExistsAtPath: dataPath]) {
// Check that the data directory contains at least one .pk3 file. We don't know what it will be named, so don't hard code a name (for example it might be named 'french.pk3' for a French release
NSArray *files;
unsigned int fileIndex;
files = [defaultManager directoryContentsAtPath: dataPath];
fileIndex = [files count];
while (fileIndex--) {
if ([[files objectAtIndex: fileIndex] hasSuffix: @"pk3"]) {
//NSLog(@"Found %@.", [files objectAtIndex: fileIndex]);
foundDirectory = YES;
break;
}
}
}
if (foundDirectory)
break;
#ifdef DEDICATED
break;
#warning TJW: We are hard coding the app name and default domain here since the dedicated server is a tool, not a app bundle and does not have access to the Info.plist that the client app does. Suck.
NSLog(@"Unable to determine installation directory. Please move the executable into the '%@' installation directory or add a '%@' key in the 'Q3DedicatedServer' defaults domain.", appName, installationPathKey, [[NSBundle mainBundle] bundleIdentifier]);
Sys_Quit();
exit(1);
#else
selectButton = @"Select Retail Installation...";
result = NSRunAlertPanel(demoAppName, @"You need to select the installation directory for %@ (not any directory inside of it -- the installation directory itself).", selectButton, @"Quit", nil, appName);
switch (result) {
case NSAlertDefaultReturn:
break;
default:
Sys_Quit();
break;
}
openPanel = [NSOpenPanel openPanel];
[openPanel setAllowsMultipleSelection:NO];
[openPanel setCanChooseDirectories:YES];
[openPanel setCanChooseFiles:NO];
result = [openPanel runModalForDirectory:nil file:nil];
if (result == NSOKButton) {
NSArray *filenames;
filenames = [openPanel filenames];
if ([filenames count] == 1) {
installationPath = [filenames objectAtIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:installationPath forKey:installationPathKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
#endif
}
// Create the application support directory if it doesn't exist already
do {
NSArray *results;
NSString *libraryPath, *homePath, *filePath;
NSDictionary *attributes;
results = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
if (![results count])
break;
libraryPath = [results objectAtIndex: 0];
homePath = [libraryPath stringByAppendingPathComponent: @"Application Support"];
homePath = [homePath stringByAppendingPathComponent: appName];
filePath = [homePath stringByAppendingPathComponent: @"foo"];
attributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithUnsignedInt: 0750], NSFilePosixPermissions, nil];
NS_DURING {
Sys_CreatePathToFile(filePath, attributes);
Sys_SetDefaultHomePath([homePath fileSystemRepresentation]);
} NS_HANDLER {
NSLog(@"Exception: %@", localException);
#ifndef DEDICATED
NSRunAlertPanel(nil, @"Unable to create '%@'. Please make sure that you have permission to write to this folder and re-run the game.", @"OK", nil, nil, homePath);
#endif
Sys_Quit();
} NS_ENDHANDLER;
} while(0);
// Provoke the CD scanning code into looking up the CD.
Sys_CheckCD();
// Let the filesystem know where our local install is
Sys_SetDefaultInstallPath([installationPath cString]);
cmdline = NULL;
#if 0
if (GRCheckFileForCmd()) {
GRGetWaitingCmd();
if (GRHasProperty( 'Exec' )) {
NSString *cfgPath, *grCfg;
cfgPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
cfgPath = [cfgPath stringByAppendingPathComponent: [NSString stringWithCString: GRGetPropertyStr( 'Exec' )]];
grCfg = [NSString stringWithContentsOfFile: cfgPath];
cmdline = malloc(strlen([grCfg cString])+1);
[grCfg getCString: cmdline];
}
}
#endif
if (!cmdline) {
// merge the command line, this is kinda silly
for (commandLineLength = 1, argumentIndex = 1; argumentIndex < argc; argumentIndex++)
commandLineLength += strlen(argv[argumentIndex]) + 1;
cmdline = malloc(commandLineLength);
*cmdline = '\0';
for (argumentIndex = 1; argumentIndex < argc; argumentIndex++) {
if (argumentIndex > 1)
strcat(cmdline, " ");
strcat(cmdline, argv[argumentIndex]);
}
}
Com_Printf("command line: %s\n", cmdline);
Com_Init(cmdline);
#ifndef DEDICATED
[NSApp activateIgnoringOtherApps:YES];
#endif
while (1) {
Com_Frame();
if ((count & 15)==0) {
// We should think about doing this less frequently than every frame
[pool release];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool release];
}
@end
// Creates any directories needed to be able to create a file at the specified path. Raises an exception on failure.
static void Sys_CreatePathToFile(NSString *path, NSDictionary *attributes)
{
NSArray *pathComponents;
unsigned int dirIndex, dirCount;
unsigned int startingIndex;
NSFileManager *manager;
manager = [NSFileManager defaultManager];
pathComponents = [path pathComponents];
dirCount = [pathComponents count] - 1;
startingIndex = 0;
for (dirIndex = startingIndex; dirIndex < dirCount; dirIndex++) {
NSString *partialPath;
BOOL fileExists;
partialPath = [NSString pathWithComponents:[pathComponents subarrayWithRange:NSMakeRange(0, dirIndex + 1)]];
// Don't use the 'fileExistsAtPath:isDirectory:' version since it doesn't traverse symlinks
fileExists = [manager fileExistsAtPath:partialPath];
if (!fileExists) {
if (![manager createDirectoryAtPath:partialPath attributes:attributes]) {
[NSException raise:NSGenericException format:@"Unable to create a directory at path: %@", partialPath];
}
} else {
NSDictionary *attributes;
attributes = [manager fileAttributesAtPath:partialPath traverseLink:YES];
if (![[attributes objectForKey:NSFileType] isEqualToString: NSFileTypeDirectory]) {
[NSException raise:NSGenericException format:@"Unable to write to path \"%@\" because \"%@\" is not a directory",
path, partialPath];
}
}
}
}
#ifdef DEDICATED
void S_ClearSoundBuffer( void ) {
}
#endif

0
code/macosx/Quake3.icns Normal file → Executable file
View file

0
code/macosx/Quake3.nib/classes.nib generated Normal file → Executable file
View file

0
code/macosx/Quake3.nib/info.nib generated Normal file → Executable file
View file

0
code/macosx/Quake3.nib/objects.nib generated Normal file → Executable file
View file

1126
code/macosx/Quake3.pbproj/apple.pbxuser Normal file → Executable file

File diff suppressed because it is too large Load diff

23604
code/macosx/Quake3.pbproj/project.pbxproj Normal file → Executable file

File diff suppressed because it is too large Load diff

18
code/macosx/RecordDemo.zsh Normal file → Executable file
View file

@ -1,9 +1,9 @@
#!/bin/zsh -x
/Local/Public/bungi/BuildOutput/Quake3.app/Contents/MacOS/Quake3 \
+set sv_pure 0 \
+set g_syncronousClients 1 \
+map q3dm6 \
+record foo
#!/bin/zsh -x
/Local/Public/bungi/BuildOutput/Quake3.app/Contents/MacOS/Quake3 \
+set sv_pure 0 \
+set g_syncronousClients 1 \
+map q3dm6 \
+record foo

0
code/macosx/banner.jpg Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Before After
Before After

392
code/macosx/botlib.log Normal file → Executable file
View file

@ -1,196 +1,196 @@
item team_redobelisk has modelindex 0item team_blueobelisk has modelindex 0item team_neutralobelisk has modelindex 0item item_botroam has modelindex 0entity worldspawn unknown item
entity target_delay unknown item
entity light unknown item
entity target_delay unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity misc_model unknown item
entity light unknown item
entity light unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity target_position unknown item
entity info_player_intermission unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity misc_model unknown item
entity light unknown item
entity misc_teleporter_dest unknown item
entity target_position unknown item
entity misc_portal_camera unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity info_null unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity info_player_deathmatch unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity trigger_multiple unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity trigger_teleport unknown item
entity misc_portal_surface unknown item
entity misc_portal_surface unknown item
entity info_player_deathmatch unknown item
entity misc_model unknown item
entity light unknown item
entity func_rotating unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity func_rotating unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity misc_model unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity func_door unknown item
entity func_door unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity light unknown item
bots/crash_c.cskill 1073741824
{
0 Crash
1 female
2 0.366667
3 bots/crash_w.c
4 0.366667
5 180
6 4.166667
7 0.366667
8 0.366667
9 0.450000
10 0.450000
11 0.450000
12 0.450000
13 0.450000
14 0.450000
15 0.450000
16 0.366667
17 0.450000
18 0.450000
19 0.450000
20 0.450000
21 bots/crash_t.c
22 crash
23 400
24 0.400000
25 1.000000
26 1.000000
27 1.000000
28 1.000000
29 1.000000
30 1.000000
31 1.000000
32 1.000000
33 1.000000
34 1.000000
35 1.000000
36 0.000000
37 0.000000
38 0.000000
39 0.000000
40 bots/crash_i.c
41 0.233333
42 0.233333
43 0.233333
44 0.233333
45 0.000000
46 0.233333
47 0.333333
48 1.000000
}
item info 7 "weapon_gauntlet" has no fuzzy weight
item info 16 "weapon_grapplinghook" has no fuzzy weight
item info 49 "team_redobelisk" has no fuzzy weight
item info 50 "team_blueobelisk" has no fuzzy weight
item info 51 "team_neutralobelisk" has no fuzzy weight
item team_redobelisk has modelindex 0item team_blueobelisk has modelindex 0item team_neutralobelisk has modelindex 0item item_botroam has modelindex 0entity worldspawn unknown item
entity target_delay unknown item
entity light unknown item
entity target_delay unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity misc_model unknown item
entity light unknown item
entity light unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity target_position unknown item
entity info_player_intermission unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity misc_model unknown item
entity light unknown item
entity misc_teleporter_dest unknown item
entity target_position unknown item
entity misc_portal_camera unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity info_null unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity info_player_deathmatch unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity info_player_deathmatch unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity trigger_multiple unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity trigger_multiple unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity trigger_teleport unknown item
entity misc_portal_surface unknown item
entity misc_portal_surface unknown item
entity info_player_deathmatch unknown item
entity misc_model unknown item
entity light unknown item
entity func_rotating unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity target_position unknown item
entity light unknown item
entity light unknown item
entity func_rotating unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity misc_model unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity func_timer unknown item
entity target_speaker unknown item
entity func_door unknown item
entity func_door unknown item
entity light unknown item
entity light unknown item
entity misc_model unknown item
entity light unknown item
bots/crash_c.cskill 1073741824
{
0 Crash
1 female
2 0.366667
3 bots/crash_w.c
4 0.366667
5 180
6 4.166667
7 0.366667
8 0.366667
9 0.450000
10 0.450000
11 0.450000
12 0.450000
13 0.450000
14 0.450000
15 0.450000
16 0.366667
17 0.450000
18 0.450000
19 0.450000
20 0.450000
21 bots/crash_t.c
22 crash
23 400
24 0.400000
25 1.000000
26 1.000000
27 1.000000
28 1.000000
29 1.000000
30 1.000000
31 1.000000
32 1.000000
33 1.000000
34 1.000000
35 1.000000
36 0.000000
37 0.000000
38 0.000000
39 0.000000
40 bots/crash_i.c
41 0.233333
42 0.233333
43 0.233333
44 0.233333
45 0.000000
46 0.233333
47 0.333333
48 1.000000
}
item info 7 "weapon_gauntlet" has no fuzzy weight
item info 16 "weapon_grapplinghook" has no fuzzy weight
item info 49 "team_redobelisk" has no fuzzy weight
item info 50 "team_blueobelisk" has no fuzzy weight
item info 51 "team_neutralobelisk" has no fuzzy weight

76
code/macosx/macosx_display.h Normal file → Executable file
View file

@ -1,38 +1,38 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "macosx_local.h"
@class NSDictionary;
extern NSDictionary *Sys_GetMatchingDisplayMode(qboolean allowStretchedModes);
extern void Sys_StoreGammaTables();
extern void Sys_GetGammaTable(glwgamma_t *table);
extern void Sys_SetScreenFade(glwgamma_t *table, float fraction);
extern void Sys_FadeScreens();
extern void Sys_FadeScreen(CGDirectDisplayID display);
extern void Sys_UnfadeScreens();
extern void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table);
extern void Sys_ReleaseAllDisplays();
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "macosx_local.h"
@class NSDictionary;
extern NSDictionary *Sys_GetMatchingDisplayMode(qboolean allowStretchedModes);
extern void Sys_StoreGammaTables();
extern void Sys_GetGammaTable(glwgamma_t *table);
extern void Sys_SetScreenFade(glwgamma_t *table, float fraction);
extern void Sys_FadeScreens();
extern void Sys_FadeScreen(CGDirectDisplayID display);
extern void Sys_UnfadeScreens();
extern void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table);
extern void Sys_ReleaseAllDisplays();

746
code/macosx/macosx_display.m Normal file → Executable file
View file

@ -1,373 +1,373 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_display.h"
#include "tr_local.h"
#import "macosx_local.h"
#import <Foundation/Foundation.h>
#import <IOKit/graphics/IOGraphicsTypes.h> // for interpreting the kCGDisplayIOFlags element of the display mode
NSDictionary *Sys_GetMatchingDisplayMode(qboolean allowStretchedModes)
{
NSArray *displayModes;
NSDictionary *mode;
unsigned int modeIndex, modeCount, bestModeIndex;
int verbose;
cvar_t *cMinFreq, *cMaxFreq;
int minFreq, maxFreq;
unsigned int colorDepth;
verbose = r_verbose->integer;
colorDepth = r_colorbits->integer;
if (colorDepth < 16 || !r_fullscreen->integer)
colorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue];
cMinFreq = ri.Cvar_Get("r_minDisplayRefresh", "0", CVAR_ARCHIVE);
cMaxFreq = ri.Cvar_Get("r_maxDisplayRefresh", "0", CVAR_ARCHIVE);
if (cMinFreq && cMaxFreq && cMinFreq->integer && cMaxFreq->integer &&
cMinFreq->integer > cMaxFreq->integer) {
ri.Error(ERR_FATAL, "r_minDisplayRefresh must be less than or equal to r_maxDisplayRefresh");
}
minFreq = cMinFreq ? cMinFreq->integer : 0;
maxFreq = cMaxFreq ? cMaxFreq->integer : 0;
displayModes = (NSArray *)CGDisplayAvailableModes(glw_state.display);
if (!displayModes) {
ri.Error(ERR_FATAL, "CGDisplayAvailableModes returned NULL -- 0x%0x is an invalid display", glw_state.display);
}
modeCount = [displayModes count];
if (verbose) {
ri.Printf(PRINT_ALL, "%d modes avaliable\n", modeCount);
ri.Printf(PRINT_ALL, "Current mode is %s\n", [[(id)CGDisplayCurrentMode(glw_state.display) description] cString]);
}
// Default to the current desktop mode
bestModeIndex = 0xFFFFFFFF;
for ( modeIndex = 0; modeIndex < modeCount; ++modeIndex ) {
id object;
int refresh;
mode = [displayModes objectAtIndex: modeIndex];
if (verbose) {
ri.Printf(PRINT_ALL, " mode %d -- %s\n", modeIndex, [[mode description] cString]);
}
// Make sure we get the right size
object = [mode objectForKey: (id)kCGDisplayWidth];
if ([[mode objectForKey: (id)kCGDisplayWidth] intValue] != glConfig.vidWidth ||
[[mode objectForKey: (id)kCGDisplayHeight] intValue] != glConfig.vidHeight) {
if (verbose)
ri.Printf(PRINT_ALL, " -- bad size\n");
continue;
}
if (!allowStretchedModes) {
if ([[mode objectForKey: (id)kCGDisplayIOFlags] intValue] & kDisplayModeStretchedFlag) {
if (verbose)
ri.Printf(PRINT_ALL, " -- stretched modes disallowed\n");
continue;
}
}
// Make sure that our frequency restrictions are observed
refresh = [[mode objectForKey: (id)kCGDisplayRefreshRate] intValue];
if (minFreq && refresh < minFreq) {
if (verbose)
ri.Printf(PRINT_ALL, " -- refresh too low\n");
continue;
}
if (maxFreq && refresh > maxFreq) {
if (verbose)
ri.Printf(PRINT_ALL, " -- refresh too high\n");
continue;
}
if ([[mode objectForKey: (id)kCGDisplayBitsPerPixel] intValue] != colorDepth) {
if (verbose)
ri.Printf(PRINT_ALL, " -- bad depth\n");
continue;
}
bestModeIndex = modeIndex;
if (verbose)
ri.Printf(PRINT_ALL, " -- OK\n", bestModeIndex);
}
if (verbose)
ri.Printf(PRINT_ALL, " bestModeIndex = %d\n", bestModeIndex);
if (bestModeIndex == 0xFFFFFFFF) {
ri.Printf(PRINT_ALL, "No suitable display mode available.\n");
return nil;
}
return [displayModes objectAtIndex: bestModeIndex];
}
#define MAX_DISPLAYS 128
void Sys_GetGammaTable(glwgamma_t *table)
{
CGTableCount tableSize = 512;
CGDisplayErr err;
table->tableSize = tableSize;
if (table->red)
free(table->red);
table->red = malloc(tableSize * sizeof(*table->red));
if (table->green)
free(table->green);
table->green = malloc(tableSize * sizeof(*table->green));
if (table->blue)
free(table->blue);
table->blue = malloc(tableSize * sizeof(*table->blue));
// TJW: We _could_ loop here if we get back the same size as our table, increasing the table size.
err = CGGetDisplayTransferByTable(table->display, tableSize, table->red, table->green, table->blue,
&table->tableSize);
if (err != CGDisplayNoErr) {
Com_Printf("GLimp_Init: CGGetDisplayTransferByTable returned %d.\n", err);
table->tableSize = 0;
}
}
void Sys_SetGammaTable(glwgamma_t *table)
{
}
void Sys_StoreGammaTables()
{
// Store the original gamma for all monitors so that we can fade and unfade them all
CGDirectDisplayID displays[MAX_DISPLAYS];
CGDisplayCount displayIndex;
CGDisplayErr err;
err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &glw_state.displayCount);
if (err != CGDisplayNoErr)
Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
glw_state.originalDisplayGammaTables = calloc(glw_state.displayCount, sizeof(*glw_state.originalDisplayGammaTables));
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
glwgamma_t *table;
table = &glw_state.originalDisplayGammaTables[displayIndex];
table->display = displays[displayIndex];
Sys_GetGammaTable(table);
}
}
// This isn't a mathematically correct fade, but we don't care that much.
void Sys_SetScreenFade(glwgamma_t *table, float fraction)
{
CGTableCount tableSize;
CGGammaValue *red, *blue, *green;
CGTableCount gammaIndex;
if (!glConfig.deviceSupportsGamma)
return;
if (!(tableSize = table->tableSize))
// we couldn't get the table for this display for some reason
return;
// Com_Printf("0x%08x %f\n", table->display, fraction);
red = glw_state.tempTable.red;
green = glw_state.tempTable.green;
blue = glw_state.tempTable.blue;
if (glw_state.tempTable.tableSize < tableSize) {
glw_state.tempTable.tableSize = tableSize;
red = realloc(red, sizeof(*red) * tableSize);
green = realloc(green, sizeof(*green) * tableSize);
blue = realloc(blue, sizeof(*blue) * tableSize);
glw_state.tempTable.red = red;
glw_state.tempTable.green = green;
glw_state.tempTable.blue = blue;
}
for (gammaIndex = 0; gammaIndex < table->tableSize; gammaIndex++) {
red[gammaIndex] = table->red[gammaIndex] * fraction;
blue[gammaIndex] = table->blue[gammaIndex] * fraction;
green[gammaIndex] = table->green[gammaIndex] * fraction;
}
CGSetDisplayTransferByTable(table->display, table->tableSize, red, green, blue);
}
// Fades all the active displays at the same time.
#define FADE_DURATION 0.5
void Sys_FadeScreens()
{
CGDisplayCount displayIndex;
int stepIndex;
glwgamma_t *table;
NSTimeInterval start, current;
float time;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Fading all displays\n");
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
}
}
}
void Sys_FadeScreen(CGDirectDisplayID display)
{
CGDisplayCount displayIndex;
glwgamma_t *table;
int stepIndex;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Fading display 0x%08x\n", display);
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
NSTimeInterval start, current;
float time;
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
table = &glw_state.originalDisplayGammaTables[displayIndex];
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
}
return;
}
}
Com_Printf("Unable to find display to fade it\n");
}
void Sys_UnfadeScreens()
{
CGDisplayCount displayIndex;
int stepIndex;
glwgamma_t *table;
NSTimeInterval start, current;
float time;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Unfading all displays\n");
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
Sys_SetScreenFade(table, time / FADE_DURATION);
}
}
}
void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table)
{
CGDisplayCount displayIndex;
int stepIndex;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Unfading display 0x%08x\n", display);
if (table) {
CGTableCount i;
Com_Printf("Given table:\n");
for (i = 0; i < table->tableSize; i++) {
Com_Printf(" %f %f %f\n", table->red[i], table->blue[i], table->green[i]);
}
}
// Search for the original gamma table for the display
if (!table) {
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
break;
}
}
}
if (table) {
NSTimeInterval start, current;
float time;
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
Sys_SetScreenFade(table, time / FADE_DURATION);
}
return;
}
Com_Printf("Unable to find display to unfade it\n");
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_display.h"
#include "tr_local.h"
#import "macosx_local.h"
#import <Foundation/Foundation.h>
#import <IOKit/graphics/IOGraphicsTypes.h> // for interpreting the kCGDisplayIOFlags element of the display mode
NSDictionary *Sys_GetMatchingDisplayMode(qboolean allowStretchedModes)
{
NSArray *displayModes;
NSDictionary *mode;
unsigned int modeIndex, modeCount, bestModeIndex;
int verbose;
cvar_t *cMinFreq, *cMaxFreq;
int minFreq, maxFreq;
unsigned int colorDepth;
verbose = r_verbose->integer;
colorDepth = r_colorbits->integer;
if (colorDepth < 16 || !r_fullscreen->integer)
colorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue];
cMinFreq = ri.Cvar_Get("r_minDisplayRefresh", "0", CVAR_ARCHIVE);
cMaxFreq = ri.Cvar_Get("r_maxDisplayRefresh", "0", CVAR_ARCHIVE);
if (cMinFreq && cMaxFreq && cMinFreq->integer && cMaxFreq->integer &&
cMinFreq->integer > cMaxFreq->integer) {
ri.Error(ERR_FATAL, "r_minDisplayRefresh must be less than or equal to r_maxDisplayRefresh");
}
minFreq = cMinFreq ? cMinFreq->integer : 0;
maxFreq = cMaxFreq ? cMaxFreq->integer : 0;
displayModes = (NSArray *)CGDisplayAvailableModes(glw_state.display);
if (!displayModes) {
ri.Error(ERR_FATAL, "CGDisplayAvailableModes returned NULL -- 0x%0x is an invalid display", glw_state.display);
}
modeCount = [displayModes count];
if (verbose) {
ri.Printf(PRINT_ALL, "%d modes avaliable\n", modeCount);
ri.Printf(PRINT_ALL, "Current mode is %s\n", [[(id)CGDisplayCurrentMode(glw_state.display) description] cString]);
}
// Default to the current desktop mode
bestModeIndex = 0xFFFFFFFF;
for ( modeIndex = 0; modeIndex < modeCount; ++modeIndex ) {
id object;
int refresh;
mode = [displayModes objectAtIndex: modeIndex];
if (verbose) {
ri.Printf(PRINT_ALL, " mode %d -- %s\n", modeIndex, [[mode description] cString]);
}
// Make sure we get the right size
object = [mode objectForKey: (id)kCGDisplayWidth];
if ([[mode objectForKey: (id)kCGDisplayWidth] intValue] != glConfig.vidWidth ||
[[mode objectForKey: (id)kCGDisplayHeight] intValue] != glConfig.vidHeight) {
if (verbose)
ri.Printf(PRINT_ALL, " -- bad size\n");
continue;
}
if (!allowStretchedModes) {
if ([[mode objectForKey: (id)kCGDisplayIOFlags] intValue] & kDisplayModeStretchedFlag) {
if (verbose)
ri.Printf(PRINT_ALL, " -- stretched modes disallowed\n");
continue;
}
}
// Make sure that our frequency restrictions are observed
refresh = [[mode objectForKey: (id)kCGDisplayRefreshRate] intValue];
if (minFreq && refresh < minFreq) {
if (verbose)
ri.Printf(PRINT_ALL, " -- refresh too low\n");
continue;
}
if (maxFreq && refresh > maxFreq) {
if (verbose)
ri.Printf(PRINT_ALL, " -- refresh too high\n");
continue;
}
if ([[mode objectForKey: (id)kCGDisplayBitsPerPixel] intValue] != colorDepth) {
if (verbose)
ri.Printf(PRINT_ALL, " -- bad depth\n");
continue;
}
bestModeIndex = modeIndex;
if (verbose)
ri.Printf(PRINT_ALL, " -- OK\n", bestModeIndex);
}
if (verbose)
ri.Printf(PRINT_ALL, " bestModeIndex = %d\n", bestModeIndex);
if (bestModeIndex == 0xFFFFFFFF) {
ri.Printf(PRINT_ALL, "No suitable display mode available.\n");
return nil;
}
return [displayModes objectAtIndex: bestModeIndex];
}
#define MAX_DISPLAYS 128
void Sys_GetGammaTable(glwgamma_t *table)
{
CGTableCount tableSize = 512;
CGDisplayErr err;
table->tableSize = tableSize;
if (table->red)
free(table->red);
table->red = malloc(tableSize * sizeof(*table->red));
if (table->green)
free(table->green);
table->green = malloc(tableSize * sizeof(*table->green));
if (table->blue)
free(table->blue);
table->blue = malloc(tableSize * sizeof(*table->blue));
// TJW: We _could_ loop here if we get back the same size as our table, increasing the table size.
err = CGGetDisplayTransferByTable(table->display, tableSize, table->red, table->green, table->blue,
&table->tableSize);
if (err != CGDisplayNoErr) {
Com_Printf("GLimp_Init: CGGetDisplayTransferByTable returned %d.\n", err);
table->tableSize = 0;
}
}
void Sys_SetGammaTable(glwgamma_t *table)
{
}
void Sys_StoreGammaTables()
{
// Store the original gamma for all monitors so that we can fade and unfade them all
CGDirectDisplayID displays[MAX_DISPLAYS];
CGDisplayCount displayIndex;
CGDisplayErr err;
err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &glw_state.displayCount);
if (err != CGDisplayNoErr)
Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
glw_state.originalDisplayGammaTables = calloc(glw_state.displayCount, sizeof(*glw_state.originalDisplayGammaTables));
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
glwgamma_t *table;
table = &glw_state.originalDisplayGammaTables[displayIndex];
table->display = displays[displayIndex];
Sys_GetGammaTable(table);
}
}
// This isn't a mathematically correct fade, but we don't care that much.
void Sys_SetScreenFade(glwgamma_t *table, float fraction)
{
CGTableCount tableSize;
CGGammaValue *red, *blue, *green;
CGTableCount gammaIndex;
if (!glConfig.deviceSupportsGamma)
return;
if (!(tableSize = table->tableSize))
// we couldn't get the table for this display for some reason
return;
// Com_Printf("0x%08x %f\n", table->display, fraction);
red = glw_state.tempTable.red;
green = glw_state.tempTable.green;
blue = glw_state.tempTable.blue;
if (glw_state.tempTable.tableSize < tableSize) {
glw_state.tempTable.tableSize = tableSize;
red = realloc(red, sizeof(*red) * tableSize);
green = realloc(green, sizeof(*green) * tableSize);
blue = realloc(blue, sizeof(*blue) * tableSize);
glw_state.tempTable.red = red;
glw_state.tempTable.green = green;
glw_state.tempTable.blue = blue;
}
for (gammaIndex = 0; gammaIndex < table->tableSize; gammaIndex++) {
red[gammaIndex] = table->red[gammaIndex] * fraction;
blue[gammaIndex] = table->blue[gammaIndex] * fraction;
green[gammaIndex] = table->green[gammaIndex] * fraction;
}
CGSetDisplayTransferByTable(table->display, table->tableSize, red, green, blue);
}
// Fades all the active displays at the same time.
#define FADE_DURATION 0.5
void Sys_FadeScreens()
{
CGDisplayCount displayIndex;
int stepIndex;
glwgamma_t *table;
NSTimeInterval start, current;
float time;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Fading all displays\n");
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
}
}
}
void Sys_FadeScreen(CGDirectDisplayID display)
{
CGDisplayCount displayIndex;
glwgamma_t *table;
int stepIndex;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Fading display 0x%08x\n", display);
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
NSTimeInterval start, current;
float time;
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
table = &glw_state.originalDisplayGammaTables[displayIndex];
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
}
return;
}
}
Com_Printf("Unable to find display to fade it\n");
}
void Sys_UnfadeScreens()
{
CGDisplayCount displayIndex;
int stepIndex;
glwgamma_t *table;
NSTimeInterval start, current;
float time;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Unfading all displays\n");
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
Sys_SetScreenFade(table, time / FADE_DURATION);
}
}
}
void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table)
{
CGDisplayCount displayIndex;
int stepIndex;
if (!glConfig.deviceSupportsGamma)
return;
Com_Printf("Unfading display 0x%08x\n", display);
if (table) {
CGTableCount i;
Com_Printf("Given table:\n");
for (i = 0; i < table->tableSize; i++) {
Com_Printf(" %f %f %f\n", table->red[i], table->blue[i], table->green[i]);
}
}
// Search for the original gamma table for the display
if (!table) {
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
table = &glw_state.originalDisplayGammaTables[displayIndex];
break;
}
}
}
if (table) {
NSTimeInterval start, current;
float time;
start = [NSDate timeIntervalSinceReferenceDate];
time = 0.0;
while (time != FADE_DURATION) {
current = [NSDate timeIntervalSinceReferenceDate];
time = current - start;
if (time > FADE_DURATION)
time = FADE_DURATION;
Sys_SetScreenFade(table, time / FADE_DURATION);
}
return;
}
Com_Printf("Unable to find display to unfade it\n");
}

74
code/macosx/macosx_glimp.h Normal file → Executable file
View file

@ -1,37 +1,37 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#ifndef GL_EXT_abgr
#include <OpenGL/glext.h>
#endif
// This can be defined to use the CGLMacro.h support which avoids looking up
// the current context.
//#define USE_CGLMACROS
#ifdef USE_CGLMACROS
#include "macosx_local.h"
#define cgl_ctx glw_state._cgl_ctx
#include <OpenGL/CGLMacro.h>
#endif
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#ifndef GL_EXT_abgr
#include <OpenGL/glext.h>
#endif
// This can be defined to use the CGLMacro.h support which avoids looking up
// the current context.
//#define USE_CGLMACROS
#ifdef USE_CGLMACROS
#include "macosx_local.h"
#define cgl_ctx glw_state._cgl_ctx
#include <OpenGL/CGLMacro.h>
#endif

2228
code/macosx/macosx_glimp.m Normal file → Executable file

File diff suppressed because it is too large Load diff

352
code/macosx/macosx_glsmp_mutex.m Normal file → Executable file
View file

@ -1,176 +1,176 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
#import "macosx_display.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <pthread.h>
//
// The main Q3 SMP API
//
static pthread_mutex_t smpMutex;
static pthread_cond_t mainThreadCondition;
static pthread_cond_t renderThreadCondition;
static volatile qboolean smpDataChanged;
static volatile void *smpData;
static void *GLimp_RenderThreadWrapper(void *arg)
{
Com_Printf("Render thread starting\n");
((void (*)())arg)();
#ifndef USE_CGLMACROS
// Unbind the context before we die
OSX_GLContextClearCurrent();
#endif
Com_Printf("Render thread terminating\n");
return arg;
}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
pthread_t renderThread;
int rc;
pthread_mutex_init(&smpMutex, NULL);
pthread_cond_init(&mainThreadCondition, NULL);
pthread_cond_init(&renderThreadCondition, NULL);
rc = pthread_create(&renderThread, NULL, GLimp_RenderThreadWrapper, function);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
return qfalse;
} else {
rc = pthread_detach(renderThread);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
}
}
return qtrue;
}
// Called in the rendering thread to wait until a command buffer is ready.
// The command buffer returned might be NULL, indicating that the rendering thread should exit.
void *GLimp_RendererSleep(void)
{
void *data;
GLSTAMP("GLimp_RendererSleep start", 0);
#ifndef USE_CGLMACROS
// Clear the current context while we sleep so the main thread can access it
OSX_GLContextClearCurrent();
#endif
pthread_mutex_lock(&smpMutex); {
// Clear out any data we had and signal the main thread that we are no longer busy
smpData = NULL;
smpDataChanged = qfalse;
pthread_cond_signal(&mainThreadCondition);
// Wait until we get something new to work on
while (!smpDataChanged)
pthread_cond_wait(&renderThreadCondition, &smpMutex);
// Record the data (if any).
data = smpData;
} pthread_mutex_unlock(&smpMutex);
#ifndef USE_CGLMACROS
// We are going to render a frame... retake the context
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_RendererSleep end", 0);
return (void *)data;
}
// Called from the main thread to wait until the rendering thread is done with the command buffer.
void GLimp_FrontEndSleep(void)
{
GLSTAMP("GLimp_FrontEndSleep start", 0);
pthread_mutex_lock(&smpMutex); {
while (smpData) {
#if 0
struct timespec ts;
int result;
ts.tv_sec = 1;
ts.tv_nsec = 0;
result = pthread_cond_timedwait_relative_np(&mainThreadCondition, &smpMutex, &ts);
if (result) {
Com_Printf("GLimp_FrontEndSleep timed out. Probably due to R_SyncRenderThread called due to Com_Error being called\n");
break;
}
#else
pthread_cond_wait(&mainThreadCondition, &smpMutex);
#endif
}
} pthread_mutex_unlock(&smpMutex);
#ifndef USE_CGLMACROS
// We are done waiting for the background thread, take the current context back.
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_FrontEndSleep end", 0);
}
// This is called in the main thread to issue another command
// buffer to the rendering thread. This is always called AFTER
// GLimp_FrontEndSleep, so we know that there is no command
// pending in 'smpData'.
void GLimp_WakeRenderer( void *data )
{
GLSTAMP("GLimp_WakeRenderer start", data);
#ifndef USE_CGLMACROS
// We want the background thread to draw stuff. Give up the current context
OSX_GLContextClearCurrent();
#endif
pthread_mutex_lock(&smpMutex); {
// Store the new data pointer and wake up the rendering thread
assert(smpData == NULL);
smpData = data;
smpDataChanged = qtrue;
pthread_cond_signal(&renderThreadCondition);
} pthread_mutex_unlock(&smpMutex);
GLSTAMP("GLimp_WakeRenderer end", data);
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
#import "macosx_display.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <pthread.h>
//
// The main Q3 SMP API
//
static pthread_mutex_t smpMutex;
static pthread_cond_t mainThreadCondition;
static pthread_cond_t renderThreadCondition;
static volatile qboolean smpDataChanged;
static volatile void *smpData;
static void *GLimp_RenderThreadWrapper(void *arg)
{
Com_Printf("Render thread starting\n");
((void (*)())arg)();
#ifndef USE_CGLMACROS
// Unbind the context before we die
OSX_GLContextClearCurrent();
#endif
Com_Printf("Render thread terminating\n");
return arg;
}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
pthread_t renderThread;
int rc;
pthread_mutex_init(&smpMutex, NULL);
pthread_cond_init(&mainThreadCondition, NULL);
pthread_cond_init(&renderThreadCondition, NULL);
rc = pthread_create(&renderThread, NULL, GLimp_RenderThreadWrapper, function);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
return qfalse;
} else {
rc = pthread_detach(renderThread);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
}
}
return qtrue;
}
// Called in the rendering thread to wait until a command buffer is ready.
// The command buffer returned might be NULL, indicating that the rendering thread should exit.
void *GLimp_RendererSleep(void)
{
void *data;
GLSTAMP("GLimp_RendererSleep start", 0);
#ifndef USE_CGLMACROS
// Clear the current context while we sleep so the main thread can access it
OSX_GLContextClearCurrent();
#endif
pthread_mutex_lock(&smpMutex); {
// Clear out any data we had and signal the main thread that we are no longer busy
smpData = NULL;
smpDataChanged = qfalse;
pthread_cond_signal(&mainThreadCondition);
// Wait until we get something new to work on
while (!smpDataChanged)
pthread_cond_wait(&renderThreadCondition, &smpMutex);
// Record the data (if any).
data = smpData;
} pthread_mutex_unlock(&smpMutex);
#ifndef USE_CGLMACROS
// We are going to render a frame... retake the context
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_RendererSleep end", 0);
return (void *)data;
}
// Called from the main thread to wait until the rendering thread is done with the command buffer.
void GLimp_FrontEndSleep(void)
{
GLSTAMP("GLimp_FrontEndSleep start", 0);
pthread_mutex_lock(&smpMutex); {
while (smpData) {
#if 0
struct timespec ts;
int result;
ts.tv_sec = 1;
ts.tv_nsec = 0;
result = pthread_cond_timedwait_relative_np(&mainThreadCondition, &smpMutex, &ts);
if (result) {
Com_Printf("GLimp_FrontEndSleep timed out. Probably due to R_SyncRenderThread called due to Com_Error being called\n");
break;
}
#else
pthread_cond_wait(&mainThreadCondition, &smpMutex);
#endif
}
} pthread_mutex_unlock(&smpMutex);
#ifndef USE_CGLMACROS
// We are done waiting for the background thread, take the current context back.
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_FrontEndSleep end", 0);
}
// This is called in the main thread to issue another command
// buffer to the rendering thread. This is always called AFTER
// GLimp_FrontEndSleep, so we know that there is no command
// pending in 'smpData'.
void GLimp_WakeRenderer( void *data )
{
GLSTAMP("GLimp_WakeRenderer start", data);
#ifndef USE_CGLMACROS
// We want the background thread to draw stuff. Give up the current context
OSX_GLContextClearCurrent();
#endif
pthread_mutex_lock(&smpMutex); {
// Store the new data pointer and wake up the rendering thread
assert(smpData == NULL);
smpData = data;
smpDataChanged = qtrue;
pthread_cond_signal(&renderThreadCondition);
} pthread_mutex_unlock(&smpMutex);
GLSTAMP("GLimp_WakeRenderer end", data);
}

92
code/macosx/macosx_glsmp_null.m Normal file → Executable file
View file

@ -1,46 +1,46 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
return qfalse;
}
void *GLimp_RendererSleep(void)
{
return NULL;
}
void GLimp_FrontEndSleep(void)
{
}
void GLimp_WakeRenderer( void *data )
{
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
return qfalse;
}
void *GLimp_RendererSleep(void)
{
return NULL;
}
void GLimp_FrontEndSleep(void)
{
}
void GLimp_WakeRenderer( void *data )
{
}

850
code/macosx/macosx_glsmp_ports.m Normal file → Executable file
View file

@ -1,425 +1,425 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
#import "macosx_display.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <mach/mach.h>
#import <mach/mach_error.h>
#warning Using Mach Ports SMP acceleration implementation
/*
===========================================================
SMP acceleration
===========================================================
*/
#import <pthread.h>
#define USE_MACH_PORTS 1
// This is a small cover layer that makes for easier calling
typedef struct _MsgPort {
#if USE_MACH_PORTS
mach_port_t port;
id nsPort;
#else
pthread_mutex_t mutex;
pthread_cond_t condition;
volatile unsigned int status;
unsigned int msgCode;
void *msgData;
#endif
} MsgPort;
static BOOL portsInited = NO;
static pthread_mutex_t logMutex;
static unsigned int renderMsgOutstanding;
static unsigned int rendererProcessingCommand;
static MsgPort rendererMsgPort;
static MsgPort frontEndMsgPort;
enum {
MsgNone,
MsgPending,
};
enum {
MsgCodeInvalid = 0,
RenderCommandMsg = 1,
RenderCompletedMsg = 2,
};
static /*inline*/ void MsgPortInit(MsgPort *port)
{
#if USE_MACH_PORTS
port->nsPort = [[NSMachPort alloc] init];
port->port = [port->nsPort machPort];
//rc = mach_port_allocate(mach_task_self(), MACH_PORT_TYPE_SEND_RECEIVE, &port->port);
//if (rc) {
// fprintf(stderr, "MsgPortInit: mach_port_allocate returned: %d: %s \n",rc, mach_error_string(rc));
// }
#else
int rc;
rc = pthread_mutex_init(&port->mutex, NULL);
if (rc) {
ri.Printf(PRINT_ALL, "MsgPortInit: pthread_mutex_init returned: %d: %s\n", rc, strerror(rc));
}
rc = pthread_cond_init(&port->condition, NULL);
if (rc) {
ri.Printf(PRINT_ALL, "EventInit: pthread_cond_init returned %d: %s\n", rc, strerror(rc));
}
port->status = MsgNone;
port->msgCode = MsgCodeInvalid;
port->msgData = NULL;
#endif
}
static /*inline*/ void _SendMsg(MsgPort *port, unsigned int msgCode, void *msgData,
const char *functionName, const char *portName, const char *msgName)
{
int rc;
#if USE_MACH_PORTS
mach_msg_header_t msg;
//printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
/*
typedef struct
{
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_msg_size_t msgh_reserved;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
*/
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
msg.msgh_size=sizeof(msg);
//msg.msg_type=MSG_TYPE_NORMAL;
msg.msgh_local_port=MACH_PORT_NULL;
msg.msgh_remote_port=port->port;
msg.msgh_reserved = 0;
msg.msgh_id=(mach_msg_id_t)msgData; // HACK
rc = mach_msg_send(&msg);
if(rc) {
fprintf(stderr,"SendMsg: mach_msg_send returned %d: %s\n", rc, mach_error_string(rc));
}
#else
//printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
rc = pthread_mutex_lock(&port->mutex);
if(rc) {
fprintf(stderr,"SendMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
}
/* Block until port is empty */
while(port->status != MsgNone) {
//fprintf(stderr, "SendMsg: %s blocking until port %s is empty\n", functionName, portName);
rc = pthread_cond_wait(&port->condition, &port->mutex);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
}
}
/* Queue msg */
port->msgCode = msgCode;
port->msgData = msgData;
port->status = MsgPending;
/* Unlock port */
rc = pthread_mutex_unlock(&port->mutex);
if(rc) {
fprintf(stderr, "SendMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
/* Wake up any threads blocked waiting for a message */
rc = pthread_cond_broadcast(&port->condition);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
}
#endif
}
static /*inline*/ void _WaitMsg(MsgPort *port, unsigned int *msgCode, void **msgData,
const char *functionName, const char *portName)
{
int rc;
#if USE_MACH_PORTS
mach_msg_empty_rcv_t msg;
//printf("WaitMsg: %s %s\n",functionName, portName);
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
msg.header.msgh_size= sizeof(msg);
//msg.msg_type=MSG_TYPE_NORMAL;
msg.header.msgh_local_port=port->port;
msg.header.msgh_remote_port=MACH_PORT_NULL;
msg.header.msgh_reserved = 0;
msg.header.msgh_id=(mach_msg_id_t)msgData; // HACK
rc = mach_msg_receive(&msg.header);
if(rc) {
fprintf(stderr,"SendMsg: mach_msg_receive returned %d: %s\n", rc, mach_error_string(rc));
}
*msgData = (void *)msg.header.msgh_id;
//printf("WaitMsg: %s %s got %08lx\n",functionName, portName, *msgData);
#else
//printf("WaitMsg: %s %s\n",functionName, portName);
rc = pthread_mutex_lock(&port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
}
/* Block until port is empty */
while(port->status != MsgPending) {
rc = pthread_cond_wait(&port->condition, &port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
}
}
/* Remove msg */
*msgCode = port->msgCode;
*msgData = port->msgData;
//printf("WaitMsg: %s %s got %d %08lx\n",functionName, portName, *msgCode, *msgData);
port->status = MsgNone;
port->msgCode = 0;
port->msgData = NULL;
rc = pthread_mutex_unlock(&port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
/* Wake up any threads blocked waiting for port to be empty. */
rc = pthread_cond_broadcast(&port->condition);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
}
#endif
}
#define SendMsg(p, c, d) _SendMsg(p, c, d, __PRETTY_FUNCTION__, #p, #c)
#define WaitMsg(p, c, d) _WaitMsg(p, c, d, __PRETTY_FUNCTION__, #p)
#if 0
static void _Log(const char *msg)
{
int rc;
rc = pthread_mutex_lock(&logMutex);
if (rc)
ri.Printf(PRINT_ALL, "_Log: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
fputs(msg,stderr);
fflush(stderr);
rc = pthread_mutex_unlock(&logMutex);
if (rc)
ri.Printf(PRINT_ALL, "_Log: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
#endif
//
// The main Q3 SMP API
//
static void (*glimpRenderThread)( void ) = NULL;
static void *GLimp_RenderThreadWrapper(void *arg)
{
Com_Printf("Render thread starting\n");
glimpRenderThread();
#ifndef USE_CGLMACROS
// Unbind the context before we die
OSX_GLContextClearCurrent();
#endif
// Send one last message back to front end before we die...
// This is somewhat of a hack.. fixme.
if (rendererProcessingCommand) {
SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
rendererProcessingCommand = NO;
}
Com_Printf("Render thread terminating\n");
return arg;
}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
pthread_t renderThread;
int rc;
if (!portsInited) {
portsInited = YES;
MsgPortInit(&rendererMsgPort);
MsgPortInit(&frontEndMsgPort);
renderMsgOutstanding = NO;
rendererProcessingCommand = NO;
pthread_mutex_init(&logMutex, NULL);
}
glimpRenderThread = function;
rc = pthread_create(&renderThread,
NULL, // attributes
GLimp_RenderThreadWrapper,
NULL); // argument
if (rc) {
ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
return qfalse;
} else {
rc = pthread_detach(renderThread);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
}
}
return qtrue;
}
static volatile void *smpData;
// TJW - This is calling in the rendering thread to wait until another
// command buffer is ready. The command buffer returned might be NULL,
// indicating that the rendering thread should exit.
void *GLimp_RendererSleep(void)
{
//_Log(__PRETTY_FUNCTION__ " entered");
unsigned int msgCode;
void *msgData;
GLSTAMP("GLimp_RendererSleep start", 0);
#ifndef USE_CGLMACROS
// Clear the current context while we sleep so the main thread can access it
OSX_GLContextClearCurrent();
#endif
// Let the main thread we are idle and that no work is queued
//_Log("rs0\n");
/* If we actually had some work to do, then tell the front end we completed it. */
if (rendererProcessingCommand) {
SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
rendererProcessingCommand = NO;
}
// Wait for new msg
for (;;) {
WaitMsg(&rendererMsgPort, &msgCode, &msgData);
if (1 || msgCode == RenderCommandMsg) {
smpData = msgData;
break;
} else {
printf("renderer received unknown message: %d\n",msgCode);
}
}
#ifndef USE_CGLMACROS
// We are going to render a frame... retake the context
OSX_GLContextSetCurrent();
#endif
rendererProcessingCommand = YES;
GLSTAMP("GLimp_RendererSleep end", 0);
return (void *)smpData;
}
// TJW - This is from the main thread to wait until the rendering thread
// has completed the command buffer that it has
void GLimp_FrontEndSleep(void)
{
unsigned int msgCode;
void *msgData;
GLSTAMP("GLimp_FrontEndSleep start", 1);
if (renderMsgOutstanding) {
for (;;) {
WaitMsg(&frontEndMsgPort, &msgCode, &msgData);
if(1 || msgCode == RenderCompletedMsg) {
break;
} else {
printf("front end received unknown message: %d\n",msgCode);
}
}
renderMsgOutstanding = NO;
}
#ifndef USE_CGLMACROS
// We are done waiting for the background thread, take the current context back.
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_FrontEndSleep end", 1);
}
// TJW - This is called in the main thread to issue another command
// buffer to the rendering thread. This is always called AFTER
// GLimp_FrontEndSleep, so we know that there is no command
// pending in 'smpData'.
void GLimp_WakeRenderer( void *data )
{
GLSTAMP("GLimp_WakeRenderer start", 1);
#ifndef USE_CGLMACROS
// We want the background thread to draw stuff. Give up the current context
OSX_GLContextClearCurrent();
#endif
SendMsg(&rendererMsgPort, RenderCommandMsg, data);
// Don't set flag saying that the renderer is processing something if it's just
// being told to exit.
//if(data != NULL)
renderMsgOutstanding = YES;
GLSTAMP("GLimp_WakeRenderer end", 1);
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
#import "macosx_display.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <mach/mach.h>
#import <mach/mach_error.h>
#warning Using Mach Ports SMP acceleration implementation
/*
===========================================================
SMP acceleration
===========================================================
*/
#import <pthread.h>
#define USE_MACH_PORTS 1
// This is a small cover layer that makes for easier calling
typedef struct _MsgPort {
#if USE_MACH_PORTS
mach_port_t port;
id nsPort;
#else
pthread_mutex_t mutex;
pthread_cond_t condition;
volatile unsigned int status;
unsigned int msgCode;
void *msgData;
#endif
} MsgPort;
static BOOL portsInited = NO;
static pthread_mutex_t logMutex;
static unsigned int renderMsgOutstanding;
static unsigned int rendererProcessingCommand;
static MsgPort rendererMsgPort;
static MsgPort frontEndMsgPort;
enum {
MsgNone,
MsgPending,
};
enum {
MsgCodeInvalid = 0,
RenderCommandMsg = 1,
RenderCompletedMsg = 2,
};
static /*inline*/ void MsgPortInit(MsgPort *port)
{
#if USE_MACH_PORTS
port->nsPort = [[NSMachPort alloc] init];
port->port = [port->nsPort machPort];
//rc = mach_port_allocate(mach_task_self(), MACH_PORT_TYPE_SEND_RECEIVE, &port->port);
//if (rc) {
// fprintf(stderr, "MsgPortInit: mach_port_allocate returned: %d: %s \n",rc, mach_error_string(rc));
// }
#else
int rc;
rc = pthread_mutex_init(&port->mutex, NULL);
if (rc) {
ri.Printf(PRINT_ALL, "MsgPortInit: pthread_mutex_init returned: %d: %s\n", rc, strerror(rc));
}
rc = pthread_cond_init(&port->condition, NULL);
if (rc) {
ri.Printf(PRINT_ALL, "EventInit: pthread_cond_init returned %d: %s\n", rc, strerror(rc));
}
port->status = MsgNone;
port->msgCode = MsgCodeInvalid;
port->msgData = NULL;
#endif
}
static /*inline*/ void _SendMsg(MsgPort *port, unsigned int msgCode, void *msgData,
const char *functionName, const char *portName, const char *msgName)
{
int rc;
#if USE_MACH_PORTS
mach_msg_header_t msg;
//printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
/*
typedef struct
{
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_msg_size_t msgh_reserved;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
*/
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
msg.msgh_size=sizeof(msg);
//msg.msg_type=MSG_TYPE_NORMAL;
msg.msgh_local_port=MACH_PORT_NULL;
msg.msgh_remote_port=port->port;
msg.msgh_reserved = 0;
msg.msgh_id=(mach_msg_id_t)msgData; // HACK
rc = mach_msg_send(&msg);
if(rc) {
fprintf(stderr,"SendMsg: mach_msg_send returned %d: %s\n", rc, mach_error_string(rc));
}
#else
//printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
rc = pthread_mutex_lock(&port->mutex);
if(rc) {
fprintf(stderr,"SendMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
}
/* Block until port is empty */
while(port->status != MsgNone) {
//fprintf(stderr, "SendMsg: %s blocking until port %s is empty\n", functionName, portName);
rc = pthread_cond_wait(&port->condition, &port->mutex);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
}
}
/* Queue msg */
port->msgCode = msgCode;
port->msgData = msgData;
port->status = MsgPending;
/* Unlock port */
rc = pthread_mutex_unlock(&port->mutex);
if(rc) {
fprintf(stderr, "SendMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
/* Wake up any threads blocked waiting for a message */
rc = pthread_cond_broadcast(&port->condition);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
}
#endif
}
static /*inline*/ void _WaitMsg(MsgPort *port, unsigned int *msgCode, void **msgData,
const char *functionName, const char *portName)
{
int rc;
#if USE_MACH_PORTS
mach_msg_empty_rcv_t msg;
//printf("WaitMsg: %s %s\n",functionName, portName);
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
msg.header.msgh_size= sizeof(msg);
//msg.msg_type=MSG_TYPE_NORMAL;
msg.header.msgh_local_port=port->port;
msg.header.msgh_remote_port=MACH_PORT_NULL;
msg.header.msgh_reserved = 0;
msg.header.msgh_id=(mach_msg_id_t)msgData; // HACK
rc = mach_msg_receive(&msg.header);
if(rc) {
fprintf(stderr,"SendMsg: mach_msg_receive returned %d: %s\n", rc, mach_error_string(rc));
}
*msgData = (void *)msg.header.msgh_id;
//printf("WaitMsg: %s %s got %08lx\n",functionName, portName, *msgData);
#else
//printf("WaitMsg: %s %s\n",functionName, portName);
rc = pthread_mutex_lock(&port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
}
/* Block until port is empty */
while(port->status != MsgPending) {
rc = pthread_cond_wait(&port->condition, &port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
}
}
/* Remove msg */
*msgCode = port->msgCode;
*msgData = port->msgData;
//printf("WaitMsg: %s %s got %d %08lx\n",functionName, portName, *msgCode, *msgData);
port->status = MsgNone;
port->msgCode = 0;
port->msgData = NULL;
rc = pthread_mutex_unlock(&port->mutex);
if(rc) {
fprintf(stderr, "WaitMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
/* Wake up any threads blocked waiting for port to be empty. */
rc = pthread_cond_broadcast(&port->condition);
if(rc) {
fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
}
#endif
}
#define SendMsg(p, c, d) _SendMsg(p, c, d, __PRETTY_FUNCTION__, #p, #c)
#define WaitMsg(p, c, d) _WaitMsg(p, c, d, __PRETTY_FUNCTION__, #p)
#if 0
static void _Log(const char *msg)
{
int rc;
rc = pthread_mutex_lock(&logMutex);
if (rc)
ri.Printf(PRINT_ALL, "_Log: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
fputs(msg,stderr);
fflush(stderr);
rc = pthread_mutex_unlock(&logMutex);
if (rc)
ri.Printf(PRINT_ALL, "_Log: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
}
#endif
//
// The main Q3 SMP API
//
static void (*glimpRenderThread)( void ) = NULL;
static void *GLimp_RenderThreadWrapper(void *arg)
{
Com_Printf("Render thread starting\n");
glimpRenderThread();
#ifndef USE_CGLMACROS
// Unbind the context before we die
OSX_GLContextClearCurrent();
#endif
// Send one last message back to front end before we die...
// This is somewhat of a hack.. fixme.
if (rendererProcessingCommand) {
SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
rendererProcessingCommand = NO;
}
Com_Printf("Render thread terminating\n");
return arg;
}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
pthread_t renderThread;
int rc;
if (!portsInited) {
portsInited = YES;
MsgPortInit(&rendererMsgPort);
MsgPortInit(&frontEndMsgPort);
renderMsgOutstanding = NO;
rendererProcessingCommand = NO;
pthread_mutex_init(&logMutex, NULL);
}
glimpRenderThread = function;
rc = pthread_create(&renderThread,
NULL, // attributes
GLimp_RenderThreadWrapper,
NULL); // argument
if (rc) {
ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
return qfalse;
} else {
rc = pthread_detach(renderThread);
if (rc) {
ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
}
}
return qtrue;
}
static volatile void *smpData;
// TJW - This is calling in the rendering thread to wait until another
// command buffer is ready. The command buffer returned might be NULL,
// indicating that the rendering thread should exit.
void *GLimp_RendererSleep(void)
{
//_Log(__PRETTY_FUNCTION__ " entered");
unsigned int msgCode;
void *msgData;
GLSTAMP("GLimp_RendererSleep start", 0);
#ifndef USE_CGLMACROS
// Clear the current context while we sleep so the main thread can access it
OSX_GLContextClearCurrent();
#endif
// Let the main thread we are idle and that no work is queued
//_Log("rs0\n");
/* If we actually had some work to do, then tell the front end we completed it. */
if (rendererProcessingCommand) {
SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
rendererProcessingCommand = NO;
}
// Wait for new msg
for (;;) {
WaitMsg(&rendererMsgPort, &msgCode, &msgData);
if (1 || msgCode == RenderCommandMsg) {
smpData = msgData;
break;
} else {
printf("renderer received unknown message: %d\n",msgCode);
}
}
#ifndef USE_CGLMACROS
// We are going to render a frame... retake the context
OSX_GLContextSetCurrent();
#endif
rendererProcessingCommand = YES;
GLSTAMP("GLimp_RendererSleep end", 0);
return (void *)smpData;
}
// TJW - This is from the main thread to wait until the rendering thread
// has completed the command buffer that it has
void GLimp_FrontEndSleep(void)
{
unsigned int msgCode;
void *msgData;
GLSTAMP("GLimp_FrontEndSleep start", 1);
if (renderMsgOutstanding) {
for (;;) {
WaitMsg(&frontEndMsgPort, &msgCode, &msgData);
if(1 || msgCode == RenderCompletedMsg) {
break;
} else {
printf("front end received unknown message: %d\n",msgCode);
}
}
renderMsgOutstanding = NO;
}
#ifndef USE_CGLMACROS
// We are done waiting for the background thread, take the current context back.
OSX_GLContextSetCurrent();
#endif
GLSTAMP("GLimp_FrontEndSleep end", 1);
}
// TJW - This is called in the main thread to issue another command
// buffer to the rendering thread. This is always called AFTER
// GLimp_FrontEndSleep, so we know that there is no command
// pending in 'smpData'.
void GLimp_WakeRenderer( void *data )
{
GLSTAMP("GLimp_WakeRenderer start", 1);
#ifndef USE_CGLMACROS
// We want the background thread to draw stuff. Give up the current context
OSX_GLContextClearCurrent();
#endif
SendMsg(&rendererMsgPort, RenderCommandMsg, data);
// Don't set flag saying that the renderer is processing something if it's just
// being told to exit.
//if(data != NULL)
renderMsgOutstanding = YES;
GLSTAMP("GLimp_WakeRenderer end", 1);
}

1832
code/macosx/macosx_input.m Normal file → Executable file

File diff suppressed because it is too large Load diff

258
code/macosx/macosx_local.h Normal file → Executable file
View file

@ -1,129 +1,129 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __macosx_local_h
#define __macosx_local_h
#include "qcommon.h"
#ifdef __cplusplus
typedef void NSDictionary;
typedef void NSOpenGLContext;
typedef void NSWindow;
extern "C" {
#else
#import <Foundation/NSGeometry.h>
@class NSEvent, NSOpenGLContext, NSWindow;
#endif
#include <ApplicationServices/ApplicationServices.h>
#include <OpenGL/CGLTypes.h>
// In macosx_input.m
extern void Sys_InitInput(void);
extern void Sys_ShutdownInput(void);
extern void Sys_SetMouseInputRect(CGRect newRect);
extern CGDirectDisplayID Sys_DisplayToUse(void);
// In macosx_sys.m
extern void Sys_QueEvent(int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr);
extern void Sys_AnnoyingBanner();
// In macosx_glimp.m
extern qboolean Sys_IsHidden;
extern qboolean Sys_Hide();
extern qboolean Sys_Unhide();
typedef struct {
CGDirectDisplayID display;
CGTableCount tableSize;
CGGammaValue *red;
CGGammaValue *blue;
CGGammaValue *green;
} glwgamma_t;
typedef struct
{
CGDirectDisplayID display;
NSDictionary *desktopMode;
NSDictionary *gameMode;
CGDisplayCount displayCount;
glwgamma_t *originalDisplayGammaTables;
glwgamma_t inGameTable;
glwgamma_t tempTable;
NSOpenGLContext *_ctx;
CGLContextObj _cgl_ctx;
qboolean _ctx_is_current;
NSWindow *window;
FILE *log_fp;
unsigned int bufferSwapCount;
unsigned int glPauseCount;
} glwstate_t;
extern glwstate_t glw_state;
#define OSX_SetGLContext(context) \
do { \
NSOpenGLContext *_context = (context); \
glw_state._ctx = _context; \
glw_state._cgl_ctx = [_context cglContext]; \
} while (0)
#define OSX_GetNSGLContext() glw_state._ctx
#define OSX_GetCGLContext() glw_state._cgl_ctx
#define OSX_GLContextIsCurrent() glw_state._ctx_is_current
#define OSX_GLContextSetCurrent() \
do { \
[glw_state._ctx makeCurrentContext]; \
glw_state._ctx_is_current = (glw_state._ctx != nil); \
} while (0)
#define OSX_GLContextClearCurrent() \
do { \
[NSOpenGLContext clearCurrentContext]; \
glw_state._ctx_is_current = NO; \
} while (0)
extern void Sys_PauseGL();
extern void Sys_ResumeGL();
#import "macosx_timers.h"
#ifdef OMNI_TIMER
extern OTStampList glThreadStampList;
#define GLSTAMP(name, data) OTStampListAddStamp(glThreadStampList, name, data)
#else
#define GLSTAMP(name, data)
#endif
#ifdef __cplusplus
}
#endif
#endif // __macosx_local_h
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __macosx_local_h
#define __macosx_local_h
#include "qcommon.h"
#ifdef __cplusplus
typedef void NSDictionary;
typedef void NSOpenGLContext;
typedef void NSWindow;
extern "C" {
#else
#import <Foundation/NSGeometry.h>
@class NSEvent, NSOpenGLContext, NSWindow;
#endif
#include <ApplicationServices/ApplicationServices.h>
#include <OpenGL/CGLTypes.h>
// In macosx_input.m
extern void Sys_InitInput(void);
extern void Sys_ShutdownInput(void);
extern void Sys_SetMouseInputRect(CGRect newRect);
extern CGDirectDisplayID Sys_DisplayToUse(void);
// In macosx_sys.m
extern void Sys_QueEvent(int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr);
extern void Sys_AnnoyingBanner();
// In macosx_glimp.m
extern qboolean Sys_IsHidden;
extern qboolean Sys_Hide();
extern qboolean Sys_Unhide();
typedef struct {
CGDirectDisplayID display;
CGTableCount tableSize;
CGGammaValue *red;
CGGammaValue *blue;
CGGammaValue *green;
} glwgamma_t;
typedef struct
{
CGDirectDisplayID display;
NSDictionary *desktopMode;
NSDictionary *gameMode;
CGDisplayCount displayCount;
glwgamma_t *originalDisplayGammaTables;
glwgamma_t inGameTable;
glwgamma_t tempTable;
NSOpenGLContext *_ctx;
CGLContextObj _cgl_ctx;
qboolean _ctx_is_current;
NSWindow *window;
FILE *log_fp;
unsigned int bufferSwapCount;
unsigned int glPauseCount;
} glwstate_t;
extern glwstate_t glw_state;
#define OSX_SetGLContext(context) \
do { \
NSOpenGLContext *_context = (context); \
glw_state._ctx = _context; \
glw_state._cgl_ctx = [_context cglContext]; \
} while (0)
#define OSX_GetNSGLContext() glw_state._ctx
#define OSX_GetCGLContext() glw_state._cgl_ctx
#define OSX_GLContextIsCurrent() glw_state._ctx_is_current
#define OSX_GLContextSetCurrent() \
do { \
[glw_state._ctx makeCurrentContext]; \
glw_state._ctx_is_current = (glw_state._ctx != nil); \
} while (0)
#define OSX_GLContextClearCurrent() \
do { \
[NSOpenGLContext clearCurrentContext]; \
glw_state._ctx_is_current = NO; \
} while (0)
extern void Sys_PauseGL();
extern void Sys_ResumeGL();
#import "macosx_timers.h"
#ifdef OMNI_TIMER
extern OTStampList glThreadStampList;
#define GLSTAMP(name, data) OTStampListAddStamp(glThreadStampList, name, data)
#else
#define GLSTAMP(name, data)
#endif
#ifdef __cplusplus
}
#endif
#endif // __macosx_local_h

10190
code/macosx/macosx_qgl.h Normal file → Executable file

File diff suppressed because it is too large Load diff

650
code/macosx/macosx_sndcore.m Normal file → Executable file
View file

@ -1,325 +1,325 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mac_snddma.c
// all other sound mixing is portable
#include "../client/snd_local.h"
#include <CoreServices/CoreServices.h>
#include <CoreAudio/AudioHardware.h>
#include <QuickTime/QuickTime.h>
// For 'ri'
#include "../renderer/tr_local.h"
#import <Foundation/NSData.h>
#import <Foundation/NSString.h>
static unsigned int submissionChunk;
static unsigned int maxMixedSamples;
static short *s_mixedSamples;
static int s_chunkCount; // number of chunks submitted
static qboolean s_isRunning;
static AudioDeviceID outputDeviceID;
static AudioStreamBasicDescription outputStreamBasicDescription;
/*
===============
audioDeviceIOProc
===============
*/
OSStatus audioDeviceIOProc(AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
const AudioBufferList *inInputData,
const AudioTimeStamp *inInputTime,
AudioBufferList *outOutputData,
const AudioTimeStamp *inOutputTime,
void *inClientData)
{
int offset;
short *samples;
unsigned int sampleIndex;
float *outBuffer;
float scale, temp;
offset = ( s_chunkCount * submissionChunk ) % maxMixedSamples;
samples = s_mixedSamples + offset;
assert(outOutputData->mNumberBuffers == 1);
assert(outOutputData->mBuffers[0].mNumberChannels == 2);
//assert(outOutputData->mBuffers[0].mDataByteSize == (dma.submission_chunk * sizeof(float)));
outBuffer = (float *)outOutputData->mBuffers[0].mData;
// If we have run out of samples, return silence
if (s_chunkCount * submissionChunk > dma.channels * s_paintedtime) {
memset(outBuffer, 0, sizeof(*outBuffer) * dma.submission_chunk);
} else {
scale = (1.0f / SHRT_MAX);
if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 22050) {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=2) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
temp = samples[sampleIndex + 0] * scale;
outBuffer[(sampleIndex<<1)+0] = temp;
outBuffer[(sampleIndex<<1)+2] = temp;
temp = samples[sampleIndex + 1] * scale;
outBuffer[(sampleIndex<<1)+1] = temp;
outBuffer[(sampleIndex<<1)+3] = temp;
}
} else if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 11025) {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=4) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
temp = samples[sampleIndex + 0] * scale;
outBuffer[(sampleIndex<<1)+0] = temp;
outBuffer[(sampleIndex<<1)+2] = temp;
outBuffer[(sampleIndex<<1)+4] = temp;
outBuffer[(sampleIndex<<1)+6] = temp;
temp = samples[sampleIndex + 1] * scale;
outBuffer[(sampleIndex<<1)+1] = temp;
outBuffer[(sampleIndex<<1)+3] = temp;
outBuffer[(sampleIndex<<1)+5] = temp;
outBuffer[(sampleIndex<<1)+7] = temp;
}
} else {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex++) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
outBuffer[sampleIndex] = samples[sampleIndex] * scale;
}
}
}
s_chunkCount++; // this is the next buffer we will submit
return 0;
}
/*
===============
S_MakeTestPattern
===============
*/
void S_MakeTestPattern( void ) {
int i;
float v;
int sample;
for ( i = 0 ; i < dma.samples / 2 ; i ++ ) {
v = sin( M_PI * 2 * i / 64 );
sample = v * 0x4000;
((short *)dma.buffer)[i*2] = sample;
((short *)dma.buffer)[i*2+1] = sample;
}
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
cvar_t *bufferSize;
cvar_t *chunkSize;
OSStatus status;
UInt32 propertySize, bufferByteCount;
if (s_isRunning)
return qtrue;
chunkSize = ri.Cvar_Get( "s_chunksize", "2048", CVAR_ARCHIVE );
bufferSize = ri.Cvar_Get( "s_buffersize", "16384", CVAR_ARCHIVE );
Com_Printf(" Chunk size = %d\n", chunkSize->integer);
Com_Printf("Buffer size = %d\n", bufferSize->integer);
if (!chunkSize->integer)
ri.Error(ERR_FATAL, "s_chunksize must be non-zero\n");
if (!bufferSize->integer)
ri.Error(ERR_FATAL, "s_buffersize must be non-zero\n");
if (chunkSize->integer >= bufferSize->integer)
ri.Error(ERR_FATAL, "s_chunksize must be less than s_buffersize\n");
if (bufferSize->integer % chunkSize->integer)
ri.Error(ERR_FATAL, "s_buffersize must be an even multiple of s_chunksize\n");
// Get the output device
propertySize = sizeof(outputDeviceID);
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &outputDeviceID);
if (status) {
Com_Printf("AudioHardwareGetProperty returned %d\n", status);
return qfalse;
}
if (outputDeviceID == kAudioDeviceUnknown) {
Com_Printf("AudioHardwareGetProperty: outputDeviceID is kAudioDeviceUnknown\n");
return qfalse;
}
// Configure the output device
propertySize = sizeof(bufferByteCount);
bufferByteCount = chunkSize->integer * sizeof(float);
status = AudioDeviceSetProperty(outputDeviceID, NULL, 0, NO, kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount);
if (status) {
Com_Printf("AudioDeviceSetProperty: returned %d when setting kAudioDevicePropertyBufferSize to %d\n", status, chunkSize->integer);
return qfalse;
}
propertySize = sizeof(bufferByteCount);
status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyBufferSize, &propertySize, &bufferByteCount);
if (status) {
Com_Printf("AudioDeviceGetProperty: returned %d when setting kAudioDevicePropertyBufferSize\n", status);
return qfalse;
}
// Print out the device status
propertySize = sizeof(outputStreamBasicDescription);
status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyStreamFormat, &propertySize, &outputStreamBasicDescription);
if (status) {
Com_Printf("AudioDeviceGetProperty: returned %d when getting kAudioDevicePropertyStreamFormat\n", status);
return qfalse;
}
Com_Printf("Hardware format:\n");
Com_Printf(" %f mSampleRate\n", outputStreamBasicDescription.mSampleRate);
Com_Printf(" %c%c%c%c mFormatID\n",
(outputStreamBasicDescription.mFormatID & 0xff000000) >> 24,
(outputStreamBasicDescription.mFormatID & 0x00ff0000) >> 16,
(outputStreamBasicDescription.mFormatID & 0x0000ff00) >> 8,
(outputStreamBasicDescription.mFormatID & 0x000000ff) >> 0);
Com_Printf(" %5d mBytesPerPacket\n", outputStreamBasicDescription.mBytesPerPacket);
Com_Printf(" %5d mFramesPerPacket\n", outputStreamBasicDescription.mFramesPerPacket);
Com_Printf(" %5d mBytesPerFrame\n", outputStreamBasicDescription.mBytesPerFrame);
Com_Printf(" %5d mChannelsPerFrame\n", outputStreamBasicDescription.mChannelsPerFrame);
Com_Printf(" %5d mBitsPerChannel\n", outputStreamBasicDescription.mBitsPerChannel);
if(outputStreamBasicDescription.mFormatID != kAudioFormatLinearPCM) {
Com_Printf("Default Audio Device doesn't support Linear PCM!");
return qfalse;
}
// Start sound running
status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL);
if (status) {
Com_Printf("AudioDeviceAddIOProc: returned %d\n", status);
return qfalse;
}
submissionChunk = chunkSize->integer;
if (outputStreamBasicDescription.mSampleRate == 44100) {
submissionChunk = chunkSize->integer/2;
}
maxMixedSamples = bufferSize->integer;
s_mixedSamples = calloc(1, sizeof(*s_mixedSamples) * maxMixedSamples);
Com_Printf("Chunk Count = %d\n", (maxMixedSamples / submissionChunk));
// Tell the main app what we expect from it
dma.samples = maxMixedSamples;
dma.submission_chunk = submissionChunk;
dma.samplebits = 16;
dma.buffer = (byte *)s_mixedSamples;
dma.channels = outputStreamBasicDescription.mChannelsPerFrame;
dma.speed = 22050; //(unsigned long)outputStreamBasicDescription.mSampleRate;
// We haven't enqueued anything yet
s_chunkCount = 0;
status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceStart: returned %d\n", status);
return qfalse;
}
s_isRunning = qtrue;
return qtrue;
}
/*
===============
SNDDMA_GetBufferDuration
===============
*/
float SNDDMA_GetBufferDuration(void)
{
return (float)dma.samples / (float)(dma.channels * dma.speed);
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void)
{
return s_chunkCount * dma.submission_chunk;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void)
{
OSStatus status;
if (!s_isRunning)
return;
status = AudioDeviceStop(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceStop: returned %d\n", status);
return;
}
s_isRunning = qfalse;
status = AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceRemoveIOProc: returned %d\n", status);
return;
}
free(s_mixedSamples);
s_mixedSamples = NULL;
dma.samples = NULL;
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting(void) {
}
/*
===============
SNDDMA_Submit
===============
*/
void SNDDMA_Submit(void) {
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mac_snddma.c
// all other sound mixing is portable
#include "../client/snd_local.h"
#include <CoreServices/CoreServices.h>
#include <CoreAudio/AudioHardware.h>
#include <QuickTime/QuickTime.h>
// For 'ri'
#include "../renderer/tr_local.h"
#import <Foundation/NSData.h>
#import <Foundation/NSString.h>
static unsigned int submissionChunk;
static unsigned int maxMixedSamples;
static short *s_mixedSamples;
static int s_chunkCount; // number of chunks submitted
static qboolean s_isRunning;
static AudioDeviceID outputDeviceID;
static AudioStreamBasicDescription outputStreamBasicDescription;
/*
===============
audioDeviceIOProc
===============
*/
OSStatus audioDeviceIOProc(AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
const AudioBufferList *inInputData,
const AudioTimeStamp *inInputTime,
AudioBufferList *outOutputData,
const AudioTimeStamp *inOutputTime,
void *inClientData)
{
int offset;
short *samples;
unsigned int sampleIndex;
float *outBuffer;
float scale, temp;
offset = ( s_chunkCount * submissionChunk ) % maxMixedSamples;
samples = s_mixedSamples + offset;
assert(outOutputData->mNumberBuffers == 1);
assert(outOutputData->mBuffers[0].mNumberChannels == 2);
//assert(outOutputData->mBuffers[0].mDataByteSize == (dma.submission_chunk * sizeof(float)));
outBuffer = (float *)outOutputData->mBuffers[0].mData;
// If we have run out of samples, return silence
if (s_chunkCount * submissionChunk > dma.channels * s_paintedtime) {
memset(outBuffer, 0, sizeof(*outBuffer) * dma.submission_chunk);
} else {
scale = (1.0f / SHRT_MAX);
if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 22050) {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=2) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
temp = samples[sampleIndex + 0] * scale;
outBuffer[(sampleIndex<<1)+0] = temp;
outBuffer[(sampleIndex<<1)+2] = temp;
temp = samples[sampleIndex + 1] * scale;
outBuffer[(sampleIndex<<1)+1] = temp;
outBuffer[(sampleIndex<<1)+3] = temp;
}
} else if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 11025) {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=4) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
temp = samples[sampleIndex + 0] * scale;
outBuffer[(sampleIndex<<1)+0] = temp;
outBuffer[(sampleIndex<<1)+2] = temp;
outBuffer[(sampleIndex<<1)+4] = temp;
outBuffer[(sampleIndex<<1)+6] = temp;
temp = samples[sampleIndex + 1] * scale;
outBuffer[(sampleIndex<<1)+1] = temp;
outBuffer[(sampleIndex<<1)+3] = temp;
outBuffer[(sampleIndex<<1)+5] = temp;
outBuffer[(sampleIndex<<1)+7] = temp;
}
} else {
for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex++) {
// Convert the samples from shorts to floats. Scale the floats to be [-1..1].
outBuffer[sampleIndex] = samples[sampleIndex] * scale;
}
}
}
s_chunkCount++; // this is the next buffer we will submit
return 0;
}
/*
===============
S_MakeTestPattern
===============
*/
void S_MakeTestPattern( void ) {
int i;
float v;
int sample;
for ( i = 0 ; i < dma.samples / 2 ; i ++ ) {
v = sin( M_PI * 2 * i / 64 );
sample = v * 0x4000;
((short *)dma.buffer)[i*2] = sample;
((short *)dma.buffer)[i*2+1] = sample;
}
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
cvar_t *bufferSize;
cvar_t *chunkSize;
OSStatus status;
UInt32 propertySize, bufferByteCount;
if (s_isRunning)
return qtrue;
chunkSize = ri.Cvar_Get( "s_chunksize", "2048", CVAR_ARCHIVE );
bufferSize = ri.Cvar_Get( "s_buffersize", "16384", CVAR_ARCHIVE );
Com_Printf(" Chunk size = %d\n", chunkSize->integer);
Com_Printf("Buffer size = %d\n", bufferSize->integer);
if (!chunkSize->integer)
ri.Error(ERR_FATAL, "s_chunksize must be non-zero\n");
if (!bufferSize->integer)
ri.Error(ERR_FATAL, "s_buffersize must be non-zero\n");
if (chunkSize->integer >= bufferSize->integer)
ri.Error(ERR_FATAL, "s_chunksize must be less than s_buffersize\n");
if (bufferSize->integer % chunkSize->integer)
ri.Error(ERR_FATAL, "s_buffersize must be an even multiple of s_chunksize\n");
// Get the output device
propertySize = sizeof(outputDeviceID);
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &outputDeviceID);
if (status) {
Com_Printf("AudioHardwareGetProperty returned %d\n", status);
return qfalse;
}
if (outputDeviceID == kAudioDeviceUnknown) {
Com_Printf("AudioHardwareGetProperty: outputDeviceID is kAudioDeviceUnknown\n");
return qfalse;
}
// Configure the output device
propertySize = sizeof(bufferByteCount);
bufferByteCount = chunkSize->integer * sizeof(float);
status = AudioDeviceSetProperty(outputDeviceID, NULL, 0, NO, kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount);
if (status) {
Com_Printf("AudioDeviceSetProperty: returned %d when setting kAudioDevicePropertyBufferSize to %d\n", status, chunkSize->integer);
return qfalse;
}
propertySize = sizeof(bufferByteCount);
status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyBufferSize, &propertySize, &bufferByteCount);
if (status) {
Com_Printf("AudioDeviceGetProperty: returned %d when setting kAudioDevicePropertyBufferSize\n", status);
return qfalse;
}
// Print out the device status
propertySize = sizeof(outputStreamBasicDescription);
status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyStreamFormat, &propertySize, &outputStreamBasicDescription);
if (status) {
Com_Printf("AudioDeviceGetProperty: returned %d when getting kAudioDevicePropertyStreamFormat\n", status);
return qfalse;
}
Com_Printf("Hardware format:\n");
Com_Printf(" %f mSampleRate\n", outputStreamBasicDescription.mSampleRate);
Com_Printf(" %c%c%c%c mFormatID\n",
(outputStreamBasicDescription.mFormatID & 0xff000000) >> 24,
(outputStreamBasicDescription.mFormatID & 0x00ff0000) >> 16,
(outputStreamBasicDescription.mFormatID & 0x0000ff00) >> 8,
(outputStreamBasicDescription.mFormatID & 0x000000ff) >> 0);
Com_Printf(" %5d mBytesPerPacket\n", outputStreamBasicDescription.mBytesPerPacket);
Com_Printf(" %5d mFramesPerPacket\n", outputStreamBasicDescription.mFramesPerPacket);
Com_Printf(" %5d mBytesPerFrame\n", outputStreamBasicDescription.mBytesPerFrame);
Com_Printf(" %5d mChannelsPerFrame\n", outputStreamBasicDescription.mChannelsPerFrame);
Com_Printf(" %5d mBitsPerChannel\n", outputStreamBasicDescription.mBitsPerChannel);
if(outputStreamBasicDescription.mFormatID != kAudioFormatLinearPCM) {
Com_Printf("Default Audio Device doesn't support Linear PCM!");
return qfalse;
}
// Start sound running
status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL);
if (status) {
Com_Printf("AudioDeviceAddIOProc: returned %d\n", status);
return qfalse;
}
submissionChunk = chunkSize->integer;
if (outputStreamBasicDescription.mSampleRate == 44100) {
submissionChunk = chunkSize->integer/2;
}
maxMixedSamples = bufferSize->integer;
s_mixedSamples = calloc(1, sizeof(*s_mixedSamples) * maxMixedSamples);
Com_Printf("Chunk Count = %d\n", (maxMixedSamples / submissionChunk));
// Tell the main app what we expect from it
dma.samples = maxMixedSamples;
dma.submission_chunk = submissionChunk;
dma.samplebits = 16;
dma.buffer = (byte *)s_mixedSamples;
dma.channels = outputStreamBasicDescription.mChannelsPerFrame;
dma.speed = 22050; //(unsigned long)outputStreamBasicDescription.mSampleRate;
// We haven't enqueued anything yet
s_chunkCount = 0;
status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceStart: returned %d\n", status);
return qfalse;
}
s_isRunning = qtrue;
return qtrue;
}
/*
===============
SNDDMA_GetBufferDuration
===============
*/
float SNDDMA_GetBufferDuration(void)
{
return (float)dma.samples / (float)(dma.channels * dma.speed);
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void)
{
return s_chunkCount * dma.submission_chunk;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void)
{
OSStatus status;
if (!s_isRunning)
return;
status = AudioDeviceStop(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceStop: returned %d\n", status);
return;
}
s_isRunning = qfalse;
status = AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
if (status) {
Com_Printf("AudioDeviceRemoveIOProc: returned %d\n", status);
return;
}
free(s_mixedSamples);
s_mixedSamples = NULL;
dma.samples = NULL;
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting(void) {
}
/*
===============
SNDDMA_Submit
===============
*/
void SNDDMA_Submit(void) {
}

410
code/macosx/macosx_snddma.m Normal file → Executable file
View file

@ -1,205 +1,205 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mac_snddma.c
// all other sound mixing is portable
#include "../client/snd_local.h"
#include <Carbon/Carbon.h>
// For 'ri'
#include "../renderer/tr_local.h"
#import <Foundation/NSZone.h>
// TJW - Different versions of SoundManager have different DMA buffer sizes. On MacOS X DP2,
// the buffer size is 8K. On MacOS 9 it is much smaller. The SoundManager guy at Apple says
// that the size of the buffer will be decreasing for final release to help get rid of latency.
//#define MAX_MIXED_SAMPLES (0x8000 * 64)
//#define SUBMISSION_CHUNK (0x100 * 64)
// Original MacOS 9 sizes
//#define MAX_MIXED_SAMPLES 0x8000
//#define SUBMISSION_CHUNK 0x100
static unsigned int submissionChunk;
static unsigned int maxMixedSamples;
static short *s_mixedSamples;
static int s_chunkCount; // number of chunks submitted
static SndChannel *s_sndChan;
static ExtSoundHeader s_sndHeader;
/*
===============
S_Callback
===============
*/
void S_Callback( SndChannel *sc, SndCommand *cmd )
{
SndCommand mySndCmd;
SndCommand mySndCmd2;
int offset;
offset = ( s_chunkCount * submissionChunk ) & (maxMixedSamples-1);
// queue up another sound buffer
memset( &s_sndHeader, 0, sizeof( s_sndHeader ) );
s_sndHeader.samplePtr = (void *)(s_mixedSamples + offset);
s_sndHeader.numChannels = 2;
s_sndHeader.sampleRate = rate22khz;
s_sndHeader.loopStart = 0;
s_sndHeader.loopEnd = 0;
s_sndHeader.encode = extSH;
s_sndHeader.baseFrequency = 1;
s_sndHeader.numFrames = submissionChunk / 2;
s_sndHeader.markerChunk = NULL;
s_sndHeader.instrumentChunks = NULL;
s_sndHeader.AESRecording = NULL;
s_sndHeader.sampleSize = 16;
mySndCmd.cmd = bufferCmd;
mySndCmd.param1 = 0;
mySndCmd.param2 = (int)&s_sndHeader;
SndDoCommand( sc, &mySndCmd, true );
// and another callback
mySndCmd2.cmd = callBackCmd;
mySndCmd2.param1 = 0;
mySndCmd2.param2 = 0;
SndDoCommand( sc, &mySndCmd2, true );
s_chunkCount++; // this is the next buffer we will submit
}
/*
===============
S_MakeTestPattern
===============
*/
void S_MakeTestPattern( void ) {
int i;
float v;
int sample;
for ( i = 0 ; i < dma.samples / 2 ; i ++ ) {
v = sin( M_PI * 2 * i / 64 );
sample = v * 0x4000;
((short *)dma.buffer)[i*2] = sample;
((short *)dma.buffer)[i*2+1] = sample;
}
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
int err;
cvar_t *bufferSize;
cvar_t *chunkSize;
chunkSize = ri.Cvar_Get( "s_chunksize", "8192", CVAR_ARCHIVE );
bufferSize = ri.Cvar_Get( "s_buffersize", "65536", CVAR_ARCHIVE );
if (!chunkSize->integer) {
ri.Error(ERR_FATAL, "snd_chunkSize must be non-zero\n");
}
if (!bufferSize->integer) {
ri.Error(ERR_FATAL, "snd_bufferSize must be non-zero\n");
}
if (chunkSize->integer >= bufferSize->integer) {
ri.Error(ERR_FATAL, "snd_chunkSize must be less than snd_bufferSize\n");
}
if (bufferSize->integer % chunkSize->integer) {
ri.Error(ERR_FATAL, "snd_bufferSize must be an even multiple of snd_chunkSize\n");
}
// create a sound channel
s_sndChan = NULL;
err = SndNewChannel( &s_sndChan, sampledSynth, initStereo, NewSndCallBackProc(S_Callback) );
if ( err ) {
return false;
}
submissionChunk = chunkSize->integer;
maxMixedSamples = bufferSize->integer;
s_mixedSamples = NSZoneMalloc(NULL, sizeof(*s_mixedSamples) * maxMixedSamples);
dma.channels = 2;
dma.samples = maxMixedSamples;
dma.submission_chunk = submissionChunk;
dma.samplebits = 16;
dma.speed = 22050;
dma.buffer = (byte *)s_mixedSamples;
// que up the first submission-chunk sized buffer
s_chunkCount = 0;
S_Callback( s_sndChan, NULL );
return qtrue;
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void) {
return s_chunkCount * submissionChunk;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void) {
if ( s_sndChan ) {
SndDisposeChannel( s_sndChan, true );
s_sndChan = NULL;
}
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting(void) {
}
/*
===============
SNDDMA_Submit
===============
*/
void SNDDMA_Submit(void) {
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mac_snddma.c
// all other sound mixing is portable
#include "../client/snd_local.h"
#include <Carbon/Carbon.h>
// For 'ri'
#include "../renderer/tr_local.h"
#import <Foundation/NSZone.h>
// TJW - Different versions of SoundManager have different DMA buffer sizes. On MacOS X DP2,
// the buffer size is 8K. On MacOS 9 it is much smaller. The SoundManager guy at Apple says
// that the size of the buffer will be decreasing for final release to help get rid of latency.
//#define MAX_MIXED_SAMPLES (0x8000 * 64)
//#define SUBMISSION_CHUNK (0x100 * 64)
// Original MacOS 9 sizes
//#define MAX_MIXED_SAMPLES 0x8000
//#define SUBMISSION_CHUNK 0x100
static unsigned int submissionChunk;
static unsigned int maxMixedSamples;
static short *s_mixedSamples;
static int s_chunkCount; // number of chunks submitted
static SndChannel *s_sndChan;
static ExtSoundHeader s_sndHeader;
/*
===============
S_Callback
===============
*/
void S_Callback( SndChannel *sc, SndCommand *cmd )
{
SndCommand mySndCmd;
SndCommand mySndCmd2;
int offset;
offset = ( s_chunkCount * submissionChunk ) & (maxMixedSamples-1);
// queue up another sound buffer
memset( &s_sndHeader, 0, sizeof( s_sndHeader ) );
s_sndHeader.samplePtr = (void *)(s_mixedSamples + offset);
s_sndHeader.numChannels = 2;
s_sndHeader.sampleRate = rate22khz;
s_sndHeader.loopStart = 0;
s_sndHeader.loopEnd = 0;
s_sndHeader.encode = extSH;
s_sndHeader.baseFrequency = 1;
s_sndHeader.numFrames = submissionChunk / 2;
s_sndHeader.markerChunk = NULL;
s_sndHeader.instrumentChunks = NULL;
s_sndHeader.AESRecording = NULL;
s_sndHeader.sampleSize = 16;
mySndCmd.cmd = bufferCmd;
mySndCmd.param1 = 0;
mySndCmd.param2 = (int)&s_sndHeader;
SndDoCommand( sc, &mySndCmd, true );
// and another callback
mySndCmd2.cmd = callBackCmd;
mySndCmd2.param1 = 0;
mySndCmd2.param2 = 0;
SndDoCommand( sc, &mySndCmd2, true );
s_chunkCount++; // this is the next buffer we will submit
}
/*
===============
S_MakeTestPattern
===============
*/
void S_MakeTestPattern( void ) {
int i;
float v;
int sample;
for ( i = 0 ; i < dma.samples / 2 ; i ++ ) {
v = sin( M_PI * 2 * i / 64 );
sample = v * 0x4000;
((short *)dma.buffer)[i*2] = sample;
((short *)dma.buffer)[i*2+1] = sample;
}
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
int err;
cvar_t *bufferSize;
cvar_t *chunkSize;
chunkSize = ri.Cvar_Get( "s_chunksize", "8192", CVAR_ARCHIVE );
bufferSize = ri.Cvar_Get( "s_buffersize", "65536", CVAR_ARCHIVE );
if (!chunkSize->integer) {
ri.Error(ERR_FATAL, "snd_chunkSize must be non-zero\n");
}
if (!bufferSize->integer) {
ri.Error(ERR_FATAL, "snd_bufferSize must be non-zero\n");
}
if (chunkSize->integer >= bufferSize->integer) {
ri.Error(ERR_FATAL, "snd_chunkSize must be less than snd_bufferSize\n");
}
if (bufferSize->integer % chunkSize->integer) {
ri.Error(ERR_FATAL, "snd_bufferSize must be an even multiple of snd_chunkSize\n");
}
// create a sound channel
s_sndChan = NULL;
err = SndNewChannel( &s_sndChan, sampledSynth, initStereo, NewSndCallBackProc(S_Callback) );
if ( err ) {
return false;
}
submissionChunk = chunkSize->integer;
maxMixedSamples = bufferSize->integer;
s_mixedSamples = NSZoneMalloc(NULL, sizeof(*s_mixedSamples) * maxMixedSamples);
dma.channels = 2;
dma.samples = maxMixedSamples;
dma.submission_chunk = submissionChunk;
dma.samplebits = 16;
dma.speed = 22050;
dma.buffer = (byte *)s_mixedSamples;
// que up the first submission-chunk sized buffer
s_chunkCount = 0;
S_Callback( s_sndChan, NULL );
return qtrue;
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void) {
return s_chunkCount * submissionChunk;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void) {
if ( s_sndChan ) {
SndDisposeChannel( s_sndChan, true );
s_sndChan = NULL;
}
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting(void) {
}
/*
===============
SNDDMA_Submit
===============
*/
void SNDDMA_Submit(void) {
}

1074
code/macosx/macosx_sys.m Normal file → Executable file

File diff suppressed because it is too large Load diff

112
code/macosx/macosx_timers.h Normal file → Executable file
View file

@ -1,56 +1,56 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef OMNI_TIMER
#import <OmniTimer/OmniTimer.h>
#define OTSTART(node) OTStackPush(node)
#define OTSTOP(node) OTStackPop()
extern OTStackNode *rootNode;
extern OTStackNode *markFragmentsNode1;
extern OTStackNode *markFragmentsNode2;
extern OTStackNode *markFragmentsGrid;
extern OTStackNode *markFragmentsNode4;
extern OTStackNode *addMarkFragmentsNode;
extern OTStackNode *chopPolyNode;
extern OTStackNode *boxTraceNode;
extern OTStackNode *boxOnPlaneSideNode;
extern OTStackNode *recursiveWorldNode;
extern OTStackNode *surfaceAnimNode;
extern OTStackNode *surfaceFaceNode;
extern OTStackNode *surfaceMeshNode;
extern OTStackNode *surfaceEndNode;
extern OTStackNode *shadowEndNode;
extern OTStackNode *stageIteratorGenericNode;
extern OTStackNode *computeColorAndTexNode;
extern OTStackNode *mp3DecodeNode;
extern void InitializeTimers();
#else
#define OTSTART(node)
#define OTSTOP(node)
#endif
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef OMNI_TIMER
#import <OmniTimer/OmniTimer.h>
#define OTSTART(node) OTStackPush(node)
#define OTSTOP(node) OTStackPop()
extern OTStackNode *rootNode;
extern OTStackNode *markFragmentsNode1;
extern OTStackNode *markFragmentsNode2;
extern OTStackNode *markFragmentsGrid;
extern OTStackNode *markFragmentsNode4;
extern OTStackNode *addMarkFragmentsNode;
extern OTStackNode *chopPolyNode;
extern OTStackNode *boxTraceNode;
extern OTStackNode *boxOnPlaneSideNode;
extern OTStackNode *recursiveWorldNode;
extern OTStackNode *surfaceAnimNode;
extern OTStackNode *surfaceFaceNode;
extern OTStackNode *surfaceMeshNode;
extern OTStackNode *surfaceEndNode;
extern OTStackNode *shadowEndNode;
extern OTStackNode *stageIteratorGenericNode;
extern OTStackNode *computeColorAndTexNode;
extern OTStackNode *mp3DecodeNode;
extern void InitializeTimers();
#else
#define OTSTART(node)
#define OTSTOP(node)
#endif

150
code/macosx/macosx_timers.m Normal file → Executable file
View file

@ -1,75 +1,75 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef OMNI_TIMER
#import "macosx_timers.h"
#import <Foundation/NSString.h>
#import <stdio.h>
OTStackNode *rootNode;
OTStackNode *markFragmentsNode1;
OTStackNode *markFragmentsNode2;
OTStackNode *markFragmentsGrid;
OTStackNode *markFragmentsNode4;
OTStackNode *addMarkFragmentsNode;
OTStackNode *chopPolyNode;
OTStackNode *boxTraceNode;
OTStackNode *boxOnPlaneSideNode;
OTStackNode *recursiveWorldNode;
OTStackNode *surfaceAnimNode;
OTStackNode *surfaceFaceNode;
OTStackNode *surfaceMeshNode;
OTStackNode *surfaceEndNode;
OTStackNode *shadowEndNode;
OTStackNode *stageIteratorGenericNode;
OTStackNode *computeColorAndTexNode;
OTStackNode *mp3DecodeNode;
void InitializeTimers()
{
const char *env;
OTSetup();
rootNode = OTStackNodeCreate("root");
markFragmentsNode1 = OTStackNodeCreate("R_MarkFragments 1");
markFragmentsNode2 = OTStackNodeCreate("R_MarkFragments 2");
markFragmentsGrid = OTStackNodeCreate("R_MarkFragmentsGrid");
markFragmentsNode4 = OTStackNodeCreate("R_MarkFragments 4");
addMarkFragmentsNode = OTStackNodeCreate("R_AddMarkFragments");
chopPolyNode = OTStackNodeCreate("R_ChopPolyBehindPlane");
boxTraceNode = OTStackNodeCreate("CM_BoxTrace");
boxOnPlaneSideNode = OTStackNodeCreate("BoxOnPlaneSide");
recursiveWorldNode = OTStackNodeCreate("R_RecursiveWorldNode");
surfaceAnimNode = OTStackNodeCreate("RB_SurfaceAnim");
surfaceFaceNode = OTStackNodeCreate("RB_SurfaceFace");
surfaceMeshNode = OTStackNodeCreate("RB_SurfaceMesh");
surfaceEndNode = OTStackNodeCreate("RB_EndSurface");
shadowEndNode = OTStackNodeCreate("RB_ShadowTessEnd");
stageIteratorGenericNode = OTStackNodeCreate("RB_StageIteratorGeneric");
computeColorAndTexNode = OTStackNodeCreate("ComputeColors & ComputeTexCoords");
mp3DecodeNode = OTStackNodeCreate("MP3Stream_Decode");
}
#endif // OMNI_TIMER
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef OMNI_TIMER
#import "macosx_timers.h"
#import <Foundation/NSString.h>
#import <stdio.h>
OTStackNode *rootNode;
OTStackNode *markFragmentsNode1;
OTStackNode *markFragmentsNode2;
OTStackNode *markFragmentsGrid;
OTStackNode *markFragmentsNode4;
OTStackNode *addMarkFragmentsNode;
OTStackNode *chopPolyNode;
OTStackNode *boxTraceNode;
OTStackNode *boxOnPlaneSideNode;
OTStackNode *recursiveWorldNode;
OTStackNode *surfaceAnimNode;
OTStackNode *surfaceFaceNode;
OTStackNode *surfaceMeshNode;
OTStackNode *surfaceEndNode;
OTStackNode *shadowEndNode;
OTStackNode *stageIteratorGenericNode;
OTStackNode *computeColorAndTexNode;
OTStackNode *mp3DecodeNode;
void InitializeTimers()
{
const char *env;
OTSetup();
rootNode = OTStackNodeCreate("root");
markFragmentsNode1 = OTStackNodeCreate("R_MarkFragments 1");
markFragmentsNode2 = OTStackNodeCreate("R_MarkFragments 2");
markFragmentsGrid = OTStackNodeCreate("R_MarkFragmentsGrid");
markFragmentsNode4 = OTStackNodeCreate("R_MarkFragments 4");
addMarkFragmentsNode = OTStackNodeCreate("R_AddMarkFragments");
chopPolyNode = OTStackNodeCreate("R_ChopPolyBehindPlane");
boxTraceNode = OTStackNodeCreate("CM_BoxTrace");
boxOnPlaneSideNode = OTStackNodeCreate("BoxOnPlaneSide");
recursiveWorldNode = OTStackNodeCreate("R_RecursiveWorldNode");
surfaceAnimNode = OTStackNodeCreate("RB_SurfaceAnim");
surfaceFaceNode = OTStackNodeCreate("RB_SurfaceFace");
surfaceMeshNode = OTStackNodeCreate("RB_SurfaceMesh");
surfaceEndNode = OTStackNodeCreate("RB_EndSurface");
shadowEndNode = OTStackNodeCreate("RB_ShadowTessEnd");
stageIteratorGenericNode = OTStackNodeCreate("RB_StageIteratorGeneric");
computeColorAndTexNode = OTStackNodeCreate("ComputeColors & ComputeTexCoords");
mp3DecodeNode = OTStackNodeCreate("MP3Stream_Decode");
}
#endif // OMNI_TIMER

52
code/macosx/timedemo.zsh Normal file → Executable file
View file

@ -1,26 +1,26 @@
#!/bin/zsh
buildRoot=./build
executable=$buildRoot/Quake3.app/Contents/MacOS/Quake3
ls -l $executable
flags="$flags +set timedemo 1"
flags="$flags +set s_initsound 0"
flags="$flags +set vm_cgame 1"
flags="$flags +set vm_game 1"
flags="$flags +set r_texturebits 16"
flags="$flags +set r_depthbits 16"
flags="$flags +set r_colorbits 16"
flags="$flags +set stencilbits 8"
flags="$flags +set r_appleTransformHint 1"
echo flags=$flags
function demo {
echo Demo $*
$executable $flags +demo $* |& egrep "(seconds|VM)"
}
demo foo
#!/bin/zsh
buildRoot=./build
executable=$buildRoot/Quake3.app/Contents/MacOS/Quake3
ls -l $executable
flags="$flags +set timedemo 1"
flags="$flags +set s_initsound 0"
flags="$flags +set vm_cgame 1"
flags="$flags +set vm_game 1"
flags="$flags +set r_texturebits 16"
flags="$flags +set r_depthbits 16"
flags="$flags +set r_colorbits 16"
flags="$flags +set stencilbits 8"
flags="$flags +set r_appleTransformHint 1"
echo flags=$flags
function demo {
echo Demo $*
$executable $flags +demo $* |& egrep "(seconds|VM)"
}
demo foo