/**************************************************************************** * * The SuperVGA Kit * * Copyright (C) 1994 SciTech Software * All rights reserved. * * Filename: $RCSfile: svgac.c $ * Version: $Revision: 1.1 $ * * 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 model. * * $Id: svgac.c 1.1 1994/08/22 12:27:00 kjb release $ * ****************************************************************************/ #include #include #include #include #include "pmode.h" #include "svga.h" #include "vesavbe.h" /*---------------------------- Global Variables ---------------------------*/ #define MAXMODES 50 /* Maximum modes available in list */ int maxx,maxy,memory; long maxcolor,defcolor; int maxpage,bytesperline,bytesperpixel; uchar redMask,greenMask,blueMask; int redPos,redAdjust; int greenPos,greenAdjust; int bluePos,blueAdjust; bool twobanks = false; short modeList[MAXMODES]; char OEMString[80]; bool extendedflipping = false; /* True for extended flipping enable*/ bool widedac = false; /* True for 8 bit DAC support */ int oldMode = 0x3; /* Old video mode number */ bool old50Lines; /* Was old mode 80x50? */ int curBank; /* Current read/write bank */ int bankShift; /* Bank granularity adjust factor */ long pagesize; /* Page size for current mode */ void *bankSwitch; /* Pointer to bank switch routine */ void *writeBank; /* Pointer to write bank routine */ void *readBank; /* Pointer to read bank routine */ uint VESABuf_sel; /* Selector for VESABuf (1k size) */ uint VESABuf_off; /* Offset for VESABuf (1k size) */ uint VESABuf_rseg; /* Real mode segment of VESABuf */ uint VESABuf_roff; /* Real mode offset of VESABuf */ int oldFS; /* Old value of FS selector */ void (_cdecl *line)(int x1,int y1,int x2,int y2,long color); void (_cdecl *putPixel)(int x,int y,long color); void (_cdecl *clear)(long color); extern uchar font8x16[]; /* Bitmap font definition */ /*----------------------------- Implementation ----------------------------*/ /* Declare all video mode dependent routines */ int _cdecl _setFS(uint sel); void _cdecl _clear16(long color); void _cdecl _clear256(long color); void _cdecl _clear32k(long color); void _cdecl _clear16m(long color); void _cdecl _clear4G(long color); void _cdecl _putPixel16(int x,int y,long color); void _cdecl _putPixel256(int x,int y,long color); void _cdecl _putPixel32k(int x,int y,long color); void _cdecl _putPixel16m(int x,int y,long color); void _cdecl _putPixel4G(int x,int y,long color); void _cdecl _line16(int x1,int y1,int x2,int y2,long color); void _cdecl _line256(int x1,int y1,int x2,int y2,long color); void _cdecl _line32k(int x1,int y1,int x2,int y2,long color); void _cdecl _line16m(int x1,int y1,int x2,int y2,long color); void _cdecl _line4G(int x1,int y1,int x2,int y2,long color); void _cdecl _EMU_line(int x1,int y1,int x2,int y2,long color); PRIVATE void CallVBE(RMREGS *regs, void *buffer, int size) /**************************************************************************** * * Function: CallVBE * Parameters: regs - Registers to load when calling VBE * buffer - Buffer to copy VBE info block to * size - Size of buffer to fill * * Description: Calls the VESA VBE and passes in a buffer for the VBE to * store information in, which is then copied into the users * buffers space. This works in protected mode as the buffer * passed to the VESA VBE is allocated in conventional * memory, and is then copied into the users memory block. * ****************************************************************************/ { RMSREGS sregs; sregs.es = VESABuf_rseg; regs->x.di = VESABuf_roff; PM_int86x(0x10, regs, regs, &sregs); PM_memcpynf(buffer, VESABuf_sel, VESABuf_off, size); } PRIVATE void exitSuperVGA(void) /**************************************************************************** * * Function: exitSuperVGA * * Description: Cleans up after using the SuperVGA library. We need to * de-allocate any real mode memory that we have allocated * during the operation of the library, and any protected * mode pointers etc. * ****************************************************************************/ { PM_freeRealSeg(VESABuf_sel,VESABuf_off); } PUBLIC int initSuperVGA(bool enableSpecialFeatures) /**************************************************************************** * * Function: initSuperVGA * Parameters: enableSpecialFeatures - True to enable enhanced features * Returns: VBE version number for the SuperVGA (0 if no SuperVGA). * * 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. * ****************************************************************************/ { VgaInfoBlock vgaInfo; ModeInfoBlock modeInfo; RMREGS regs; short *p; uint sel,off; ulong addr; int i; /* Allocate a global buffer for communicating with the VESA VBE */ if (!PM_allocRealSeg(1024, &VESABuf_sel, &VESABuf_off, &VESABuf_rseg, &VESABuf_roff)) { fprintf(stderr, "PM_allocRealSeg failed!\n"); exit(1); } regs.x.ax = 0x4F00; /* Get SuperVGA information */ CallVBE(®s, &vgaInfo, sizeof(vgaInfo)); if (regs.x.ax != 0x004F) return false; if (strncmp(vgaInfo.VESASignature,"VESA",4) != 0) return false; /* 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. */ addr = getLong(vgaInfo.VideoModePtr); PM_mapRealPointer(&sel,&off,addr >> 16, addr & 0xFFFF); for (i = 0; PM_getWord(sel,off) != 0xFFFF; off += 2,i++) { if (PM_getWord(sel,off) != 0x6A) modeList[i] = PM_getWord(sel,off); } modeList[i] = -1; memory = getShort(vgaInfo.TotalMemory) * 64; addr = getLong(vgaInfo.OEMStringPtr); PM_mapRealPointer(&sel,&off,addr >> 16, addr & 0xFFFF); PM_memcpynf(OEMString,sel,off,sizeof(OEMString)); /* Determine if the board supports separate read/write banks */ for (p = modeList; *p != -1; p++) { regs.x.ax = 0x4F01; /* Get SuperVGA mode info */ regs.x.cx = *p; CallVBE(®s, &modeInfo, sizeof(modeInfo)); if (regs.x.ax == 0x004F && (modeInfo.MemoryModel == 3 || modeInfo.MemoryModel == 4)) { modeInfo.WinBAttributes &= 0x7; twobanks = (modeInfo.WinBAttributes == 0x3); /* Check for support of extended page flipping and wide palettes. * We need to initialise a video mode to do this. */ if (enableSpecialFeatures) { setSuperVGAMode(*p); extendedflipping = setSuperVGADisplayStart(10,10); widedac = set8BitPalette() && set6BitPalette(); restoreMode(); } break; } } atexit(exitSuperVGA); /* Ensure our exit routine is always called */ return getShort(vgaInfo.VESAVersion); } PRIVATE void computePageInfo(ModeInfoBlock *modeInfo,int *maxpage, long *pagesize) /**************************************************************************** * * Function: computePageInfo * Parameters: modeInfo - Pointer to valid mode information block * maxpage - Number of display pages - 1 * pagesize - Size of each logical display page in bytes * * Description: Computes the number of image pages and size of each image * page for a specified video mode. * ****************************************************************************/ { long memsize,size; if (!extendedflipping) { if (modeInfo->MemoryModel == memPL) memsize = 256 * 1024L; else memsize = 64 * 1024L; } else memsize = memory * 1024L; size = (long)getShort(modeInfo->BytesPerScanLine) * (long)getShort(modeInfo->YResolution); if (modeInfo->BitsPerPixel == 4) { /* We have a 16 color video mode, so round up the page size to * 8k, 16k, 32k or 64k boundaries depending on how large it is. */ size = (size + 0x1FFFL) & 0xFFFFE000L; if (size != 0x2000) { size = (size + 0x3FFFL) & 0xFFFFC000L; if (size != 0x4000) { size = (size + 0x7FFFL) & 0xFFFF8000L; if (size != 0x8000) size = (size + 0xFFFFL) & 0xFFFF0000L; } } } else size = (size + 0xFFFFL) & 0xFFFF0000L; if (modeInfo->MemoryModel == memPL) memsize /= 4; if (size <= memsize) *maxpage = (memsize / size) - 1; else *maxpage = 0; *pagesize = size; } PUBLIC bool getSuperVGAModeInfo(int mode,int *xres,int *yres, int *bytesperline,int *bitsperpixel,int *memmodel,int *maxpage, long *pagesize) /**************************************************************************** * * Function: getSuperVGAModeInfo * Parameters: mode - Mode to get information about * xres - Place to store x resolution * yres - Place to store y resolution * bytesperline - Bytes per scanline * bitsperpixel - Place to store bits per pixel (2^n colors) * memmodel - Memory model for mode (planar, packed etc) * maxpage - Number of display pages - 1 * pagesize - Size of each logical display page in bytes * Returns: True if mode number was valid, false if not. * * Description: Obtains information about a specific video mode from the * VBE. You should use this function to find the video mode * you wish to set, as the new VBE 2.0 mode numbers may be * completely arbitrary. * ****************************************************************************/ { ModeInfoBlock modeInfo; RMREGS regs; if (mode <= 0x13) { /* This is a standard VGA mode, so fill in the required information * ourselves. */ switch (mode) { case 0x0D: getShort(modeInfo.XResolution) = 320; getShort(modeInfo.YResolution) = 200; getShort(modeInfo.BytesPerScanLine) = 40; modeInfo.BitsPerPixel = 4; modeInfo.MemoryModel = memPL; break; case 0x0E: getShort(modeInfo.XResolution) = 640; getShort(modeInfo.YResolution) = 200; getShort(modeInfo.BytesPerScanLine) = 80; modeInfo.BitsPerPixel = 4; modeInfo.MemoryModel = memPL; break; case 0x10: getShort(modeInfo.XResolution) = 640; getShort(modeInfo.YResolution) = 350; getShort(modeInfo.BytesPerScanLine) = 80; modeInfo.BitsPerPixel = 4; modeInfo.MemoryModel = memPL; break; case 0x12: getShort(modeInfo.XResolution) = 640; getShort(modeInfo.YResolution) = 480; getShort(modeInfo.BytesPerScanLine) = 80; modeInfo.BitsPerPixel = 4; modeInfo.MemoryModel = memPL; break; case 0x13: getShort(modeInfo.XResolution) = 320; getShort(modeInfo.YResolution) = 200; getShort(modeInfo.BytesPerScanLine) = 320; modeInfo.BitsPerPixel = 8; modeInfo.MemoryModel = memPK; break; default: return false; } } else { /* This is a VESA mode, so call the BIOS to get information about * it. */ regs.x.ax = 0x4F01; /* Get mode information */ regs.x.cx = mode; CallVBE(®s, &modeInfo, sizeof(modeInfo)); if (regs.x.ax != 0x004F) return false; if ((getShort(modeInfo.ModeAttributes) & 0x1) == 0) return false; } *xres = getShort(modeInfo.XResolution); *yres = getShort(modeInfo.YResolution); *bytesperline = getShort(modeInfo.BytesPerScanLine); *memmodel = modeInfo.MemoryModel; *bitsperpixel = modeInfo.BitsPerPixel; /* Emulate RGB modes using a 3 3 2 palette arrangement by default */ redMask = 0x7; redPos = 5; redAdjust = 5; greenMask = 0x7; greenPos = 2; greenAdjust = 5; blueMask = 0x3; bluePos = 0; blueAdjust = 6; if (*memmodel == memPK && *bitsperpixel > 8) { /* Support old style definitions, which some BIOS'es still use :-( */ *memmodel = memRGB; switch (*bitsperpixel) { case 15: redMask = 0x1F; redPos = 10; redAdjust = 3; greenMask = 0x1F; greenPos = 5; greenAdjust = 3; blueMask = 0x1F; bluePos = 0; blueAdjust = 3; break; case 16: redMask = 0x1F; redPos = 11; redAdjust = 3; greenMask = 0x3F; greenPos = 5; greenAdjust = 2; blueMask = 0x1F; bluePos = 0; blueAdjust = 3; break; case 24: case 32: redMask = 0xFF; redPos = 16; redAdjust = 0; greenMask = 0xFF; greenPos = 8; greenAdjust = 0; blueMask = 0xFF; bluePos = 0; blueAdjust = 0; break; } } else if (*memmodel == memRGB) { /* Convert the 32k direct color modes of VBE 1.2+ BIOSes to * be recognised as 15 bits per pixel modes. */ if (*bitsperpixel == 16 && modeInfo.RsvdMaskSize == 1) *bitsperpixel = 15; /* Save direct color info mask positions etc */ redMask = (0xFF >> (redAdjust = 8 - modeInfo.RedMaskSize)); redPos = modeInfo.RedFieldPosition; greenMask = (0xFF >> (greenAdjust = 8 - modeInfo.GreenMaskSize)); greenPos = modeInfo.GreenFieldPosition; blueMask = (0xFF >> (blueAdjust = 8 - modeInfo.BlueMaskSize)); bluePos = modeInfo.BlueFieldPosition; } switch (*bitsperpixel) { case 15: case 16: bytesperpixel = 2; break; case 24: bytesperpixel = 3; break; case 32: bytesperpixel = 4; break; default: bytesperpixel = 1; break; } computePageInfo(&modeInfo,maxpage,pagesize); return true; } PUBLIC bool setSuperVGAMode(int mode) /**************************************************************************** * * Function: setSuperVGAMode * Parameters: mode - SuperVGA video mode to set. * 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 initSuperVGA() routine first. * ****************************************************************************/ { ModeInfoBlock modeInfo; RMREGS regs; int bitsperpixel,memmodel; regs.x.ax = 0x0F00; PM_int86(0x10, ®s, ®s); oldMode = regs.x.ax & 0x7F; /* Save old video mode */ old50Lines = false; /* Default to 25 line mode */ if (oldMode == 0x3) { regs.x.ax = 0x1130; regs.x.bx = 0; regs.x.dx = 0; PM_int86(0x10,®s,®s); old50Lines = (regs.h.dl == 49); } regs.x.ax = 0x4F02; regs.x.bx = mode; PM_int86(0x10,®s,®s); /* Set the video mode */ if (regs.x.ax != 0x004F) return false; getSuperVGAModeInfo(mode,&maxx,&maxy,&bytesperline,&bitsperpixel, &memmodel,&maxpage,&pagesize); maxx--; maxy--; /* Now set up the vectors to the correct routines for the video * mode type. */ switch (bitsperpixel) { case 4: clear = _clear16; putPixel = _putPixel16; line = _line16; maxcolor = defcolor = 15; break; case 8: clear = _clear256; putPixel = _putPixel256; line = _line256; maxcolor = 255; defcolor = 15; break; case 15: clear = _clear32k; putPixel = _putPixel32k; line = _line32k; maxcolor = defcolor = 0x7FFF; break; case 16: clear = _clear32k; putPixel = _putPixel32k; line = _line32k; maxcolor = defcolor = 0xFFFF; break; case 24: clear = _clear16m; putPixel = _putPixel16m; line = _line16m; maxcolor = defcolor = 0xFFFFFF; break; case 32: clear = _clear4G; putPixel = _putPixel4G; line = _line4G; maxcolor = defcolor = 0xFFFFFF; break; } if (mode <= 0x13) { /* This is a normal VGA style mode, so we need to determine the * correct information for bank switching from the BIOS */ if (mode == 0x13) mode = 0x101; else mode = 0x102; } regs.x.ax = 0x4F01; /* Get mode information */ regs.x.cx = mode; CallVBE(®s, &modeInfo, sizeof(modeInfo)); bankShift = 0; while ((64 >> bankShift) != getShort(modeInfo.WinGranularity)) bankShift++; curBank = -1; /* Create a pointer to the real mode function for bank switching. In * protected mode it is extremely complicated and slow to call a * real mode function from low level assembly language, so we simply * set the routine to NULL so that the Int 10h interface will be used * instead. */ if (_PM_modeType == PM_realMode) bankSwitch = (void *)getLong(modeInfo.WinFuncPtr); else bankSwitch = NULL; /* Now set up the vectors to the appropriate bank switching routines. * If the Universal VESA VBE is installed, we can move the bank * switching routines from there into our own code space for speed * (especially under protected mode). */ writeBank = readBank = NULL; #ifdef PM386 { uint sel,off; RMSREGS sregs; regs.x.ax = 0x4F0A; regs.x.bx = 0xFE01; regs.x.dx = 0x0500; PM_int86x(0x10, ®s, ®s, &sregs); if (regs.x.ax == 0x004F) { PM_mapRealPointer(&sel,&off,sregs.es,regs.x.di); writeBank = malloc(regs.x.dx); PM_memcpynf(writeBank,sel,off,regs.x.dx); } regs.x.ax = 0x4F0A; regs.x.bx = 0xFE01; regs.x.dx = 0x0501; PM_int86x(0x10, ®s, ®s, &sregs); if (regs.x.ax == 0x004F) { PM_mapRealPointer(&sel,&off,sregs.es,regs.x.di); readBank = malloc(regs.x.dx); PM_memcpynf(readBank,sel,off,regs.x.dx); } } #endif oldFS = _setFS(PM_getVGASelector()); /* Set FS to VGA selector */ return true; } PUBLIC void restoreMode(void) /**************************************************************************** * * Function: 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; _setFS(oldFS); /* Restore value of FS selector */ free(readBank); /* Free the relocated reoutines */ free(writeBank); /* if any were allocated */ regs.x.ax = oldMode; PM_int86(0x10,®s,®s); /* Set the old video mode */ if (old50Lines) { regs.x.ax = 0x1112; regs.x.bx = 0; PM_int86(0x10,®s,®s); /* Restore 50 line mode */ } } bool setSuperVGADisplayStart(int x,int y) /**************************************************************************** * * Function: setDisplayStart * Parameters: x,y - Position of the first pixel to display * Returns: True if function was successful. * * Description: Sets the new starting display position to implement * hardware scrolling. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F07; regs.x.bx = 0x0000; regs.x.cx = x; regs.x.dx = y; PM_int86(0x10,®s,®s); if (regs.x.ax != 0x004F) return false; return true; } bool set8BitPalette(void) /**************************************************************************** * * Function: set8BitPalette * Returns: True if 8 bit wide palette has been set. * * Description: Attempts to set the system into the 8 bit wide palette * mode if supported by the VBE. Returns true on success, false * otherwise. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F08; /* Set DAC service */ regs.x.bx = 0x0800; /* BH := 8, BL := 0 (set DAC width) */ PM_int86(0x10,®s,®s); if (regs.x.ax != 0x004F) return false; /* Function failed, no wide dac */ if (regs.h.bh == 6) return false; regs.x.ax = 0x4F08; regs.x.bx = 0x0001; /* Get DAC width (should now be 8) */ PM_int86(0x10,®s,®s); if (regs.x.ax != 0x004F) return false; if (regs.h.bh != 8) return false; return true; } bool set6BitPalette(void) /**************************************************************************** * * Function: set6BitPalette * Returns: True if 6 bit wide palette has been set. * * Description: Attempts to set the system back into the 6 bit wide palette * mode if supported by the VBE. Returns true on success, false * otherwise. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F08; regs.x.bx = 0x0600; PM_int86(0x10,®s,®s); /* Restore to 6 bit DAC */ if (regs.x.ax != 0x004F) return true; if (regs.h.bh != 6) return false; return true; } void setPalette(int start, int num, palette *palbuf) /**************************************************************************** * * Function: setPalette * Parameters: start - Starting index number * num - Number of entries to program * palbuf - Buffer of palette values to program * * Description: Sets the palette values. The values should be in the * range 0-63 if the palette is in the 6 bit mode, or 0-255 * if the palette is in the 8 bit mode. The palette is * programmed via the BIOS. * ****************************************************************************/ { RMREGS regs; RMSREGS sregs; regs.x.ax = 0x1012; regs.x.bx = start; regs.x.cx = num; sregs.es = VESABuf_rseg; regs.x.dx = VESABuf_roff; PM_memcpyfn(VESABuf_sel,VESABuf_off, palbuf, num * 3); PM_int86x(0x10, ®s, ®s, &sregs); } void getPalette(int start, int num, palette *palbuf) /**************************************************************************** * * Function: getPalette * Parameters: start - Starting index number * num - Number of entries to read * red - Array of red values (0-63 or 0-255) * green - Array of green values (0-63 or 0-255) * blue - Array of blue values (0-63 or 0-255) * * Description: Reads the current palette values. * ****************************************************************************/ { RMREGS regs; RMSREGS sregs; regs.x.ax = 0x1017; regs.x.bx = start; regs.x.cx = num; sregs.es = VESABuf_rseg; regs.x.dx = VESABuf_roff; PM_int86x(0x10, ®s, ®s, &sregs); PM_memcpynf(palbuf, VESABuf_sel,VESABuf_off, num * 3); } long 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 ((long)((r >> redAdjust) & redMask) << redPos) | ((long)((g >> greenAdjust) & greenMask) << greenPos) | ((long)((b >> blueAdjust) & blueMask) << bluePos); } PUBLIC void _cdecl _EMU_line(int x1,int y1,int x2,int y2,long color) /**************************************************************************** * * Function: line * Parameters: x1,y1 - First endpoint of line * x2,y2 - Second endpoint of line * color - Color to draw the line in * * Description: Scan convert a line segment using the MidPoint Digital * Differential Analyser algorithm. * ****************************************************************************/ { 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. */ 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 our 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 the * 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 */ } } } PUBLIC void writeText(int x,int y,char *str,long 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); 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) putPixel(x+i,y+j,color); byte <<= 1; } } x += 8; } }