--- /dev/null
+500 frames in 8.351648 seconds for 59.868421 fps\r
--- /dev/null
+all: test.exe\r
+\r
+test.exe: test.obj modex16.obj\r
+ wcl -0 -d2 test.obj modex16.obj\r
+\r
+test.obj: test.c modex16.h\r
+ wcl -0 -d2 -c test.c\r
+\r
+modex16.obj: modex16.h modex16.c\r
+ wcl -0 -d2 -c modex16.c\r
--- /dev/null
+#include <dos.h>\r
+#include <string.h>\r
+#include <mem.h>\r
+#include <conio.h>\r
+#include "modex16.h"\r
+\r
+\r
+byte far* VGA=(byte far*) 0xA0000000; /* this points to video memory. */\r
+\r
+static void\r
+vgaSetMode(byte mode)\r
+{\r
+ union REGS regs;\r
+\r
+ regs.h.ah = SET_MODE;\r
+ regs.h.al = mode;\r
+ int86(VIDEO_INT, ®s, ®s);\r
+}\r
+\r
+\r
+/* -========================= Entry Points ==========================- */\r
+void\r
+modexEnter() {\r
+ word i;\r
+ dword far*ptr=(dword far*)VGA; /* used for faster screen clearing */\r
+ word CRTParms[] = {\r
+ 0x0d06, /* vertical total */\r
+ 0x3e07, /* overflow (bit 8 of vertical counts) */\r
+ 0x4109, /* cell height (2 to double-scan */\r
+ 0xea10, /* v sync start */\r
+ 0xac11, /* v sync end and protect cr0-cr7 */\r
+ 0xdf12, /* vertical displayed */\r
+ 0x0014, /* turn off dword mode */\r
+ 0xe715, /* v blank start */\r
+ 0x0616, /* v blank end */\r
+ 0xe317 /* turn on byte mode */\r
+ };\r
+ int CRTParmCount = sizeof(CRTParms) / sizeof(CRTParms[0]);\r
+\r
+ /* TODO save current video mode and palette */\r
+ vgaSetMode(VGA_256_COLOR_MODE);\r
+\r
+ /* disable chain4 mode */\r
+ outpw(SC_INDEX, 0x0604);\r
+\r
+ /* synchronous reset while setting Misc Output */\r
+ outpw(SC_INDEX, 0x0100);\r
+\r
+ /* select 25 MHz dot clock & 60 Hz scanning rate */\r
+ outp(MISC_OUTPUT, 0xe3);\r
+\r
+ /* undo reset (restart sequencer) */\r
+ outpw(SC_INDEX, 0x0300);\r
+\r
+ /* reprogram the CRT controller */\r
+ outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */\r
+ outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */\r
+\r
+ /* send the CRTParms */\r
+ for(i=0; i<CRTParmCount; i++) {\r
+ outpw(CRTC_INDEX, CRTParms[i]);\r
+ }\r
+\r
+ /* clear video memory */\r
+ outpw(SC_INDEX, 0x0f02);\r
+ for(i=0; i<0x8000; i++) {\r
+ ptr[i] = 0x0000;\r
+ }\r
+}\r
+\r
+\r
+void\r
+modexLeave() {\r
+ /* TODO restore original mode and palette */\r
+ vgaSetMode(TEXT_MODE);\r
+}\r
+\r
+\r
+void\r
+modexShowPage(page_t page) {\r
+ word high_address;\r
+ word low_address;\r
+\r
+ high_address = HIGH_ADDRESS | ((word)(page) & 0xff00);\r
+ low_address = LOW_ADDRESS | ((word)(page) << 8);\r
+\r
+ /* wait for appropriate timing */\r
+ while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));\r
+ outpw(CRTC_INDEX, high_address);\r
+ outpw(CRTC_INDEX, low_address);\r
+\r
+ /* wait for one retrace */\r
+ while (!(inp(INPUT_STATUS_1) & VRETRACE)); \r
+}\r
+\r
+\r
+void\r
+modexPanPage(page_t *page, int dx, int dy) {\r
+ /* TODO figure out how the $@#! you do horizontal panning */\r
+ *page += dy * SCREEN_WIDTH;\r
+}\r
+\r
+\r
+void\r
+modexSelectPlane(byte plane) {\r
+ outp(SC_INDEX, MAP_MASK); /* select plane */\r
+ outp(SC_DATA, plane);\r
+}\r
+\r
+\r
+void\r
+modexClearRegion(page_t page, int x, int y, int w, int h, byte color) {\r
+ byte plane;\r
+ word endx = x + w;\r
+ word endy = y + h;\r
+ word dx, dy;\r
+\r
+ /* TODO Make this fast. It's SLOOOOOOW */\r
+ for(plane=0; plane < 4; plane++) {\r
+ modexSelectPlane(PLANE(plane+x));\r
+ for(dx = x; dx < endx; dx+=4) {\r
+ for(dy=y; dy<endy; dy++) {\r
+ page[PAGE_OFFSET(dx, dy)] = color;\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Functions for handling modex and doing other basic graphics stuff.\r
+ */\r
+#ifndef MODEX16_H\r
+#define MODEX16_H\r
+#include <conio.h>\r
+#include "types.h"\r
+\r
+/* -========================== Types & Macros ==========================- */\r
+#define PAGE_OFFSET(x,y) ((y<<6)+(y<<4)+(x>>2))\r
+#define PLANE(x) (1<< (x&3))\r
+typedef byte far* page_t;\r
+#define SELECT_ALL_PLANES() outpw(0x03c4, 0xff02)\r
+\r
+/* -============================ Functions =============================- */\r
+void modexEnter();\r
+void modexLeave();\r
+void modexShowPage(page_t page);\r
+void modexPanPage(page_t *page, int dx, int dy);\r
+void modexSelectPlane(byte plane);\r
+void modexClearRegion(page_t page, int x, int y, int w, int h, byte color);\r
+\r
+/* -======================= Constants & Vars ==========================- */\r
+extern byte far* VGA; /* The VGA Memory */\r
+#define VIDEO_INT 0x10\r
+#define SET_MODE 0x00\r
+#define VGA_256_COLOR_MODE 0x13\r
+#define TEXT_MODE 0x03\r
+#define SCREEN_WIDTH 320\r
+#define SCREEN_HEIGHT 240\r
+#define PAGE_SIZE (word)(SCREEN_WIDTH/4 * SCREEN_HEIGHT)\r
+\r
+#define SC_INDEX 0x03c4\r
+#define SC_DATA 0x03c5\r
+#define CRTC_INDEX 0x03d4\r
+#define CRTC_DATA 0x03d5\r
+#define MISC_OUTPUT 0x03c2\r
+#define HIGH_ADDRESS 0x0C\r
+#define LOW_ADDRESS 0x0D\r
+#define VRETRACE 0x08\r
+#define INPUT_STATUS_1 0x03da\r
+#define DISPLAY_ENABLE 0x01\r
+#define MAP_MASK 0x02\r
+#endif\r
--- /dev/null
+/*\r
+ * File: PALETTE.C\r
+ * Purpose: This file contains routines for manipulating the VGA palette.\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <conio.h>\r
+#include "palette.h"\r
+\r
+static void fadePalette(byte fade, byte start, word iter, byte *palette);\r
+static byte tmppal[PAL_SIZE];\r
+\r
+/* fade and flash */\r
+void\r
+fadeOn(word fade, byte *palette) {\r
+ fadePalette(-fade, 64, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+fadeOff(word fade, byte *palette) {\r
+ fadePalette(fade, 0, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+flashOn(word fade, byte *palette) {\r
+ fadePalette(fade, -64, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+flashOff(word fade, byte *palette) {\r
+ fadePalette(-fade, 0, 64/fade+1, palette);\r
+}\r
+\r
+\r
+static void\r
+fadePalette(byte fade, byte start, word iter, byte *palette) {\r
+ word i;\r
+ byte dim = start;\r
+\r
+ /* handle the case where we just update */\r
+ if(iter == 0) {\r
+ palUpdate(palette);\r
+ return;\r
+ }\r
+\r
+ while(iter > 0) { /* FadeLoop */\r
+ for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
+ tmppal[i] = palette[i] - dim;\r
+ if(tmppal[i] > 127) {\r
+ tmppal[i] = 0;\r
+ } else if(tmppal[i] > 63) {\r
+ tmppal[i] = 63;\r
+ }\r
+ }\r
+ palUpdate(tmppal);\r
+ iter--;\r
+ dim += fade;\r
+ }\r
+}\r
+\r
+\r
+/* save and load */\r
+void\r
+palSave(byte *palette) {\r
+ int i;\r
+\r
+ outp(PEL_READ_REG, 0); /* start at palette entry 0 */\r
+ for(i=0; i<PAL_SIZE; i++) {\r
+ palette[i] = inp(PEL_DATA_REG); /* read the palette data */\r
+ }\r
+}\r
+\r
+\r
+byte *\r
+newPal() {\r
+ byte *ptr;\r
+ ptr = malloc(PAL_SIZE);\r
+\r
+ /* handle errors */\r
+ if(!ptr) {\r
+ printf("Could not allocate palette.\n");\r
+ exit(-1);\r
+ }\r
+\r
+ return ptr;\r
+}\r
+\r
+\r
+void\r
+loadPaletteFile(byte *filename, byte **palette) {\r
+ FILE *file;\r
+ byte *ptr;\r
+\r
+ /* free the palette if it exists */\r
+ if(*palette) {\r
+ free(*palette);\r
+ }\r
+\r
+ /* allocate the new palette */\r
+ *palette = newPal();\r
+\r
+ /* open the file */\r
+ file = fopen(filename, "rb");\r
+ if(!file) {\r
+ printf("Could not open palette file: %s\n", filename);\r
+ exit(-2);\r
+ }\r
+\r
+ /* read the file */\r
+ ptr = *palette;\r
+ while(!feof(file)) {\r
+ *ptr++ = fgetc(file);\r
+ }\r
+\r
+ fclose(file);\r
+}\r
+\r
+\r
+/* blanking */\r
+void\r
+palBlack() {\r
+ fadePalette(-1, 64, 1, tmppal);\r
+}\r
+\r
+\r
+void\r
+palWhite() {\r
+ fadePalette(-1, -64, 1, tmppal);\r
+}\r
+\r
+\r
+/* utility */\r
+void\r
+palUpdate(byte *p) {\r
+ int i;\r
+ waitborder();\r
+ outp(PEL_WRITE_REG, 0); /* start at the beginning of palette */\r
+ for(i=0; i<PAL_SIZE/2; i++) {\r
+ outp(PEL_DATA_REG, p[i]);\r
+ }\r
+ waitborder(); /* waits one retrace -- less flicker */\r
+ for(i=PAL_SIZE/2; i<PAL_SIZE; i++) {\r
+ outp(PEL_DATA_REG, p[i]);\r
+ }\r
+}\r
+\r
+\r
+void\r
+waitborder() {\r
+ while(inp(INPUT_STATUS_1) & 8) {\r
+ /* spin */\r
+ }\r
+\r
+ while(!(inp(INPUT_STATUS_1) & 8)) {\r
+ /* spin */\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Headers and definitions for the palette routines.\r
+ */\r
+#include "constant.h"\r
+\r
+/* fade and flash */\r
+void fadeOn(word fade, byte *palette);\r
+void fadeOff(word fade, byte *palette);\r
+void flashOn(word fade, byte *palette);\r
+void flashOff(word fade, byte *palette);\r
+\r
+/* save and load */\r
+void palSave(byte *palette);\r
+byte *newPal();\r
+void loadPaletteFile(char *filename, byte **palette);\r
+\r
+/* blanking */\r
+void palBlack();\r
+void palWhite();\r
+\r
+/* utility */\r
+void palUpdate();\r
+void waitborder();\r
+\r
--- /dev/null
+#include "modex16.h"\r
+#include <stdio.h>\r
+\r
+word far* clock= (word far*) 0x046C; /* 18.2hz clock */\r
+\r
+void main() {\r
+ int plane;\r
+ int x, y, i;\r
+ word start, end;\r
+ page_t page, page2;\r
+ word far* ptr;\r
+ float elapsed;\r
+\r
+ modexEnter();\r
+\r
+ page= VGA;\r
+ page2=VGA+PAGE_SIZE;\r
+\r
+ /* fill the page with one color */\r
+ modexShowPage(page2);\r
+ modexClearRegion(page, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 42);\r
+ modexClearRegion(page, 17, 12, 30, 30, 19);\r
+ modexShowPage(page);\r
+\r
+ start = *clock;\r
+ for(i=0; i<500; i++) {\r
+ modexShowPage(page);\r
+ page+=SCREEN_WIDTH/4;\r
+ }\r
+ end = *clock;\r
+\r
+ modexLeave();\r
+ elapsed = (end-start)/18.2;\r
+ printf("500 frames in %f seconds for %f fps\n", elapsed, 500.0/elapsed);\r
+}\r
--- /dev/null
+/*\r
+ * Just some handy typedefs that make it easier to think about the low\r
+ * level code\r
+ */\r
+\r
+typedef unsigned char byte;\r
+typedef unsigned short word;\r
+typedef unsigned long dword;\r
+typedef signed short sword;\r
+typedef signed long sdword;\r