📄 vid_ext.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.
*/
//
// vid_ext.c: extended video modes
// in this implementation, VESA-specific DOS video stuff
//
// TODO: make dependencies on vid_vga.c explicit or eliminate them
#include <stdlib.h>
#include <dos.h>
#include "quakedef.h"
#include "d_local.h"
#include "dosisms.h"
#include "vid_dos.h"
#include <dpmi.h>
#define MODE_SUPPORTED_IN_HW 0x0001
#define COLOR_MODE 0x0008
#define GRAPHICS_MODE 0x0010
#define VGA_INCOMPATIBLE 0x0020
#define LINEAR_FRAME_BUFFER 0x0080
#define LINEAR_MODE 0x4000
#define VESA_DONT_WAIT_VSYNC 0 // when page flipping
#define VESA_WAIT_VSYNC 0x80
#define MAX_VESA_MODES 30 // we'll just take the first 30 if there
// are more
typedef struct {
int pages[3]; // either 2 or 3 is valid
int vesamode; // LINEAR_MODE set if linear mode
void *plinearmem; // linear address of start of frame buffer
qboolean vga_incompatible;
} vesa_extra_t;
static vmode_t vesa_modes[MAX_VESA_MODES] =
{{NULL, NULL, " ********* VESA modes ********* "}};
static vesa_extra_t vesa_extra[MAX_VESA_MODES];
static char names[MAX_VESA_MODES][10];
extern regs_t regs;
static int VID_currentpage;
static int VID_displayedpage;
static int *VID_pagelist;
static byte *VID_membase;
static int VID_banked;
typedef struct
{
int modenum;
int mode_attributes;
int winasegment;
int winbsegment;
int bytes_per_scanline; // bytes per logical scanline (+16)
int win; // window number (A=0, B=1)
int win_size; // window size (+6)
int granularity; // how finely i can set the window in vid mem (+4)
int width, height; // displayed width and height (+18, +20)
int bits_per_pixel; // er, better be 8, 15, 16, 24, or 32 (+25)
int bytes_per_pixel; // er, better be 1, 2, or 4
int memory_model; // and better be 4 or 6, packed or direct color (+27)
int num_pages; // number of complete frame buffer pages (+29)
int red_width; // the # of bits in the red component (+31)
int red_pos; // the bit position of the red component (+32)
int green_width; // etc.. (+33)
int green_pos; // (+34)
int blue_width; // (+35)
int blue_pos; // (+36)
int pptr;
int pagesize;
int numpages;
} modeinfo_t;
static modeinfo_t modeinfo;
// all bytes to avoid problems with compiler field packing
typedef struct vbeinfoblock_s {
byte VbeSignature[4];
byte VbeVersion[2];
byte OemStringPtr[4];
byte Capabilities[4];
byte VideoModePtr[4];
byte TotalMemory[2];
byte OemSoftwareRev[2];
byte OemVendorNamePtr[4];
byte OemProductNamePtr[4];
byte OemProductRevPtr[4];
byte Reserved[222];
byte OemData[256];
} vbeinfoblock_t;
static int totalvidmem;
static byte *ppal;
qboolean vsync_exists, de_exists;
qboolean VID_ExtraGetModeInfo(int modenum);
int VID_ExtraInitMode (viddef_t *vid, vmode_t *pcurrentmode);
void VID_ExtraSwapBuffers (viddef_t *vid, vmode_t *pcurrentmode,
vrect_t *rects);
/*
================
VGA_BankedBeginDirectRect
================
*/
void VGA_BankedBeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
int x, int y, byte *pbitmap, int width, int height)
{
if (!lvid->direct)
return;
regs.x.ax = 0x4f05;
regs.x.bx = 0;
regs.x.dx = VID_displayedpage;
dos_int86(0x10);
VGA_BeginDirectRect (lvid, pcurrentmode, x, y, pbitmap, width, height);
regs.x.ax = 0x4f05;
regs.x.bx = 0;
regs.x.dx = VID_currentpage;
dos_int86(0x10);
}
/*
================
VGA_BankedEndDirectRect
================
*/
void VGA_BankedEndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
int x, int y, int width, int height)
{
if (!lvid->direct)
return;
regs.x.ax = 0x4f05;
regs.x.bx = 0;
regs.x.dx = VID_displayedpage;
dos_int86(0x10);
VGA_EndDirectRect (lvid, pcurrentmode, x, y, width, height);
regs.x.ax = 0x4f05;
regs.x.bx = 0;
regs.x.dx = VID_currentpage;
dos_int86(0x10);
}
/*
================
VID_SetVESAPalette
================
*/
void VID_SetVESAPalette (viddef_t *lvid, vmode_t *pcurrentmode,
unsigned char *pal)
{
int i;
byte *pp;
UNUSED(lvid);
UNUSED(pcurrentmode);
pp = ppal;
for (i=0 ; i<256 ; i++)
{
pp[2] = pal[0] >> 2;
pp[1] = pal[1] >> 2;
pp[0] = pal[2] >> 2;
pp += 4;
pal += 3;
}
regs.x.ax = 0x4F09;
regs.x.bx = 0;
regs.x.cx = 256;
regs.x.dx = 0;
regs.x.es = ptr2real(ppal) >> 4;
regs.x.di = ptr2real(ppal) & 0xf;
dos_int86(0x10);
if (regs.x.ax != 0x4f)
Sys_Error ("Unable to load VESA palette\n");
}
/*
================
VID_ExtraFarToLinear
================
*/
void *VID_ExtraFarToLinear (void *ptr)
{
int temp;
temp = (int)ptr;
return real2ptr(((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
}
/*
================
VID_ExtraWaitDisplayEnable
================
*/
void VID_ExtraWaitDisplayEnable ()
{
while ((inportb (0x3DA) & 0x01) == 1)
;
}
/*
================
VID_ExtraVidLookForState
================
*/
qboolean VID_ExtraVidLookForState (unsigned state, unsigned mask)
{
int i;
double starttime, time;
starttime = Sys_FloatTime ();
do
{
for (i=0 ; i<100000 ; i++)
{
if ((inportb (0x3DA) & mask) == state)
return true;
}
time = Sys_FloatTime ();
} while ((time - starttime) < 0.1);
return false;
}
/*
================
VID_ExtraStateFound
================
*/
qboolean VID_ExtraStateFound (unsigned state)
{
int i, workingstate;
workingstate = 0;
for (i=0 ; i<10 ; i++)
{
if (!VID_ExtraVidLookForState(workingstate, state))
{
return false;
}
workingstate ^= state;
}
return true;
}
/*
================
VID_InitExtra
================
*/
void VID_InitExtra (void)
{
int nummodes;
short *pmodenums;
vbeinfoblock_t *pinfoblock;
__dpmi_meminfo phys_mem_info;
pinfoblock = dos_getmemory(sizeof(vbeinfoblock_t));
*(long *)pinfoblock->VbeSignature = 'V' + ('B'<<8) + ('E'<<16) + ('2'<<24);
// see if VESA support is available
regs.x.ax = 0x4f00;
regs.x.es = ptr2real(pinfoblock) >> 4;
regs.x.di = ptr2real(pinfoblock) & 0xf;
dos_int86(0x10);
if (regs.x.ax != 0x4f)
return; // no VESA support
if (pinfoblock->VbeVersion[1] < 0x02)
return; // not VESA 2.0 or greater
Con_Printf ("VESA 2.0 compliant adapter:\n%s\n",
VID_ExtraFarToLinear (*(byte **)&pinfoblock->OemStringPtr[0]));
totalvidmem = *(unsigned short *)&pinfoblock->TotalMemory[0] << 16;
pmodenums = (short *)
VID_ExtraFarToLinear (*(byte **)&pinfoblock->VideoModePtr[0]);
// find 8 bit modes until we either run out of space or run out of modes
nummodes = 0;
while ((*pmodenums != -1) && (nummodes < MAX_VESA_MODES))
{
if (VID_ExtraGetModeInfo (*pmodenums))
{
vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
if (modeinfo.width > 999)
{
if (modeinfo.height > 999)
{
sprintf (&names[nummodes][0], "%4dx%4d", modeinfo.width,
modeinfo.height);
names[nummodes][9] = 0;
}
else
{
sprintf (&names[nummodes][0], "%4dx%3d", modeinfo.width,
modeinfo.height);
names[nummodes][8] = 0;
}
}
else
{
if (modeinfo.height > 999)
{
sprintf (&names[nummodes][0], "%3dx%4d", modeinfo.width,
modeinfo.height);
names[nummodes][8] = 0;
}
else
{
sprintf (&names[nummodes][0], "%3dx%3d", modeinfo.width,
modeinfo.height);
names[nummodes][7] = 0;
}
}
vesa_modes[nummodes].name = &names[nummodes][0];
vesa_modes[nummodes].width = modeinfo.width;
vesa_modes[nummodes].height = modeinfo.height;
vesa_modes[nummodes].aspect =
((float)modeinfo.height / (float)modeinfo.width) *
(320.0 / 240.0);
vesa_modes[nummodes].rowbytes = modeinfo.bytes_per_scanline;
vesa_modes[nummodes].planar = 0;
vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
vesa_modes[nummodes].setmode = VID_ExtraInitMode;
vesa_modes[nummodes].swapbuffers = VID_ExtraSwapBuffers;
vesa_modes[nummodes].setpalette = VID_SetVESAPalette;
if (modeinfo.mode_attributes & LINEAR_FRAME_BUFFER)
{
// add linear bit to mode for linear modes
vesa_extra[nummodes].vesamode = modeinfo.modenum | LINEAR_MODE;
vesa_extra[nummodes].pages[0] = 0;
vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
vesa_modes[nummodes].numpages = modeinfo.numpages;
vesa_modes[nummodes].begindirectrect = VGA_BeginDirectRect;
vesa_modes[nummodes].enddirectrect = VGA_EndDirectRect;
phys_mem_info.address = (int)modeinfo.pptr;
phys_mem_info.size = 0x400000;
if (__dpmi_physical_address_mapping(&phys_mem_info))
goto NextMode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -