e1ab049608
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3239 fc73d0e0-1445-4013-8a0c-d673dee63da5
636 lines
11 KiB
Objective-C
636 lines
11 KiB
Objective-C
/*
|
|
|
|
Copyright (C) 2001-2002 A Nourai
|
|
Copyright (C) 2006 Jacek Piszczek (Mac OSX port)
|
|
|
|
This program 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.
|
|
|
|
This program 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 included (GNU.txt) GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
#import <Quartz/Quartz.h>
|
|
#include "quakedef.h"
|
|
|
|
id _p;
|
|
extern float mouse_x,mouse_y;
|
|
int evcnt = 2;
|
|
|
|
// Jacek: some keys are bogus, my ibook kb lacks keys and apple's docs lack
|
|
// keyCode documentation
|
|
|
|
unsigned char keyconv[] =
|
|
{
|
|
'a', /* 0 */
|
|
's',
|
|
'd',
|
|
'f',
|
|
'h',
|
|
'g',
|
|
'z',
|
|
'x',
|
|
'c',
|
|
'v',
|
|
'0', /* 10 */
|
|
'b',
|
|
'q',
|
|
'w',
|
|
'e',
|
|
'r',
|
|
'y',
|
|
't',
|
|
'1',
|
|
'2',
|
|
'3', /* 20 */
|
|
'4',
|
|
'6',
|
|
'5',
|
|
'=',
|
|
'9',
|
|
'7',
|
|
'-',
|
|
'8',
|
|
'0',
|
|
']', /* 30 */
|
|
'o',
|
|
'u',
|
|
'[',
|
|
'i',
|
|
'p',
|
|
K_ENTER,
|
|
'l',
|
|
'j',
|
|
'\'',
|
|
'k', /* 40 */
|
|
';',
|
|
'\\',
|
|
',',
|
|
'/',
|
|
'n',
|
|
'm',
|
|
'.',
|
|
K_TAB,
|
|
K_SPACE,
|
|
'`', /* 50 */
|
|
K_BACKSPACE,
|
|
'v',
|
|
K_ESCAPE,
|
|
'n',
|
|
'm',
|
|
',',
|
|
'.',
|
|
'/',
|
|
0,
|
|
K_KP_DEL, /* 60 */
|
|
K_KP_HOME,
|
|
K_KP_UPARROW,
|
|
K_KP_PGUP,
|
|
' ',
|
|
K_KP_DEL,
|
|
K_TAB,
|
|
K_KP_STAR,
|
|
K_ENTER,
|
|
K_KP_PLUS,
|
|
K_DEL, /* 70 */
|
|
K_INS,
|
|
K_PGUP,
|
|
K_PGDN,
|
|
K_KP_MINUS,
|
|
K_KP_SLASH,
|
|
K_KP_ENTER,
|
|
0,
|
|
K_KP_MINUS,
|
|
0,
|
|
K_F1, /* 80 */
|
|
K_F2,
|
|
K_KP_INS,
|
|
K_KP_END,
|
|
K_KP_DOWNARROW,
|
|
K_KP_PGDN,
|
|
K_KP_LEFTARROW,
|
|
K_KP_5,
|
|
K_KP_RIGHTARROW,
|
|
K_KP_HOME,
|
|
0, /* 90 */
|
|
K_KP_UPARROW,
|
|
K_KP_PGUP,
|
|
0,
|
|
K_KP_PLUS,
|
|
0,
|
|
K_LSHIFT,
|
|
K_RSHIFT,
|
|
0,
|
|
K_RCTRL,
|
|
K_ALT, /* 100 */
|
|
K_ALT,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
K_PAUSE, /* 110 */
|
|
K_F12,
|
|
0,
|
|
0,
|
|
0,
|
|
K_HOME,
|
|
K_PGUP,
|
|
K_DEL,
|
|
0,
|
|
K_END,
|
|
0, /* 120 */
|
|
K_PGDN,
|
|
0,
|
|
K_LEFTARROW,
|
|
K_RIGHTARROW,
|
|
K_DOWNARROW,
|
|
K_UPARROW,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 130 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 140 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 150 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 160 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 170 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 180 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 190 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 200 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 210 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 220 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 230 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 240 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* 250 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
// validate the depth
|
|
int checkDepth(int d)
|
|
{
|
|
if (d == 24)
|
|
d = 32;
|
|
if (d != 15 && d != 16 && d != 32)
|
|
d = 32;
|
|
|
|
return d;
|
|
}
|
|
|
|
@interface FTEApplication : NSApplication
|
|
{
|
|
NSOpenGLContext *_openGLContext;
|
|
NSTimer *_timer;
|
|
double time, oldtime, newtime;
|
|
unsigned int oldmflags;
|
|
CFDictionaryRef olddmode;
|
|
}
|
|
- (void)initDisplayWidth:(int)width height:(int)height depth:(int)depth;
|
|
- (void)flushBuffer;
|
|
- (void)runLoop:(NSTimer *)timer;
|
|
@end
|
|
|
|
@implementation FTEApplication
|
|
|
|
- (id)init
|
|
{
|
|
if((self = [super init]))
|
|
[self setDelegate:self];
|
|
|
|
oldmflags = 0;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)initDisplayWidth:(int)width height:(int)height depth:(int)depth;
|
|
{
|
|
long value = 1;
|
|
NSOpenGLPixelFormat* format;
|
|
NSOpenGLPixelFormatAttribute attributes[] = {
|
|
NSOpenGLPFAFullScreen,
|
|
NSOpenGLPFAScreenMask,
|
|
CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
|
|
NSOpenGLPFANoRecovery,
|
|
NSOpenGLPFADoubleBuffer,
|
|
NSOpenGLPFAAccelerated,
|
|
NSOpenGLPFADepthSize, checkDepth(depth),
|
|
0};
|
|
|
|
olddmode = CGDisplayCurrentMode(kCGDirectMainDisplay);
|
|
|
|
// zeros mean we use the default screen! (but with 32bit depth)
|
|
if (!((width == 0) && (height == 0) && (depth == 0)))
|
|
{
|
|
depth = checkDepth(depth);
|
|
if (width == 0)
|
|
width = CGDisplayPixelsWide(kCGDirectMainDisplay);
|
|
if (height == 0)
|
|
height = CGDisplayPixelsHigh(kCGDirectMainDisplay);
|
|
CFDictionaryRef dmode = CGDisplayBestModeForParameters(
|
|
kCGDirectMainDisplay,
|
|
checkDepth(depth),
|
|
width,
|
|
height,
|
|
FALSE);
|
|
CGDisplaySwitchToMode(kCGDirectMainDisplay,dmode);
|
|
}
|
|
|
|
// get screen size
|
|
vid.width = CGDisplayPixelsWide(kCGDirectMainDisplay);
|
|
vid.height = CGDisplayPixelsHigh(kCGDirectMainDisplay);
|
|
|
|
// capture the display!
|
|
CGDisplayCapture(kCGDirectMainDisplay);
|
|
CGDisplayHideCursor(kCGDirectMainDisplay);
|
|
CGAssociateMouseAndMouseCursorPosition(false);
|
|
|
|
format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
|
_openGLContext = [[NSOpenGLContext alloc]
|
|
initWithFormat:format
|
|
shareContext:nil];
|
|
[format release];
|
|
if(_openGLContext == nil)
|
|
{
|
|
NSLog(@"Cannot create OpenGL context");
|
|
[NSApp terminate:nil];
|
|
return;
|
|
}
|
|
|
|
[_openGLContext setFullScreen];
|
|
[_openGLContext setValues:&value forParameter:kCGLCPSwapInterval];
|
|
|
|
[_openGLContext makeCurrentContext];
|
|
|
|
_timer = [[NSTimer scheduledTimerWithTimeInterval:1.0/250.0
|
|
target:self
|
|
selector:@selector(runLoop:)
|
|
userInfo:nil
|
|
repeats:YES]
|
|
retain];
|
|
|
|
[[NSApp mainWindow] setAcceptsMouseMovedEvents:YES];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
CGAssociateMouseAndMouseCursorPosition(true);
|
|
CGDisplayRelease(kCGDirectMainDisplay);
|
|
CGDisplayRestoreColorSyncSettings();
|
|
CGDisplaySwitchToMode(kCGDirectMainDisplay,olddmode);
|
|
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,
|
|
CGPointMake(vid.width/2,vid.height/2));
|
|
[_openGLContext release];
|
|
[_timer invalidate];
|
|
[_timer release];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void) sendEvent:(NSEvent*)event
|
|
{
|
|
if ([event type] == NSKeyDown)
|
|
{
|
|
int code = keyconv[[event keyCode]]
|
|
Key_Event(code, code, TRUE);
|
|
//printf("%d\n",[event keyCode]);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSKeyUp)
|
|
{
|
|
int code = keyconv[[event keyCode]];
|
|
Key_Event(code, code, FALSE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSFlagsChanged)
|
|
{
|
|
unsigned int mflags = [event modifierFlags];
|
|
|
|
if ((mflags & NSAlternateKeyMask) ^ (oldmflags & NSAlternateKeyMask))
|
|
{
|
|
Key_Event(K_ALT, 0, (mflags & NSAlternateKeyMask) ? TRUE : FALSE);
|
|
}
|
|
|
|
if ((mflags & NSControlKeyMask) ^ (oldmflags & NSControlKeyMask))
|
|
{
|
|
Key_Event(K_LCTRL, 0, (mflags & NSControlKeyMask) ? TRUE : FALSE);
|
|
}
|
|
|
|
if ((mflags & NSShiftKeyMask) ^ (oldmflags & NSShiftKeyMask))
|
|
{
|
|
Key_Event(K_LSHIFT, 0, (mflags & NSShiftKeyMask) ? TRUE : FALSE);
|
|
}
|
|
|
|
if ((mflags & NSCommandKeyMask) ^ (oldmflags & NSCommandKeyMask))
|
|
{
|
|
Key_Event(K_LWIN, 0, (mflags & NSCommandKeyMask) ? TRUE : FALSE);
|
|
}
|
|
|
|
if ((mflags & NSAlphaShiftKeyMask) ^ (oldmflags & NSAlphaShiftKeyMask))
|
|
{
|
|
Key_Event(K_CAPSLOCK, 0, (mflags & NSAlphaShiftKeyMask) ? TRUE : FALSE);
|
|
}
|
|
|
|
oldmflags = mflags;
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSMouseMoved)
|
|
{
|
|
mouse_x += [event deltaX];
|
|
mouse_y += [event deltaY];
|
|
|
|
// lame hack to avoid mouse ptr moving to the top of the screen since
|
|
// a click there causes the mouse to appear and lock the event stream
|
|
// Apple sucks :(
|
|
// NOTE: it seems this is still needed for 10.3.x!
|
|
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,
|
|
CGPointMake(vid.width - 1,vid.height - 1));
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSLeftMouseDragged)
|
|
{
|
|
mouse_x += [event deltaX];
|
|
mouse_y += [event deltaY];
|
|
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,
|
|
CGPointMake(vid.width - 1,vid.height - 1));
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSRightMouseDragged)
|
|
{
|
|
mouse_x += [event deltaX];
|
|
mouse_y += [event deltaY];
|
|
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,
|
|
CGPointMake(vid.width - 1,vid.height - 1));
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSOtherMouseDragged)
|
|
{
|
|
mouse_x += [event deltaX];
|
|
mouse_y += [event deltaY];
|
|
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,
|
|
CGPointMake(vid.width - 1,vid.height - 1));
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSLeftMouseDown)
|
|
{
|
|
Key_Event(K_MOUSE1, 0, TRUE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSLeftMouseUp)
|
|
{
|
|
Key_Event(K_MOUSE1, 0, FALSE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSRightMouseDown)
|
|
{
|
|
Key_Event(K_MOUSE2, 0, TRUE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSRightMouseUp)
|
|
{
|
|
Key_Event(K_MOUSE2, 0, FALSE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSOtherMouseDown)
|
|
{
|
|
Key_Event(K_MOUSE3, 0, TRUE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSOtherMouseUp)
|
|
{
|
|
Key_Event(K_MOUSE3, 0, FALSE);
|
|
return;
|
|
}
|
|
|
|
if ([event type] == NSScrollWheel)
|
|
{
|
|
Key_Event(([event deltaY] > 0.0) ? K_MWHEELUP : K_MWHEELDOWN, 0, TRUE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
- (void)flushBuffer
|
|
{
|
|
// synchronise display
|
|
[_openGLContext flushBuffer];
|
|
}
|
|
|
|
// called on a timer event
|
|
- (void)runLoop:(NSTimer *)timer
|
|
{
|
|
newtime = Sys_DoubleTime ();
|
|
time = newtime - oldtime;
|
|
oldtime = newtime;
|
|
|
|
Host_Frame(time);
|
|
}
|
|
|
|
- (void)run
|
|
{
|
|
oldtime = Sys_DoubleTime ();
|
|
[super run];
|
|
}
|
|
|
|
@end
|
|
|
|
static FTEApplication *fteglapp;
|
|
|
|
BOOL initCocoa(rendererstate_t *info)
|
|
{
|
|
// init the application the hard way since we don't want to run it
|
|
// immediately
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
fteglapp = [FTEApplication sharedApplication];
|
|
|
|
// store the var for later disposal
|
|
_p = pool;
|
|
|
|
// init the display
|
|
[fteglapp initDisplayWidth:info->width height:info->height depth:info->bpp];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
qboolean glcocoaRunLoop(void)
|
|
{
|
|
if (!fteglapp)
|
|
return false;
|
|
// this will initialise the NSTimer and run the app
|
|
[NSApp run];
|
|
|
|
return true;
|
|
}
|
|
|
|
void killCocoa(void)
|
|
{
|
|
// terminates FTEApplicaiton
|
|
[NSApp terminate:nil];
|
|
[_p release];
|
|
|
|
fteglapp = NULL;
|
|
}
|
|
|
|
void flushCocoa(void)
|
|
{
|
|
// synchronises display
|
|
[NSApp flushBuffer];
|
|
}
|
|
|
|
void cocoaGamma(unsigned short *r,unsigned short *g,unsigned short *b)
|
|
{
|
|
CGByteValue gammatable[3*256];
|
|
int i;
|
|
|
|
// convert the gamma values
|
|
for(i=0;i<256;i++)
|
|
{
|
|
gammatable[i] = r[i] >> 8;
|
|
gammatable[i+256] = g[i] >> 8;
|
|
gammatable[i+512] = b[i] >> 8;
|
|
}
|
|
|
|
//... and set them
|
|
CGSetDisplayTransferByByteTable(kCGDirectMainDisplay,256,
|
|
gammatable,
|
|
gammatable + 256,
|
|
gammatable + 512);
|
|
}
|