mirror of
https://github.com/id-Software/Quake.git
synced 2026-03-20 09:00:31 +01:00
The Quake sources as originally release under the GPL license on December 21, 1999
This commit is contained in:
478
WinQuake/vid_vga.c
Normal file
478
WinQuake/vid_vga.c
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
//
|
||||
// vid_vga.c: VGA-specific DOS video stuff
|
||||
//
|
||||
|
||||
// TODO: proper handling of page-swap failure
|
||||
|
||||
#include <dos.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "d_local.h"
|
||||
#include "dosisms.h"
|
||||
#include "vid_dos.h"
|
||||
#include <dpmi.h>
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
|
||||
byte *VGA_pagebase;
|
||||
vmode_t *VGA_pcurmode;
|
||||
|
||||
static int VGA_planar;
|
||||
static int VGA_numpages;
|
||||
static int VGA_buffersize;
|
||||
|
||||
void *vid_surfcache;
|
||||
int vid_surfcachesize;
|
||||
|
||||
int VGA_highhunkmark;
|
||||
|
||||
#include "vgamodes.h"
|
||||
|
||||
#define NUMVIDMODES (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
|
||||
|
||||
void VGA_UpdatePlanarScreen (void *srcbuffer);
|
||||
|
||||
static byte backingbuf[48*24];
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_BeginDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, byte *pbitmap, int width, int height)
|
||||
{
|
||||
int i, j, k, plane, reps, repshift;
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
if (lvid->aspect > 1.5)
|
||||
{
|
||||
reps = 2;
|
||||
repshift = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reps = 1;
|
||||
repshift = 0;
|
||||
}
|
||||
|
||||
if (pcurrentmode->planar)
|
||||
{
|
||||
for (plane=0 ; plane<4 ; plane++)
|
||||
{
|
||||
// select the correct plane for reading and writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 1 << plane);
|
||||
outportb (GC_INDEX, READ_MAP);
|
||||
outportb (GC_DATA, plane);
|
||||
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (k=0 ; k<reps ; k++)
|
||||
{
|
||||
for (j=0 ; j<(width >> 2) ; j++)
|
||||
{
|
||||
backingbuf[(i + k) * 24 + (j << 2) + plane] =
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes +
|
||||
(x >> 2) + j];
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
|
||||
pbitmap[(i >> repshift) * 24 +
|
||||
(j << 2) + plane];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (j=0 ; j<reps ; j++)
|
||||
{
|
||||
memcpy (&backingbuf[(i + j) * 24],
|
||||
lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
width);
|
||||
memcpy (lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
&pbitmap[(i >> repshift) * width],
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_EndDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, int width, int height)
|
||||
{
|
||||
int i, j, k, plane, reps, repshift;
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
if (lvid->aspect > 1.5)
|
||||
{
|
||||
reps = 2;
|
||||
repshift = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reps = 1;
|
||||
repshift = 0;
|
||||
}
|
||||
|
||||
if (pcurrentmode->planar)
|
||||
{
|
||||
for (plane=0 ; plane<4 ; plane++)
|
||||
{
|
||||
// select the correct plane for writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 1 << plane);
|
||||
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (k=0 ; k<reps ; k++)
|
||||
{
|
||||
for (j=0 ; j<(width >> 2) ; j++)
|
||||
{
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
|
||||
backingbuf[(i + k) * 24 + (j << 2) + plane];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (j=0 ; j<reps ; j++)
|
||||
{
|
||||
memcpy (lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
&backingbuf[(i + j) * 24],
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_Init
|
||||
================
|
||||
*/
|
||||
void VGA_Init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// link together all the VGA modes
|
||||
for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
|
||||
{
|
||||
vgavidmodes[i].pnext = &vgavidmodes[i+1];
|
||||
}
|
||||
|
||||
// add the VGA modes at the start of the mode list
|
||||
vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
|
||||
pvidmodes = &vgavidmodes[0];
|
||||
|
||||
numvidmodes += NUMVIDMODES;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_WaitVsync
|
||||
================
|
||||
*/
|
||||
void VGA_WaitVsync (void)
|
||||
{
|
||||
while ((inportb (0x3DA) & 0x08) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_ClearVideoMem
|
||||
================
|
||||
*/
|
||||
void VGA_ClearVideoMem (int planar)
|
||||
{
|
||||
|
||||
if (planar)
|
||||
{
|
||||
// enable all planes for writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 0x0F);
|
||||
}
|
||||
|
||||
Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_FreeAndAllocVidbuffer
|
||||
================
|
||||
*/
|
||||
qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
|
||||
{
|
||||
int tsize, tbuffersize;
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
// alloc an extra line in case we want to wrap, and allocate the z-buffer
|
||||
tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
|
||||
(lvid->width * lvid->height * sizeof (*d_pzbuffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
// just allocate the z-buffer
|
||||
tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
|
||||
}
|
||||
|
||||
tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
|
||||
|
||||
tbuffersize += tsize;
|
||||
|
||||
// see if there's enough memory, allowing for the normal mode 0x13 pixel,
|
||||
// z, and surface buffers
|
||||
if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
|
||||
0x10000 * 3) < minimum_memory)
|
||||
{
|
||||
Con_Printf ("Not enough memory for video mode\n");
|
||||
VGA_pcurmode = NULL; // so no further accesses to the buffer are
|
||||
// attempted, particularly when clearing
|
||||
return false; // not enough memory for mode
|
||||
}
|
||||
|
||||
VGA_buffersize = tbuffersize;
|
||||
vid_surfcachesize = tsize;
|
||||
|
||||
if (d_pzbuffer)
|
||||
{
|
||||
D_FlushCaches ();
|
||||
Hunk_FreeToHighMark (VGA_highhunkmark);
|
||||
d_pzbuffer = NULL;
|
||||
}
|
||||
|
||||
VGA_highhunkmark = Hunk_HighMark ();
|
||||
|
||||
d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
|
||||
|
||||
vid_surfcache = (byte *)d_pzbuffer
|
||||
+ lvid->width * lvid->height * sizeof (*d_pzbuffer);
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_CheckAdequateMem
|
||||
================
|
||||
*/
|
||||
qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
|
||||
int allocnewbuffer)
|
||||
{
|
||||
int tbuffersize;
|
||||
|
||||
tbuffersize = width * height * sizeof (*d_pzbuffer);
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
// alloc an extra line in case we want to wrap, and allocate the z-buffer
|
||||
tbuffersize += (rowbytes * (height + 1));
|
||||
}
|
||||
|
||||
tbuffersize += D_SurfaceCacheForRes (width, height);
|
||||
|
||||
// see if there's enough memory, allowing for the normal mode 0x13 pixel,
|
||||
// z, and surface buffers
|
||||
if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
|
||||
0x10000 * 3) < minimum_memory)
|
||||
{
|
||||
return false; // not enough memory for mode
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_InitMode
|
||||
================
|
||||
*/
|
||||
int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
|
||||
{
|
||||
vextra_t *pextra;
|
||||
|
||||
pextra = pcurrentmode->pextradata;
|
||||
|
||||
if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
|
||||
return -1; // memory alloc failed
|
||||
|
||||
if (VGA_pcurmode)
|
||||
VGA_ClearVideoMem (VGA_pcurmode->planar);
|
||||
|
||||
// mode 0x13 is the base for all the Mode X-class mode sets
|
||||
regs.h.ah = 0;
|
||||
regs.h.al = 0x13;
|
||||
dos_int86(0x10);
|
||||
|
||||
VGA_pagebase = (void *)real2ptr(0xa0000);
|
||||
lvid->direct = (pixel_t *)VGA_pagebase;
|
||||
|
||||
// set additional registers as needed
|
||||
VideoRegisterSet (pextra->pregset);
|
||||
|
||||
VGA_numpages = 1;
|
||||
lvid->numpages = VGA_numpages;
|
||||
|
||||
VGA_width = (lvid->width + 0x1F) & ~0x1F;
|
||||
VGA_height = lvid->height;
|
||||
VGA_planar = pcurrentmode->planar;
|
||||
if (VGA_planar)
|
||||
VGA_rowbytes = lvid->rowbytes / 4;
|
||||
else
|
||||
VGA_rowbytes = lvid->rowbytes;
|
||||
VGA_bufferrowbytes = lvid->rowbytes;
|
||||
lvid->colormap = host_colormap;
|
||||
lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
|
||||
|
||||
lvid->maxwarpwidth = WARP_WIDTH;
|
||||
lvid->maxwarpheight = WARP_HEIGHT;
|
||||
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
lvid->conrowbytes = lvid->rowbytes;
|
||||
lvid->conwidth = lvid->width;
|
||||
lvid->conheight = lvid->height;
|
||||
|
||||
VGA_pcurmode = pcurrentmode;
|
||||
|
||||
VGA_ClearVideoMem (pcurrentmode->planar);
|
||||
|
||||
if (_vid_wait_override.value)
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
|
||||
}
|
||||
|
||||
D_InitCaches (vid_surfcache, vid_surfcachesize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SetPalette
|
||||
================
|
||||
*/
|
||||
void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
|
||||
{
|
||||
int shiftcomponents=2;
|
||||
int i;
|
||||
|
||||
UNUSED(lvid);
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
dos_outportb(0x3c8, 0);
|
||||
for (i=0 ; i<768 ; i++)
|
||||
outportb(0x3c9, pal[i]>>shiftcomponents);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SwapBuffersCopy
|
||||
================
|
||||
*/
|
||||
void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
|
||||
vrect_t *rects)
|
||||
{
|
||||
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
// TODO: can write a dword at a time
|
||||
// TODO: put in ASM
|
||||
// TODO: copy only specified rectangles
|
||||
if (VGA_planar)
|
||||
{
|
||||
|
||||
// TODO: copy only specified rectangles
|
||||
|
||||
VGA_UpdatePlanarScreen (lvid->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (rects)
|
||||
{
|
||||
VGA_UpdateLinearScreen (
|
||||
lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
|
||||
VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
|
||||
rects->width,
|
||||
rects->height,
|
||||
lvid->rowbytes,
|
||||
VGA_rowbytes);
|
||||
|
||||
rects = rects->pnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SwapBuffers
|
||||
================
|
||||
*/
|
||||
void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
|
||||
{
|
||||
UNUSED(lvid);
|
||||
|
||||
if (vid_wait.value == VID_WAIT_VSYNC)
|
||||
VGA_WaitVsync ();
|
||||
|
||||
VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user