⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vid_ext.c

📁 quake1 dos源代码最新版本
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
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 + -