--- /dev/null
+////////////////////////////////////////\r
+// Graph.h\r
+// Coded by Denn Man\r
+//\r
+// Licensed under the Academic Free License version 1.2\r
+//\r
+// *Special thanks to Micheal Abrash\r
+// and his columns in Dr. Dobbs Journal\r
+// (Jul91 and Aug91) documenting\r
+// ModeX\r
+//\r
+// For use with Turbo-C\r
+// Uses as much assembly as possible\r
+// in order to optimize drawing speed\r
+// Self-sufficient: Nothing else needed\r
+////////////////////////////////////////\r
+\r
+#include <alloc.h>\r
+#include <dos.h>\r
+#include <math.h>\r
+#include <stdio.h>\r
+\r
+\r
+// Start of video memory (SEGMENT)\r
+#define MCGA_MEM 0xA000\r
+// Video Digital-Analog-Converter Port\r
+#define VIDEO_DAC 0x03C8\r
+// Video DAC Read Port\r
+#define DAC_READ 0x03C7\r
+// Video Data Port\r
+#define VIDEO_DATA 0x03C9\r
+// VGA Sequence Controller\r
+#define SC_INDEX 0x03C4\r
+// CRT Control Register\r
+#define CRTC_INDEX 0x03D4\r
+// Miscellaneous Output Register\r
+#define MISC_OUTPUT 0x03C2\r
+// VGA Map Mask Register\r
+#define MAP_MASK 0x02\r
+// Screen Width\r
+#define SCR_WIDTH 80\r
+// VGA Graphics Controller Register\r
+#define GC_INDEX 0x03CE\r
+// VGA Read Map Register\r
+#define READ_MAP 0x04\r
+// PI\r
+#define PI 3.14159265358\r
+\r
+// Datatypes\r
+typedef unsigned char byte;\r
+typedef unsigned int word;\r
+typedef unsigned long dword;\r
+\r
+typedef struct tagTILE {\r
+ word height;\r
+ word width;\r
+ byte *data;\r
+} TILE;\r
+\r
+// FOR BITMAP FILES!!!\r
+typedef struct tagBITMAPFILEHEADER {\r
+ word bfType;\r
+ dword bfSize;\r
+ word bfReserved1;\r
+ word bfReserved2;\r
+ dword bfOffBits;\r
+} BITMAPFILEHEADER;\r
+\r
+typedef struct tagBITMAPINFOHEADER {\r
+ dword biSize;\r
+ dword biWidth;\r
+ dword biHeight;\r
+ word biPlanes;\r
+ word biBitCount;\r
+ dword biCompression;\r
+ dword biSizeImage;\r
+ dword biXPelsPerMeter;\r
+ dword biYPelsPerMeter;\r
+ dword biClrUsed;\r
+ dword biClrImportant;\r
+} BITMAPINFOHEADER;\r
+\r
+typedef struct tagRGBQUAD {\r
+ byte rgbBlue;\r
+ byte rgbGreen;\r
+ byte rgbRed;\r
+ byte rgbReserved;\r
+} RGBQUAD;\r
+\r
+typedef struct tagBITMAPINFO {\r
+ BITMAPINFOHEADER bmiHeader;\r
+ RGBQUAD bmiColors[256];\r
+} BITMAPINFO;\r
+\r
+typedef struct tagBITMAP {\r
+ BITMAPFILEHEADER bmFileHeader;\r
+ BITMAPINFO bmInfo;\r
+ byte *bmData;\r
+} BITMAP;\r
+// DONE WITH BITMAP FILE INFO\r
+\r
+// Monitor settings for ModeX\r
+struct tagCRTParms {\r
+ word V_Total; // Vertical Total\r
+ word OverFlow; // Overflow\r
+ word CellHeight; // Cell Height\r
+ word V_Sync_Start; // Vertical Sync Start\r
+ word V_Sync_End; // Vertical Sync End\r
+ word V_Disp; // Vertical Displayed\r
+ word D_Off; // Turn off dword mode\r
+ word V_Blank_Start; // Vertical Blank Start\r
+ word V_Blank_End; // Vertical Blank End\r
+ word B_On; // Turn byte mode on\r
+} CRTParms;\r
+\r
+byte VIDEO_MODE; // The current video mode\r
+word MAX_X; // Last available X\r
+word MAX_Y; // Last available Y\r
+word SCREEN_WIDTH;\r
+word SCREEN_HEIGHT;\r
+byte MAX_COLORS; // Last available color\r
+byte FG_COLOR; // For text and mono stuff\r
+byte BG_COLOR;\r
+word CUR_X; // Current X\r
+word CUR_Y; // Current Y\r
+word visibleStart;// Start offset in video memory of screen\r
+word activeStart; // Start offset in video memory to write to\r
+\r
+// For rectangle filling (ModeX)\r
+byte LeftClipPlaneMask[] = { 0x0F, 0x0E, 0x0C, 0x08 };\r
+byte RightClipPlaneMask[] = { 0x0F, 0x01, 0x03, 0x07 };\r
+\r
+// In case things go awry\r
+char msg_error[81];\r
+\r
+void exit_error(void)\r
+{\r
+ printf("%s\a\n", msg_error);\r
+}\r
+\r
+////////////////////////////////////////\r
+// init_modeX\r
+//\r
+// -Initialized modeX 320x240x256 graphics\r
+// -Clears video memory\r
+// -Sets page 1 active at offset 0\r
+////////////////////////////////////////\r
+void init_modeX(void)\r
+{\r
+ // Fill the CRT Parameters\r
+ CRTParms.V_Total = 0x0D06;\r
+ CRTParms.OverFlow = 0x3E07;\r
+ CRTParms.CellHeight = 0x4109;\r
+ CRTParms.V_Sync_Start = 0xEA10;\r
+ CRTParms.V_Sync_End = 0xAC11;\r
+ CRTParms.V_Disp = 0xDF12;\r
+ CRTParms.D_Off = 0x0014;\r
+ CRTParms.V_Blank_Start = 0xE715;\r
+ CRTParms.V_Blank_End = 0x0616;\r
+ CRTParms.B_On = 0xE317;\r
+\r
+ asm {\r
+ mov ax, 0x0013 // Start in mode 13h\r
+ int 0x10 // Call interrupt\r
+\r
+ mov dx, SC_INDEX // Disable Chain-4 Memory model\r
+ mov ax, 0x0604\r
+ out dx, ax\r
+ mov ax, 0x0100 // Synchronous reset while switching clocks\r
+ out dx, ax\r
+\r
+ mov dx, MISC_OUTPUT // Select 28MHz dot clock, 60 Hz scan rate\r
+ mov al, 0xE3\r
+ out dx, al\r
+\r
+ mov dx, SC_INDEX // Restart Sequencer\r
+ mov ax, 0x0300\r
+ out dx, ax\r
+\r
+ mov dx, CRTC_INDEX // Reprogram the CRT Controller\r
+ mov al, 0x11 // Select Write-Protect bit\r
+ out dx, al\r
+ inc dx // CRT-Data register into DX now\r
+ in al, dx // Get current VSync End Register setting\r
+ and al, 0x7F // Remove write-protect on various registers\r
+ out dx, al\r
+ dec dx // CRT-Controller\r
+ cld // Clear the direction\r
+ mov si, OFFSET CRTParms // Load settings\r
+ mov cx, 20 // 20 Entries\r
+ }\r
+ SetCRTParmsLoop:asm {\r
+ lodsw // Load the addr:data pair\r
+ out dx, ax // Send them out\r
+ loop SetCRTParmsLoop // Do it for each one\r
+\r
+ mov dx, SC_INDEX // Enable write to all bitplanes\r
+ mov ax, 0x0F02\r
+ out dx, ax\r
+ mov ax, MCGA_MEM // Load video memory\r
+ mov es, ax\r
+ mov di, 0 // Start at the top\r
+ mov ax, 0 // Store 0's\r
+ mov cx, 0x8000 // Do it 8000h times\r
+ rep stosw // Store them\r
+ }\r
+\r
+ // Fill globals\r
+ VIDEO_MODE = 0xFF;\r
+ MAX_X = 319;\r
+ MAX_Y = 239;\r
+ SCREEN_WIDTH = 320;\r
+ SCREEN_HEIGHT = 240;\r
+ MAX_COLORS = 255;\r
+ FG_COLOR = 15;\r
+ BG_COLOR = 0;\r
+ CUR_X = 0;\r
+ CUR_Y = 0;\r
+\r
+ activeStart = 0; // Write to Page 0\r
+ visibleStart = 0; // Read from Page 0\r
+}\r
+\r
+////////////////////////////////////////\r
+// close_graph\r
+//\r
+// -Shuts down graphics, sets text mode,\r
+// and fills appropriate variables\r
+// -Frees memory taken by video buffers\r
+////////////////////////////////////////\r
+void close_graph(void)\r
+{\r
+ asm {\r
+ mov ax, 0x0003\r
+ int 0x10\r
+ }\r
+\r
+ VIDEO_MODE = 0x03;\r
+ MAX_X = 80;\r
+ MAX_Y = 25;\r
+ SCREEN_WIDTH = 80;\r
+ SCREEN_HEIGHT = 25;\r
+ MAX_COLORS = 15;\r
+ FG_COLOR = 7;\r
+ BG_COLOR = 0;\r
+ CUR_X = 1;\r
+ CUR_Y = 1;\r
+}\r
+\r
+void cleargraph(void)\r
+{\r
+ asm {\r
+ pusha\r
+ push es\r
+ push di\r
+\r
+ mov ax, MCGA_MEM\r
+ mov es, ax\r
+ mov di, 0\r
+\r
+ mov dx, SC_INDEX // Enable write to all bitplanes\r
+ mov ax, 0x0F02\r
+ out dx, ax\r
+\r
+ mov cx, 0x8000\r
+ mov ax, 0x0000\r
+ rep stosw\r
+\r
+ pop di\r
+ pop es\r
+ popa\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// setActiveStart\r
+//\r
+// -Sets the starting memory address\r
+// at which graphics are written to\r
+////////////////////////////////////////\r
+void setActiveStart(word PageBase)\r
+{\r
+ activeStart = PageBase;\r
+}\r
+\r
+////////////////////////////////////////\r
+// setVisibleStart\r
+//\r
+// -Sets the starting memory address\r
+// at which graphics are displayed from\r
+////////////////////////////////////////\r
+void setVisibleStart(word PageBase)\r
+{\r
+ visibleStart = PageBase;\r
+\r
+ asm {\r
+ pusha // Dont touch!\r
+\r
+ mov bx, PageBase // Load the offset into BX\r
+ mov dx, CRTC_INDEX // Load the CRT Index Port into DX\r
+ mov al, 0x0C // Function 0Ch, High Byte of addres\r
+ mov ah, bh // Load the high byte\r
+ out dx, ax // Send it\r
+ inc al // Function 0Dh, Low Byte of address\r
+ mov ah, bl // Load the low byte\r
+ out dx, ax // Send it\r
+\r
+ popa // We were never here\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// setActivePage\r
+//\r
+// -Sets page in which graphics are\r
+// written\r
+////////////////////////////////////////\r
+void setActivePage(byte Page)\r
+{\r
+ // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))\r
+ setActiveStart(Page * SCR_WIDTH * SCREEN_HEIGHT);\r
+}\r
+\r
+////////////////////////////////////////\r
+// setVisiblePage\r
+//\r
+// -Sets page from which graphics are\r
+// drawn\r
+////////////////////////////////////////\r
+void setVisiblePage(byte Page)\r
+{\r
+ // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))\r
+ setVisibleStart(Page * SCR_WIDTH * SCREEN_HEIGHT);\r
+}\r
+\r
+void vScroll(int rows)\r
+{\r
+ // Scrolling = current start + (rows * bytes in a row)\r
+ setVisibleStart(visibleStart + (rows * SCR_WIDTH));\r
+}\r
+\r
+void read_palette(byte *pal)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < 256; i++)\r
+ {\r
+ asm cli\r
+ outportb(DAC_READ, i);\r
+ pal[(i * 3) + 0] = inportb(VIDEO_DATA);\r
+ pal[(i * 3) + 1] = inportb(VIDEO_DATA);\r
+ pal[(i * 3) + 2] = inportb(VIDEO_DATA);\r
+ asm sti\r
+ }\r
+}\r
+\r
+void load_palette(byte *pal)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < 256; i++)\r
+ {\r
+ asm cli\r
+ outportb(VIDEO_DAC, i);\r
+ outportb(VIDEO_DATA, pal[(i * 3) + 0]);\r
+ outportb(VIDEO_DATA, pal[(i * 3) + 1]);\r
+ outportb(VIDEO_DATA, pal[(i * 3) + 2]);\r
+ asm sti\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// setpalette\r
+//\r
+// -Self explanatory, sets the color\r
+// of a given index in 256 MCGA mode\r
+////////////////////////////////////////\r
+void setpalette(byte index, byte red, byte green, byte blue)\r
+{\r
+ outportb(VIDEO_DAC, index);\r
+ outportb(VIDEO_DATA, red);\r
+ outportb(VIDEO_DATA, green);\r
+ outportb(VIDEO_DATA, blue);\r
+}\r
+\r
+////////////////////////////////////////\r
+// putpixel\r
+//\r
+// -Puts a pixel (in modeX) at (X, Y)\r
+// in active page\r
+////////////////////////////////////////\r
+void putpixel(word x, word y, byte Color)\r
+{\r
+ asm {\r
+ pusha\r
+ push es\r
+ push di\r
+\r
+ mov ax, SCR_WIDTH // Load screen width, in bytes\r
+ mul y // Multiply it by Y to get row\r
+ mov di, x // Load X into BX\r
+ shr di, 2 // Divide X by 4 to get plane\r
+ add di, ax // Add to col offset, row offset\r
+ add di, activeStart // Add the page offset\r
+ mov ax, MCGA_MEM // Load video memory into AX\r
+ mov es, ax // Then ES\r
+\r
+ mov cx, x // Get X pos\r
+ and cl, 0x03 // Get X plane\r
+ mov ax, 0x0100 + MAP_MASK // Load Map-Mask register\r
+ shl ah, cl // Write to only the desired plane\r
+ mov dx, SC_INDEX // Tell the Map-Mask to do the same\r
+ out dx, ax // Do it\r
+\r
+ mov al, Color // Load the color\r
+ stosb // Store it\r
+\r
+ pop di\r
+ pop es\r
+ popa\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// getpixel\r
+//\r
+// -Returns color of pixel (in ModeX)\r
+// at (x, y)\r
+////////////////////////////////////////\r
+byte getpixel(word x, word y)\r
+{\r
+ byte returnvalue; // To hold color\r
+\r
+ asm {\r
+ pusha // Dont touch anything\r
+ push es\r
+ push di\r
+ mov ax, SCR_WIDTH // Move screen width (in bytes) into AX\r
+ mul y // Multiply by y to get row\r
+ mov bx, x // Move x into BX\r
+ shr bx, 2 // Divide by 4 to get plane\r
+ add bx, ax // Add the two offsets together\r
+ add bx, activeStart // Add the PageBase\r
+ mov ax, MCGA_MEM // Video Memory into AX\r
+ mov es, ax // Now into ES\r
+\r
+ mov ah, byte ptr x // X into AH\r
+ and ah, 0x03 // Get Plane\r
+ mov al, READ_MAP // Tell the Video Card\r
+ mov dx, GC_INDEX\r
+ out dx, ax // Do it\r
+\r
+ mov al, es:[bx] // Get the color\r
+ sub ah, ah // Clear AH\r
+ mov returnvalue, al // Store the color into returnvalue\r
+ pop di\r
+ pop es\r
+ popa // Put everything back\r
+ }\r
+\r
+ return returnvalue; // Return color\r
+}\r
+\r
+////////////////////////////////////////\r
+// vline\r
+//\r
+// -Draws a vertical line from (x,y1)-(x,y2)\r
+// of color in activePage\r
+////////////////////////////////////////\r
+void vline(word y1, word y2, word x, byte color)\r
+{\r
+ asm {\r
+ pusha // Dont touch anything here\r
+ push es\r
+ push di\r
+ push si // For lowY\r
+\r
+ mov si, y1 // Move y1 into SI\r
+ mov bx, y2 // y2 into BX\r
+ cmp si, bx // Compare the two\r
+ jle vline_ordered // IF y1 <= y2, skip the next lines\r
+\r
+ xchg si, bx // ELSE switch them\r
+ }\r
+ vline_ordered:asm {\r
+ mov ax, MCGA_MEM // Load the video memory into AX\r
+ mov es, ax // then into ES\r
+ mov ax, SCR_WIDTH // Load screen width (bytes) into AX\r
+ mul si // and Multiply by the y1 value\r
+ mov di, ax // Move it into DI\r
+ mov ax, x // x into AX\r
+ shr ax, 2 // Divided by 4\r
+ add di, ax // and added to get first point offset\r
+\r
+ mov dx, SC_INDEX // Point to Sequence Controller\r
+ mov al, MAP_MASK // Select Map Mask Register (0x02)\r
+ out dx, al // Do it\r
+ inc dx // Next Register (SC Data)\r
+ mov cl, byte ptr x // x into CL\r
+ and cl, 0x03 // x & 0011b to get plane\r
+ mov al, 0x01 // Only one plane, so load 0001b\r
+ shl ax, cl // Shift it left by the plane number\r
+ out dx, al // Send it\r
+\r
+ mov cx, bx // Load highY into CX\r
+ sub cx, si // Subtract lowY to get ydelta\r
+ inc cx // Add one\r
+\r
+ mov al, color // Load the color into AL\r
+ }\r
+ vline_row_top:asm {\r
+ stosb // Store the color\r
+ add di, SCR_WIDTH // Add a row\r
+ dec di // Subtract one, because STO incs DI\r
+ loop vline_row_top // Loop until done\r
+\r
+ pop si\r
+ pop di\r
+ pop es\r
+ popa // Put everything back\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// hline\r
+//\r
+// -Draws a horizontal line from\r
+// (x1, y)-(x2, y) of color in activePage\r
+// -Faster than a speeding bullet! (Draws\r
+// four pixels at a time by turning on\r
+// all bitplanes for read at once.\r
+// -This function is ALL MINE!!! Not one\r
+// bit of a copy. :)\r
+////////////////////////////////////////\r
+void hline(word x1, word x2, word y, byte color)\r
+{\r
+ asm {\r
+ pusha // Dont touch anything\r
+ push es\r
+ push di\r
+ push si // For lowX\r
+\r
+ mov ax, MCGA_MEM // Load the graphics memory\r
+ mov es, ax\r
+\r
+ mov ax, SCR_WIDTH // Screen width (bytes) into AX\r
+ mul y // Multiply by y to get row offset\r
+ mov di, ax // Move row offset into DI\r
+\r
+ mov si, x1 // This was a pain to order the variables\r
+ mov cx, x2 // Load x1 into SI, x2 into CX\r
+ cmp si, cx // Compare them\r
+ jle hline_ordered // If x1 is <= x2, skip the next stuff\r
+\r
+ xchg si, cx // ELSE switch them\r
+ }\r
+ hline_ordered:asm {\r
+ mov ax, si // lowX into AX\r
+ shr ax, 2 // Divided by 4\r
+ add di, ax // Add the lowX offset to DI\r
+\r
+ mov ax, si // lowX back into AX\r
+ and ax, 0x0003 // lowX AND 0011b to get left bit planes\r
+ }\r
+ _BH = LeftClipPlaneMask[_AX]; // Load the left mask into BH\r
+ asm {\r
+ mov dx, SC_INDEX // Sequence Controller into DX\r
+ mov al, MAP_MASK // Map Mask (Function 0Ch) into AL\r
+ out dx, al // Send it\r
+ inc dx // SC Data Register\r
+ mov al, bh // Load the mask into AL\r
+ out dx, al // Send it\r
+\r
+ mov al, color // Load color into AL\r
+ stosb // Store the first byte of line\r
+\r
+ mov dx, SC_INDEX // Loading a mask again\r
+ mov al, MAP_MASK // ...\r
+ out dx, al // ...\r
+ inc dx // ... as before\r
+ mov al, 0x0F // Turn all bits on, we want MAX SPEED!\r
+ out dx, al // Send it\r
+\r
+ push cx // Store the highX\r
+ sub cx, si // Subtract the lowX from highX\r
+ shr cx, 2 // Divide it by 4\r
+ dec cx // Minus the last byte\r
+\r
+ mov al, color // Load the color into AL\r
+ rep stosb // Repeat the storing of color\r
+\r
+ pop cx // Get out highX back\r
+ inc cl // Increment, BUG FIX : Not sure why\r
+ and cl, 0x03 // AND 0011b to get bit planes\r
+ }\r
+ _BL = RightClipPlaneMask[_CL];// Load the right mask into BL\r
+ asm {\r
+ mov dx, SC_INDEX // Again, we send the mask to the\r
+ mov al, MAP_MASK // VGA card\r
+ out dx, al // ...\r
+ inc dx // ...\r
+ mov al, bl // ...\r
+ out dx, al // ... We have seen this already...\r
+\r
+ mov al, color // Load the color into AL\r
+ stosb // Store the last byte\r
+\r
+ pop si\r
+ pop di\r
+ pop es\r
+ popa // Put everything back, we're done!\r
+ }\r
+}\r
+\r
+////////////////////////////////////////\r
+// line\r
+//\r
+// -Draws a line from (x1, y1)-(x2, y2)\r
+// of color in the active page\r
+// -Uses Bresenhem's Line routine\r
+////////////////////////////////////////\r
+void line(word x1, word y1, word x2, word y2, byte color)\r
+{\r
+ int dx, dy;\r
+ int xinc, yinc;\r
+ int P_right;\r
+ int P_right_up;\r
+ int P;\r
+\r
+ if (x1 == x2)\r
+ vline(y1, y2, x1, color);\r
+// if (y1 == y2)\r
+// hline(x1, x1, y1, 0, color);\r
+\r
+ dx = abs(x2 - x1);\r
+ dy = abs(y2 - y1);\r
+\r
+ xinc = (x1 > x2) ? -1 : 1;\r
+ yinc = (y1 > y2) ? -1 : 1;\r
+\r
+ if (dx > dy)\r
+ {\r
+ P_right = (2 * dy);\r
+ P_right_up = P_right - (2 * dx);\r
+ P = P_right - dx;\r
+\r
+ for (; dx >= 0; dx--)\r
+ {\r
+ putpixel(x1, y1, color);\r
+ if (P > 0)\r
+ {\r
+ x1 += xinc;\r
+ y1 += yinc;\r
+ P += P_right_up;\r
+ }\r
+ else\r
+ {\r
+ x1 += xinc;\r
+ P += P_right;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ P_right = (2 * dx);\r
+ P_right_up = P_right - (2 * dy);\r
+ P = P_right - dy;\r
+\r
+ for (; dy >= 0; dy--)\r
+ {\r
+ putpixel(x1, y1, color);\r
+ if (P > 0)\r
+ {\r
+ x1 += xinc;\r
+ y1 += yinc;\r
+ P += P_right_up;\r
+ }\r
+ else\r
+ {\r
+ y1 += yinc;\r
+ P += P_right;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void rect(word x1, word y1, word x2, word y2, byte color)\r
+{\r
+ // Just draw the four lines, x is longer because hline is a\r
+ // faster routine than vline.\r
+ hline(x1, x2, y1, color);\r
+ hline(x1, x2, y2, color);\r
+ vline(y1 + 1, y2 - 1, x1, color);\r
+ vline(y1 + 1, y2 - 1, x2, color);\r
+}\r
+\r
+////////////////////////////////////////\r
+// fillrect\r
+//\r
+// -Fills a rectangle (in ModeX) of color\r
+// from (x1, y1) to (x2, y2)\r
+//\r
+// *Adopted from Dr. Dobbs Journal Sep 91\r
+////////////////////////////////////////\r
+void fillrect(word x1, word y1, word x2, word y2, byte color)\r
+{\r
+ asm {\r
+ pusha // Dont touch anything\r
+ push ds\r
+ push si\r
+ push es\r
+ push di\r
+ push bp\r
+\r
+ cld // Clear direction flag (left to right)\r
+ mov ax, SCR_WIDTH // Screen Width (bytes) into AX\r
+ mul y1 // Times y1 value\r
+ mov di, x1 // x1 into DI\r
+ shr di, 2 // Divided by four to get plane\r
+ add di, ax // Add the y offset\r
+ add di, activeStart // Add the PageBase\r
+ mov ax, MCGA_MEM // Now set up the video memory\r
+ mov es, ax // into ES\r
+ mov dx, SC_INDEX // Point to Sequence Controller\r
+ mov al, MAP_MASK // Select Map Mask Register (0x02)\r
+ out dx, al // Do it\r
+ inc dx // Next Register (SC Data)\r
+ mov si, x1 // x1 into SI\r
+ and si, 0x0003 // x1 & 0011b to get plane\r
+ }\r
+ _BH = LeftClipPlaneMask[_SI]; // Select appropriate mask\r
+ asm {\r
+ mov si, x2 // Do the same for x2\r
+ and si, 0x0003 // x2 & 0011b\r
+ }\r
+ _BL = RightClipPlaneMask[_SI]; // Mask select\r
+ asm {\r
+ mov cx, x2 // x2 into CX\r
+ mov si, x1 // x1 into SI\r
+ cmp cx, si // Compare them\r
+ jle FillDone // IF CX <= SI jump to FillDone\r
+ dec cx // Decrement CX\r
+ and si, 0xFFFC // x1 & 1111111111111100\r
+ sub cx, si // Subtract x1 from x2\r
+ shr cx, 2 // Divide CX by 4\r
+ jnz MasksSet // Jump if not zero to MasksSet\r
+ and bh, bl // BH = BH and BL\r
+ }\r
+ MasksSet:asm {\r
+ mov si, y2 // y2 into SI\r
+ sub si, y1 // Subtract y1\r
+ jle FillDone // IF SI <= 0 jump to FillDone\r
+ mov ah, byte ptr color // Load color\r
+ mov bp, SCR_WIDTH // Load screen width (bytes)\r
+ sub bp, cx // Subtract xdelta from width\r
+ dec bp // Minus 1\r
+ }\r
+ FillRowsLoop:asm {\r
+ push cx // Dont hurt CX\r
+ mov al, bh // Left Clip Mask into AL\r
+ out dx, al // Send it out\r
+ mov al, ah // Color to AL\r
+ stosb // Send it out\r
+ dec cx // Minus left edge byte\r
+ js FillLoopBottom // Jump if SIGNAL flag NOT set\r
+ jz DoRightEdge // If that's it, do the right.\r
+ mov al, 0x0F // Turn all bit planes on\r
+ out dx, al // Do it\r
+ mov al, ah // Load color into AL\r
+ rep stosb // Store it over and over\r
+ }\r
+ DoRightEdge:asm {\r
+ mov al, bl // Right Clip Mask into AL\r
+ out dx, al // Do it\r
+ mov al, ah // Load color into AL\r
+ stosb // Store it\r
+ }\r
+ FillLoopBottom:asm {\r
+ add di, bp // Next scan line\r
+ pop cx // What row?\r
+ dec si // One less row\r
+ jnz FillRowsLoop // If not zero, go again\r
+ }\r
+ FillDone:asm {\r
+ pop bp\r
+ pop di\r
+ pop es\r
+ pop si\r
+ pop ds\r
+ popa // All done, put everything back\r
+ }\r
+}\r
+\r
+void circle(word x, word y, word radius, byte color)\r
+{\r
+ float angle;\r
+ float ainc = 1;\r
+ word xc, yc;\r
+\r
+ if (radius > 119) // IF the radius is greater than 119, make the\r
+ ainc = 0.25; // increment smaller\r
+ if (radius > 61) // IF it's bigger than 61\r
+ ainc = 0.5; // do the same\r
+\r
+\r
+ // Only calculate 1/8th of the circle\r
+ // Four quadrants = (x, y), (-x, y), (-x, -y), (x, -y)\r
+ // Eight octants are made by switching x's and y's.\r
+ // Draw eight pixels per iteration and make the circle\r
+ // eight times faster than conventional routines.\r
+ for (angle = 0; angle <= 45; angle += ainc)\r
+ {\r
+ xc = (word)floor(cos((angle * PI) / 180) * radius);\r
+ yc = (word)floor(sin((angle * PI) / 180) * radius);\r
+\r
+ putpixel(x + xc, y + yc, color);\r
+ putpixel(x + xc, y - yc, color);\r
+ putpixel(x - xc, y + yc, color);\r
+ putpixel(x - xc, y - yc, color);\r
+\r
+ putpixel(x + yc, y + xc, color);\r
+ putpixel(x + yc, y - xc, color);\r
+ putpixel(x - yc, y + xc, color);\r
+ putpixel(x - yc, y - xc, color);\r
+ }\r
+}\r
+\r
+void load_BMP_palette(BITMAP *s)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < 256; i++)\r
+ setpalette(i, (byte)floor((s->bmInfo.bmiColors[i].rgbRed / 63) * 255),\r
+ (byte)floor((s->bmInfo.bmiColors[i].rgbGreen / 63) * 255),\r
+ (byte)floor((s->bmInfo.bmiColors[i].rgbBlue / 63) * 255));\r
+}\r
+\r
+////////////////////////////////////////\r
+// load_BMP\r
+//\r
+// -Opens a bitmap (Non-Compressed) and\r
+// stores the data into a given BITMAP\r
+// variable\r
+// -Allocate memory BEFORE calling this\r
+// function for the BITMAP structure\r
+// -Must be 256 Color, Columns divisible\r
+// by four\r
+////////////////////////////////////////\r
+void load_BMP(char *filename, TILE *target)\r
+{\r
+ FILE *inBMP; // Create file handle\r
+ BITMAP *tempBMP;\r
+ int color;\r
+\r
+ if ((inBMP = fopen(filename, "r+b")) == NULL)// Open it\r
+ {\r
+ sprintf(msg_error, "Cannot open %s", filename);\r
+ atexit(exit_error); // IF error, exit and\r
+ exit(1); // tell user.\r
+ }\r
+\r
+ tempBMP = (BITMAP *)malloc(sizeof(BITMAP) - 1);\r
+\r
+ fseek(inBMP, 0, 0); // Goto the beginning\r
+ fread(tempBMP, sizeof(BITMAP) - 1, 1, inBMP); // And load it all into\r
+ // the given variable\r
+\r
+ fseek(inBMP, 54, 0); // Goto color offset\r
+ for (color = 0; color < 256; color++) // and read 'em in.\r
+ {\r
+ tempBMP->bmInfo.bmiColors[color].rgbBlue = fgetc(inBMP);\r
+ tempBMP->bmInfo.bmiColors[color].rgbGreen = fgetc(inBMP);\r
+ tempBMP->bmInfo.bmiColors[color].rgbRed = fgetc(inBMP);\r
+ tempBMP->bmInfo.bmiColors[color].rgbReserved = fgetc(inBMP);\r
+ }\r
+\r
+ load_BMP_palette(tempBMP);\r
+\r
+ // Allocate space for the data to hold the pixels\r
+ // Goto the pixel offset in the file\r
+ // Read in the pixels\r
+ target->data = (byte *)calloc((tempBMP->bmFileHeader.bfSize - tempBMP->bmFileHeader.bfOffBits), 1);\r
+ target->height = tempBMP->bmInfo.bmiHeader.biHeight;\r
+ target->width = tempBMP->bmInfo.bmiHeader.biWidth;\r
+ fseek(inBMP, tempBMP->bmFileHeader.bfOffBits, 0);\r
+ fread(target->data, target->height * target->width, 1, inBMP);\r
+\r
+ free(tempBMP);\r
+ fclose(inBMP); // Dont forget to close\r
+}\r
+\r
+void show_BMP(TILE *source, word x, word y)\r
+{\r
+ word row, col, offset = 0;\r
+\r
+ for (row = source->height; row > 0; row--)\r
+ {\r
+ for (col = 0; col < source->height; col++)\r
+ {\r
+ if (source->data[offset] != 255)\r
+ putpixel(x + col, y + row, source->data[offset]);\r
+ offset++;\r
+ }\r
+ }\r
+}\r
+\r
+void show_tile(TILE *tile, word x, word y)\r
+{\r
+ word cx, cy;\r
+\r
+ for (cy = 1; cy <= tile->height; cy++)\r
+ for (cx = 0; cx < tile->width; cx++)\r
+ if (tile->data[cx + (cy * tile->width)] != 255)\r
+ putpixel(x + cx, y + cy, tile->data[cx + (cy * tile->width)]);\r
+}\r
+\r
+void make_tile(TILE *target, TILE *source)\r
+{\r
+ int row, col, offset = 0;\r
+\r
+ target->data = (byte *)malloc(source->height * source->width + source->width);\r
+\r
+ target->height = source->height;\r
+ target->width = source->width;\r
+\r
+ for (row = source->height * source->width; row >= 0; row -= source->width)\r
+ {\r
+ for (col = 0; col < source->width; col++)\r
+ {\r
+ target->data[offset] = source->data[col + row];\r
+ offset++;\r
+ }\r
+ }\r
+}\r
+\r
+void get_tile(word x1, word y1, word x2, word y2, TILE *target)\r
+{\r
+ int cx, cy, offset = 0;\r
+\r
+ target->height = abs(y2 - y1);\r
+ target->width = abs(x2 - x1);\r
+\r
+ target->data = (byte *)malloc(target->height * target->width + target->width);\r
+\r
+ for (cy = 0; cy <= target->height; cy++)\r
+ for (cx = 0; cx < target->width; cx++)\r
+ {\r
+ target->data[offset] = getpixel(x1 + cx, y1 + cy);\r
+ offset++;\r
+ }\r
+}\r