The Quake III Arena sources as originally released under the GPL license on August 20, 2005.

This commit is contained in:
Travis Bradshaw 2012-01-31 13:41:34 -06:00
commit dbe4ddb103
1409 changed files with 806066 additions and 0 deletions

17
code/macosx/BuildRelease Normal file
View file

@ -0,0 +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 ./*

View file

@ -0,0 +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);

View file

@ -0,0 +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);
}

185
code/macosx/CGPrivateAPI.h Normal file
View file

@ -0,0 +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)

146
code/macosx/GenerateQGL.pl Normal file
View file

@ -0,0 +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";
}

114
code/macosx/Performance.rtf Normal file
View file

@ -0,0 +1,114 @@
{\rtf1\mac\ansicpg10000{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
{\colortbl;\red255\green255\blue255;\red255\green0\blue16;\red255\green0\blue16;}
\paperw14240\paperh14700
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\f0\fs24 \cf0 \
\b +set timedemo 1 +demo die.dm3 +set s_initsound 0 +set r_enablerender 0 +set vm_cgame 0 +set vm_game 0\
4865 frames, 154.3 seconds: 31.5 fps\
\
\
+set timedemo 1 +demo die.dm3 +set s_initsound 0 +set r_enablerender 0 +set vm_cgame 2 +set vm_game 2\
4865 frames, 199.8 seconds: 24.4 fps\
\
\
+set timedemo 1 +demo demo001.dm3 +set s_initsound 0 +set r_enablerender 0 +set vm_cgame 0 +set vm_game 0\
1346 frames, 10.1 seconds: 133.0 fps\
\
\
+set timedemo 1 +demo demo001.dm3 +set s_initsound 0 +set r_enablerender 0 +set vm_cgame 2 +set vm_game 2\
1346 frames, 12.8 seconds: 105.4 fps\
\
\
\
Starting point\
\b0 4865 frames, 154.5 seconds: 31.5 fps\
[seconds spent locally, % of parent, % of total, # of samples]\
[133.623469 -- 60130560955, 100.00%, 100.00%, 4866] Root\
[126.853849 -- 57084231997, 94.93%, 94.93%, 4866] CL_Frame\
[125.895845 -- 56653130083, 99.24%, 94.22%, 4918] SCR_UpdateScreen\
[50.532841 -- 22739778533, 40.14%, 37.82%, 524036] RB_SurfaceMesh\
[46.583051 -- 20962372767, 92.18%, 34.86%, 524036] LerpMeshVertexes\
[8.465527 -- 3809487228, 18.17%, 6.34%, 455917] LerpMeshVertexes 1\
\b \cf2 [37.967433 -- 17085344910, 81.50%, 28.41%, 68119] LerpMeshVertexes 2\
\b0 \cf0 [0.32% spent locally]\
[7.82% spent locally]\
[59.86% spent locally]\
[0.76% spent locally]\
[5.07% spent locally]\
\
\b Minor cleanup of local variables\
\b0 [seconds spent locally, % of parent, % of total, # of samples]\
[133.121489 -- 59904670191, 100.00%, 100.00%, 4866] Root\
[126.329343 -- 56848204176, 94.90%, 94.90%, 4866] CL_Frame\
[125.402239 -- 56431007399, 99.27%, 94.20%, 4918] SCR_UpdateScreen\
[50.013076 -- 22505884288, 39.88%, 37.57%, 524036] RB_SurfaceMesh\
[46.085775 -- 20738598809, 92.15%, 34.62%, 524036] LerpMeshVertexes\
[8.427565 -- 3792404277, 18.29%, 6.33%, 455917] LerpMeshVertexes 1\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b \cf3 [37.517092 -- 16882691281, 81.41%, 28.18%, 68119] LerpMeshVertexes 2\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b0 \cf0 [0.31% spent locally]\
[7.85% spent locally]\
[60.12% spent locally]\
[0.73% spent locally]\
[5.10% spent locally]\
\
\
\b Split out normalization of LERPed normals (i.e., all the sqrt calls)\
\b0 [seconds spent locally, % of parent, % of total, # of samples]\
[133.110463 -- 59899708244, 100.00%, 100.00%, 4866] Root\
[126.357393 -- 56860826689, 94.93%, 94.93%, 4866] CL_Frame\
[125.364641 -- 56414088645, 99.21%, 94.18%, 4918] SCR_UpdateScreen\
[49.854816 -- 22434667309, 39.77%, 37.45%, 524036] RB_SurfaceMesh\
[45.981802 -- 20691810706, 92.23%, 34.54%, 524036] LerpMeshVertexes\
[8.407983 -- 3783592133, 18.29%, 6.32%, 455917] LerpMeshVertexes 1\
[37.432159 -- 16844471717, 81.41%, 28.12%, 68119] LerpMeshVertexes 2\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b \cf3 [30.288000 -- 13629599780, 80.91%, 22.75%, 68119] VectorArrayNormalize\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b0 \cf0 [19.09% spent locally]\
[0.31% spent locally]\
[7.77% spent locally]\
[60.23% spent locally]\
[0.79% spent locally]\
[5.07% spent locally]\
\
\b Rewrote VectorArrayNormalize to use PPC frsqrt instruction (with Newton-Rhapson refinement)\
\b0 4865 frames, 128.7 seconds: 37.8 fps\
[seconds spent locally, % of parent, % of total, # of samples]\
[103.972710 -- 46787719721, 100.00%, 100.00%, 4866] Root\
[97.153160 -- 43718922078, 93.44%, 93.44%, 4866] CL_Frame\
[96.219348 -- 43298706398, 99.04%, 92.54%, 4918] SCR_UpdateScreen\
[20.873944 -- 9393274747, 21.69%, 20.08%, 524036] RB_SurfaceMesh\
[17.053245 -- 7673960266, 81.70%, 16.40%, 524036] LerpMeshVertexes\
[8.356579 -- 3760460537, 49.00%, 8.04%, 455917] LerpMeshVertexes 1\
[8.560159 -- 3852071404, 50.20%, 8.23%, 68119] LerpMeshVertexes 2\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b \cf3 [1.429376 -- 643219234, 16.70%, 1.37%, 68119] VectorArrayNormalize\
\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural
\b0 \cf0 [83.30% spent locally]\
[0.80% spent locally]\
[18.30% spent locally]\
[78.31% spent locally]\
[0.96% spent locally]\
[6.56% spent locally]\
\
\
}

View file

@ -0,0 +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

435
code/macosx/Q3Controller.m Normal file
View file

@ -0,0 +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

BIN
code/macosx/Quake3.icns Normal file

Binary file not shown.

18
code/macosx/Quake3.nib/classes.nib generated Normal file
View file

@ -0,0 +1,18 @@
{
IBClasses = (
{
ACTIONS = {showHelp = id; };
CLASS = FirstResponder;
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
},
{
ACTIONS = {paste = id; requestTerminate = id; };
CLASS = Q3Controller;
LANGUAGE = ObjC;
OUTLETS = {bannerPanel = id; };
SUPERCLASS = NSObject;
}
);
IBVersion = 1;
}

19
code/macosx/Quake3.nib/info.nib generated Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBEditorPositions</key>
<dict>
<key>29</key>
<string>69 252 121 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
<array>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>5V21</string>
</dict>
</plist>

BIN
code/macosx/Quake3.nib/objects.nib generated Normal file

Binary file not shown.

View file

@ -0,0 +1,563 @@
// !$*UTF8*$!
{
00F5ED38FEBA95B7C697A12F = {
activeExec = 0;
};
00F5ED90FEBA9615C697A12F = {
activeExec = 0;
};
016EAE0300B4BDD1C697A10E = {
activeExec = 0;
};
0170304B00B4885DC697A10E = {
activeExec = 0;
executables = (
1895FF35065E291B00F8B3F4,
);
};
0170311C00B49352C697A10E = {
activeExec = 0;
};
043627B100868916C697A10E = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1586, 6033}}";
sepNavSelRange = "{136, 0}";
sepNavVisRect = "{{0, 0}, {711, 428}}";
};
};
0654BA41FE8ECEE0C697A12F = {
activeBuildStyle = 07F3F50BFFE98E8EC697A10E;
activeExecutable = 1895FF30065E291B00F8B3F4;
activeTarget = 00F5ED90FEBA9615C697A12F;
codeSenseManager = 1895FF4C065E294000F8B3F4;
executables = (
1895FF2F065E291B00F8B3F4,
1895FF30065E291B00F8B3F4,
1895FF31065E291B00F8B3F4,
1895FF35065E291B00F8B3F4,
);
perUserDictionary = {
PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID;
PBXFileTableDataSourceColumnWidthsKey = (
22,
843.7974,
);
PBXFileTableDataSourceColumnsKey = (
PBXExecutablesDataSource_ActiveFlagID,
PBXExecutablesDataSource_NameID,
);
};
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
550,
20,
99,
43,
43,
20,
);
PBXFileTableDataSourceColumnsKey = (
PBXFileDataSource_FiletypeID,
PBXFileDataSource_Filename_ColumnID,
PBXFileDataSource_Built_ColumnID,
PBXFileDataSource_ObjectSize_ColumnID,
PBXFileDataSource_Errors_ColumnID,
PBXFileDataSource_Warnings_ColumnID,
PBXFileDataSource_Target_ColumnID,
);
};
PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
467,
101,
20,
101,
43,
43,
);
PBXFileTableDataSourceColumnsKey = (
PBXFileDataSource_FiletypeID,
PBXFileDataSource_Filename_ColumnID,
PBXTargetDataSource_PrimaryAttribute,
PBXFileDataSource_Built_ColumnID,
PBXFileDataSource_ObjectSize_ColumnID,
PBXFileDataSource_Errors_ColumnID,
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 106915007;
PBXPrepackagedSmartGroups_v2 = (
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
activationKey = OldTargetSmartGroup;
clz = PBXTargetSmartGroup;
description = "Displays all targets of the project.";
globalID = 1C37FABC04509CD000000102;
name = Targets;
preferences = {
image = Targets;
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXTargetSmartGroup2;
description = "Displays all targets of the project as well as nested build phases.";
globalID = 1C37FBAC04509CD000000102;
name = Targets;
preferences = {
image = Targets;
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXExecutablesSmartGroup;
description = "Displays all executables of the project.";
globalID = 1C37FAAC04509CD000000102;
name = Executables;
preferences = {
image = Executable;
};
},
{
" PBXTransientLocationAtTop " = bottom;
absolutePathToBundle = "";
clz = PBXErrorsWarningsSmartGroup;
description = "Displays files with errors or warnings.";
globalID = 1C08E77C0454961000C914BD;
name = "Errors and Warnings";
preferences = {
fnmatch = "";
image = WarningsErrors;
recursive = 1;
regex = "";
root = "<PROJECT>";
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXFilenameSmartGroup;
description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter.";
globalID = 1CC0EA4004350EF90044410B;
name = "Implementation Files";
preferences = {
canSave = 1;
fnmatch = "";
image = SmartFolder;
isLeaf = 0;
recursive = 1;
regex = "?*\\.[mcMC]";
root = "<PROJECT>";
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXFilenameSmartGroup;
description = "This group displays Interface Builder NIB Files.";
globalID = 1CC0EA4004350EF90041110B;
name = "NIB Files";
preferences = {
canSave = 1;
fnmatch = "*.nib";
image = SmartFolder;
isLeaf = 0;
recursive = 1;
regex = "";
root = "<PROJECT>";
};
},
{
PBXTransientLocationAtTop = no;
absolutePathToBundle = "";
clz = PBXFindSmartGroup;
description = "Displays Find Results.";
globalID = 1C37FABC05509CD000000102;
name = "Find Results";
preferences = {
image = spyglass;
};
},
{
PBXTransientLocationAtTop = no;
absolutePathToBundle = "";
clz = PBXBookmarksSmartGroup;
description = "Displays Project Bookmarks.";
globalID = 1C37FABC05539CD112110102;
name = Bookmarks;
preferences = {
image = Bookmarks;
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = XCSCMSmartGroup;
description = "Displays files with interesting SCM status.";
globalID = E2644B35053B69B200211256;
name = SCM;
preferences = {
image = PBXRepository;
isLeaf = 0;
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXSymbolsSmartGroup;
description = "Displays all symbols for the project.";
globalID = 1C37FABC04509CD000100104;
name = "Project Symbols";
preferences = {
image = ProjectSymbols;
isLeaf = 1;
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXFilenameSmartGroup;
description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter.";
globalID = PBXTemplateMarker;
name = "Simple Filter SmartGroup";
preferences = {
canSave = 1;
fnmatch = "*.nib";
image = SmartFolder;
isLeaf = 0;
recursive = 1;
regex = "";
root = "<PROJECT>";
};
},
{
PBXTransientLocationAtTop = bottom;
absolutePathToBundle = "";
clz = PBXFilenameSmartGroup;
description = "Filters items in a given group (potentially recursively) based on matching the name with the regular expression of the filter.";
globalID = PBXTemplateMarker;
name = "Simple Regular Expression SmartGroup";
preferences = {
canSave = 1;
fnmatch = "";
image = SmartFolder;
isLeaf = 0;
recursive = 1;
regex = "?*\\.[mcMC]";
root = "<PROJECT>";
};
},
);
PBXWorkspaceContents = (
{
PBXProjectWorkspaceModule_StateKey_Rev39 = {
PBXProjectWorkspaceModule_DataSourceSelectionKey_Rev6 = {
BoundsStr = "{{0, 0}, {823, 735}}";
Rows = (
);
VisibleRectStr = "{{0, 0}, {823, 735}}";
};
PBXProjectWorkspaceModule_EditorOpen = false;
PBXProjectWorkspaceModule_EmbeddedNavigatorGroup = {
PBXSplitModuleInNavigatorKey = {
SplitCount = 1;
};
};
PBXProjectWorkspaceModule_GeometryKey_Rev15 = {
PBXProjectWorkspaceModule_SGTM_Geometry = {
_collapsingFrameDimension = 0;
_indexOfCollapsedView = 0;
_percentageOfCollapsedView = 0;
sizes = (
"{{0, 0}, {210, 752}}",
"{{210, 0}, {838, 752}}",
);
};
};
PBXProjectWorkspaceModule_OldDetailFrame = "{{0, 0}, {838, 752}}";
PBXProjectWorkspaceModule_OldEditorFrame = "{{0, 0}, {750, 480}}";
PBXProjectWorkspaceModule_OldSuperviewFrame = "{{210, 0}, {838, 752}}";
PBXProjectWorkspaceModule_SGTM = {
PBXBottomSmartGroupGIDs = (
1C37FBAC04509CD000000102,
1C37FAAC04509CD000000102,
1C08E77C0454961000C914BD,
1CC0EA4004350EF90044410B,
1CC0EA4004350EF90041110B,
1C37FABC05509CD000000102,
1C37FABC05539CD112110102,
E2644B35053B69B200211256,
1C37FABC04509CD000100104,
);
PBXSmartGroupTreeModuleColumnData = {
PBXSmartGroupTreeModuleColumnWidthsKey = (
193,
);
PBXSmartGroupTreeModuleColumnsKey_v4 = (
MainColumn,
);
};
PBXSmartGroupTreeModuleOutlineStateKey_v7 = {
PBXSmartGroupTreeModuleOutlineStateExpansionKey = (
1C37FBAC04509CD000000102,
18A3D348065F659F006A719A,
18A3D35B065F6655006A719A,
);
PBXSmartGroupTreeModuleOutlineStateSelectionKey = (
(
2,
1,
),
);
PBXSmartGroupTreeModuleOutlineStateVisibleRectKey = "{{0, 0}, {193, 734}}";
};
PBXTopSmartGroupGIDs = (
);
};
};
},
);
"PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXBuildResultsModule" = {
};
"PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXCVSModule" = {
};
"PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXDebugCLIModule" = {
};
"PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXNavigatorGroup" = {
PBXSplitModuleInNavigatorKey = {
SplitCount = 1;
};
};
"PBXWorkspaceContents:PBXConfiguration.PBXModule.PBXProjectWorkspaceModule" = {
PBXProjectWorkspaceModule_StateKey_Rev39 = {
PBXProjectWorkspaceModule_DataSourceSelectionKey_Rev6 = {
BoundsStr = "{{0, 0}, {851, 4290}}";
Rows = (
0,
);
VisibleRectStr = "{{0, 0}, {851, 735}}";
};
PBXProjectWorkspaceModule_EditorOpen = false;
PBXProjectWorkspaceModule_EmbeddedNavigatorGroup = {
PBXSplitModuleInNavigatorKey = {
SplitCount = 1;
};
};
PBXProjectWorkspaceModule_GeometryKey_Rev15 = {
PBXProjectWorkspaceModule_SGTM_Geometry = {
_collapsingFrameDimension = 0;
_indexOfCollapsedView = 0;
_percentageOfCollapsedView = 0;
sizes = (
"{{0, 0}, {182, 752}}",
"{{182, 0}, {866, 752}}",
);
};
};
PBXProjectWorkspaceModule_OldDetailFrame = "{{0, 0}, {866, 752}}";
PBXProjectWorkspaceModule_OldEditorFrame = "{{0, 0}, {750, 480}}";
PBXProjectWorkspaceModule_OldSuperviewFrame = "{{182, 0}, {866, 752}}";
PBXProjectWorkspaceModule_SGTM = {
PBXBottomSmartGroupGIDs = (
1C37FBAC04509CD000000102,
1C37FAAC04509CD000000102,
1C08E77C0454961000C914BD,
1CC0EA4004350EF90044410B,
1CC0EA4004350EF90041110B,
1C37FABC05509CD000000102,
1C37FABC05539CD112110102,
E2644B35053B69B200211256,
1C37FABC04509CD000100104,
);
PBXSmartGroupTreeModuleColumnData = {
PBXSmartGroupTreeModuleColumnWidthsKey = (
165,
);
PBXSmartGroupTreeModuleColumnsKey_v4 = (
MainColumn,
);
};
PBXSmartGroupTreeModuleOutlineStateKey_v7 = {
PBXSmartGroupTreeModuleOutlineStateExpansionKey = (
1C37FBAC04509CD000000102,
18A3D340065F651C006A719A,
18A3D341065F651D006A719A,
);
PBXSmartGroupTreeModuleOutlineStateSelectionKey = (
(
1,
),
);
PBXSmartGroupTreeModuleOutlineStateVisibleRectKey = "{{0, 0}, {165, 734}}";
};
PBXTopSmartGroupGIDs = (
);
};
};
};
PBXWorkspaceGeometries = (
{
Frame = "{{0, 0}, {1048, 752}}";
PBXProjectWorkspaceModule_GeometryKey_Rev15 = {
};
RubberWindowFrame = "17 182 1048 794 0 0 1680 1028 ";
},
);
"PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXBuildResultsModule" = {
Frame = "{{0, 0}, {755, 578}}";
PBXModuleWindowStatusBarHidden = YES;
RubberWindowFrame = "612 317 755 599 0 0 1680 1028 ";
};
"PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXCVSModule" = {
Frame = "{{0, 0}, {482, 276}}";
RubberWindowFrame = "590 449 482 318 0 0 1680 1028 ";
};
"PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXDebugCLIModule" = {
Frame = "{{0, 0}, {400, 201}}";
PBXModuleWindowStatusBarHidden = YES;
RubberWindowFrame = "50 1000 400 222 0 0 1680 1028 ";
};
"PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXNavigatorGroup" = {
Frame = "{{0, 0}, {750, 460}}";
RubberWindowFrame = "428 357 750 502 0 0 1680 1028 ";
};
"PBXWorkspaceGeometries:PBXConfiguration.PBXModule.PBXProjectWorkspaceModule" = {
Frame = "{{0, 0}, {1048, 752}}";
PBXProjectWorkspaceModule_GeometryKey_Rev15 = {
PBXProjectWorkspaceModule_BuildResultsWindowVisible = true;
};
RubberWindowFrame = "17 182 1048 794 0 0 1680 1028 ";
};
PBXWorkspaceStateSaveDate = 106915007;
};
sourceControlManager = 1895FF4B065E294000F8B3F4;
userBuildSettings = {
};
};
0654BA5CFE8ECEE0C697A12F = {
activeExec = 0;
executables = (
1895FF2F065E291B00F8B3F4,
);
};
1895FF2F065E291B00F8B3F4 = {
activeArgIndex = 2147483647;
activeArgIndices = (
);
argumentStrings = (
);
configStateDict = {
};
debuggerPlugin = GDBDebugging;
dylibVariantSuffix = "";
enableDebugStr = 1;
environmentEntries = (
);
isa = PBXExecutable;
name = "Quake3 (Application)";
shlibInfoDictList = (
);
sourceDirectories = (
);
};
1895FF30065E291B00F8B3F4 = {
activeArgIndex = 2147483647;
activeArgIndices = (
);
argumentStrings = (
);
configStateDict = {
};
debuggerPlugin = GDBDebugging;
enableDebugStr = 1;
environmentEntries = (
);
isa = PBXExecutable;
name = "Dedicated Server G4";
shlibInfoDictList = (
);
sourceDirectories = (
);
};
1895FF31065E291B00F8B3F4 = {
activeArgIndex = 2147483647;
activeArgIndices = (
);
argumentStrings = (
);
configStateDict = {
};
debuggerPlugin = GDBDebugging;
enableDebugStr = 1;
environmentEntries = (
);
isa = PBXExecutable;
name = "Quake3 G4 (Application)";
shlibInfoDictList = (
);
sourceDirectories = (
);
};
1895FF35065E291B00F8B3F4 = {
activeArgIndex = 2147483647;
activeArgIndices = (
);
argumentStrings = (
);
configStateDict = {
};
debuggerPlugin = GDBDebugging;
enableDebugStr = 1;
environmentEntries = (
);
isa = PBXExecutable;
name = "Dedicated Server";
shlibInfoDictList = (
);
sourceDirectories = (
);
};
1895FF4B065E294000F8B3F4 = {
isa = PBXSourceControlManager;
scmConfiguration = {
};
scmType = scm.cvs;
};
1895FF4C065E294000F8B3F4 = {
indexTemplatePath = "";
isa = PBXCodeSenseManager;
usesDefaults = 1;
wantsCodeCompletion = 1;
wantsCodeCompletionAutoPopup = 0;
wantsCodeCompletionAutoSuggestions = 0;
wantsCodeCompletionCaseSensitivity = 1;
wantsCodeCompletionOnlyMatchingItems = 1;
wantsCodeCompletionParametersIncluded = 1;
wantsCodeCompletionPlaceholdersInserted = 1;
wantsCodeCompletionTabCompletes = 1;
wantsIndex = 1;
};
4FF0904804896C0E00030DA8 = {
activeExec = 0;
executables = (
1895FF31065E291B00F8B3F4,
);
};
4FF0912704896C1600030DA8 = {
activeExec = 0;
executables = (
1895FF30065E291B00F8B3F4,
);
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +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
code/macosx/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

196
code/macosx/botlib.log Normal file
View file

@ -0,0 +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

View file

@ -0,0 +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();

View file

@ -0,0 +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");
}

View file

@ -0,0 +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

1114
code/macosx/macosx_glimp.m Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +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);
}

View file

@ -0,0 +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 )
{
}

View file

@ -0,0 +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);
}

916
code/macosx/macosx_input.m Normal file
View file

@ -0,0 +1,916 @@
/*
===========================================================================
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>
#import <Foundation/Foundation.h>
#include <ApplicationServices/ApplicationServices.h>
#import "../client/client.h"
#import "macosx_local.h"
#import "../renderer/tr_local.h"
#import "Q3Controller.h"
//#import "CGMouseDeltaFix.h"
#import "macosx_timers.h"
#import "macosx_display.h" // For Sys_SetScreenFade
#import <drivers/event_status_driver.h>
#import <sys/types.h>
#import <sys/time.h>
#import <unistd.h>
static qboolean inputActive;
static NSDate *distantPast;
static cvar_t *in_nomouse;
static cvar_t *in_showevents;
static cvar_t *in_mouseLowEndSlope;
static cvar_t *in_mouseHighEndCutoff;
static cvar_t *in_disableOSMouseScaling;
static void Sys_StartMouseInput();
static void Sys_StopMouseInput();
static qboolean mouseactive = qfalse;
static BOOL inputRectValid = NO;
static CGRect inputRect;
static NXMouseScaling originalScaling;
static unsigned int currentModifierFlags;
static void Sys_PreventMouseMovement(CGPoint point)
{
CGEventErr err;
//Com_Printf("**** Calling CGAssociateMouseAndMouseCursorPosition(false)\n");
err = CGAssociateMouseAndMouseCursorPosition(false);
if (err != CGEventNoErr) {
Sys_Error("Could not disable mouse movement, CGAssociateMouseAndMouseCursorPosition returned %d\n", err);
}
// Put the mouse in the position we want to leave it at
err = CGWarpMouseCursorPosition(point);
if (err != CGEventNoErr) {
Sys_Error("Could not disable mouse movement, CGWarpMouseCursorPosition returned %d\n", err);
}
}
static void Sys_ReenableMouseMovement()
{
CGEventErr err;
//Com_Printf("**** Calling CGAssociateMouseAndMouseCursorPosition(true)\n");
err = CGAssociateMouseAndMouseCursorPosition(true);
if (err != CGEventNoErr) {
Sys_Error("Could not reenable mouse movement, CGAssociateMouseAndMouseCursorPosition returned %d\n", err);
}
// Leave the mouse where it was -- don't warp here.
}
void Sys_InitInput(void)
{
// no input with dedicated servers
if ( com_dedicated->integer ) {
return;
}
// The Cvars don't seem to work really early.
[(Q3Controller *)[NSApp delegate] showBanner];
Com_Printf( "------- Input Initialization -------\n" );
if (!distantPast)
distantPast = [[NSDate distantPast] retain];
// For hide support. If we don't do this, then the command key will get stuck on when we hide (since we won't get the flags changed event when it goes up).
currentModifierFlags = 0;
r_fullscreen = Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
in_nomouse = Cvar_Get( "in_nomouse", "0", 0 );
in_showevents = Cvar_Get( "in_showevents", "0", 0 );
// these defaults were arrived at via emprical testing between a Windows box and a Mac OS X box
#define ACT_LIKE_WINDOWS
#ifdef ACT_LIKE_WINDOWS
in_mouseLowEndSlope = Cvar_Get("in_mouseLowEndSlope", "3.5", CVAR_ARCHIVE);
if (in_mouseLowEndSlope->value < 1) {
Cvar_Set("in_mouseLowEndSlope", "1");
}
#else
in_mouseLowEndSlope = Cvar_Get("in_mouseLowEndSlope", "1", CVAR_ARCHIVE);
if (in_mouseLowEndSlope->value < 1) {
Cvar_Set("in_mouseLowEndSlope", "1");
}
#endif
in_mouseHighEndCutoff = Cvar_Get("in_mouseHighEndCutoff", "20", CVAR_ARCHIVE);
if (in_mouseLowEndSlope->value < 1) {
Cvar_Set("in_mouseHighEndCutoff", "1");
}
in_disableOSMouseScaling = Cvar_Get("in_disableOSMouseScaling", "1", CVAR_ARCHIVE );
glw_state.display = Sys_DisplayToUse();
inputActive = qtrue;
if ( in_nomouse->integer == 0 )
Sys_StartMouseInput();
else
Com_Printf( " in_nomouse is set, skipping.\n" );
Com_Printf( "------------------------------------\n" );
}
void Sys_ShutdownInput(void)
{
// no input with dedicated servers
if ( !com_dedicated || com_dedicated->integer ) {
return;
}
Com_Printf( "------- Input Shutdown -------\n" );
if ( !inputActive ) {
return;
}
inputActive = qfalse;
if (mouseactive)
Sys_StopMouseInput();
Com_Printf( "------------------------------\n" );
}
static void Sys_LockMouseInInputRect(CGRect rect)
{
CGPoint center;
center.x = rect.origin.x + rect.size.width / 2.0;
center.y = rect.origin.y + rect.size.height / 2.0;
// Now, put the mouse in the middle of the input rect (anywhere over it would do)
// and don't allow it to move. This means that the user won't be able to accidentally
// select another application.
Sys_PreventMouseMovement(center);
}
extern void Sys_UpdateWindowMouseInputRect(void);
static void Sys_StartMouseInput()
{
NXEventHandle eventStatus;
CGMouseDelta dx, dy;
if (mouseactive) {
//Com_Printf("**** Attempted to start mouse input while already started\n");
return;
}
Com_Printf("Starting mouse input\n");
mouseactive = qtrue;
if (inputRectValid && !glConfig.isFullscreen)
// Make sure that if window moved we don't hose the user...
Sys_UpdateWindowMouseInputRect();
Sys_LockMouseInInputRect(inputRect);
// Grab any mouse delta information to reset the last delta buffer
CGGetLastMouseDelta(&dx, &dy);
// Turn off mouse scaling
if (in_disableOSMouseScaling->integer==0 && (eventStatus = NXOpenEventStatus())) {
NXMouseScaling newScaling;
NXGetMouseScaling(eventStatus, &originalScaling);
newScaling.numScaleLevels = 1;
newScaling.scaleThresholds[0] = 1;
newScaling.scaleFactors[0] = -1;
NXSetMouseScaling(eventStatus, &newScaling);
NXCloseEventStatus(eventStatus);
}
[NSCursor hide];
}
static void Sys_StopMouseInput()
{
NXEventHandle eventStatus;
if (!mouseactive) {
//Com_Printf("**** Attempted to stop mouse input while already stopped\n");
return;
}
Com_Printf("Stopping mouse input\n");
// Restore mouse scaling
if (in_disableOSMouseScaling->integer == 0 && (eventStatus = NXOpenEventStatus())) {
NXSetMouseScaling(eventStatus, &originalScaling);
NXCloseEventStatus(eventStatus);
}
mouseactive = qfalse;
Sys_ReenableMouseMovement();
[NSCursor unhide];
}
//===========================================================================
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
static char *Sys_ConsoleInput(void)
{
extern qboolean stdin_active;
static char text[256];
int len;
fd_set fdset;
struct timeval timeout;
if (!com_dedicated || !com_dedicated->integer)
return NULL;
if (!stdin_active)
return NULL;
FD_ZERO(&fdset);
FD_SET(fileno(stdin), &fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(fileno(stdin), &fdset))
return NULL;
len = read (fileno(stdin), text, sizeof(text));
if (len == 0) { // eof!
stdin_active = qfalse;
return NULL;
}
if (len < 1)
return NULL;
text[len-1] = 0; // rip off the /n and terminate
return text;
}
//===========================================================================
// Mouse input
//===========================================================================
#define MAX_DISPLAYS 128
CGDirectDisplayID Sys_DisplayToUse(void)
{
static BOOL gotDisplay = NO;
static CGDirectDisplayID displayToUse;
cvar_t *vid_screen;
CGDisplayErr err;
CGDirectDisplayID displays[MAX_DISPLAYS];
CGDisplayCount displayCount;
int displayIndex;
if (gotDisplay)
return displayToUse;
gotDisplay = YES;
err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &displayCount);
if (err != CGDisplayNoErr)
Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
// -1, the default, means to use the main screen
if ((vid_screen = Cvar_Get("vid_screen", "-1", CVAR_ARCHIVE)))
displayIndex = vid_screen->integer;
else
displayIndex = -1;
if (displayIndex < 0 || displayIndex >= displayCount)
// This is documented (in CGDirectDisplay.h) to be the main display. We want to
// return this instead of kCGDirectMainDisplay since this will allow us to compare
// display IDs.
displayToUse = displays[0];
else
displayToUse = displays[displayIndex];
return displayToUse;
}
void Sys_SetMouseInputRect(CGRect newRect)
{
inputRectValid = YES;
inputRect = newRect;
//Com_Printf("**** inputRect = (%f, %f, %f, %f)\n", newRect.origin.x, newRect.origin.y, newRect.size.width, newRect.size.height);
if (mouseactive)
Sys_LockMouseInInputRect(inputRect);
}
static void Sys_ProcessMouseMovedEvent(NSEvent *mouseMovedEvent, int currentTime)
{
float dx, dy;
if (!mouseactive)
return;
dx = [mouseMovedEvent deltaX];
dy = [mouseMovedEvent deltaY];
if (in_showevents->integer)
Com_Printf("MOUSE MOVED: %d, %d\n", dx, dy);
Sys_QueEvent(currentTime, SE_MOUSE, dx, dy, 0, NULL );
}
// If we are 'paused' (i.e., in any state that our normal key bindings aren't in effect), then interpret cmd-h and cmd-tab as hiding the application.
static qboolean maybeHide()
{
if ((currentModifierFlags & NSCommandKeyMask) == 0)
return qfalse;
return Sys_Hide();
}
static inline void sendEventForCharacter(NSEvent *event, unichar character, qboolean keyDownFlag, int currentTime)
{
if (in_showevents->integer)
Com_Printf("CHARACTER: 0x%02x down=%d\n", character, keyDownFlag);
#ifdef OMNI_TIMER
if (character == NSF9FunctionKey && !keyDownFlag) {
// Log and reset the root timer. We should currently only have the root on the stack.
OTStackPopRoot();
OTStackReportResults(NULL);
OTStackReset();
OTStackPushRoot(rootNode);
}
#endif
switch (character) {
case 0x03:
Sys_QueEvent(currentTime, SE_KEY, K_KP_ENTER, keyDownFlag, 0, NULL);
break;
case '\b':
case '\177':
Sys_QueEvent(currentTime, SE_KEY, K_BACKSPACE, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, '\b', 0, 0, NULL);
}
break;
case '\t':
if (maybeHide())
return;
Sys_QueEvent(currentTime, SE_KEY, K_TAB, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, '\t', 0, 0, NULL);
}
break;
case '\r':
case '\n':
Sys_QueEvent(currentTime, SE_KEY, K_ENTER, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, '\r', 0, 0, NULL);
}
break;
case '\033':
Sys_QueEvent(currentTime, SE_KEY, K_ESCAPE, keyDownFlag, 0, NULL);
break;
case ' ':
Sys_QueEvent(currentTime, SE_KEY, K_SPACE, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, ' ', 0, 0, NULL);
}
break;
case NSUpArrowFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_UPARROW, keyDownFlag, 0, NULL);
break;
case NSDownArrowFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_DOWNARROW, keyDownFlag, 0, NULL);
break;
case NSLeftArrowFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_LEFTARROW, keyDownFlag, 0, NULL);
break;
case NSRightArrowFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_RIGHTARROW, keyDownFlag, 0, NULL);
break;
case NSF1FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F1, keyDownFlag, 0, NULL);
break;
case NSF2FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F2, keyDownFlag, 0, NULL);
break;
case NSF3FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F3, keyDownFlag, 0, NULL);
break;
case NSF4FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F4, keyDownFlag, 0, NULL);
break;
case NSF5FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F5, keyDownFlag, 0, NULL);
break;
case NSF6FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F6, keyDownFlag, 0, NULL);
break;
case NSF7FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F7, keyDownFlag, 0, NULL);
break;
case NSF8FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F8, keyDownFlag, 0, NULL);
break;
case NSF9FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F9, keyDownFlag, 0, NULL);
break;
case NSF10FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F10, keyDownFlag, 0, NULL);
break;
case NSF11FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F11, keyDownFlag, 0, NULL);
break;
case NSF12FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_F12, keyDownFlag, 0, NULL);
break;
case NSF13FunctionKey:
Sys_QueEvent(currentTime, SE_KEY, '`', keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, '`', 0, 0, NULL);
}
break;
case NSInsertFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_INS, keyDownFlag, 0, NULL);
break;
case NSDeleteFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_DEL, keyDownFlag, 0, NULL);
break;
case NSPageDownFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_PGDN, keyDownFlag, 0, NULL);
break;
case NSPageUpFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_PGUP, keyDownFlag, 0, NULL);
break;
case NSHomeFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_HOME, keyDownFlag, 0, NULL);
break;
case NSEndFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_END, keyDownFlag, 0, NULL);
break;
case NSPauseFunctionKey:
Sys_QueEvent(currentTime, SE_KEY, K_PAUSE, keyDownFlag, 0, NULL);
break;
default:
if ([event modifierFlags] & NSNumericPadKeyMask) {
switch (character) {
case '0':
Sys_QueEvent(currentTime, SE_KEY, K_KP_INS, keyDownFlag, 0, NULL);
break;
case '1':
Sys_QueEvent(currentTime, SE_KEY, K_KP_END, keyDownFlag, 0, NULL);
break;
case '2':
Sys_QueEvent(currentTime, SE_KEY, K_KP_DOWNARROW, keyDownFlag, 0, NULL);
break;
case '3':
Sys_QueEvent(currentTime, SE_KEY, K_KP_PGDN, keyDownFlag, 0, NULL);
break;
case '4':
Sys_QueEvent(currentTime, SE_KEY, K_KP_LEFTARROW, keyDownFlag, 0, NULL);
break;
case '5':
Sys_QueEvent(currentTime, SE_KEY, K_KP_5, keyDownFlag, 0, NULL);
break;
case '6':
Sys_QueEvent(currentTime, SE_KEY, K_KP_RIGHTARROW, keyDownFlag, 0, NULL);
break;
case '7':
Sys_QueEvent(currentTime, SE_KEY, K_KP_HOME, keyDownFlag, 0, NULL);
break;
case '8':
Sys_QueEvent(currentTime, SE_KEY, K_KP_UPARROW, keyDownFlag, 0, NULL);
break;
case '9':
Sys_QueEvent(currentTime, SE_KEY, K_KP_PGUP, keyDownFlag, 0, NULL);
break;
case '.':
case ',':
Sys_QueEvent(currentTime, SE_KEY, K_KP_DEL, keyDownFlag, 0, NULL);
break;
case '+':
Sys_QueEvent(currentTime, SE_KEY, K_KP_PLUS, keyDownFlag, 0, NULL);
break;
case '-':
Sys_QueEvent(currentTime, SE_KEY, K_KP_MINUS, keyDownFlag, 0, NULL);
break;
case '*':
Sys_QueEvent(currentTime, SE_KEY, K_KP_STAR, keyDownFlag, 0, NULL);
break;
case '/':
Sys_QueEvent(currentTime, SE_KEY, K_KP_SLASH, keyDownFlag, 0, NULL);
break;
case '=':
Sys_QueEvent(currentTime, SE_KEY, K_KP_EQUALS, keyDownFlag, 0, NULL);
break;
default:
//NSLog(@"TODO: Implement character %d", (int)character);
break;
}
} else if (character >= 'a' && character <= 'z') {
if (character == 'h') {
if (maybeHide())
return;
}
Sys_QueEvent(currentTime, SE_KEY, character, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, (char)character, 0, 0, NULL);
}
} else if (character >= 'A' && character <= 'Z') {
Sys_QueEvent(currentTime, SE_KEY, 'a' + (character - 'A'), keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, character, 0, 0, NULL);
}
} else if (character >= 32 && character < 127) {
Sys_QueEvent(currentTime, SE_KEY, character, keyDownFlag, 0, NULL);
if (keyDownFlag) {
Sys_QueEvent(currentTime, SE_CHAR, (char)character, 0, 0, NULL);
}
} else {
//NSLog(@"TODO: Implement character %d", (int)character);
}
break;
}
}
static inline void processKeyEvent(NSEvent *keyEvent, qboolean keyDownFlag, int currentTime)
{
NSEventType eventType;
NSString *characters;
unsigned int characterIndex, characterCount;
eventType = [keyEvent type];
characters = [keyEvent charactersIgnoringModifiers];
characterCount = [characters length];
for (characterIndex = 0; characterIndex < characterCount; characterIndex++) {
sendEventForCharacter(keyEvent, [characters characterAtIndex:characterIndex], keyDownFlag, currentTime);
}
}
static inline void sendEventForMaskChangeInFlags(int quakeKey, unsigned int modifierMask, unsigned int newModifierFlags, int currentTime)
{
BOOL oldHadModifier, newHasModifier;
oldHadModifier = (currentModifierFlags & modifierMask) != 0;
newHasModifier = (newModifierFlags & modifierMask) != 0;
if (oldHadModifier != newHasModifier) {
// NSLog(@"Key %d posted for modifier mask modifierMask", quakeKey);
Sys_QueEvent(currentTime, SE_KEY, quakeKey, newHasModifier, 0, NULL);
}
}
static inline void processFlagsChangedEvent(NSEvent *flagsChangedEvent, int currentTime)
{
int newModifierFlags;
newModifierFlags = [flagsChangedEvent modifierFlags];
sendEventForMaskChangeInFlags(K_COMMAND, NSCommandKeyMask, newModifierFlags, currentTime);
sendEventForMaskChangeInFlags(K_CAPSLOCK, NSAlphaShiftKeyMask, newModifierFlags, currentTime);
sendEventForMaskChangeInFlags(K_ALT, NSAlternateKeyMask, newModifierFlags, currentTime);
sendEventForMaskChangeInFlags(K_CTRL, NSControlKeyMask, newModifierFlags, currentTime);
sendEventForMaskChangeInFlags(K_SHIFT, NSShiftKeyMask, newModifierFlags, currentTime);
currentModifierFlags = newModifierFlags;
}
static inline void processSystemDefinedEvent(NSEvent *systemDefinedEvent, int currentTime)
{
static int oldButtons = 0;
int buttonsDelta;
int buttons;
int isDown;
if ([systemDefinedEvent subtype] == 7) {
if (!mouseactive)
return;
buttons = [systemDefinedEvent data2];
buttonsDelta = oldButtons ^ buttons;
//Com_Printf("uberbuttons: %08lx %08lx\n",buttonsDelta,buttons);
if (buttonsDelta & 1) {
isDown = buttons & 1;
Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, isDown, 0, NULL);
if (in_showevents->integer) {
Com_Printf("MOUSE2: %s\n", isDown ? "down" : "up");
}
}
if (buttonsDelta & 2) {
isDown = buttons & 2;
Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, isDown, 0, NULL);
if (in_showevents->integer) {
Com_Printf("MOUSE3: %s\n", isDown ? "down" : "up");
}
}
if (buttonsDelta & 4) {
isDown = buttons & 4;
Sys_QueEvent(currentTime, SE_KEY, K_MOUSE3, isDown, 0, NULL);
if (in_showevents->integer) {
Com_Printf("MOUSE1: %s\n", isDown ? "down" : "up");
}
}
if (buttonsDelta & 8) {
isDown = buttons & 8;
Sys_QueEvent(currentTime, SE_KEY, K_MOUSE4, isDown, 0, NULL);
if (in_showevents->integer) {
Com_Printf("MOUSE4: %s\n", isDown ? "down" : "up");
}
}
if (buttonsDelta & 16) {
isDown = buttons & 16;
Sys_QueEvent(currentTime, SE_KEY, K_MOUSE5, isDown, 0, NULL);
if (in_showevents->integer) {
Com_Printf("MOUSE5: %s\n", isDown ? "down" : "up");
}
}
oldButtons = buttons;
}
}
static inline void processEvent(NSEvent *event, int currentTime)
{
NSEventType eventType;
if (!inputActive)
return;
eventType = [event type];
if (in_showevents->integer)
NSLog(@"event = %@", event);
switch (eventType) {
// These six event types are ignored since we do all of our mouse down/up process via the uber-mouse system defined event. We have to accept these events however since they get enqueued and the queue will fill up if we don't.
case NSLeftMouseDown:
//Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, qtrue, 0, NULL);
return;
case NSLeftMouseUp:
//Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, qfalse, 0, NULL);
return;
case NSRightMouseDown:
//Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, qtrue, 0, NULL);
return;
case NSRightMouseUp:
//Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, qfalse, 0, NULL);
return;
case 25: // other mouse down
return;
case 26: // other mouse up
return;
case NSMouseMoved:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case 27: // other mouse dragged
Sys_ProcessMouseMovedEvent(event, currentTime);
return;
case NSKeyDown:
case NSKeyUp:
processKeyEvent(event, eventType == NSKeyDown, currentTime);
return;
case NSFlagsChanged:
processFlagsChangedEvent(event, currentTime);
return;
case NSSystemDefined:
processSystemDefinedEvent(event, currentTime);
return;
case NSScrollWheel:
if ([event deltaY] < 0.0) {
Sys_QueEvent(currentTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
Sys_QueEvent(currentTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
} else {
Sys_QueEvent(currentTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
Sys_QueEvent(currentTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
}
return;
default:
break;
}
[NSApp sendEvent:event];
}
static void Sys_SendKeyEvents(int currentTime)
{
#ifndef DEDICATED
NSEvent *event;
NSDate *timeout;
extern float SNDDMA_GetBufferDuration();
timeout = distantPast;
if (Sys_IsHidden)
timeout = [NSDate dateWithTimeIntervalSinceNow: 0.25 * SNDDMA_GetBufferDuration()];
// This gets call regardless of whether inputActive is true or not. This is important since we need to be poking the event queue in order for the unhide event to make its way through the system. This means that when we hide, we can just shut down the input system and reeanbled it when we unhide.
while ((event = [NSApp nextEventMatchingMask: NSAnyEventMask
untilDate: timeout
inMode: NSDefaultRunLoopMode
dequeue:YES])) {
if (Sys_IsHidden) {
// Just let NSApp handle events so that we'll get the app activation event
[NSApp sendEvent: event];
timeout = [NSDate dateWithTimeIntervalSinceNow: 0.1];
} else {
static int lastEventTime = 0;
static BOOL lastEventTimeValid = NO;
// Mac OS X 10.0.3 has a bug where the if the monitor goes to sleep in fullscreen GL mode, the gamma won't be restored. We'll restore the gamma if there is a pause while in the game of more than 10 seconds. We don't do this on the 'Sys_IsHidden' branch since unhiding will restore the monitor gamma.
if ((currentTime - lastEventTime > 1 * 1000) && lastEventTimeValid) {
//Com_Printf("Restoring monitor gamma after being idle for %f seconds.\n", (currentTime - lastEventTime) / 1000.0);
[NSCursor hide];
Sys_SetScreenFade(&glw_state.inGameTable, 1.0);
}
lastEventTime = [event timestamp] * 1000.0; //currentTime;
lastEventTimeValid = YES;
processEvent(event, lastEventTime);
}
}
#endif
}
/*
========================================================================
EVENT LOOP
========================================================================
*/
extern qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message );
#define MAX_QUED_EVENTS 256
#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
static sysEvent_t eventQue[MAX_QUED_EVENTS];
static int eventHead, eventTail;
static byte sys_packetReceived[MAX_MSGLEN];
/*
================
Sys_QueEvent
A time of 0 will get the current time
Ptr should either be null, or point to a block of data that can
be freed by the game later.
================
*/
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
sysEvent_t *ev;
int i,j;
#ifndef DEDICATED
if (in_showevents->integer)
NSLog(@"EVENT ENQUEUE: time=%d type=%d value=0x%08x value2=0x%08x\n", time, type, value, value2);
#endif
if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
Com_Printf("Sys_QueEvent: overflow\n");
}
if ( !time ) {
time = Sys_Milliseconds();
}
// insert it by time
for ( i = eventTail ; i < eventHead ; i++ ) {
ev = &eventQue[ i & MASK_QUED_EVENTS ];
if ( ev->evTime > time ) {
break;
}
}
// insert before i
for ( j = eventHead ; j > i ; j-- ) {
eventQue[ j & MASK_QUED_EVENTS ] = eventQue[ (j-1) & MASK_QUED_EVENTS ];
}
ev = &eventQue[ i & MASK_QUED_EVENTS ];
eventHead++;
ev->evTime = time;
ev->evType = type;
ev->evValue = value;
ev->evValue2 = value2;
ev->evPtrLength = ptrLength;
ev->evPtr = ptr;
}
/*
================
Sys_GetEvent
================
*/
sysEvent_t Sys_GetEvent( void )
{
sysEvent_t ev;
char *s;
msg_t netmsg;
netadr_t adr;
int currentTime;
// return if we have data
if (eventHead > eventTail) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// The queue must be empty. Check all of the event sources. If the events are
// already in the queue, we can't imply any real ordering, so we'll avoid extra
// system calls and give them all the same time.
currentTime = Sys_Milliseconds();
// Check for mouse and keyboard events
Sys_SendKeyEvents(currentTime);
// check for console commands
s = Sys_ConsoleInput();
if ( s ) {
char *b;
int len;
len = strlen( s ) + 1;
b = Z_Malloc( len );
strcpy( b, s );
Sys_QueEvent( currentTime, SE_CONSOLE, 0, 0, len, b );
}
// During debugging it is sometimes usefull to be able to start/stop mouse input.
// Don't turn on the input when we've disabled it because we're hidden, however.
if (!com_dedicated->integer) {
if (in_nomouse->integer == mouseactive && !Sys_IsHidden) {
if (in_nomouse->integer)
Sys_StopMouseInput();
else
Sys_StartMouseInput();
}
}
// check for network packets
MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
if ( Sys_GetPacket ( &adr, &netmsg ) ) {
netadr_t *buf;
int len;
// copy out to a seperate buffer for qeueing
len = sizeof( netadr_t ) + netmsg.cursize;
buf = Z_Malloc( len );
*buf = adr;
memcpy( buf+1, netmsg.data, netmsg.cursize );
Sys_QueEvent( currentTime, SE_PACKET, 0, 0, len, buf );
}
// If we got an event, return it
if (eventHead > eventTail) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// Otherwise, return an empty event to indicate that there are no events pending.
memset( &ev, 0, sizeof( ev ) );
ev.evTime = currentTime;
return ev;
}

129
code/macosx/macosx_local.h Normal file
View file

@ -0,0 +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

5095
code/macosx/macosx_qgl.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +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) {
}

205
code/macosx/macosx_snddma.m Normal file
View file

@ -0,0 +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) {
}

537
code/macosx/macosx_sys.m Normal file
View file

@ -0,0 +1,537 @@
/*
===========================================================================
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 "../client/client.h"
#import "macosx_local.h"
#import "dlfcn.h"
#import "Q3Controller.h"
#import <AppKit/AppKit.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOBSD.h>
#import <IOKit/storage/IOCDMedia.h>
#import <mach/mach_error.h>
#import <sys/types.h>
#import <unistd.h>
#import <sys/param.h>
#import <sys/mount.h>
#import <sys/sysctl.h>
#ifdef OMNI_TIMER
#import "macosx_timers.h"
#endif
qboolean stdin_active = qfalse;
//===========================================================================
int main(int argc, const char *argv[]) {
#ifdef DEDICATED
Q3Controller *controller;
stdin_active = qtrue;
controller = [[Q3Controller alloc] init];
[controller quakeMain];
return 0;
#else
return NSApplicationMain(argc, argv);
#endif
}
//===========================================================================
/*
=================
Sys_UnloadDll
=================
*/
void Sys_UnloadDll( void *dllHandle ) {
if ( !dllHandle ) {
return;
}
dlclose( dllHandle );
}
/*
=================
Sys_LoadDll
Used to load a development dll instead of a virtual machine
=================
*/
extern char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
void * QDECL Sys_LoadDll( const char *name, char *fqpath , int (QDECL **entryPoint)(int, ...),
int (QDECL *systemcalls)(int, ...) ) {
void *libHandle;
void (*dllEntry)( int (*syscallptr)(int, ...) );
NSString *bundlePath, *libraryPath;
const char *path;
// TTimo
// I don't understand the search strategy here. How can the Quake3 bundle know about the location
// of the other bundles? is that configured somewhere in XCode?
/*
bundlePath = [[NSBundle mainBundle] pathForResource: [NSString stringWithCString: name] ofType: @"bundle"];
libraryPath = [NSString stringWithFormat: @"%@/Contents/MacOS/%s", bundlePath, name];
*/
libraryPath = [NSString stringWithFormat: @"%s.bundle/Contents/MacOS/%s", name, name];
if (!libraryPath)
return NULL;
path = [libraryPath cString];
Com_Printf("Loading '%s'.\n", path);
libHandle = dlopen( [libraryPath cString], RTLD_LAZY );
if (!libHandle) {
libHandle = dlopen( name, RTLD_LAZY );
if (!libHandle) {
Com_Printf("Error loading dll: %s\n", dlerror());
return NULL;
}
}
dllEntry = dlsym( libHandle, "_dllEntry" );
if (!dllEntry) {
Com_Printf("Error loading dll: No dllEntry symbol.\n");
dlclose(libHandle);
return NULL;
}
*entryPoint = dlsym( libHandle, "_vmMain" );
if (!*entryPoint) {
Com_Printf("Error loading dll: No vmMain symbol.\n");
dlclose(libHandle);
return NULL;
}
dllEntry(systemcalls);
return libHandle;
}
//===========================================================================
char *Sys_GetClipboardData(void) // FIXME
{
NSPasteboard *pasteboard;
NSArray *pasteboardTypes;
pasteboard = [NSPasteboard generalPasteboard];
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *clipboardString;
clipboardString = [pasteboard stringForType:NSStringPboardType];
if (clipboardString && [clipboardString length] > 0) {
return strdup([clipboardString cString]);
}
}
return NULL;
}
char *Sys_GetWholeClipboard ( void )
{
return NULL;
}
void Sys_SetClipboard (const char *contents)
{
}
/*
==================
Sys_FunctionCheckSum
==================
*/
int Sys_FunctionCheckSum(void *f1) {
return 0;
}
/*
==================
Sys_MonkeyShouldBeSpanked
==================
*/
int Sys_MonkeyShouldBeSpanked( void ) {
return 0;
}
//===========================================================================
void Sys_BeginProfiling(void)
{
}
void Sys_EndProfiling(void)
{
}
//===========================================================================
/*
================
Sys_Init
The cvar and file system has been setup, so configurations are loaded
================
*/
void Sys_Init(void)
{
#ifdef OMNI_TIMER
InitializeTimers();
OTStackPushRoot(rootNode);
#endif
NET_Init();
Sys_InitInput();
}
/*
=================
Sys_Shutdown
=================
*/
void Sys_Shutdown(void)
{
Com_Printf( "----- Sys_Shutdown -----\n" );
Sys_EndProfiling();
Sys_ShutdownInput();
Com_Printf( "------------------------\n" );
}
void Sys_Error(const char *error, ...)
{
va_list argptr;
NSString *formattedString;
Sys_Shutdown();
va_start(argptr,error);
formattedString = [[NSString alloc] initWithFormat:[NSString stringWithCString:error] arguments:argptr];
va_end(argptr);
NSLog(@"Sys_Error: %@", formattedString);
NSRunAlertPanel(@"Quake 3 Error", formattedString, nil, nil, nil);
Sys_Quit();
}
void Sys_Quit(void)
{
Sys_Shutdown();
[NSApp terminate:nil];
}
/*
================
Sys_Print
This is called for all console output, even if the game is running
full screen and the dedicated console window is hidden.
================
*/
char *ansiColors[8] =
{ "\033[30m" , /* ANSI Black */
"\033[31m" , /* ANSI Red */
"\033[32m" , /* ANSI Green */
"\033[33m" , /* ANSI Yellow */
"\033[34m" , /* ANSI Blue */
"\033[36m" , /* ANSI Cyan */
"\033[35m" , /* ANSI Magenta */
"\033[37m" }; /* ANSI White */
void Sys_Print(const char *text)
{
#if 0
/* Okay, this is a stupid hack, but what the hell, I was bored. ;) */
const char *scan = text;
int index;
/* Make sure terminal mode is reset at the start of the line... */
fputs("\033[0m", stdout);
while(*scan) {
/* See if we have a color control code. If so, snarf the character,
print what we have so far, print the ANSI Terminal color code,
skip over the color control code and continue */
if(Q_IsColorString(scan)) {
index = ColorIndex(scan[1]);
/* Flush current message */
if(scan != text) {
fwrite(text, scan - text, 1, stdout);
}
/* Write ANSI color code */
fputs(ansiColors[index], stdout);
/* Reset search */
text = scan+2;
scan = text;
continue;
}
scan++;
}
/* Flush whatever's left */
fputs(text, stdout);
/* Make sure terminal mode is reset at the end of the line too... */
fputs("\033[0m", stdout);
#else
fputs(text, stdout);
#endif
}
/*
================
Sys_CheckCD
Return true if the proper CD is in the drive
================
*/
qboolean Sys_ObjectIsCDRomDevice(io_object_t object)
{
CFStringRef value;
kern_return_t krc;
CFDictionaryRef properties;
qboolean isCDROM = qfalse;
io_iterator_t parentIterator;
io_object_t parent;
krc = IORegistryEntryCreateCFProperties(object, &properties, kCFAllocatorDefault, (IOOptionBits)0);
if (krc != KERN_SUCCESS) {
fprintf(stderr, "IORegistryEntryCreateCFProperties returned 0x%08x -- %s\n", krc, mach_error_string(krc));
return qfalse;
}
//NSLog(@"properties = %@", properties);
// See if this is a CD-ROM
value = CFDictionaryGetValue(properties, CFSTR(kIOCDMediaTypeKey));
if (value && CFStringCompare(value, CFSTR("CD-ROM"), 0) == kCFCompareEqualTo)
isCDROM = qtrue;
CFRelease(properties);
// If it isn't check each of its parents. It seems that the parent enumerator only returns the immediate parent. Maybe the plural indicates that an object can have multiple direct parents. So, we'll call ourselves recursively for each parent.
if (!isCDROM) {
krc = IORegistryEntryGetParentIterator(object, kIOServicePlane, &parentIterator);
if (krc != KERN_SUCCESS) {
fprintf(stderr, "IOServiceGetMatchingServices returned 0x%08x -- %s\n",
krc, mach_error_string(krc));
} else {
while (!isCDROM && (parent = IOIteratorNext(parentIterator))) {
if (Sys_ObjectIsCDRomDevice(parent))
isCDROM = qtrue;
IOObjectRelease(parent);
}
IOObjectRelease(parentIterator);
}
}
//NSLog(@"Sys_ObjectIsCDRomDevice -> %d", isCDROM);
return isCDROM;
}
qboolean Sys_IsCDROMDevice(const char *deviceName)
{
kern_return_t krc;
io_iterator_t deviceIterator;
mach_port_t masterPort;
io_object_t object;
qboolean isCDROM = qfalse;
krc = IOMasterPort(bootstrap_port, &masterPort);
if (krc != KERN_SUCCESS) {
fprintf(stderr, "IOMasterPort returned 0x%08x -- %s\n", krc, mach_error_string(krc));
return qfalse;
}
// Get an iterator for this BSD device. If it is a CD, it will likely only be one partition of the larger CD-ROM device.
krc = IOServiceGetMatchingServices(masterPort,
IOBSDNameMatching(masterPort, 0, deviceName),
&deviceIterator);
if (krc != KERN_SUCCESS) {
fprintf(stderr, "IOServiceGetMatchingServices returned 0x%08x -- %s\n",
krc, mach_error_string(krc));
return qfalse;
}
while (!isCDROM && (object = IOIteratorNext(deviceIterator))) {
if (Sys_ObjectIsCDRomDevice(object)) {
isCDROM = qtrue;
}
IOObjectRelease(object);
}
IOObjectRelease(deviceIterator);
//NSLog(@"Sys_IsCDROMDevice -> %d", isCDROM);
return isCDROM;
}
qboolean Sys_CheckCD( void )
{
// DO NOT just return success here if we have a library directory.
// Actually look for the CD.
// We'll look through the actual mount points rather than just looking
// for a particular directory since (a) the mount point may change
// between OS version (/foo in Public Beta, /Volumes/foo after Public Beta)
// and (b) this way someone can't just create a directory and warez the files.
unsigned int mountCount;
struct statfs *mounts;
mountCount = getmntinfo(&mounts, MNT_NOWAIT);
if (mountCount <= 0) {
perror("getmntinfo");
#if 1 // Q3:TA doesn't need a CD, but we still need to locate it to allow for partial installs
return qtrue;
#else
return qfalse;
#endif
}
while (mountCount--) {
const char *lastComponent;
if ((mounts[mountCount].f_flags & MNT_RDONLY) != MNT_RDONLY) {
// Should have been a read only CD... this isn't it
continue;
}
if ((mounts[mountCount].f_flags & MNT_LOCAL) != MNT_LOCAL) {
// Should have been a local filesystem
continue;
}
lastComponent = strrchr(mounts[mountCount].f_mntonname, '/');
if (!lastComponent) {
// No slash in the mount point! How is that possible?
continue;
}
// Skip the slash and look for the game name
lastComponent++;
if ((strcasecmp(lastComponent, "Quake3") != 0)) {
continue;
}
#if 0
fprintf(stderr, "f_bsize: %d\n", mounts[mountCount].f_bsize);
fprintf(stderr, "f_blocks: %d\n", mounts[mountCount].f_blocks);
fprintf(stderr, "type: %d\n", mounts[mountCount].f_type);
fprintf(stderr, "flags: %d\n", mounts[mountCount].f_flags);
fprintf(stderr, "fstype: %s\n", mounts[mountCount].f_fstypename);
fprintf(stderr, "f_mntonname: %s\n", mounts[mountCount].f_mntonname);
fprintf(stderr, "f_mntfromname: %s\n", mounts[mountCount].f_mntfromname);
fprintf(stderr, "\n\n");
#endif
lastComponent = strrchr(mounts[mountCount].f_mntfromname, '/');
if (!lastComponent) {
// No slash in the device name! How is that possible?
continue;
}
lastComponent++;
if (!Sys_IsCDROMDevice(lastComponent))
continue;
// This looks good
Sys_SetDefaultCDPath(mounts[mountCount].f_mntonname);
return qtrue;
}
#if 1 // Q3:TA doesn't need a CD, but we still need to locate it to allow for partial installs
return qtrue;
#else
return qfalse;
#endif
}
//===================================================================
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
}
void Sys_EndStreamedFile( fileHandle_t f ) {
}
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
return FS_Read( buffer, size * count, f );
}
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
FS_Seek( f, offset, origin );
}
void OutputDebugString(char * s)
{
#ifdef DEBUG
fprintf(stderr, "%s", s);
#endif
}
/*
==================
Sys_LowPhysicalMemory()
==================
*/
#define MEM_THRESHOLD 96*1024*1024
qboolean Sys_LowPhysicalMemory()
{
return NSRealMemoryAvailable() <= MEM_THRESHOLD;
}
static unsigned int _Sys_ProcessorCount = 0;
unsigned int Sys_ProcessorCount()
{
if (!_Sys_ProcessorCount) {
int name[] = {CTL_HW, HW_NCPU};
size_t size;
size = sizeof(_Sys_ProcessorCount);
if (sysctl(name, 2, &_Sys_ProcessorCount, &size, NULL, 0) < 0) {
perror("sysctl");
_Sys_ProcessorCount = 1;
} else {
Com_Printf("System processor count is %d\n", _Sys_ProcessorCount);
}
}
return _Sys_ProcessorCount;
}

View file

@ -0,0 +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

View file

@ -0,0 +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

26
code/macosx/timedemo.zsh Normal file
View file

@ -0,0 +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