From eeb1e86cba2c7cc4b8e140f34931078068b1e7a6 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Thu, 24 Jan 2019 21:36:42 -0500 Subject: [PATCH] Refactor into seperate modules & Turbo C++ project --- .gitignore | 3 +- game.exe | Bin 0 -> 66544 bytes game.prj | Bin 0 -> 4416 bytes kbd.c | 75 ++++++ kbd.h | 106 ++++++++ mouse.c | 55 +++++ mouse.h | 13 + testbed.c | 701 ++--------------------------------------------------- tiff.c | 187 ++++++++++++++ tiff.h | 17 ++ tiles.c | 222 +++++++++++++++++ tiles.h | 9 + video.c | 39 +++ video.h | 34 +++ 14 files changed, 775 insertions(+), 686 deletions(-) create mode 100755 game.exe create mode 100755 game.prj create mode 100755 kbd.c create mode 100755 kbd.h create mode 100755 mouse.c create mode 100755 mouse.h create mode 100755 tiff.c create mode 100755 tiff.h create mode 100755 tiles.c create mode 100755 tiles.h create mode 100755 video.c create mode 100755 video.h 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 0000000000000000000000000000000000000000..93502fbf4d15f6776f90cb19c7681782a054473d GIT binary patch literal 66544 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 Y{>*RQm8l?aW+9K3BKt4bq-?(b2idEfN&o-= literal 0 HcmV?d00001 diff --git a/game.prj b/game.prj new file mode 100755 index 0000000000000000000000000000000000000000..b40dde2be5c42541f68744ca930e3b6214abaf5a GIT binary patch literal 4416 zcmeH~+f!Rr6vo#M2?-_k^^Q+F4LT9t??E}5eo&mRJ2O5 zwc2`V)#*RLRNs7Y#z$X#aHbdUI=(oLXWNrw=@BDjB*sRb%=Aqd-Gf6Jqd`=4O}%Om@do9p=c2eo$t6(averM={6x2W zs`bx6$N60I3(YTe`&XJ@gJtp!xLbb0Sn@OR3vmTdzf${+_?`HJ_!Cf9sr^MbgebH@ zM3n*JCOkwr+q}R!AJAU`7?prj5vz!5Vl|-FP`in^nW!OZi8?^7CHyq&iCc(uL<4av zaT}o4Q)>juHqbO^Zc)t9gD%*I069SIAtFUQOgut7N<2n9PNa!GqMyhR2Z;gV2|xy^ z4H3gM4-+FaM~SCsj!_$@HbG1hN7(i>wJB=P5YG}viRS=0Lp)D&nm9(x5HAqNi4%al zNbMx?63v&1Q#4N#uMn>iuMw{kXNfn6H;K21ttyNZEniGEBcWX>JCusVLcROKmhdXA zw9L<;H_|1%N-wR-E!%@4+muIwZHOO)vaPjMWVJ$4oJxTm1Uy#+mXqon?A388|_5N6>xs3IxHFYozxJ7Sd*FPG__y;fog z6C4=Jj4r`#$u3(DZ!rQia(6GkAhHy%ycMj!+un(S%fSSiZ=1XEK`aUNP-0(fvltfr!x(Hv%g?b}{oQ zw$DXJvKgEXXVQ}c1Nk#36aB>oxp6-uVC}bJozYTnG&i12@vWEUQ;6@rgZSjjTZA$( z3XkF={iEl9C54wA{yP3I%gR8TT;T_^eEUvE4EfYTI~w1Yw6F!?O-to;wihcNY+_z< zqkD~fhghTKH~_%<0GA!tyv{Ub#~U&H&LlV8Jt2nI5hTj&HW3T_ld)vxhim@ z_K%qV literal 0 HcmV?d00001 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); +