mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-22 20:02:09 +00:00
c3f5581b0a
Unchained, Ultimate, Ultra, Up Yours, Underworld, Underground, Unified, Unity, etc. You know the drill. This takes care of the "standalone" problem with the wrong name, and the recent snafu with multiple developers working on the same files simultaneously...expect me (and probably others) to start locking dirs when updates are taking place. And yes, this update is really as large as it looks. Software only at the moment, but I will have the makefile updated to build the GL builds as well.
953 lines
19 KiB
C
953 lines
19 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 <errno.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <dir.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <dpmi.h>
|
|
#include <sys/nearptr.h>
|
|
#include <conio.h>
|
|
|
|
#include "quakedef.h"
|
|
#include "dosisms.h"
|
|
|
|
#define MINIMUM_WIN_MEMORY 0x800000
|
|
#define MINIMUM_WIN_MEMORY_LEVELPAK (MINIMUM_WIN_MEMORY + 0x100000)
|
|
|
|
int end_of_memory;
|
|
qboolean lockmem, lockunlockmem, unlockmem;
|
|
static int win95;
|
|
|
|
#define STDOUT 1
|
|
|
|
#define KEYBUF_SIZE 256
|
|
static unsigned char keybuf[KEYBUF_SIZE];
|
|
static int keybuf_head=0;
|
|
static int keybuf_tail=0;
|
|
|
|
static quakeparms_t quakeparms;
|
|
int sys_checksum;
|
|
static double curtime = 0.0;
|
|
static double lastcurtime = 0.0;
|
|
static double oldtime = 0.0;
|
|
|
|
static qboolean isDedicated;
|
|
|
|
static int minmem;
|
|
|
|
float fptest_temp;
|
|
|
|
extern char start_of_memory __asm__("start");
|
|
|
|
//=============================================================================
|
|
|
|
// this is totally dependent on cwsdpmi putting the stack right after tge
|
|
// global data
|
|
|
|
// This does evil things in a Win95 DOS box!!!
|
|
#if 0
|
|
extern byte end;
|
|
#define CHECKBYTE 0xed
|
|
void Sys_InitStackCheck (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i<128*1024 ; i++)
|
|
(&end)[i] = CHECKBYTE;
|
|
}
|
|
|
|
void Sys_StackCheck (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i<128*1024 ; i++)
|
|
if ( (&end)[i] != CHECKBYTE )
|
|
break;
|
|
|
|
Con_Printf ("%i undisturbed stack bytes\n", i);
|
|
if (end != CHECKBYTE)
|
|
Sys_Error ("System stack overflow!");
|
|
}
|
|
#endif
|
|
|
|
//=============================================================================
|
|
|
|
byte scantokey[128] =
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 8 9 A B C D E F
|
|
0 , 27, '1', '2', '3', '4', '5', '6',
|
|
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
|
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
|
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
|
|
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
|
|
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
|
|
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
|
|
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
|
|
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME,
|
|
K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4
|
|
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
|
|
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
|
|
};
|
|
|
|
byte shiftscantokey[128] =
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 8 9 A B C D E F
|
|
0 , 27, '!', '@', '#', '$', '%', '^',
|
|
'&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0
|
|
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
|
'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1
|
|
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
|
|
'"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2
|
|
'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*',
|
|
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
|
|
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME,
|
|
K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4
|
|
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
|
|
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
|
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
|
|
};
|
|
|
|
void TrapKey(void)
|
|
{
|
|
// static int ctrl=0;
|
|
keybuf[keybuf_head] = dos_inportb(0x60);
|
|
dos_outportb(0x20, 0x20);
|
|
/*
|
|
if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL)
|
|
ctrl=keybuf[keybuf_head]&0x80;
|
|
if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c')
|
|
Sys_Error("ctrl-c hit\n");
|
|
*/
|
|
keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1);
|
|
}
|
|
|
|
#define SC_UPARROW 0x48
|
|
#define SC_DOWNARROW 0x50
|
|
#define SC_LEFTARROW 0x4b
|
|
#define SC_RIGHTARROW 0x4d
|
|
#define SC_LEFTSHIFT 0x2a
|
|
#define SC_RIGHTSHIFT 0x36
|
|
#define SC_RIGHTARROW 0x4d
|
|
|
|
void MaskExceptions (void);
|
|
void Sys_InitFloatTime (void);
|
|
void Sys_PushFPCW_SetHigh (void);
|
|
void Sys_PopFPCW (void);
|
|
|
|
#define LEAVE_FOR_CACHE (512*1024) //FIXME: tune
|
|
#define LOCKED_FOR_MALLOC (128*1024) //FIXME: tune
|
|
|
|
|
|
void Sys_DetectWin95 (void)
|
|
{
|
|
__dpmi_regs r;
|
|
|
|
r.x.ax = 0x160a; /* Get Windows Version */
|
|
__dpmi_int(0x2f, &r);
|
|
|
|
if(r.x.ax || r.h.bh < 4) /* Not windows or earlier than Win95 */
|
|
{
|
|
win95 = 0;
|
|
lockmem = true;
|
|
lockunlockmem = false;
|
|
unlockmem = true;
|
|
}
|
|
else
|
|
{
|
|
win95 = 1;
|
|
lockunlockmem = COM_CheckParm ("-winlockunlock");
|
|
|
|
if (lockunlockmem)
|
|
lockmem = true;
|
|
else
|
|
lockmem = COM_CheckParm ("-winlock");
|
|
|
|
unlockmem = lockmem && !lockunlockmem;
|
|
}
|
|
}
|
|
|
|
|
|
void *dos_getmaxlockedmem(int *size)
|
|
{
|
|
__dpmi_free_mem_info meminfo;
|
|
__dpmi_meminfo info;
|
|
int working_size;
|
|
void *working_memory;
|
|
int last_locked;
|
|
int extra, i, j, allocsize;
|
|
static char *msg = "Locking data...";
|
|
int m, n;
|
|
byte *x;
|
|
|
|
// first lock all the current executing image so the locked count will
|
|
// be accurate. It doesn't hurt to lock the memory multiple times
|
|
last_locked = __djgpp_selector_limit + 1;
|
|
info.size = last_locked - 4096;
|
|
info.address = __djgpp_base_address + 4096;
|
|
|
|
if (lockmem)
|
|
{
|
|
if(__dpmi_lock_linear_region(&info))
|
|
{
|
|
Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n",
|
|
info.address, info.size/1024);
|
|
}
|
|
}
|
|
|
|
__dpmi_get_free_memory_information(&meminfo);
|
|
|
|
if (!win95) /* Not windows or earlier than Win95 */
|
|
{
|
|
working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096;
|
|
}
|
|
else
|
|
{
|
|
working_size = meminfo.largest_available_free_block_in_bytes -
|
|
LEAVE_FOR_CACHE;
|
|
}
|
|
|
|
working_size &= ~0xffff; /* Round down to 64K */
|
|
working_size += 0x10000;
|
|
|
|
do
|
|
{
|
|
working_size -= 0x10000; /* Decrease 64K and try again */
|
|
working_memory = sbrk(working_size);
|
|
} while (working_memory == (void *)-1);
|
|
|
|
extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff);
|
|
|
|
if (extra > 0)
|
|
{
|
|
sbrk(extra);
|
|
working_size += extra;
|
|
}
|
|
|
|
// now grab the memory
|
|
info.address = last_locked + __djgpp_base_address;
|
|
|
|
if (!win95)
|
|
{
|
|
info.size = __djgpp_selector_limit + 1 - last_locked;
|
|
|
|
while (info.size > 0 && __dpmi_lock_linear_region(&info))
|
|
{
|
|
info.size -= 0x1000;
|
|
working_size -= 0x1000;
|
|
sbrk(-0x1000);
|
|
}
|
|
}
|
|
else
|
|
{ /* Win95 section */
|
|
j = COM_CheckParm("-winmem");
|
|
|
|
if (standard_quake)
|
|
minmem = MINIMUM_WIN_MEMORY;
|
|
else
|
|
minmem = MINIMUM_WIN_MEMORY_LEVELPAK;
|
|
|
|
if (j)
|
|
{
|
|
allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 +
|
|
LOCKED_FOR_MALLOC;
|
|
|
|
if (allocsize < (minmem + LOCKED_FOR_MALLOC))
|
|
allocsize = minmem + LOCKED_FOR_MALLOC;
|
|
}
|
|
else
|
|
{
|
|
allocsize = minmem + LOCKED_FOR_MALLOC;
|
|
}
|
|
|
|
if (!lockmem)
|
|
{
|
|
// we won't lock, just sbrk the memory
|
|
info.size = allocsize;
|
|
goto UpdateSbrk;
|
|
}
|
|
|
|
// lock the memory down
|
|
write (STDOUT, msg, strlen (msg));
|
|
|
|
for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ;
|
|
j -= 0x100000)
|
|
{
|
|
info.size = j;
|
|
|
|
if (!__dpmi_lock_linear_region(&info))
|
|
goto Locked;
|
|
|
|
write (STDOUT, ".", 1);
|
|
}
|
|
|
|
// finally, try with the absolute minimum amount
|
|
for (i=0 ; i<10 ; i++)
|
|
{
|
|
info.size = minmem + LOCKED_FOR_MALLOC;
|
|
|
|
if (!__dpmi_lock_linear_region(&info))
|
|
goto Locked;
|
|
}
|
|
|
|
Sys_Error ("Can't lock memory; %d Mb lockable RAM required. "
|
|
"Try shrinking smartdrv.", info.size / 0x100000);
|
|
|
|
Locked:
|
|
|
|
UpdateSbrk:
|
|
|
|
info.address += info.size;
|
|
info.address -= __djgpp_base_address + 4; // ending point, malloc align
|
|
working_size = info.address - (int)working_memory;
|
|
sbrk(info.address-(int)sbrk(0)); // negative adjustment
|
|
}
|
|
|
|
|
|
if (lockunlockmem)
|
|
{
|
|
__dpmi_unlock_linear_region (&info);
|
|
printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000);
|
|
}
|
|
else if (lockmem)
|
|
{
|
|
printf ("Locked %d Mb data\n", working_size / 0x100000);
|
|
}
|
|
else
|
|
{
|
|
printf ("Allocated %d Mb data\n", working_size / 0x100000);
|
|
}
|
|
|
|
// touch all the memory to make sure it's there. The 16-page skip is to
|
|
// keep Win 95 from thinking we're trying to page ourselves in (we are
|
|
// doing that, of course, but there's no reason we shouldn't)
|
|
x = (byte *)working_memory;
|
|
|
|
for (n=0 ; n<4 ; n++)
|
|
{
|
|
for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4)
|
|
{
|
|
sys_checksum += *(int *)&x[m];
|
|
sys_checksum += *(int *)&x[m + 16 * 0x1000];
|
|
}
|
|
}
|
|
|
|
// give some of what we locked back for malloc before returning. Done
|
|
// by cheating and passing a negative value to sbrk
|
|
working_size -= LOCKED_FOR_MALLOC;
|
|
sbrk( -(LOCKED_FOR_MALLOC));
|
|
*size = working_size;
|
|
return working_memory;
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
Sys_FileTime
|
|
|
|
returns -1 if not present
|
|
============
|
|
*/
|
|
int Sys_FileTime (char *path)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (stat (path,&buf) == -1)
|
|
return -1;
|
|
|
|
return buf.st_mtime;
|
|
}
|
|
|
|
void Sys_mkdir (char *path)
|
|
{
|
|
mkdir (path, 0777);
|
|
}
|
|
|
|
|
|
void Sys_Sleep(void)
|
|
{
|
|
}
|
|
|
|
|
|
char *Sys_ConsoleInput(void)
|
|
{
|
|
static char text[256];
|
|
static int len = 0;
|
|
char ch;
|
|
|
|
if (!isDedicated)
|
|
return NULL;
|
|
|
|
if (! kbhit())
|
|
return NULL;
|
|
|
|
ch = getche();
|
|
|
|
switch (ch)
|
|
{
|
|
case '\r':
|
|
putch('\n');
|
|
if (len)
|
|
{
|
|
text[len] = 0;
|
|
len = 0;
|
|
return text;
|
|
}
|
|
break;
|
|
|
|
case '\b':
|
|
putch(' ');
|
|
if (len)
|
|
{
|
|
len--;
|
|
putch('\b');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
text[len] = ch;
|
|
len = (len + 1) & 0xff;
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Sys_Init(void)
|
|
{
|
|
|
|
MaskExceptions ();
|
|
|
|
Sys_SetFPCW ();
|
|
|
|
dos_outportb(0x43, 0x34); // set system timer to mode 2
|
|
dos_outportb(0x40, 0); // for the Sys_DoubleTime() function
|
|
dos_outportb(0x40, 0);
|
|
|
|
Sys_InitFloatTime ();
|
|
|
|
_go32_interrupt_stack_size = 4 * 1024;;
|
|
_go32_rmcb_stack_size = 4 * 1024;
|
|
}
|
|
|
|
void Sys_Shutdown(void)
|
|
{
|
|
if (!isDedicated)
|
|
dos_restoreintr(9);
|
|
|
|
if (unlockmem)
|
|
{
|
|
dos_unlockmem (&start_of_memory,
|
|
end_of_memory - (int)&start_of_memory);
|
|
dos_unlockmem (quakeparms.membase, quakeparms.memsize);
|
|
}
|
|
}
|
|
|
|
|
|
#define SC_RSHIFT 0x36
|
|
#define SC_LSHIFT 0x2a
|
|
void Sys_SendKeyEvents (void)
|
|
{
|
|
int k, next;
|
|
int outkey;
|
|
|
|
// get key events
|
|
|
|
while (keybuf_head != keybuf_tail)
|
|
{
|
|
|
|
k = keybuf[keybuf_tail++];
|
|
keybuf_tail &= (KEYBUF_SIZE-1);
|
|
|
|
if (k==0xe0)
|
|
continue; // special / pause keys
|
|
next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)];
|
|
if (next == 0xe1)
|
|
continue; // pause key bullshit
|
|
if (k==0xc5 && next == 0x9d)
|
|
{
|
|
Key_Event (K_PAUSE, true);
|
|
continue;
|
|
}
|
|
|
|
// extended keyboard shift key bullshit
|
|
if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT )
|
|
{
|
|
if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 )
|
|
continue;
|
|
k &= 0x80;
|
|
k |= SC_RSHIFT;
|
|
}
|
|
|
|
if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d)
|
|
continue; // more pause bullshit
|
|
|
|
outkey = scantokey[k & 0x7f];
|
|
|
|
if (k & 0x80)
|
|
Key_Event (outkey, false);
|
|
else
|
|
Key_Event (outkey, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// General routines
|
|
// =======================================================================
|
|
|
|
/*
|
|
================
|
|
Sys_Printf
|
|
================
|
|
*/
|
|
|
|
void Sys_Printf (char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
char text[1024];
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (text,fmt,argptr);
|
|
va_end (argptr);
|
|
|
|
if (cls.state == ca_dedicated)
|
|
fprintf(stderr, "%s", text);
|
|
}
|
|
|
|
void Sys_AtExit (void)
|
|
{
|
|
|
|
// shutdown only once (so Sys_Error can call this function to shutdown, then
|
|
// print the error message, then call exit without exit calling this function
|
|
// again)
|
|
Sys_Shutdown();
|
|
}
|
|
|
|
|
|
void Sys_Quit (void)
|
|
{
|
|
byte screen[80*25*2];
|
|
byte *d;
|
|
char ver[6];
|
|
int i;
|
|
|
|
|
|
// load the sell screen before shuting everything down
|
|
if (registered.value)
|
|
d = COM_LoadHunkFile ("end2.bin");
|
|
else
|
|
d = COM_LoadHunkFile ("end1.bin");
|
|
if (d)
|
|
memcpy (screen, d, sizeof(screen));
|
|
|
|
// write the version number directly to the end screen
|
|
sprintf (ver, " v%4.2f", VERSION);
|
|
for (i=0 ; i<6 ; i++)
|
|
screen[0*80*2 + 72*2 + i*2] = ver[i];
|
|
|
|
Host_Shutdown();
|
|
|
|
// do the text mode sell screen
|
|
if (d)
|
|
{
|
|
memcpy ((void *)real2ptr(0xb8000), screen,80*25*2);
|
|
|
|
// set text pos
|
|
regs.x.ax = 0x0200;
|
|
regs.h.bh = 0;
|
|
regs.h.dl = 0;
|
|
regs.h.dh = 22;
|
|
dos_int86 (0x10);
|
|
}
|
|
else
|
|
printf ("couldn't load endscreen.\n");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
void Sys_Error (char *error, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,error);
|
|
vsprintf (string,error,argptr);
|
|
va_end (argptr);
|
|
|
|
Host_Shutdown();
|
|
fprintf(stderr, "Error: %s\n", string);
|
|
// Sys_AtExit is called by exit to shutdown the system
|
|
exit(0);
|
|
}
|
|
|
|
|
|
int Sys_FileOpenRead (char *path, int *handle)
|
|
{
|
|
int h;
|
|
struct stat fileinfo;
|
|
|
|
h = open (path, O_RDONLY|O_BINARY, 0666);
|
|
*handle = h;
|
|
if (h == -1)
|
|
return -1;
|
|
|
|
if (fstat (h,&fileinfo) == -1)
|
|
Sys_Error ("Error fstating %s", path);
|
|
|
|
return fileinfo.st_size;
|
|
}
|
|
|
|
int Sys_FileOpenWrite (char *path)
|
|
{
|
|
int handle;
|
|
|
|
umask (0);
|
|
|
|
handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
|
|
, 0666);
|
|
|
|
if (handle == -1)
|
|
Sys_Error ("Error opening %s: %s", path,strerror(errno));
|
|
|
|
return handle;
|
|
}
|
|
|
|
void Sys_FileClose (int handle)
|
|
{
|
|
close (handle);
|
|
}
|
|
|
|
void Sys_FileSeek (int handle, int position)
|
|
{
|
|
lseek (handle, position, SEEK_SET);
|
|
}
|
|
|
|
int Sys_FileRead (int handle, void *dest, int count)
|
|
{
|
|
return read (handle, dest, count);
|
|
}
|
|
|
|
int Sys_FileWrite (int handle, void *data, int count)
|
|
{
|
|
return write (handle, data, count);
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_MakeCodeWriteable
|
|
================
|
|
*/
|
|
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
|
{
|
|
// it's always writeable
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_DoubleTime
|
|
================
|
|
*/
|
|
double Sys_DoubleTime (void)
|
|
{
|
|
int r;
|
|
unsigned t, tick;
|
|
double ft, time;
|
|
static int sametimecount;
|
|
|
|
Sys_PushFPCW_SetHigh ();
|
|
|
|
//{static float t = 0; t=t+0.05; return t;} // DEBUG
|
|
|
|
t = *(unsigned short*)real2ptr(0x46c) * 65536;
|
|
|
|
dos_outportb(0x43, 0); // latch time
|
|
r = dos_inportb(0x40);
|
|
r |= dos_inportb(0x40) << 8;
|
|
r = (r-1) & 0xffff;
|
|
|
|
tick = *(unsigned short*)real2ptr(0x46c) * 65536;
|
|
if ((tick != t) && (r & 0x8000))
|
|
t = tick;
|
|
|
|
ft = (double) (t+(65536-r)) / 1193200.0;
|
|
time = ft - oldtime;
|
|
oldtime = ft;
|
|
|
|
if (time < 0)
|
|
{
|
|
if (time > -3000.0)
|
|
time = 0.0;
|
|
else
|
|
time += 3600.0;
|
|
}
|
|
|
|
curtime += time;
|
|
|
|
if (curtime == lastcurtime)
|
|
{
|
|
sametimecount++;
|
|
|
|
if (sametimecount > 100000)
|
|
{
|
|
curtime += 1.0;
|
|
sametimecount = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sametimecount = 0;
|
|
}
|
|
|
|
lastcurtime = curtime;
|
|
|
|
Sys_PopFPCW ();
|
|
|
|
return curtime;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_InitFloatTime
|
|
================
|
|
*/
|
|
void Sys_InitFloatTime (void)
|
|
{
|
|
int j;
|
|
|
|
Sys_DoubleTime ();
|
|
|
|
oldtime = curtime;
|
|
|
|
j = COM_CheckParm("-starttime");
|
|
|
|
if (j)
|
|
{
|
|
curtime = (double) (Q_atof(com_argv[j+1]));
|
|
}
|
|
else
|
|
{
|
|
curtime = 0.0;
|
|
}
|
|
lastcurtime = curtime;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_GetMemory
|
|
================
|
|
*/
|
|
void Sys_GetMemory(void)
|
|
{
|
|
int j, tsize;
|
|
|
|
j = COM_CheckParm("-mem");
|
|
if (j)
|
|
{
|
|
quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
|
|
quakeparms.membase = malloc (quakeparms.memsize);
|
|
}
|
|
else
|
|
{
|
|
quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize);
|
|
}
|
|
|
|
fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize);
|
|
|
|
if (COM_CheckParm ("-heapsize"))
|
|
{
|
|
tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024;
|
|
|
|
if (tsize < quakeparms.memsize)
|
|
quakeparms.memsize = tsize;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_PageInProgram
|
|
|
|
walks the text, data, and bss to make sure it's all paged in so that the
|
|
actual physical memory detected by Sys_GetMemory is correct.
|
|
================
|
|
*/
|
|
void Sys_PageInProgram(void)
|
|
{
|
|
int i, j;
|
|
|
|
end_of_memory = (int)sbrk(0);
|
|
|
|
if (lockmem)
|
|
{
|
|
if (dos_lockmem ((void *)&start_of_memory,
|
|
end_of_memory - (int)&start_of_memory))
|
|
Sys_Error ("Couldn't lock text and data");
|
|
}
|
|
|
|
if (lockunlockmem)
|
|
{
|
|
dos_unlockmem((void *)&start_of_memory,
|
|
end_of_memory - (int)&start_of_memory);
|
|
printf ("Locked and unlocked %d Mb image\n",
|
|
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
|
}
|
|
else if (lockmem)
|
|
{
|
|
printf ("Locked %d Mb image\n",
|
|
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
|
}
|
|
else
|
|
{
|
|
printf ("Loaded %d Mb image\n",
|
|
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
|
}
|
|
|
|
// touch the entire image, doing the 16-page skip so Win95 doesn't think we're
|
|
// trying to page ourselves in
|
|
for (j=0 ; j<4 ; j++)
|
|
{
|
|
for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4)
|
|
{
|
|
sys_checksum += *(int *)i;
|
|
sys_checksum += *(int *)(i + 16 * 0x1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_NoFPUExceptionHandler
|
|
================
|
|
*/
|
|
void Sys_NoFPUExceptionHandler(int whatever)
|
|
{
|
|
printf ("\nError: Quake requires a floating-point processor\n");
|
|
exit (0);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Sys_DefaultExceptionHandler
|
|
================
|
|
*/
|
|
void Sys_DefaultExceptionHandler(int whatever)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
main
|
|
================
|
|
*/
|
|
int main (int c, char **v)
|
|
{
|
|
double time, oldtime, newtime;
|
|
extern void (*dos_error_func)(char *, ...);
|
|
static char cwd[1024];
|
|
|
|
printf ("Quake v%4.2f\n", VERSION);
|
|
|
|
// make sure there's an FPU
|
|
signal(SIGNOFP, Sys_NoFPUExceptionHandler);
|
|
signal(SIGABRT, Sys_DefaultExceptionHandler);
|
|
signal(SIGALRM, Sys_DefaultExceptionHandler);
|
|
signal(SIGKILL, Sys_DefaultExceptionHandler);
|
|
signal(SIGQUIT, Sys_DefaultExceptionHandler);
|
|
signal(SIGINT, Sys_DefaultExceptionHandler);
|
|
|
|
if (fptest_temp >= 0.0)
|
|
fptest_temp += 0.1;
|
|
|
|
COM_InitArgv (c, v);
|
|
|
|
quakeparms.argc = com_argc;
|
|
quakeparms.argv = com_argv;
|
|
|
|
dos_error_func = Sys_Error;
|
|
|
|
Sys_DetectWin95 ();
|
|
Sys_PageInProgram ();
|
|
Sys_GetMemory ();
|
|
|
|
atexit (Sys_AtExit); // in case we crash
|
|
|
|
getwd (cwd);
|
|
if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0;
|
|
quakeparms.basedir = cwd; //"f:/quake";
|
|
|
|
isDedicated = (COM_CheckParm ("-dedicated") != 0);
|
|
|
|
Sys_Init ();
|
|
|
|
if (!isDedicated)
|
|
dos_registerintr(9, TrapKey);
|
|
|
|
//Sys_InitStackCheck ();
|
|
|
|
Host_Init(&quakeparms);
|
|
|
|
//Sys_StackCheck ();
|
|
|
|
//Con_Printf ("Top of stack: 0x%x\n", &time);
|
|
oldtime = Sys_DoubleTime ();
|
|
while (1)
|
|
{
|
|
newtime = Sys_DoubleTime ();
|
|
time = newtime - oldtime;
|
|
|
|
if (cls.state == ca_dedicated && (time<sys_ticrate.value))
|
|
continue;
|
|
|
|
Host_Frame (time);
|
|
|
|
//Sys_StackCheck ();
|
|
|
|
oldtime = newtime;
|
|
}
|
|
}
|
|
|
|
|