a dos port, as a dig at eukara about his xbox port project.

mouse+kb+soundblaster devices should work.
you can compile a dedicated server, but the lack of any networking support makes it a bit pointless.
the software renderer will work, but its crap and gets absolutely dire framerates.
there's no code to init mesa or anything, so its crappy-software rendering only.
I doubt anything useful will ever result from this, but it was still interesting to do. possibly the only useful thing to come from this will be from limiting ram use.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5104 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-05-19 03:32:02 +00:00
parent 5d2ff1286d
commit 445e7f476b
15 changed files with 1859 additions and 473 deletions

View file

@ -289,6 +289,12 @@ ifeq ($(FTE_TARGET),morphos)
endif
endif
ifeq ($(FTE_TARGET),dos)
#at least from dos.
CC=i586-pc-msdosdjgpp-gcc
CFLAGS+=-DNO_ZLIB
endif
#if you have an x86, you can get gcc to build binaries using 3 different ABIs, instead of builds for just the default ABI
ifeq ($(FTE_TARGET),linux32)
FTE_TARGET=linux
@ -360,6 +366,7 @@ CLIENT_DIR=$(BASE_DIR)/client
GL_DIR=$(BASE_DIR)/gl
D3D_DIR=$(BASE_DIR)/d3d
VK_DIR=$(BASE_DIR)/vk
SW_DIR=$(BASE_DIR)/sw
SERVER_DIR=$(BASE_DIR)/server
COMMON_DIR=$(BASE_DIR)/common
HTTP_DIR=$(BASE_DIR)/http
@ -399,6 +406,9 @@ endif
ifeq ($(FTE_TARGET),cyg)
BASELDFLAGS=-lm
endif
ifeq ($(FTE_TARGET),dos)
BASELDFLAGS=-lm
endif
ifeq ($(FTE_TARGET),morphos)
BASELDFLAGS=-lm
endif
@ -1369,6 +1379,30 @@ ifeq ($(FTE_TARGET),morphos)
SV_CFLAGS=$(SERVER_ONLY_CFLAGS)
endif
ifeq ($(FTE_TARGET),dos)
EXEPOSTFIX=.exe
SV_DIR=sv_dos
GLB_DIR=gl_dos
MB_DIR=m_dos
MCL_DIR=mcl_dos
MINGL_DIR=mingl_dos
VKB_DIR=vk_dos
VKCL_DIR=vkcl_dos
IMAGELDFLAGS=
OGGVORBISLDFLAGS=
SOFTWARE_OBJS=sw_rast.o sw_backend.o sw_image.o
M_LDFLAGS=
M_CFLAGS=-DSWQUAKE -DNO_ZLIB
MCL_OBJS=$(SOFTWARE_OBJS) $(D3DGL_OBJS) sw_viddos.o cd_null.o sys_dos.o snd_sblaster.o
M_EXE_NAME=../$(EXE_NAME)$(EXEPOSTFIX)
SV_EXE_NAME=../$(EXE_NAME)sv$(BITS)$(EXEPOSTFIX)
VK_EXE_NAME=../$(EXE_NAME)-vk$(BITS)$(EXEPOSTFIX)
VKCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) cd_null.o sys_dos.o snd_sblaster.o
endif
ifeq ($(FTE_TARGET),cyg)
SV_DIR=sv_cygwin
@ -1510,7 +1544,7 @@ ifneq ($(OUT_DIR),)
endif
VPATH = $(BASE_DIR) : $(CLIENT_DIR) : $(GL_DIR) : $(COMMON_DIR) : $(SERVER_DIR) : $(HTTP_DIR) : $(BASE_DIR)/irc : $(BASE_DIR)/email : $(QUX_DIR) : $(PROGS_DIR) : $(NACL_DIR) : $(D3D_DIR) : $(VK_DIR) : $(BOTLIB_DIR) : $(BASE_DIR)/libs/speex/libspeex : $(BASE_DIR)/web
VPATH = $(BASE_DIR) : $(CLIENT_DIR) : $(GL_DIR) : $(SW_DIR) : $(COMMON_DIR) : $(SERVER_DIR) : $(HTTP_DIR) : $(BASE_DIR)/irc : $(BASE_DIR)/email : $(QUX_DIR) : $(PROGS_DIR) : $(NACL_DIR) : $(D3D_DIR) : $(VK_DIR) : $(BOTLIB_DIR) : $(BASE_DIR)/libs/speex/libspeex : $(BASE_DIR)/web
ifneq ($(findstring -DSPEEX_STATIC, $(CFLAGS)),)
#add these to statically link libspeex

View file

@ -328,12 +328,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ARCH_STRING "x86"
#define Q3_BIG_ENDIAN
#define Q3_LITTLE_ENDIAN
#define DLL_EXT ".dll"
#endif
#ifdef __DJGPP__
#define OS_STRING "msdos"
#define ID_INLINE static inline
#define PATH_SEP '/'
#define ARCH_STRING "dos"
#define Q3_LITTLE_ENDIAN
#define DLL_EXT ".dll"
#endif
#ifdef FTE_TARGET_WEB
#define OS_STRING "emscripten"
#define ID_INLINE static inline

View file

@ -91,7 +91,13 @@ cvar_t snd_noextraupdate = CVARAF( "s_noextraupdate", "0",
"snd_noextraupdate", 0);
cvar_t snd_show = CVARAF( "s_show", "0",
"snd_show", 0);
cvar_t snd_khz = CVARAFD( "s_khz", "48",
#ifdef __DJGPP__
#define DEFAULT_SND_KHZ "11"
#else
//fixme: are android devices more likely to use 44.1khz?
#define DEFAULT_SND_KHZ "48" //most modern systems should go with 48khz audio (dvd quality). various hardware codecs support nothing else.
#endif
cvar_t snd_khz = CVARAFD( "s_khz", DEFAULT_SND_KHZ,
"snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "1",
"snd_inactive", CVAR_ARCHIVE,
@ -1507,11 +1513,16 @@ extern sounddriver_t XAUDIO2_Output;
extern sounddriver_t DSOUND_Output;
#endif
sounddriver_t SDL_Output;
#ifdef __linux__
sounddriver_t ALSA_Output;
#endif
sounddriver_t OSS_Output;
#ifdef AVAIL_OPENAL
extern sounddriver_t OPENAL_Output;
#endif
#ifdef __DJGPP__
extern sounddriver_t SBLASTER_Output;
#endif
sounddriver pSNDIO_InitCard;
sounddriver pOSS_InitCard;
@ -1546,6 +1557,9 @@ static sounddriver_t *outputdrivers[] =
&ALSA_Output, //pure shite
#endif
&OSS_Output, //good, but not likely to work any more
#ifdef __DJGPP__
&SBLASTER_Output, //zomgwtfdos?
#endif
NULL
};
typedef struct {

View file

@ -0,0 +1,590 @@
/*
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.
*/
//I had one at least, back in the day.
//should be fine for dosbox, if nothing else.
//warning: this sound code doesn't seem to cope well with low framerates. the dma buffer is too small.
//4096 bytes 16bit stereo means 1024 samples. so less than 10 fps and the mixer will miss buffer wraps.
#include <quakedef.h>
#include <dos.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/nearptr.h>
#define SDRVNAME "SoundBlaster"
/*
===============================================================================
BLASTER SUPPORT
===============================================================================
*/
_go32_dpmi_seginfo dma_buffer_memory;
static short *dma_buffer=0; //realigned pointer
quintptr_t dma_buffer_phys; //realigned physical address - must be within the first 16mb
static int dma_size;
static int dma;
static int dsp_port;
static int irq;
static int low_dma;
static int high_dma;
static int mixer_port;
static int mpu401_port;
static int dsp_version;
static int dsp_minor_version;
static int timeconstant=-1;
static int oldmixervalue;
static int mode_reg;
static int flipflop_reg;
static int disable_reg;
static int clear_reg;
static soundcardinfo_t *becauseglobalssuck; //just protects against multiple devices being spawned at once.
static void PrintBits (qbyte b)
{
int i;
char str[9];
for (i=0 ; i<8 ; i++)
str[i] = '0' + ((b & (1<<(7-i))) > 0);
str[8] = 0;
Con_Printf ("%s (%i)", str, b);
}
// =======================================================================
// Interprets BLASTER variable
// =======================================================================
static int GetBLASTER(void)
{
char *BLASTER;
char *param;
BLASTER = getenv("BLASTER");
if (!BLASTER)
return 0;
param = strchr(BLASTER, 'A');
if (!param)
param = strchr(BLASTER, 'a');
if (!param)
return 0;
sscanf(param+1, "%x", &dsp_port);
param = strchr(BLASTER, 'I');
if (!param)
param = strchr(BLASTER, 'i');
if (!param)
return 0;
sscanf(param+1, "%d", &irq);
param = strchr(BLASTER, 'D');
if (!param)
param = strchr(BLASTER, 'd');
if (!param)
return 0;
sscanf(param+1, "%d", &low_dma);
param = strchr(BLASTER, 'H');
if (!param)
param = strchr(BLASTER, 'h');
if (param)
sscanf(param+1, "%d", &high_dma);
param = strchr(BLASTER, 'M');
if (!param)
param = strchr(BLASTER, 'm');
if (param)
sscanf(param+1, "%x", &mixer_port);
else
mixer_port = dsp_port;
param = strchr(BLASTER, 'P');
if (!param)
param = strchr(BLASTER, 'p');
if (param)
sscanf(param+1, "%x", &mpu401_port);
return 1;
}
// ==================================================================
// Resets DSP. Returns 0 on success.
// ==================================================================
static int ResetDSP(void)
{
volatile int i;
outportb(dsp_port + 6, 1);
for (i=65536 ; i ; i--) ;
outportb(dsp_port + 6, 0);
for (i=65536 ; i ; i--)
{
if (!(inportb(dsp_port + 0xe) & 0x80)) continue;
if (inportb(dsp_port + 0xa) == 0xaa) break;
}
if (i) return 0;
else return 1;
}
static int ReadDSP(void)
{
while (!(inportb(dsp_port+0xe)&0x80)) ;
return inportb(dsp_port+0xa);
}
static void WriteDSP(int val)
{
while ((inportb(dsp_port+0xc)&0x80)) ;
outportb(dsp_port+0xc, val);
}
static int ReadMixer(int addr)
{
outportb(mixer_port+4, addr);
return inportb(mixer_port+5);
}
static void WriteMixer(int addr, int val)
{
outportb(mixer_port+4, addr);
outportb(mixer_port+5, val);
}
/*
================
StartSB
================
*/
static void StartSB(soundcardinfo_t *sc)
{
int i;
// version 4.xx startup code
if (dsp_version >= 4)
{
Con_Printf("Version 4 SB startup\n");
WriteDSP(0xd1); // turn on speaker
WriteDSP(0x41);
WriteDSP(sc->sn.speed>>8);
WriteDSP(sc->sn.speed&0xff);
WriteDSP(0xb6); // 16-bit output
WriteDSP(0x30); // stereo
WriteDSP((sc->sn.samples-1) & 0xff); // # of samples - 1
WriteDSP((sc->sn.samples-1) >> 8);
}
// version 3.xx startup code
else if (dsp_version == 3)
{
Con_Printf("Version 3 SB startup\n");
WriteDSP(0xd1); // turn on speaker
oldmixervalue = ReadMixer (0xe);
WriteMixer (0xe, oldmixervalue | 0x2);// turn on stereo
WriteDSP(0x14); // send one byte
WriteDSP(0x0);
WriteDSP(0x0);
for (i=0 ; i<0x10000 ; i++)
inportb(dsp_port+0xe); // ack the dsp
timeconstant = 65536-(256000000/(sc->sn.numchannels*sc->sn.speed));
WriteDSP(0x40);
WriteDSP(timeconstant>>8);
WriteMixer (0xe, ReadMixer(0xe) | 0x20);// turn off filter
WriteDSP(0x48);
WriteDSP((sc->sn.samples-1) & 0xff); // # of samples - 1
WriteDSP((sc->sn.samples-1) >> 8);
WriteDSP(0x90); // high speed 8 bit stereo
}
// normal speed mono
else
{
Con_Printf("Version 2 SB startup\n");
WriteDSP(0xd1); // turn on speaker
timeconstant = 65536-(256000000/(sc->sn.numchannels*sc->sn.speed));
WriteDSP(0x40);
WriteDSP(timeconstant>>8);
WriteDSP(0x48);
WriteDSP((sc->sn.samples-1) & 0xff); // # of samples - 1
WriteDSP((sc->sn.samples-1) >> 8);
WriteDSP(0x1c); // normal speed 8 bit mono
}
}
static const int page_reg[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
static const int addr_reg[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
static const int count_reg[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
/*
================
StartDMA
================
*/
static void StartDMA(void)
{
int mode;
// use a high dma channel if specified
if (high_dma && dsp_version >= 4) // 8 bit snd can never use 16 bit dma
dma = high_dma;
else
dma = low_dma;
Con_Printf ("Using DMA channel %i\n", dma);
if (dma > 3)
{
mode_reg = 0xd6;
flipflop_reg = 0xd8;
disable_reg = 0xd4;
clear_reg = 0xdc;
}
else
{
mode_reg = 0xb;
flipflop_reg = 0xc;
disable_reg = 0xa;
clear_reg = 0xe;
}
outportb(disable_reg, dma|4); // disable channel
// set mode- see "undocumented pc", p.876
mode = (1<<6) // single-cycle
+(0<<5) // address increment
+(1<<4) // auto-init dma
+(2<<2) // read
+(dma&3); // channel #
outportb(mode_reg, mode);
// set address
// set page
outportb(page_reg[dma], dma_buffer_phys >> 16);
if (dma > 3)
{ // address is in words
outportb(flipflop_reg, 0); // prepare to send 16-bit value
outportb(addr_reg[dma], (dma_buffer_phys>>1) & 0xff);
outportb(addr_reg[dma], (dma_buffer_phys>>9) & 0xff);
outportb(flipflop_reg, 0); // prepare to send 16-bit value
outportb(count_reg[dma], ((dma_size>>1)-1) & 0xff);
outportb(count_reg[dma], ((dma_size>>1)-1) >> 8);
}
else
{ // address is in bytes
outportb(flipflop_reg, 0); // prepare to send 16-bit value
outportb(addr_reg[dma], dma_buffer_phys & 0xff);
outportb(addr_reg[dma], (dma_buffer_phys>>8) & 0xff);
outportb(flipflop_reg, 0); // prepare to send 16-bit value
outportb(count_reg[dma], (dma_size-1) & 0xff);
outportb(count_reg[dma], (dma_size-1) >> 8);
}
outportb(clear_reg, 0); // clear write mask
outportb(disable_reg, dma&~4);
}
/*
==============
BLASTER_GetDMAPos
return the current sample position (in mono samples read)
inside the recirculating dma buffer, so the mixing code will know
how many sample are required to fill it up.
===============
*/
static unsigned int SBLASTER_GetDMAPos(soundcardinfo_t *sc)
{
int count;
// this function is called often. acknowledge the transfer completions
// all the time so that it loops
if (dsp_version >= 4)
inportb(dsp_port+0xf); // 16 bit audio
else
inportb(dsp_port+0xe); // 8 bit audio
// clear 16-bit reg flip-flop
// load the current dma count register
if (dma < 4)
{
outportb(0xc, 0);
count = inportb(dma*2+1);
count += inportb(dma*2+1) << 8;
if (sc->sn.samplebits == 16)
count /= 2;
count = sc->sn.samples - (count+1);
}
else
{
outportb(0xd8, 0);
count = inportb(0xc0+(dma-4)*4+2);
count += inportb(0xc0+(dma-4)*4+2) << 8;
if (sc->sn.samplebits == 8)
count *= 2;
count = sc->sn.samples - (count+1);
}
// Con_Printf("DMA pos = 0x%x\n", count);
// sc->sn.samplepos = count & (sc->sn.samples-1);
return count;
}
/*
==============
BLASTER_Shutdown
Reset the sound device for exiting
===============
*/
static void SBLASTER_Shutdown(soundcardinfo_t *sc)
{
if (becauseglobalssuck == sc)
becauseglobalssuck = NULL;
if (dsp_version >= 4)
{
}
else if (dsp_version == 3)
{
ResetDSP (); // stop high speed mode
WriteMixer (0xe, oldmixervalue); // turn stereo off and filter on
}
else
{
}
WriteDSP(0xd3); // turn off speaker
ResetDSP ();
outportb(disable_reg, dma|4); // disable dma channel
_go32_dpmi_free_dos_memory(&dma_buffer_memory);
}
//simple ring buffer
static void *SBLASTER_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx)
{
return sc->sn.buffer;
}
//that's permanently locked
static void SBLASTER_UnlockBuffer(soundcardinfo_t *sc, void *buffer)
{
}
//that the hardware has direct access to.
static void SBLASTER_Submit (soundcardinfo_t *sc, int start, int end)
{
}
//returns the address of some memory.
//ctx is required to free the memory afterwards
static qboolean dosmem_alloc(_go32_dpmi_seginfo *ctx, size_t size)
{
ctx->size = (size+15)>>4;
if (_go32_dpmi_allocate_dos_memory(ctx))
return false; //failed
return true;
}
static quintptr_t dosmem_phys(_go32_dpmi_seginfo *ctx)
{
return ctx->rm_segment<<4;
}
static void *dosmem_ptr(_go32_dpmi_seginfo *ctx)
{
__djgpp_nearptr_enable();
return (void*)(__djgpp_conventional_base+dosmem_phys(ctx));
}
/*
==================
BLASTER_Init
Returns false if nothing is found.
==================
*/
static qboolean SBLASTER_InitCard(soundcardinfo_t *sc, const char *pcmname)
{
int size;
int p;
if (becauseglobalssuck)
return 0;
//
// must have a blaster variable set
//
if (!GetBLASTER())
{
Con_NotifyBox (
"The BLASTER environment variable\n"
"is not set, sound effects are\n"
"disabled. See README.TXT for help.\n"
);
return 0;
}
if (ResetDSP())
{
Con_Printf("Could not reset SB");
return 0;
}
//
// get dsp version
//
WriteDSP(0xe1);
dsp_version = ReadDSP();
dsp_minor_version = ReadDSP();
// we need at least v2 for auto-init dma
if (dsp_version < 2)
{
Con_Printf ("Sound blaster must be at least v2.0\n");
return 0;
}
// allow command line parm to set quality down
p = COM_CheckParm ("-dsp");
if (p && p < com_argc - 1)
{
p = Q_atoi (com_argv[p+1]);
if (p < 2 || p > 4)
Con_Printf ("-dsp parameter can only be 2, 3, or 4\n");
else if (p > dsp_version)
Con_Printf ("Can't -dsp %i on v%i hardware\n", p, dsp_version);
else
dsp_version = p;
}
// everyone does 11khz sampling rate unless told otherwise
// sc->sn.speed = 11025;
// rc = COM_CheckParm("-sspeed");
// if (rc)
// sc->sn.speed = Q_atoi(com_argv[rc+1]);
// version 4 cards (sb 16) do 16 bit stereo
if (dsp_version >= 4)
{
if (sc->sn.numchannels != 1)
sc->sn.numchannels = 2;
if (sc->sn.samplebits != 8)
sc->sn.samplebits = 16;
}
// version 3 cards (sb pro) do 8 bit stereo
else if (dsp_version == 3)
{
if (sc->sn.numchannels != 1)
sc->sn.numchannels = 2;
sc->sn.samplebits = 8;
}
// v2 cards do 8 bit mono
else
{
sc->sn.numchannels = 1;
sc->sn.samplebits = 8;
}
sc->Lock = SBLASTER_LockBuffer;
sc->Unlock = SBLASTER_UnlockBuffer;
sc->Shutdown = SBLASTER_Shutdown;
sc->GetDMAPos = SBLASTER_GetDMAPos;
sc->Submit = SBLASTER_Submit;
size = 4096;
// allocate 8k and get a 4k-aligned buffer from it
if (!dosmem_alloc(&dma_buffer_memory, size*2))
{
Con_Printf("Couldn't allocate sound dma buffer");
return false;
}
dma_buffer_phys = ((dosmem_phys(&dma_buffer_memory) + size) & ~(size-1));
dma_buffer = (short *)((qbyte*)dosmem_ptr(&dma_buffer_memory) + dma_buffer_phys-dosmem_phys(&dma_buffer_memory));
dma_size = size;
memset(dma_buffer, 0, dma_size);
sc->sn.samples = size/(sc->sn.samplebits/8);
sc->sn.samplepos = 0;
sc->sn.buffer = (unsigned char *) dma_buffer;
sc->sn.samples = size/(sc->sn.samplebits/8);
StartDMA();
StartSB(sc);
becauseglobalssuck = sc;
return true;
}
static qboolean QDECL SBLASTER_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename))
{
return false;
}
sounddriver_t SBLASTER_Output =
{
SDRVNAME,
SBLASTER_InitCard,
SBLASTER_Enumerate
};

185
engine/client/sys_dos.c Normal file
View file

@ -0,0 +1,185 @@
#include <quakedef.h>
//because cake.
#include "sys_linux.c"
#include <dos.h>
#include <dpmi.h>
_go32_dpmi_registers regs;
int dos_int86(int vec)
{
int rc;
regs.x.ss = regs.x.sp = 0;
rc = _go32_dpmi_simulate_int(vec, &regs);
return rc || (regs.x.flags & 1);
}
static int mouse_buttons;
static int mouse_numbuttons;
static unsigned int dosmousedeviceid;
static unsigned int doskeyboarddeviceid;
#define KBRINGSIZE 256
static struct
{
unsigned char buf[KBRINGSIZE];
int write;
int read;
} kbring;
void TheKBHandler(void)
{ //this needs to be kept simple and small.
//we write to a really simple ringbuffer to avoid needing to lock various code/data pages.
kbring.buf[kbring.write++&(KBRINGSIZE-1)] = inportb(0x60);
outportb(0x20, 0x20);
}
unsigned char keymap[256] =
{
//this is a copy of the US keymap from vanilla quake.
//its so very tempting to switch it to a UK keymap...
// 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,K_TAB, // 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_LSHIFT,'\\', 'z', 'x', 'c', 'v', // 2
'b', 'n', 'm', ',', '.', '/', K_RSHIFT, '*',
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
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
0 , 27, '!', '@', '#', '$', '%', '^',
'&', '*', '(', ')', '_', '+', K_BACKSPACE,K_TAB, // 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_LSHIFT,'|', 'Z', 'X', 'C', 'V', // 2
'B', 'N', 'M', '<', '>', '?', K_RSHIFT, '*',
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 INS_Init(void)
{
//make sure the kb handler and its data won't get paged out.
_go32_dpmi_lock_code((void *) TheKBHandler, 512);
_go32_dpmi_lock_data((void *) &kbring, sizeof(kbring));
//set up our interrupt handler.
_go32_dpmi_seginfo info;
info.pm_offset = (int) TheKBHandler;
_go32_dpmi_allocate_iret_wrapper(&info);
_go32_dpmi_set_protected_mode_interrupt_vector(9, &info);
}
void Sys_SendKeyEvents(void)
{ //this is kinda silly, but the handler can't do it if we want to be correct with respect to virtual memory.
static int shift_down;
while (kbring.read != kbring.write)
{ //keyboard maps are complicated, annoyingly so. left/right/extended.... and don't get me started on sysreq. some keys don't even have release events!
unsigned char c = kbring.buf[kbring.read++&(KBRINGSIZE-1)];
unsigned int qkey, ukey;
qkey = keymap[c&0x7f];
ukey = (qkey >= 32 && qkey < 127)?keymap[(c&0x7f)|(shift_down?128:0)]:0;
if (c == 0xe0)
{ //extended keys...
if (kbring.buf[kbring.read&(KBRINGSIZE-1)] == 0x1d)
qkey = K_RSHIFT;
else
continue; //annoying extended keys.
ukey = 0;
kbring.read++;
}
if (qkey == K_LSHIFT)
shift_down = (shift_down&~1) | ((c&0x80)?0:1);
if (qkey == K_RSHIFT)
shift_down = (shift_down&~2) | ((c&0x80)?0:2);
// Con_Printf("Keyboard: %x\n", c);
IN_KeyEvent(doskeyboarddeviceid, !(c&0x80), qkey, ukey);
}
}
void INS_Move(float *movements, int pnum)
{
}
void INS_Commands(void)
{
if (!mouse_numbuttons)
return;
regs.x.ax = 11; // read move
dos_int86(0x33);
if (regs.x.cx || regs.x.dx)
{
IN_MouseMove(dosmousedeviceid, false, (short)regs.x.cx, (short)regs.x.dx, 0, 0);
Con_Printf("Mouse Move: %i %i\n", (short)regs.x.cx, (short)regs.x.dx);
}
regs.x.ax = 3; // read buttons
dos_int86(0x33);
int b = mouse_buttons ^ regs.x.bx;
mouse_buttons = regs.x.bx;
for (int i = 0; i < mouse_numbuttons; i++)
{
if (b&(1u<<i))
IN_KeyEvent(dosmousedeviceid, !!(mouse_buttons&(1u<<i)), K_MOUSE1+i, 0);
}
Sys_SendKeyEvents();
}
void INS_ReInit(void)
{
dosmousedeviceid = 0;
mouse_buttons = 0;
mouse_numbuttons = 0;
regs.x.ax = 0;
dos_int86(0x33);
if (!regs.x.ax)
{
Con_Printf ("No mouse found\n");
return;
}
mouse_numbuttons = regs.x.bx;
if (mouse_numbuttons >= 255)
mouse_numbuttons = 2;
if (mouse_numbuttons > 10)
mouse_numbuttons = 10;
Con_Printf("%d-button mouse available\n", mouse_numbuttons);
}
void INS_Shutdown(void)
{
}
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid))
{
callback(ctx, "mouse", "dosmouse", &dosmousedeviceid);
callback(ctx, "keyboard", "doskeyboard", &doskeyboarddeviceid);
}
void Sys_Sleep (double seconds)
{
usleep(seconds * 1000000);
}

View file

@ -36,7 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <dlfcn.h>
#include <dirent.h>
#ifndef __CYGWIN__
#if !defined(__CYGWIN__) && !defined(__DJGPP__)
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
@ -46,7 +46,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/wait.h>
#include <sys/mman.h>
#include <errno.h>
#ifndef __MACOSX__
#if !defined(__MACOSX__) && !defined(__DJGPP__)
#include <X11/Xlib.h>
#endif
#ifdef MULTITHREAD
@ -255,8 +255,10 @@ void Sys_Printf (char *fmt, ...)
void Sys_Quit (void)
{
Host_Shutdown();
#ifndef __DJGPP__
if (!noconinput)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
#endif
#ifdef USE_LIBTOOL
lt_dlexit();
@ -400,9 +402,11 @@ void Sys_Error (const char *error, ...)
va_list argptr;
char string[1024];
#ifndef __DJGPP__
// change stdin to non blocking
if (!noconinput)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
#endif
va_start (argptr,error);
vsnprintf (string,sizeof(string)-1, error,argptr);
@ -827,13 +831,6 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
// Sleeps for microseconds
// =======================================================================
static volatile int oktogo;
void alarm_handler(int x)
{
oktogo=1;
}
char *Sys_ConsoleInput(void)
{
#if 1
@ -853,7 +850,9 @@ char *Sys_ConsoleInput(void)
// if (!qrenderer)
{
Con_Printf("ConsoleInput\n");
len = read (0, text, sizeof(text));
Con_Printf("ConsoleInput read %i\n", len);
if (len < 1)
return NULL;
@ -948,13 +947,17 @@ int main (int c, const char **v)
noconinput = COM_CheckParm("-noconinput");
#ifndef __DJGPP__
if (!noconinput)
fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
#endif
#ifdef SUBSERVERS
if (COM_CheckParm("-clusterslave"))
isDedicated = nostdout = isClusterSlave = true;
#endif
if (COM_CheckParm("-dedicated"))
isDedicated = true;
if (COM_CheckParm("-nostdout"))
nostdout = 1;
@ -963,7 +966,6 @@ int main (int c, const char **v)
for (i = 1; i < parms.argc; i++)
{
Con_Printf("Arg%i == %s\n", i, parms.argv[i]);
if (!parms.argv[i])
continue;
if (*parms.argv[i] == '+' || *parms.argv[i] == '-')
@ -1033,7 +1035,7 @@ void Sys_ServerActivity(void)
//from the OS. This will cause problems with framebuffer-only setups.
qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate)
{
#ifdef __MACOSX__
#if defined(__MACOSX__) || defined(__DJGPP__)
//this about sums up the problem with this function
return false;
#else

View file

@ -356,7 +356,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
//software rendering is just too glitchy, don't use it.
#if defined(SWQUAKE) && !defined(_DEBUG)
#if defined(SWQUAKE) && !defined(_DEBUG) && !defined(__DJGPP__)
#undef SWQUAKE
#endif
#if (defined(D3D8QUAKE) || defined(D3D9QUAKE) || defined(D3D11QUAKE)) && !defined(D3DQUAKE)
@ -444,6 +444,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef WEBCLIENT //http/ftp clients.
#endif
#ifdef __DJGPP__
//no bsd sockets library.
#undef HAVE_TCP
#undef HAVE_PACKET
#undef SUPPORT_ICE
//too lazy to deal with no dlopen
#undef PLUGINS
#undef Q2SERVER
#undef Q3SERVER
#undef Q2CLIENT //fixme...
#undef Q3CLIENT //might as well.
//too lazy to write the code to boot up more cores. dosbox would probably hate it so why bother.
#undef MULTITHREAD
//too lazy to deal with various libraries
#undef VOICECHAT
#undef AVAIL_JPEGLIB
#undef AVAIL_PNGLIB
#undef AVAIL_OGGVORBIS
#endif
#ifdef FTE_TARGET_WEB
//sandboxing...
#undef HAVE_TCP //websockets are not real tcp.

View file

@ -71,7 +71,7 @@ void Mod_DoCRC(model_t *mod, char *buffer, int buffersize)
#ifdef _WIN32
#if defined(_WIN32) || defined(__DJGPP__)
#include <malloc.h>
#else
#include <alloca.h>

View file

@ -1717,7 +1717,7 @@ void MSG_ReadPos (vec3_t pos)
pos[2] = MSG_ReadCoord();
}
#if defined(Q2SERVER) || !defined(SERVERONLY)
#if 1//defined(Q2SERVER) || !defined(SERVERONLY)
#define Q2NUMVERTEXNORMALS 162
vec3_t bytedirs[Q2NUMVERTEXNORMALS] =
{
@ -2652,7 +2652,7 @@ unsigned int unicode_charofsfrombyteofs(const char *str, unsigned int byteofs, q
return chars;
}
#ifdef FTE_TARGET_WEB
#if defined(FTE_TARGET_WEB) || defined(__DJGPP__)
//targets that don't support towupper/towlower...
#define towupper Q_towupper
#define towlower Q_towlower

View file

@ -4,7 +4,7 @@
#endif
#include "com_mesh.h"
#ifdef _WIN32
#if defined(_WIN32) || defined(__DJGPP__)
#include <malloc.h>
#else
#include <alloca.h>

View file

@ -17,7 +17,7 @@
#include "glquake.h"
#ifndef SERVERONLY
#ifdef _WIN32
#if defined(_WIN32) || defined(__DJGPP__)
#include <malloc.h>
#else
#include <alloca.h>

View file

@ -6057,7 +6057,7 @@ static qboolean Terr_Brush_DeleteId(heightmap_t *hm, unsigned int brushid)
}
#ifdef _WIN32
#if defined(_WIN32) || defined(__DJGPP__)
#include <malloc.h>
#else
#include <alloca.h>

View file

@ -120,6 +120,8 @@ struct q2gclient_s
// this point in the structure
};
#endif
#if defined(Q2SERVER) || defined(Q2CLIENT)
typedef struct q2entity_state_s
{
int number; // edict index
@ -141,6 +143,8 @@ typedef struct q2entity_state_s
// events only go out for a single frame, they
// are automatically cleared each frame
} q2entity_state_t;
#endif
#if defined(Q2SERVER)
struct q2edict_s

View file

@ -660,6 +660,165 @@ void SWBE_ClearVBO(struct vbo_s *vbo)
void SWBE_UploadAllLightmaps(void)
{
}
static void SWR_RotateForEntity (float *m, float *modelview, const entity_t *e, const model_t *mod)
{
if ((e->flags & RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0)
{
float em[16];
float vm[16];
if (e->flags & RF_WEAPONMODELNOBOB)
{
vm[0] = vpn[0];
vm[1] = vpn[1];
vm[2] = vpn[2];
vm[3] = 0;
vm[4] = -vright[0];
vm[5] = -vright[1];
vm[6] = -vright[2];
vm[7] = 0;
vm[8] = vup[0];
vm[9] = vup[1];
vm[10] = vup[2];
vm[11] = 0;
vm[12] = r_refdef.vieworg[0];
vm[13] = r_refdef.vieworg[1];
vm[14] = r_refdef.vieworg[2];
vm[15] = 1;
}
else
{
vm[0] = r_refdef.playerview->vw_axis[0][0];
vm[1] = r_refdef.playerview->vw_axis[0][1];
vm[2] = r_refdef.playerview->vw_axis[0][2];
vm[3] = 0;
vm[4] = r_refdef.playerview->vw_axis[1][0];
vm[5] = r_refdef.playerview->vw_axis[1][1];
vm[6] = r_refdef.playerview->vw_axis[1][2];
vm[7] = 0;
vm[8] = r_refdef.playerview->vw_axis[2][0];
vm[9] = r_refdef.playerview->vw_axis[2][1];
vm[10] = r_refdef.playerview->vw_axis[2][2];
vm[11] = 0;
vm[12] = r_refdef.playerview->vw_origin[0];
vm[13] = r_refdef.playerview->vw_origin[1];
vm[14] = r_refdef.playerview->vw_origin[2];
vm[15] = 1;
}
em[0] = e->axis[0][0];
em[1] = e->axis[0][1];
em[2] = e->axis[0][2];
em[3] = 0;
em[4] = e->axis[1][0];
em[5] = e->axis[1][1];
em[6] = e->axis[1][2];
em[7] = 0;
em[8] = e->axis[2][0];
em[9] = e->axis[2][1];
em[10] = e->axis[2][2];
em[11] = 0;
em[12] = e->origin[0];
em[13] = e->origin[1];
em[14] = e->origin[2];
em[15] = 1;
Matrix4_Multiply(vm, em, m);
}
else
{
m[0] = e->axis[0][0];
m[1] = e->axis[0][1];
m[2] = e->axis[0][2];
m[3] = 0;
m[4] = e->axis[1][0];
m[5] = e->axis[1][1];
m[6] = e->axis[1][2];
m[7] = 0;
m[8] = e->axis[2][0];
m[9] = e->axis[2][1];
m[10] = e->axis[2][2];
m[11] = 0;
m[12] = e->origin[0];
m[13] = e->origin[1];
m[14] = e->origin[2];
m[15] = 1;
}
if (e->scale != 1 && e->scale != 0) //hexen 2 stuff
{
#ifdef HEXEN2
float z;
float escale;
escale = e->scale;
switch(e->drawflags&SCALE_TYPE_MASK)
{
default:
case SCALE_TYPE_UNIFORM:
VectorScale((m+0), escale, (m+0));
VectorScale((m+4), escale, (m+4));
VectorScale((m+8), escale, (m+8));
break;
case SCALE_TYPE_XYONLY:
VectorScale((m+0), escale, (m+0));
VectorScale((m+4), escale, (m+4));
break;
case SCALE_TYPE_ZONLY:
VectorScale((m+8), escale, (m+8));
break;
}
if (mod && (e->drawflags&SCALE_TYPE_MASK) != SCALE_TYPE_XYONLY)
{
switch(e->drawflags&SCALE_ORIGIN_MASK)
{
case SCALE_ORIGIN_CENTER:
z = ((mod->maxs[2] + mod->mins[2]) * (1-escale))/2;
VectorMA((m+12), z, e->axis[2], (m+12));
break;
case SCALE_ORIGIN_BOTTOM:
VectorMA((m+12), mod->mins[2]*(1-escale), e->axis[2], (m+12));
break;
case SCALE_ORIGIN_TOP:
VectorMA((m+12), -mod->maxs[2], e->axis[2], (m+12));
break;
}
}
#else
VectorScale((m+0), e->scale, (m+0));
VectorScale((m+4), e->scale, (m+4));
VectorScale((m+8), e->scale, (m+8));
#endif
}
else if (mod && !strcmp(mod->name, "progs/eyes.mdl"))
{
/*resize eyes, to make them easier to see*/
m[14] -= (22 + 8);
VectorScale((m+0), 2, (m+0));
VectorScale((m+4), 2, (m+4));
VectorScale((m+8), 2, (m+8));
}
if (mod && !ruleset_allow_larger_models.ival && mod->clampscale != 1 && mod->type == mod_alias)
{ //possibly this should be on a per-frame basis, but that's a real pain to do
Con_DPrintf("Rescaling %s by %f\n", mod->name, mod->clampscale);
VectorScale((m+0), mod->clampscale, (m+0));
VectorScale((m+4), mod->clampscale, (m+4));
VectorScale((m+8), mod->clampscale, (m+8));
}
Matrix4_Multiply(r_refdef.m_view, m, modelview);
}
void SWBE_SelectEntity(struct entity_s *ent)
{
float modelmatrix[16];
@ -670,7 +829,7 @@ void SWBE_SelectEntity(struct entity_s *ent)
return;
shaderstate.curentity = ent;
R_RotateForEntity(modelmatrix, modelviewmatrix, shaderstate.curentity, shaderstate.curentity->model);
SWR_RotateForEntity(modelmatrix, modelviewmatrix, shaderstate.curentity, shaderstate.curentity->model);
Matrix4_Multiply(r_refdef.m_projection, modelviewmatrix, shaderstate.m_mvp);
shaderstate.viewplane[0] = vpn[0];//-modelviewmatrix[0];//0*4+2];
shaderstate.viewplane[1] = vpn[1];//-modelviewmatrix[1];//1*4+2];

365
engine/sw/sw_viddos.c Normal file
View file

@ -0,0 +1,365 @@
#include "quakedef.h"
#ifdef SWQUAKE
#include "sw.h"
/* from http://www.delorie.com/djgpp/doc/ug/graphics/vesa.html */
typedef struct VESA_INFO
{
unsigned char VESASignature[4];
unsigned short VESAVersion __attribute__ ((packed));
unsigned long OEMStringPtr __attribute__ ((packed));
unsigned char Capabilities[4];
unsigned long VideoModePtr __attribute__ ((packed));
unsigned short TotalMemory __attribute__ ((packed));
unsigned short OemSoftwareRev __attribute__ ((packed));
unsigned long OemVendorNamePtr __attribute__ ((packed));
unsigned long OemProductNamePtr __attribute__ ((packed));
unsigned long OemProductRevPtr __attribute__ ((packed));
unsigned char Reserved[222];
unsigned char OemData[256];
} VESA_INFO;
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>
static VESA_INFO vesa_info;
static int get_vesa_info()
{
__dpmi_regs r;
long dosbuf;
int c;
/* use the conventional memory transfer buffer */
dosbuf = __tb & 0xFFFFF;
/* initialize the buffer to zero */
for (c=0; c<sizeof(VESA_INFO); c++)
_farpokeb(_dos_ds, dosbuf+c, 0);
dosmemput("VBE2", 4, dosbuf);
/* call the VESA function */
r.x.ax = 0x4F00;
r.x.di = dosbuf & 0xF;
r.x.es = (dosbuf>>4) & 0xFFFF;
__dpmi_int(0x10, &r);
/* quit if there was an error */
if (r.h.ah)
return -1;
/* copy the resulting data into our structure */
dosmemget(dosbuf, sizeof(VESA_INFO), &vesa_info);
/* check that we got the right magic marker value */
if (strncmp(vesa_info.VESASignature, "VESA", 4) != 0)
return -1;
/* it worked! */
return 0;
}
typedef struct MODE_INFO
{
unsigned short ModeAttributes __attribute__ ((packed));
unsigned char WinAAttributes;
unsigned char WinBAttributes;
unsigned short WinGranularity __attribute__ ((packed));
unsigned short WinSize __attribute__ ((packed));
unsigned short WinASegment __attribute__ ((packed));
unsigned short WinBSegment __attribute__ ((packed));
unsigned long WinFuncPtr __attribute__ ((packed));
unsigned short BytesPerScanLine __attribute__ ((packed));
unsigned short XResolution __attribute__ ((packed));
unsigned short YResolution __attribute__ ((packed));
unsigned char XCharSize;
unsigned char YCharSize;
unsigned char NumberOfPlanes;
unsigned char BitsPerPixel;
unsigned char NumberOfBanks;
unsigned char MemoryModel;
unsigned char BankSize;
unsigned char NumberOfImagePages;
unsigned char Reserved_page;
unsigned char RedMaskSize;
unsigned char RedMaskPos;
unsigned char GreenMaskSize;
unsigned char GreenMaskPos;
unsigned char BlueMaskSize;
unsigned char BlueMaskPos;
unsigned char ReservedMaskSize;
unsigned char ReservedMaskPos;
unsigned char DirectColorModeInfo;
unsigned long PhysBasePtr __attribute__ ((packed));
unsigned long OffScreenMemOffset __attribute__ ((packed));
unsigned short OffScreenMemSize __attribute__ ((packed));
unsigned char Reserved[206];
} MODE_INFO;
static MODE_INFO mode_info;
static int get_mode_info(int mode)
{
__dpmi_regs r;
long dosbuf;
int c;
/* use the conventional memory transfer buffer */
dosbuf = __tb & 0xFFFFF;
/* initialize the buffer to zero */
for (c=0; c<sizeof(MODE_INFO); c++)
_farpokeb(_dos_ds, dosbuf+c, 0);
/* call the VESA function */
r.x.ax = 0x4F01;
r.x.di = dosbuf & 0xF;
r.x.es = (dosbuf>>4) & 0xFFFF;
r.x.cx = mode;
__dpmi_int(0x10, &r);
/* quit if there was an error */
if (r.h.ah)
return -1;
/* copy the resulting data into our structure */
dosmemget(dosbuf, sizeof(MODE_INFO), &mode_info);
/* it worked! */
return 0;
}
static int find_vesa_mode(int w, int h, int bpp)
{
int mode_list[256];
int number_of_modes;
long mode_ptr;
int c;
/* check that the VESA driver exists, and get information about it */
if (get_vesa_info() != 0)
return 0;
/* convert the mode list pointer from seg:offset to a linear address */
mode_ptr = ((vesa_info.VideoModePtr & 0xFFFF0000) >> 12) + (vesa_info.VideoModePtr & 0xFFFF);
number_of_modes = 0;
/* read the list of available modes */
while (_farpeekw(_dos_ds, mode_ptr) != 0xFFFF)
{
mode_list[number_of_modes] = _farpeekw(_dos_ds, mode_ptr);
number_of_modes++;
mode_ptr += 2;
}
/* scan through the list of modes looking for the one that we want */
for (c=0; c<number_of_modes; c++)
{
/* get information about this mode */
if (get_mode_info(mode_list[c]) != 0)
continue;
/* check the flags field to make sure this is a color graphics mode,
* and that it is supported by the current hardware */
if ((mode_info.ModeAttributes & 0x19) != 0x19)
continue;
/* check that this mode is the right size */
if ((mode_info.XResolution != w) || (mode_info.YResolution != h))
continue;
/* check that there is only one color plane */
if (mode_info.NumberOfPlanes != 1)
continue;
/* check that it is a packed-pixel mode (other values are used for
* different memory layouts, eg. 6 for a truecolor resolution) */
if (mode_info.MemoryModel != ((bpp==8)?4:6))
continue;
/* check that this is an 8-bit (256 color) mode */
if (mode_info.BitsPerPixel != bpp)
continue;
/* if it passed all those checks, this must be the mode we want! */
return mode_list[c];
}
/* oh dear, there was no mode matching the one we wanted! */
return 0;
}
static int set_vesa_mode(int w, int h, int bpp)
{
__dpmi_regs r;
int mode_number;
/* find the number for this mode */
mode_number = find_vesa_mode(w, h, bpp);
if (!mode_number)
return -1;
/* call the VESA mode set function */
r.x.ax = 0x4F02;
r.x.bx = mode_number;
__dpmi_int(0x10, &r);
if (r.h.ah)
return -1;
/* it worked! */
return 0;
}
void set_vesa_bank(int bank_number)
{
__dpmi_regs r;
r.x.ax = 0x4F05;
r.x.bx = 0;
r.x.dx = bank_number;
__dpmi_int(0x10, &r);
}
static void copy_to_vesa_screen(char *memory_buffer, int screen_size)
{
//FIXME: use OffScreenMemOffset if possible.
int bank_size = mode_info.WinSize*1024;
int bank_granularity = mode_info.WinGranularity*1024;
int bank_number = 0;
int todo = screen_size;
int copy_size;
while (todo > 0)
{
/* select the appropriate bank */
set_vesa_bank(bank_number);
/* how much can we copy in one go? */
if (todo > bank_size)
copy_size = bank_size;
else
copy_size = todo;
/* copy a bank of data to the screen */
dosmemput(memory_buffer, copy_size, 0xA0000);
/* move on to the next bank of data */
todo -= copy_size;
memory_buffer += copy_size;
bank_number += bank_size/bank_granularity;
}
}
extern int nostdout; //we flag with 0x800 to disable printfs while displaying stuff.
static qboolean videoatexitregistered;
static void videoatexit(void)
{
if (nostdout & 0x800)
{
nostdout &= ~0x800;
__dpmi_regs r;
r.x.ax = 0x0000 | 3;
__dpmi_int(0x10, &r);
}
}
static unsigned int *backbuffer;
static unsigned int *depthbuffer;
static unsigned int framenumber;
//#define NORENDER
qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette)
{
int bpp = info->bpp;
vid.pixelwidth = info->width;
vid.pixelheight = info->height;
if (bpp != 32)
bpp = 32; //sw renderer supports only this
#ifndef NORENDER
nostdout |= 0x800;
if (set_vesa_mode(vid.pixelwidth, vid.pixelheight, bpp) < 0)
return false;
#endif
if (!videoatexitregistered)
{
videoatexitregistered = true;
atexit(videoatexit);
}
backbuffer = BZ_Malloc(vid.pixelwidth * vid.pixelheight * sizeof(*backbuffer));
if (!backbuffer)
return false;
depthbuffer = BZ_Malloc(vid.pixelwidth * vid.pixelheight * sizeof(*depthbuffer));
if (!depthbuffer)
return false;
return true;
}
void SW_VID_DeInit(void)
{
BZ_Free(backbuffer);
backbuffer = NULL;
BZ_Free(depthbuffer);
depthbuffer = NULL;
}
qboolean SW_VID_ApplyGammaRamps (unsigned int rampcount, unsigned short *ramps)
{ //no gamma ramps with VESA.
return false;
}
char *SW_VID_GetRGBInfo(int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
{
void *ret = BZ_Malloc(vid.pixelwidth*vid.pixelheight*4);
if (!ret)
return NULL;
memcpy(ret, backbuffer, vid.pixelwidth*vid.pixelheight*4);
*bytestride = vid.pixelwidth*4;
*truevidwidth = vid.pixelwidth;
*truevidheight = vid.pixelheight;
*fmt = TF_BGRX32;
return ret;
}
void SW_VID_SetWindowCaption(const char *msg)
{
}
void SW_VID_SwapBuffers(void)
{
#ifndef NORENDER
copy_to_vesa_screen((char*)backbuffer, vid.pixelwidth*vid.pixelheight*4);
#endif
framenumber++;
}
void SW_VID_UpdateViewport(wqcom_t *com)
{
com->viewport.cbuf = backbuffer + vid.pixelwidth*(vid.pixelheight-1);
com->viewport.dbuf = depthbuffer;
com->viewport.width = vid.pixelwidth;
com->viewport.height = vid.pixelheight;
com->viewport.stride = -vid.pixelwidth; //this is in pixels. which is stupid.
com->viewport.framenum = framenumber;
}
#endif