diff --git a/.gitignore b/.gitignore index 15e50eb..d0dad88 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.obj *.bak - +*.dsk +*.swp diff --git a/game.exe b/game.exe new file mode 100755 index 0000000..93502fb Binary files /dev/null and b/game.exe differ diff --git a/game.prj b/game.prj new file mode 100755 index 0000000..b40dde2 Binary files /dev/null and b/game.prj differ diff --git a/kbd.c b/kbd.c new file mode 100755 index 0000000..cf246fd --- /dev/null +++ b/kbd.c @@ -0,0 +1,75 @@ +#include +#include +#include "kbd.h" + +static void interrupt (*oldKbdISR)() = NULL; + +void kbd_cleanup() { + if (oldKbdISR != NULL) { + setvect(KBD_INT, oldKbdISR); + oldKbdISR = NULL; + } +} + +volatile unsigned char keybuf[128] = { 0 }; +volatile char kbd_triggered = 0; + +static void interrupt kbd_isr() { + unsigned char raw; + char ctl; + + asm sti; + raw = inp(0x60); + ctl = inp(0x61) | 0x82; + outp(0x61, ctl); + outp(0x61, ctl & 0x7f); + outp(0x20, 0x20); + + if (raw & 0x80) { + keybuf[raw & 0x7f] &= ~KEY_SIGNAL; + } else { + keybuf[raw] |= KEY_SIGNAL; + } + kbd_triggered = raw; +} + +unsigned char kbd_wait() { + kbd_triggered = 0; + while (!kbd_triggered) {} + return kbd_triggered; +} + +void kbd_init() { + if (oldKbdISR == NULL) { + memset(keybuf, 0, 128); + oldKbdISR = getvect(KBD_INT); + setvect(KBD_INT, kbd_isr); + atexit(kbd_cleanup); + } +} + +void kbd_debounce() { + int i = 0; + asm cli; + for (i = 0; i < 128; i ++) { + unsigned char signal = keybuf[i] & KEY_SIGNAL; + unsigned char keystate = keybuf[i] & 0x0f; + + if (!signal) { + if (keystate == KEY_RELEASED) { + keystate = KEY_OFF; + } else if (keystate != KEY_OFF) { + keystate = KEY_RELEASED; + } + } else { + if (keystate == KEY_OFF) { + keystate = KEY_PRESSED; + } else if (keystate == KEY_PRESSED) { + keystate = KEY_DOWN; + } + } + + keybuf[i] = signal | keystate; + } + asm sti; +} \ No newline at end of file diff --git a/kbd.h b/kbd.h new file mode 100755 index 0000000..9fefd03 --- /dev/null +++ b/kbd.h @@ -0,0 +1,106 @@ +/*** K E Y B O A R D ***/ +#define KBD_INT 0x09 + +extern volatile unsigned char keybuf[128]; +extern volatile char kbd_triggered; + +void kbd_init(); +void kbd_debounce(); // call once per frame +unsigned char kbd_wait(); + +#define KEY_OFF 0 +#define KEY_PRESSED 1 +#define KEY_DOWN 2 +#define KEY_RELEASED 3 +#define KEY_SIGNAL 0x80 + +#define keyIsDown(k) (keybuf[k] & KEY_SIGNAL) +#define keyWasPressed(k) ((keybuf[k] & 0x0f) == KEY_PRESSED) +#define keyWasReleased(k) ((keybuf[k] & 0x0f) == KEY_RELEASED) + +#define K_ESC 1 +#define K_1 2 +#define K_2 3 +#define K_3 4 +#define K_4 5 +#define K_5 6 +#define K_6 7 +#define K_7 8 +#define K_8 9 +#define K_9 10 +#define K_0 11 +#define K_MINUS 12 +#define K_EQUAL 13 +#define K_BKSP 14 +#define K_TAB 15 +#define K_Q 16 +#define K_W 17 +#define K_E 18 +#define K_R 19 +#define K_T 20 +#define K_Y 21 +#define K_U 22 +#define K_I 23 +#define K_O 24 +#define K_P 25 +#define K_LBRK 26 +#define K_RBRK 27 +#define K_ENTER 28 +#define K_CTRL 29 +#define K_A 30 +#define K_S 31 +#define K_D 32 +#define K_F 33 +#define K_G 34 +#define K_H 35 +#define K_J 36 +#define K_K 37 +#define K_L 38 +#define K_SEMI 39 +#define K_APOS 40 +#define K_TILDE 41 +#define K_LSHFT 42 +#define K_BSLSH 43 +#define K_Z 44 +#define K_X 45 +#define K_C 46 +#define K_V 47 +#define K_B 48 +#define K_N 49 +#define K_M 50 +#define K_COMMA 51 +#define K_DOT 52 +#define K_SLASH 53 +#define K_RSHFT 54 +#define K_PSCRN 55 +#define K_ALT 56 +#define K_SPACE 57 +#define K_CAPS 58 +#define K_F1 59 +#define K_F2 60 +#define K_F3 61 +#define K_F4 62 +#define K_F5 63 +#define K_F6 64 +#define K_F7 65 +#define K_F8 66 +#define K_F9 67 +#define K_F10 68 +#define K_NUMLK 69 +#define K_SCRL 70 +#define K_HOME 71 +#define K_UP 72 +#define K_PGUP 73 +#define K_NDASH 74 +#define K_LEFT 75 +#define K_CENT 76 +#define K_RIGHT 77 +#define K_NPLUS 78 +#define K_END 79 +#define K_DOWN 80 +#define K_PGDN 81 +#define K_INS 82 +#define K_DEL 83 +#define K_F11 87 +#define K_F12 88 + diff --git a/mouse.c b/mouse.c new file mode 100755 index 0000000..78dbafd --- /dev/null +++ b/mouse.c @@ -0,0 +1,55 @@ +#include +#include "mouse.h"; + +/*** M O U S E ***/ +Mouse_t MOUSE; + +void far mouse_callback() { + asm { + mov ax, DGROUP + mov ds, ax + shr cx, 1 + mov MOUSE.x, cx + mov MOUSE.y, dx + mov MOUSE.buttons, bx + } +} + +void mouse_cleanup() { + //uninstall handler + asm { + mov ax, 0ch + mov dx, 0 + mov es, dx + mov cx, 0 + int 33h + + xor ax, ax + int 33h + } +} + +void mouse_init() { + unsigned seg_mouse_callback = FP_SEG(mouse_callback); + unsigned off_mouse_callback = FP_OFF(mouse_callback); + unsigned int result; + asm { + xor ax, ax + int 33h + mov result, ax + } + if (result == 0) { + printf("Mouse driver not installed\n"); + exit(1); + } + atexit(mouse_cleanup); + + asm { + mov ax, seg_mouse_callback + mov es, ax + mov dx, off_mouse_callback + mov ax, 0ch + mov cx, 1fh + int 33h + } +} diff --git a/mouse.h b/mouse.h new file mode 100755 index 0000000..6dc02d1 --- /dev/null +++ b/mouse.h @@ -0,0 +1,13 @@ +/*** M O U S E ***/ +typedef struct { + unsigned int x; + unsigned int y; + unsigned int buttons; +} Mouse_t; + +extern Mouse_t MOUSE; + +void mouse_init(); + +#define mouse_hide() asm { mov ax, 02h; int 33h } +#define mouse_show() asm { mov ax, 01h; int 33h } diff --git a/testbed.c b/testbed.c index cd56ed1..aed83c2 100755 --- a/testbed.c +++ b/testbed.c @@ -2,677 +2,14 @@ #include #include -/*** V I D E O ***/ -#define setMode(hexval) asm { mov ax, hexval; int 10h } - -#define setVGAMode() setMode(0013h) -#define setEGAMode() setMode(000Dh) -#define setTextMode() setMode(0003h) - -#define REG_AC 0x03c0 -#define REG_TS 0x03c4 -#define REG_GDC 0x03ce -#define REG_CRTC 0x03d4 - -#define PLANE_B 0x00 -#define PLANE_G 0x01 -#define PLANE_R 0x02 -#define PLANE_I 0x03 -#define setPlane(p) outport(REG_TS, 2 | (0x100 << p)) -#define setAllPlanes() outport(REG_TS, 0x0f02) - -#define VID ((volatile char far *)MK_FP(0xa000, 0)) -#define WVID ((volatile int far *)MK_FP(0xa000, 0)) - -void vid_cleanup() { - setTextMode(); -} - -#define setWriteMode(m) outport(REG_GDC, 0x05 | m << 8) -void setSplitScreen(unsigned int y) { - int val; - outport(REG_CRTC, 0x18 | (y << 8)); - outp(REG_CRTC, 7); - val = inp(REG_CRTC + 1); - val &= ~0x10; - val |= (y & 0x100) >> 4; - outp(REG_CRTC + 1, val); - outp(REG_CRTC, 9); - val = inp(REG_CRTC + 1); - val &= ~0x40; - outp(REG_CRTC + 1, val); -} - -void unsetSplitScreen() { - outport(REG_CRTC, 0xff18); - outport(REG_CRTC, 0x1107); - outport(REG_CRTC, 0x0f09); -} - - -#define flipPage(p) outport(REG_CRTC, 0x0c | (p << 8)) - -void setDisplayOffset(unsigned int offset) { - outport(REG_CRTC, 0x0c | (offset & 0xff00)); - outport(REG_CRTC, 0x0d | (offset << 8)); -} - -void setHorizontalPan(int offset) { - inp(0x3da); // INPUT_STATUS_1? - outp(REG_AC, 0x13 | 0x20); - outp(REG_AC, offset); -} - -#define setLogicalWidth(w) outport(REG_CRTC, 0x13 | (w << 8)) - -/*** K E Y B O A R D ***/ -#define KBD_INT 0x09 -void interrupt (*oldKbdISR)() = NULL; - -void kbd_cleanup() { - if (oldKbdISR != NULL) { - setvect(KBD_INT, oldKbdISR); - oldKbdISR = NULL; - } -} - -volatile char keybuf[128]; -volatile char kbd_triggered = 0; - -void interrupt kbd_isr() { - unsigned char raw; - char ctl; - - asm sti; - raw = inp(0x60); - ctl = inp(0x61) | 0x82; - outp(0x61, ctl); - outp(0x61, ctl & 0x7f); - outp(0x20, 0x20); - - if (raw & 0x80) { - keybuf[raw & 0x7f] = 0; - } else { - keybuf[raw] = 1; - } - kbd_triggered = raw; -} - -#define K_ESC 1 -#define K_1 2 -#define K_2 3 -#define K_3 4 -#define K_4 5 -#define K_5 6 -#define K_6 7 -#define K_7 8 -#define K_8 9 -#define K_9 10 -#define K_0 11 -#define K_MINUS 12 -#define K_EQUAL 13 -#define K_BKSP 14 -#define K_TAB 15 -#define K_Q 16 -#define K_W 17 -#define K_E 18 -#define K_R 19 -#define K_T 20 -#define K_Y 21 -#define K_U 22 -#define K_I 23 -#define K_O 24 -#define K_P 25 -#define K_LBRK 26 -#define K_RBRK 27 -#define K_ENTER 28 -#define K_CTRL 29 -#define K_A 30 -#define K_S 31 -#define K_D 32 -#define K_F 33 -#define K_G 34 -#define K_H 35 -#define K_J 36 -#define K_K 37 -#define K_L 38 -#define K_SEMI 39 -#define K_APOS 40 -#define K_TILDE 41 -#define K_LSHFT 42 -#define K_BSLSH 43 -#define K_Z 44 -#define K_X 45 -#define K_C 46 -#define K_V 47 -#define K_B 48 -#define K_N 49 -#define K_M 50 -#define K_COMMA 51 -#define K_DOT 52 -#define K_SLASH 53 -#define K_RSHFT 54 -#define K_PSCRN 55 -#define K_ALT 56 -#define K_SPACE 57 -#define K_CAPS 58 -#define K_F1 59 -#define K_F2 60 -#define K_F3 61 -#define K_F4 62 -#define K_F5 63 -#define K_F6 64 -#define K_F7 65 -#define K_F8 66 -#define K_F9 67 -#define K_F10 68 -#define K_NUMLK 69 -#define K_SCRL 70 -#define K_HOME 71 -#define K_UP 72 -#define K_PGUP 73 -#define K_NDASH 74 -#define K_LEFT 75 -#define K_CENT 76 -#define K_RIGHT 77 -#define K_NPLUS 78 -#define K_END 79 -#define K_DOWN 80 -#define K_PGDN 81 -#define K_INS 82 -#define K_DEL 83 -#define K_F11 87 -#define K_F12 88 -#define keyPressed(k) keybuf[k] - -unsigned char kbd_wait() { - kbd_triggered = 0; - while (!kbd_triggered) {} - return kbd_triggered; -} - -void kbd_init() { - if (oldKbdISR == NULL) { - memset(keybuf, 0, 128); - oldKbdISR = getvect(KBD_INT); - setvect(KBD_INT, kbd_isr); - atexit(kbd_cleanup); - } -} - -/*** M O U S E ***/ -struct { - unsigned int x; - unsigned int y; - unsigned int buttons; -} MOUSE; - -void far mouse_callback() { - asm { - mov ax, DGROUP - mov ds, ax - shr cx, 1 - mov MOUSE.x, cx - mov MOUSE.y, dx - mov MOUSE.buttons, bx - } -} - -void mouse_cleanup() { - //uninstall handler - asm { - mov ax, 0ch - mov dx, 0 - mov es, dx - mov cx, 0 - int 33h - - xor ax, ax - int 33h - } -} - -void mouse_init() { - unsigned seg_mouse_callback = FP_SEG(mouse_callback); - unsigned off_mouse_callback = FP_OFF(mouse_callback); - unsigned int result; - asm { - xor ax, ax - int 33h - mov result, ax - } - if (result == 0) { - printf("Mouse driver not installed\n"); - exit(1); - } - atexit(mouse_cleanup); - - asm { - mov ax, seg_mouse_callback - mov es, ax - mov dx, off_mouse_callback - mov ax, 0ch - mov cx, 1fh - int 33h - } -} - -#define mouse_hide() asm { mov ax, 02h; int 33h } -#define mouse_show() asm { mov ax, 01h; int 33h } - -/*** T I F F ***/ -typedef struct { - unsigned int endian; - unsigned int version; - unsigned long ifdOffset; -} TifHeader_t; - -#define TIF_WIDTH 256 -#define TIF_HEIGHT 257 -#define TIF_BITSPERSAMPLE 258 -#define TIF_COMPRESSION 259 -#define TIF_STRIPOFFSETS 273 -#define TIF_ROWSPERSTRIP 278 - -typedef struct { - unsigned int id; - unsigned int dataType; - unsigned long dataCount; - unsigned long dataOffset; -} TifTag_t; - -typedef struct { - unsigned int width; - unsigned int height; - unsigned long rowsPerStrip; - unsigned long stripCount; - unsigned long stripOffsets; -} TifImageMeta_t; - -TifImageMeta_t tifLoadMeta(FILE *f) { - TifImageMeta_t meta = {0, 0, 0, 0, 0}; - TifHeader_t header; - TifTag_t tag; - unsigned int i, tagCount; - - fseek(f, 0, SEEK_SET); - fread(&header, 8, 1, f); - - if (header.endian != 0x4949 || header.version != 0x2a) { - goto fail; - } - fseek(f, header.ifdOffset, SEEK_SET); - fread(&tagCount, 2, 1, f); - for (i = 0; i < tagCount; i ++) { - fread(&tag, 12, 1, f); - if (tag.id == TIF_WIDTH) { - meta.width = tag.dataOffset; - } else if (tag.id == TIF_HEIGHT) { - meta.height = tag.dataOffset; - } else if (tag.id == TIF_BITSPERSAMPLE) { - if (tag.dataOffset != 4) goto fail; - } else if (tag.id == TIF_COMPRESSION) { - if (tag.dataOffset != 1) goto fail; - } else if (tag.id == TIF_STRIPOFFSETS) { - meta.stripCount = tag.dataCount; - meta.stripOffsets = tag.dataOffset; - } else if (tag.id == TIF_ROWSPERSTRIP) { - meta.rowsPerStrip = tag.dataOffset; - } - } - return meta; -fail: - meta.stripCount = 0; - return meta; -} - -#define MAX_WIDTH 320 - -int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w) { - int istrip; - int irow; - int ipixelpair; - int y = 0; - unsigned long offset; - unsigned char rowData[MAX_WIDTH >> 1]; - volatile unsigned char far *out = &VID[vidOffset]; - unsigned char b, g, r, i; - - if (meta.width > MAX_WIDTH || (meta.width % 16) != 0) { - return 0; - } - setWriteMode(0); - - for (istrip = 0; istrip < meta.stripCount; istrip ++) { - fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); - fread(&offset, 4, 1, f); - fseek(f, offset, SEEK_SET); - - for (irow = 0; irow < meta.rowsPerStrip; irow ++) { - int ipixelpairLim = meta.width >> 1; - fread(rowData, 1, ipixelpairLim, f); - b = g = r = i = 0; - for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { - unsigned char pixelpair = rowData[ipixelpair]; - int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; - int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; - int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; - int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; - int shift = (3 - (ipixelpair % 4)) << 1; - - b |= bpair << shift; - g |= gpair << shift; - r |= rpair << shift; - i |= ipair << shift; - - if (shift == 0 || ipixelpair == ipixelpairLim - 1) { - // todo: use write mode 2, this is slooww - setPlane(PLANE_B); *out = b; - setPlane(PLANE_R); *out = r; - setPlane(PLANE_G); *out = g; - setPlane(PLANE_I); *out = i; - out ++; - b = g = r = i = 0; - } - } - y++; - if (y == maxY) { - return y; - } - out += (w - meta.width) >> 3; - } - } - return y; -} - -int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int yRepeat, int planes) { - int istrip; - int irow; - int ipixelpair; - int y = 0; - unsigned long offset; - unsigned char rowData[MAX_WIDTH >> 1]; - unsigned int planeStride = (meta.width >> 4) * yRepeat; - unsigned int *bp = planeBuf; - unsigned int *gp = bp + planeStride; - unsigned int *rp = gp + planeStride; - unsigned int *ip = rp + planeStride; - unsigned int *mp = ip + planeStride; - unsigned int bv, gv, rv, iv; - - if (meta.width > MAX_WIDTH || (meta.width % 16) != 0 || planes < 4 || planes > 5) { - return 0; - } - - for (istrip = 0; istrip < meta.stripCount; istrip ++) { - fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); - fread(&offset, 4, 1, f); - fseek(f, offset, SEEK_SET); - - for (irow = 0; irow < meta.rowsPerStrip; irow ++) { - int ipixelpairLim = meta.width >> 1; - fread(rowData, 1, ipixelpairLim, f); - bv = gv = rv = iv = 0; - for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { - unsigned char pixelpair = rowData[ipixelpair]; - int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; - int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; - int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; - int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; - int shift = (7 - (ipixelpair % 8)) << 1; - - bv |= bpair << shift; - gv |= gpair << shift; - rv |= rpair << shift; - iv |= ipair << shift; - - if (shift == 0 || ipixelpair == ipixelpairLim - 1) { - *bp++ = bv; - *gp++ = gv; - *rp++ = rv; - *ip++ = iv; - if (planes == 5) { - iv = ~(bv & gv & rv & iv); - *mp++ = iv; - } - bv = gv = rv = iv = 0; - } - } - y++; - if (y == maxY) { - return y; - } - if (y % yRepeat == 0) { - bp += planeStride * (planes - 1); - gp += planeStride * (planes - 1); - rp += planeStride * (planes - 1); - ip += planeStride * (planes - 1); - mp += planeStride * (planes - 1); - } - } - } - return y; -} - -/*** T I L E S ***/ - -// Tiles are 16x16 bitmaps, stored as arrays of words. -// Each tile has 4 or 5 planes (depending on whether it is a tile or sprite) -// which are stored adjacant to each other; ie. a 16-word array of blue, -// followed by a 16-word array of green, etc. -// Tiles in RAM are stored byte-swapped to aid in fast bit-shifting, and must -// be byte-swapped before being written to video memory. - -// Because bit-shifting operations happen on little-endian words: -// 01234567 89ABCDEF << 3 => 34567XXX BCDEF012 -// which is wrong. So instead we do: -// 89ABCDEF 01234567 << 3 => BCDEFXXX 3456789A byteswap => 3456789A BCDEFXXX - -#define PAGE_TILES_W 21 -#define PAGE_TILES_H 14 -#define PAGE_TILES_COUNT (PAGE_TILES_H * PAGE_TILES_W) -#define PAGE_STRIDE (PAGE_TILES_W << 1) - -void tile_init() { - setLogicalWidth(PAGE_STRIDE >> 1); -} - -void blitTile(unsigned int offsetFrom, unsigned int offsetTo) { - int y; - for (y = 0; y < 16; y ++) { - VID[offsetTo] = VID[offsetFrom ++]; - VID[offsetTo + 1] = VID[offsetFrom ++]; - offsetTo += PAGE_STRIDE; - } -} - -#define D_NOTHING 0x80 -#define D_BGTILE 0x81 -#define isBufIndex(d) (!((d) & 0x80)) - -#define NUM_BUFFERS 32 -#define nextBufferIndex(i) ((i + 1) % 32) -#define BUF_WSTRIDE 16 -#define BUF_WSIZE (BUF_WSTRIDE * 4) -typedef struct { - unsigned int w; - unsigned int h; - int scrollX; - int scrollY; - unsigned int pageOffset[2]; - unsigned char dirty[2][PAGE_TILES_COUNT]; - unsigned int tilesOffset; - unsigned int *memTiles; - unsigned char *map; - unsigned int buffer[NUM_BUFFERS][BUF_WSIZE]; - unsigned int bufferOffset[NUM_BUFFERS]; - unsigned char currentPage; - unsigned char nextBuffer; - unsigned char firstBuffer; -} TiledScreen_t; - -TiledScreen_t screen = { 0, 0, 0, 0, { 0x0600, 0x2B00 }, 0, 0, NULL, NULL, - 0, 0, 0, 0, 0 }; - -void loadTiles(unsigned int tilesOffset, unsigned int *memTiles) { - screen.tilesOffset = tilesOffset; - screen.memTiles = memTiles; -} - -void loadMap(unsigned char *map, unsigned int w, unsigned int h) { - screen.map = map; - screen.w = w; - screen.h = h; - memset(screen.dirty, D_BGTILE, PAGE_TILES_COUNT * 2); -} - -int prepareBuffer(int pageX, int pageY) { - unsigned char *dirty = &screen.dirty[screen.currentPage][pageX + (pageY * PAGE_TILES_W)]; - if (!isBufIndex(*dirty)) { - unsigned int startX = screen.scrollX >> 4; - unsigned int startY = screen.scrollY >> 4; - unsigned char tile = screen.map[startX + pageX + ((startY + pageY) * screen.w)]; - unsigned char ibuffer = screen.nextBuffer; - screen.nextBuffer = nextBufferIndex(ibuffer); - *dirty = ibuffer; - memcpy(screen.buffer[ibuffer], &screen.memTiles[tile * BUF_WSIZE], BUF_WSIZE << 1); - screen.bufferOffset[ibuffer] = screen.pageOffset[screen.currentPage] - + (pageX << 1) + (pageY * PAGE_STRIDE * 16); - } - return *dirty; -} - -void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int yStart) { - unsigned int *buf, *mask; - unsigned int maskval; - int y, h, plane; - if (pageX < 0 || pageY < 0 || - pageX >= PAGE_TILES_W || pageY >= PAGE_TILES_H || - shift >= 16 || shift <= -16 || - yStart <= -16 || yStart >= 16) { - return; - } - - buf = screen.buffer[prepareBuffer(pageX, pageY)]; - if (yStart < 0) { - sprite = &sprite[-yStart]; - h = yStart + 16; - } else { - buf = &buf[yStart]; - h = 16 - yStart; - } - mask = &sprite[BUF_WSTRIDE * 4]; - if (shift < 0) { - shift = -shift; - for (plane = 0; plane < 4; plane ++) { - for (y = 0; y < h; y ++) { - maskval = mask[y] << shift; - buf[y] = (buf[y] & ~maskval) | ((sprite[y] << shift) & maskval); - } - sprite += BUF_WSTRIDE; - buf += BUF_WSTRIDE; - } - } else { - for (plane = 0; plane < 4; plane ++) { - for (y = 0; y < h; y ++) { - maskval = mask[y] >> shift; - buf[y] = (buf[y] & ~maskval) | ((sprite[y] >> shift) & maskval); - } - sprite += BUF_WSTRIDE; - buf += BUF_WSTRIDE; - } - } -} - -void drawSprite(unsigned int *sprite, int x, int y) { - int pageX = (int)(x - (screen.scrollX & 0xfff0)) >> 4; - int pageY = (int)(y - (screen.scrollY & 0xfff0)) >> 4; - int pageOffsetX = x & 0x0f; - int pageOffsetY = y & 0x0f; - - drawSpriteToBuf(sprite, pageX, pageY, pageOffsetX, pageOffsetY); - drawSpriteToBuf(sprite, pageX + 1, pageY, pageOffsetX - 16, pageOffsetY); - drawSpriteToBuf(sprite, pageX, pageY + 1, pageOffsetX, pageOffsetY - 16); - drawSpriteToBuf(sprite, pageX + 1, pageY + 1, pageOffsetX - 16, pageOffsetY - 16); -} - -void scroll(int newX, int newY) { - newX = min(max(newX, 0), (screen.w << 4) - 320); - newY = min(max(newY, 0), (screen.h << 4) - 200); - if ((screen.scrollX & 0xfff0) != (newX & 0xfff0) || - (screen.scrollY & 0xfff0) != (newY & 0xfff0)) { - int mapX, mapY; - unsigned char page; - for (page = 0; page < 2; page ++) { - int mapOffsetOld = (screen.scrollX >> 4) + ((screen.scrollY >> 4) * screen.w); - int mapOffsetNew = (newX >> 4) + ((newY >> 4) * screen.w); - unsigned char *dirty = screen.dirty[page]; - for (mapY = 0; mapY < PAGE_TILES_H; mapY ++) { - for (mapX = 0; mapX < PAGE_TILES_W; mapX ++) { - if (*dirty != D_NOTHING || - screen.map[mapOffsetOld + mapX] != screen.map[mapOffsetNew + mapX]) { - *dirty = D_BGTILE; - } - dirty ++; - } - mapOffsetNew += screen.w; - mapOffsetOld += screen.w; - } - } - } - screen.scrollX = newX; - screen.scrollY = newY; -} - -void drawScreen() { - unsigned int startX = screen.scrollX >> 4; - unsigned int startY = screen.scrollY >> 4; - unsigned int offsetX = screen.scrollX - (startX << 4); - unsigned int offsetY = screen.scrollY - (startY << 4); - unsigned int drawOffset = screen.pageOffset[screen.currentPage]; - unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE); - unsigned char *dirty = screen.dirty[screen.currentPage]; - unsigned int x, y, di, plane, bmp; - - setAllPlanes(); - setWriteMode(1); - - di = 0; - for (y = startY; y < startY + PAGE_TILES_H; y ++) { - for (x = startX; x < startX + PAGE_TILES_W; x ++) { - if (dirty[di++] == D_BGTILE) { - blitTile( - screen.tilesOffset + (screen.map[x + (y * screen.w)] << 5), - drawOffset); - } - drawOffset += 2; - } - drawOffset += PAGE_STRIDE * 15; - } - setWriteMode(0); - for(plane = 0; plane < 4; plane ++) { - setPlane(plane); - for (di = screen.firstBuffer; di != screen.nextBuffer; di = nextBufferIndex(di)) { - drawOffset = screen.bufferOffset[di] >> 1; - for (y = 0; y < 16; y ++) { - bmp = screen.buffer[di][y + (BUF_WSTRIDE * plane)]; - WVID[drawOffset] = (bmp << 8) | (bmp >> 8); - drawOffset += PAGE_STRIDE >> 1; - } - } - } - setAllPlanes(); - setDisplayOffset(scrollOffset); - setHorizontalPan(screen.scrollX & 0x07); - - screen.currentPage ^= 1; - screen.firstBuffer = screen.nextBuffer; - for (di = 0; di < PAGE_TILES_COUNT; di ++) { - dirty[di] = isBufIndex(dirty[di]) ? D_BGTILE : D_NOTHING; - } -} +#include "video.h" +#include "kbd.h" +#include "mouse.h" +#include "tiff.h" +#include "tiles.h" /*** S C R A T C H ***/ + #define NUM_TILES 128 #define NUM_SPRITES 64 #define OFF_TILES 0x5000 @@ -681,7 +18,6 @@ void drawScreen() { unsigned int tiles[NUM_TILES * TILE_STRIDE]; unsigned int sprites[NUM_SPRITES * SPRITE_STRIDE]; - unsigned char map[10000]; void fillMap() { @@ -719,16 +55,15 @@ void drawEntity(Entity_t *entity) { } void playerThink(Entity_t *self) { - if (keyPressed(K_LEFT)) { self->x -= 3; self->dir = DIR_W; } - if (keyPressed(K_RIGHT)) { self->x += 3; self->dir = DIR_E; } - if (keyPressed(K_UP)) { self->y -= 3; self->dir = DIR_N; } - if (keyPressed(K_DOWN)) { self->y += 3; self->dir = DIR_S; } + if (keyIsDown(K_LEFT)) { self->x -= 3; self->dir = DIR_W; } + if (keyIsDown(K_RIGHT)) { self->x += 3; self->dir = DIR_E; } + if (keyIsDown(K_UP)) { self->y -= 3; self->dir = DIR_N; } + if (keyIsDown(K_DOWN)) { self->y += 3; self->dir = DIR_S; } } typedef struct { int dy; int y; - int debounce; } Footer_t; typedef struct { @@ -756,6 +91,8 @@ void game_init() { setEGAMode(); atexit(vid_cleanup); + kbd_init(); + tile_init(); fillMap(); @@ -775,8 +112,6 @@ void game_init() { tifLoad(f, meta, sprites, NUM_SPRITES * 16, 16, 5); fclose(f); -// setSplitScreen(351); - loadTiles(OFF_TILES, tiles); loadMap(map, 100, 100); scroll(0, 0); @@ -784,22 +119,18 @@ void game_init() { int main() { game_init(); - kbd_init(); - while (!keyPressed(K_ESC)) { + while (!keyIsDown(K_ESC)) { + kbd_debounce(); if (game.state == STATE_MAP) { - if (keyPressed(K_SPACE)) { + if (keyWasPressed(K_SPACE)) { game.state = STATE_DIALOG; - game.footer.debounce = 1; game.footer.dy = 1; } playerThink(&game.player); scroll(game.player.x - 152, game.player.y - 92); } else if (game.state == STATE_DIALOG) { - if (game.footer.debounce && !keyPressed(K_SPACE)) { - game.footer.debounce = 0; - } - if (!game.footer.debounce && keyPressed(K_SPACE)) { + if (keyWasPressed(K_SPACE)) { game.footer.dy = -1; } game.footer.y += game.footer.dy; diff --git a/tiff.c b/tiff.c new file mode 100755 index 0000000..72ee169 --- /dev/null +++ b/tiff.c @@ -0,0 +1,187 @@ +#include +#include "tiff.h" +#include "video.h" + +/*** T I F F ***/ +typedef struct { + unsigned int endian; + unsigned int version; + unsigned long ifdOffset; +} TifHeader_t; + +#define TIF_WIDTH 256 +#define TIF_HEIGHT 257 +#define TIF_BITSPERSAMPLE 258 +#define TIF_COMPRESSION 259 +#define TIF_STRIPOFFSETS 273 +#define TIF_ROWSPERSTRIP 278 + +typedef struct { + unsigned int id; + unsigned int dataType; + unsigned long dataCount; + unsigned long dataOffset; +} TifTag_t; + +TifImageMeta_t tifLoadMeta(FILE *f) { + TifImageMeta_t meta = {0, 0, 0, 0, 0}; + TifHeader_t header; + TifTag_t tag; + unsigned int i, tagCount; + + fseek(f, 0, SEEK_SET); + fread(&header, 8, 1, f); + + if (header.endian != 0x4949 || header.version != 0x2a) { + goto fail; + } + fseek(f, header.ifdOffset, SEEK_SET); + fread(&tagCount, 2, 1, f); + for (i = 0; i < tagCount; i ++) { + fread(&tag, 12, 1, f); + if (tag.id == TIF_WIDTH) { + meta.width = tag.dataOffset; + } else if (tag.id == TIF_HEIGHT) { + meta.height = tag.dataOffset; + } else if (tag.id == TIF_BITSPERSAMPLE) { + if (tag.dataOffset != 4) goto fail; + } else if (tag.id == TIF_COMPRESSION) { + if (tag.dataOffset != 1) goto fail; + } else if (tag.id == TIF_STRIPOFFSETS) { + meta.stripCount = tag.dataCount; + meta.stripOffsets = tag.dataOffset; + } else if (tag.id == TIF_ROWSPERSTRIP) { + meta.rowsPerStrip = tag.dataOffset; + } + } + return meta; +fail: + meta.stripCount = 0; + return meta; +} + +int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w) { + int istrip; + int irow; + int ipixelpair; + int y = 0; + unsigned long offset; + unsigned char rowData[MAX_WIDTH >> 1]; + volatile unsigned char far *out = &VID[vidOffset]; + unsigned char b, g, r, i; + + if (meta.width > MAX_WIDTH || (meta.width % 16) != 0) { + return 0; + } + setWriteMode(0); + + for (istrip = 0; istrip < meta.stripCount; istrip ++) { + fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); + fread(&offset, 4, 1, f); + fseek(f, offset, SEEK_SET); + + for (irow = 0; irow < meta.rowsPerStrip; irow ++) { + int ipixelpairLim = meta.width >> 1; + fread(rowData, 1, ipixelpairLim, f); + b = g = r = i = 0; + for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { + unsigned char pixelpair = rowData[ipixelpair]; + int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; + int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; + int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; + int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; + int shift = (3 - (ipixelpair % 4)) << 1; + + b |= bpair << shift; + g |= gpair << shift; + r |= rpair << shift; + i |= ipair << shift; + + if (shift == 0 || ipixelpair == ipixelpairLim - 1) { + // todo: use write mode 2, this is slooww + setPlane(PLANE_B); *out = b; + setPlane(PLANE_R); *out = r; + setPlane(PLANE_G); *out = g; + setPlane(PLANE_I); *out = i; + out ++; + b = g = r = i = 0; + } + } + y++; + if (y == maxY) { + return y; + } + out += (w - meta.width) >> 3; + } + } + return y; +} + +int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int yRepeat, int planes) { + int istrip; + int irow; + int ipixelpair; + int y = 0; + unsigned long offset; + unsigned char rowData[MAX_WIDTH >> 1]; + unsigned int planeStride = (meta.width >> 4) * yRepeat; + unsigned int *bp = planeBuf; + unsigned int *gp = bp + planeStride; + unsigned int *rp = gp + planeStride; + unsigned int *ip = rp + planeStride; + unsigned int *mp = ip + planeStride; + unsigned int bv, gv, rv, iv; + + if (meta.width > MAX_WIDTH || (meta.width % 16) != 0 || planes < 4 || planes > 5) { + return 0; + } + + for (istrip = 0; istrip < meta.stripCount; istrip ++) { + fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); + fread(&offset, 4, 1, f); + fseek(f, offset, SEEK_SET); + + for (irow = 0; irow < meta.rowsPerStrip; irow ++) { + int ipixelpairLim = meta.width >> 1; + fread(rowData, 1, ipixelpairLim, f); + bv = gv = rv = iv = 0; + for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { + unsigned char pixelpair = rowData[ipixelpair]; + int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; + int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; + int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; + int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; + int shift = (7 - (ipixelpair % 8)) << 1; + + bv |= bpair << shift; + gv |= gpair << shift; + rv |= rpair << shift; + iv |= ipair << shift; + + if (shift == 0 || ipixelpair == ipixelpairLim - 1) { + *bp++ = bv; + *gp++ = gv; + *rp++ = rv; + *ip++ = iv; + if (planes == 5) { + iv = ~(bv & gv & rv & iv); + *mp++ = iv; + } + bv = gv = rv = iv = 0; + } + } + y++; + if (y == maxY) { + return y; + } + if (y % yRepeat == 0) { + bp += planeStride * (planes - 1); + gp += planeStride * (planes - 1); + rp += planeStride * (planes - 1); + ip += planeStride * (planes - 1); + mp += planeStride * (planes - 1); + } + } + } + return y; +} diff --git a/tiff.h b/tiff.h new file mode 100755 index 0000000..3e1101f --- /dev/null +++ b/tiff.h @@ -0,0 +1,17 @@ +#include + +/*** T I F F ***/ + +typedef struct { + unsigned int width; + unsigned int height; + unsigned long rowsPerStrip; + unsigned long stripCount; + unsigned long stripOffsets; +} TifImageMeta_t; + +#define MAX_WIDTH 320 + +TifImageMeta_t tifLoadMeta(FILE *f); +int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w); +int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int yRepeat, int planes); diff --git a/tiles.c b/tiles.c new file mode 100755 index 0000000..66ccc6a --- /dev/null +++ b/tiles.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include "video.h" + +/*** T I L E S ***/ + +// Tiles are 16x16 bitmaps, stored as arrays of words. +// Each tile has 4 or 5 planes (depending on whether it is a tile or sprite) +// which are stored adjacant to each other; ie. a 16-word array of blue, +// followed by a 16-word array of green, etc. +// Tiles in RAM are stored byte-swapped to aid in fast bit-shifting, and must +// be byte-swapped before being written to video memory. + +// Because bit-shifting operations happen on little-endian words: +// 01234567 89ABCDEF << 3 => 34567XXX BCDEF012 +// which is wrong. So instead we do: +// 89ABCDEF 01234567 << 3 => BCDEFXXX 3456789A byteswap => 3456789A BCDEFXXX + +#define PAGE_TILES_W 21 +#define PAGE_TILES_H 14 +#define PAGE_TILES_COUNT (PAGE_TILES_H * PAGE_TILES_W) +#define PAGE_STRIDE (PAGE_TILES_W << 1) + +void tile_init() { + setLogicalWidth(PAGE_STRIDE >> 1); +} + +void blitTile(unsigned int offsetFrom, unsigned int offsetTo) { + int y; + for (y = 0; y < 16; y ++) { + VID[offsetTo] = VID[offsetFrom ++]; + VID[offsetTo + 1] = VID[offsetFrom ++]; + offsetTo += PAGE_STRIDE; + } +} + +#define D_NOTHING 0x80 +#define D_BGTILE 0x81 +#define isBufIndex(d) (!((d) & 0x80)) + +#define NUM_BUFFERS 32 +#define nextBufferIndex(i) ((i + 1) % 32) +#define BUF_WSTRIDE 16 +#define BUF_WSIZE (BUF_WSTRIDE * 4) +typedef struct { + unsigned int w; + unsigned int h; + int scrollX; + int scrollY; + unsigned int pageOffset[2]; + unsigned char dirty[2][PAGE_TILES_COUNT]; + unsigned int tilesOffset; + unsigned int *memTiles; + unsigned char *map; + unsigned int buffer[NUM_BUFFERS][BUF_WSIZE]; + unsigned int bufferOffset[NUM_BUFFERS]; + unsigned char currentPage; + unsigned char nextBuffer; + unsigned char firstBuffer; +} TiledScreen_t; + +TiledScreen_t screen = { 0, 0, 0, 0, { 0x0600, 0x2B00 }, 0, 0, NULL, NULL, + 0, 0, 0, 0, 0 }; + +void loadTiles(unsigned int tilesOffset, unsigned int *memTiles) { + screen.tilesOffset = tilesOffset; + screen.memTiles = memTiles; +} + +void loadMap(unsigned char *map, unsigned int w, unsigned int h) { + screen.map = map; + screen.w = w; + screen.h = h; + memset(screen.dirty, D_BGTILE, PAGE_TILES_COUNT * 2); +} + +int prepareBuffer(int pageX, int pageY) { + unsigned char *dirty = &screen.dirty[screen.currentPage][pageX + (pageY * PAGE_TILES_W)]; + if (!isBufIndex(*dirty)) { + unsigned int startX = screen.scrollX >> 4; + unsigned int startY = screen.scrollY >> 4; + unsigned char tile = screen.map[startX + pageX + ((startY + pageY) * screen.w)]; + unsigned char ibuffer = screen.nextBuffer; + screen.nextBuffer = nextBufferIndex(ibuffer); + *dirty = ibuffer; + memcpy(screen.buffer[ibuffer], &screen.memTiles[tile * BUF_WSIZE], BUF_WSIZE << 1); + screen.bufferOffset[ibuffer] = screen.pageOffset[screen.currentPage] + + (pageX << 1) + (pageY * PAGE_STRIDE * 16); + } + return *dirty; +} + +void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int yStart) { + unsigned int *buf, *mask; + unsigned int maskval; + int y, h, plane; + if (pageX < 0 || pageY < 0 || + pageX >= PAGE_TILES_W || pageY >= PAGE_TILES_H || + shift >= 16 || shift <= -16 || + yStart <= -16 || yStart >= 16) { + return; + } + + buf = screen.buffer[prepareBuffer(pageX, pageY)]; + if (yStart < 0) { + sprite = &sprite[-yStart]; + h = yStart + 16; + } else { + buf = &buf[yStart]; + h = 16 - yStart; + } + mask = &sprite[BUF_WSTRIDE * 4]; + if (shift < 0) { + shift = -shift; + for (plane = 0; plane < 4; plane ++) { + for (y = 0; y < h; y ++) { + maskval = mask[y] << shift; + buf[y] = (buf[y] & ~maskval) | ((sprite[y] << shift) & maskval); + } + sprite += BUF_WSTRIDE; + buf += BUF_WSTRIDE; + } + } else { + for (plane = 0; plane < 4; plane ++) { + for (y = 0; y < h; y ++) { + maskval = mask[y] >> shift; + buf[y] = (buf[y] & ~maskval) | ((sprite[y] >> shift) & maskval); + } + sprite += BUF_WSTRIDE; + buf += BUF_WSTRIDE; + } + } +} + +void drawSprite(unsigned int *sprite, int x, int y) { + int pageX = (int)(x - (screen.scrollX & 0xfff0)) >> 4; + int pageY = (int)(y - (screen.scrollY & 0xfff0)) >> 4; + int pageOffsetX = x & 0x0f; + int pageOffsetY = y & 0x0f; + + drawSpriteToBuf(sprite, pageX, pageY, pageOffsetX, pageOffsetY); + drawSpriteToBuf(sprite, pageX + 1, pageY, pageOffsetX - 16, pageOffsetY); + drawSpriteToBuf(sprite, pageX, pageY + 1, pageOffsetX, pageOffsetY - 16); + drawSpriteToBuf(sprite, pageX + 1, pageY + 1, pageOffsetX - 16, pageOffsetY - 16); +} + +void scroll(int newX, int newY) { + newX = min(max(newX, 0), (screen.w << 4) - 320); + newY = min(max(newY, 0), (screen.h << 4) - 200); + if ((screen.scrollX & 0xfff0) != (newX & 0xfff0) || + (screen.scrollY & 0xfff0) != (newY & 0xfff0)) { + int mapX, mapY; + unsigned char page; + for (page = 0; page < 2; page ++) { + int mapOffsetOld = (screen.scrollX >> 4) + ((screen.scrollY >> 4) * screen.w); + int mapOffsetNew = (newX >> 4) + ((newY >> 4) * screen.w); + unsigned char *dirty = screen.dirty[page]; + for (mapY = 0; mapY < PAGE_TILES_H; mapY ++) { + for (mapX = 0; mapX < PAGE_TILES_W; mapX ++) { + if (*dirty != D_NOTHING || + screen.map[mapOffsetOld + mapX] != screen.map[mapOffsetNew + mapX]) { + *dirty = D_BGTILE; + } + dirty ++; + } + mapOffsetNew += screen.w; + mapOffsetOld += screen.w; + } + } + } + screen.scrollX = newX; + screen.scrollY = newY; +} + +void drawScreen() { + unsigned int startX = screen.scrollX >> 4; + unsigned int startY = screen.scrollY >> 4; + unsigned int offsetX = screen.scrollX - (startX << 4); + unsigned int offsetY = screen.scrollY - (startY << 4); + unsigned int drawOffset = screen.pageOffset[screen.currentPage]; + unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE); + unsigned char *dirty = screen.dirty[screen.currentPage]; + unsigned int x, y, di, plane, bmp; + + setAllPlanes(); + setWriteMode(1); + + di = 0; + for (y = startY; y < startY + PAGE_TILES_H; y ++) { + for (x = startX; x < startX + PAGE_TILES_W; x ++) { + if (dirty[di++] == D_BGTILE) { + blitTile( + screen.tilesOffset + (screen.map[x + (y * screen.w)] << 5), + drawOffset); + } + drawOffset += 2; + } + drawOffset += PAGE_STRIDE * 15; + } + setWriteMode(0); + for(plane = 0; plane < 4; plane ++) { + setPlane(plane); + for (di = screen.firstBuffer; di != screen.nextBuffer; di = nextBufferIndex(di)) { + drawOffset = screen.bufferOffset[di] >> 1; + for (y = 0; y < 16; y ++) { + bmp = screen.buffer[di][y + (BUF_WSTRIDE * plane)]; + WVID[drawOffset] = (bmp << 8) | (bmp >> 8); + drawOffset += PAGE_STRIDE >> 1; + } + } + } + setAllPlanes(); + setDisplayOffset(scrollOffset); + setHorizontalPan(screen.scrollX & 0x07); + + screen.currentPage ^= 1; + screen.firstBuffer = screen.nextBuffer; + for (di = 0; di < PAGE_TILES_COUNT; di ++) { + dirty[di] = isBufIndex(dirty[di]) ? D_BGTILE : D_NOTHING; + } +} diff --git a/tiles.h b/tiles.h new file mode 100755 index 0000000..98b83fb --- /dev/null +++ b/tiles.h @@ -0,0 +1,9 @@ +/*** T I L E S ***/ + +void tile_init(); + +void loadTiles(unsigned int tilesOffset, unsigned int *memTiles); +void loadMap(unsigned char *map, unsigned int w, unsigned int h); +void drawSprite(unsigned int *sprite, int x, int y); +void scroll(int newX, int newY); +void drawScreen(); diff --git a/video.c b/video.c new file mode 100755 index 0000000..39710c4 --- /dev/null +++ b/video.c @@ -0,0 +1,39 @@ +#include +#include "video.h" + +void vid_cleanup() { + setTextMode(); +} + +void setSplitScreen(unsigned int y) { + int val; + outport(REG_CRTC, 0x18 | (y << 8)); + outp(REG_CRTC, 7); + val = inp(REG_CRTC + 1); + val &= ~0x10; + val |= (y & 0x100) >> 4; + outp(REG_CRTC + 1, val); + outp(REG_CRTC, 9); + val = inp(REG_CRTC + 1); + val &= ~0x40; + outp(REG_CRTC + 1, val); +} + +void unsetSplitScreen() { + outport(REG_CRTC, 0xff18); + outport(REG_CRTC, 0x1107); + outport(REG_CRTC, 0x0f09); +} + + +void setDisplayOffset(unsigned int offset) { + outport(REG_CRTC, 0x0c | (offset & 0xff00)); + outport(REG_CRTC, 0x0d | (offset << 8)); +} + +void setHorizontalPan(int offset) { + inp(0x3da); // INPUT_STATUS_1? + outp(REG_AC, 0x13 | 0x20); + outp(REG_AC, offset); +} + diff --git a/video.h b/video.h new file mode 100755 index 0000000..491a177 --- /dev/null +++ b/video.h @@ -0,0 +1,34 @@ +/*** V I D E O ***/ +#define setMode(hexval) asm { mov ax, hexval; int 10h } + +#define setVGAMode() setMode(0013h) +#define setEGAMode() setMode(000Dh) +#define setTextMode() setMode(0003h) + +#define REG_AC 0x03c0 +#define REG_TS 0x03c4 +#define REG_GDC 0x03ce +#define REG_CRTC 0x03d4 + +#define PLANE_B 0x00 +#define PLANE_G 0x01 +#define PLANE_R 0x02 +#define PLANE_I 0x03 +#define setPlane(p) outport(REG_TS, 2 | (0x100 << p)) +#define setAllPlanes() outport(REG_TS, 0x0f02) + +#define setWriteMode(m) outport(REG_GDC, 0x05 | m << 8) + +#define VID ((volatile char far *)MK_FP(0xa000, 0)) +#define WVID ((volatile int far *)MK_FP(0xa000, 0)) + +#define flipPage(p) outport(REG_CRTC, 0x0c | (p << 8)) + +#define setLogicalWidth(w) outport(REG_CRTC, 0x13 | (w << 8)) + +void vid_cleanup(); +void setSplitScreen(unsigned int y); +void unsetSplitScreen(); +void setDisplayOffset(unsigned int offset); +void setHorizontalPan(int offset); +