mirror of
https://git.code.sf.net/p/quake/quake2forge
synced 2024-12-12 13:42:21 +00:00
735 lines
15 KiB
Objective-C
735 lines
15 KiB
Objective-C
|
|
#import <AppKit/AppKit.h>
|
|
#include "../ref_soft/r_local.h"
|
|
|
|
/*
|
|
====================================================================
|
|
|
|
OPENSTEP specific stuff
|
|
|
|
====================================================================
|
|
*/
|
|
|
|
@interface QuakeView : NSView
|
|
@end
|
|
|
|
NSWindow *vid_window_i;
|
|
QuakeView *vid_view_i;
|
|
|
|
unsigned *buffernative;
|
|
|
|
//===========================================================
|
|
|
|
|
|
int Draw_SetResolution (void);
|
|
|
|
#define TYPE_FULLSCREEN 0
|
|
#define TYPE_WINDOWED 1
|
|
#define TYPE_STRETCHED 2
|
|
|
|
#define NUM_RESOLUTIONS 7
|
|
int resolutions[NUM_RESOLUTIONS][2] = {
|
|
{320,200}, {320,240}, {400,300}, {512,384}, {640,480}, {800,600}, {1024,768} };
|
|
|
|
qboolean available[NUM_RESOLUTIONS][3];
|
|
int mode_res = 0, mode_type = TYPE_WINDOWED;
|
|
|
|
byte gammatable[256]; // palette is sent through this
|
|
unsigned current_palette[256];
|
|
unsigned gamma_palette[256];
|
|
|
|
int cursor_res, cursor_type;
|
|
|
|
cvar_t *vid_x;
|
|
cvar_t *vid_y;
|
|
cvar_t *vid_mode;
|
|
cvar_t *vid_stretched;
|
|
cvar_t *vid_fullscreen;
|
|
cvar_t *draw_gamma;
|
|
|
|
void Draw_BuildGammaTable (void);
|
|
|
|
/*
|
|
====================================================================
|
|
|
|
MENU INTERACTION
|
|
|
|
====================================================================
|
|
*/
|
|
|
|
void FindModes (void)
|
|
{
|
|
if (mode_res < 0 || mode_res >= NUM_RESOLUTIONS)
|
|
mode_res = 0;
|
|
if (mode_type < 0 || mode_type > 3)
|
|
mode_type = 1;
|
|
|
|
}
|
|
|
|
void RM_Print (int x, int y, char *s)
|
|
{
|
|
while (*s)
|
|
{
|
|
Draw_Char (x, y, (*s)+128);
|
|
s++;
|
|
x += 8;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
Draw_MenuDraw
|
|
================
|
|
*/
|
|
void Draw_MenuDraw (void)
|
|
{
|
|
int i, j;
|
|
int y;
|
|
char string[32];
|
|
|
|
Draw_Pic ( 4, 4, "vidmodes");
|
|
|
|
RM_Print (80, 32, "fullscreen windowed stretched");
|
|
RM_Print (80, 40, "---------- -------- ---------");
|
|
y = 50;
|
|
|
|
// draw background behind selected mode
|
|
Draw_Fill ( (mode_type+1)*80, y+(mode_res)*10, 40,10, 8);
|
|
|
|
// draw available grid
|
|
for (i=0 ; i<NUM_RESOLUTIONS ; i++, y+= 10)
|
|
{
|
|
sprintf (string, "%ix%i", resolutions[i][0], resolutions[i][1]);
|
|
RM_Print (0, y, string);
|
|
for (j=0 ; j<3 ; j++)
|
|
if (available[i][j])
|
|
RM_Print ( 80 + j*80, y, "*");
|
|
}
|
|
|
|
// draw the cursor
|
|
Draw_Char (80 + cursor_type*80, 50 + cursor_res*10, 128 + 12+((int)(r_newrefdef.time*4)&1));
|
|
}
|
|
|
|
|
|
#define K_TAB 9
|
|
#define K_ENTER 13
|
|
#define K_ESCAPE 27
|
|
#define K_SPACE 32
|
|
|
|
// normal keys should be passed as lowercased ascii
|
|
|
|
#define K_BACKSPACE 127
|
|
#define K_UPARROW 128
|
|
#define K_DOWNARROW 129
|
|
#define K_LEFTARROW 130
|
|
#define K_RIGHTARROW 131
|
|
|
|
/*
|
|
================
|
|
Draw_MenuKey
|
|
================
|
|
*/
|
|
void Draw_MenuKey (int key)
|
|
{
|
|
switch (key)
|
|
{
|
|
case K_LEFTARROW:
|
|
cursor_type--;
|
|
if (cursor_type < 0)
|
|
cursor_type = 2;
|
|
break;
|
|
|
|
case K_RIGHTARROW:
|
|
cursor_type++;
|
|
if (cursor_type > 2)
|
|
cursor_type = 0;
|
|
break;
|
|
|
|
case K_UPARROW:
|
|
cursor_res--;
|
|
if (cursor_res < 0)
|
|
cursor_res = NUM_RESOLUTIONS-1;
|
|
break;
|
|
|
|
case K_DOWNARROW:
|
|
cursor_res++;
|
|
if (cursor_res >= NUM_RESOLUTIONS)
|
|
cursor_res = 0;
|
|
break;
|
|
|
|
case K_ENTER:
|
|
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", cursor_res));
|
|
switch (cursor_type)
|
|
{
|
|
case TYPE_FULLSCREEN:
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 1");
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
|
|
break;
|
|
case TYPE_WINDOWED:
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
|
|
break;
|
|
case TYPE_STRETCHED:
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 1");
|
|
break;
|
|
}
|
|
|
|
mode_res = cursor_res;
|
|
mode_type = cursor_type;
|
|
Draw_SetResolution ();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
|
|
|
|
/*
|
|
================
|
|
Draw_SetResolution
|
|
|
|
The vid structure will be filled in on return
|
|
Also allocates the z buffer and surface cache
|
|
================
|
|
*/
|
|
int Draw_SetResolution (void)
|
|
{
|
|
NSRect content;
|
|
|
|
if (vid_mode->value < 0)
|
|
ri.Cmd_ExecuteText (EXEC_NOW, "vid_mode 0");
|
|
if (vid_mode->value >= NUM_RESOLUTIONS)
|
|
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", NUM_RESOLUTIONS-1));
|
|
|
|
vid_mode->modified = false;
|
|
vid_fullscreen->modified = false;
|
|
vid_stretched->modified = false;
|
|
|
|
// free nativebuffer
|
|
if (buffernative)
|
|
{
|
|
free (buffernative);
|
|
buffernative = NULL;
|
|
}
|
|
|
|
// free z buffer
|
|
if (d_pzbuffer)
|
|
{
|
|
free (d_pzbuffer);
|
|
d_pzbuffer = NULL;
|
|
}
|
|
// free surface cache
|
|
if (sc_base)
|
|
{
|
|
D_FlushCaches ();
|
|
free (sc_base);
|
|
sc_base = NULL;
|
|
}
|
|
|
|
vid.width = resolutions[(int)(vid_mode->value)][0];
|
|
vid.height = resolutions[(int)(vid_mode->value)][1];
|
|
|
|
vid.win_width = vid.width;
|
|
vid.win_height = vid.height;
|
|
if (vid_stretched->value)
|
|
{
|
|
vid.win_width <<= 1;
|
|
vid.win_height <<= 1;
|
|
}
|
|
|
|
vid.aspect = 1;
|
|
vid.buffer = malloc (vid.width*vid.height);
|
|
vid.rowbytes = vid.width;
|
|
d_pzbuffer = malloc(vid.width*vid.height*2);
|
|
buffernative = malloc(vid.width*vid.height*4);
|
|
|
|
D_InitCaches ();
|
|
|
|
Sys_SetPalette ((byte *)d_8to24table);
|
|
|
|
if (vid_view_i)
|
|
[vid_view_i unlockFocus];
|
|
if (vid_window_i)
|
|
[vid_window_i close];
|
|
//
|
|
// open a window
|
|
//
|
|
content = NSMakeRect (vid_x->value,vid_y->value,vid.win_width, vid.win_height);
|
|
vid_window_i = [[NSWindow alloc]
|
|
initWithContentRect: content
|
|
styleMask: NSTitledWindowMask
|
|
backing: NSBackingStoreRetained
|
|
defer: NO
|
|
];
|
|
|
|
[vid_window_i setDelegate: vid_window_i];
|
|
[vid_window_i display];
|
|
[NSApp activateIgnoringOtherApps: YES];
|
|
[vid_window_i makeKeyAndOrderFront: nil];
|
|
|
|
// NSPing ();
|
|
|
|
content.origin.x = content.origin.y = 0;
|
|
vid_view_i = [[QuakeView alloc] initWithFrame: content];
|
|
[vid_window_i setContentView: vid_view_i];
|
|
[vid_window_i makeFirstResponder: vid_view_i];
|
|
[vid_window_i setDelegate: vid_view_i];
|
|
|
|
// [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK];
|
|
[vid_window_i setTitle: @"Bitmap Quake Console"];
|
|
[vid_window_i makeKeyAndOrderFront: nil];
|
|
|
|
// leave focus locked forever
|
|
[vid_view_i lockFocus];
|
|
|
|
ri.VID_SetSize (vid.width, vid.height);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
Draw_Init
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
*/
|
|
int Draw_Init (void *window)
|
|
{
|
|
[NSApplication sharedApplication];
|
|
[NSApp finishLaunching];
|
|
|
|
ri.Con_Printf (PRINT_ALL, "refresh version: "REF_VERSION"\n");
|
|
|
|
vid_x = ri.Cvar_Get ("vid_x", "0", CVAR_ARCHIVE);
|
|
vid_y = ri.Cvar_Get ("vid_y", "0", CVAR_ARCHIVE);
|
|
vid_mode = ri.Cvar_Get ("vid_mode", "0", CVAR_ARCHIVE);
|
|
vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
|
|
vid_stretched = ri.Cvar_Get ("vid_stretched", "0", CVAR_ARCHIVE);
|
|
draw_gamma = ri.Cvar_Get ("gamma", "1", CVAR_ARCHIVE);
|
|
|
|
Draw_GetPalette ();
|
|
|
|
Draw_BuildGammaTable ();
|
|
|
|
// get the lighting colormap
|
|
ri.FS_LoadFile ("gfx/colormap.lmp", (void **)&vid.colormap);
|
|
if (!vid.colormap)
|
|
{
|
|
ri.Con_Printf (PRINT_ALL, "ERROR: Couldn't load gfx/colormap.lmp");
|
|
return -1;
|
|
}
|
|
|
|
Draw_SetResolution ();
|
|
|
|
R_Init ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
Draw_Shutdown
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
*/
|
|
void Draw_Shutdown (void)
|
|
{
|
|
R_Shutdown ();
|
|
}
|
|
|
|
|
|
/*
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
Draw_BuildGammaTable
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
*/
|
|
void Draw_BuildGammaTable (void)
|
|
{
|
|
int i, inf;
|
|
float g;
|
|
|
|
draw_gamma->modified = false;
|
|
g = draw_gamma->value;
|
|
|
|
if (g == 1.0)
|
|
{
|
|
for (i=0 ; i<256 ; i++)
|
|
gammatable[i] = i;
|
|
return;
|
|
}
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
|
|
if (inf < 0)
|
|
inf = 0;
|
|
if (inf > 255)
|
|
inf = 255;
|
|
gammatable[i] = inf;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
Draw_BeginFram
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
*/
|
|
void Draw_BeginFrame (void)
|
|
{
|
|
if (vid_mode->modified || vid_fullscreen->modified
|
|
|| vid_stretched->modified)
|
|
Draw_SetResolution ();
|
|
|
|
if (draw_gamma->modified)
|
|
{
|
|
Draw_BuildGammaTable ();
|
|
Sys_SetPalette ((byte *)current_palette);
|
|
}
|
|
|
|
// MGL_beginDirectAccess();
|
|
// vid.buffer = mgldc->surface;
|
|
// vid.rowbytes = mgldc->mi.bytesPerLine;
|
|
}
|
|
|
|
|
|
/*
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
Draw_EndFrame
|
|
|
|
@@@@@@@@@@@@@@@@@@@@@
|
|
*/
|
|
void Draw_EndFrame (void)
|
|
{
|
|
int i, c;
|
|
int bps, spp, bpp, bpr;
|
|
unsigned char *planes[5];
|
|
NSRect bounds;
|
|
|
|
// translate to 24 bit color
|
|
c = vid.width*vid.height;
|
|
for (i=0 ; i<c ; i++)
|
|
buffernative[i] = gamma_palette[vid.buffer[i]];
|
|
|
|
bps = 8;
|
|
spp = 3;
|
|
bpp = 32;
|
|
bpr = vid.width * 4;
|
|
planes[0] = (unsigned char *)buffernative;
|
|
|
|
bounds = [vid_view_i bounds];
|
|
|
|
NSDrawBitmap(
|
|
bounds,
|
|
vid.width,
|
|
vid.height,
|
|
bps,
|
|
spp,
|
|
bpp,
|
|
bpr,
|
|
NO,
|
|
NO,
|
|
@"NSDeviceRGBColorSpace",
|
|
planes
|
|
);
|
|
}
|
|
|
|
|
|
//===============================================================================
|
|
|
|
#define HUNK_MAGIC 0xffaffaff
|
|
typedef struct
|
|
{
|
|
int magic;
|
|
int length;
|
|
int pad[6];
|
|
} hunkheader_t;
|
|
|
|
hunkheader_t *membase;
|
|
int maxsize;
|
|
int cursize;
|
|
|
|
void *Hunk_Begin (void)
|
|
{
|
|
kern_return_t r;
|
|
|
|
// reserve a huge chunk of memory, but don't commit any yet
|
|
maxsize = 16*1024*1024;
|
|
cursize = 0;
|
|
membase = NULL;
|
|
r = vm_allocate(task_self(), (vm_address_t *)&membase, maxsize, 1);
|
|
if (!membase || r != KERN_SUCCESS)
|
|
ri.Sys_Error (ERR_FATAL,"vm_allocate failed");
|
|
membase->magic = HUNK_MAGIC;
|
|
membase->length = maxsize;
|
|
cursize = 32;
|
|
return (void *)((byte *)membase + cursize);
|
|
}
|
|
|
|
void *Hunk_Alloc (int size)
|
|
{
|
|
// round to cacheline
|
|
size = (size+31)&~31;
|
|
|
|
cursize += size;
|
|
|
|
if (cursize > maxsize)
|
|
ri.Sys_Error (ERR_DROP, "Hunk_Alloc overflow");
|
|
|
|
memset ((byte *)membase+cursize-size,0,size);
|
|
|
|
return (void *)((byte *)membase+cursize-size);
|
|
}
|
|
|
|
int Hunk_End (void)
|
|
{
|
|
kern_return_t r;
|
|
|
|
// round to pagesize
|
|
cursize = (cursize+vm_page_size)&~(vm_page_size-1);
|
|
membase->length = cursize;
|
|
r = vm_deallocate(task_self(),
|
|
(vm_address_t)((byte *)membase + cursize),
|
|
maxsize - cursize);
|
|
if ( r != KERN_SUCCESS )
|
|
ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
|
|
return cursize;
|
|
}
|
|
|
|
void Hunk_Free (void *base)
|
|
{
|
|
hunkheader_t *h;
|
|
kern_return_t r;
|
|
|
|
h = ((hunkheader_t *)base) - 1;
|
|
if (h->magic != HUNK_MAGIC)
|
|
ri.Sys_Error (ERR_FATAL, "Hunk_Free: bad magic");
|
|
|
|
r = vm_deallocate(task_self(), (vm_address_t)h, h->length);
|
|
if ( r != KERN_SUCCESS )
|
|
ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_MakeCodeWriteable
|
|
================
|
|
*/
|
|
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_SetPalette
|
|
================
|
|
*/
|
|
void Sys_SetPalette (byte *palette)
|
|
{
|
|
byte *p;
|
|
int i;
|
|
|
|
memcpy (current_palette, palette, sizeof(current_palette));
|
|
p = (byte *)gamma_palette;
|
|
// gamma correct and byte swap
|
|
for (i=0 ; i<256 ; i++, p+=4, palette+=4)
|
|
{
|
|
p[0] = gammatable[palette[0]];
|
|
p[1] = gammatable[palette[1]];
|
|
p[2] = gammatable[palette[2]];
|
|
p[3] = 0xff;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
|
|
NEXTSTEP VIEW CLASS
|
|
|
|
==========================================================================
|
|
*/
|
|
#include "../client/keys.h"
|
|
|
|
void IN_ActivateMouse (void);
|
|
void IN_DeactivateMouse (void);
|
|
|
|
@implementation QuakeView
|
|
|
|
-(BOOL) acceptsFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (void)windowDidMove: (NSNotification *)note
|
|
{
|
|
NSRect r;
|
|
|
|
r = [vid_window_i frame];
|
|
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_x %i", (int)r.origin.x+1));
|
|
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_y %i", (int)r.origin.y+1));
|
|
}
|
|
|
|
- (void)becomeKeyWindow
|
|
{
|
|
IN_ActivateMouse ();
|
|
}
|
|
|
|
- (void)resignKeyWindow
|
|
{
|
|
IN_DeactivateMouse ();
|
|
}
|
|
|
|
|
|
typedef struct
|
|
{
|
|
int source, dest;
|
|
} keymap_t;
|
|
|
|
keymap_t keymaps[] =
|
|
{
|
|
{103, K_RIGHTARROW},
|
|
{102, K_LEFTARROW},
|
|
{100, K_UPARROW},
|
|
{101, K_DOWNARROW},
|
|
|
|
{59, K_F1},
|
|
{60, K_F2},
|
|
{61, K_F3},
|
|
{62, K_F4},
|
|
{63, K_F5},
|
|
{64, K_F6},
|
|
{65, K_F7},
|
|
{66, K_F8},
|
|
{67, K_F9},
|
|
{68, K_F10},
|
|
{87, K_F11},
|
|
{88, K_F12},
|
|
|
|
{-1,-1}
|
|
};
|
|
|
|
keymap_t flagmaps[] =
|
|
{
|
|
{NSShiftKeyMask, K_SHIFT},
|
|
{NSControlKeyMask, K_CTRL},
|
|
{NSAlternateKeyMask, K_ALT},
|
|
{NSCommandKeyMask, K_ALT},
|
|
|
|
{-1,-1}
|
|
};
|
|
|
|
- (void)mouseDown:(NSEvent *)theEvent
|
|
{
|
|
Key_Event (K_MOUSE1, true);
|
|
}
|
|
- (void)mouseUp:(NSEvent *)theEvent
|
|
{
|
|
Key_Event (K_MOUSE1, false);
|
|
}
|
|
- (void)rightMouseDown:(NSEvent *)theEvent
|
|
{
|
|
Key_Event (K_MOUSE2, true);
|
|
}
|
|
- (void)rightMouseUp:(NSEvent *)theEvent
|
|
{
|
|
Key_Event (K_MOUSE2, false);
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
keyboard methods
|
|
===================
|
|
*/
|
|
- (void)keyDown:(NSEvent *)theEvent
|
|
{
|
|
int ch;
|
|
keymap_t *km;
|
|
|
|
// PSobscurecursor ();
|
|
|
|
// check for non-ascii first
|
|
ch = [theEvent keyCode];
|
|
for (km=keymaps;km->source!=-1;km++)
|
|
if (ch == km->source)
|
|
{
|
|
Key_Event (km->dest, true);
|
|
return;
|
|
}
|
|
|
|
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
|
if (ch >= 'A' && ch <= 'Z')
|
|
ch += 'a' - 'A';
|
|
if (ch>=256)
|
|
return;
|
|
|
|
Key_Event (ch, true);
|
|
}
|
|
|
|
- (void)flagsChanged:(NSEvent *)theEvent
|
|
{
|
|
static int oldflags;
|
|
int newflags;
|
|
int delta;
|
|
keymap_t *km;
|
|
int i;
|
|
|
|
// PSobscurecursor ();
|
|
newflags = [theEvent modifierFlags];
|
|
delta = newflags ^ oldflags;
|
|
for (i=0 ; i<32 ; i++)
|
|
{
|
|
if ( !(delta & (1<<i)))
|
|
continue;
|
|
// changed
|
|
for (km=flagmaps;km->source!=-1;km++)
|
|
if ( (1<<i) == km->source)
|
|
{
|
|
if (newflags & (1<<i))
|
|
Key_Event (km->dest, true);
|
|
else
|
|
Key_Event (km->dest, false);
|
|
}
|
|
|
|
}
|
|
|
|
oldflags = newflags;
|
|
}
|
|
|
|
|
|
- (void)keyUp:(NSEvent *)theEvent
|
|
{
|
|
int ch;
|
|
keymap_t *km;
|
|
|
|
// check for non-ascii first
|
|
ch = [theEvent keyCode];
|
|
for (km=keymaps;km->source!=-1;km++)
|
|
if (ch == km->source)
|
|
{
|
|
Key_Event (km->dest, false);
|
|
return;
|
|
}
|
|
|
|
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
|
if (ch >= 'A' && ch <= 'Z')
|
|
ch += 'a' - 'A';
|
|
if (ch>=256)
|
|
return;
|
|
Key_Event (ch, false);
|
|
}
|
|
|
|
@end
|
|
|
|
|