
typedef	signed		long	int	SLONG;		//32 bit signed.
typedef	unsigned	long	int	ULONG;		//32 bit unsigned.
typedef	signed		short	int	SWORD;		//16 bit signed.
typedef	unsigned	short	int	UWORD;		//16 bit unsigned.
typedef	signed		char		SBYTE;		//8 bit signed.
typedef	unsigned 	char		UBYTE;		//8 bit unsigned.
typedef ULONG                           BOOL;           //Yeah, should be a byte.
typedef UBYTE                           BBOOL;          //Most people define a bool as a long.  Bytes use less space and should be just as efficient.
#define TRUE                1
#define FALSE               0
typedef struct RealPointer
{
	UWORD			Segment;	//The real mode segment (offset is 0).
	UWORD			Selector;	//In protected mode, you need to chuck this dude into a segment register and use an offset 0.
} RealPointer;

typedef struct VesaInfo
{
	char		Signature[4];
	UWORD		Version;
	UWORD		OEMNameOffset;
	UWORD		OEMNameSegment;			//Pointer to OEM name?
	UBYTE		Capabilities[4];
	UWORD		SupportedModesOffset;
	UWORD		SupportedModesSegment;		//Pointer to list of supported VESA and OEM modes (terminated with 0xffff).
	UBYTE		Reserved[238];
} VesaInfo;

typedef struct VesaModeData
{
	UWORD		ModeAttributes;
	UBYTE		WindowAAttributes;
	UBYTE		WindowBAttributes;
	UWORD		WindowGranularity;
	UWORD		WindowSize;
	UWORD		StartSegmentWindowA;
	UWORD		StartSegmentWindowB;
	void		(*WindowPositioningFunction)(SLONG page);
	UWORD		BytesPerScanLine;

	//Remainder of this structure is optional for VESA modes in v1.0/1.1, needed for OEM modes.

	UWORD		PixelWidth;
	UWORD		PixelHeight;
	UBYTE		CharacterCellPixelWidth;
	UBYTE		CharacterCellPixelHeight;
	UBYTE		NumberOfMemoryPlanes;
	UBYTE		BitsPerPixel;
	UBYTE		NumberOfBanks;
	UBYTE		MemoryModelType;
	UBYTE		SizeOfBank;
	UBYTE		NumberOfImagePages;
	UBYTE		Reserved1;

	//VBE v1.2+

	UBYTE		RedMaskSize;
	UBYTE		RedFieldPosition;
	UBYTE		GreenMaskSize;
	UBYTE		GreenFieldPosition;
	UBYTE		BlueMaskSize;
	UBYTE		BlueFieldPosition;
	UBYTE		ReservedMaskSize;
	UBYTE		ReservedFieldPosition;
	UBYTE		DirectColourModeInfo;

    //VBE v2.0+

    ULONG       PhysicalAddress;
    UBYTE       Reserved2[212];
} VesaModeData;

typedef struct RMREGS
{
	ULONG		edi;
	ULONG		esi;
	ULONG		ebp;
	ULONG		reserved;
	ULONG		ebx;
	ULONG		edx;
	ULONG		ecx;
	ULONG		eax;
	UWORD		flags;
	UWORD		es,ds,fs,gs,ip,cs,sp,ss;
} RMREGS;

BBOOL	vesa_get_info(void);
void	vesa_free_info(void);
BBOOL	vesa_set_mode(UWORD vmode);
BBOOL	vesa_get_mode_info(UWORD vmode);
void	vesa_free_mode_info(void);
void	vesa_set_page(SLONG vpage);
void	vesa_screen_swap(UBYTE * source,SLONG swidth,SLONG sheight,SLONG bpp);

extern	SLONG			vesa_granularity;
extern	SLONG			vesa_page;
extern	SLONG			vesa_width;
extern	SLONG			vesa_height;
extern	SLONG			vesa_bits_per_pixel;


static void far * allocate_dos_memory(RealPointer * rp,ULONG bytes_to_allocate);
static void free_dos_memory(RealPointer * rp);
RealPointer				vesa_info_rp;
RealPointer				vesa_mode_data_rp;
VesaInfo                                far *vesa_info = NULL;
VesaModeData                            far *vesa_mode_data = NULL;
SLONG					vesa_granularity;
SLONG					vesa_page;
SLONG					vesa_width;
SLONG					vesa_height;
SLONG					vesa_bits_per_pixel;
SLONG                                   vesa_addy;

BBOOL vesa_get_info(void)
{
	union		REGS	regs;
	struct		SREGS	sregs;
	RMREGS				rmregs;
	BBOOL				ok			= FALSE;

	if((vesa_info = (VesaInfo far *)allocate_dos_memory(&vesa_info_rp,sizeof(VesaInfo))) != NULL)
	{
		memset(&rmregs,0,sizeof(rmregs));
		memset(&regs,0,sizeof(regs));
		memset(&sregs,0,sizeof(sregs));
		segread(&sregs);
		rmregs.eax = 0x4f00;
		rmregs.es = vesa_info_rp.Segment;
		rmregs.ds = vesa_info_rp.Segment;
		regs.x.eax = 0x300;
		regs.x.ebx = 0x10;
		regs.x.ecx = 0;
		sregs.es = FP_SEG(&rmregs);
		regs.x.edi = FP_OFF(&rmregs);
		int386x(0x31,&regs,&regs,&sregs);	//Get vesa info.
		if(rmregs.eax == 0x4f)
		{
			ok = TRUE;
		}
	}
	return(ok);
}

void vesa_free_info(void)
{
	free_dos_memory(&vesa_info_rp);
}

BBOOL vesa_get_mode_info(UWORD vmode)
{
	union	REGS	regs;
	struct	SREGS	sregs;
	RMREGS			rmregs;
	BBOOL			ok		= FALSE;

	if((vesa_mode_data = (VesaModeData far *)allocate_dos_memory(&vesa_mode_data_rp,sizeof(VesaModeData))) != NULL)
	{
		memset(&rmregs,0,sizeof(rmregs));
		rmregs.es = vesa_mode_data_rp.Segment;
		rmregs.ds = vesa_mode_data_rp.Segment;
		rmregs.edi = 0;
		rmregs.eax = 0x4f01;
		rmregs.ecx = vmode;
		memset(&regs,0,sizeof(regs));
		memset(&sregs,0,sizeof(sregs));
		segread(&sregs);
		regs.x.eax = 0x300;
		regs.x.ebx = 0x10;
		regs.x.edi = (ULONG)&rmregs;
                vesa_mode_data->PhysicalAddress = 0;
		int386x(0x31,&regs,&regs,&sregs);
		if(regs.h.al == 0)
		{

			//cache a few important items in protected mode memory area.

			vesa_granularity	= vesa_mode_data->WindowGranularity;
			vesa_width			= vesa_mode_data->PixelWidth;
			vesa_height			= vesa_mode_data->PixelHeight;
			vesa_bits_per_pixel	= vesa_mode_data->BitsPerPixel;
                        vesa_addy = vesa_mode_data->PhysicalAddress;
			ok = TRUE;
		}
	}
	return(ok);
}

void vesa_free_mode_info(void)
{
	free_dos_memory(&vesa_mode_data_rp);
}

static void far * allocate_dos_memory(RealPointer * rp,ULONG bytes_to_allocate)
{
	void	far	*		ptr		= NULL;
	union	REGS		regs;

	bytes_to_allocate = ((bytes_to_allocate + 15) & 0xfffffff0);	//Round up to nearest paragraph.
	memset(&regs,0,sizeof(regs));
	regs.w.ax = 0x100;
	regs.w.bx = (UWORD)(bytes_to_allocate >> 4);		//Allocate dos memory in pages, so convert bytes to pages.
	int386(0x31,&regs,&regs);
	if(regs.x.cflag == 0)
	{	//Everything OK.
		rp->Segment = regs.w.ax;
		rp->Selector = regs.w.dx;
		ptr = MK_FP(regs.w.dx,0);
	}
	return(ptr);
}

static void free_dos_memory(RealPointer * rp)
{
	union	REGS		regs;

	regs.w.ax = 0x101;
	regs.w.dx = rp->Selector;
	int386(0x31,&regs,&regs);
}
