forked from len0rd/rockbox
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
436 lines
7.2 KiB
C
436 lines
7.2 KiB
C
#include <limits.h>
|
|
#include <sys/types.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
|
|
#include "quakedef.h"
|
|
|
|
qboolean isDedicated;
|
|
|
|
int noconinput = 0;
|
|
|
|
char *basedir = "/.rockbox/quake";
|
|
char *cachedir = NULL;
|
|
|
|
cvar_t sys_linerefresh = {"sys_linerefresh","0"};// set for entity display
|
|
cvar_t sys_nostdout = {"sys_nostdout","0"};
|
|
|
|
// =======================================================================
|
|
// General routines
|
|
// =======================================================================
|
|
|
|
void Sys_DebugNumber(int y, int val)
|
|
{
|
|
}
|
|
|
|
int enable_printf = 1;
|
|
|
|
void Sys_Printf (char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
char text[1024];
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (text,fmt,argptr);
|
|
va_end (argptr);
|
|
if(enable_printf)
|
|
{
|
|
printf("%s", text);
|
|
}
|
|
LOGF("%s", text);
|
|
|
|
//Con_Print (text);
|
|
}
|
|
|
|
void Sys_Quit (void)
|
|
{
|
|
Host_Shutdown();
|
|
exit(0);
|
|
}
|
|
|
|
void Sys_Init(void)
|
|
{
|
|
#if id386
|
|
Sys_SetFPCW();
|
|
#endif
|
|
}
|
|
|
|
#if !id386
|
|
|
|
/*
|
|
================
|
|
Sys_LowFPPrecision
|
|
================
|
|
*/
|
|
void Sys_LowFPPrecision (void)
|
|
{
|
|
// causes weird problems on Nextstep
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_HighFPPrecision
|
|
================
|
|
*/
|
|
void Sys_HighFPPrecision (void)
|
|
{
|
|
// causes weird problems on Nextstep
|
|
}
|
|
|
|
#endif // !id386
|
|
|
|
|
|
void Sys_Error (char *error, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,error);
|
|
vsprintf (string,error,argptr);
|
|
va_end (argptr);
|
|
rb->splashf(HZ*5, "Error: %s\n", string);
|
|
|
|
Host_Shutdown ();
|
|
exit (1);
|
|
|
|
}
|
|
|
|
void Sys_Warn (char *warning, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,warning);
|
|
vsprintf (string,warning,argptr);
|
|
va_end (argptr);
|
|
rb->splashf(HZ*2, "Warning: %s", string);
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
FILE IO
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#define MAX_HANDLES 10
|
|
static FILE *sys_handles[MAX_HANDLES];
|
|
|
|
void Sys_Shutdown(void)
|
|
{
|
|
for(int i = 0; i < MAX_HANDLES; i++)
|
|
{
|
|
FILE *f = sys_handles[i];
|
|
if(f)
|
|
fclose(f);
|
|
sys_handles[i] = NULL;
|
|
}
|
|
}
|
|
|
|
int findhandle (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=1 ; i<MAX_HANDLES ; i++)
|
|
if (!sys_handles[i])
|
|
return i;
|
|
Sys_Error ("out of handles");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Qfilelength
|
|
================
|
|
*/
|
|
static int Qfilelength (FILE *f)
|
|
{
|
|
int pos;
|
|
int end;
|
|
|
|
pos = ftell (f);
|
|
fseek (f, 0, SEEK_END);
|
|
end = ftell (f);
|
|
fseek (f, pos, SEEK_SET);
|
|
|
|
return end;
|
|
}
|
|
|
|
int Sys_FileOpenRead (char *path, int *hndl)
|
|
{
|
|
FILE *f;
|
|
int i;
|
|
|
|
i = findhandle ();
|
|
|
|
f = fopen(path, "rb");
|
|
if (!f)
|
|
{
|
|
*hndl = -1;
|
|
return -1;
|
|
}
|
|
sys_handles[i] = f;
|
|
*hndl = i;
|
|
|
|
//rb->splashf(HZ*2, "Allocating handle %d to %s", i, path);
|
|
|
|
|
|
return Qfilelength(f);
|
|
}
|
|
|
|
int Sys_FileOpenWrite (char *path)
|
|
{
|
|
FILE *f;
|
|
int i;
|
|
|
|
i = findhandle ();
|
|
|
|
f = fopen(path, "wb");
|
|
if (!f)
|
|
Sys_Error ("Error opening %s: %s", path,strerror(errno));
|
|
sys_handles[i] = f;
|
|
|
|
return i;
|
|
}
|
|
|
|
void Sys_FileClose (int handle)
|
|
{
|
|
if ( handle >= 0 ) {
|
|
//rb->splashf(HZ, "Close handle %d", handle);
|
|
fclose (sys_handles[handle]);
|
|
sys_handles[handle] = NULL;
|
|
}
|
|
}
|
|
|
|
void Sys_FileSeek (int handle, int position)
|
|
{
|
|
if ( handle >= 0 ) {
|
|
fseek (sys_handles[handle], position, SEEK_SET);
|
|
}
|
|
}
|
|
|
|
int Sys_FileRead (int handle, void *dst, int count)
|
|
{
|
|
char *data;
|
|
int size, done;
|
|
|
|
size = 0;
|
|
if ( handle >= 0 ) {
|
|
data = dst;
|
|
while ( count > 0 ) {
|
|
done = fread (data, 1, count, sys_handles[handle]);
|
|
if ( done == 0 ) {
|
|
break;
|
|
}
|
|
else if(done < 0)
|
|
{
|
|
Sys_Error("stream error %d, file is %d = %d", done, handle, sys_handles[handle]);
|
|
}
|
|
data += done;
|
|
count -= done;
|
|
size += done;
|
|
}
|
|
}
|
|
return size;
|
|
|
|
}
|
|
|
|
int Sys_FileWrite (int handle, void *src, int count)
|
|
{
|
|
char *data;
|
|
int size, done;
|
|
|
|
size = 0;
|
|
if ( handle >= 0 ) {
|
|
data = src;
|
|
while ( count > 0 ) {
|
|
done = fread (data, 1, count, sys_handles[handle]);
|
|
if ( done == 0 ) {
|
|
break;
|
|
}
|
|
data += done;
|
|
count -= done;
|
|
size += done;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int Sys_FileTime (char *path)
|
|
{
|
|
FILE *f;
|
|
|
|
f = fopen(path, "rb");
|
|
if (f)
|
|
{
|
|
fclose(f);
|
|
return 1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Sys_mkdir (char *path)
|
|
{
|
|
#ifdef __WIN32__
|
|
mkdir (path);
|
|
#else
|
|
mkdir (path);
|
|
#endif
|
|
}
|
|
|
|
void Sys_DebugLog(char *file, char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
static char data[1024];
|
|
FILE *fp;
|
|
|
|
va_start(argptr, fmt);
|
|
vsprintf(data, fmt, argptr);
|
|
va_end(argptr);
|
|
fp = fopen(file, "a");
|
|
fwrite(data, strlen(data), 1, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
double Sys_FloatTime (void)
|
|
{
|
|
static int starttime = 0;
|
|
|
|
if ( ! starttime )
|
|
starttime = *rb->current_tick;
|
|
|
|
return (*rb->current_tick - starttime) / ((double)HZ);
|
|
}
|
|
|
|
// =======================================================================
|
|
// Sleeps for microseconds
|
|
// =======================================================================
|
|
|
|
static volatile int oktogo;
|
|
|
|
void alarm_handler(int x)
|
|
{
|
|
oktogo=1;
|
|
}
|
|
|
|
byte *Sys_ZoneBase (int *size)
|
|
{
|
|
|
|
char *QUAKEOPT = getenv("QUAKEOPT");
|
|
|
|
*size = 0xc00000;
|
|
if (QUAKEOPT)
|
|
{
|
|
while (*QUAKEOPT)
|
|
if (tolower(*QUAKEOPT++) == 'm')
|
|
{
|
|
*size = atof(QUAKEOPT) * 1024*1024;
|
|
break;
|
|
}
|
|
}
|
|
return malloc (*size);
|
|
|
|
}
|
|
|
|
void Sys_LineRefresh(void)
|
|
{
|
|
}
|
|
|
|
void Sys_Sleep(void)
|
|
{
|
|
SDL_Delay(1);
|
|
}
|
|
|
|
void floating_point_exception_handler(int whatever)
|
|
{
|
|
// Sys_Warn("floating point exception\n");
|
|
}
|
|
|
|
void moncontrol(int x)
|
|
{
|
|
}
|
|
|
|
int my_main (int c, char **v)
|
|
{
|
|
double time, oldtime, newtime;
|
|
quakeparms_t parms;
|
|
extern int vcrFile;
|
|
extern int recording;
|
|
static int frame;
|
|
|
|
moncontrol(0);
|
|
|
|
// signal(SIGFPE, floating_point_exception_handler);
|
|
|
|
//rb->splash(0, "quake 1");
|
|
|
|
parms.memsize = 8*1024*1024;
|
|
parms.membase = malloc (parms.memsize);
|
|
parms.basedir = basedir;
|
|
parms.cachedir = cachedir;
|
|
|
|
COM_InitArgv(c, v);
|
|
parms.argc = com_argc;
|
|
parms.argv = com_argv;
|
|
|
|
Sys_Init();
|
|
//rb->splash(0, "quake 2");
|
|
|
|
Host_Init(&parms);
|
|
//rb->splash(0, "quake 3");
|
|
|
|
//Cvar_RegisterVariable (&sys_nostdout);
|
|
//rb->splash(0, "quake 4");
|
|
|
|
oldtime = Sys_FloatTime () - 0.1;
|
|
while (1)
|
|
{
|
|
// find time spent rendering last frame
|
|
newtime = Sys_FloatTime ();
|
|
time = newtime - oldtime;
|
|
|
|
if (cls.state == ca_dedicated)
|
|
{ // play vcrfiles at max speed
|
|
if (time < sys_ticrate.value && (vcrFile == -1 || recording) )
|
|
{
|
|
rb->yield();
|
|
continue; // not time to run a server only tic yet
|
|
}
|
|
time = sys_ticrate.value;
|
|
}
|
|
|
|
if (time > sys_ticrate.value*2)
|
|
oldtime = newtime;
|
|
else
|
|
oldtime += time;
|
|
|
|
if (++frame > 10)
|
|
moncontrol(1); // profile only while we do each Quake frame
|
|
Host_Frame (time);
|
|
moncontrol(0);
|
|
|
|
// graphic debugging aids
|
|
if (sys_linerefresh.value)
|
|
Sys_LineRefresh ();
|
|
|
|
rb->yield();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_MakeCodeWriteable
|
|
================
|
|
*/
|
|
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
|
{
|
|
|
|
Sys_Error("Protection change failed\n");
|
|
|
|
}
|
|
|