oolite/MyOpenGLView.m
2005-10-30 22:00:02 +00:00

1166 lines
35 KiB
Objective-C

/*
*
* Oolite
*
* Created by Giles Williams on Sat Apr 03 2004.
* Copyright (c) 2004 for aegidian.org. All rights reserved.
*
Copyright (c) 2004, Giles C Williams
All rights reserved.
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/
or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
You are free:
¥ to copy, distribute, display, and perform the work
¥ to make derivative works
Under the following conditions:
¥ Attribution. You must give the original author credit.
¥ Noncommercial. You may not use this work for commercial purposes.
¥ Share Alike. If you alter, transform, or build upon this work,
you may distribute the resulting work only under a license identical to this one.
For any reuse or distribution, you must make clear to others the license terms of this work.
Any of these conditions can be waived if you get permission from the copyright holder.
Your fair use and other rights are in no way affected by the above.
*/
#import <Foundation/NSAutoreleasePool.h>
#import "MyOpenGLView.h"
#import "GameController.h"
#import "Universe.h"
#import "JoystickHandler.h" // TODO: Not here!
#include <ctype.h>
@implementation MyOpenGLView
+ (NSMutableDictionary *) getNativeSize
{
SDL_SysWMinfo dpyInfo;
NSMutableDictionary *mode=[[NSMutableDictionary alloc] init];
SDL_VERSION(&dpyInfo.version);
if(SDL_GetWMInfo(&dpyInfo))
{
#if defined(LINUX) && ! defined (WIN32)
[mode setValue: [NSNumber numberWithInt: DisplayWidth(dpyInfo.info.x11.display, 0)]
forKey: kCGDisplayWidth];
[mode setValue: [NSNumber numberWithInt: DisplayHeight(dpyInfo.info.x11.display, 0)]
forKey: kCGDisplayHeight];
[mode setValue: [NSNumber numberWithInt: 0] forKey: kCGDisplayRefreshRate];
#else
NSLog(@"Unknown architecture, defaulting to 1024x768");
[mode setValue: [NSNumber numberWithInt: 1024] forKey: kCGDisplayWidth];
[mode setValue: [NSNumber numberWithInt: 768] forKey: kCGDisplayHeight];
[mode setValue: [NSNumber numberWithInt: 0] forKey: kCGDisplayRefreshRate];
#endif
}
else
{
NSLog(@"SDL_GetWMInfo failed, defaulting to 1024x768 for native size");
[mode setValue: [NSNumber numberWithInt: 1024] forKey: kCGDisplayWidth];
[mode setValue: [NSNumber numberWithInt: 768] forKey: kCGDisplayHeight];
[mode setValue: [NSNumber numberWithInt: 0] forKey: kCGDisplayRefreshRate];
}
return mode;
}
- (id) init
{
self = [super init];
// TODO: This code up to and including stickHandler really ought
// not to be in this class.
NSLog(@"initialising SDL");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
{
NSLog(@"Unable to init SDL: %s\n", SDL_GetError());
[self dealloc];
return nil;
}
else if (Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 2048) < 0)
{
NSLog(@"Mix_OpenAudio: %s\n", Mix_GetError());
[self dealloc];
return nil;
}
Mix_AllocateChannels(MAX_CHANNELS);
stickHandler=[[JoystickHandler alloc] init];
// end TODO
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
NSLog(@"CREATING MODE LIST");
[self populateFullScreenModelist];
currentSize = 0;
// Find what the full screen and windowed settings are.
[self loadFullscreenSettings];
[self loadWindowSize];
int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL;
if (fullScreen)
{
videoModeFlags |= SDL_FULLSCREEN;
NSSize fs=[self modeAsSize: currentSize];
surface = SDL_SetVideoMode(fs.width, fs.height, 32, videoModeFlags);
}
else
{
videoModeFlags |= SDL_RESIZABLE;
surface = SDL_SetVideoMode(currentWindowSize.width,
currentWindowSize.height,
32, videoModeFlags);
}
bounds.size.width = surface->w;
bounds.size.height = surface->h;
if (fullScreen)
{
if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)
SDL_ShowCursor(SDL_DISABLE);
}
else
{
if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE)
SDL_ShowCursor(SDL_ENABLE);
}
virtualJoystickPosition = NSMakePoint(0.0,0.0);
typedString = [[NSMutableString alloc] initWithString:@""];
allowingStringInput = NO;
isAlphabetKeyDown = NO;
timeIntervalAtLastClick = [NSDate timeIntervalSinceReferenceDate];
m_glContextInitialized = NO;
return self;
}
- (void) dealloc
{
if (typedString)
[typedString release];
if (surface != 0)
{
SDL_FreeSurface(surface);
surface = 0;
}
SDL_Quit();
[super dealloc];
}
- (void) allowStringInput: (BOOL) value
{
allowingStringInput = value;
}
-(BOOL) allowingStringInput
{
return allowingStringInput;
}
- (NSString *) typedString
{
return typedString;
}
- (void) resetTypedString
{
[typedString setString:@""];
}
- (void) setTypedString:(NSString*) value
{
// NSLog(@"DEBUG setTypedString:%@",value);
[typedString setString:value];
}
- (NSRect) bounds
{
return bounds;
}
- (NSSize) viewSize
{
return viewSize;
}
- (GLfloat) display_z
{
return display_z;
}
- (GameController *) gameController
{
return gameController;
}
- (void) setGameController:(GameController *) controller
{
gameController = controller;
}
- (BOOL) inFullScreenMode
{
return fullScreen;
}
#ifdef GNUSTEP
- (void) setFullScreenMode:(BOOL)fsm
{
fullScreen = fsm;
// Save the settings for later.
[[NSUserDefaults standardUserDefaults]
setBool: fullScreen forKey:@"fullscreen"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void) toggleScreenMode
{
[self setFullScreenMode: !fullScreen];
if(fullScreen)
[self initialiseGLWithSize:[self modeAsSize: currentSize]];
else
[self initialiseGLWithSize: currentWindowSize];
}
- (void) setDisplayMode:(int)mode fullScreen:(BOOL)fsm
{
[self setFullScreenMode: fsm];
currentSize=mode;
if(fullScreen)
[self initialiseGLWithSize: [self modeAsSize: mode]];
}
- (int) indexOfCurrentSize
{
return currentSize;
}
- (void) setScreenSize: (int)sizeIndex
{
currentSize=sizeIndex;
if(fullScreen)
[self initialiseGLWithSize: [self modeAsSize: currentSize]];
}
- (NSMutableArray *)getScreenSizeArray
{
return screenSizes;
}
- (NSSize) modeAsSize:(int)sizeIndex
{
NSDictionary *mode=[screenSizes objectAtIndex: sizeIndex];
return NSMakeSize([[mode objectForKey: kCGDisplayWidth] intValue],
[[mode objectForKey: kCGDisplayHeight] intValue]);
}
#endif
- (void) display
{
[self drawRect: NSMakeRect(0, 0, viewSize.width, viewSize.height)];
}
- (void) drawRect:(NSRect)rect
{
if ((viewSize.width != surface->w)||(viewSize.height != surface->h)) // resized
{
m_glContextInitialized = NO;
viewSize.width = surface->w;
viewSize.height = surface->h;
//NSLog(@"DEBUG resized to %.0f x %.0f", viewSize.width, viewSize.height);
}
if (m_glContextInitialized == NO)
{
NSLog(@"drawRect calling initialiseGLWithSize");
[self initialiseGLWithSize:viewSize];
}
if (surface == 0)
return;
// do all the drawing!
//
if ([gameController universe])
[[gameController universe] drawFromEntity:0];
else
{
// not set up yet, draw a black screen
NSLog(@"no universe, clearning surface");
glClearColor( 0.0, 0.0, 0.0, 0.0);
glClear( GL_COLOR_BUFFER_BIT);
}
SDL_GL_SwapBuffers();
}
- (void) initialiseGLWithSize:(NSSize) v_size
{
int videoModeFlags;
GLfloat sun_ambient[] = {0.0, 0.0, 0.0, 1.0};
GLfloat sun_diffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat sun_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat sun_center_position[] = {4000000.0, 0.0, 0.0, 1.0};
GLfloat stars_ambient[] = {0.25, 0.2, 0.25, 1.0};
viewSize = v_size;
if (viewSize.width/viewSize.height > 4.0/3.0)
display_z = 480.0 * viewSize.width/viewSize.height;
else
display_z = 640.0;
// NSLog(@">>>>> display_z = %.1f", display_z);
float ratio = 0.5;
float aspect = viewSize.height/viewSize.width;
if (surface != 0)
SDL_FreeSurface(surface);
NSLog(@"Creating a new surface of %d x %d", (int)v_size.width, (int)v_size.height);
videoModeFlags = SDL_HWSURFACE | SDL_OPENGL;
if (fullScreen == YES)
videoModeFlags |= SDL_FULLSCREEN;
else
videoModeFlags |= SDL_RESIZABLE;
surface = SDL_SetVideoMode((int)v_size.width, (int)v_size.height, 32, videoModeFlags);
if (fullScreen)
{
if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)
SDL_ShowCursor(SDL_DISABLE);
}
else
{
if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE)
SDL_ShowCursor(SDL_ENABLE);
}
glShadeModel(GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapBuffers();
glClearDepth(MAX_CLEAR_DEPTH);
glViewport( 0, 0, viewSize.width, viewSize.height);
squareX = 0.0;
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset matrix
glFrustum( -ratio, ratio, -aspect*ratio, aspect*ratio, 1.0, MAX_CLEAR_DEPTH); // set projection matrix
glMatrixMode( GL_MODELVIEW);
glEnable( GL_DEPTH_TEST); // depth buffer
glDepthFunc( GL_LESS); // depth buffer
glFrontFace( GL_CCW); // face culling - front faces are AntiClockwise!
glCullFace( GL_BACK); // face culling
glEnable( GL_CULL_FACE); // face culling
glEnable( GL_BLEND); // alpha blending
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha blending
if ([gameController universe])
{
Entity* the_sun = [[gameController universe] sun];
Vector sun_pos = (the_sun)? the_sun->position : make_vector(0,0,0);
sun_center_position[0] = sun_pos.x;
sun_center_position[1] = sun_pos.y;
sun_center_position[2] = sun_pos.z;
[[gameController universe] setLighting];
}
else
{
glLightfv(GL_LIGHT1, GL_AMBIENT, sun_ambient);
glLightfv(GL_LIGHT1, GL_SPECULAR, sun_specular);
glLightfv(GL_LIGHT1, GL_DIFFUSE, sun_diffuse);
glLightfv(GL_LIGHT1, GL_POSITION, sun_center_position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, stars_ambient);
//
// light for demo ships display..
GLfloat white[] = { 1.0, 1.0, 1.0, 1.0}; // white light
glLightfv(GL_LIGHT0, GL_AMBIENT, white);
glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
glLightfv(GL_LIGHT0, GL_SPECULAR, white);
}
glEnable(GL_LIGHT1); // lighting
glEnable(GL_LIGHT0); // lighting
glEnable(GL_LIGHTING); // lighting
// world's simplest OpenGL optimisations...
glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST);
glDisable(GL_NORMALIZE);
glDisable(GL_RESCALE_NORMAL);
m_glContextInitialized = YES;
}
- (void) snapShot
{
SDL_Surface* tmpSurface;
int w = viewSize.width;
int h = viewSize.height;
if (w & 3)
w = w + 4 - (w & 3);
long nPixels = w * h + 1;
NSString *filepath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
int imageNo = 1;
NSString *pathToPic =
[filepath stringByAppendingPathComponent:
[NSString stringWithFormat:@"oolite-%03d.bmp",imageNo]];
while ([[NSFileManager defaultManager] fileExistsAtPath:pathToPic])
{
imageNo++;
pathToPic = [filepath stringByAppendingPathComponent:[NSString stringWithFormat:@"oolite-%03d.bmp",imageNo]];
}
NSLog(@">>>>> Snapshot %d x %d file path chosen = %@", w, h, pathToPic);
unsigned char *puntos = (unsigned char*)malloc(surface->w * surface->h * 3);
SDL_Surface *screen;
glReadPixels(0,0,surface->w,surface->h,GL_RGB,GL_UNSIGNED_BYTE,puntos);
int pitch = surface->w * 3;
unsigned char *aux= (unsigned char*)malloc( pitch );
short h2=surface->h/2;
unsigned char *p1=puntos;
unsigned char *p2=puntos+((surface->h-1)*pitch); //go to last line
int i;
for(i=0; i<h2; i++){
memcpy(aux,p1,pitch);
memcpy(p1,p2,pitch);
memcpy(p2,aux,pitch);
p1+=pitch;
p2-=pitch;
}
free(aux);
tmpSurface=SDL_CreateRGBSurfaceFrom(puntos,surface->w,surface->h,24,surface->w*3,0xFF,0xFF00,0xFF0000,0x0);
SDL_SaveBMP(tmpSurface, [pathToPic cString]);
SDL_FreeSurface(tmpSurface);
free(puntos);
}
/*
* These are commented out because they use AppKit classes, but left here to remind
* me to replace them with SDL code in future.
*
- (void)mouseDown:(NSEvent *)theEvent
{
if (doubleClick)
{
doubleClick = NO;
keys[gvMouseDoubleClick] = NO;
}
keys[gvMouseLeftButton] = YES; // 'a' down
}
- (void)mouseUp:(NSEvent *)theEvent
{
NSTimeInterval timeBetweenClicks = [NSDate timeIntervalSinceReferenceDate] - timeIntervalAtLastClick;
timeIntervalAtLastClick += timeBetweenClicks;
if (!doubleClick)
{
doubleClick = (timeBetweenClicks < MOUSE_DOUBLE_CLICK_INTERVAL); // One fifth of a second
keys[gvMouseDoubleClick] = doubleClick;
// if (doubleClick)
// NSLog(@"DEBUG registering a double-click!");
}
keys[gvMouseLeftButton] = NO; // 'a' up
}
- (void)mouseDragged:(NSEvent *)theEvent
{
squareX = [theEvent locationInWindow].x - mouseDragStartPoint.x;
squareY = [theEvent locationInWindow].y - mouseDragStartPoint.y;
[self setNeedsDisplay:YES];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
double mx = [theEvent locationInWindow].x - viewSize.width/2.0;
double my = [theEvent locationInWindow].y - viewSize.height/2.0;
if (display_z > 640.0)
{
mx /= viewSize.width * MAIN_GUI_PIXEL_WIDTH / display_z;
my /= viewSize.height;
}
else
{
mx /= MAIN_GUI_PIXEL_WIDTH * viewSize.width / 640.0;
my /= MAIN_GUI_PIXEL_HEIGHT * viewSize.width / 640.0;
}
[self setVirtualJoystick:mx :-my];
}
/////////////////////////////////////////////////////////////
/* Turn the Cocoa ArrowKeys into our arrow key constants. */
- (int) translateKeyCode: (int) input
{
int key = input;
switch ( input )
{
case NSUpArrowFunctionKey:
key = gvArrowKeyUp;
break;
case NSDownArrowFunctionKey:
key = gvArrowKeyDown;
break;
case NSLeftArrowFunctionKey:
key = gvArrowKeyLeft;
break;
case NSRightArrowFunctionKey:
key = gvArrowKeyRight;
break;
case NSF1FunctionKey:
key = gvFunctionKey1;
break;
case NSF2FunctionKey:
key = gvFunctionKey2;
break;
case NSF3FunctionKey:
key = gvFunctionKey3;
break;
case NSF4FunctionKey:
key = gvFunctionKey4;
break;
case NSF5FunctionKey:
key = gvFunctionKey5;
break;
case NSF6FunctionKey:
key = gvFunctionKey6;
break;
case NSF7FunctionKey:
key = gvFunctionKey7;
break;
case NSF8FunctionKey:
key = gvFunctionKey8;
break;
case NSF9FunctionKey:
key = gvFunctionKey9;
break;
case NSF10FunctionKey:
key = gvFunctionKey10;
break;
case NSF11FunctionKey:
key = gvFunctionKey11;
break;
case NSHomeFunctionKey:
key = gvHomeKey;
break;
default:
break;
}
return key;
}
- (void) setVirtualJoystick:(double) vmx :(double) vmy
{
virtualJoystickPosition.x = vmx;
virtualJoystickPosition.y = vmy;
}
- (NSPoint) virtualJoystickPosition
{
return virtualJoystickPosition;
}
/////////////////////////////////////////////////////////////
- (void) clearKeys
{
int i;
for (i = 0; i < [self numKeys]; i++)
keys[i] = NO;
}
- (void) clearMouse
{
keys[gvMouseDoubleClick] = NO;
keys[gvMouseLeftButton] = NO;
doubleClick = NO;
}
- (BOOL) isAlphabetKeyDown
{
return isAlphabetKeyDown = NO;;
}
// DJS: When entering submenus in the gui, it is not helpful if the
// key down that brought you into the submenu is still registered
// as down when we're in. This makes isDown return NO until a key up
// event has been received from SDL.
- (void) supressKeysUntilKeyUp
{
supressKeys = YES;
[self clearKeys];
}
- (BOOL) isDown: (int) key
{
if ( supressKeys )
return NO;
if ( key < 0 )
return NO;
if ( key >= [self numKeys] )
return NO;
return keys[key];
}
- (BOOL) isOptDown
{
return opt;
}
- (BOOL) isCtrlDown
{
return ctrl;
}
- (BOOL) isCommandDown
{
return command;
}
- (BOOL) isShiftDown
{
return shift;
}
- (int) numKeys
{
return NUM_KEYS;
}
- (void) pollControls: (id)sender
{
SDL_Event event;
SDL_KeyboardEvent* kbd_event;
SDL_MouseButtonEvent* mbtn_event;
SDL_MouseMotionEvent *mmove_event;
Uint32 startTicks;
Sint32 sleepTicks;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_JOYAXISMOTION:
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
[stickHandler handleSDLEvent: &event];
break;
case SDL_MOUSEBUTTONDOWN:
mbtn_event = (SDL_MouseButtonEvent*)&event;
if (mbtn_event->button == SDL_BUTTON_LEFT)
{
//NSLog(@"LMB down");
keys[gvMouseLeftButton] = YES;
}
break;
case SDL_MOUSEBUTTONUP:
mbtn_event = (SDL_MouseButtonEvent*)&event;
if (mbtn_event->button == SDL_BUTTON_LEFT)
{
//NSLog(@"LMB up");
keys[gvMouseLeftButton] = NO;
}
break;
case SDL_MOUSEMOTION:
mmove_event = (SDL_MouseMotionEvent*)&event;
double mx = mmove_event->x - viewSize.width/2.0;
double my = mmove_event->y - viewSize.height/2.0;
if (display_z > 640.0)
{
mx /= viewSize.width * MAIN_GUI_PIXEL_WIDTH / display_z;
my /= viewSize.height;
}
else
{
mx /= MAIN_GUI_PIXEL_WIDTH * viewSize.width / 640.0;
my /= MAIN_GUI_PIXEL_HEIGHT * viewSize.width / 640.0;
}
[self setVirtualJoystick:mx :my];
break;
case SDL_KEYDOWN:
kbd_event = (SDL_KeyboardEvent*)&event;
if(allowingStringInput)
{
[self handleStringInput: kbd_event];
}
//printf("Keydown scancode: %d\n", kbd_event->keysym.scancode);
switch (kbd_event->keysym.sym) {
case SDLK_1: if (shift) { keys[33] = YES; keys[gvNumberKey1] = NO; } else { keys[33] = NO; keys[gvNumberKey1] = YES; } break;
case SDLK_2: keys[gvNumberKey2] = YES; break;
case SDLK_3: keys[gvNumberKey3] = YES; break;
case SDLK_4: keys[gvNumberKey4] = YES; break;
case SDLK_5: keys[gvNumberKey5] = YES; break;
case SDLK_6: keys[gvNumberKey6] = YES; break;
case SDLK_7: keys[gvNumberKey7] = YES; break;
case SDLK_8: if (shift) { keys[42] = YES; keys[gvNumberKey8] = NO; } else { keys[42] = NO; keys[gvNumberKey8] = YES; } break;
case SDLK_9: keys[gvNumberKey9] = YES; break;
case SDLK_0: keys[gvNumberKey0] = YES; break;
case SDLK_a: if (shift) { keys[65] = YES; keys[97] = NO; } else { keys[65] = NO; keys[97] = YES; } break;
case SDLK_b: if (shift) { keys[66] = YES; keys[98] = NO; } else { keys[66] = NO; keys[98] = YES; } break;
case SDLK_c: if (shift) { keys[67] = YES; keys[99] = NO; } else { keys[67] = NO; keys[99] = YES; } break;
case SDLK_d: if (shift) { keys[68] = YES; keys[100] = NO; } else { keys[68] = NO; keys[100] = YES; } break;
case SDLK_e: if (shift) { keys[69] = YES; keys[101] = NO; } else { keys[69] = NO; keys[101] = YES; } break;
case SDLK_f: if (shift) { keys[70] = YES; keys[102] = NO; } else { keys[70] = NO; keys[102] = YES; } break;
case SDLK_g: if (shift) { keys[71] = YES; keys[103] = NO; } else { keys[71] = NO; keys[103] = YES; } break;
case SDLK_h: if (shift) { keys[72] = YES; keys[104] = NO; } else { keys[72] = NO; keys[104] = YES; } break;
case SDLK_i: if (shift) { keys[73] = YES; keys[105] = NO; } else { keys[73] = NO; keys[105] = YES; } break;
case SDLK_j: if (shift) { keys[74] = YES; keys[106] = NO; } else { keys[74] = NO; keys[106] = YES; } break;
case SDLK_k: if (shift) { keys[75] = YES; keys[107] = NO; } else { keys[75] = NO; keys[107] = YES; } break;
case SDLK_l: if (shift) { keys[76] = YES; keys[108] = NO; } else { keys[76] = NO; keys[108] = YES; } break;
case SDLK_m: if (shift) { keys[77] = YES; keys[109] = NO; } else { keys[77] = NO; keys[109] = YES; } break;
case SDLK_n: if (shift) { keys[78] = YES; keys[110] = NO; } else { keys[78] = NO; keys[110] = YES; } break;
case SDLK_o: if (shift) { keys[79] = YES; keys[111] = NO; } else { keys[79] = NO; keys[111] = YES; } break;
case SDLK_p: if (shift) { keys[80] = YES; keys[112] = NO; } else { keys[80] = NO; keys[112] = YES; } break;
case SDLK_q: if (shift) { keys[81] = YES; keys[113] = NO; } else { keys[81] = NO; keys[113] = YES; } break;
case SDLK_r: if (shift) { keys[82] = YES; keys[114] = NO; } else { keys[82] = NO; keys[114] = YES; } break;
case SDLK_s: if (shift) { keys[83] = YES; keys[115] = NO; } else { keys[83] = NO; keys[115] = YES; } break;
case SDLK_t: if (shift) { keys[84] = YES; keys[116] = NO; } else { keys[84] = NO; keys[116] = YES; } break;
case SDLK_u: if (shift) { keys[85] = YES; keys[117] = NO; } else { keys[85] = NO; keys[117] = YES; } break;
case SDLK_v: if (shift) { keys[86] = YES; keys[118] = NO; } else { keys[86] = NO; keys[118] = YES; } break;
case SDLK_w: if (shift) { keys[87] = YES; keys[119] = NO; } else { keys[87] = NO; keys[119] = YES; } break;
case SDLK_x: if (shift) { keys[88] = YES; keys[120] = NO; } else { keys[88] = NO; keys[120] = YES; } break;
case SDLK_y: if (shift) { keys[89] = YES; keys[121] = NO; } else { keys[89] = NO; keys[121] = YES; } break;
case SDLK_z: if (shift) { keys[90] = YES; keys[122] = NO; } else { keys[90] = NO; keys[122] = YES; } break;
case SDLK_BACKSLASH: if (! shift) keys[92] = YES; break;
case SDLK_BACKQUOTE: if (! shift) keys[96] = YES; break;
case SDLK_HOME: keys[gvHomeKey] = YES; break;
case SDLK_SPACE: keys[32] = YES; break;
case SDLK_RETURN: keys[13] = YES; break;
case SDLK_TAB: keys[9] = YES; break;
case SDLK_KP8:
case SDLK_UP: keys[gvArrowKeyUp] = YES; break;
case SDLK_KP2:
case SDLK_DOWN: keys[gvArrowKeyDown] = YES; break;
case SDLK_KP4:
case SDLK_LEFT: keys[gvArrowKeyLeft] = YES; break;
case SDLK_KP6:
case SDLK_RIGHT: keys[gvArrowKeyRight] = YES; break;
case SDLK_F1: keys[gvFunctionKey1] = YES; break;
case SDLK_F2: keys[gvFunctionKey2] = YES; break;
case SDLK_F3: keys[gvFunctionKey3] = YES; break;
case SDLK_F4: keys[gvFunctionKey4] = YES; break;
case SDLK_F5: keys[gvFunctionKey5] = YES; break;
case SDLK_F6: keys[gvFunctionKey6] = YES; break;
case SDLK_F7: keys[gvFunctionKey7] = YES; break;
case SDLK_F8: keys[gvFunctionKey8] = YES; break;
case SDLK_F9: keys[gvFunctionKey9] = YES; break;
case SDLK_F10: keys[gvFunctionKey10] = YES; break;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
shift = YES;
break;
case SDLK_LCTRL:
case SDLK_RCTRL:
ctrl = YES;
break;
case SDLK_F11:
if(!fullScreen)
break;
if(shift)
{
currentSize--;
if (currentSize < 0)
currentSize = [screenSizes count] - 1;
}
else
{
currentSize++;
if (currentSize >= [screenSizes count])
currentSize = 0;
}
[self initialiseGLWithSize: [self modeAsSize: currentSize]];
break;
case SDLK_F12:
if (fullScreen == NO)
{
fullScreen = YES;
[self initialiseGLWithSize: [self modeAsSize: currentSize]];
}
else
{
// flip to user-selected size
fullScreen = NO;
[self initialiseGLWithSize: [self modeAsSize: currentSize]];
}
break;
case SDLK_ESCAPE:
if (shift)
{
SDL_FreeSurface(surface);
[gameController exitApp];
}
else
keys[27] = YES;
}
break;
case SDL_KEYUP:
supressKeys = NO; // DJS
kbd_event = (SDL_KeyboardEvent*)&event;
//printf("Keydown scancode: %d\n", kbd_event->keysym.scancode);
switch (kbd_event->keysym.sym) {
case SDLK_1: keys[33] = NO; keys[gvNumberKey1] = NO; break;
case SDLK_2: keys[gvNumberKey2] = NO; break;
case SDLK_3: keys[gvNumberKey3] = NO; break;
case SDLK_4: keys[gvNumberKey4] = NO; break;
case SDLK_5: keys[gvNumberKey5] = NO; break;
case SDLK_6: keys[gvNumberKey6] = NO; break;
case SDLK_7: keys[gvNumberKey7] = NO; break;
case SDLK_8: keys[42] = NO; keys[gvNumberKey8] = NO; break;
case SDLK_9: keys[gvNumberKey9] = NO; break;
case SDLK_0: keys[gvNumberKey0] = NO; break;
case SDLK_a: keys[65] = NO; keys[97] = NO; break;
case SDLK_b: keys[66] = NO; keys[98] = NO; break;
case SDLK_c: keys[67] = NO; keys[99] = NO; break;
case SDLK_d: keys[68] = NO; keys[100] = NO; break;
case SDLK_e: keys[69] = NO; keys[101] = NO; break;
case SDLK_f: keys[70] = NO; keys[102] = NO; break;
case SDLK_g: keys[71] = NO; keys[103] = NO; break;
case SDLK_h: keys[72] = NO; keys[104] = NO; break;
case SDLK_i: keys[73] = NO; keys[105] = NO; break;
case SDLK_j: keys[74] = NO; keys[106] = NO; break;
case SDLK_k: keys[75] = NO; keys[107] = NO; break;
case SDLK_l: keys[76] = NO; keys[108] = NO; break;
case SDLK_m: keys[77] = NO; keys[109] = NO; break;
case SDLK_n: keys[78] = NO; keys[110] = NO; break;
case SDLK_o: keys[79] = NO; keys[111] = NO; break;
case SDLK_p: keys[80] = NO; keys[112] = NO; break;
case SDLK_q: keys[81] = NO; keys[113] = NO; break;
case SDLK_r: keys[82] = NO; keys[114] = NO; break;
case SDLK_s: keys[83] = NO; keys[115] = NO; break;
case SDLK_t: keys[84] = NO; keys[116] = NO; break;
case SDLK_u: keys[85] = NO; keys[117] = NO; break;
case SDLK_v: keys[86] = NO; keys[118] = NO; break;
case SDLK_w: keys[87] = NO; keys[119] = NO; break;
case SDLK_x: keys[88] = NO; keys[120] = NO; break;
case SDLK_y: keys[89] = NO; keys[121] = NO; break;
case SDLK_z: keys[90] = NO; keys[122] = NO; break;
case SDLK_BACKSLASH: keys[92] = NO; break;
case SDLK_BACKQUOTE: keys[96] = NO; break;
case SDLK_HOME: keys[gvHomeKey] = NO; break;
case SDLK_SPACE: keys[32] = NO; break;
case SDLK_RETURN: keys[13] = NO; break;
case SDLK_TAB: keys[9] = NO; break;
case SDLK_KP8:
case SDLK_UP: keys[gvArrowKeyUp] = NO; break;
case SDLK_KP2:
case SDLK_DOWN: keys[gvArrowKeyDown] = NO; break;
case SDLK_KP4:
case SDLK_LEFT: keys[gvArrowKeyLeft] = NO; break;
case SDLK_KP6:
case SDLK_RIGHT: keys[gvArrowKeyRight] = NO; break;
case SDLK_F1: keys[gvFunctionKey1] = NO; break;
case SDLK_F2: keys[gvFunctionKey2] = NO; break;
case SDLK_F3: keys[gvFunctionKey3] = NO; break;
case SDLK_F4: keys[gvFunctionKey4] = NO; break;
case SDLK_F5: keys[gvFunctionKey5] = NO; break;
case SDLK_F6: keys[gvFunctionKey6] = NO; break;
case SDLK_F7: keys[gvFunctionKey7] = NO; break;
case SDLK_F8: keys[gvFunctionKey8] = NO; break;
case SDLK_F9: keys[gvFunctionKey9] = NO; break;
case SDLK_F10: keys[gvFunctionKey10] = NO; break;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
shift = NO;
break;
case SDLK_LCTRL:
case SDLK_RCTRL:
ctrl = NO;
break;
case SDLK_ESCAPE:
keys[27] = NO;
break;
}
break;
case SDL_VIDEORESIZE:
{
SDL_ResizeEvent *rsevt=(SDL_ResizeEvent *)&event;
NSSize newSize=NSMakeSize(rsevt->w, rsevt->h);
[self initialiseGLWithSize: newSize];
[self saveWindowSize: newSize];
break;
}
}
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[gameController doStuff: nil];
// Clean up any autoreleased objects that were created this time through the loop.
[pool release];
}
// DJS: String input handler. Since for SDL versions we're also handling
// freeform typing this has necessarily got more complex than the non-SDL
// versions.
- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event;
{
SDLKey key=kbd_event->keysym.sym;
// Del, Backspace
if(key == SDLK_BACKSPACE || key == SDLK_DELETE)
{
if([typedString length] >= 1)
{
[typedString deleteCharactersInRange:
NSMakeRange([typedString length]-1, 1)];
}
else
{
[self resetTypedString];
}
}
// Note: if we start using this handler for anything other
// than savegames, a more flexible mechanism is needed
// for max. string length.
if([typedString length] < 40)
{
// keys a-z
if(key >= SDLK_a && key <= SDLK_z)
{
isAlphabetKeyDown=YES;
if(shift)
{
key=toupper(key);
}
[typedString appendFormat:@"%c", key];
}
// keys 0-9, Space
// Left-Shift seems to produce the key code for 0 :/
if((key >= SDLK_0 && key <= SDLK_9) || key == SDLK_SPACE)
{
[typedString appendFormat:@"%c", key];
}
}
}
// Full screen mode enumerator.
- (void) populateFullScreenModelist
{
int i;
SDL_Rect **modes;
NSMutableDictionary *mode;
screenSizes=[[NSMutableArray alloc] init];
[screenSizes retain];
// The default resolution (slot 0) is the resolution we are
// already in since this is guaranteed to work.
mode=[MyOpenGLView getNativeSize];
[screenSizes addObject: mode];
modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
if(modes == (SDL_Rect **)NULL)
{
NSLog(@"SDL didn't return any screen modes");
return;
}
if(modes == (SDL_Rect **)-1)
{
NSLog(@"SDL claims 'all resolutions available' which is unhelpful in the extreme");
return;
}
int lastw=[[mode objectForKey: kCGDisplayWidth] intValue];
int lasth=[[mode objectForKey: kCGDisplayHeight] intValue];
for(i=0; modes[i]; i++)
{
// SDL_ListModes often lists a mode several times,
// presumably because each mode has several refresh rates.
// But the modes pointer is an SDL_Rect which can't represent
// refresh rates. WHY!?
if(modes[i]->w != lastw && modes[i]->h != lasth)
{
// new resolution, save it
mode=[[NSMutableDictionary alloc] init];
[mode setValue: [NSNumber numberWithInt: (int)modes[i]->w]
forKey: kCGDisplayWidth];
[mode setValue: [NSNumber numberWithInt: (int)modes[i]->h]
forKey: kCGDisplayHeight];
[mode setValue: [NSNumber numberWithInt: 0]
forKey: kCGDisplayRefreshRate];
[screenSizes addObject: mode];
NSLog(@"Added res %d x %d", modes[i]->w, modes[i]->h);
lastw=modes[i]->w;
lasth=modes[i]->h;
}
}
}
// Save and restore window sizes to/from defaults.
- (void) saveWindowSize: (NSSize) windowSize
{
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setInteger: (int)windowSize.width forKey: @"window_width"];
[defaults setInteger: (int)windowSize.height forKey: @"window_height"];
currentWindowSize=windowSize;
}
- (NSSize) loadWindowSize
{
NSSize windowSize;
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
if([defaults objectForKey:@"window_width"] &&
[defaults objectForKey:@"window_height"])
{
windowSize=NSMakeSize([defaults integerForKey: @"window_width"],
[defaults integerForKey: @"window_height"]);
}
else
{
windowSize=NSMakeSize(800, 600);
}
currentWindowSize=windowSize;
return windowSize;
}
- (int) loadFullscreenSettings
{
currentSize=0;
int width=0, height=0, refresh=0;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([userDefaults objectForKey:@"display_width"])
width = [userDefaults integerForKey:@"display_width"];
if ([userDefaults objectForKey:@"display_height"])
height = [userDefaults integerForKey:@"display_height"];
if ([userDefaults objectForKey:@"display_refresh"])
refresh = [userDefaults integerForKey:@"display_refresh"];
if([userDefaults objectForKey:@"fullscreen"])
fullScreen=[userDefaults boolForKey:@"fullscreen"];
if(width && height)
{
currentSize=[self findDisplayModeForWidth: width Height: height Refresh: refresh];
return currentSize;
}
return currentSize;
}
- (int) findDisplayModeForWidth:(unsigned int) d_width Height:(unsigned int) d_height Refresh:(unsigned int) d_refresh
{
int i, modeCount;
NSDictionary *mode;
unsigned int modeWidth, modeHeight, modeRefresh;
modeCount = [screenSizes count];
for (i = 0; i < modeCount; i++)
{
mode = [screenSizes objectAtIndex: i];
modeWidth = [[mode objectForKey: (NSString *)kCGDisplayWidth] intValue];
modeHeight = [[mode objectForKey: (NSString *)kCGDisplayHeight] intValue];
modeRefresh = [[mode objectForKey: (NSString *)kCGDisplayRefreshRate] intValue];
if ((modeWidth == d_width)&&(modeHeight == d_height)&&(modeRefresh == d_refresh))
{
NSLog(@"Found mode %@", mode);
return i;
}
}
NSLog(@"Failed to find mode: width=%d height=%d refresh=%d", d_width, d_height, d_refresh);
NSLog(@"Contents of list: %@", screenSizes);
return 0;
}
- (NSSize) currentScreenSize
{
NSDictionary *mode=[screenSizes objectAtIndex: currentSize];
if(mode)
{
return NSMakeSize([[mode objectForKey: (NSString *)kCGDisplayWidth] intValue],
[[mode objectForKey: (NSString *)kCGDisplayHeight] intValue]);
}
NSLog(@"Screen size unknown!");
return NSMakeSize(800, 600);
}
- (JoystickHandler *) getStickHandler
{
return stickHandler;
}
@end