5d05b9d3e9
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
367 lines
7.1 KiB
C
367 lines
7.1 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
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 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"
|
|
|
|
void CL_FinishTimeDemo (void);
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
DEMO CODE
|
|
|
|
When a demo is playing back, all NET_SendMessages are skipped, and
|
|
NET_GetMessages are read from the demo file.
|
|
|
|
Whenever cl.time gets past the last received message, another message is
|
|
read from the demo file.
|
|
==============================================================================
|
|
*/
|
|
|
|
/*
|
|
==============
|
|
CL_StopPlayback
|
|
|
|
Called when a demo file runs out, or the user starts a game
|
|
==============
|
|
*/
|
|
void CL_StopPlayback (void)
|
|
{
|
|
if (!cls.demoplayback)
|
|
return;
|
|
|
|
fclose (cls.demofile);
|
|
cls.demoplayback = false;
|
|
cls.demofile = NULL;
|
|
cls.state = ca_disconnected;
|
|
|
|
if (cls.timedemo)
|
|
CL_FinishTimeDemo ();
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_WriteDemoMessage
|
|
|
|
Dumps the current net message, prefixed by the length and view angles
|
|
====================
|
|
*/
|
|
void CL_WriteDemoMessage (void)
|
|
{
|
|
int len;
|
|
int i;
|
|
float f;
|
|
|
|
len = LittleLong (net_message.cursize);
|
|
fwrite (&len, 4, 1, cls.demofile);
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
f = LittleFloat (cl.viewangles[i]);
|
|
fwrite (&f, 4, 1, cls.demofile);
|
|
}
|
|
fwrite (net_message.data, net_message.cursize, 1, cls.demofile);
|
|
fflush (cls.demofile);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_GetMessage
|
|
|
|
Handles recording and playback of demos, on top of NET_ code
|
|
====================
|
|
*/
|
|
int CL_GetMessage (void)
|
|
{
|
|
int r, i;
|
|
float f;
|
|
|
|
if (cls.demoplayback)
|
|
{
|
|
// decide if it is time to grab the next message
|
|
if (cls.signon == SIGNONS) // allways grab until fully connected
|
|
{
|
|
if (cls.timedemo)
|
|
{
|
|
if (host_framecount == cls.td_lastframe)
|
|
return 0; // allready read this frame's message
|
|
cls.td_lastframe = host_framecount;
|
|
// if this is the second frame, grab the real td_starttime
|
|
// so the bogus time on the first frame doesn't count
|
|
if (host_framecount == cls.td_startframe + 1)
|
|
cls.td_starttime = realtime;
|
|
}
|
|
else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])
|
|
{
|
|
return 0; // don't need another message yet
|
|
}
|
|
}
|
|
|
|
// get the next message
|
|
fread (&net_message.cursize, 4, 1, cls.demofile);
|
|
VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r = fread (&f, 4, 1, cls.demofile);
|
|
cl.mviewangles[0][i] = LittleFloat (f);
|
|
}
|
|
|
|
net_message.cursize = LittleLong (net_message.cursize);
|
|
if (net_message.cursize > MAX_MSGLEN)
|
|
Sys_Error ("Demo message > MAX_MSGLEN");
|
|
r = fread (net_message.data, net_message.cursize, 1, cls.demofile);
|
|
if (r != 1)
|
|
{
|
|
CL_StopPlayback ();
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
r = NET_GetMessage (cls.netcon);
|
|
|
|
if (r != 1 && r != 2)
|
|
return r;
|
|
|
|
// discard nop keepalive message
|
|
if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
|
|
Con_Printf ("<-- server to client keepalive\n");
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (cls.demorecording)
|
|
CL_WriteDemoMessage ();
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
CL_Stop_f
|
|
|
|
stop recording a demo
|
|
====================
|
|
*/
|
|
void CL_Stop_f (void)
|
|
{
|
|
if (cmd_source != src_command)
|
|
return;
|
|
|
|
if (!cls.demorecording)
|
|
{
|
|
Con_Printf ("Not recording a demo.\n");
|
|
return;
|
|
}
|
|
|
|
// write a disconnect message to the demo file
|
|
SZ_Clear (&net_message);
|
|
MSG_WriteByte (&net_message, svc_disconnect);
|
|
CL_WriteDemoMessage ();
|
|
|
|
// finish up
|
|
fclose (cls.demofile);
|
|
cls.demofile = NULL;
|
|
cls.demorecording = false;
|
|
Con_Printf ("Completed demo\n");
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_Record_f
|
|
|
|
record <demoname> <map> [cd track]
|
|
====================
|
|
*/
|
|
void CL_Record_f (void)
|
|
{
|
|
int c;
|
|
char name[MAX_OSPATH];
|
|
int track;
|
|
|
|
if (cmd_source != src_command)
|
|
return;
|
|
|
|
c = Cmd_Argc();
|
|
if (c != 2 && c != 3 && c != 4)
|
|
{
|
|
Con_Printf ("record <demoname> [<map> [cd track]]\n");
|
|
return;
|
|
}
|
|
|
|
if (strstr(Cmd_Argv(1), ".."))
|
|
{
|
|
Con_Printf ("Relative pathnames are not allowed.\n");
|
|
return;
|
|
}
|
|
|
|
if (c == 2 && cls.state == ca_connected)
|
|
{
|
|
Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
|
|
return;
|
|
}
|
|
|
|
// write the forced cd track number, or -1
|
|
if (c == 4)
|
|
{
|
|
track = atoi(Cmd_Argv(3));
|
|
Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
|
|
}
|
|
else
|
|
track = -1;
|
|
|
|
sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
|
|
|
|
//
|
|
// start the map up
|
|
//
|
|
if (c > 2)
|
|
Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
|
|
|
|
//
|
|
// open the demo file
|
|
//
|
|
COM_DefaultExtension (name, ".dem");
|
|
|
|
Con_Printf ("recording to %s.\n", name);
|
|
cls.demofile = fopen (name, "wb");
|
|
if (!cls.demofile)
|
|
{
|
|
Con_Printf ("ERROR: couldn't open.\n");
|
|
return;
|
|
}
|
|
|
|
cls.forcetrack = track;
|
|
fprintf (cls.demofile, "%i\n", cls.forcetrack);
|
|
|
|
cls.demorecording = true;
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
CL_PlayDemo_f
|
|
|
|
play [demoname]
|
|
====================
|
|
*/
|
|
void CL_PlayDemo_f (void)
|
|
{
|
|
char name[256];
|
|
int c;
|
|
qboolean neg = false;
|
|
|
|
if (cmd_source != src_command)
|
|
return;
|
|
|
|
if (Cmd_Argc() != 2)
|
|
{
|
|
Con_Printf ("play <demoname> : plays a demo\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// disconnect from server
|
|
//
|
|
CL_Disconnect ();
|
|
|
|
//
|
|
// open the demo file
|
|
//
|
|
strcpy (name, Cmd_Argv(1));
|
|
COM_DefaultExtension (name, ".dem");
|
|
|
|
Con_Printf ("Playing demo from %s.\n", name);
|
|
COM_FOpenFile (name, &cls.demofile);
|
|
if (!cls.demofile)
|
|
{
|
|
Con_Printf ("ERROR: couldn't open.\n");
|
|
cls.demonum = -1; // stop demo loop
|
|
return;
|
|
}
|
|
|
|
cls.demoplayback = true;
|
|
cls.state = ca_connected;
|
|
cls.forcetrack = 0;
|
|
|
|
while ((c = getc(cls.demofile)) != '\n')
|
|
if (c == '-')
|
|
neg = true;
|
|
else
|
|
cls.forcetrack = cls.forcetrack * 10 + (c - '0');
|
|
|
|
if (neg)
|
|
cls.forcetrack = -cls.forcetrack;
|
|
// ZOID, fscanf is evil
|
|
//fscanf (cls.demofile, "%i\n", &cls.forcetrack);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_FinishTimeDemo
|
|
|
|
====================
|
|
*/
|
|
void CL_FinishTimeDemo (void)
|
|
{
|
|
int frames;
|
|
float time;
|
|
|
|
cls.timedemo = false;
|
|
|
|
// the first frame didn't count
|
|
frames = (host_framecount - cls.td_startframe) - 1;
|
|
time = realtime - cls.td_starttime;
|
|
if (!time)
|
|
time = 1;
|
|
Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_TimeDemo_f
|
|
|
|
timedemo [demoname]
|
|
====================
|
|
*/
|
|
void CL_TimeDemo_f (void)
|
|
{
|
|
if (cmd_source != src_command)
|
|
return;
|
|
|
|
if (Cmd_Argc() != 2)
|
|
{
|
|
Con_Printf ("timedemo <demoname> : gets demo speeds\n");
|
|
return;
|
|
}
|
|
|
|
CL_PlayDemo_f ();
|
|
|
|
// cls.td_starttime will be grabbed at the second frame of the demo, so
|
|
// all the loading time doesn't get counted
|
|
|
|
cls.timedemo = true;
|
|
cls.td_startframe = host_framecount;
|
|
cls.td_lastframe = -1; // get a new message this frame
|
|
}
|
|
|