mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 04:11:53 +00:00
445e7f476b
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
365 lines
9 KiB
C
365 lines
9 KiB
C
#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
|