neuttower/testbed.c

762 lines
17 KiB
C
Executable file

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <alloc.h>
#include <ctype.h>
#include "video.h"
#include "kbd.h"
#include "mouse.h"
#include "tiff.h"
#include "tiles.h"
#include "serial.h"
#include "timer.h"
#include "jorth.h"
#include "egamap.h"
#include "adlib.h"
/*** T E X T ***/
char far *font = NULL;
void text_init() {
unsigned int fontSeg, fontOff;
asm {
push es
push bp
mov ah, 11h
mov al, 30h
mov bh, 3
int 10h
mov ax, bp
pop bp
mov fontSeg, es
mov fontOff, ax
pop es
}
font = MK_FP(fontSeg, fontOff);
}
void text_draw_char(unsigned int vidOffset, unsigned char c) {
unsigned int fontOffset = c << 3;
int i;
for (i = 0; i < 8; i ++) {
VID[vidOffset] = font[fontOffset++];
vidOffset += PAGE_STRIDE;
}
}
void text_draw(unsigned int vidOffset, unsigned char *s) {
while (*s) {
text_draw_char(vidOffset++, *s++);
}
}
/*** I / O ***/
size_t fwritefar(FILE *fp, void far *buf, size_t length) {
char nearbuf[32];
size_t written = 0;
size_t towrite;
for (; towrite = min(32, length), length > 0; length -= towrite) {
movedata(FP_SEG(buf), FP_OFF(buf) + written, _SS, nearbuf, towrite);
if (!fwrite(nearbuf, towrite, 1, fp)) {
break;
}
written += towrite;
}
return written;
}
size_t freadfar(FILE *fp, void far *buf, size_t length) {
char nearbuf[32];
size_t totalread = 0;
size_t toread;
for (; toread = min(32, length), length > 0; length -= toread) {
size_t bytesread = fread(nearbuf, 1, toread, fp);
movedata(_SS, nearbuf, FP_SEG(buf), FP_OFF(buf) + totalread, bytesread);
totalread += bytesread;
if (bytesread != toread) {
break;
}
}
return totalread;
}
/*** S C R A T C H ***/
#define PORTRAIT_GFX
#define NUM_SPRITES 64
#define TILE_STRIDE 64
#define SPRITE_STRIDE 80
#define PORTRAIT_STRIDE 256
unsigned int far *tiles;
unsigned int far *sprites;
unsigned int far *portraits;
unsigned char map[10000];
void deallocate_gfx() {
if (tiles) farfree(tiles);
if (sprites) farfree(sprites);
if (portraits) farfree(portraits);
}
void allocate_gfx() {
unsigned long memleft = farcoreleft();
tiles = farmalloc(NUM_TILES * TILE_STRIDE * 2);
sprites = farmalloc(NUM_SPRITES * SPRITE_STRIDE * 2);
portraits = farmalloc(NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
atexit(deallocate_gfx);
if (!tiles || !sprites || !portraits) {
printf("%lu bytes free - need %lu\n", memleft,
(unsigned long)
((NUM_TILES * TILE_STRIDE * 2) +
(NUM_SPRITES * SPRITE_STRIDE * 2) +
(NUM_PORTRAITS * PORTRAIT_STRIDE * 2)));
exit(1);
}
}
void fillMap() {
unsigned int x, y, z;
z = 0;
for (y = 0; y < 100; y ++) {
for (x = 0; x < 100; x ++) {
map[x + (y * 100)] = ((x + y + z) >> 2) % 4;
}
}
}
void readTifTiles(char *filename) {
FILE *f;
TifImageMeta_t meta;
f = fopen(filename, "rb");
meta = tifLoadMeta(f);
tifLoad(f, meta, tiles, NUM_TILES * 16, 16, 4);
fclose(f);
loadTiles(OFF_TILES, tiles);
}
void readTiles(char *filename) {
FILE *f = fopen(filename, "rb");
freadfar(f, tiles, NUM_TILES * TILE_STRIDE * 2);
fclose(f);
loadTiles(OFF_TILES, tiles);
}
void f_loadtiles() {
if (tolower(TOP().s[strlen(TOP().s) - 1]) == 'f') {
readTifTiles(TOP().s);
} else {
readTiles(TOP().s);
}
DROP(1);
}
void f_load_footer() {
FILE *f = fopen("FOOTER.TIF", "rb");
TifImageMeta_t meta = tifLoadMeta(f);
tifLoadEGA(f, meta, 0, 48, 336);
fclose(f);
}
void f_reloadportraits() {
blitMemToVid(OFF_PORTRAITS, portraits, PORTRAIT_STRIDE >> 2, NUM_PORTRAITS);
}
void game_init() {
FILE *f;
TifImageMeta_t meta;
allocate_gfx();
mouse_init();
setEGAMode();
atexit(vid_cleanup);
kbd_init();
timer_init(TIMER_30HZ);
text_init();
tile_init();
fillMap();
f_load_footer();
f = fopen("sprite.gfx", "rb");
freadfar(f, sprites, NUM_SPRITES * SPRITE_STRIDE * 2);
fclose(f);
#ifdef PORTRAIT_GFX
f = fopen("portrait.gfx", "rb");
freadfar(f, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
fclose(f);
f_reloadportraits();
#else
f = fopen("PORTRAIT.TIF", "rb");
meta = tifLoadMeta(f);
tifLoad(f, meta, portraits, NUM_PORTRAITS * 32, 32, 4);
tifLoadEGA(f, meta, OFF_PORTRAITS, NUM_PORTRAITS * 32, 32);
fclose(f);
#endif
readTiles("tiles.gfx");
loadMap(map, 100, 100);
scroll(0, 0);
}
void f_seremit() {
ser_write_byte(TOP().i);
if (TOP().i == '\n') {
ser_write_byte('\r');
}
DROP(1);
}
void f_keyWasPressed() {
int k = TOP().i;
TOP().i = keyWasPressed(k);
consumeKey(k);
}
void f_keyIsDown() {
TOP().i = keyIsDown(TOP().i);
}
void f_drawSprite() { // ( x y sprite -- )
if (TOP().i >= 0) {
drawSprite(&sprites[TOP().i * SPRITE_STRIDE], ST2().i, ST1().i, NULL);
}
DROP(3);
}
void f_scroll() { // ( x y -- )
scroll(ST1().i, TOP().i);
DROP(2);
}
void f_scrollpos() { // ( -- x y )
PUSHI(screen.scrollX);
PUSHI(screen.scrollY);
}
void f_ticks() {
PUSHU(timer_counter);
}
void f_splitscreen() {
setSplitScreen(399 - (TOP().i << 1));
DROP(1);
}
void f_textc() { // ( col line c color -- )
setWriteMode(0);
setPlaneColor(TOP().u);
DROP(1);
text_draw_char(ST2().u + (ST1().u * PAGE_STRIDE), TOP().i);
DROP(3);
}
void f_text() { // ( col line s color -- )
setWriteMode(0);
setPlaneColor(TOP().u);
DROP(1);
text_draw(ST2().u + (ST1().u * PAGE_STRIDE), TOP().s);
DROP(3);
}
void f_map() {
PUSHP(map);
}
void f_mapsize() { // ( -- w h )
PUSHI(screen.w);
PUSHI(screen.h);
}
void f_mapsize_set() { // ( w h -- )
loadMap(map, ST1().i, TOP().i);
DROP(2);
}
void f_mousepos() { // ( -- x y )
PUSHI(MOUSE.x);
PUSHI(MOUSE.y);
}
void f_mousebuttons() {
PUSHI(MOUSE.buttons);
}
void f_drawportrait() {
setAllPlanes();
setWriteMode(1);
blit32x32(OFF_PORTRAITS + (TOP().u << 7), (PAGE_STRIDE << 3) + 1);
DROP(1);
}
void f_adlib() {
adlib_write(TOP().u, ST1().u);
DROP(2);
}
cell f_atexit;
void f_cleanup() {
f_execcp(f_atexit);
}
void f_glitch() {
int count = TOP().u;
int i, x, y;
DROP(1);
for (i = 0; i < count; i ++) {
x = screen.scrollX + (rand() % 352) - 16;
y = screen.scrollY + (rand() % 232) - 16;
switch(rand()%2) {
case 0:
drawSprite(sprites + (rand() % (NUM_SPRITES * SPRITE_STRIDE)), x, y, NULL);
break;
case 1:
drawSprite(mem + (rand() % MEM_SIZE), x, y, NULL);
break;
}
}
}
/* JILES */
#define SCREEN_STRIDE 40
typedef enum {
ET_SPRITE = 0,
ET_TILE = 1,
ET_PORTRAIT = 2
} EditTarget_t;
EditTarget_t editTarget = ET_SPRITE;
unsigned int far *getTarget(int index) {
if (editTarget == ET_SPRITE) {
return &sprites[index * SPRITE_STRIDE];
} else if (editTarget == ET_TILE) {
return &tiles[index * TILE_STRIDE];
} else {
return &portraits[index * PORTRAIT_STRIDE];
}
}
#define ET_STRIDE (editTarget == ET_SPRITE ? SPRITE_STRIDE : \
(editTarget == ET_TILE ? TILE_STRIDE : PORTRAIT_STRIDE))
int getsprpixel(int x, int y, unsigned int far *spr) {
int shift = (15 - (x % 16));
int plane_stride = 16;
int b, g, r, i, v;
if (editTarget == ET_PORTRAIT) {
y = y << 1;
if (x > 15) y ++;
plane_stride = 64;
}
spr += y;
b = (*spr & (1 << shift)) >> shift; spr += plane_stride;
g = (*spr & (1 << shift)) >> shift; spr += plane_stride;
r = (*spr & (1 << shift)) >> shift; spr += plane_stride;
i = (*spr & (1 << shift)) >> shift; spr += plane_stride;
v = editTarget != ET_SPRITE || (*spr & (1 << shift)) ? 0 : 1;
return b | (g << 1) | (r << 2) | (i << 3) | (v << 4);
}
int resetEnabledCache = 0;
#define setResetEnabledCached(m) \
if (resetEnabledCache != m) { \
resetEnabledCache = m; \
setResetEnabled(m); \
}
void drawFatBox(int x, int y, int color) {
int faty;
int fill1 = color <= 0x0f ? 0xff : 0x55;
int fill2 = fill1 == 0xff ? 0xff : 0xaa;
unsigned int dst = SCREEN_STRIDE * y;
if (color > 0x0f) {
setResetEnabledCached(0);
} else {
setResetEnabledCached(0x0f);
setResetMask(color);
}
for ( faty = 0; faty < 8; faty ++) {
VID[dst + x + (SCREEN_STRIDE * faty)] = (faty % 2) ? fill1 : fill2;
}
}
void drawDoubleFatBox(int x, int y, int colorl, int colorr) {
int faty, plane;
unsigned int dst = (SCREEN_STRIDE * y) + x;
setResetEnabledCached(0);
for ( plane = 0; plane < 4; plane ++ ) {
int fill = colorr & ( 1 << plane ) ? 0x0f : 0x00;
fill |= colorl & ( 1 << plane ) ? 0xf0 : 0x00;
setPlane( plane );
for ( faty = 0; faty < 4; faty ++ ) {
VID[dst + (SCREEN_STRIDE * faty)] = fill;
}
}
}
void f_drawfatsprite() {
int isprite = TOP().i;
unsigned int far *spr = getTarget(isprite);
int x, y;
DROP(1);
if (editTarget != ET_PORTRAIT) {
setAllPlanes();
for ( y = 0; y < 16; y ++ ) {
for ( x = 0; x < 16; x ++ ) {
int color = getsprpixel(x, y, spr);
drawFatBox(x, y << 3, color);
}
}
} else {
for ( y = 0; y < 32; y ++ ) {
for ( x = 0; x < 32; x += 2 ) {
int colorl = getsprpixel( x, y, spr);
int colorr = getsprpixel(x + 1, y, spr);
drawDoubleFatBox(x >> 1, y << 2, colorl, colorr);
}
}
setAllPlanes();
}
}
void f_drawfatbox() {
drawFatBox(ST1().i, TOP().i, ST2().i);
DROP(3);
}
void f_savegfx() {
FILE *fp = fopen(TOP().s, "wb");
if (editTarget == ET_SPRITE) {
fwritefar(fp, sprites, NUM_SPRITES * SPRITE_STRIDE * 2);
} else if (editTarget == ET_TILE) {
fwritefar(fp, tiles, NUM_TILES * TILE_STRIDE * 2);
} else {
fwritefar(fp, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
}
fclose(fp);
DROP(1);
}
void f_mousehide() {
mouse_hide();
}
void f_mouseshow() {
mouse_show();
}
void f_resetvideo() {
setLogicalWidth(SCREEN_STRIDE >> 1);
setResetEnabledCached(0);
setWriteMode(0);
setAllPlanes();
setDisplayOffset(0);
setHorizontalPan(0);
}
void f_putpixel() {
int isprite = TOP().i;
unsigned int far *spr = getTarget(isprite);
int x = ST2().i;
int y = ST1().i;
int color, shift, b, g, r, i, v;
int plane_stride = 16;
DROP(3);
color = TOP().i;
DROP(1);
shift = (15 - (x % 16));
if (editTarget == ET_PORTRAIT) {
y = y << 1;
if (x > 15) y ++;
plane_stride = 64;
}
b = (color & 0x01);
g = (color & 0x02) >> 1;
r = (color & 0x04) >> 2;
i = (color & 0x08) >> 3;
v = ((color & 0x10) >> 4) ^ 1;
spr = &spr[y];
*spr = (*spr & ~(1 << shift)) | (b << shift); spr += plane_stride;
*spr = (*spr & ~(1 << shift)) | (g << shift); spr += plane_stride;
*spr = (*spr & ~(1 << shift)) | (r << shift); spr += plane_stride;
*spr = (*spr & ~(1 << shift)) | (i << shift); spr += plane_stride;
if (editTarget == ET_SPRITE) {
*spr = (*spr & ~(1 << shift)) | (v << shift);
}
}
void f_getpixel() {
int isprite = TOP().i;
unsigned int far *spr = getTarget(isprite);
int x = ST2().i;
int y = ST1().i;
DROP(2);
TOP().i = getsprpixel(x, y, spr);
}
void f_spritecount() {
if (editTarget == ET_SPRITE) {
PUSHI(NUM_SPRITES);
} else if (editTarget == ET_TILE) {
PUSHI(NUM_TILES);
} else if (editTarget == ET_PORTRAIT) {
PUSHI(NUM_PORTRAITS);
}
}
void f_tile2buf() {
unsigned int *buf = (unsigned int *)TOP().p;
unsigned int itile = ST1().u;
DROP(2);
writeTile(buf, &tiles[itile * TILE_STRIDE]);
}
void f_spr2buf() {
unsigned int *buf = (unsigned int *)TOP().p;
unsigned int isprite = ST1().u;
DROP(2);
overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, NULL);
}
void f_remap_spr2buf() {
unsigned int *buf = (unsigned int *)TOP().p;
unsigned int isprite = ST1().u;
char *remap = (char*)ST2().p;
DROP(3);
overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, remap);
}
void f_pastetile() {
unsigned int far *src = getTarget(ST1().i);
unsigned int far *dst = getTarget(TOP().i);
unsigned int stride = ET_STRIDE;
unsigned int i;
DROP(2);
for (i = 0; i < stride; i ++) {
dst[i] = src[i];
}
}
void f_fliptile() {
unsigned int far *dst = getTarget(TOP().i);
unsigned int stride = ET_STRIDE;
unsigned int i;
unsigned int bit;
DROP(1);
for (i = 0; i < stride; i ++) {
unsigned int src = dst[i];
unsigned int result = 0;
for (bit = 0; bit < 16; bit ++) {
if (src & (1 << bit)) {
result |= (1 << (15 - bit));
}
}
if (editTarget == ET_PORTRAIT && ((i % 2) == 1)) {
bit = dst[i - 1];
dst[i - 1] = result;
dst[i] = bit;
} else {
dst[i] = result;
}
}
}
void f_vfliptile() {
unsigned int far *dst;
unsigned int far *gfx = editTarget == ET_SPRITE ? sprites : tiles;
unsigned int stride = editTarget == ET_SPRITE ? SPRITE_STRIDE : TILE_STRIDE;
unsigned int y;
unsigned int plane;
if (editTarget == ET_PORTRAIT) return; // TODO
dst = &gfx[TOP().i * stride];
DROP(1);
for (plane = 0; plane < (editTarget == ET_SPRITE ? 5 : 4); plane ++) {
for (y = 0; y < 8; y ++) {
unsigned int tmp = dst[y];
dst[y] = dst[15 - y];
dst[15 - y] = tmp;
}
dst += 16;
}
}
void f_nudgesprite() {
unsigned int far *dst = &sprites[TOP().i * SPRITE_STRIDE];
int direction = ST1().i < 0 ? -1 : 1;
int ystart = direction < 0 ? 0 : 15;
int ylim = direction < 0 ? 15 : 0;
int plane, y;
unsigned int itransparent = direction < 0 ? 64 : 79;
DROP(2);
if (dst[itransparent] != 0 || editTarget != ET_SPRITE) {
return;
}
for (plane = 0; plane < 5; plane ++) {
for (y = ystart; y != ylim; y -= direction) {
dst[y] = dst[y - direction];
}
dst[ylim] = 0;
dst += 16;
}
}
void f_paintbuf() {
unsigned int *buf = (unsigned int *)TOP().p;
int y = ST1().i;
int x = ST2().i;
DROP(3);
paintBuffer(buf, x + (y * SCREEN_STRIDE));
}
void f_setedittarget() {
editTarget = TOP().i;
}
void f_getedittarget() {
PUSHI(editTarget);
}
void f_reloadtiles() {
loadTiles(OFF_TILES, tiles);
}
/* INIT */
void game_f_init(char *exe, char *bootjor) {
f_init(exe);
CDEF("seremit", f_seremit);
CDEF("key-pressed", f_keyWasPressed);
CDEF("key-down", f_keyIsDown);
CDEF("key-start", kbd_init);
CDEF("key-end", kbd_cleanup);
CDEF("draw-sprite", f_drawSprite);
CDEF("draw-portrait", f_drawportrait);
CDEF("scroll", f_scroll);
CDEF("scrollpos", f_scrollpos);
CDEF("draw-screen", drawScreen);
CDEF("split-screen", f_splitscreen);
CDEF("ticks", f_ticks);
CDEF("text", f_text);
CDEF("textc", f_textc);
CDEF("map", f_map);
CDEF("mapsize", f_mapsize);
CDEF("mapsize!", f_mapsize_set);
CDEF("mousepos", f_mousepos);
CDEF("mousebuttons", f_mousebuttons);
CDEF("loadtiles", f_loadtiles);
CDEF("glitch", f_glitch);
CDEF("unfuck", tile_init);
CDEF("load-footer", f_load_footer);
CDEF("fuck", f_resetvideo);
CDEF("mouseshow", f_mouseshow);
CDEF("mousehide", f_mousehide);
CDEF("drawfatsprite", f_drawfatsprite);
CDEF("drawfatbox", f_drawfatbox);
CDEF("putpixel", f_putpixel);
CDEF("getpixel", f_getpixel);
CDEF("spritecount", f_spritecount);
CDEF("savegfx", f_savegfx);
CDEF("tile>buf", f_tile2buf);
CDEF("spr>buf", f_spr2buf);
CDEF("remap-spr>buf", f_remap_spr2buf);
CDEF("paintbuf", f_paintbuf);
CDEF("edittarget", f_getedittarget);
CDEF("edittarget!", f_setedittarget);
CDEF("reloadtiles", f_reloadtiles);
CDEF("reloadportraits", f_reloadportraits);
CDEF("paste-tile", f_pastetile);
CDEF("flip-tile", f_fliptile);
CDEF("vflip-tile", f_vfliptile);
CDEF("nudge-sprite", f_nudgesprite);
f_loadjor(bootjor);
f_atexit = f_lookupcp("atexit");
atexit(f_cleanup);
}
void f_poll() {
static char line[128] = { 0 };
while (ser_getline(line)) {
PUSHS(line);
f_runstring("REPL send");
f_taskloop();
line[0] = '\0';
}
}
int DONE = 0;
static void f_quit() {
DONE = 1;
}
void do_repl(char *exe) {
char buf[128];
f_init(exe);
CDEF("quit", f_quit);
CDEF("adlib", f_adlib);
f_loadfile("repl.jor");
f_taskloop();
while (!DONE) {
PUSHS(gets(buf));
f_runstring("REPL send");
f_taskloop();
}
}
int main(int argc, char *argv[]) {
cell tick, draw;
char *bootjor = "gameboot.jor";
if (argc > 1) {
bootjor = argv[1];
}
ser_init(SER_COM2, BAUD_19200, SER_8N1);
game_init();
game_f_init(argv[0], bootjor);
tick = f_lookupcp("tick");
draw = f_lookupcp("draw");
while (!keyIsDown(K_ESC)) {
kbd_debounce();
f_poll();
f_taskloop();
f_execcp(tick);
f_taskloop();
f_execcp(draw);
}
return 0;
}