From e59d02ed523ee411136d639a120d3e5cba4da436 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 23 Sep 2007 22:00:19 +0000 Subject: [PATCH] We now have a really crappy gl renderer for macosx. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2689 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 26 +- engine/client/in_macos.c | 97 ++++++ engine/client/keys.h | 5 + engine/client/snd_dma.c | 2 + engine/client/snd_macos.c | 258 ++++++++++++++++ engine/client/sys_linux.c | 19 ++ engine/common/qvm.c | 4 + engine/gl/gl_vidcocoa.m | 634 ++++++++++++++++++++++++++++++++++++++ engine/gl/gl_vidmacos.c | 239 ++++++++++++++ 9 files changed, 1281 insertions(+), 3 deletions(-) create mode 100644 engine/client/in_macos.c create mode 100644 engine/client/snd_macos.c create mode 100644 engine/gl/gl_vidcocoa.m create mode 100644 engine/gl/gl_vidmacos.c diff --git a/engine/Makefile b/engine/Makefile index 6ac01463..57bcbffc 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -575,12 +575,25 @@ ifeq ($(FTE_TARGET),macosx) SWCL_DIR=sw_macosx GL_CFLAGS=$(GLCFLAGS) -D__MACOSX__ - GL_LDFLAGS=-framework AGL -framework OpenGL - GLCL_OBJS=$(GL_OBJS) $(GLQUAKE_OBJS) gl_vidmac.o sys_linux.o cd_null.o + GL_LDFLAGS=-framework AGL -framework OpenGL -framework Cocoa -framework AudioUnit + GLCL_OBJS=$(GL_OBJS) $(GLQUAKE_OBJS) gl_vidcocoa.mo gl_vidmacos.o sys_linux.o in_macos.o cd_null.o snd_macos.o SW_CFLAGS=$(SWCFLAGS) -D__MACOSX__ SW_LDFLAGS= - SWCL_OBJS=$(SOFTWARE_OBJS) cd_null.o sys_linux.o + SWCL_OBJS=$(SOFTWARE_OBJS) cd_null.o sys_linux.o vid_null.o + + GL_EXE_NAME=../fteqw.gl + GLCL_EXE_NAME=../fteqwcl.gl + SW_EXE_NAME=../fteqw.sw + SWCL_EXE_NAME=../fteqwcl.sw + M_EXE_NAME=../fteqw + MCL_EXE_NAME=../fteqwcl + MINGL_EXE_NAME=../fteqw.mingl + MINGL_DIR=mingl_morphos + + + #seems, macosx has a more limited version of strip + STRIPFLAGS= endif ifeq ($(FTE_TARGET),morphos) @@ -714,6 +727,13 @@ $(OUT_DIR)/%.oo $(OUT_DIR)/%.d : %.c rm -f $@.d.$$$$ $(DO_CC) -I$(OUT_DIR) +$(OUT_DIR)/%.mo $(OUT_DIR)/%.d : %.m + @set -e; rm -f $@.d; \ + $(CC) -MM $(ALL_CFLAGS) $< > $@.d.$$$$; \ + sed 's,\($*\)\.mo[ :]*,\1.mo $@.d : ,g' < $@.d.$$$$ > $@.d; \ + rm -f $@.d.$$$$ + $(DO_CC) -I$(OUT_DIR) + ifeq ($(USEASM),true) $(OUT_DIR)/%.o : %.s sw/*.h $(DO_AS) diff --git a/engine/client/in_macos.c b/engine/client/in_macos.c new file mode 100644 index 00000000..ed64d84b --- /dev/null +++ b/engine/client/in_macos.c @@ -0,0 +1,97 @@ +/* + + 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. +*/ + +#include "quakedef.h" + +float mouse_x,mouse_y; +float old_mouse_x,old_mouse_y; + +cvar_t m_filter = SCVARF("m_filter", "1", CVAR_ARCHIVE); + +void IN_Init (void) +{ + Cvar_Register (&m_filter, "input values"); +} + +void IN_ReInit(void) +{ +} + +void IN_Shutdown (void) +{ +} + +void IN_Commands (void) +{ +} +// oportunity for devices to stick commands on the script buffer + +void IN_ModeChanged (void) +{ +} +// called whenever screen dimensions change + +void IN_Move (usercmd_t *cmd, int pnum) +{ + float tx, ty, filterfrac; + + tx = mouse_x; + ty = mouse_y; + + if (m_filter.value) + { + filterfrac = bound(0, m_filter.value, 1) / 2.0; + mouse_x = (tx * (1 - filterfrac) + old_mouse_x * filterfrac); + mouse_y = (ty * (1 - filterfrac) + old_mouse_y * filterfrac); + } + + old_mouse_x = tx; + old_mouse_y = ty; + + mouse_x *= sensitivity.value; + mouse_y *= sensitivity.value; + + if ((in_strafe.state[pnum] & 1) || (lookstrafe.value && in_mlook.state[pnum])) + { + cmd->sidemove += m_side.value * mouse_x; + } + else + { + cl.viewangles[pnum][YAW] -= m_yaw.value * mouse_x; + } + + if (in_mlook.state[pnum]) + V_StopPitchDrift(pnum); + + if (in_mlook.state[pnum] && !(in_strafe.state[pnum] & 1)) + { + cl.viewangles[pnum][PITCH] += m_pitch.value * mouse_y; + cl.viewangles[pnum][PITCH] = bound(-70, cl.viewangles[pnum][PITCH], 80); + } + else + { + cmd->forwardmove -= m_forward.value * mouse_y; + } + + mouse_x = mouse_y = 0.0; +} +// add additional movement on top of the keyboard move cmd + diff --git a/engine/client/keys.h b/engine/client/keys.h index 82252721..ad70eb03 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -159,6 +159,11 @@ K_APP = 241, K_MAX = 256 }; +#define K_LSHIFT K_SHIFT +#define K_RSHIFT K_SHIFT +#define K_RCTRL K_CTRL +#define K_LCTRL K_CTRL + typedef enum {key_game, key_console, key_message, key_menu, key_editor} keydest_t; extern keydest_t key_dest; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index eff81bb2..74a409bd 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -144,6 +144,7 @@ void S_RunCapture(void) sounddriver pDSOUND_InitCard; sounddriver pALSA_InitCard; sounddriver pOSS_InitCard; +sounddriver pMacOS_InitCard; sounddriver pSDL_InitCard; sounddriver pWAV_InitCard; sounddriver pAHI_InitCard; @@ -157,6 +158,7 @@ sdriver_t drivers[] = { {"DSound", &pDSOUND_InitCard}, {"ALSA", &pALSA_InitCard}, {"OSS", &pOSS_InitCard}, + {"MacOS", &pMacOS_InitCard}, {"SDL", &pSDL_InitCard}, {"WaveOut", &pWAV_InitCard}, {"AHI", &pAHI_InitCard}, diff --git a/engine/client/snd_macos.c b/engine/client/snd_macos.c new file mode 100644 index 00000000..2cb23482 --- /dev/null +++ b/engine/client/snd_macos.c @@ -0,0 +1,258 @@ +/* + + 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. +*/ + +#include "quakedef.h" +#include "sound.h" +#include +#include + +// Jacek: +// coreaudio is poorly documented so I'm not 100% sure the code below +// is correct :( + +struct MacOSSound_Private +{ + AudioUnit gOutputUnit; + unsigned int readpos; +}; + +static OSStatus AudioRender(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + soundcardinfo_t *sc = inRefCon; + struct MacOSSound_Private *pdata = sc->handle; + + int start = pdata->readpos; + int buffersize = sc->sn.samples * (sc->sn.samplebits/8); + int bytes = ioData->mBuffers[0].mDataByteSize; + int remaining; + + start %= buffersize; + if (start + bytes > buffersize) + { + remaining = bytes; + bytes = buffersize - start; + remaining -= bytes; + } + else + { + remaining = 0; + } + + memcpy(ioData->mBuffers[0].mData, sc->sn.buffer + start, bytes); + memcpy((char*)ioData->mBuffers[0].mData+bytes, sc->sn.buffer, remaining); + + pdata->readpos += inNumberFrames*sc->sn.numchannels * (sc->sn.samplebits/8); + + return noErr; +} + +static void MacOS_Shutdown(soundcardinfo_t *sc) +{ + struct MacOSSound_Private *pdata = sc->handle; + sc->handle = NULL; + if (!pdata) + return; + + // stop playback + AudioOutputUnitStop (pdata->gOutputUnit); + + // release the unit + AudioUnitUninitialize (pdata->gOutputUnit); + + // free the unit + CloseComponent (pdata->gOutputUnit); + + // free the buffer memory + Z_Free(sc->sn.buffer); + Z_Free(pdata); +} + +static unsigned int MacOS_GetDMAPos(soundcardinfo_t *sc) +{ + struct MacOSSound_Private *pdata = sc->handle; + sc->sn.samplepos = pdata->readpos/(sc->sn.samplebits/8); + return sc->sn.samplepos; +} + +static void MacOS_Submit(soundcardinfo_t *sc) +{ +} + +static void *MacOS_Lock(soundcardinfo_t *sc) +{ + return sc->sn.buffer; +} + +static void MacOS_Unlock(soundcardinfo_t *sc, void *buffer) +{ +} + +static void MacOS_SetWaterDistortion(soundcardinfo_t *sc, qboolean isunderwater) +{ +} + +static int MacOS_InitCard(soundcardinfo_t *sc, int cardnum) +{ + ComponentResult err = noErr; + + if (cardnum) + return 2; /* no more */ + + struct MacOSSound_Private *pdata = Z_Malloc(sizeof(*pdata)); + if (!pdata) + return FALSE; + + // Open the default output unit + ComponentDescription desc; + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + Component comp = FindNextComponent(NULL, &desc); + if (comp == NULL) + { + Con_Printf("FindNextComponent failed\n"); + Z_Free(pdata); + return FALSE; + } + + err = OpenAComponent(comp, &pdata->gOutputUnit); + if (comp == NULL) + { + Con_Printf("OpenAComponent failed\n"); + Z_Free(pdata); + return FALSE; + } + + // Set up a callback function to generate output to the output unit + AURenderCallbackStruct input; + input.inputProc = AudioRender; + input.inputProcRefCon = sc; + + err = AudioUnitSetProperty ( pdata->gOutputUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &input, + sizeof(input)); + if (err) + { + Con_Printf("AudioUnitSetProperty failed\n"); + CloseComponent(pdata->gOutputUnit); + Z_Free(pdata); + return FALSE; + } + + // describe our audio data + AudioStreamBasicDescription streamFormat; + streamFormat.mSampleRate = sc->sn.speed; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagsNativeEndian + | kLinearPCMFormatFlagIsPacked; + //| kAudioFormatFlagIsNonInterleaved; + streamFormat.mFramesPerPacket = 1; + streamFormat.mChannelsPerFrame = 2; + streamFormat.mBitsPerChannel = 16; + if (streamFormat.mBitsPerChannel >= 16) + streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + else + streamFormat.mFormatFlags |= 0; + + streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * (streamFormat.mBitsPerChannel/8); + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; + + err = AudioUnitSetProperty (pdata->gOutputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(AudioStreamBasicDescription)); + if (err) + { + Con_Printf("AudioUnitSetProperty failed\n"); + CloseComponent(pdata->gOutputUnit); + Z_Free(pdata); + return FALSE; + } + + // set the shm structure + sc->sn.speed = streamFormat.mSampleRate; + sc->sn.samplebits = streamFormat.mBitsPerChannel; + sc->sn.numchannels = streamFormat.mChannelsPerFrame; + sc->sn.samples = 256 * 1024; + sc->sn.buffer = Z_Malloc(sc->sn.samples*sc->sn.samplebits/8); + + int i; + for (i = 0; i < sc->sn.samples*sc->sn.samplebits/8; i++) + sc->sn.buffer[i] = rand(); + + if (sc->sn.buffer == 0) + { + Con_Printf("Malloc failed - cannot allocate sound buffer\n"); + CloseComponent(pdata->gOutputUnit); + Z_Free(pdata); + return FALSE; + } + + // Initialize unit + err = AudioUnitInitialize(pdata->gOutputUnit); + if (err) + { + Con_Printf("AudioOutputInitialize failed\n"); + CloseComponent(pdata->gOutputUnit); + Z_Free(sc->sn.buffer); + Z_Free(pdata); + return FALSE; + } + + // start playing :) + err = AudioOutputUnitStart (pdata->gOutputUnit); + if (err) + { + Con_Printf("AudioOutputUnitStart failed\n"); + AudioUnitUninitialize (pdata->gOutputUnit); + CloseComponent(pdata->gOutputUnit); + Z_Free(sc->sn.buffer); + Z_Free(pdata); + return FALSE; + } + + sc->handle = pdata; + sc->Lock = MacOS_Lock; + sc->Unlock = MacOS_Unlock; + sc->SetWaterDistortion = MacOS_SetWaterDistortion; + sc->Submit = MacOS_Submit; + sc->GetDMAPos = MacOS_GetDMAPos; + sc->Shutdown = MacOS_Shutdown; + + Con_Printf("Sound initialised\n"); + return TRUE; +} + +sounddriver pMacOS_InitCard = &MacOS_InitCard; + diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index eb0335e5..96bd51a1 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -478,6 +478,25 @@ int main (int c, char **v) oldtime = Sys_DoubleTime (); while (1) { +#ifdef __MACOSX__ + //wow, not even windows was this absurd. +#ifdef RGLQUAKE + if (glcocoaRunLoop()) + { + oldtime = Sys_DoubleTime (); + continue; + } +#endif +#ifdef SWQUAKE +#warning don't worry if this causes linker errors - we don't have a macos sw renderer yet! + if (swcocoaRunLoop()) + { + oldtime = Sys_DoubleTime (); + continue; + } +#endif +#endif + // find time spent rendering last frame newtime = Sys_DoubleTime (); time = newtime - oldtime; diff --git a/engine/common/qvm.c b/engine/common/qvm.c index 3c8ff314..f8111561 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -154,6 +154,10 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int sprintf(dllname, "%samd.so", name); #elif defined(_M_IX86) || defined(__i386__) sprintf(dllname, "%sx86.so", name); +#elif defined(__powerpc__) + sprintf(dllname, "%sppc.so", name); +#elif defined(__ppc__) + sprintf(dllname, "%sppc.so", name); #else sprintf(dllname, "%sunk.so", name); #endif diff --git a/engine/gl/gl_vidcocoa.m b/engine/gl/gl_vidcocoa.m new file mode 100644 index 00000000..0d072919 --- /dev/null +++ b/engine/gl/gl_vidcocoa.m @@ -0,0 +1,634 @@ +/* + + 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 +#import +#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) + { + Key_Event(keyconv[[event keyCode]],TRUE); + //printf("%d\n",[event keyCode]); + return; + } + + if ([event type] == NSKeyUp) + { + Key_Event(keyconv[[event keyCode]],FALSE); + return; + } + + if ([event type] == NSFlagsChanged) + { + unsigned int mflags = [event modifierFlags]; + + if ((mflags & NSAlternateKeyMask) ^ (oldmflags & NSAlternateKeyMask)) + { + Key_Event(K_ALT,(mflags & NSAlternateKeyMask) ? TRUE : FALSE); + } + + if ((mflags & NSControlKeyMask) ^ (oldmflags & NSControlKeyMask)) + { + Key_Event(K_LCTRL,(mflags & NSControlKeyMask) ? TRUE : FALSE); + } + + if ((mflags & NSShiftKeyMask) ^ (oldmflags & NSShiftKeyMask)) + { + Key_Event(K_LSHIFT,(mflags & NSShiftKeyMask) ? TRUE : FALSE); + } + + if ((mflags & NSCommandKeyMask) ^ (oldmflags & NSCommandKeyMask)) + { + Key_Event(K_LWIN,(mflags & NSCommandKeyMask) ? TRUE : FALSE); + } + + if ((mflags & NSAlphaShiftKeyMask) ^ (oldmflags & NSAlphaShiftKeyMask)) + { + Key_Event(K_CAPSLOCK,(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,TRUE); + return; + } + + if ([event type] == NSLeftMouseUp) + { + Key_Event(K_MOUSE1,FALSE); + return; + } + + if ([event type] == NSRightMouseDown) + { + Key_Event(K_MOUSE2,TRUE); + return; + } + + if ([event type] == NSRightMouseUp) + { + Key_Event(K_MOUSE2,FALSE); + return; + } + + if ([event type] == NSOtherMouseDown) + { + Key_Event(K_MOUSE3,TRUE); + return; + } + + if ([event type] == NSOtherMouseUp) + { + Key_Event(K_MOUSE3,FALSE); + return; + } + + if ([event type] == NSScrollWheel) + { + Key_Event(([event deltaY] > 0.0) ? K_MWHEELUP : K_MWHEELDOWN,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); +} diff --git a/engine/gl/gl_vidmacos.c b/engine/gl/gl_vidmacos.c new file mode 100644 index 00000000..5260266b --- /dev/null +++ b/engine/gl/gl_vidmacos.c @@ -0,0 +1,239 @@ +/* + + 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. +*/ + +#include "quakedef.h" +#include "glquake.h" + +#include + +//#include "vid_macos.h" + +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 + +// note: cocoa code is separated in vid_cocoa.m because of compilation pbs + +static qboolean vid_hwgamma_enabled = false; + +cvar_t in_xflip = SCVAR("in_xflip", "0"); + +static int real_width, real_height; + +static void *agllibrary; +static void *opengllibrary; +void *AGL_GetProcAddress(char *functionname) +{ + void *func; + if (agllibrary) + { + func = dlsym(agllibrary, functionname); + if (func) + return func; + } + if (opengllibrary) + { + func = dlsym(opengllibrary, functionname); + if (func) + return func; + } + return NULL; +} + +qboolean GLVID_Init(rendererstate_t *info, unsigned char *palette) +{ + int argnum; + int i; + + agllibrary = dlopen("/System/Library/Frameworks/AGL.framework/AGL", RTLD_LAZY); + if (!agllibrary) + { + Con_Printf("Couldn't load AGL framework\n"); + return false; + } + opengllibrary = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY); + //don't care if opengl failed. + + vid.width = info->width; + vid.height = info->height; + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.numpages = 2; + vid.colormap = host_colormap; + vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); + + // initialise the NSApplication and the screen + initCocoa(info); + + // initCocoa stores current screen size in vid + real_width = vid.width; + real_height = vid.height; + + + // calculate the conwidth AFTER the screen has been opened + if (vid.width <= 640) + { + vid.conwidth = vid.width; + vid.conheight = vid.height; + } + else + { + vid.conwidth = vid.width/2; + vid.conheight = vid.height/2; + } + + if ((i = COM_CheckParm("-conwidth")) && i + 1 < com_argc) + { + vid.conwidth = Q_atoi(com_argv[i + 1]); + + // pick a conheight that matches with correct aspect + vid.conheight = vid.conwidth * 3 / 4; + } + + vid.conwidth &= 0xfff8; // make it a multiple of eight + + if ((i = COM_CheckParm("-conheight")) && i + 1 < com_argc) + vid.conheight = Q_atoi(com_argv[i + 1]); + + if (vid.conwidth < 320) + vid.conwidth = 320; + + if (vid.conheight < 200) + vid.conheight = 200; + + vid.rowbytes = vid.width; + vid.direct = 0; /* Isn't used anywhere, but whatever. */ + vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0); + + if (vid.conheight > vid.height) + vid.conheight = vid.height; + if (vid.conwidth > vid.width) + vid.conwidth = vid.width; + + vid.width = vid.conwidth; + vid.height = vid.conheight; + + GL_Init(AGL_GetProcAddress); + + GLVID_SetPalette(palette); + + vid.recalc_refdef = 1; + + return true; +} + +void GLVID_DeInit(void) +{ + killCocoa(); +} + +void GL_DoSwap(void) +{ +} + +void GLVID_ForceLockState(int i) +{ +} + +int GLVID_ForceUnlockedAndReturnState(void) +{ + return 0; +} + +void GLVID_SetPalette (unsigned char *palette) +{ + qbyte *pal; + unsigned int r,g,b; + int i; + unsigned *table1; + unsigned *table2; + extern qbyte gammatable[256]; + + Con_Printf("Converting 8to24\n"); + + pal = palette; + table1 = d_8to24rgbtable; + table2 = d_8to24bgrtable; + for (i=0 ; i<256 ; i++) + { + r = gammatable[pal[0]]; + g = gammatable[pal[1]]; + b = gammatable[pal[2]]; + pal += 3; + + *table1++ = LittleLong((255<<24) + (r<<0) + (g<<8) + (b<<16)); + *table2++ = LittleLong((255<<24) + (r<<16) + (g<<8) + (b<<0)); + } + d_8to24bgrtable[255] &= LittleLong(0xffffff); // 255 is transparent + d_8to24rgbtable[255] &= LittleLong(0xffffff); // 255 is transparent + Con_Printf("Converted\n"); +} + +void GLVID_ShiftPalette(unsigned char *p) +{ +// GLVID_SetPalette(p); +} + +void Sys_SendKeyEvents(void) +{ +} + +void GLVID_LockBuffer(void) +{ +} + +void GLVID_UnlockBuffer(void) +{ +} + +qboolean GLVID_IsLocked(void) +{ + return 0; +} + +void GLD_BeginDirectRect(int x, int y, qbyte *pbitmap, int width, int height) +{ +} + +void GLD_EndDirectRect(int x, int y, int width, int height) +{ +} + +void GLVID_SetCaption(char *text) +{ +} + +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + *x = *y = 0; + *width = real_width; + *height = real_height; +} + +void GL_EndRendering(void) +{ + flushCocoa(); +} + +void GLVID_SetDeviceGammaRamp(unsigned short *ramps) +{ + cocoaGamma(ramps,ramps+256,ramps+512); +} +