Input: AX=4F00h Return VBE controller information
ES:DI= Pointer to buffer in which to place
VbeInfoBlock structure.
(VbeSignature should be set to 'VBE2' when
function is called to indicate VBE 2.0
information is desired and the information
block is 512 bytes in size.)
Output*: AX= VBE return status
Input: AX=4F01h Return VBE mode information
CX= Mode number
ES:DI= Pointer to ModeInfoBlock structure
Output*: AX= VBE return status
Input: AX=4F02h Set VBE mode
BX= Desired mode to set
D0-D8= Mode number
D9-D13= Reserved (must be 0)
D14=0 Use windowed frame buffer model
=1 Use linear/flat frame buffer model
D15=0 Clear display memory
=1 Don't clear display memory
Output*: AX= VBE return status
Input: AX=4F03h Return current VBE mode
Output*: AX= VBE Return Status
BX= Current VBE mode
D0-D13= Mode number
D14=0 Windowed frame buffer model
=1 Linear/flat frame buffer model
D15=0 Memory cleared at last mode set
=1 Memory not cleared at last mode set
Input: AX=4F04h Save/restore state
DL=00h Return save/restore state buffer size
=01h Save state
=02h Restore state
CX= Requested states
D0= Save/Restore controller hardware state
D1= Save/Restore BIOS data state
D2= Save/Restore DAC state
D3= Save/Restore Register state
ES:BX= Pointer to buffer (if DL <> 00h)
Output*: AX= VBE return status
BX= Number of 64-byte blocks to hold the state
buffer (if DL= 00h)
Input: AX=4F05h VBE display-window control
BH=00h Set memory window
=01h Get memory window
BL= Window number
=00h Window A
=01h Window B
DX= Window number in video memory in
window-granularity units (set memory
window only)
Output: AX= VBE return status
DX= Window number in window-granularity units
Input: AX=4F06h VBE set/get logical scan-line length
BL=00h Set scan-line length in pixels
=01h Get scan-line length
=02h Set scan-line length in bytes
=03h Get maximum scan-line length
CX= If BL=00h desired width in pixels
If BL=02h desired width in bytes (ignored
for get functions)
Output: AX= VBE return status
BX= Bytes per scan line
CX= Actual pixels/scan line (truncated to
nearest complete pixel)
DX= Maximum number of scan lines
Input: AX=4F07h VBE set/get display start control
BH=00h Reserved and must be 00h
BL=00h Set display start
=01h Get display start
=80h Set display start during vertical retrace
CX= First displayed pixel in scan line (set
display start only)
DX= First displayed scan line (set display
start only)
Output: AX= VBE return status
BH= 00h reserved and will be 0 (get display
start only)
CX= First displayed pixel in scan line (get
display start only)
DX= First displayed scan line (get display
start only)
Input: AX=4F08h VBE set/get palette format
BL=00h Set DAC palette format
=01h Get DAC palette format
BH= Desired bits of color per primary (set
DAC palette format only)
Output: AX= VBE return status
BH= Current number of bits of color per primary
Input: AX=4F09h VBE load/unload palette data
BL=00h Set palette data
=01h Get palette data
=02h Set secondary palette data
=03h Get secondary palette data
=80h Set palette data during vertical retrace
with blank bit on
CX= Number of palette registers to update
DX= First palette register to update
ES:DI= Table of palette values (see below for format)
Output: AX= VBE return status
Format of Alignment byte, red byte, green byte,
palette values: blue byte
Input: AX=4F0Ah VBE 2.0 protected-mode interface
BL=00h Return protected-mode table
Output: AX= Status
ES= Real-mode segment of table
DI= Offset of table
CX= Length of table, including protected-mode
code in bytes (for copying purposes)
*All other registers are preserved.
/****************************************************************************
* Hello VBE!
* Language: C (Keyword far is by definition not ANSI, therefore to make it true
* ANSI remove all far references and compile under MEDIUM model.)
* Environment: IBM PC (MSDOS) 16 bit Real Mode
* Original code contributed by: - Kendall Bennett, SciTech Software
* Conversion to Microsoft C by: - Rex Wolfe, Western Digital Imaging
* - George Bystricky, S-MOS Systems
* Description: Simple 'Hello World' program to initialize a user-specified
* 256-color graphics mode, and display a simple moire pattern. Tested with
* VBE 1.2 and above. This code does not have any hard-coded VBE mode
* numbers, but will use the VBE 2.0 aware method of searching for available
* video modes, so will work with any new extended video modes defined by a
* particular OEM VBE 2.0 version. For brevity, we don't check for failure
* conditions returned by the VBE (but we shouldn't get any).
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
/* Comment out the following #define to disable direct bank switching.
* The code will then use Int 10h software interrupt method for banking. */
#define DIRECT_BANKING
#ifdef DIRECT_BANKING
/* only needed to setup registers BX,DX prior to the direct call.. */
extern far setbxdx(int, int);
#endif
/*---------------------- Macro and type definitions -----------------------*/
/* SuperVGA information block */
struct
{
char VESASignature[4]; /* 'VESA' 4 byte signature */
short VESAVersion; /* VBE version number */
char far *OEMStringPtr; /* Pointer to OEM string */
long Capabilities; /* Capabilities of video card */
unsigned far *VideoModePtr; /* Pointer to supported modes */
short TotalMemory; /* Number of 64kb memory blocks */
char reserved[236]; /* Pad to 256 byte block size */
} VbeInfoBlock;
/* SuperVGA mode information block */
struct
{
unsigned short ModeAttributes; /* Mode attributes */
unsigned char WinAAttributes; /* Window A attributes */
unsigned char WinBAttributes; /* Window B attributes */
unsigned short WinGranularity; /* Window granularity in k */
unsigned short WinSize; /* Window size in k */
unsigned short WinASegment; /* Window A segment */
unsigned short WinBSegment; /* Window B segment */
void (far *WinFuncPtr)(void); /* Pointer to window function */
unsigned short BytesPerScanLine; /* Bytes per scanline */
unsigned short XResolution; /* Horizontal resolution */
unsigned short YResolution; /* Vertical resolution */
unsigned char XCharSize; /* Character cell width */
unsigned char YCharSize; /* Character cell height */
unsigned char NumberOfPlanes; /* Number of memory planes */
unsigned char BitsPerPixel; /* Bits per pixel */
unsigned char NumberOfBanks; /* Number of CGA style banks */
unsigned char MemoryModel; /* Memory model type */
unsigned char BankSize; /* Size of CGA style banks */
unsigned char NumberOfImagePages; /* Number of images pages */
unsigned char res1; /* Reserved */
unsigned char RedMaskSize; /* Size of direct color red mask */
unsigned char RedFieldPosition; /* Bit posn of lsb of red mask */
unsigned char GreenMaskSize; /* Size of direct color green mask */
unsigned char GreenFieldPosition; /* Bit posn of lsb of green mask */
unsigned char BlueMaskSize; /* Size of direct color blue mask */
unsigned char BlueFieldPosition; /* Bit posn of lsb of blue mask */
unsigned char RsvdMaskSize; /* Size of direct color res mask */
unsigned char RsvdFieldPosition; /* Bit posn of lsb of res mask */
unsigned char DirectColorModeInfo; /* Direct color mode attributes */
unsigned char res2[216]; /* Pad to 256 byte block size */
} ModeInfoBlock;
typedef enum
{
memPL = 3, /* Planar memory model */
memPK = 4, /* Packed pixel memory model */
memRGB = 6, /* Direct color RGB memory model */
memYUV = 7, /* Direct color YUV memory model */
} memModels;
/*--------------------------- Global Variables ----------------------------*/
char mystr[256];
char *get_str();
int xres,yres; /* Resolution of video mode used */
int bytesperline; /* Logical CRT scanline length */
int curBank; /* Current read/write bank */
unsigned int bankShift; /* Bank granularity adjust factor */
int oldMode; /* Old video mode number */
char far *screenPtr; /* Pointer to start of video memory */
void (far *bankSwitch)(void); /* Direct bank switching function */
/*------------------------ VBE Interface Functions ------------------------*/
/* Get SuperVGA information, returning true if VBE found */
int getVbeInfo()
{
union REGS in,out;
struct SREGS segs;
char far *VbeInfo = (char far *)&VbeInfoBlock;
in.x.ax = 0x4F00;
in.x.di = FP_OFF(VbeInfo);
segs.es = FP_SEG(VbeInfo);
int86x(0x10, &in, &out, &segs);
return (out.x.ax == 0x4F);
}
/* Get video mode information given a VBE mode number. We return 0 if the mode
* is not available, or if it is not a 256 color packed pixel mode. */
int getModeInfo(int mode)
{
union REGS in,out;
struct SREGS segs;
char far *modeInfo = (char far *)&ModeInfoBlock;
if (mode < 0x100) return 0; /* Ignore non-VBE modes */
in.x.ax = 0x4F01;
in.x.cx = mode;
in.x.di = FP_OFF(modeInfo);
segs.es = FP_SEG(modeInfo);
int86x(0x10, &in, &out, &segs);
if (out.x.ax != 0x4F) return 0;
if ((ModeInfoBlock.ModeAttributes & 0x1)
&& ModeInfoBlock.MemoryModel == memPK
&& ModeInfoBlock.BitsPerPixel == 8
&& ModeInfoBlock.NumberOfPlanes == 1)
return 1;
return 0;
}
/* Set a VBE video mode */
void setVBEMode(int mode)
{
union REGS in,out;
in.x.ax = 0x4F02; in.x.bx = mode;
int86(0x10,&in,&out);
}
/* Return the current VBE video mode */
int getVBEMode(void)
{
union REGS in,out;
in.x.ax = 0x4F03;
int86(0x10,&in,&out);
return out.x.bx;
}
/* Set new read/write bank. Set both Window A and Window B, as many VBE's have
* these set as separately available read and write windows. We also use a
* simple (but very effective) optimization of checking if the requested bank
* is currently active. */
void setBank(int bank)
{
union REGS in,out;
if (bank == curBank) return; /* Bank is already active */
curBank = bank; /* Save current bank number */
bank <<= bankShift; /* Adjust to window granularity */
#ifdef DIRECT_BANKING
setbxdx(0,bank);
bankSwitch();
setbxdx(1,bank);
bankSwitch();
#else
in.x.ax = 0x4F05; in.x.bx = 0; in.x.dx = bank;
int86(0x10, &in, &out);
in.x.ax = 0x4F05; in.x.bx = 1; in.x.dx = bank;
int86(0x10, &in, &out);
#endif
}
/*-------------------------- Application Functions ------------------------*/
/* Plot a pixel at location (x,y) in specified color (8 bit modes only) */
void putPixel(int x,int y,int color)
{
long addr = (long)y * bytesperline + x;
setBank((int)(addr >> 16));
*(screenPtr + (addr & 0xFFFF)) = (char)color;
}
/* Draw a line from (x1,y1) to (x2,y2) in specified color */
void line(int x1,int y1,int x2,int y2,int color)
{
int d; /* Decision variable */
int dx,dy; /* Dx and Dy values for the line */
int Eincr,NEincr; /* Decision variable increments */
int yincr; /* Increment for y values */
int t; /* Counters etc. */
#define ABS(a) ((a) >= 0 ? (a) : -(a))
dx = ABS(x2 - x1);
dy = ABS(y2 - y1);
if (dy <= dx)
{
/* We have a line with a slope between -1 and 1. Ensure that we are
* always scan converting the line from left to right to ensure that
* we produce the same line from P1 to P0 as the line from P0 to P1. */
if (x2 < x1)
{
t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
}
if (y2 > y1)
yincr = 1;
else
yincr = -1;
d = 2*dy - dx; /* Initial decision variable value */
Eincr = 2*dy; /* Increment to move to E pixel */
NEincr = 2*(dy - dx); /* Increment to move to NE pixel */
putPixel(x1,y1,color); /* Draw the first point at (x1,y1) */
/* Incrementally determine the positions of the remaining pixels */
for (x1++; x1 <= x2; x1++)
{
if (d < 0)
d += Eincr; /* Choose the Eastern Pixel */
else
{
d += NEincr; /* Choose the North Eastern Pixel */
y1 += yincr; /* (or SE pixel for dx/dy < 0!) */
}
putPixel(x1,y1,color); /* Draw the point */
}
}
else
{
/* We have a line with a slope between -1 and 1 (ie: includes vertical
* lines). We must swap x and y coordinates for this. Ensure that we
* are always scan converting the line from left to right to ensure
* that we produce the same line from P1 to P0 as line from P0 to P1.*/
if (y2 < y1)
{
t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
}
if (x2 > x1)
yincr = 1;
else
yincr = -1;
d = 2*dx - dy; /* Initial decision variable value */
Eincr = 2*dx; /* Increment to move to E pixel */
NEincr = 2*(dx - dy); /* Increment to move to NE pixel */
putPixel(x1,y1,color); /* Draw the first point at (x1,y1) */
/* Incrementally determine the positions of the remaining pixels */
for (y1++; y1 <= y2; y1++)
{
if (d < 0)
d += Eincr; /* Choose the Eastern Pixel */
else
{
d += NEincr; /* Choose the North Eastern Pixel */
x1 += yincr; /* (or SE pixel for dx/dy < 0!) */
}
putPixel(x1,y1,color); /* Draw the point */
}
}
}
/* Draw a simple moire pattern of lines on the display */
void drawMoire(void)
{
int i;
for (i = 0; i < xres; i += 5)
{
line(xres/2,yres/2,i,0,i % 0xFF);
line(xres/2,yres/2,i,yres,(i+1) % 0xFF);
}
for (i = 0; i < yres; i += 5)
{
line(xres/2,yres/2,0,i,(i+2) % 0xFF);
line(xres/2,yres/2,xres,i,(i+3) % 0xFF);
}
line(0,0,xres-1,0,15);
line(0,0,0,yres-1,15);
line(xres-1,0,xres-1,yres-1,15);
line(0,yres-1,xres-1,yres-1,15);
}
/* Return NEAR pointer to FAR string pointer*/
char *get_str(char far *p)
{
int i;
char *q=mystr;
for(i=0;i<255;i++)
{
if(*p) *q++ = *p++;
else break;
}
*q = '\0';
return(mystr);
}
/* Display a list of available resolutions. Be careful with calls to function
* 00h to get SuperVGA mode information. Many VBE's build the list of video
* modes directly in this information block, so if you are using a common
* buffer (which we aren't here, but in protected mode you will), then you will
* need to make a local copy of this list of available modes. */
void availableModes(void)
{
unsigned far *p;
if (!getVbeInfo())
{
printf("No VESA VBE detected\n");
exit(1);
}
printf("VESA VBE Version %d.%d detected (%s)\n\n",
VbeInfoBlock.VESAVersion >> 8, VbeInfoBlock.VESAVersion & 0xF,
get_str(VbeInfoBlock.OEMStringPtr));
printf("Available 256 color video modes:\n");
for (p = VbeInfoBlock.VideoModePtr; *p !=(unsigned)-1; p++)
{
if (getModeInfo(*p))
{
printf(" %4d x %4d %d bits per pixel\n",
ModeInfoBlock.XResolution, ModeInfoBlock.YResolution,
ModeInfoBlock.BitsPerPixel);
}
}
printf("\nUsage: hellovbe <xres> <yres>\n");
exit(1);
}
/* Initialize the specified video mode. Notice how we determine a shift factor
* for adjusting the Window granularity for bank switching. This is much faster
* than doing it with a multiply (especially with direct banking enabled). */
void initGraphics(unsigned int x, unsigned int y)
{
unsigned far *p;
if (!getVbeInfo())
{
printf("No VESA VBE detected\n");
exit(1);
}
for (p = VbeInfoBlock.VideoModePtr; *p != (unsigned)-1; p++)
{
if (getModeInfo(*p) && ModeInfoBlock.XResolution == x
&& ModeInfoBlock.YResolution == y)
{
xres = x; yres = y;
bytesperline = ModeInfoBlock.BytesPerScanLine;
bankShift = 0;
while ((unsigned)(64 >> bankShift) != ModeInfoBlock.WinGranularity)
bankShift++;
bankSwitch = ModeInfoBlock.WinFuncPtr;
curBank = -1;
screenPtr = (char far *)( ((long)0xA000)<<16 | 0);
oldMode = getVBEMode();
setVBEMode(*p);
return;
}
}
printf("Valid video mode not found\n");
exit(1);
}
/* Main routine. Expects the x & y resolution of the desired video mode to be
* passed on command line. Will print out a list of available video modes if
* no command line is present. */
void main(int argc,char *argv[])
{
int x,y;
if (argc != 3)
availableModes(); /* Display list of available modes */
x = atoi(argv[1]); /* Get requested resolution */
y = atoi(argv[2]);
initGraphics(x,y); /* Start requested video mode */
drawMoire(); /* Draw a moire pattern */
getch(); /* Wait for keypress */
setVBEMode(oldMode); /* Restore previous mode */
}
/*----------------------------------------------------------------------*/
/* The following commented-out routines are for Planar modes */
/* outpw() is for word output, outp() is for byte output */
/*----------------------------------------------------------------------*/
/* Initialize Planar (Write mode 2)
* Should be Called from initGraphics
void initPlanar()
{
outpw(0x3C4,0x0F02);
outpw(0x3CE,0x0003);
outpw(0x3CE,0x0205);
}
*/
/* Reset to Write Mode 0
* for BIOS default draw text
void setWriteMode0()
{
outpw(0x3CE,0xFF08);
outpw(0x3CE,0x0005);
}
*/
/* Plot a pixel in Planar mode
void putPixelP(int x, int y, int color)
{
char dummy_read;
long addr = (long)y * bytesperline + (x/8);
setBank((int)(addr >> 16));
outp(0x3CE,8);
outp(0x3CF,0x80 >> (x & 7));
dummy_read = *(screenPtr + (addr & 0xFFFF));
*(screenPtr + (addr & 0xFFFF)) = color;
}
*/
; This module performs the bank switching for HELLOVBE.EXE. If your compiler
; supports in-line assembly, this code can be incorporated into HELLOVBE.C
public _setbxdx
.MODEL SMALL ;whatever
.CODE
set_struc struc
dw ? ;old bp
dd ? ;return addr (always far call)
p_bx dw ? ;reg bx value
p_dx dw ? ;reg dx value
set_struc ends
_setbxdx proc far ; must be FAR
push bp
mov bp,sp
mov bx,[bp]+p_bx
mov dx,[bp]+p_dx
pop bp
ret
_setbxdx endp
END
Copyright © 1995, Dr. Dobb's Journal