mirror of
https://github.com/ioquake/ioq3.git
synced 2025-05-31 09:01:54 +00:00
Itsa me, quake3io!
This commit is contained in:
parent
dbe4ddb103
commit
5b755058f5
1409 changed files with 798983 additions and 798983 deletions
34
code/macosx/BuildRelease
Normal file → Executable file
34
code/macosx/BuildRelease
Normal file → Executable 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
54
code/macosx/CGMouseDeltaFix.h
Normal file → Executable 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
262
code/macosx/CGMouseDeltaFix.m
Normal file → Executable 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
370
code/macosx/CGPrivateAPI.h
Normal file → Executable 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
292
code/macosx/GenerateQGL.pl
Normal file → Executable 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
0
code/macosx/Performance.rtf
Normal file → Executable file
80
code/macosx/Q3Controller.h
Normal file → Executable file
80
code/macosx/Q3Controller.h
Normal file → Executable 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
870
code/macosx/Q3Controller.m
Normal file → Executable 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
0
code/macosx/Quake3.icns
Normal file → Executable file
0
code/macosx/Quake3.nib/classes.nib
generated
Normal file → Executable file
0
code/macosx/Quake3.nib/classes.nib
generated
Normal file → Executable file
0
code/macosx/Quake3.nib/info.nib
generated
Normal file → Executable file
0
code/macosx/Quake3.nib/info.nib
generated
Normal file → Executable file
0
code/macosx/Quake3.nib/objects.nib
generated
Normal file → Executable file
0
code/macosx/Quake3.nib/objects.nib
generated
Normal file → Executable file
1126
code/macosx/Quake3.pbproj/apple.pbxuser
Normal file → Executable 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
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
18
code/macosx/RecordDemo.zsh
Normal file → Executable 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
0
code/macosx/banner.jpg
Normal file → Executable file
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
392
code/macosx/botlib.log
Normal file → Executable file
392
code/macosx/botlib.log
Normal file → Executable 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
76
code/macosx/macosx_display.h
Normal file → Executable 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
746
code/macosx/macosx_display.m
Normal file → Executable 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
74
code/macosx/macosx_glimp.h
Normal file → Executable 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
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
352
code/macosx/macosx_glsmp_mutex.m
Normal file → Executable 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
92
code/macosx/macosx_glsmp_null.m
Normal file → Executable 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
850
code/macosx/macosx_glsmp_ports.m
Normal file → Executable 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
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
258
code/macosx/macosx_local.h
Normal file → Executable 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
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
650
code/macosx/macosx_sndcore.m
Normal file → Executable 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
410
code/macosx/macosx_snddma.m
Normal file → Executable 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
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
112
code/macosx/macosx_timers.h
Normal file → Executable 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
150
code/macosx/macosx_timers.m
Normal file → Executable 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
52
code/macosx/timedemo.zsh
Normal file → Executable 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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue