/****************************************************************************
*
* The SuperVGA Kit - UniVBE Software Development Kit
*
* Copyright (C) 1996 SciTech Software
* All rights reserved.
*
* Filename: $Workfile: svgasdk.c $
* Version: $Revision: 1.33 $
*
* Language: ANSI C
* Environment: IBM PC (MSDOS) Real Mode and 16/32 bit Protected Mode.
*
* Description: Simple library to collect together the functions in the
* SuperVGA test library for use in other C programs. The
* support is reasonably low level, so you can do what you
* want. The set of routines in this source file are general
* SuperVGA routines and are independant of the video mode
* selected.
*
* MUST be compiled in the LARGE or FLAT models.
*
* $Date: 04 Nov 1996 12:18:58 $ $Author: AlanR $
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "pmpro.h"
#include "svga.h"
#include "wdirect.h"
/* If we are compiling for either 32 bit protected mode or 16 bit Windows,
* then we can use the VBE 2.0 protected mode functions and linear
* framebuffer code, and also VBE/AF Accelerator Functions.
*/
#if defined(PM386) || defined(__WINDOWS16__) || defined(TESTING_PM)
#define USE_VBE20
#endif
#if !defined(__16BIT__) || defined(TESTING_PM)
#define USE_VBEAF
#endif
/*---------------------------- Global Variables ---------------------------*/
#define MAXMODES 100 /* Maximum modes available in list */
#define DC _SV_devCtx /* Macro to access global structure */
PUBLIC SV_devCtx _ASMAPI _SV_devCtx = {0};
#ifdef USE_VBEAF
PRIVATE AF_devCtx *loadedDC = NULL; /* DC of loaded VBE/AF driver */
#endif
PRIVATE uint VESABuf_len = 1024; /* Length of VESABuf */
PRIVATE uint VESABuf_sel = 0; /* Selector for VESABuf */
PRIVATE uint VESABuf_off; /* Offset for VESABuf */
PRIVATE uint VESABuf_rseg; /* Real mode segment of VESABuf */
PRIVATE uint VESABuf_roff; /* Real mode offset of VESABuf */
PRIVATE ushort _SV_modeList[MAXMODES];
PRIVATE char _SV_OEMString[80];
PRIVATE bool _SV_old50Lines; /* Was old mode 80x50? */
PRIVATE bool _SV_convertPal; /* True to convert palette entries */
PUBLIC int _ASMAPI _SV_bankShift;/* Bank granularity adjust factor */
PUBLIC long _ASMAPI _SV_pagesize; /* Page size for current mode */
PUBLIC void * _ASMAPI _SV_setBankRM;/* Pointer to direct VBE bank code*/
PUBLIC void * _ASMAPI _SV_setBankPtr;/* Pointer to bank switch code */
#ifdef __WINDOWS__
PRIVATE HWND hwndMain = NULL; /* Main window for application */
#endif
void _ASMAPI _VBE_setBankA(void); /* VBE setBank routine single bank */
void _ASMAPI _VBE_setBankAB(void); /* VBE setBank routine dual banks */
#ifdef USE_VBE20
void _ASMAPI _VBE20_setBankA(void); /* VBE 2.0 setBank single bank */
void _ASMAPI _VBE20_setBankAB(void); /* VBE 2.0 setBank dual banks */
void _ASMAPI _VBE20_setBankA_ES(void); /* VBE 2.0 setBank for MMIO */
void _ASMAPI _VBE20_setBankAB_ES(void); /* VBE 2.0 setBank for MMIO */
PUBLIC void * _ASMAPI _SV_setBank20 = NULL;/* Pointer to set bank routine*/
PUBLIC void * _ASMAPI _SV_setCRT20 = NULL;/* Pointer to set CRT routine*/
PUBLIC void * _ASMAPI _SV_setPal20 = NULL;/* Pointer to set palette rtn*/
extern short _ASMAPI VBE_MMIOSel; /* Selector to MMIO registers */
#endif
#ifdef USE_VBEAF
void SVAPI _VBEAF_setBank(void); /* VBE/AF setBank function */
#endif
extern uchar _ASMAPI font8x16[]; /* Bitmap font definition */
extern SV_palette _ASMAPI VGA8_defPal[];
/*----------------------------- Implementation ----------------------------*/
/* Declare all banked framebuffer routines */
void _ASMAPI _SV_setActivePage(int page);
void _ASMAPI _SV_setVisualPage(int page,bool waitVRT);
void _ASMAPI _VGA_setPalette(int start,int num,SV_palette *pal,bool waitVRT);
void _ASMAPI _VBE20_setPalette(int start,int num,SV_palette *pal,bool waitVRT);
void _ASMAPI _SV_clear16(ulong color);
void _ASMAPI _SV_clear256(ulong color);
void _ASMAPI _SV_clear32k(ulong color);
void _ASMAPI _SV_clear16m(ulong color);
void _ASMAPI _SV_clear4G(ulong color);
void _ASMAPI _SV_putPixel16(int x,int y,ulong color);
void _ASMAPI _SV_putPixel256(int x,int y,ulong color);
void _ASMAPI _SV_putPixel32k(int x,int y,ulong color);
void _ASMAPI _SV_putPixel16m(int x,int y,ulong color);
void _ASMAPI _SV_putPixel4G(int x,int y,ulong color);
void _ASMAPI _SV_line16(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line256(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line32k(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line16m(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line4G(int x1,int y1,int x2,int y2,ulong color);
/* Declare all the linear framebuffer routines */
#ifdef USE_VBE20
#ifdef __WINDOWS16__
void _ASMAPI linsdk_enable32(void);
#endif
void _ASMAPI _SV_setActivePageLin(int page);
void _ASMAPI _SV_clear256Lin(ulong color);
void _ASMAPI _SV_clear32kLin(ulong color);
void _ASMAPI _SV_clear16mLin(ulong color);
void _ASMAPI _SV_clear4GLin(ulong color);
void _ASMAPI _SV_putPixel256Lin(int x,int y,ulong color);
void _ASMAPI _SV_putPixel32kLin(int x,int y,ulong color);
void _ASMAPI _SV_putPixel16mLin(int x,int y,ulong color);
void _ASMAPI _SV_putPixel4GLin(int x,int y,ulong color);
void _ASMAPI _SV_line256Lin(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line32kLin(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line16mLin(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_line4GLin(int x1,int y1,int x2,int y2,ulong color);
#endif
/* Declare all VBE/AF specific functions */
#ifdef USE_VBEAF
void _ASMAPI _SV_setActivePageAF(int page);
void _ASMAPI _SV_setActivePageLinAF(int page);
void _ASMAPI _SV_setVisualPageAF(int page,bool waitVRT);
void _ASMAPI _SV_beginDirectAccessAFSLOW(void);
void _ASMAPI _SV_endDirectAccessAFSLOW(void);
void _ASMAPI _SV_beginPixelAFSLOW(void);
void _ASMAPI _SV_endPixelAFSLOW(void);
void _ASMAPI _SV_beginLineAFSLOW(void);
void _ASMAPI _SV_endLineAFSLOW(void);
void _ASMAPI _SV_beginDirectAccessAF(void);
void _ASMAPI _SV_endDirectAccessAF(void);
void _ASMAPI _SV_beginPixelAF(void);
void _ASMAPI _SV_endPixelAF(void);
void _ASMAPI _SV_beginLineAF(void);
void _ASMAPI _SV_endLineAF(void);
void _ASMAPI _SV_clearAF(ulong color);
void _ASMAPI _SV_putPixelAF(int x,int y,ulong color);
void _ASMAPI _SV_lineFastAF(int x1,int y1,int x2,int y2,ulong color);
void _ASMAPI _SV_softLineAF(int x1,int y1,int x2,int y2,ulong color);
#endif
/*----------------------------- Implementation ----------------------------*/
#pragma warn -par
PRIVATE void ExitVBEBuf(void)
{
if (VESABuf_sel)
PM_freeRealSeg(VESABuf_sel,VESABuf_off);
VESABuf_sel = 0;
}
void SVAPI SV_initRMBuf(void)
/****************************************************************************
*
* Function: SV_initRMBuf
*
* Description: Initialises the VBE transfer buffer in real mode DC.memory.
* This routine is called by the VESAVBE module every time
* it needs to use the transfer buffer, so we simply allocate
* it once and then return.
*
****************************************************************************/
{
if (!VESABuf_sel) {
/* Allocate a global buffer for communicating with the VESA VBE */
if (!PM_allocRealSeg(VESABuf_len, &VESABuf_sel, &VESABuf_off,
&VESABuf_rseg, &VESABuf_roff))
exit(1);
VBE_init(VESABuf_len,VESABuf_sel,VESABuf_off,VESABuf_rseg,VESABuf_roff);
atexit(ExitVBEBuf);
}
}
void SV_nop(void) {}
PRIVATE SV_devCtx *InitVBE(void)
/****************************************************************************
*
* Function: InitVBE
* Returns: Pointer to device context block or 0 if no SuperVGA.
*
* Description: Performs initialisation for VBE based devices.
*
****************************************************************************/
{
VBE_vgaInfo vgaInfo;
VBE_modeInfo modeInfo;
int i;
ushort *p,tmodeList[MAXMODES];
SV_initRMBuf();
if ((DC.VBEVersion = VBE_detect(&vgaInfo)) == 0)
return NULL;
/* Copy relevent information from the mode block into our globals.
* Note that the video mode list _may_ be built in the information
* block that we have passed, so we _must_ copy this from here
* into our our storage if we want to continue to use it. Note
* that we filter out the mode 0x6A, which some BIOSes include as
* well as the 0x102 mode for 800x600x16.
*/
for (i = 0, p = vgaInfo.VideoModePtr; (*p != 0xFFFF && i < MAXMODES); p++) {
if (*p >= 0x100)
tmodeList[i++] = *p;
}
tmodeList[i] = -1;
/* Now build our global list of available video modes, filtering out
* those modes that are not available or not graphics modes. A VBE
* implementation may put modes in the mode list that are not available
* on the current hardware configuration, so we need to check for this.
*/
DC.haveMultiBuffer = false;
DC.haveVirtualScroll = false;
DC.linearAddr = 0;
for (i = 0,p = tmodeList; (*p != 0xFFFF && i < MAXMODES); p++) {
if (!VBE_getModeInfo(*p,&modeInfo))
continue;
if ((modeInfo.ModeAttributes & vbeMdGraphMode) == 0)
continue;
if (!DC.linearAddr && (modeInfo.ModeAttributes & vbeMdLinear))
DC.linearAddr = modeInfo.PhysBasePtr;
if (modeInfo.NumberOfImagePages > 0) {
/* If we have any graphics mode reports that it has more than
* 1 display page available, then we assume double buffering
* and virtual scrolling are available. Note that under VBE
* 1.2 and 2.0 these are one and the same, but under VBE/AF
* you can have cards that do double buffering but not virtual
* scrolling (and vice versa).
*/
DC.haveMultiBuffer = true;
DC.haveVirtualScroll = true;
}
DC.modeList[i++] = *p;
}
DC.modeList[i] = -1;
DC.memory = vgaInfo.TotalMemory * 64;
DC.haveWideDAC = ((int)vgaInfo.Capabilities & vbe8BitDAC) != 0;
strcpy(DC.OEMString,vgaInfo.OemStringPtr);
#ifndef REALMODE
if (DC.VBEVersion >= 0x200 && VF_available()) {
int codeLen;
void *bankFunc;
DC.haveVirtualBuffer = VBE_getBankFunc32(&codeLen,&bankFunc,0,0);
}
else
DC.haveVirtualBuffer = false;
#endif
#ifdef __WINDOWS16__
linsdk_enable32(); /* Enable 32 bit linear framebuffer module */
#endif
return &DC;
}
PUBLIC SV_devCtx * SVAPI SV_init(bool useVBEAF)
/****************************************************************************
*
* Function: SV_init
* Parameters: useVBEAF - True to use the VBE/AF driver if found
* Returns: Pointer to device context block, or NULL if SVGA not found.
*
* Description: Detects if a VESA VBE compliant SuperVGA is out there, and
* initialises the library if one is. The VBE version number
* is specified with the major version number in the high
* byte and the minor version number in the low byte. So
* version 1.2 is the number 0x102.
*
* If we detect VBE/AF Accelerator Functions support, we
* initialise the library to use VBE/AF rather than VBE 1.2/2.0
* and return a DC.VBEVersion number of 2.0. It is up to the
* application program to then check the DC.AFDC pointer to
* determine if VBE/AF is available or not.
*
****************************************************************************/
{
/* Initialise global pointers in global device context block */
DC.modeList = _SV_modeList;
DC.OEMString = _SV_OEMString;
#ifdef USE_VBEAF
DC.AFDC = NULL;
#endif
if (useVBEAF) {
#ifdef USE_VBEAF
int i;
short *p;
AF_modeInfo modeInfo;
if (loadedDC)
DC.AFDC = loadedDC;
else
DC.AFDC = loadedDC = AF_loadDriver(NULL);
if (DC.AFDC) {
/* Copy list of available modes */
for (i = 0,p = DC.AFDC->AvailableModes; (*p != -1 && i < MAXMODES); p++) {
if (AF_getVideoModeInfo(DC.AFDC,*p,&modeInfo) != 0)
continue;
DC.modeList[i++] = *p;
}
DC.modeList[i] = -1;
/* Obtain configuration information from driver */
DC.haveMultiBuffer = (DC.AFDC->Attributes & afHaveMultiBuffer);
DC.haveVirtualScroll = (DC.AFDC->Attributes & afHaveVirtualScroll);
DC.haveWideDAC = (DC.AFDC->Attributes & afHave8BitDAC);
DC.haveAccel2D = (DC.AFDC->Attributes & afHaveAccel2D);
DC.haveHWCursor = (DC.AFDC->Attributes & afHaveHWCursor);
DC.linearAddr = DC.AFDC->LinearBasePtr;
DC.memory = DC.AFDC->TotalMemory;
strcpy(DC.OEMString,DC.AFDC->OemVendorName);
DC.haveVirtualBuffer = (DC.AFDC->SetBank32 != NULL);
#ifdef __WINDOWS16__
linsdk_enable32();
#endif
DC.VBEVersion = 0x200;
return &DC;
}
#endif
}
return InitVBE();
}
PUBLIC void SVAPI SV_exit(void)
/****************************************************************************
*
* Function: SV_exit
*
* Description: Clean up correctly for the SuperVGA Kit. Needed for
* DLL versions when running under Windows 3.1 to properly
* clean up after the DLL (exit functions dont seem to work).
*
****************************************************************************/
{
ExitVBEBuf();
}
PUBLIC bool SVAPI SV_getModeInfo(ushort mode,SV_modeInfo *modeInfo)
/****************************************************************************
*
* Function: SV_getModeInfo
* Parameters: mode - Mode number for the mode
* modeInfo - Place to store the mode information
* Returns: True if for valid mode, false if invalid.
*
* Description: Obtains mode information for the specified mode number.
* Note that we either call the VBE BIOS or the VBE/AF driver
* for this information, massaging the information returned
* into our common buffer format.
*
****************************************************************************/
{
/* Mask off any extra flags from the mode number before we pass it
* onto the BIOS. We also ignore any non-VBE modes.
*/
if ((mode &= 0x1FF) < 0x100)
return false;
if (DC.AFDC) {
#ifdef USE_VBEAF
AF_modeInfo miAF;
if (AF_getVideoModeInfo(DC.AFDC,mode,&miAF) != 0)
return false;
modeInfo->Attributes = miAF.Attributes;
modeInfo->XResolution = miAF.XResolution;
modeInfo->YResolution = miAF.YResolution;
modeInfo->BitsPerPixel = miAF.BitsPerPixel;
modeInfo->BytesPerScanLine = miAF.BytesPerScanLine;
modeInfo->NumberOfPages = miAF.MaxBuffers;
modeInfo->RedMaskSize = miAF.RedMaskSize;
modeInfo->RedFieldPosition = miAF.RedFieldPosition;
modeInfo->GreenMaskSize = miAF.GreenMaskSize;
modeInfo->GreenFieldPosition = miAF.GreenFieldPosition;
modeInfo->BlueMaskSize = miAF.BlueMaskSize;
modeInfo->BlueFieldPosition = miAF.BlueFieldPosition;
modeInfo->RsvdMaskSize = miAF.RsvdMaskSize;
modeInfo->RsvdFieldPosition = miAF.RsvdFieldPosition;
if (miAF.LinBytesPerScanLine != 0) {
/* VBE/AF 1.1 spec and later */
modeInfo->LinBytesPerScanLine = miAF.LinBytesPerScanLine;
modeInfo->BnkNumberOfPages = miAF.BnkMaxBuffers;
modeInfo->LinNumberOfPages = miAF.LinMaxBuffers;
modeInfo->LinRedMaskSize = miAF.LinRedMaskSize;
modeInfo->LinRedFieldPosition = miAF.LinRedFieldPosition;
modeInfo->LinGreenMaskSize = miAF.LinGreenMaskSize;
modeInfo->LinGreenFieldPosition = miAF.LinGreenFieldPosition;
modeInfo->LinBlueMaskSize = miAF.LinBlueMaskSize;
modeInfo->LinBlueFieldPosition = miAF.LinBlueFieldPosition;
modeInfo->LinRsvdMaskSize = miAF.LinRsvdMaskSize;
modeInfo->LinRsvdFieldPosition = miAF.LinRsvdFieldPosition;
}
else {
/* Older version of the VBE/AF spec so use banked values */
modeInfo->LinBytesPerScanLine = miAF.BytesPerScanLine;
modeInfo->BnkNumberOfPages = miAF.MaxBuffers;
modeInfo->LinNumberOfPages = miAF.MaxBuffers;
modeInfo->LinRedMaskSize = miAF.RedMaskSize;
modeInfo->LinRedFieldPosition = miAF.RedFieldPosition;
modeInfo->LinGreenMaskSize = miAF.GreenMaskSize;
modeInfo->LinGreenFieldPosition = miAF.GreenFieldPosition;
modeInfo->LinBlueMaskSize = miAF.BlueMaskSize;
modeInfo->LinBlueFieldPosition = miAF.BlueFieldPosition;
modeInfo->LinRsvdMaskSize = miAF.RsvdMaskSize;
modeInfo->LinRsvdFieldPosition = miAF.RsvdFieldPosition;
}
#endif
}
else {
VBE_modeInfo miVBE;
if (!VBE_getModeInfo(mode,&miVBE))
return false;
if (!(miVBE.ModeAttributes & vbeMdGraphMode))
return false;
modeInfo->XResolution = miVBE.XResolution;
modeInfo->YResolution = miVBE.YResolution;
modeInfo->BitsPerPixel = miVBE.BitsPerPixel;
modeInfo->BytesPerScanLine = miVBE.BytesPerScanLine;
modeInfo->NumberOfPages = miVBE.NumberOfImagePages+1;
modeInfo->RedMaskSize = miVBE.RedMaskSize;
modeInfo->RedFieldPosition = miVBE.RedFieldPosition;
modeInfo->GreenMaskSize = miVBE.GreenMaskSize;
modeInfo->GreenFieldPosition = miVBE.GreenFieldPosition;
modeInfo->BlueMaskSize = miVBE.BlueMaskSize;
modeInfo->BlueFieldPosition = miVBE.BlueFieldPosition;
modeInfo->RsvdMaskSize = miVBE.RsvdMaskSize;
modeInfo->RsvdFieldPosition = miVBE.RsvdFieldPosition;
/* Fill in Attributes field depending on what the controller can
* support.
*/
modeInfo->Attributes = svIsVBEMode;
if (modeInfo->NumberOfPages > 1) {
modeInfo->Attributes |= svHaveMultiBuffer;
modeInfo->Attributes |= svHaveVirtualScroll;
}
if (!(miVBE.ModeAttributes & vbeMdNonBanked))
modeInfo->Attributes |= svHaveBankedBuffer;
if (miVBE.ModeAttributes & vbeMdLinear)
modeInfo->Attributes |= svHaveLinearBuffer;
if (miVBE.ModeAttributes & vbeMdNonVGA)
modeInfo->Attributes |= svNonVGAMode;
if (miVBE.LinBytesPerScanLine != 0) {
/* VBE 2.1 and later extra information for properly handling
* the linear framebuffer modes.
*/
modeInfo->LinBytesPerScanLine = miVBE.LinBytesPerScanLine;
modeInfo->BnkNumberOfPages = miVBE.BnkNumberOfImagePages+1;
modeInfo->LinNumberOfPages = miVBE.LinNumberOfImagePages+1;
modeInfo->LinRedMaskSize = miVBE.LinRedMaskSize;
modeInfo->LinRedFieldPosition = miVBE.LinRedFieldPosition;
modeInfo->LinGreenMaskSize = miVBE.LinGreenMaskSize;
modeInfo->LinGreenFieldPosition = miVBE.LinGreenFieldPosition;
modeInfo->LinBlueMaskSize = miVBE.LinBlueMaskSize;
modeInfo->LinBlueFieldPosition = miVBE.LinBlueFieldPosition;
modeInfo->LinRsvdMaskSize = miVBE.LinRsvdMaskSize;
modeInfo->LinRsvdFieldPosition = miVBE.LinRsvdFieldPosition;
}
else {
/* Older VBE 2.0 version of the spec, so use the values
* for the banked modes.
*/
modeInfo->LinBytesPerScanLine = miVBE.BytesPerScanLine;
modeInfo->BnkNumberOfPages = miVBE.NumberOfImagePages+1;
modeInfo->LinNumberOfPages = miVBE.NumberOfImagePages+1;
modeInfo->LinRedMaskSize = miVBE.RedMaskSize;
modeInfo->LinRedFieldPosition = miVBE.RedFieldPosition;
modeInfo->LinGreenMaskSize = miVBE.GreenMaskSize;
modeInfo->LinGreenFieldPosition = miVBE.GreenFieldPosition;
modeInfo->LinBlueMaskSize = miVBE.BlueMaskSize;
modeInfo->LinBlueFieldPosition = miVBE.BlueFieldPosition;
modeInfo->LinRsvdMaskSize = miVBE.RsvdMaskSize;
modeInfo->LinRsvdFieldPosition = miVBE.RsvdFieldPosition;
}
}
modeInfo->Mode = mode;
return true;
}
PUBLIC int SVAPI SV_getModeName(char *buf,SV_modeInfo *mi,ushort mode,bool useLinear)
/****************************************************************************
*
* Function: SV_getModeName
* Parameters: buf - Buffer to put mode name into
* mi - Pointer to VBE mode info block
* mode - Mode number for the mode
* useLinear - True if we should the linear buffer if available
* Returns: Mode number to set mode with (with appropriate flags added)
*
* Description: Puts the name of the video mode in a standard format into
* the string buffer, and returns the mode number to be used
* to set the video mode.
*
****************************************************************************/
{
char buf1[80],buf2[80];
int bankedAndLinear,attr = mi->Attributes;
/* Ignore linear only modes if linear buffering not available */
if (!(attr & svHaveBankedBuffer) && !useLinear)
return 0;
/* Build the name of the mode */
if (useLinear) {
if ((attr & svHaveBankedBuffer) && (attr & svHaveLinearBuffer)) {
sprintf(buf2,", Banked+Linear");
bankedAndLinear = true;
}
else if (attr & svHaveLinearBuffer) {
sprintf(buf2,", Linear Only");
bankedAndLinear = false;
}
else {
sprintf(buf2,", Banked Only");
bankedAndLinear = false;
}
#ifdef USE_VBE20
/* Use the linear framebuffer mode if available */
if (attr & svHaveLinearBuffer)
mode |= svLinearBuffer;
#endif
}
else {
sprintf(buf2,", Banked Only");
bankedAndLinear = false;
}
if (bankedAndLinear && (mi->BnkNumberOfPages != mi->LinNumberOfPages))
sprintf(buf1,"%2d/%d", mi->BnkNumberOfPages, mi->LinNumberOfPages);
else
sprintf(buf1,"%2d", mi->NumberOfPages);
sprintf(buf,"%4d x %4d %d bit (%s page%s",mi->XResolution,mi->YResolution,
mi->BitsPerPixel,buf1,buf2);
if (attr & svHaveAccel2D)
strcat(buf,", Accelerated");
if (attr & svNonVGAMode)
strcat(buf,", NonVGA)");
else
strcat(buf,")");
return mode;
}
PRIVATE bool SetModeVBE(ushort mode,bool use8BitDAC,bool useVirtualBuffer,
bool setPalette)
/****************************************************************************
*
* Function: SetModeVBE
* Parameters: mode - SuperVGA video mode to set.
* use8BitDAC - True to set up the 8 bit DAC mode
* Returns: True if the mode was set, false if not.
*
* Description: Attempts to set the specified video mode. This routine
* assumes that the library and SuperVGA have been initialised
* with the SV_init() routine first.
*
****************************************************************************/
{
VBE_modeInfo modeInfo;
RMREGS regs;
int imode = mode & svModeMask;
int cntMode = VBE_getVideoMode();
if (imode < 0x100 && imode != 0x13)
return false;
if (imode != cntMode && cntMode <= 3) {
_SV_old50Lines = false; /* Default to 25 line mode */
if (cntMode == 0x3) {
regs.x.ax = 0x1130;
regs.x.bx = 0;
regs.x.dx = 0;
PM_int86(0x10,®s,®s);
_SV_old50Lines = (regs.h.dl == 49);
}
}
if (!VBE_setVideoMode(mode)) /* Set the video mode */
return false;
/* Initialise global variables for current video mode dimensions */
if (imode == 0x13) {
/* Special case for VGA mode 13h */
DC.maxx = 319;
DC.maxy = 199;
DC.bytesperline = 320;
DC.bitsperpixel = 8;
DC.maxpage = 0;
_SV_pagesize = 0x10000L;
_SV_bankShift = 0;
DC.isNonVGA = false;
}
else {
VBE_getModeInfo(imode,&modeInfo);
DC.maxx = modeInfo.XResolution-1;
DC.maxy = modeInfo.YResolution-1;
DC.bitsperpixel = modeInfo.BitsPerPixel;
if (modeInfo.LinBytesPerScanLine != 0) {
/* VBE 2.1 extensions for linear buffer info */
DC.bytesperline = modeInfo.LinBytesPerScanLine;
if (mode & vbeLinearBuffer)
DC.maxpage = modeInfo.LinNumberOfImagePages;
else
DC.maxpage = modeInfo.BnkNumberOfImagePages;
}
else {
DC.bytesperline = modeInfo.BytesPerScanLine;
DC.maxpage = modeInfo.NumberOfImagePages;
}
_SV_pagesize = VBE_getPageSize(&modeInfo);
_SV_bankShift = 0;
while ((64 >> _SV_bankShift) != modeInfo.WinGranularity)
_SV_bankShift++;
/* If the controller is reported as NonVGA, then we must use the
* provided VBE 2.0 palette programming functions. Otherwise we
* can simply program the VGA palette registers directly.
*/
DC.isNonVGA = ((modeInfo.ModeAttributes & vbeMdNonVGA) != 0);
}
DC.curBank = -1;
/* Emulate RGB modes using a 3 3 2 palette arrangement by default */
DC.redMask = 0x7; DC.redPos = 5; DC.redAdjust = 5;
DC.greenMask = 0x7; DC.greenPos = 2; DC.greenAdjust = 5;
DC.blueMask = 0x3; DC.bluePos = 0; DC.blueAdjust = 6;
if (imode != 0x13 && modeInfo.MemoryModel == vbeMemRGB) {
/* Save direct color info mask positions etc */
if ((mode & vbeLinearBuffer) && modeInfo.LinBytesPerScanLine != 0) {
/* VBE 2.1 extended linear mode color format information */
DC.redMask = (0xFF >> (DC.redAdjust = 8 - modeInfo.LinRedMaskSize));
DC.redPos = modeInfo.LinRedFieldPosition;
DC.greenMask = (0xFF >> (DC.greenAdjust = 8 - modeInfo.LinGreenMaskSize));
DC.greenPos = modeInfo.LinGreenFieldPosition;
DC.blueMask = (0xFF >> (DC.blueAdjust = 8 - modeInfo.LinBlueMaskSize));
DC.bluePos = modeInfo.LinBlueFieldPosition;
}
else {
/* Banked color format information */
DC.redMask = (0xFF >> (DC.redAdjust = 8 - modeInfo.RedMaskSize));
DC.redPos = modeInfo.RedFieldPosition;
DC.greenMask = (0xFF >> (DC.greenAdjust = 8 - modeInfo.GreenMaskSize));
DC.greenPos = modeInfo.GreenFieldPosition;
DC.blueMask = (0xFF >> (DC.blueAdjust = 8 - modeInfo.BlueMaskSize));
DC.bluePos = modeInfo.BlueFieldPosition;
}
}
/* Get pointer to video memory */
if (imode == 0x13) {
#ifdef __WIN386__
ushort sel = PM_createSelector(0xA0000L,0xFFFF);
if (!sel) {
SV_restoreMode();
exit(1);
}
DC.videoMem = (void*)((ulong)sel << 16);
#else
if ((DC.videoMem = PM_mapPhysicalAddr(0xA0000L,0xFFFF)) == NULL) {
SV_restoreMode();
exit(1);
}
#endif
}
else {
if ((DC.videoMem = VBE_getBankedPointer(&modeInfo)) == NULL) {
SV_restoreMode();
exit(1);
}
}
DC.virtualBuffer = false;
DC.setActivePage = _SV_setActivePage;
DC.setVisualPage = _SV_setVisualPage;
#ifdef USE_VBE20
VBE_freePMCode();
_SV_setBank20 = VBE_getSetBank();
_SV_setCRT20 = VBE_getSetDisplayStart();
_SV_setPal20 = VBE_getSetPalette();
if ((mode & vbeLinearBuffer) && imode != 0x13) {
#ifdef PM386
if ((DC.videoMem = VBE_getLinearPointer(&modeInfo)) == NULL) {
SV_restoreMode();
exit(1);
}
#else
uint videoSel = VBE_getLinearSelector(&modeInfo);
if (!videoSel) {
SV_restoreMode();
exit(1);
}
DC.videoMem = MK_FP(videoSel,0);
#endif
DC.setActivePage = _SV_setActivePageLin;
}
else if (DC.haveVirtualBuffer && useVirtualBuffer && DC.bitsperpixel > 4) {
/* See if we can use the VFlat virtual linear framebuffer. This
* does however require VBE 2.0 and the virtual flat linear
* framebuffer device support.
*/
void *bankFunc,*p;
int codeLen;
VBE_getBankFunc32(&codeLen,&bankFunc,0,_SV_bankShift);
VF_exit();
if ((p = VF_init((ulong)modeInfo.WinASegment << 4,modeInfo.WinSize,
codeLen,bankFunc)) != NULL) {
DC.videoMem = p;
DC.setActivePage = _SV_setActivePageLin;
DC.virtualBuffer = true;
mode |= vbeLinearBuffer;
}
}
#endif
/* Set up a pointer to the appopriate bank switching code to use */
_SV_setBankPtr = (void*)SV_nop;
if (imode != 0x13) {
if ((modeInfo.WinAAttributes & 0x7) != 0x7) {
#ifdef USE_VBE20
if (_SV_setBank20) {
if (VBE_MMIOSel)
_SV_setBankPtr = _VBE20_setBankAB_ES;
else
_SV_setBankPtr = _VBE20_setBankAB;
}
else
#endif
_SV_setBankPtr = _VBE_setBankAB;
}
else {
#ifdef USE_VBE20
if (_SV_setBank20) {
if (VBE_MMIOSel)
_SV_setBankPtr = _VBE20_setBankA_ES;
else
_SV_setBankPtr = _VBE20_setBankA;
}
else
#endif
_SV_setBankPtr = _VBE_setBankA;
}
#ifdef REALMODE
_SV_setBankRM = (void *)modeInfo.WinFuncPtr;
#else
_SV_setBankRM = NULL;
#endif
}
/* Now set up the vectors to the correct routines for the video
* mode type.
*/
switch (DC.bitsperpixel) {
case 4:
DC.clear = _SV_clear16;
DC.putPixel = _SV_putPixel16;
DC.line = _SV_line16;
DC.maxcolor = DC.defcolor = 15;
DC.bytesperpixel = 1;
break;
case 8:
DC.clear = _SV_clear256;
DC.putPixel = _SV_putPixel256;
DC.line = _SV_line256;
DC.maxcolor = 255;
DC.defcolor = 15;
DC.bytesperpixel = 1;
#ifdef USE_VBE20
if (mode & vbeLinearBuffer) {
DC.clear = _SV_clear256Lin;
DC.putPixel = _SV_putPixel256Lin;
DC.line = _SV_line256Lin;
}
#endif
break;
case 15:
case 16:
DC.clear = _SV_clear32k;
DC.putPixel = _SV_putPixel32k;
DC.line = _SV_line32k;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 2;
#ifdef USE_VBE20
if (mode & vbeLinearBuffer) {
DC.clear = _SV_clear32kLin;
DC.putPixel = _SV_putPixel32kLin;
DC.line = _SV_line32kLin;
}
#endif
break;
case 24:
DC.clear = _SV_clear16m;
DC.putPixel = _SV_putPixel16m;
DC.line = _SV_line16m;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 3;
#ifdef USE_VBE20
if (mode & vbeLinearBuffer) {
DC.clear = _SV_clear16mLin;
DC.putPixel = _SV_putPixel16mLin;
DC.line = _SV_line16mLin;
}
#endif
break;
case 32:
DC.clear = _SV_clear4G;
DC.putPixel = _SV_putPixel4G;
DC.line = _SV_line4G;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 4;
#ifdef USE_VBE20
if (mode & vbeLinearBuffer) {
DC.clear = _SV_clear4GLin;
DC.putPixel = _SV_putPixel4GLin;
DC.line = _SV_line4GLin;
}
#endif
break;
}
DC.beginDirectAccess = (void*)SV_nop;
DC.endDirectAccess = (void*)SV_nop;
DC.beginPixel = (void*)SV_nop;
DC.putPixelFast = DC.putPixel;
DC.endPixel = (void*)SV_nop;
DC.beginLine = (void*)SV_nop;
DC.lineFast = DC.line;
DC.endLine = (void*)SV_nop;
PM_saveDS();
if (DC.bitsperpixel == 8) {
/* Program the default VGA palette */
_SV_convertPal = true;
if (use8BitDAC && VBE_setDACWidth(8))
_SV_convertPal = false;
if (setPalette)
SV_setPalette(0,256,VGA8_defPal,-1);
else {
SV_palette tmp[256];
memset(tmp,0,sizeof(tmp));
SV_setPalette(0,256,tmp,-1);
}
}
DC.setActivePage(0);
DC.setVisualPage(0,false);
if ((mode & svDontClear) == 0)
SV_clear(0);
return true;
}
#ifdef USE_VBEAF
PRIVATE bool SetModeAF(ushort mode,int virtualX,int virtualY,
bool useVirtualBuffer,int numBuffers,bool setPalette)
/****************************************************************************
*
* Function: SetModeAF
* Parameters: mode - SuperVGA video mode to set.
* Returns: True if the mode was set, false if not.
*
* Description:
*
****************************************************************************/
{
AF_modeInfo modeInfo;
AF_int32 bpl = -1;
int cntMode,imode = mode & svModeMask;
RMREGS regs;
/* Grab information about the current video mode */
if (imode < 0x100)
return false;
regs.h.ah = 0x0F;
PM_int86(0x10,®s,®s);
cntMode = regs.h.al & 0x7F;
if (imode != cntMode && cntMode <= 3) {
_SV_old50Lines = false; /* Default to 25 line mode */
if (cntMode == 0x3) {
regs.x.ax = 0x1130;
regs.x.bx = 0;
regs.x.dx = 0;
PM_int86(0x10,®s,®s);
_SV_old50Lines = (regs.h.dl == 49);
}
}
/* Turn off the double buffer flag if the user requested double
* buffering but only one pages is available. If we dont do this, the
* VBE/AF mode set code will fail the mode set.
*/
AF_getVideoModeInfo(DC.AFDC,imode,&modeInfo);
if (!(modeInfo.Attributes & afHaveMultiBuffer))
mode &= ~svMultiBuffer;
/* Set the video mode - note that we dont clear the video memory as
* we need to save and restore the video memory if we are running
* under Windows to fix problems with buggy Windows drivers that cache
* bitmaps in offscreen memory, but dont bother to save/restore them
* across a DOS box.
*/
if (mode & afVirtualScroll) {
if (AF_setVirtualVideoMode(DC.AFDC,mode,virtualX,virtualY,&bpl,
numBuffers) != 0)
return false;
}
else {
if (AF_setVideoMode(DC.AFDC,mode,&bpl,numBuffers) != 0)
return false;
}
/* Initialise global variables for current video mode dimensions */
DC.bytesperline = bpl;
DC.maxx = DC.AFDC->BufferEndX;
DC.maxy = DC.AFDC->BufferEndY;
DC.bitsperpixel = modeInfo.BitsPerPixel;
if (modeInfo.LinBytesPerScanLine != 0) {
if (mode & vbeLinearBuffer)
DC.maxpage = modeInfo.LinMaxBuffers-1;
else
DC.maxpage = modeInfo.BnkMaxBuffers-1;
}
else {
DC.maxpage = modeInfo.MaxBuffers-1;
}
_SV_pagesize = 0;
_SV_bankShift = 0;
DC.curBank = -1;
/* Save direct color info mask positions etc. We emulate 8 bit RGB modes
* using a 3 3 2 palette arrangement by default
*/
DC.redMask = 0x7; DC.redPos = 5; DC.redAdjust = 5;
DC.greenMask = 0x7; DC.greenPos = 2; DC.greenAdjust = 5;
DC.blueMask = 0x3; DC.bluePos = 0; DC.blueAdjust = 6;
if (DC.bitsperpixel > 8) {
if ((mode & vbeLinearBuffer) && modeInfo.LinBytesPerScanLine != 0) {
DC.redMask = (0xFF >> (DC.redAdjust = 8 - modeInfo.LinRedMaskSize));
DC.redPos = modeInfo.LinRedFieldPosition;
DC.greenMask = (0xFF >> (DC.greenAdjust = 8 - modeInfo.LinGreenMaskSize));
DC.greenPos = modeInfo.LinGreenFieldPosition;
DC.blueMask = (0xFF >> (DC.blueAdjust = 8 - modeInfo.LinBlueMaskSize));
DC.bluePos = modeInfo.LinBlueFieldPosition;
}
else {
DC.redMask = (0xFF >> (DC.redAdjust = 8 - modeInfo.RedMaskSize));
DC.redPos = modeInfo.RedFieldPosition;
DC.greenMask = (0xFF >> (DC.greenAdjust = 8 - modeInfo.GreenMaskSize));
DC.greenPos = modeInfo.GreenFieldPosition;
DC.blueMask = (0xFF >> (DC.blueAdjust = 8 - modeInfo.BlueMaskSize));
DC.bluePos = modeInfo.BlueFieldPosition;
}
}
/* Set up a pointer to the appopriate bank switching code to use */
DC.virtualBuffer = false;
_SV_setBankPtr = _VBEAF_setBank;
DC.videoMem = DC.AFDC->BankedMem;
DC.setActivePage = _SV_setActivePageAF;
DC.setVisualPage = _SV_setVisualPageAF;
if (mode & svLinearBuffer) {
DC.videoMem = DC.AFDC->LinearMem;
DC.setActivePage = _SV_setActivePageLinAF;
}
else if (DC.haveVirtualBuffer && useVirtualBuffer && DC.AFDC->SetBank32) {
/* See if we can use the VFlat virtual linear framebuffer */
void *bankFunc,*p;
int codeLen;
AF_getBankFunc32(DC.AFDC,&codeLen,&bankFunc);
VF_exit();
if ((p = VF_init(DC.AFDC->BankedBasePtr,DC.AFDC->BankSize,
codeLen,bankFunc)) != NULL) {
DC.videoMem = p;
DC.setActivePage = _SV_setActivePageLinAF;
DC.virtualBuffer = true;
mode |= svLinearBuffer;
}
}
/* Now set up the vectors to the correct routines for the video
* mode type.
*/
switch (DC.bitsperpixel) {
case 8:
DC.clear = _SV_clear256;
DC.putPixel = _SV_putPixel256;
DC.line = _SV_line256;
DC.maxcolor = 255;
DC.defcolor = 15;
DC.bytesperpixel = 1;
if (mode & svLinearBuffer) {
DC.clear = _SV_clear256Lin;
DC.putPixel = _SV_putPixel256Lin;
DC.line = _SV_line256Lin;
}
break;
case 15:
case 16:
DC.clear = _SV_clear32k;
DC.putPixel = _SV_putPixel32k;
DC.line = _SV_line32k;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 2;
if (mode & svLinearBuffer) {
DC.clear = _SV_clear32kLin;
DC.putPixel = _SV_putPixel32kLin;
DC.line = _SV_line32kLin;
}
break;
case 24:
DC.clear = _SV_clear16m;
DC.putPixel = _SV_putPixel16m;
DC.line = _SV_line16m;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 3;
if (mode & svLinearBuffer) {
DC.clear = _SV_clear16mLin;
DC.putPixel = _SV_putPixel16mLin;
DC.line = _SV_line16mLin;
}
break;
case 32:
DC.clear = _SV_clear4G;
DC.putPixel = _SV_putPixel4G;
DC.line = _SV_line4G;
DC.maxcolor = DC.defcolor = SV_rgbColor(0xFF,0xFF,0xFF);
DC.bytesperpixel = 4;
if (mode & svLinearBuffer) {
DC.clear = _SV_clear4GLin;
DC.putPixel = _SV_putPixel4GLin;
DC.line = _SV_line4GLin;
}
break;
}
/* Setup support for accelerator functions if we have these. Note that
* we transparently support acceleration of screen clearing and line
* drawing functions only. You can call the VBE/AF function to draw
* other primitives directly but we dont have software emulation for
* the routines if they are not available in hardware.
*/
DC.beginDirectAccess = (void*)SV_nop;
DC.endDirectAccess = (void*)SV_nop;
DC.beginPixel = (void*)SV_nop;
DC.putPixelFast = DC.putPixel;
DC.endPixel = (void*)SV_nop;
DC.beginLine = (void*)SV_nop;
DC.lineFast = DC.line;
DC.endLine = (void*)SV_nop;
if (modeInfo.Attributes & afHaveAccel2D) {
if (DC.AFDC->EnableDirectAccess) {
DC.beginDirectAccess = _SV_beginDirectAccessAFSLOW;
DC.endDirectAccess = _SV_endDirectAccessAFSLOW;
DC.beginPixel = _SV_beginPixelAFSLOW;
DC.endPixel = _SV_endPixelAFSLOW;
DC.beginLine = _SV_beginLineAFSLOW;
DC.endLine = _SV_endLineAFSLOW;
}
else {
DC.beginDirectAccess = _SV_beginDirectAccessAF;
DC.endDirectAccess = _SV_endDirectAccessAF;
DC.beginPixel = _SV_beginPixelAF;
DC.endPixel = _SV_endPixelAF;
DC.beginLine = _SV_beginLineAF;
DC.endLine = _SV_endLineAF;
}
DC.clear = _SV_clearAF;
DC.putPixel = _SV_putPixelAF;
#if 0
if (DC.AFDC->DrawLine) {
/* Accelerated line drawing */
DC.beginLine = (void*)SV_nop;
DC.line = _SV_lineFastAF;
DC.lineFast = _SV_lineFastAF;
DC.endLine = (void*)SV_nop;
}
else {
#endif
/* Software line drawing */
DC.line = _SV_softLineAF;
// }
/* Set default mix */
AF_setMix(DC.AFDC,AF_REPLACE_MIX,AF_REPLACE_MIX);
}
PM_saveDS();
if (DC.bitsperpixel == 8) {
/* Program the default VGA palette. Note that VBE/AF always takes
* palette values in 8 bits per pixel format.
*/
_SV_convertPal = false;
if (setPalette)
SV_setPalette(0,256,VGA8_defPal,-1);
else {
SV_palette tmp[256];
memset(tmp,0,sizeof(tmp));
SV_setPalette(0,256,tmp,-1);
}
}
DC.setActivePage(0);
DC.setVisualPage(0,false);
if ((mode & svDontClear) == 0)
SV_clear(0);
return true;
}
void SVAPI SV_setACCELDriver(AF_devCtx *driver)
{
loadedDC = driver;
}
#endif
#if defined(SAFE_MODE) || defined(__WINDOWS__)
/* The following Safe Mode can be enabled to save/restore the entire
* video memory to disk before the video mode is started. This can solve
* some problems with Windows drivers for code running in a DOS box or
* in a WinDirect Window. This does however cause a significant slowdown
* in the code, which is why it is currently only enabled for Windows
* apps when the safe mode option of WinDirect is on.
*/
PRIVATE int saveMode;
PRIVATE char saveMemName[_MAX_PATH] = "";
PRIVATE void backslash(char *s)
{
uint pos = strlen(s);
if (s[pos-1] != '\\') {
s[pos] = '\\';
s[pos+1] = '\0';
}
}
PRIVATE void SaveVideoMemory(int mode)
/****************************************************************************
*
* Function: SaveVideoMemory
*
* Description: Starts a 640x480x256 color graphics mode and streams all
* video memory to a tempory disk file. This is necessary so
* we can restore the video memory back to the state it was
* in originally to avoid problems with buggy Windows drivers
* that cache bitmaps in offscreen video memory but do not
* correctly restore the memory when a DOS box or WinDirect
* application returns to GDI mode.
*
* If we are starting a banked video mode, we start a banked
* version of 640x480x256 and save the memory with that. For
* linear modes we start the linear version instead.
*
****************************************************************************/
{
ulong size;
bool fail = false;
FILE *f;
if (saveMemName[0] != 0)
return;
#ifndef __WINDOWS__
/* Dont bother to save/restore video memory when running under real DOS,
* only under Windows DOS boxes.
*/
{
RMREGS regs;
regs.x.ax = 0x160A;
PM_int86(0x2F,®s,®s);
if (regs.x.ax != 0)
return;
}
#else
if (!WD_isSafeMode())
return;
#endif
saveMode = 0x101 | (mode & svLinearBuffer) | svDontClear;
#ifdef USE_VBEAF
if (DC.AFDC) {
if (!SetModeAF(saveMode,-1,-1,false,1,false))
return;
}
else
#endif
if (!SetModeVBE(saveMode,false,false,false))
return;
/* Open a temporary file to save the video memory to */
if (getenv("TEMP"))
strcpy(saveMemName,getenv("TEMP"));
else if (getenv("TMP"))
strcpy(saveMemName,getenv("TEMP"));
else
strcpy(saveMemName,"c:\\");
backslash(saveMemName);
strcat(saveMemName,tmpnam(NULL));
if ((f = fopen(saveMemName,"wb")) == NULL)
return;
/* Save entire video memory in chunks of 32Kb at a time except under
* 32 bit protecetd mode with a linear framebuffer in which case we
* can save it directly as a single block.
*/
#ifdef PM386
if (saveMode & svLinearBuffer) {
size = DC.memory * 1024L;
if (fwrite(DC.videoMem,1,size,f) != size)
fail = true;
}
else
#endif
{
#ifndef __WIN386__
int i,maxBlocks = DC.memory / 64;
size = 0x8000;
for (i = 0; i < maxBlocks; i++) {
SV_setBank(i >> 1);
if ((i & 1) == 0) {
if (fwrite((uchar*)DC.videoMem,1,size,f) != size) {
fail = true;
break;
}
}
else {
if (fwrite((uchar*)DC.videoMem + size,1,size,f) != size) {
fail = true;
break;
}
}
}
#endif
}
fclose(f);
if (fail) {
unlink(saveMemName);
saveMemName[0] = 0;
}
}
PRIVATE void RestoreVideoMemory(void)
/****************************************************************************
*
* Function: RestoreVideoMemory
*
* Description: Restores the video memory from the memory buffer or
* disk file after the mode has been reset to correctly
* restore all cached bitmaps for Windows drivers.
*
****************************************************************************/
{
ulong size;
FILE *f;
if (saveMemName[0] == 0)
return;
#ifdef USE_VBEAF
if (DC.AFDC) {
if (!SetModeAF(saveMode,-1,-1,false,1,false))
return;
}
else
#endif
if (!SetModeVBE(saveMode,false,false,false))
return;
/* Open the temporary file to restore the video memory from */
if ((f = fopen(saveMemName,"rb")) == NULL)
return;
/* Restore entire video memory in chunks of 32Kb at a time except under
* 32 bit protecetd mode with a linear framebuffer in which case we
* can restore it directly as a single block.
*/
#ifdef PM386
if (saveMode & svLinearBuffer) {
size = DC.memory * 1024L;
fread(DC.videoMem,1,size,f);
}
else
#endif
{
#ifndef __WIN386__
int i,maxBlocks = DC.memory / 64;
size = 0x8000;
for (i = 0; i < maxBlocks; i++) {
SV_setBank(i >> 1);
if ((i & 1) == 0)
fread((uchar*)DC.videoMem,1,size,f);
else
fread((uchar*)DC.videoMem + size,1,size,f);
}
#endif
}
fclose(f);
unlink(saveMemName);
saveMemName[0] = 0;
}
#else
#define SaveVideoMemory(m)
#define RestoreVideoMemory()
#endif
PUBLIC bool SVAPI SV_setMode(ushort mode,bool use8BitDAC,
bool useVirtualBuffer,bool numBuffers)
/****************************************************************************
*
* Function: SV_setMode
* Parameters: mode - SuperVGA video mode to set.
* use8BitDAC - Turn on 8 bit DAC mode (for VBE modes only)
* useVirtualBuffer - True to use virtual linear buffer
* numBuffers - Number of image buffers to use
* Returns: True if the mode was set, false if not.
*
* Description: Attempts to set the specified video mode. This routine
* assumes that the library and SuperVGA have been initialised
* with the SV_init() routine first.
*
* If the use8BitDAC flag is set, the 8 bit DAC mode will be
* use for VBE graphics modes. For VBE/AF the 8 bit DAC mode
* is used automatically if it is available, so this flag is
* ignored.
*
****************************************************************************/
{
SV_modeInfo mi;
if (!SV_getModeInfo(mode & svModeMask,&mi))
return false;
#ifdef __WINDOWS__
WD_startFullScreen(hwndMain,mi.XResolution,mi.YResolution);
#else
WD_startFullScreen(NULL,mi.XResolution,mi.YResolution);
#endif
SaveVideoMemory(mode);
#ifdef USE_VBEAF
if (DC.AFDC) {
if (!SetModeAF(mode,-1,-1,useVirtualBuffer,numBuffers,true))
return false;
}
else
#endif
{
if (!SetModeVBE(mode &= ~svMultiBuffer,use8BitDAC,useVirtualBuffer,true))
return false;
}
WD_inFullScreen();
return true;
}
PUBLIC bool SVAPI SV_setVirtualMode(ushort mode,int virtualX,int virtualY,
bool use8BitDAC,bool useVirtualBuffer,int numBuffers)
/****************************************************************************
*
* Function: SV_setVirtualMode
* Parameters: mode - SuperVGA video mode to set.
* virtualX - Virtual screen X coordinate
* virtualY - Virtual screen Y coordinate
* Returns: True if the mode was set, false if not.
*
* Description: Attempts to set the specified video mode with virtual
* scrolling enabled for the specified dimensions. If virtual
* scrolling cannot be obtained correctly for this mode,
* we return false.
*
****************************************************************************/
{
int newbytes;
SV_modeInfo mi;
if (!SV_getModeInfo(mode & svModeMask,&mi))
return false;
#ifdef __WINDOWS__
WD_startFullScreen(hwndMain,mi.XResolution,mi.YResolution);
#else
WD_startFullScreen(NULL,mi.XResolution,mi.YResolution);
#endif
SaveVideoMemory(mode);
#ifdef USE_VBEAF
if (DC.AFDC) {
return SetModeAF(mode | afVirtualScroll,virtualX,virtualY,
useVirtualBuffer,numBuffers,true);
}
else
#endif
{
if (!SetModeVBE(mode,use8BitDAC,useVirtualBuffer,true))
return false;
if (!VBE_setPixelsPerLine(virtualX,&newbytes,&virtualX,&virtualY)) {
SV_restoreMode();
return false;
}
}
DC.bytesperline = newbytes;
DC.maxx = virtualX-1;
DC.maxy = virtualY-1;
return true;
}
PUBLIC void SVAPI SV_restoreMode(void)
/****************************************************************************
*
* Function: SV_restoreMode
*
* Description: Restore the previous video mode in use before the SuperVGA
* mode was set. This routine will also restore the 50 line
* display mode if this mode was previously set.
*
****************************************************************************/
{
RMREGS regs;
RestoreVideoMemory();
#ifdef USE_VBE20
VF_exit();
VBE_freePMCode(); /* Free up protected mode code */
#endif
#ifdef USE_VBEAF
if (DC.AFDC)
AF_restoreTextMode(DC.AFDC);
else
#endif
VBE_setVideoMode(0x3); /* Reset to text mode */
if (_SV_old50Lines) {
regs.x.ax = 0x1112;
regs.x.bx = 0;
PM_int86(0x10,®s,®s); /* Restore 50 line mode */
}
WD_restoreGDI();
}
PUBLIC void SVAPI SV_setPalette(int start,int num,SV_palette *pal,int maxProg)
/****************************************************************************
*
* Function: SV_setPalette
* Parameters: start - Starting palette index to program
* num - Number of palette indexes to program
* pal - Palette buffer containing values
* waitVRT - Wait for vertical retrace flag
* Returns: True on success, false on failure
*
* Description: Sets the palette by interleaving blocks of values with
* the vertical retrace interval. We use the VBE 2.0 palette
* interface routines if possible, and have a VGA style
* routine for VBE 1.2 implementations.
*
* Note that this routine *requires* all input palette values
* to be in 8 bits per primary format, and does automatic
* conversion from 8 bits per primary formay to the 6 bit
* format required by some cards if necessary.
*
****************************************************************************/
{
int i,waitFlag,count;
uchar temp[1024],*t,*p = (uchar*)&pal[start];
/* First copy the palette values into our temporary palette,
* translating from the internal 8 bit format to the VGA 6 bit
* format (if we have a wide palette, then we simply skip this step)
*/
if (_SV_convertPal) {
for (i = 0,t = temp; i < num; i++) {
*t++ = *p++ >> 2;
*t++ = *p++ >> 2;
*t++ = *p++ >> 2;
t++; p++;
}
p = temp;
}
/* Determine if we need to wait for the vertical retrace */
if (maxProg == -1) {
waitFlag = 0x00;
count = num;
}
else {
waitFlag = 0x80;
count = (num > maxProg) ? maxProg : num;
}
while (num) {
#ifdef USE_VBEAF
if (DC.AFDC)
AF_setPaletteData(DC.AFDC,(AF_palette*)p,count,start,waitFlag == 0x80);
else
#endif
if (!DC.isNonVGA)
_VGA_setPalette(start,count,(SV_palette*)p,waitFlag);
#ifdef USE_VBE20
else if (_SV_setPal20)
_VBE20_setPalette(start,count,(SV_palette*)p,waitFlag);
#endif
else
VBE_setPalette(start,count,(VBE_palette*)p,waitFlag);
start += count;
p += count;
num -= count;
count = (num > maxProg) ? maxProg : num;
}
}
PUBLIC ulong SVAPI SV_rgbColor(uchar r,uchar g,uchar b)
/****************************************************************************
*
* Function: rgbColor
*
* Returns: Value representing the color. The value is converted from
* 24 bit RGB space into the appropriate color for the
* video mode.
*
****************************************************************************/
{
return ((ulong)((r >> DC.redAdjust) & DC.redMask) << DC.redPos)
| ((ulong)((g >> DC.greenAdjust) & DC.greenMask) << DC.greenPos)
| ((ulong)((b >> DC.blueAdjust) & DC.blueMask) << DC.bluePos);
}
PUBLIC void SVAPI SV_writeText(int x,int y,char *str,ulong color)
/****************************************************************************
*
* Function: writeText
* Parameters: x,y - Position to begin drawing string at
* str - String to draw
*
* Description: Draws a string using the BIOS 8x16 video font by plotting
* each pixel in the characters individually. This should
* work for all video modes.
*
****************************************************************************/
{
uchar byte;
int i,j,k,length,ch;
uchar *font;
font = font8x16;
length = strlen(str);
DC.beginPixel();
for (k = 0; k < length; k++) {
ch = str[k];
for (j = 0; j < 16; j++) {
byte = *(font + ch * 16 + j);
for (i = 0; i < 8; i++) {
if ((byte & 0x80) != 0)
DC.putPixelFast(x+i,y+j,color);
byte <<= 1;
}
}
x += 8;
}
DC.endPixel();
}
void SVAPI SV_setDisplayStart(int x,int y,bool waitVRT)
/****************************************************************************
*
* Function: SV_setDisplayStart
* Parameters: x,y - Position of the first pixel to display
*
* Description: Sets the new starting display position to implement
* hardware scrolling.
*
****************************************************************************/
{
#ifdef USE_VBEAF
if (DC.AFDC)
AF_setDisplayStart(DC.AFDC,x,y,waitVRT);
else
#endif
VBE_setDisplayStart(x,y,waitVRT);
}
#ifdef USE_VBEAF
PUBLIC void _ASMAPI _SV_setActivePageAF(int page)
{
ulong addr;
/* Set active buffer and update internal pointers */
AF_setActiveBuffer(DC.AFDC,page);
addr = DC.AFDC->OriginOffset;
DC.originOffset = (ushort)addr;
SV_setBank(DC.bankOffset = (addr >> 16));
/* Set hardware clip rectangle to new active page */
if (DC.AFDC->SetClipRect)
AF_setClipRect(DC.AFDC,0,0,DC.maxx,DC.maxy);
}
PUBLIC void _ASMAPI _SV_setActivePageLinAF(int page)
{
/* Set active buffer and update internal pointers */
AF_setActiveBuffer(DC.AFDC,page);
DC.originOffset = (ulong)DC.videoMem + DC.AFDC->OriginOffset;
/* Set hardware clip rectangle to new active page */
if (DC.AFDC->SetClipRect)
AF_setClipRect(DC.AFDC,0,0,DC.maxx,DC.maxy);
}
PUBLIC void _ASMAPI _SV_setVisualPageAF(int page,bool waitVRT)
{
AF_setVisibleBuffer(DC.AFDC,page,waitVRT);
}
PUBLIC void _ASMAPI _SV_clearAF(ulong color)
{
AF_drawRect(DC.AFDC,color,0,0,DC.maxx+1,DC.maxy+1);
}
PUBLIC void _ASMAPI _SV_putPixelAF(int x,int y,ulong color)
{
DC.beginPixel();
DC.putPixelFast(x,y,color);
DC.endPixel();
}
PUBLIC void _ASMAPI _SV_softLineAF(int x1,int y1,int x2,int y2,ulong color)
{
DC.beginLine();
DC.lineFast(x1,y1,x2,y2,color);
DC.endLine();
}
#endif
#ifdef __WINDOWS16__
/* Windows specific stubs to handle different calling conventions for
* 16 bit DLL's. We export all functions as pascal calling conventions,
* and we do an internal thunk to the C calling conventions that we
* require internally.
*/
void _ASMAPI _SV_setBank(int bank);
int _ASMAPI _SV_queryCpu(void);
void SVAPI SV_setBank(int bank)
{ _SV_setBank(bank); }
int SVAPI SV_queryCpu(void)
{ return _SV_queryCpu(); }
void SVAPI SV_beginPixel(void)
{ DC.beginPixel(); }
void SVAPI SV_putPixel(int x,int y,ulong color)
{ DC.putPixel(x,y,color); }
void SVAPI SV_putPixelFast(int x,int y,ulong color)
{ DC.putPixelFast(x,y,color); }
void SVAPI SV_endPixel(void)
{ DC.endPixel(); }
void SVAPI SV_clear(ulong color)
{ DC.clear(color); }
void SVAPI SV_line(int x1,int y1,int x2,int y2,ulong color)
{ DC.line(x1,y1,x2,y2,color); }
void SVAPI SV_beginLine(void)
{ DC.beginLine(); }
void SVAPI SV_lineFast(int x1,int y1,int x2,int y2,ulong color)
{ DC.lineFast(x1,y1,x2,y2,color); }
void SVAPI SV_endLine(void)
{ DC.endLine(); }
void SVAPI SV_setActivePage(int page)
{ DC.setActivePage(page); }
void SVAPI SV_setVisualPage(int page,bool waitVRT)
{ DC.setVisualPage(page,waitVRT); }
void SVAPI SV_beginDirectAccess(void)
{ DC.beginDirectAccess(); }
void SVAPI SV_endDirectAccess(void)
{ DC.endDirectAccess(); }
#endif
#ifdef __WINDOWS__
void SVAPI SV_setMainWindow(HWND hwnd)
{ hwndMain = hwnd; }
#endif