#include #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_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)) void vid_cleanup() { setTextMode(); } typedef struct { unsigned int b[16]; unsigned int g[16]; unsigned int r[16]; unsigned int i[16]; } Tile_t; unsigned int PAGE[] = { 0x04, 0x24 }; #define setWriteMode(m) outport(REG_GDC, 0x05 | m << 8) void setSplitScreen(unsigned int y) { // TODO: VGA registers?? outport(REG_CRTC, 0x1018);// | y << 8); outport(REG_CRTC, 0x0107); } void unsetSplitScreen() { outport(REG_CRTC, 0xff18); outport(REG_CRTC, 0x1107); } void prepareEgaMemCopy() { setAllPlanes(); setWriteMode(1); } #define PAGE_STRIDE 40 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 flipPage(p) outport(REG_CRTC, 0x0c | (p << 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) { 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; } } } return y; } int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int yRepeat) { 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 *b = planeBuf - 1; unsigned int *g = b + planeStride; unsigned int *r = g + planeStride; unsigned int *i = r + planeStride; if (meta.width > MAX_WIDTH || (meta.width % 16) != 0) { 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 ++) { fread(rowData, 1, meta.width >> 1, f); for (ipixelpair = 0; ipixelpair < meta.width >> 1; 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 = (ipixelpair % 8) << 1; if (shift == 0) { *++b = bpair; *++g = gpair; *++r = rpair; *++i = ipair; } else { *b |= bpair << shift; *g |= gpair << shift; *r |= rpair << shift; *i |= ipair << shift; } } y++; if (y == maxY) { return y; } if (y % yRepeat == 0) { b += planeStride * 3; g += planeStride * 3; r += planeStride * 3; i += planeStride * 3; } } } return y; } /*** S C R A T C H ***/ void paintPattern(int r, int g, int b, int t) { int i; setPlane(PLANE_R); for (i = 0; i < 8000; i ++) { VID[i] = r; } setPlane(PLANE_G); for (i = 0; i < 8000; i ++) { VID[i] = g; } setPlane(PLANE_B); for (i = 0; i < 8000; i ++) { VID[i] = b; } setPlane(PLANE_I); for (i = 0; i < 8000; i ++) { VID[i] = t; } } int main() { Tile_t tiles[16]; FILE *f; TifImageMeta_t meta; int plane; int x; int y; int z = 0; unsigned int drawOffset; unsigned int page = 0; #define OFF_TILES 0x4200 setEGAMode(); atexit(vid_cleanup); f = fopen("FOOTER.TIF", "rb"); meta = tifLoadMeta(f); tifLoadEGA(f, meta, 0, 24); fclose(f); f = fopen("TILES.TIF", "rb"); meta = tifLoadMeta(f); tifLoadEGA(f, meta, OFF_TILES, 256); fclose(f); mouse_init(); kbd_init(); while (!keyPressed(K_ESC)) { page ^= 1; prepareEgaMemCopy(); drawOffset = PAGE[page] << 8; for (y = 0; y < 11; y ++) { for (x = 0; x < 20; x ++) { blitTile(OFF_TILES + ((((x + y + z) >> 2) % 3) << 5), drawOffset); drawOffset += 2; } drawOffset += 600; // 40 bytes per line * 15 more lines } flipPage(PAGE[page]); setSplitScreen(16); kbd_wait(); z++; } return 0; }