OSDN Git Service

new file: 16/graph.h
authorsparky4 <sparky4@4ch.maidlab.jp>
Sun, 18 May 2014 03:38:26 +0000 (22:38 -0500)
committersparky4 <sparky4@4ch.maidlab.jp>
Sun, 18 May 2014 03:38:26 +0000 (22:38 -0500)
16/graph.h [new file with mode: 0644]

diff --git a/16/graph.h b/16/graph.h
new file mode 100644 (file)
index 0000000..cabc296
--- /dev/null
@@ -0,0 +1,951 @@
+////////////////////////////////////////\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