Initial commit
This commit is contained in:
commit
1b87ca8aa3
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.obj
|
||||||
|
*.bak
|
||||||
|
|
511
testbed.c
Executable file
511
testbed.c
Executable file
|
@ -0,0 +1,511 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int b[16];
|
||||||
|
unsigned int g[16];
|
||||||
|
unsigned int r[16];
|
||||||
|
unsigned int i[16];
|
||||||
|
} Tile_t;
|
||||||
|
|
||||||
|
unsigned int PAGE[] = { 0x00, 0x20, 0x40, 0x60 };
|
||||||
|
// todo: HIGH BITS??
|
||||||
|
#define setWriteMode(m) outport(REG_GDC, 0x05 | m << 8)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void blitTile(Tile_t *tile, int plane, unsigned int page, unsigned int x, unsigned int y) {
|
||||||
|
unsigned int *data = tile->b + (plane << 4);
|
||||||
|
volatile unsigned int far *out = (volatile unsigned int far *)
|
||||||
|
&VID[(y * 640) + (x << 1) + (page << 8)];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 320; i += 20) {
|
||||||
|
out[i] = *(data++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 = (ipixelpair % 4) << 1;
|
||||||
|
|
||||||
|
b |= bpair << shift;
|
||||||
|
g |= gpair << shift;
|
||||||
|
r |= rpair << shift;
|
||||||
|
i |= ipair << shift;
|
||||||
|
|
||||||
|
if (shift == 6 || 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();
|
||||||
|
|
||||||
|
f = fopen("TILES.TIF", "rb");
|
||||||
|
meta = tifLoadMeta(f);
|
||||||
|
tifLoadEGA(f, meta, OFF_TILES, 256);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
mouse_init();
|
||||||
|
kbd_init();
|
||||||
|
atexit(vid_cleanup);
|
||||||
|
|
||||||
|
while (!keyPressed(K_ESC)) {
|
||||||
|
page ^= 0x20;
|
||||||
|
|
||||||
|
prepareEgaMemCopy();
|
||||||
|
drawOffset = page << 8;
|
||||||
|
for (y = 0; y < 13; 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);
|
||||||
|
|
||||||
|
kbd_wait();
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
testbed.exe
Executable file
BIN
testbed.exe
Executable file
Binary file not shown.
Loading…
Reference in a new issue