// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
// This file has been modified from Ken Silverman's original release

#ifndef _INCLUDE_VES2_H_
#define _INCLUDE_VES2_H_

#if (!defined PLATFORM_DOS)
#error Do not include this file. It is for the DOS target only.
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>

#include "build.h"
#include "pragmas.h"

#pragma pack(push,1);

typedef struct
{
	char VESASignature[4];
	short VESAVersion;
	long OemStringPtr, Capabilities, VideoModePtr;
	short TotalMemory, OemSoftwareRev;
	long OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr;
	char reserved[222], OemDATA[256];
} VBE_vgaInfo;

typedef struct
{
	short ModeAttributes;
	char WinAAtributes, WinBAttributes;
	short WinGranularity, WinSize, WinASegment, WinBSegment;
	long WinFuncPtr;
	short BytesPerScanLine, XResolution, YResolution;
	char XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel;
	char NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages;
	char res1;
	char RedMaskSize, RedFieldPosition;
	char GreenMaskSize, GreenFieldPosition;
	char BlueMaskSize, BlueFieldPosition;
	char RsvdMaskSize, RsvdFieldPosition, DirectColorModeInfo;
	long PhysBasePtr, OffScreenMemOffset;
	short OffScreenMemSize;
	char res2[206];
} VBE_modeInfo;

struct _RMWORDREGS { unsigned short ax, bx, cx, dx, si, di, cflag; };
struct _RMBYTEREGS { unsigned char al, ah, bl, bh, cl, ch, dl, dh; };
typedef union { struct _RMWORDREGS x; struct _RMBYTEREGS h; } RMREGS;
typedef struct { unsigned short es, cs, ss, ds; } RMSREGS;

typedef struct
{
	long edi, esi, ebp, reserved, ebx, edx, ecx, eax;
	short flags, es, ds, fs, gs, ip, cs, sp, ss;
} _RMREGS;

#pragma pack(pop);

long VESABuf_sel = 0, VESABuf_rseg;
short modelist[256];
char *screen = NULL, vesachecked = 0;
long xres, yres, bytesperline, frameplace, imageSize, maxpages;
long buffermode, origbuffermode, linearmode;
long setactiveentry = 0, setvisualentry = 0, setpaletteentry = 0;
char permanentupdate = 0, vgacompatible;
short visualpagelookup[64][2];
long activepagelookup[64];
static long ves2lastx[MAXYDIM];
static long davesapageshift;
static VBE_vgaInfo vgaInfo;
long globlinplace;
static long backlinaddress = 0;  //Save address for free operation (0x801)

void faketimerhandler(void);

void qlimitrate(void);
#pragma aux qlimitrate =\
	"mov dx, 0x3da",\
	"wait1: in al, dx",\
	"test al, 1",\
	"jnz wait1",\
	modify exact [eax edx]\

void backupsegs(void);
short ods, oes, oss;
#pragma aux backupsegs =\
	"mov ods, ds",\
	"mov oes, es",\
	"mov oss, ss",\
	modify [eax]\

void restoresegs(void);
#pragma aux restoresegs =\
	"mov ds, ods",\
	"mov es, oes",\
	"mov ss, oss",\
	modify [eax]\

/*   //64-bit copybufbyte
#pragma aux copybufbyte =\
	"cmp ecx, 8",\
	"jae longcopy",\
	"test cl, 1",\
	"jz shortskip1",\
	"movsb",\
	"shortskip1: shr ecx, 2",\
	"jnc shortskip2",\
	"movsw",\
	"shortskip2: rep movsd",\
	"jmp endit",\
	"longcopy: test edi, 1",\
	"jz skip1",\
	"movsb",\
	"dec ecx",\
	"skip1: test edi, 2",\
	"jz skip2",\
	"movsw",\
	"sub ecx, 2",\
	"skip2: test edi, 4",\
	"jz skip3",\
	"movsd",\
	"sub ecx, 4",\
	"skip3: mov ebx, ecx",\
	"shr ecx, 3",\
	"jz skip4",\
	"begloop: fld qword ptr [esi]",\
	"fstp qword ptr [edi]",\
	"add esi, 8",\
	"add edi, 8",\
	"dec ecx",\
	"jnz begloop",\
	"skip4: test bl, 4",\
	"jz skip5",\
	"movsd",\
	"skip5: test bl, 2",\
	"jz skip6",\
	"movsw",\
	"skip6: test bl, 1",\
	"jz endit",\
	"movsb",\
	"endit:",\
	parm [esi][edi][ecx]\
	modify [ebx]\
*/


void vesasetactive(long i1, long i2, long i3, long i4);
#pragma aux vesasetactive =\
	"call dword ptr [setactiveentry]",\
	parm [eax][ebx][ecx][edx]\

void vesasetvisual(long i1, long i2, long i3, long i4);
#pragma aux vesasetvisual =\
	"call dword ptr [setvisualentry]",\
	parm [eax][ebx][ecx][edx]\

long vesasetpalette(long i1, long i2, long i3, long i4, long i5, char *i6);
#pragma aux vesasetpalette =\
	"call dword ptr [setpaletteentry]",\
	parm [eax][ebx][ecx][edx][esi][edi]\

long DPMI_int86(long intno, RMREGS *in, RMREGS *out)
{
	_RMREGS rmregs;
	union REGS r;
	struct SREGS sr;

	memset(&rmregs,0,sizeof(rmregs));
	rmregs.eax = in->x.ax; rmregs.ebx = in->x.bx;
	rmregs.ecx = in->x.cx; rmregs.edx = in->x.dx;
	rmregs.esi = in->x.si; rmregs.edi = in->x.di;

	segread(&sr);
	r.w.ax = 0x300; r.h.bl = intno; r.h.bh = 0; r.w.cx = 0; sr.es = sr.ds;
	r.x.edi = (unsigned)&rmregs;
	backupsegs(); int386x(0x31,&r,&r,&sr); restoresegs();

	out->x.ax = rmregs.eax; out->x.bx = rmregs.ebx;
	out->x.cx = rmregs.ecx; out->x.dx = rmregs.edx;
	out->x.si = rmregs.esi; out->x.di = rmregs.edi;
	out->x.cflag = rmregs.flags&1;
	return(out->x.ax);
}

long DPMI_int86x(long intno, RMREGS *in, RMREGS *out, RMSREGS *sregs)
{
	_RMREGS rmregs;
	union REGS r;
	struct SREGS sr;

	memset(&rmregs, 0, sizeof(rmregs));
	rmregs.eax = in->x.ax; rmregs.ebx = in->x.bx;
	rmregs.ecx = in->x.cx; rmregs.edx = in->x.dx;
	rmregs.esi = in->x.si; rmregs.edi = in->x.di;
	rmregs.es = sregs->es;
	rmregs.ds = sregs->ds;

	segread(&sr);
	r.w.ax = 0x300; r.h.bl = intno; r.h.bh = 0; r.w.cx = 0; sr.es = sr.ds;
	r.x.edi = (unsigned)&rmregs;
	backupsegs(); int386x(0x31,&r,&r,&sr); restoresegs();

	out->x.ax = rmregs.eax; out->x.bx = rmregs.ebx;
	out->x.cx = rmregs.ecx; out->x.dx = rmregs.edx;
	out->x.si = rmregs.esi; out->x.di = rmregs.edi;
	sregs->es = rmregs.es; sregs->cs = rmregs.cs;
	sregs->ss = rmregs.ss; sregs->ds = rmregs.ds;
	out->x.cflag = rmregs.flags&1;
	return(out->x.ax);
}

static void ExitVBEBuf(void)
{
	union REGS r;
	r.w.ax = 0x101; r.w.dx = VESABuf_sel; //DPMI free real seg
	backupsegs(); int386(0x31,&r,&r); restoresegs();
}

void VBE_callESDI(RMREGS *regs, void *buffer, long size)
{
	RMSREGS sregs;
	union REGS r;

	if (!VESABuf_sel)  //Init Real mode buffer
	{
		r.w.ax = 0x100; r.w.bx = 1024>>4;
		backupsegs(); int386(0x31,&r,&r); restoresegs();
		if (r.w.cflag) { printf("DPMI_allocRealSeg failed!\n"); exit(0); }
		VESABuf_sel = r.w.dx;
		VESABuf_rseg = r.w.ax;
		atexit(ExitVBEBuf);
	}
	sregs.es = VESABuf_rseg;
	regs->x.di = 0;
	_fmemcpy(MK_FP(VESABuf_sel,0),buffer,size);
	DPMI_int86x(0x10,regs,regs,&sregs);
	_fmemcpy(buffer,MK_FP(VESABuf_sel,0),size);
}

long VBE_getModeInfo(long mode, VBE_modeInfo *modeInfo)
{
	RMREGS regs;

	regs.x.ax = 0x4f01;
	regs.x.cx = mode;
	VBE_callESDI(&regs, modeInfo, sizeof(VBE_modeInfo));
	if (regs.x.ax != 0x004f) return(0);
	if ((modeInfo->ModeAttributes&1) == 0) return(0); //1 is vbeMdAvailable
	return(1);
}

GetPtrToLFB(long physAddr)
{
	#define LIMIT (4096*1024)-1
	long sel;
	union REGS r;

	r.w.ax = 0; r.w.cx = 1;
	backupsegs(); int386(0x31,&r,&r); restoresegs();
	if (r.x.cflag) { printf("DPMI_allocSelector() failed!\n"); exit(0); }
	sel = r.w.ax;
	r.w.ax = 9; r.w.bx = sel; r.w.cx = 0x8092;
	backupsegs(); int386(0x31,&r,&r); restoresegs();

	r.w.ax = 0x800; r.w.bx = physAddr >> 16; r.w.cx = physAddr & 0xffff;
	r.w.si = LIMIT>>16; r.w.di = LIMIT&0xffff;
	backupsegs(); int386(0x31,&r,&r); restoresegs();
	if (r.x.cflag) { printf("DPMI_mapPhysicalToLinear() failed!\n"); exit(0); }
	backlinaddress = globlinplace = ((long)r.w.bx<<16)+r.w.cx;

	r.w.ax = 7; r.w.bx = sel;
	r.w.cx = globlinplace>>16; r.w.dx = globlinplace&0xffff;
	backupsegs(); int386(0x31,&r,&r); restoresegs();
	if (r.x.cflag) { printf("DPMI_setSelectorBase() failed!\n"); exit(0); }

	r.w.ax = 8; r.w.bx = sel;
	r.w.cx = LIMIT>>16; r.w.dx = LIMIT&0xffff;
	backupsegs(); int386(0x31,&r,&r); restoresegs();
	if (r.x.cflag) { printf("DPMI_setSelectorLimit() failed!\n"); exit(0); }
}

void getvalidvesamodes(void)
{
	long i, j, k;
	short *p, *p2;
	VBE_modeInfo modeInfo;
	RMREGS regs;

	if (vesachecked) return;
	vesachecked = 1;

	validmodecnt = 0;
	modelist[0] = -1;

	strncpy(vgaInfo.VESASignature,"VBE2",4);
	regs.x.ax = 0x4f00;
	VBE_callESDI(&regs,&vgaInfo,sizeof(VBE_vgaInfo));
	if ((regs.x.ax != 0x004f) || (strncmp(vgaInfo.VESASignature,"VESA",4)))
		return;

	//if (vgaInfo.VESAVersion < 0x200) return;

		//LfbMapRealPointer
	p = (short *)(((vgaInfo.VideoModePtr&0xffff0000)>>12)+((vgaInfo.VideoModePtr)&0xffff));
	p2 = modelist;
	while (*p != -1) *p2++ = *p++;
	*p2 = -1;

	for(p=modelist;*p!=-1;p++)
	{
		regs.x.ax = 0x4f01; regs.x.cx = *p;
		VBE_callESDI(&regs,&modeInfo,sizeof(VBE_modeInfo));
		if (regs.x.ax != 0x004f) continue;
		if (!(modeInfo.ModeAttributes&1)) continue; //1 is vbeMdAvailable
		if (modeInfo.MemoryModel != 4) continue;    //4 is vbeMemPK
		if (modeInfo.BitsPerPixel != 8) continue;
		if (modeInfo.NumberOfPlanes != 1) continue;

		validmode[validmodecnt] = *p;
		validmodexdim[validmodecnt] = modeInfo.XResolution;
		validmodeydim[validmodecnt] = modeInfo.YResolution;
		validmodecnt++;
	}

	for(i=1;i<validmodecnt;i++)
		for(j=0;j<i;j++)
			if (validmodeydim[i] < validmodeydim[j])
			{
				k = validmode[i]; validmode[i] = validmode[j]; validmode[j] = k;
				k = validmodexdim[i]; validmodexdim[i] = validmodexdim[j]; validmodexdim[j] = k;
				k = validmodeydim[i]; validmodeydim[i] = validmodeydim[j]; validmodeydim[j] = k;
			}

	for(i=1;i<validmodecnt;i++)
		for(j=0;j<i;j++)
			if (validmodexdim[i] < validmodexdim[j])
			{
				k = validmode[i]; validmode[i] = validmode[j]; validmode[j] = k;
				k = validmodexdim[i]; validmodexdim[i] = validmodexdim[j]; validmodexdim[j] = k;
				k = validmodeydim[i]; validmodeydim[i] = validmodeydim[j]; validmodeydim[j] = k;
			}
}

int setvesa(long x, long y)
{
	div_t dived;
	long i, j, k;
	//short *p, *p1, *p2;
	short *p1;
	VBE_modeInfo modeInfo;
	RMREGS regs;
	RMSREGS sregs;

	getvalidvesamodes();

	xres = x; yres = y;
	for(k=0;k<validmodecnt;k++)
	{
		regs.x.ax = 0x4f01; regs.x.cx = validmode[k];
		VBE_callESDI(&regs,&modeInfo,sizeof(VBE_modeInfo));
		if (regs.x.ax != 0x004f) continue;
		if (!(modeInfo.ModeAttributes&1)) continue; //1 is vbeMdAvailable

		if (modeInfo.MemoryModel != 4) continue;    //4 is vbeMemPK
		if (modeInfo.BitsPerPixel != 8) continue;
		if (modeInfo.NumberOfPlanes != 1) continue;
		if (modeInfo.XResolution != x) continue;
		if (modeInfo.YResolution != y) continue;

		bytesperline = modeInfo.BytesPerScanLine;
		maxpages = min(modeInfo.NumberOfImagePages+1,64);

		regs.x.ax = 0x4f02;
		regs.x.bx = validmode[k] | ((modeInfo.ModeAttributes&128)<<7);
		DPMI_int86(0x10,&regs,&regs);

		if (modeInfo.ModeAttributes&32) vgacompatible = 0;
											else vgacompatible = 1;

		regs.x.ax = 0x4f0a; regs.x.bx = 0;
		DPMI_int86x(0x10,&regs,&regs,&sregs);
		if (regs.x.ax == 0x004f)   //cx is length of protected mode code
		{
			i = (((long)sregs.es)<<4)+((long)regs.x.di);
			p1 = (short *)i;
			setactiveentry = ((long)p1[0]) + i;
			setvisualentry = ((long)p1[1]) + i;
			setpaletteentry = ((long)p1[2]) + i;
				//p1[2] is useless palette function - see vesprot.asm for code
		}

			//Linear mode
		if (modeInfo.ModeAttributes&128) //128 is vbeMdLinear
		{
			GetPtrToLFB(modeInfo.PhysBasePtr);

			linearmode = 1;
			buffermode = (maxpages<=1);
			imageSize = bytesperline*yres;
			if (!buffermode) frameplace = globlinplace;
							else frameplace = FP_OFF(screen);
			j = 0;
			for(i=0;i<maxpages;i++)
			{
				activepagelookup[i] = globlinplace+j;
				j += imageSize;
			}
		}
		else  //Banked mode
		{
				//Get granularity
			switch(modeInfo.WinGranularity)
			{
				case 64: davesapageshift = 0; break;
				case 32: davesapageshift = 1; break;
				case 16: davesapageshift = 2; break;
				case 8: davesapageshift = 3; break;
				case 4: davesapageshift = 4; break;
				case 2: davesapageshift = 5; break;
				case 1: davesapageshift = 6; break;
			}

			linearmode = 0;
			if ((x == 320) && (y == 200) && (maxpages >= 2))
			{
				buffermode = 0;
				imageSize = 65536;
				frameplace = 0xa0000;
			}
			else
			{
				buffermode = 1;
				imageSize = bytesperline*yres;
				frameplace = FP_OFF(screen);
				maxpages = 1;
			}
		}

		origbuffermode = buffermode;

		j = 0;
		for(i=0;i<maxpages;i++)
		{
			dived = div(j,bytesperline);
			visualpagelookup[i][0] = (short)dived.rem;
			visualpagelookup[i][1] = (short)dived.quot;
			j += imageSize;
		}
		return(0);
	}
	return(-1);
}

long setdacbits(long newdacbits)
{
	RMREGS regs;

	if ((vgaInfo.Capabilities&1) == 0) return(6L);
	regs.x.ax = 0x4f08;
	regs.x.bx = (((long)newdacbits)<<8);
	DPMI_int86(0x10,&regs,&regs);
	return((long)regs.h.bh);
}

#define setvesapage(i)                                      \
{                                                           \
	if (setactiveentry)                                      \
		vesasetactive(0x4f05,0L,0L,i);                        \
	else                                                     \
	{                                                        \
		regs.x.ax = 0x4f05; regs.x.bx = 0; regs.x.dx = i;     \
		DPMI_int86(0x10,&regs,&regs);                         \
	}                                                        \
}

void setactivepage(long dapagenum)
{
	RMREGS regs;

	if ((origbuffermode == 0) && (linearmode == 0))
	{
		frameplace = 0xa0000;
		setvesapage(dapagenum<<davesapageshift);
	}
	if (buffermode != 0) { frameplace = FP_OFF(screen); return; }
	if (linearmode != 0) { frameplace = activepagelookup[dapagenum]; return; }
}

static long curpag = 0;
void setvisualpage(long dapagenum)
{
	RMREGS regs;
	long i, /*j,*/ p, dx, cx1, cy1, cx2, cy2, delta, x, y, y1, y2, ny1, ny2;

	if (buffermode != 0)
	{
		cx1 = windowx1; cy1 = windowy1; cx2 = windowx2; cy2 = windowy2;
		if (permanentupdate) { cx1 = 0; cy1 = 0; cx2 = xdim-1; cy2 = ydim-1; }
		dx = cx2-cx1+1;
		if (linearmode)
		{
			p = FP_OFF(screen);
			delta = activepagelookup[dapagenum&0x7fffffff]-FP_OFF(screen);
			if (permanentupdate == 0)
			{
				y1 = startumost[cx1]; y2 = y1;
				for(x=cx1;x<=cx2;x++)
				{
					ny1 = startumost[x]-1; ny2 = startdmost[x];
					if (ny1 < ny2-1)
					{
						if (ny1 >= y2)
						{
							while (y1 < y2-1)
							{
								y1++; if ((y1&31) == 0) faketimerhandler();
									//x,y1
								i = p+ylookup[y1]+ves2lastx[y1];
								copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]);
							}
							y1 = ny1;
						}
						else
						{
							while (y1 < ny1)
							{
								y1++; if ((y1&31) == 0) faketimerhandler();
									//x-1,y1
								i = p+ylookup[y1]+ves2lastx[y1];
								copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]);
							}
							while (y1 > ny1) ves2lastx[y1--] = x;
						}
						while (y2 > ny2)
						{
							y2--; if ((y2&31) == 0) faketimerhandler();
								//x-1,y2
							i = p+ylookup[y2]+ves2lastx[y2];
							copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y2]);
						}
						while (y2 < ny2) ves2lastx[y2++] = x;
					}
					else
					{
						while (y1 < y2-1)
						{
							y1++; if ((y1&31) == 0) faketimerhandler();
								//x-1,y1
							i = p+ylookup[y1]+ves2lastx[y1];
							copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]);
						}
						if (x == cx2) break;
						y1 = startumost[x+1]; y2 = y1;
					}
				}
				while (y1 < y2-1)
				{
					y1++; if ((y1&31) == 0) faketimerhandler();
						//cx2+1,y1
					i = p+ylookup[y1]+ves2lastx[y1];
					copybufbyte((void *)i,(void *)(i+delta),cx2+1-ves2lastx[y1]);
				}
			}
			else
			{
				p += ylookup[cy1]+cx1;
				delta = activepagelookup[dapagenum&0x7fffffff]-FP_OFF(screen);
				for(y=cy1;y<=cy2;y++)
				{
					copybufbyte((void *)p,(void *)(p+delta),dx);
					p += ylookup[1];
					if ((y&31) == 0) faketimerhandler();
				}
			}
		}
		else
		{
			p = ylookup[cy1]+cx1;
			for(y=cy1;y<=cy2;y++)
			{
				if ((p>>16) != curpag)
				{
					curpag = (p>>16);

					setvesapage(curpag<<davesapageshift);
					faketimerhandler();
				}

				i = (p&65535)+dx-65536;
				if (i <= 0)
					copybufbyte((void *)(p+FP_OFF(screen)),(void *)((p&65535)+0xa0000),dx);
				else
				{
					copybufbyte((void *)(p+FP_OFF(screen)),(void *)(0xb0000-(dx-i)),dx-i);

					curpag = ((p+dx-1)>>16);
					setvesapage(curpag<<davesapageshift);
					faketimerhandler();

					copybufbyte((void *)(p+(dx-i)+FP_OFF(screen)),(void *)0xa0000,i);
				}
				p += ylookup[1];
			}
		}
		permanentupdate = 0;
	}
	if (origbuffermode == 0)
	{
		if (setvisualentry)
		{
			i = imageSize*(dapagenum&0x7fffffff);
			if (vgacompatible)
			{
				if (dapagenum >= 0) qlimitrate();
				vesasetvisual(0x4f07,0L,i>>2,i>>18);
			}
			else
				{ vesasetvisual(0x4f07,0x80,i>>2,i>>18); }

		}
		else
		{
			regs.x.ax = 0x4f07;
			regs.x.cx = visualpagelookup[dapagenum&0x7fffffff][0]; //X-coordinate
			regs.x.dx = visualpagelookup[dapagenum&0x7fffffff][1]; //Y-coordinate
			if (vgacompatible)
			{
				regs.x.bx = 0;
				if (dapagenum >= 0) qlimitrate();
				DPMI_int86(0x10,&regs,&regs);
			}
			else
				{ regs.x.bx = 0x80; DPMI_int86(0x10,&regs,&regs); }
		}
		if (dapagenum >= 0) faketimerhandler();
	}
}

void uninitvesa(void)
{
	if (backlinaddress)
	{
		union REGS r;
		r.w.ax = 0x801;
		r.w.bx = (backlinaddress >> 16);
		r.w.cx = (backlinaddress & 0xffff);
		backupsegs(); int386(0x31,&r,&r); restoresegs();
		if (r.x.cflag) { printf("Free Physical Address failed!\n"); }
		backlinaddress = 0;
	}
	VESABuf_sel = 0;
	vesachecked = 0;
}

#if 0  // doesn't appear to be used anymore. --ryan.
#pragma aux setpalettequick =\
	"mov edx, 0x3c8",\
	"out dx, al",\
	"inc edx",\
	"lea ecx, [ecx+ecx*2]",\
	"cld",\
	"rep outsb",\
	parm [eax][ecx][esi]\
	modify exact [ecx edx esi]
#endif

int VBE_setPalette(long start, long num, char *dapal)
{
	RMREGS regs;
	long i, j, k;
	char palquick[768];

	if (stereomode == 1)
	{
		if ((unsigned)((blackband&255)-start) < (unsigned)num)
		{
			dapal[(((blackband&255)-start)<<2)+0] = 0;
			dapal[(((blackband&255)-start)<<2)+1] = 0;
			dapal[(((blackband&255)-start)<<2)+2] = 0;
		}
		if ((unsigned)((whiteband&255)-start) < (unsigned)num)
		{
			dapal[(((whiteband&255)-start)<<2)+0] = 255;
			dapal[(((whiteband&255)-start)<<2)+1] = 255;
			dapal[(((whiteband&255)-start)<<2)+2] = 255;
		}
	}
	if ((vgacompatible) || (vgaInfo.VESAVersion < 0x200) || (vidoption != 1))
	{
		j = 0; k = (start<<2);
		for(i=0;i<num;i++)
		{
			palquick[j] = dapal[k+2];
			palquick[j+1] = dapal[k+1];
			palquick[j+2] = dapal[k];
			j += 3; k += 4;
		}
		//setpalettequick(start,num,palquick);
		koutp(0x3c8,start);
		for(i=(num>>1);i>0;i--)
		{
			koutp(0x3c9,(long) dapal[2]);
			while (kinp(0x3da)&1); while (!(kinp(0x3da)&1));
										  koutp(0x3c9,(long) dapal[1]); koutp(0x3c9,(long) dapal[0]);
			koutp(0x3c9,(long) dapal[6]); koutp(0x3c9,(long) dapal[5]); koutp(0x3c9,(long) dapal[4]);
			dapal += 8;
		}
		if (num&1)
		{
			koutp(0x3c9,(long) dapal[2]);
			while (kinp(0x3da)&1); while (!(kinp(0x3da)&1));
										  koutp(0x3c9,(long) dapal[1]); koutp(0x3c9,(long) dapal[0]);
		}
		return(1);
	}

	if (setpaletteentry)
	{
		i = (vesasetpalette(0x4f09,(vgaInfo.Capabilities&4)<<5,
								  num,start,0L,dapal)&65535);
	}
	else
	{
		regs.x.ax = 0x4f09; regs.h.bl = ((vgaInfo.Capabilities&4)<<5);
		regs.x.cx = num; regs.x.dx = start;
		VBE_callESDI(&regs,dapal,sizeof(dapal)*num);
		i = regs.x.ax;
	}
	if (i != 0x004f) return(0);
	return(1);
}

VBE_getPalette(long start, long num, char *dapal)
{
	RMREGS regs;
	long i;

	if ((vgacompatible) || (vgaInfo.VESAVersion < 0x200) || (vidoption != 1))
	{
		koutp(0x3c7,start);
		for(i=num;i>0;i--)
		{
			dapal[2] = (char) kinp(0x3c9);
			dapal[1] = (char) kinp(0x3c9);
			dapal[0] = (char) kinp(0x3c9);
			dapal += 4;
		}
		return(1);
	}

	regs.x.ax = 0x4f09; regs.h.bl = 1;
	regs.x.cx = num; regs.x.dx = start;
	VBE_callESDI(&regs,dapal,sizeof(dapal)*num);
	i = regs.x.ax;
	if (i != 0x004f) return(0);
	return(1);
}

#endif   // _INCLUDE_VES2_H_

// end of ves2.h ...


