pete286/testbed.c

566 lines
12 KiB
C
Raw Normal View History

2019-01-05 21:16:08 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
/*** 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();
}
#define setWriteMode(m) outport(REG_GDC, 0x05 | m << 8)
2019-01-07 02:29:20 +00:00
void setSplitScreen(unsigned int y) {
2019-01-19 04:02:50 +00:00
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);
2019-01-07 02:29:20 +00:00
}
2019-01-19 04:02:50 +00:00
2019-01-07 02:29:20 +00:00
void unsetSplitScreen() {
outport(REG_CRTC, 0xff18);
outport(REG_CRTC, 0x1107);
2019-01-19 04:02:50 +00:00
outport(REG_CRTC, 0x0f09);
2019-01-07 02:29:20 +00:00
}
2019-01-05 21:16:08 +00:00
#define flipPage(p) outport(REG_CRTC, 0x0c | (p << 8))
2019-01-19 04:02:50 +00:00
void setDisplayOffset(unsigned int offset) {
outport(REG_CRTC, 0x0c | (offset & 0xff00));
outport(REG_CRTC, 0x0d | (offset << 8));
}
#define setLogicalWidth(w) outport(REG_CRTC, 0x13 | (w << 8))
2019-01-05 21:16:08 +00:00
/*** 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
2019-01-19 04:02:50 +00:00
int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w) {
2019-01-05 21:16:08 +00:00
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;
2019-01-07 02:29:20 +00:00
int shift = (3 - (ipixelpair % 4)) << 1;
2019-01-05 21:16:08 +00:00
b |= bpair << shift;
g |= gpair << shift;
r |= rpair << shift;
i |= ipair << shift;
2019-01-07 02:29:20 +00:00
if (shift == 0 || ipixelpair == ipixelpairLim - 1) {
2019-01-05 21:16:08 +00:00
// 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;
}
2019-01-19 04:02:50 +00:00
out += (w - meta.width) >> 3;
2019-01-05 21:16:08 +00:00
}
}
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;
}
2019-01-19 04:02:50 +00:00
/*** T I L E S ***/
void prepareEgaMemCopy() {
setAllPlanes();
setWriteMode(1);
}
2019-01-05 21:16:08 +00:00
2019-01-19 04:02:50 +00:00
#define PAGE_STRIDE 42
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;
2019-01-05 21:16:08 +00:00
}
2019-01-19 04:02:50 +00:00
}
typedef struct {
unsigned int w;
unsigned int h;
int scrollX;
int scrollY;
unsigned int pageOffset;
unsigned char *tiles;
} TilePage_t;
#define OFF_TILES 0x4840
void scrollPage(TilePage_t *page, int x, int y) {
x = min(max(x, 0), (page->w << 4) - 320);
y = min(max(y, 0), (page->h << 4) - 176);
page->scrollX = x;
page->scrollY = y;
}
void drawPage(TilePage_t *page) {
unsigned int startX = page->scrollX >> 4;
unsigned int startY = page->scrollY >> 4;
unsigned int offsetX = page->scrollX - (startX << 4);
unsigned int offsetY = page->scrollY - (startY << 4);
unsigned int drawOffset = page->pageOffset;
unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE);
unsigned int x, y;
prepareEgaMemCopy();
for (y = startY; y < startY + 13; y ++) {
for (x = startX; x < startX + 21; x ++) {
blitTile(OFF_TILES + page->tiles[x + (y * page->w)], drawOffset);
drawOffset += 2;
}
drawOffset += PAGE_STRIDE * 15;
2019-01-05 21:16:08 +00:00
}
2019-01-19 04:02:50 +00:00
setDisplayOffset(scrollOffset);
}
/*** S C R A T C H ***/
unsigned char tiles[10000];
TilePage_t pages[2] = {
{ 100, 100, 0, 0, 0x0400, tiles },
{ 100, 100, 0, 0, 0x2620, tiles }
};
void fillTiles() {
unsigned int x, y, z;
z = 0;
for (y = 0; y < 100; y ++) {
for (x = 0; x < 100; x ++) {
tiles[x + (y * 100)] = (((x + y + z) >> 2) % 3) << 5;
}
2019-01-05 21:16:08 +00:00
}
}
int main() {
FILE *f;
TifImageMeta_t meta;
int plane;
int x;
int y;
int z = 0;
unsigned int drawOffset;
unsigned int page = 0;
setEGAMode();
2019-01-07 02:29:20 +00:00
atexit(vid_cleanup);
f = fopen("FOOTER.TIF", "rb");
meta = tifLoadMeta(f);
2019-01-19 04:02:50 +00:00
tifLoadEGA(f, meta, 0, 24, 336);
2019-01-07 02:29:20 +00:00
fclose(f);
2019-01-05 21:16:08 +00:00
f = fopen("TILES.TIF", "rb");
meta = tifLoadMeta(f);
2019-01-19 04:02:50 +00:00
tifLoadEGA(f, meta, OFF_TILES, 256, 16);
2019-01-05 21:16:08 +00:00
fclose(f);
kbd_init();
2019-01-19 04:02:50 +00:00
tile_init();
setSplitScreen(351);
fillTiles();
2019-01-05 21:16:08 +00:00
while (!keyPressed(K_ESC)) {
2019-01-07 02:29:20 +00:00
page ^= 1;
2019-01-05 21:16:08 +00:00
2019-01-19 04:02:50 +00:00
x = pages[page].scrollX;
y = pages[page].scrollY;
if (keyPressed(K_LEFT)) x -= 4;
if (keyPressed(K_RIGHT)) x += 4;
if (keyPressed(K_UP)) y -= 4;
if (keyPressed(K_DOWN)) y += 4;
scrollPage(&pages[0], x, y);
scrollPage(&pages[1], x, y);
drawPage(&pages[page]);
// kbd_wait();
2019-01-05 21:16:08 +00:00
z++;
}
return 0;
}