diff --git a/presets/sound_williams-z80/swave.c b/presets/sound_williams-z80/swave.c index 08872c17..0540d595 100644 --- a/presets/sound_williams-z80/swave.c +++ b/presets/sound_williams-z80/swave.c @@ -44,23 +44,16 @@ const char WAVES[] = { const sbyte* wav; SoundEffect e; -const SoundEffect DEFAULT_SOUND = { - 2000, 0, 3000, -1, 0x40, 0 +const SoundEffect SOUNDS[] = { + { 2000, 0, 3000, -1, 0x40, 0 } }; void play(); void main() { if (command == 0) HALT; - memcpy(&e, &DEFAULT_SOUND, sizeof(e)); + memcpy(&e, &SOUNDS[command-1], sizeof(e)); play(); - /* - char i; - char j; - for (i=0; i<255; i++) { - for (j=0; j +#include +#include typedef unsigned char byte; -typedef signed char sbyte; typedef unsigned short word; -typedef enum { false, true } bool; +typedef signed char sbyte; -byte __at (0x0) vidmem[152][256]; // 304x256x4bpp video memory -byte __at (0xc000) palette[16]; -volatile byte __at (0xc804) input0; -volatile byte __at (0xc806) input1; -volatile byte __at (0xc80c) input2; -byte __at (0xc900) rom_select; -volatile byte __at (0xcb00) video_counter; -byte __at (0xcbff) watchdog0x39; -byte __at (0xcc00) nvram[0x400]; +word __at(0xa000) dvgram[0x1000]; +byte __at(0x8840) _dvgstart; -__sfr __at (0) debug; +volatile int __at(0x8100) mathbox_sum; +sbyte __at(0x8102) mathbox_arg1; +sbyte __at(0x8103) mathbox_arg2; +byte __at(0x810f) mathbox_go_mul; -// blitter flags -#define SRCSCREEN 0x1 -#define DSTSCREEN 0x2 -#define ESYNC 0x4 -#define FGONLY 0x8 -#define SOLID 0x10 -#define RSHIFT 0x20 -#define EVENONLY 0x40 -#define ODDONLY 0x80 +volatile byte __at (0x8000) input0; +volatile byte __at (0x8001) input1; +volatile byte __at (0x8002) input2; +volatile byte __at (0x800f) vidframe; +byte __at (0x8980) watchdog; -struct { - byte flags; - byte solid; - word sstart; - word dstart; - byte width; - byte height; -} __at (0xca00) blitter; - -// switch flags -#define UP1 (input0 & 0x1) -#define DOWN1 (input0 & 0x2) -#define LEFT1 (input0 & 0x4) -#define RIGHT1 (input0 & 0x8) -#define START1 (input0 & 0x10) -#define START2 (input0 & 0x20) -#define UP2 (input0 & 0x40) -#define DOWN2 (input0 & 0x80) -#define LEFT2 (input1 & 0x1) -#define RIGHT2 (input1 & 0x2) -#define AUTOUP (input2 & 0x1) -#define ADVANCE (input2 & 0x2) -#define COIN2 (input2 & 0x4) -#define HIGHSCORERESET (input2 & 0x8) -#define COIN1 (input2 & 0x10) -#define COIN3 (input2 & 0x20) -#define TILTSWITCH (input2 & 0x40) -#define SOUNDACK (input2 & 0x80) - -#define WATCHDOG watchdog0x39=0x39; +#define LEFT1 !(input1 & 0x8) +#define RIGHT1 !(input1 & 0x4) +#define UP1 !(input1 & 0x10) +#define DOWN1 !(input1 & 0x20) +#define FIRE1 !(input1 & 0x2) +#define BOMB1 !(input1 & 0x1) +#define COIN1 (input0 & 0x2) +#define COIN2 (input0 & 0x1) +#define START1 (input2 & 0x20) +#define START2 (input2 & 0x40) // void main(); void _sdcc_heap_init(void); // for malloc() -// start routine @ 0x0 -// set stack pointer, enable interrupts void start() { __asm - LD SP,#0xc000 + LD SP,#0x0 DI ; copy initialized data LD BC, #l__INITIALIZER @@ -77,486 +48,321 @@ __asm LD HL, #s__INITIALIZER LDIR __endasm; - + // init heap for malloc() and run main pgm. _sdcc_heap_init(); main(); } -#define LOCHAR 0x21 -#define HICHAR 0x5e +// VECTOR ROUTINES -const byte font8x8[HICHAR-LOCHAR+1][8] = { -{ 0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00 }, { 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x66,0x66,0xff,0x66,0xff,0x66,0x66,0x00 }, { 0x18,0x3e,0x60,0x3c,0x06,0x7c,0x18,0x00 }, { 0x62,0x66,0x0c,0x18,0x30,0x66,0x46,0x00 }, { 0x3c,0x66,0x3c,0x38,0x67,0x66,0x3f,0x00 }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x00 }, { 0x3c,0x66,0x6e,0x76,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x38,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x06,0x0c,0x30,0x60,0x7e,0x00 }, { 0x3c,0x66,0x06,0x1c,0x06,0x66,0x3c,0x00 }, { 0x06,0x0e,0x1e,0x66,0x7f,0x06,0x06,0x00 }, { 0x7e,0x60,0x7c,0x06,0x06,0x66,0x3c,0x00 }, { 0x3c,0x66,0x60,0x7c,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x0c,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x3c,0x66,0x06,0x0c,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x6e,0x6e,0x60,0x62,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00 }, { 0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00 }, { 0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00 }, { 0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00 }, { 0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00 }, { 0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00 }, { 0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00 }, { 0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00 }, { 0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00 }, { 0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 } -}; +int dvgwrofs; // write offset for DVG buffer -static byte font_table[HICHAR-LOCHAR+1][8*4]; - -void fill_char_table_entry(char ch) { - const byte* src = &font8x8[ch-LOCHAR][0]; - byte* data = &font_table[ch-LOCHAR][0]; - int i,j,pixels; - for (i=0; i<8; i++) { - byte b = *src++; - for (j=0; j<4; j++) { - pixels = 0; - if (b & 0x80) pixels |= 0xf0; - if (b & 0x40) pixels |= 0x0f; - *data++ = pixels; - b <<= 2; - } - } - WATCHDOG; -} - -void fill_char_table() { - char ch; - for (ch=LOCHAR; ch<=HICHAR; ch++) { - fill_char_table_entry(ch); - } -} - -inline word swapw(word j) { +inline word ___swapw(word j) { return ((j << 8) | (j >> 8)); } -// x1: 0-151 -// y1: 0-255 -inline void blit_solid(byte x1, byte y1, byte w, byte h, byte color) { - blitter.width = w^4; - blitter.height = h^4; - blitter.dstart = x1+y1*256; // swapped - blitter.solid = color; - blitter.flags = DSTSCREEN|SOLID; +inline void dvgreset() { + dvgwrofs = 0; } -inline void draw_solid(word x1, byte y1, byte w, byte h, byte color) { - blitter.width = w^4; - blitter.height = h^4; - blitter.dstart = (x1>>1)+y1*256; // swapped - blitter.solid = color; - blitter.flags = (x1&1) ? DSTSCREEN|SOLID|RSHIFT : DSTSCREEN|SOLID; +inline void dvgstart() { + _dvgstart = 0; } -inline void draw_vline(word x1, byte y1, byte h, byte color) { - blitter.width = 1^4; - blitter.height = h^4; - blitter.dstart = (x1>>1)+y1*256; // swapped - blitter.solid = color; - blitter.flags = (x1&1) ? DSTSCREEN|SOLID|ODDONLY : DSTSCREEN|SOLID|EVENONLY; +void dvgwrite(word w) { + dvgram[dvgwrofs++] = w; } -inline void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) { - blitter.width = w^4; - blitter.height = h^4; - blitter.sstart = swapw((word)data); - blitter.dstart = x1+y1*256; // swapped - blitter.flags = DSTSCREEN|FGONLY; +inline void VCTR(int dx, int dy, byte bright) { + dvgwrite((dy & 0x1fff)); + dvgwrite(((bright & 7) << 13) | (dx & 0x1fff)); } -inline void blit_copy_solid(byte x1, byte y1, byte w, byte h, const byte* data, byte solid) { - blitter.width = w^4; - blitter.height = h^4; - blitter.sstart = swapw((word)data); - blitter.dstart = x1+y1*256; // swapped - blitter.solid = solid; - blitter.flags = DSTSCREEN|FGONLY|SOLID; +inline void SVEC(signed char dx, signed char dy, byte bright) { + dvgwrite(0x4000 | (dx & 0x1f) | ((bright&7)<<5) | ((dy & 0x1f)<<8)); } -// bias sprites by +12 pixels -#define XBIAS 6 - -inline void draw_sprite(const byte* data, byte x, byte y) { - blitter.width = data[0]^4; - blitter.height = data[1]^4; - blitter.sstart = swapw((word)(data+2)); - blitter.dstart = (x>>1)+y*256+XBIAS; // swapped - blitter.flags = (x&1) ? DSTSCREEN|FGONLY|RSHIFT : DSTSCREEN|FGONLY; +inline void JSRL(word offset) { + dvgwrite(0xa000 | offset); } -inline void draw_sprite_solid(const byte* data, byte x, byte y, byte color) { - blitter.width = data[0]^4; - blitter.height = data[1]^4; - blitter.sstart = swapw((word)(data+2)); - blitter.dstart = (x>>1)+y*256+XBIAS; // swapped - blitter.solid = color; - blitter.flags = (x&1) ? DSTSCREEN|FGONLY|RSHIFT|SOLID : DSTSCREEN|FGONLY|SOLID; +inline void JMPL(word offset) { + dvgwrite(0xe000 | offset); } -void draw_sprite_strided(const byte* data, byte x, byte y, byte stride) { +inline void RTSL() { + dvgwrite(0xc000); +} + +inline void CNTR() { + dvgwrite(0x8000); +} + +inline void HALT() { + dvgwrite(0x2000); +} + +inline void STAT(byte rgb, byte intens) { + dvgwrite(0x6000 | ((intens & 0xf)<<4) | (rgb & 7)); +} + +inline void STAT_sparkle(byte intens) { + dvgwrite(0x6800 | ((intens & 0xf)<<4)); +} + +inline void SCAL(word scale) { + dvgwrite(0x7000 | scale); +} + +enum { + BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE +} Color; + + +/// https://trmm.net/Asteroids_font + +#define P(x,y) ((((x) & 0xF) << 4) | (((y) & 0xF) << 0)) +#define FONT_UP 0xFE +#define FONT_LAST 0xFF + +const byte vecfont[95][8] = { + ['0' - 0x20] = { P(0,0), P(8,0), P(8,12), P(0,12), P(0,0), P(8,12), FONT_LAST }, + ['1' - 0x20] = { P(4,0), P(4,12), P(3,10), FONT_LAST }, + ['2' - 0x20] = { P(0,12), P(8,12), P(8,7), P(0,5), P(0,0), P(8,0), FONT_LAST }, + ['3' - 0x20] = { P(0,12), P(8,12), P(8,0), P(0,0), FONT_UP, P(0,6), P(8,6), FONT_LAST }, + ['4' - 0x20] = { P(0,12), P(0,6), P(8,6), FONT_UP, P(8,12), P(8,0), FONT_LAST }, + ['5' - 0x20] = { P(0,0), P(8,0), P(8,6), P(0,7), P(0,12), P(8,12), FONT_LAST }, + ['6' - 0x20] = { P(0,12), P(0,0), P(8,0), P(8,5), P(0,7), FONT_LAST }, + ['7' - 0x20] = { P(0,12), P(8,12), P(8,6), P(4,0), FONT_LAST }, + ['8' - 0x20] = { P(0,0), P(8,0), P(8,12), P(0,12), P(0,0), FONT_UP, P(0,6), P(8,6), }, + ['9' - 0x20] = { P(8,0), P(8,12), P(0,12), P(0,7), P(8,5), FONT_LAST }, + [' ' - 0x20] = { FONT_LAST }, + ['.' - 0x20] = { P(3,0), P(4,0), FONT_LAST }, + [',' - 0x20] = { P(2,0), P(4,2), FONT_LAST }, + ['-' - 0x20] = { P(2,6), P(6,6), FONT_LAST }, + ['+' - 0x20] = { P(1,6), P(7,6), FONT_UP, P(4,9), P(4,3), FONT_LAST }, + ['!' - 0x20] = { P(4,0), P(3,2), P(5,2), P(4,0), FONT_UP, P(4,4), P(4,12), FONT_LAST }, + ['#' - 0x20] = { P(0,4), P(8,4), P(6,2), P(6,10), P(8,8), P(0,8), P(2,10), P(2,2) }, + ['^' - 0x20] = { P(2,6), P(4,12), P(6,6), FONT_LAST }, + ['=' - 0x20] = { P(1,4), P(7,4), FONT_UP, P(1,8), P(7,8), FONT_LAST }, + ['*' - 0x20] = { P(0,0), P(4,12), P(8,0), P(0,8), P(8,8), P(0,0), FONT_LAST }, + ['_' - 0x20] = { P(0,0), P(8,0), FONT_LAST }, + ['/' - 0x20] = { P(0,0), P(8,12), FONT_LAST }, + ['\\' - 0x20] = { P(0,12), P(8,0), FONT_LAST }, + ['@' - 0x20] = { P(8,4), P(4,0), P(0,4), P(0,8), P(4,12), P(8,8), P(4,4), P(3,6) }, + ['$' - 0x20] = { P(6,2), P(2,6), P(6,10), FONT_UP, P(4,12), P(4,0), FONT_LAST }, + ['&' - 0x20] = { P(8,0), P(4,12), P(8,8), P(0,4), P(4,0), P(8,4), FONT_LAST }, + ['[' - 0x20] = { P(6,0), P(2,0), P(2,12), P(6,12), FONT_LAST }, + [']' - 0x20] = { P(2,0), P(6,0), P(6,12), P(2,12), FONT_LAST }, + ['(' - 0x20] = { P(6,0), P(2,4), P(2,8), P(6,12), FONT_LAST }, + [')' - 0x20] = { P(2,0), P(6,4), P(6,8), P(2,12), FONT_LAST }, + ['{' - 0x20] = { P(6,0), P(4,2), P(4,10), P(6,12), FONT_UP, P(2,6), P(4,6), FONT_LAST }, + ['}' - 0x20] = { P(4,0), P(6,2), P(6,10), P(4,12), FONT_UP, P(6,6), P(8,6), FONT_LAST }, + ['%' - 0x20] = { P(0,0), P(8,12), FONT_UP, P(2,10), P(2,8), FONT_UP, P(6,4), P(6,2) }, + ['<' - 0x20] = { P(6,0), P(2,6), P(6,12), FONT_LAST }, + ['>' - 0x20] = { P(2,0), P(6,6), P(2,12), FONT_LAST }, + ['|' - 0x20] = { P(4,0), P(4,5), FONT_UP, P(4,6), P(4,12), FONT_LAST }, + [':' - 0x20] = { P(4,9), P(4,7), FONT_UP, P(4,5), P(4,3), FONT_LAST }, + [';' - 0x20] = { P(4,9), P(4,7), FONT_UP, P(4,5), P(1,2), FONT_LAST }, + ['"' - 0x20] = { P(2,10), P(2,6), FONT_UP, P(6,10), P(6,6), FONT_LAST }, + ['\'' - 0x20] = { P(2,6), P(6,10), FONT_LAST }, + ['`' - 0x20] = { P(2,10), P(6,6), FONT_LAST }, + ['~' - 0x20] = { P(0,4), P(2,8), P(6,4), P(8,8), FONT_LAST }, + ['?' - 0x20] = { P(0,8), P(4,12), P(8,8), P(4,4), FONT_UP, P(4,1), P(4,0), FONT_LAST }, + ['A' - 0x20] = { P(0,0), P(0,8), P(4,12), P(8,8), P(8,0), FONT_UP, P(0,4), P(8,4) }, + ['B' - 0x20] = { P(0,0), P(0,12), P(4,12), P(8,10), P(4,6), P(8,2), P(4,0), P(0,0) }, + ['C' - 0x20] = { P(8,0), P(0,0), P(0,12), P(8,12), FONT_LAST }, + ['D' - 0x20] = { P(0,0), P(0,12), P(4,12), P(8,8), P(8,4), P(4,0), P(0,0), FONT_LAST }, + ['E' - 0x20] = { P(8,0), P(0,0), P(0,12), P(8,12), FONT_UP, P(0,6), P(6,6), FONT_LAST }, + ['F' - 0x20] = { P(0,0), P(0,12), P(8,12), FONT_UP, P(0,6), P(6,6), FONT_LAST }, + ['G' - 0x20] = { P(6,6), P(8,4), P(8,0), P(0,0), P(0,12), P(8,12), FONT_LAST }, + ['H' - 0x20] = { P(0,0), P(0,12), FONT_UP, P(0,6), P(8,6), FONT_UP, P(8,12), P(8,0) }, + ['I' - 0x20] = { P(0,0), P(8,0), FONT_UP, P(4,0), P(4,12), FONT_UP, P(0,12), P(8,12) }, + ['J' - 0x20] = { P(0,4), P(4,0), P(8,0), P(8,12), FONT_LAST }, + ['K' - 0x20] = { P(0,0), P(0,12), FONT_UP, P(8,12), P(0,6), P(6,0), FONT_LAST }, + ['L' - 0x20] = { P(8,0), P(0,0), P(0,12), FONT_LAST }, + ['M' - 0x20] = { P(0,0), P(0,12), P(4,8), P(8,12), P(8,0), FONT_LAST }, + ['N' - 0x20] = { P(0,0), P(0,12), P(8,0), P(8,12), FONT_LAST }, + ['O' - 0x20] = { P(0,0), P(0,12), P(8,12), P(8,0), P(0,0), FONT_LAST }, + ['P' - 0x20] = { P(0,0), P(0,12), P(8,12), P(8,6), P(0,5), FONT_LAST }, + ['Q' - 0x20] = { P(0,0), P(0,12), P(8,12), P(8,4), P(0,0), FONT_UP, P(4,4), P(8,0) }, + ['R' - 0x20] = { P(0,0), P(0,12), P(8,12), P(8,6), P(0,5), FONT_UP, P(4,5), P(8,0) }, + ['S' - 0x20] = { P(0,2), P(2,0), P(8,0), P(8,5), P(0,7), P(0,12), P(6,12), P(8,10) }, + ['T' - 0x20] = { P(0,12), P(8,12), FONT_UP, P(4,12), P(4,0), FONT_LAST }, + ['U' - 0x20] = { P(0,12), P(0,2), P(4,0), P(8,2), P(8,12), FONT_LAST }, + ['V' - 0x20] = { P(0,12), P(4,0), P(8,12), FONT_LAST }, + ['W' - 0x20] = { P(0,12), P(2,0), P(4,4), P(6,0), P(8,12), FONT_LAST }, + ['X' - 0x20] = { P(0,0), P(8,12), FONT_UP, P(0,12), P(8,0), FONT_LAST }, + ['Y' - 0x20] = { P(0,12), P(4,6), P(8,12), FONT_UP, P(4,6), P(4,0), FONT_LAST }, + ['Z' - 0x20] = { P(0,12), P(8,12), P(0,0), P(8,0), FONT_UP, P(2,6), P(6,6), FONT_LAST }, +}; + +void draw_char(char ch) { + const byte* p = vecfont[ch-0x20]; + byte bright = 0; + byte x = 0; + byte y = 0; byte i; - byte width = data[0]; - byte height = data[1]; - byte yy = y-(height*(stride-1)/2); - word dest = (x>>1)+yy*256+XBIAS; - blitter.width = width^4; - blitter.height = 1^4; - for (i=0; i>4; + byte y2 = b&15; + SVEC((char)(x2-x), (char)(y2-y), bright); + bright = 2; + x = x2; + y = y2; } - dest += stride << 8; - data += width; + } + SVEC((char)12-x, (char)-y, 0); +} + +static word font_shapes[95]; + +void make_cached_font() { + char ch; + for (ch=0; ch<95; ch++) { + watchdog = 0; + font_shapes[ch] = dvgwrofs; + draw_char(ch+0x20); + RTSL(); } } -void erase_sprite_strided(const byte* data, byte x, byte y, byte stride) { - byte i; - byte width = data[0]; - byte height = data[1]; - byte yy = y-(height*(stride-1)/2); - word dest = (x>>1)+yy*256+XBIAS; - blitter.width = width^4; - blitter.height = 1^4; - blitter.solid = 0; - for (i=0; i HICHAR) return; - blit_copy_solid(x, y, 4, 8, font_table[ch - LOCHAR], color); -} - -void draw_string(const char* str, byte x, byte y, byte color) { +void draw_string(const char* str, byte spacing) { while (*str) { - draw_char(*str++, x, y, color); - x += 4; + JSRL(font_shapes[*str++ - 0x20]); + if (spacing) SVEC(spacing, 0, 0); } } -void draw_box(word x1, byte y1, word x2, byte y2, byte color) { - draw_solid(x1, y1, (x2-x1)>>1, 1, color); - draw_solid(x1, y2, (x2-x1)>>1, 1, color); - draw_vline(x1, y1, y2-y1, color); - draw_vline(x2, y1, y2-y1, color); +// MATH/3D ROUTINES + +typedef struct { + sbyte m[3][3]; +} Matrix; + +typedef struct { + sbyte x,y,z; +} Vector8; + +typedef struct { + int x,y,z; +} Vector16; + +typedef struct { + byte numverts; + const Vector8* verts; // array of vertices + const sbyte* edges; // array of vertex indices (edges) +} Wireframe; + +void mat_identity(Matrix* m) { + memset(m, 0, sizeof(*m)); + m->m[0][0] = 127; + m->m[1][1] = 127; + m->m[2][2] = 127; } -// GRAPHIC DATA - -const byte palette_data[16] = { - 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x38, 0x70, 0x7f, 0xf8, }; - -const byte laser_vert[2+1*8] = { - 1,8, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, -}; - -const byte laser_horiz[2+4*2] = { - 4,2, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, -}; - - -const byte playersprite1[] = { -7,16, -0x00,0x00,0xef,0xef,0xe0,0x00,0x00, -0x00,0xee,0xee,0xfe,0xee,0xe0,0x00, -0x0e,0xed,0xef,0xef,0xed,0xee,0x00, -0x0e,0xee,0xdd,0xdd,0xde,0xee,0x00, -0x0e,0xee,0xed,0xde,0xee,0xee,0x00, -0x00,0xee,0xee,0xde,0xee,0xe0,0x00, -0x00,0xee,0xee,0xde,0xee,0xe0,0x00, -0x00,0x00,0xed,0xdd,0xe0,0x00,0x0d, -0xdd,0xdd,0xee,0xee,0xed,0xdd,0xd0, -0x0d,0xee,0xee,0xee,0xee,0xee,0x00, -0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, -0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, -0x0e,0xe0,0xdd,0xdd,0xd0,0xde,0x00, -0x0d,0x00,0xee,0x0e,0xe0,0x0d,0x00, -0x00,0x00,0xed,0x0e,0xe0,0x00,0x00, -0x00,0x0d,0xdd,0x0d,0xdd,0x00,0x18, -}; - -const byte sprite1[2+16*16/2] = { -8,16, -0x00,0x09,0x99,0x00,0x00,0x99,0x90,0x00, -0x00,0x94,0x94,0x90,0x09,0x49,0x49,0x00, -0x04,0x49,0x49,0x90,0x09,0x94,0x94,0x90, -0x94,0x99,0x94,0x90,0x09,0x49,0x99,0x49, -0x99,0x99,0x49,0x93,0x39,0x94,0x99,0x99, -0x04,0x49,0x99,0x94,0x49,0x99,0x94,0x90, -0x00,0x94,0x94,0x43,0x34,0x49,0x49,0x00, -0x00,0x09,0x43,0x94,0x49,0x34,0x90,0x00, -0x00,0x90,0x00,0x39,0x93,0x00,0x09,0x00, -0x00,0x09,0x83,0x33,0x33,0x33,0x90,0x00, -0x00,0x09,0x32,0x23,0x32,0x23,0x90,0x00, -0x00,0x03,0x03,0x23,0x82,0x30,0x30,0x00, -0x03,0x30,0x00,0x33,0x33,0x00,0x03,0x30, -0x00,0x30,0x03,0x00,0x00,0x30,0x03,0x00, -0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00, -0x00,0x09,0x99,0x00,0x00,0x99,0x90,0x00, -}; - -const byte sprite2[2+16*16/2] = { -8,16, -0x00,0x94,0x94,0x90,0x09,0x49,0x49,0x00, -0x04,0x49,0x49,0x90,0x09,0x94,0x94,0x90, -0x94,0x99,0x94,0x90,0x09,0x49,0x99,0x49, -0x99,0x99,0x49,0x93,0x39,0x94,0x99,0x99, -0x04,0x49,0x99,0x94,0x49,0x99,0x94,0x90, -0x00,0x94,0x94,0x43,0x34,0x49,0x49,0x00, -0x00,0x09,0x43,0x94,0x49,0x34,0x90,0x00, -0x00,0x90,0x00,0x39,0x93,0x00,0x09,0x00, -0x00,0x09,0x83,0x33,0x33,0x33,0x90,0x00, -0x00,0x09,0x32,0x23,0x32,0x23,0x90,0x00, -0x00,0x03,0x03,0x23,0x82,0x30,0x30,0x00, -0x03,0x30,0x00,0x33,0x33,0x00,0x03,0x30, -0x00,0x30,0x03,0x00,0x00,0x30,0x03,0x00, -0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00, -0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, -}; - -const byte sprite3[2+16*16/2] = { -8,16, -0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00, -0x00,0x00,0x00,0x11,0x11,0x00,0x00,0x00, -0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00, -0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00, -0x00,0x11,0x10,0x01,0x10,0x01,0x11,0x00, -0x11,0x00,0x10,0x11,0x11,0x01,0x00,0x11, -0x10,0x00,0x11,0x11,0x11,0x11,0x00,0x01, -0x10,0x00,0x00,0x11,0x11,0x00,0x00,0x01, -0x00,0x01,0x10,0x11,0x41,0x01,0x10,0x00, -0x00,0x10,0x11,0x11,0x11,0x11,0x01,0x00, -0x01,0x00,0x00,0x51,0x15,0x00,0x00,0x10, -0x01,0x00,0x01,0x10,0x01,0x10,0x00,0x10, -0x01,0x00,0x10,0x00,0x00,0x01,0x00,0x10, -0x00,0x10,0x01,0x00,0x00,0x10,0x01,0x00, -0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00, -0x00,0x01,0x10,0x00,0x00,0x01,0x10,0x00, -}; - -const byte sprite4[2+16*16/2] = { -8,16, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0xbb,0xbb,0x00,0x00,0x00, -0x00,0x00,0x00,0xbb,0xbb,0x00,0x00,0x00, -0x00,0x00,0xbb,0xbb,0xbb,0xbb,0x00,0x00, -0x00,0x0b,0x4b,0xbb,0xbb,0xb4,0xb0,0x00, -0x00,0x0b,0x44,0xbb,0xbb,0x49,0xb0,0x00, -0x00,0xbb,0x99,0x4b,0xb4,0x99,0xbb,0x00, -0x00,0x4b,0xb9,0x9b,0xb4,0x4b,0xb4,0x00, -0x00,0x04,0xbb,0x4b,0xb9,0xbb,0x40,0x00, -0x00,0x00,0x4b,0xbb,0xbb,0xb4,0x00,0x00, -0x11,0x00,0x0b,0xbb,0xbb,0xb0,0x00,0x11, -0x10,0x10,0x0b,0x41,0x14,0xb0,0x01,0x01, -0x10,0x00,0x05,0x11,0x11,0x50,0x00,0x01, -0x01,0x00,0x01,0x51,0x15,0x10,0x00,0x10, -0x00,0x10,0x01,0x10,0x01,0x10,0x01,0x00, -0x01,0x01,0x10,0x10,0x01,0x01,0x10,0x10, -}; - -const byte sprite5[2+16*16/2] = { -8,16, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x22,0x00,0x00,0x22,0x00,0x00, -0x00,0x20,0x20,0x00,0x00,0x02,0x02,0x00, -0x02,0x22,0x12,0x00,0x00,0x21,0x22,0x20, -0x00,0x02,0x11,0x00,0x00,0x11,0x20,0x00, -0x00,0x00,0x02,0x11,0x11,0x20,0x00,0x00, -0x00,0x00,0x02,0x22,0x22,0x20,0x00,0x00, -0x00,0x00,0x21,0x22,0x22,0x12,0x00,0x00, -0x00,0x00,0x22,0x12,0x21,0x22,0x00,0x00, -0x02,0x00,0x22,0x12,0x21,0x22,0x00,0x20, -0x20,0x02,0x21,0x11,0x11,0x12,0x20,0x02, -0x02,0x22,0x15,0x12,0x21,0x51,0x22,0x20, -0x02,0x11,0x15,0x52,0x25,0x51,0x11,0x20, -0x20,0x00,0x22,0x12,0x21,0x22,0x00,0x02, -0x20,0x02,0x20,0x20,0x02,0x02,0x20,0x02, -0x02,0x02,0x00,0x20,0x02,0x00,0x20,0x20, -}; - -const byte sprite6[2+12*16/2] = { -8,12, -0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00, -0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x40, -0x00,0x00,0x04,0x04,0x49,0x49,0x99,0x44, -0x00,0x00,0x44,0x44,0x99,0x94,0x44,0x40, -0x00,0x04,0x49,0x99,0x94,0x49,0x99,0x40, -0x00,0x44,0x99,0x94,0x49,0x99,0x44,0x00, -0x04,0x49,0x44,0x99,0x99,0x44,0x00,0x00, -0x04,0x44,0x00,0x49,0x44,0x40,0x00,0x00, -0x04,0x40,0x00,0x04,0x00,0x00,0x00,0x00, -0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; - -const byte sprite7[2+16*16/2] = { -8,16, -0x00,0x60,0x00,0x00,0x00,0x00,0x06,0x00, -0x60,0x60,0x00,0x00,0x00,0x00,0x06,0x06, -0x60,0x60,0x50,0x00,0x00,0x05,0x06,0x06, -0x60,0x60,0x06,0x00,0x00,0x60,0x06,0x06, -0x66,0x60,0x06,0x06,0x60,0x60,0x06,0x66, -0x66,0x60,0x66,0x66,0x66,0x66,0x06,0x66, -0x66,0x60,0x6b,0x6b,0xb6,0xb6,0x06,0x66, -0x06,0x66,0x66,0xb6,0x6b,0x66,0x66,0x60, -0x00,0x67,0x66,0x66,0x66,0x66,0x66,0x00, -0x00,0x11,0x11,0x66,0x66,0x11,0x11,0x00, -0x01,0x11,0x21,0x11,0x11,0x12,0x11,0x10, -0x00,0x10,0x01,0x01,0x10,0x10,0x01,0x00, -0x00,0x10,0x11,0x00,0x00,0x11,0x01,0x00, -0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x00, -}; - -const byte sprite8[2+16*16/2] = { -8,16, -0x00,0x00,0x11,0x11,0x11,0x11,0x00,0x00, -0x00,0x01,0x61,0x11,0x21,0x12,0x10,0x00, -0x00,0x11,0x12,0x11,0x61,0x11,0x11,0x00, -0x00,0x11,0x71,0x21,0x61,0x17,0x11,0x00, -0x00,0x11,0x77,0x11,0x12,0x77,0x11,0x00, -0x00,0x11,0x17,0x17,0x71,0x72,0x11,0x00, -0x00,0x16,0x21,0x78,0x87,0x11,0x11,0x00, -0x00,0x01,0x81,0x88,0x88,0x18,0x10,0x00, -0x00,0x08,0x18,0x58,0x85,0x81,0x80,0x00, -0x00,0x88,0x01,0x88,0x88,0x10,0x88,0x00, -0x00,0x08,0x07,0x78,0x87,0x70,0x80,0x00, -0x08,0x80,0x07,0x80,0x08,0x70,0x08,0x80, -0x88,0x00,0x88,0x00,0x00,0x88,0x00,0x88, -0x80,0x00,0x08,0x80,0x08,0x80,0x00,0x08, -0x00,0x00,0x00,0x80,0x08,0x00,0x00,0x00, -}; - -const byte sprite9[2+13*16/2] = { -8,13, -0x00,0x00,0xaa,0x00,0x00,0xaa,0x00,0x00, -0x00,0x00,0xa0,0x0a,0xa0,0x0a,0x00,0x00, -0x0a,0xaa,0xa4,0xaa,0xaa,0x3a,0xaa,0xa0, -0x00,0x0a,0x3a,0x9a,0xa9,0xa3,0xa0,0x00, -0x00,0x0a,0xaa,0x99,0xa4,0xaa,0xa0,0x00, -0x00,0x0a,0xaa,0x99,0x94,0xaa,0xa0,0x00, -0x00,0xaa,0x33,0xaa,0xaa,0x43,0xaa,0x00, -0x0a,0x3a,0xaa,0x3a,0xa3,0xaa,0xa3,0xa0, -0x00,0xaa,0xaa,0x30,0x03,0xaa,0xaa,0x00, -0x00,0x0a,0xa0,0x30,0x03,0x0a,0xa0,0x00, -0x00,0xa3,0xa0,0x00,0x00,0x0a,0x4a,0x00, -0x00,0xaa,0xa0,0x00,0x00,0x0a,0xaa,0x00, -0x00,0x0a,0xa0,0x00,0x00,0x0a,0xa0,0x00, -}; - -const byte* const all_sprites[9] = { - sprite1, - sprite2, - sprite3, - sprite4, - sprite5, - sprite6, - sprite7, - sprite8, - sprite9, -}; - -// GAME CODE - -typedef struct Actor; - -typedef void (*ActorUpdateFn)(struct Actor* a); -typedef void (*ActorDrawFn)(struct Actor* a); - -typedef struct Actor { - struct Actor* next; - struct Actor** prevptr; - byte x,y; - byte* shape; - ActorUpdateFn update; - ActorDrawFn draw; - union { - struct { sbyte dx,dy; } laser; - struct { byte exploding; } enemy; - } u; -} Actor; - -#define MAX_ACTORS 128 - -static Actor actors[MAX_ACTORS]; -static Actor* player_list; -static Actor* fast_list; -static Actor* slow_lists[4]; -static Actor* obstacle_list; -static Actor* free_list; -static Actor* effects_list; -static byte frame; - -#define PLAYER 1 -#define LASER 2 - -void add_actor(Actor** list, Actor* a) { - if (*list) (*list)->prevptr = &a->next; - a->next = *list; - a->prevptr = list; - *list = a; +inline void mul16(sbyte a, sbyte b) { + mathbox_arg1 = a; + mathbox_arg2 = b; + mathbox_go_mul=0; } -void remove_actor(Actor* a) { - if (a->next) a->next->prevptr = a->prevptr; - *a->prevptr = a->next; +void vec_mat_transform(Vector16* dest, const Vector8* v, const Matrix* m) { + byte i; + int* result = &dest->x; + const sbyte* mval = &m->m[0][0]; + for (i=0; i<3; i++) { + mathbox_sum = 0; + mul16(*mval++, v->x); + mul16(*mval++, v->y); + mul16(*mval++, v->z); + *result++ = mathbox_sum; + } } -char in_rect(const Actor* e, byte x, byte y, byte w, byte h) { - byte eh = e->shape[0]; - byte ew = e->shape[1]; - return (x >= e->x-w && x <= e->x+ew && y >= e->y-h && y <= e->y+eh); -} +const sbyte sintbl[64] = { +0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, +49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88, +90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115, 116, +117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127, +}; -void draw_actor_normal(Actor* a) { - draw_sprite(a->shape, a->x, a->y); -} - -void draw_actor_exploding(Actor* a) { - erase_sprite_strided(a->shape, a->x, a->y, a->u.enemy.exploding); - if (a->u.enemy.exploding > 10) { - a->draw = NULL; +sbyte isin(byte x0) { + byte x = x0; + if (x0 & 0x40) x = 127-x; + if (x0 & 0x80) { + return -sintbl[x+128]; } else { - draw_sprite_strided(a->shape, a->x, a->y, ++a->u.enemy.exploding); + return sintbl[x]; } } -void update_actor(Actor* a) { - // if NULL shape, we don't have anything - if (a->shape) { - // erase the sprite - draw_sprite_solid(a->shape, a->x, a->y, 0); - // call update callback - if (a->update) { - a->update(a); - } - // did we delete it? - if (a->shape) { - // draw the sprite - if (a->draw) { - a->draw(a); - } - } else { - // shape became null, remove from list - remove_actor(a); - } +sbyte icos(byte x) { + return isin(x+64); +} + +void mat_rotate(Matrix* m, byte axis, byte angle) { + sbyte sin = isin(angle); + sbyte cos = icos(angle); + mat_identity(m); + switch (axis) { + case 0: + m->m[1][1] = cos; + m->m[2][1] = sin; + m->m[1][2] = -sin; + m->m[2][2] = cos; + break; + case 1: + m->m[2][2] = cos; + m->m[0][2] = sin; + m->m[2][0] = -sin; + m->m[0][0] = cos; + break; + case 2: + m->m[0][0] = cos; + m->m[1][0] = -sin; + m->m[0][1] = sin; + m->m[1][1] = cos; + break; } } -// +void xform_vertices(Vector16* dest, const Vector8* src, const Matrix* m, byte nv) { + byte i; + for (i=0; iedges; + byte bright = 0; + int x1 = 0; + int y1 = 0; + Vector16 scrnverts[16]; + xform_vertices(scrnverts, wf->verts, m, wf->numverts); + do { + sbyte i = *e++; + if (i == -1) + bright = 0; + else if (i == -2) + break; + else { + int x2 = scrnverts[i].x>>8; + int y2 = scrnverts[i].y>>8; + VCTR(x2-x1, y2-y1, bright); + x1 = x2; + y1 = y2; + } + bright = 2; + } while (1); +} + +static word lfsr = 1; word rand() { byte lsb = lfsr & 1; @@ -565,211 +371,378 @@ word rand() { return lfsr; } -signed char random_dir() { - byte x = rand(); - if (x < 85) return 0; - else if (x < 85*2) return -1; - else return 1; +// SHAPE CACHE + +const Vector8 tetra_v[] = { {0,-86,86},{86,86,86},{-86,86,86},{0,0,-86} }; +const char tetra_e[] = { 0, 1, 2, 0, 3, 1, -1, 3, 2, -2 }; +const Wireframe tetra_wf = { 4, tetra_v, tetra_e }; + +const Vector8 octa_v[] = { {86,0,0},{0,86,0},{-86,0,0},{0,-86,0},{0,0,86},{0,0,-86} }; +const char octa_e[] = { 0, 1, 2, 3, 0, 4, 1, 5, 0, -1, 2, 4, 3, 5, 2, -2 }; +const Wireframe octa_wf = { 6, octa_v, octa_e }; + +const Vector8 ship_v[] = { {0,86,0},{-30,-30,0},{-50,0,0},{50,0,0},{30,-30,0} }; +const char ship_e[] = { 0, 1, 2, 3, 4, 0, -2 }; +const Wireframe ship_wf = { 5, ship_v, ship_e }; + +const Vector8 thrust_v[] = { {-20,-30,0},{-30,-50,0},{0,-86,0},{30,-50,0},{20,-30,0} }; +const char thrust_e[] = { 0, 1, 2, 3, 4, -2 }; +const Wireframe thrust_wf = { 5, thrust_v, thrust_e }; + +const Vector8 torpedo_v[] = { {-86,0,0},{86,0,0},{-40,-40,0},{40,40,0},{0,-20,0},{0,20,0} }; +const char torpedo_e[] = { 0, 1, -1, 2, 3, -1, 4, 5, -2 }; +const Wireframe torpedo_wf = { 6, torpedo_v, torpedo_e }; + +word ship_shapes[32]; +word thrust_shapes[32]; +word tetra_shapes[32]; +word torpedo_shapes[16]; +word explosion_shape[1]; + +void draw_explosion() { + byte i; + for (i=0; i<30; i++) { + byte angle = rand(); + sbyte xd = isin(angle) >> 4; + sbyte yd = icos(angle) >> 4; + SVEC(xd, yd, 2); + SVEC(-xd, -yd, 2); + } } -void random_walk(Actor* a) { - a->x += random_dir(); - a->y += random_dir(); +void make_cached_shapes() { + Matrix mat; + byte i; + for (i=0; i<32; i++) { + watchdog = 0; + ship_shapes[i] = dvgwrofs; + mat_rotate(&mat, 2, i<<3); + draw_wireframe_ortho(&ship_wf, &mat); + RTSL(); + thrust_shapes[i] = dvgwrofs; + draw_wireframe_ortho(&thrust_wf, &mat); + RTSL(); + tetra_shapes[i] = dvgwrofs; + mat_rotate(&mat, 0, i<<3); + draw_wireframe_ortho(&octa_wf, &mat); + RTSL(); + } + for (i=0; i<16; i++) { + torpedo_shapes[i] = dvgwrofs; + mat_rotate(&mat, 2, i<<4); + draw_wireframe_ortho(&torpedo_wf, &mat); + RTSL(); + } + explosion_shape[0] = dvgwrofs; + STAT_sparkle(15); + draw_explosion(); + RTSL(); } -static byte g_section; +// MAIN PROGRAM -void update_actor_list(Actor* a) { - while (a) { - update_actor(a); +struct Actor; + +typedef void ActorUpdateFn(struct Actor*); + +typedef struct Actor { + word* shapes; + ActorUpdateFn* update_fn; + byte angshift; + byte scale; + byte color; + byte intens; + byte collision_flags; + byte angle; + word xx; + word yy; + int velx; + int vely; + struct Actor* next; + byte removed:1; +} Actor; + +#define WORLD_SCALE 0x2c0 + +void draw_actor(const Actor* a) { + CNTR(); // center beam (0,0) + SCAL(WORLD_SCALE); // world scale + VCTR(a->xx>>3, a->yy>>3, 0); // go to object center + SCAL(a->scale); // object scale + STAT(a->color, a->intens); // set color/intensity + JSRL(a->shapes[a->angle >> a->angshift]); // draw +} + +void move_actor(Actor* a) { + a->xx += a->velx; + a->yy += a->vely; +} + +static Actor* first_actor = NULL; + +Actor* new_actor(const Actor* base) { + Actor* a = (Actor*) malloc(sizeof(Actor)); + memcpy(a, base, sizeof(Actor)); + a->next = first_actor; + first_actor = a; + return a; +} + +void draw_and_update_actors() { + Actor* a = first_actor; + while (a != NULL) { + draw_actor(a); + move_actor(a); + if (a->update_fn) a->update_fn(a); a = a->next; } } -void update_actors_partial(Actor* a) { - while (a) { - if (g_section ^ (a->y < 0x80)) { - update_actor(a); - } - a = a->next; - } -} - -void update_screen_section(byte section) { - g_section = section; - update_actors_partial(player_list); - update_actors_partial(fast_list); - update_actors_partial(slow_lists[frame & 3]); -} - -byte did_overflow() { - __asm - ld l,#0 - ret nc - inc l - __endasm; -} - -static byte test_x, test_y; -static Actor* test_collided; - -Actor* test_collision(Actor* a) { - while (a) { - if (test_y >= a->y && test_x >= a->x && - test_y < a->y+16 && test_x < a->x+16) { - return a; - } - a = a->next; - } - return NULL; -} - -void laser_move(Actor* a) { - // did we hit something? - test_x = a->x; - test_y = a->y; - test_collided = test_collision(fast_list); - if (!test_collided) test_collided = test_collision(slow_lists[0]); - if (!test_collided) test_collided = test_collision(slow_lists[1]); - if (!test_collided) test_collided = test_collision(slow_lists[2]); - if (!test_collided) test_collided = test_collision(slow_lists[3]); - if (test_collided) { - // get rid of laser (we can do this in our 'update' fn) - a->shape = NULL; - // set exploding flag for enemy (we're not in its update) - test_collided->draw = draw_actor_exploding; - test_collided->update = NULL; - test_collided->u.enemy.exploding = 1; - remove_actor(test_collided); - add_actor(&effects_list, test_collided); - return; - } - // move laser - // check for wall collisions - a->x += a->u.laser.dx; - if (a->x > 255-8) a->shape = NULL; - a->y += a->u.laser.dy; - if (a->y > 255-8) a->shape = NULL; -} - -void shoot_laser(sbyte dx, sbyte dy, const byte* shape) { - Actor* a = &actors[LASER]; - a->shape = (void*) shape; - a->x = actors[PLAYER].x + 6; - a->y = actors[PLAYER].y + 8; - a->u.laser.dx = dx; - a->u.laser.dy = dy; - add_actor(&player_list, a); -} - -void player_laser() { - // is the laser being used? - if (actors[LASER].shape == NULL) { // no, check controls - if (UP2) shoot_laser(0,-8,laser_vert); - else if (DOWN2) shoot_laser(0,8,laser_vert); - else if (LEFT2) shoot_laser(-8,0,laser_horiz); - else if (RIGHT2) shoot_laser(8,0,laser_horiz); - } -} - -void player_move(Actor* a) { - byte x = a->x; - byte y = a->y; - if (UP1) y-=1; - if (DOWN1) y+=1; - if (LEFT1) x-=1; - if (RIGHT1) x+=1; - a->x = x; - a->y = y; - player_laser(); -} - -static Actor* current_effect; - -void effects_new_frame() { - current_effect = effects_list; -} - -void effects_next() { - if (current_effect) { - if (current_effect->draw) { - current_effect->draw(current_effect); +void remove_expired_actors() { + Actor* a; + // get address of first pointer + Actor** prev = &first_actor; + while ((a = *prev) != NULL) { + // was actor removed? + if (a->removed) { + // set previous pointer to skip this actor + *prev = a->next; + // free memory + free(a); } else { - remove_actor(current_effect); + // get address of next pointer + prev = &a->next; } - current_effect = current_effect->next; } } -Actor* new_actor() { - Actor* a = free_list; - remove_actor(a); - return a; +void draw_actor_rect(Actor* a) { + CNTR(); // center beam (0,0) + SCAL(WORLD_SCALE); // world scale + VCTR(a->xx>>3, a->yy>>3, 0); // go to object center + SCAL(a->scale); // object scale + STAT(RED, 7); // set color/intensity + VCTR(-86,-86,0); + VCTR(86*2,0,2); + VCTR(0,86*2,2); + VCTR(-86*2,0,2); + VCTR(0,-86*2,2); } -void redraw_playfield(Actor* a) { - a; - draw_box(0,0,303,255,0x11); +inline byte abs(sbyte x) { + return (x>=0) ? x : -x; } -Actor* new_effect(ActorDrawFn draw) { - Actor* a = new_actor(); - a->draw = draw; - add_actor(&effects_list, a); - return a; +inline word get_distance_squared(byte dx, byte dy) { + mathbox_sum = 0; + mul16(dx,dx); + mul16(dy,dy); + return mathbox_sum; +} + +typedef void ActorCollisionFn(struct Actor*, struct Actor*); + +byte test_actor_distance(ActorCollisionFn* fn, Actor* act1, byte mindist, byte flags) { + Actor* a = first_actor; + byte xx1 = act1->xx >> 8; + byte yy1 = act1->yy >> 8; + byte count = 0; + // mindist2 = mindist * mindist + word mindist2; + mathbox_sum = 0; + mul16(mindist,mindist); + mindist2 = mathbox_sum; + // go through list of actors + while (a) { + // only compare against actors with certain flags + // (that haven't been removed) + if ((a->collision_flags & flags) && !a->removed) { + byte dx = abs(xx1 - (a->xx >> 8)); + byte dy = abs(yy1 - (a->yy >> 8)); + if (dx+dy < mindist) { + word dist2 = get_distance_squared(dx, dy); + if (dist2 < mindist2) { + if (fn) fn(act1, a); + count++; + } + } + } + a = a->next; + } + return count; +} + +void explode_at(Actor* base); + +void explode_actor(Actor* a, Actor* b) { + a->removed = 1; + explode_at(b); + b->removed = 1; +} + +void obstacle_update_fn(struct Actor* a) { + a->angle += 1; +} + +void torpedo_update_fn(struct Actor* a) { + // expire? + if ((a->angle += 60) == 0) { + a->removed = 1; + } else { + // check for torpedo hits + test_actor_distance(explode_actor, a, 12, 0x2); + } +} + +void explosion_update_fn(struct Actor* a) { + a->scale -= 2; + if (a->scale < 8) { + a->removed = 1; + } +} + +const Actor ship_actor = { + ship_shapes, NULL, 3, 0xb0, WHITE, 7, 0x1, +}; +const Actor tetra_actor = { + tetra_shapes, obstacle_update_fn, 3, 0x80, CYAN, 7, 0x2, +}; +const Actor torpedo_actor = { + torpedo_shapes, torpedo_update_fn, 4, 0xe0, YELLOW, 15, 0x4, +}; +const Actor explosion_actor = { + explosion_shape, explosion_update_fn, 8, 0xa0, WHITE, 15, 0, +}; + +void create_obstacles(byte count) { + while (count--) { + Actor* a = new_actor(&tetra_actor); + a->xx = rand() | 0x8000; + a->yy = rand(); + a->velx = (int)rand()<<8>>8; + a->vely = (int)rand()<<8>>8; + } +} + +static int frame = 0; + +static Actor* curship = NULL; + +void draw_thrust() { + word rnd = rand(); + // save old values in actor + byte oldcolor = curship->color; + byte oldintens = curship->intens; + // temporarily give new thrust values + curship->shapes = thrust_shapes; + curship->scale ^= rnd; // random thrust scale + curship->intens = 15; + curship->color = (rnd&1) ? RED : YELLOW; + // draw thrust using player's ship actor + draw_actor(curship); + // restore previous values + curship->shapes = ship_shapes; + curship->scale ^= rnd; + curship->color = oldcolor; + curship->intens = oldintens; +} + +void thrust_ship() { + sbyte sin = isin(curship->angle); + sbyte cos = icos(curship->angle); + curship->velx += sin>>3; + curship->vely += cos>>3; +} + +int apply_friction(int vel) { + int delta = vel >> 8; + if (delta == 0 && vel > 0) delta++; + return vel - delta; +} + +void shoot_torpedo() { + sbyte sin = isin(curship->angle); + sbyte cos = icos(curship->angle); + Actor* torp = new_actor(&torpedo_actor); + torp->velx = sin << 2; + torp->vely = cos << 2; + torp->xx = curship->xx + torp->velx*4; + torp->yy = curship->yy + torp->vely*4; +} + +static byte can_fire; +static byte newship_timer; + +void new_player_ship() { + if (curship == NULL) { + curship = new_actor(&ship_actor); + } +} + +void explode_at(Actor* base) { + Actor* a = new_actor(&explosion_actor); + a->xx = base->xx; + a->yy = base->yy; +} + +void control_player() { + if (newship_timer && --newship_timer == 0) { + new_player_ship(); + } + if (!curship) return; + + if (LEFT1) curship->angle -= 2; + if (RIGHT1) curship->angle += 2; + if ((frame&1)==1) { + curship->velx = apply_friction(curship->velx); + curship->vely = apply_friction(curship->vely); + } + if (UP1) { + // draw flame + draw_thrust(); + // thrust every 4 frames, to avoid precision issues + if (!(frame&3)) thrust_ship(); + } + if (FIRE1) { + // must release fire button before firing again + if (can_fire) { + shoot_torpedo(); + can_fire = 0; + } + } else { + can_fire = 1; + } + // ship ran into something? + if (test_actor_distance(NULL, curship, 16, 0x2)) { + explode_at(curship); + curship->removed = 1; + curship = NULL; + newship_timer = 255; + } +} + +byte just_one_actor_left() { + return first_actor && first_actor->next == NULL; } void main() { - byte i; - byte num_actors = 32; - blit_solid(0, 0, 255, 255, 0); - memset(actors, 0, sizeof(actors)); - memcpy(palette, palette_data, 16); - fill_char_table(); - player_list = fast_list = obstacle_list = free_list = NULL; - memset(slow_lists, 0, sizeof(slow_lists)); - // add all actors to free list - for (i=MAX_ACTORS-1; i>0; i--) { - add_actor(&free_list, &actors[i]); - } - // make actors - for (i=1; ix = rand() + rand(); - a->y = rand() + rand(); - } while ((byte)(a->x - 96) < 64 && (byte)(a->y - 96) < 64); - a->shape = (void*) all_sprites[i%9]; - a->update = random_walk; - a->draw = draw_actor_normal; - if (i == PLAYER) { - a->x = 128; - a->y = 120; - add_actor(&player_list, a); - } - else if (i == LASER) ; //add_actor(&player_list, a); - else if (i < 5) add_actor(&fast_list, a); - else add_actor(&slow_lists[i&3], a); - WATCHDOG; - } - actors[PLAYER].shape = (void*) playersprite1; - actors[PLAYER].update = player_move; - actors[LASER].update = laser_move; - actors[LASER].shape = NULL; - new_effect(redraw_playfield); - WATCHDOG; - while (1) { - effects_new_frame(); - while (video_counter >= 0x90) effects_next(); - update_screen_section(1); - while (video_counter < 0x90) effects_next(); - update_screen_section(0); - switch (frame & 7) { - case 0: - draw_box(0,0,303,255,0x11); - break; - } + memset(dvgram, 0x20, sizeof(dvgram)); // HALTs + dvgwrofs = 0x800; + make_cached_font(); + make_cached_shapes(); + create_obstacles(5); + new_player_ship(); + while (!just_one_actor_left()) { + dvgreset(); + control_player(); + draw_and_update_actors(); + CNTR(); + HALT(); + dvgstart(); + remove_expired_actors(); frame++; - WATCHDOG; + watchdog=0; + while (vidframe == (frame & 0x3)) {} } + main(); } diff --git a/presets/williams-z80/game1.c b/presets/williams-z80/game1.c index 58f0692d..9148d179 100644 --- a/presets/williams-z80/game1.c +++ b/presets/williams-z80/game1.c @@ -11,6 +11,7 @@ byte __at (0xc000) palette[16]; volatile byte __at (0xc804) input0; volatile byte __at (0xc806) input1; volatile byte __at (0xc80c) input2; +byte __at (0xc80c) sound_pia; byte __at (0xc900) rom_select; volatile byte __at (0xcb00) video_counter; byte __at (0xcbff) watchdog0x39; @@ -82,38 +83,105 @@ __endasm; main(); } -#define LOCHAR 0x21 -#define HICHAR 0x5e +#define LOCHAR 0x20 +#define HICHAR 0x7e -const byte font8x8[HICHAR-LOCHAR+1][8] = { -{ 0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00 }, { 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x66,0x66,0xff,0x66,0xff,0x66,0x66,0x00 }, { 0x18,0x3e,0x60,0x3c,0x06,0x7c,0x18,0x00 }, { 0x62,0x66,0x0c,0x18,0x30,0x66,0x46,0x00 }, { 0x3c,0x66,0x3c,0x38,0x67,0x66,0x3f,0x00 }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x00 }, { 0x3c,0x66,0x6e,0x76,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x38,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x06,0x0c,0x30,0x60,0x7e,0x00 }, { 0x3c,0x66,0x06,0x1c,0x06,0x66,0x3c,0x00 }, { 0x06,0x0e,0x1e,0x66,0x7f,0x06,0x06,0x00 }, { 0x7e,0x60,0x7c,0x06,0x06,0x66,0x3c,0x00 }, { 0x3c,0x66,0x60,0x7c,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x0c,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x3c,0x66,0x06,0x0c,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x6e,0x6e,0x60,0x62,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00 }, { 0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00 }, { 0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00 }, { 0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00 }, { 0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00 }, { 0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00 }, { 0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00 }, { 0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00 }, { 0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00 }, { 0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 } -}; - -static byte font_table[HICHAR-LOCHAR+1][8*4]; - -void fill_char_table_entry(char ch) { - const byte* src = &font8x8[ch-LOCHAR][0]; - byte* data = &font_table[ch-LOCHAR][0]; - int i,j,pixels; - for (i=0; i<8; i++) { - byte b = *src++; - for (j=0; j<4; j++) { - pixels = 0; - if (b & 0x80) pixels |= 0xf0; - if (b & 0x40) pixels |= 0x0f; - *data++ = pixels; - b <<= 2; - } - } - WATCHDOG; -} - -void fill_char_table() { - char ch; - for (ch=LOCHAR; ch<=HICHAR; ch++) { - fill_char_table_entry(ch); - } -} +const char CH_32[] = { 0x21,0x51,0x00 }; +const char CH_33[] = { 0x21,0x55,0xf0,0xf0,0xf0,0x00,0xf0 }; +const char CH_34[] = { 0x42,0x52,0xf0,0xf0,0xf0,0xf0 }; +const char CH_35[] = { 0x42,0x55,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0 }; +const char CH_36[] = { 0x42,0x55,0x0f,0xf0,0xff,0x00,0x0f,0xf0,0xff,0x00,0x0f,0x00 }; +const char CH_37[] = { 0x42,0x55,0xf0,0x00,0x00,0xf0,0x0f,0x00,0xf0,0x00,0x00,0xf0 }; +const char CH_38[] = { 0x42,0x55,0xff,0x00,0xff,0x00,0xff,0xf0,0xf0,0xf0,0x0f,0xf0 }; +const char CH_39[] = { 0x21,0x52,0xf0,0xf0 }; +const char CH_40[] = { 0x32,0x55,0x0f,0x00,0xf0,0x00,0xf0,0x00,0xf0,0x00,0x0f,0x00 }; +const char CH_41[] = { 0x32,0x55,0xf0,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0xf0,0x00 }; +const char CH_42[] = { 0x42,0x53,0xf0,0xf0,0x0f,0x00,0xf0,0xf0 }; +const char CH_43[] = { 0x42,0x43,0x0f,0x00,0xff,0xf0,0x0f,0x00 }; +const char CH_44[] = { 0x32,0x22,0x0f,0x00,0xf0,0x00 }; +const char CH_45[] = { 0x42,0x31,0xff,0xf0 }; +const char CH_46[] = { 0x21,0x11,0xf0 }; +const char CH_47[] = { 0x42,0x55,0x00,0xf0,0x00,0xf0,0x0f,0x00,0xf0,0x00,0xf0,0x00 }; +const char CH_48[] = { 0x42,0x55,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0x00 }; +const char CH_49[] = { 0x32,0x55,0x0f,0x00,0xff,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00 }; +const char CH_50[] = { 0x42,0x55,0xff,0x00,0x00,0xf0,0x0f,0x00,0xf0,0x00,0xff,0xf0 }; +const char CH_51[] = { 0x42,0x55,0xff,0x00,0x00,0xf0,0x0f,0x00,0x00,0xf0,0xff,0x00 }; +const char CH_52[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xff,0xf0,0x00,0xf0,0x00,0xf0 }; +const char CH_53[] = { 0x42,0x55,0xff,0xf0,0xf0,0x00,0xff,0x00,0x00,0xf0,0xff,0x00 }; +const char CH_54[] = { 0x42,0x55,0x0f,0xf0,0xf0,0x00,0xff,0xf0,0xf0,0xf0,0xff,0xf0 }; +const char CH_55[] = { 0x42,0x55,0xff,0xf0,0x00,0xf0,0x0f,0x00,0xf0,0x00,0xf0,0x00 }; +const char CH_56[] = { 0x42,0x55,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0 }; +const char CH_57[] = { 0x42,0x55,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0x00,0xf0,0xff,0x00 }; +const char CH_58[] = { 0x21,0x43,0xf0,0x00,0xf0 }; +const char CH_59[] = { 0x32,0x44,0x0f,0x00,0x00,0x00,0x0f,0x00,0xf0,0x00 }; +const char CH_60[] = { 0x42,0x55,0x00,0xf0,0x0f,0x00,0xf0,0x00,0x0f,0x00,0x00,0xf0 }; +const char CH_61[] = { 0x42,0x43,0xff,0xf0,0x00,0x00,0xff,0xf0 }; +const char CH_62[] = { 0x42,0x55,0xf0,0x00,0x0f,0x00,0x00,0xf0,0x0f,0x00,0xf0,0x00 }; +const char CH_63[] = { 0x42,0x55,0xff,0xf0,0x00,0xf0,0x0f,0x00,0x00,0x00,0x0f,0x00 }; +const char CH_64[] = { 0x42,0x55,0x0f,0x00,0xf0,0xf0,0xff,0xf0,0xf0,0x00,0x0f,0xf0 }; +const char CH_65[] = { 0x42,0x55,0x0f,0x00,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xf0,0xf0 }; +const char CH_66[] = { 0x42,0x55,0xff,0x00,0xf0,0xf0,0xff,0x00,0xf0,0xf0,0xff,0x00 }; +const char CH_67[] = { 0x42,0x55,0x0f,0xf0,0xf0,0x00,0xf0,0x00,0xf0,0x00,0x0f,0xf0 }; +const char CH_68[] = { 0x42,0x55,0xff,0x00,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0x00 }; +const char CH_69[] = { 0x42,0x55,0xff,0xf0,0xf0,0x00,0xff,0xf0,0xf0,0x00,0xff,0xf0 }; +const char CH_70[] = { 0x42,0x55,0xff,0xf0,0xf0,0x00,0xff,0xf0,0xf0,0x00,0xf0,0x00 }; +const char CH_71[] = { 0x42,0x55,0x0f,0xf0,0xf0,0x00,0xff,0xf0,0xf0,0xf0,0x0f,0xf0 }; +const char CH_72[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xf0,0xf0 }; +const char CH_73[] = { 0x42,0x55,0xff,0xf0,0x0f,0x00,0x0f,0x00,0x0f,0x00,0xff,0xf0 }; +const char CH_74[] = { 0x42,0x55,0x00,0xf0,0x00,0xf0,0x00,0xf0,0xf0,0xf0,0x0f,0x00 }; +const char CH_75[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xff,0x00,0xf0,0xf0,0xf0,0xf0 }; +const char CH_76[] = { 0x42,0x55,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xff,0xf0 }; +const char CH_77[] = { 0x42,0x55,0xf0,0xf0,0xff,0xf0,0xff,0xf0,0xf0,0xf0,0xf0,0xf0 }; +const char CH_78[] = { 0x42,0x55,0xf0,0xf0,0xff,0xf0,0xff,0xf0,0xff,0xf0,0xf0,0xf0 }; +const char CH_79[] = { 0x42,0x55,0x0f,0x00,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0x00 }; +const char CH_80[] = { 0x42,0x55,0xff,0x00,0xf0,0xf0,0xff,0x00,0xf0,0x00,0xf0,0x00 }; +const char CH_81[] = { 0x42,0x55,0x0f,0x00,0xf0,0xf0,0xf0,0xf0,0xff,0xf0,0x0f,0xf0 }; +const char CH_82[] = { 0x42,0x55,0xff,0x00,0xf0,0xf0,0xff,0xf0,0xff,0x00,0xf0,0xf0 }; +const char CH_83[] = { 0x42,0x55,0x0f,0xf0,0xf0,0x00,0x0f,0x00,0x00,0xf0,0xff,0x00 }; +const char CH_84[] = { 0x42,0x55,0xff,0xf0,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00 }; +const char CH_85[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0xf0 }; +const char CH_86[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0x00,0x0f,0x00 }; +const char CH_87[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0xff,0xf0,0xff,0xf0,0xf0,0xf0 }; +const char CH_88[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0x0f,0x00,0xf0,0xf0,0xf0,0xf0 }; +const char CH_89[] = { 0x42,0x55,0xf0,0xf0,0xf0,0xf0,0x0f,0x00,0x0f,0x00,0x0f,0x00 }; +const char CH_90[] = { 0x42,0x55,0xff,0xf0,0x00,0xf0,0x0f,0x00,0xf0,0x00,0xff,0xf0 }; +const char CH_91[] = { 0x42,0x55,0xff,0xf0,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xff,0xf0 }; +const char CH_92[] = { 0x42,0x43,0xf0,0x00,0x0f,0x00,0x00,0xf0 }; +const char CH_93[] = { 0x42,0x55,0xff,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xf0,0xff,0xf0 }; +const char CH_94[] = { 0x42,0x52,0x0f,0x00,0xf0,0xf0 }; +const char CH_95[] = { 0x42,0x11,0xff,0xf0 }; +const char CH_96[] = { 0x32,0x52,0xf0,0x00,0x0f,0x00 }; +const char CH_97[] = { 0x42,0x44,0xff,0x00,0x0f,0xf0,0xf0,0xf0,0xff,0xf0 }; +const char CH_98[] = { 0x42,0x55,0xf0,0x00,0xff,0x00,0xf0,0xf0,0xf0,0xf0,0xff,0x00 }; +const char CH_99[] = { 0x42,0x44,0x0f,0xf0,0xf0,0x00,0xf0,0x00,0x0f,0xf0 }; +const char CH_100[] = { 0x42,0x55,0x00,0xf0,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0xf0 }; +const char CH_101[] = { 0x42,0x44,0x0f,0xf0,0xf0,0xf0,0xff,0x00,0x0f,0xf0 }; +const char CH_102[] = { 0x42,0x55,0x00,0xf0,0x0f,0x00,0xff,0xf0,0x0f,0x00,0x0f,0x00 }; +const char CH_103[] = { 0x42,0x45,0x0f,0xf0,0xf0,0xf0,0xff,0xf0,0x00,0xf0,0x0f,0x00 }; +const char CH_104[] = { 0x42,0x55,0xf0,0x00,0xff,0x00,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }; +const char CH_105[] = { 0x21,0x55,0xf0,0x00,0xf0,0xf0,0xf0 }; +const char CH_106[] = { 0x42,0x56,0x00,0xf0,0x00,0x00,0x00,0xf0,0x00,0xf0,0xf0,0xf0,0x0f,0x00 }; +const char CH_107[] = { 0x42,0x55,0xf0,0x00,0xf0,0xf0,0xff,0x00,0xff,0x00,0xf0,0xf0 }; +const char CH_108[] = { 0x42,0x55,0xff,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0xff,0xf0 }; +const char CH_109[] = { 0x42,0x44,0xff,0xf0,0xff,0xf0,0xff,0xf0,0xf0,0xf0 }; +const char CH_110[] = { 0x42,0x44,0xff,0x00,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }; +const char CH_111[] = { 0x42,0x44,0x0f,0x00,0xf0,0xf0,0xf0,0xf0,0x0f,0x00 }; +const char CH_112[] = { 0x42,0x45,0xff,0x00,0xf0,0xf0,0xf0,0xf0,0xff,0x00,0xf0,0x00 }; +const char CH_113[] = { 0x42,0x45,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0xf0,0x00,0xf0 }; +const char CH_114[] = { 0x42,0x44,0x0f,0xf0,0xf0,0x00,0xf0,0x00,0xf0,0x00 }; +const char CH_115[] = { 0x42,0x44,0x0f,0xf0,0xff,0x00,0x0f,0xf0,0xff,0x00 }; +const char CH_116[] = { 0x42,0x55,0x0f,0x00,0xff,0xf0,0x0f,0x00,0x0f,0x00,0x0f,0xf0 }; +const char CH_117[] = { 0x42,0x44,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0xf0 }; +const char CH_118[] = { 0x42,0x44,0xf0,0xf0,0xf0,0xf0,0xff,0xf0,0x0f,0x00 }; +const char CH_119[] = { 0x42,0x44,0xf0,0xf0,0xff,0xf0,0xff,0xf0,0xff,0xf0 }; +const char CH_120[] = { 0x42,0x44,0xf0,0xf0,0x0f,0x00,0x0f,0x00,0xf0,0xf0 }; +const char CH_121[] = { 0x42,0x45,0xf0,0xf0,0xf0,0xf0,0x0f,0xf0,0x00,0xf0,0x0f,0x00 }; +const char CH_122[] = { 0x42,0x44,0xff,0xf0,0x0f,0xf0,0xff,0x00,0xff,0xf0 }; +const char CH_123[] = { 0x42,0x55,0x0f,0xf0,0x0f,0x00,0xf0,0x00,0x0f,0x00,0x0f,0xf0 }; +const char CH_124[] = { 0x21,0x55,0xf0,0xf0,0x00,0xf0,0xf0 }; +const char CH_125[] = { 0x42,0x55,0xff,0x00,0x0f,0x00,0x00,0xf0,0x0f,0x00,0xff,0x00 }; +const char CH_126[] = { 0x42,0x52,0x0f,0xf0,0xff,0x00 }; +const char* const FONT_TABLE[95] = { CH_32, CH_33, CH_34, CH_35, CH_36, CH_37, CH_38, CH_39, CH_40, CH_41, CH_42, CH_43, CH_44, CH_45, CH_46, CH_47, CH_48, CH_49, CH_50, CH_51, CH_52, CH_53, CH_54, CH_55, CH_56, CH_57, CH_58, CH_59, CH_60, CH_61, CH_62, CH_63, CH_64, CH_65, CH_66, CH_67, CH_68, CH_69, CH_70, CH_71, CH_72, CH_73, CH_74, CH_75, CH_76, CH_77, CH_78, CH_79, CH_80, CH_81, CH_82, CH_83, CH_84, CH_85, CH_86, CH_87, CH_88, CH_89, CH_90, CH_91, CH_92, CH_93, CH_94, CH_95, CH_96, CH_97, CH_98, CH_99, CH_100, CH_101, CH_102, CH_103, CH_104, CH_105, CH_106, CH_107, CH_108, CH_109, CH_110, CH_111, CH_112, CH_113, CH_114, CH_115, CH_116, CH_117, CH_118, CH_119, CH_120, CH_121, CH_122, CH_123, CH_124, CH_125, CH_126, }; inline word swapw(word j) { return ((j << 8) | (j >> 8)); @@ -145,25 +213,20 @@ inline void draw_vline(word x1, byte y1, byte h, byte color) { blitter.flags = (x1&1) ? DSTSCREEN|SOLID|ODDONLY : DSTSCREEN|SOLID|EVENONLY; } -inline void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) { +inline void blit_copy_solid(word x, byte y, byte w, byte h, const byte* data, byte solid) { blitter.width = w^4; blitter.height = h^4; - blitter.sstart = swapw((word)data); - blitter.dstart = x1+y1*256; // swapped - blitter.flags = DSTSCREEN|FGONLY; -} - -inline void blit_copy_solid(byte x1, byte y1, byte w, byte h, const byte* data, byte solid) { - blitter.width = w^4; - blitter.height = h^4; - blitter.sstart = swapw((word)data); - blitter.dstart = x1+y1*256; // swapped blitter.solid = solid; - blitter.flags = DSTSCREEN|FGONLY|SOLID; + blitter.sstart = swapw((word)data); + blitter.dstart = (x>>1)+y*256; // swapped + if (solid) + blitter.flags = (x&1) ? DSTSCREEN|FGONLY|SOLID|RSHIFT : DSTSCREEN|FGONLY|SOLID; + else + blitter.flags = (x&1) ? DSTSCREEN|RSHIFT : DSTSCREEN; } -// bias sprites by +12 pixels -#define XBIAS 6 +// bias sprites by +4 pixels +#define XBIAS 2 inline void draw_sprite(const byte* data, byte x, byte y) { blitter.width = data[0]^4; @@ -219,15 +282,18 @@ void erase_sprite_strided(const byte* data, byte x, byte y, byte stride) { } } -inline void draw_char(char ch, byte x, byte y, byte color) { - if (ch < LOCHAR || ch > HICHAR) return; - blit_copy_solid(x, y, 4, 8, font_table[ch - LOCHAR], color); +byte draw_char(char ch, word x, byte y, byte color) { + const byte* shape; + if (ch < LOCHAR || ch > HICHAR) return 1; + shape = FONT_TABLE[ch - LOCHAR]; + blit_copy_solid(x, y - (shape[1]>>4), + shape[0] & 0xf, shape[1] & 0xf, shape+2, color); + return shape[0] >> 4; } -void draw_string(const char* str, byte x, byte y, byte color) { +void draw_string(const char* str, word x, byte y, byte color) { while (*str) { - draw_char(*str++, x, y, color); - x += 4; + x += draw_char(*str++, x, y, color); } } @@ -498,6 +564,8 @@ static Actor* free_list; static Actor* effects_list; static byte frame; +static word score; // bcd score + #define PLAYER 1 #define LASER 2 @@ -513,12 +581,6 @@ void remove_actor(Actor* a) { *a->prevptr = a->next; } -char in_rect(const Actor* e, byte x, byte y, byte w, byte h) { - byte eh = e->shape[0]; - byte ew = e->shape[1]; - return (x >= e->x-w && x <= e->x+ew && y >= e->y-h && y <= e->y+eh); -} - void draw_actor_normal(Actor* a) { draw_sprite(a->shape, a->x, a->y); } @@ -565,6 +627,27 @@ word rand() { return lfsr; } +word bcd_add(word a, word b) { + a; b; // to avoid "unused variable" warning +__asm + ld hl,#4 + add hl,sp + ld iy,#2 + add iy,sp + ld a,0 (iy) ; load a (lo) + add a, (hl) ; add b (lo) + daa ; convert to BCD + ld c,a + ld a,1 (iy) ; load a (hi) + inc hl + adc a, (hl) ; add b (hi) + carry + daa + ld b,a + ld l, c + ld h, b ; result in HL reg +__endasm; +} + signed char random_dir() { byte x = rand(); if (x < 85) return 0; @@ -613,6 +696,8 @@ bool test_actor_pixels(Actor* a) { a->x + a->shape[0]*2); byte y2 = minbyte(test_actor->y + test_actor->shape[1], a->y + a->shape[1]); + if (x2 < x1) x2 = 255; // clip to 8-bit coord. + if (y2 < y1) y2 = 255; // clip to 8-bit coord. if (x2 <= x1 || y2 <= y1) return false; //draw_box(x1,y1,x2,y2,0xff); p1 = &test_actor->shape[2+(y1-test_actor->y)*test_actor->shape[0]]; @@ -655,6 +740,7 @@ void setup_collision(Actor* a) { void destroy_player() { Actor* a = &actors[PLAYER]; byte i; + sound_pia = 1; // play sound for (i=0; i<60; i++) { WATCHDOG; while (video_counter != 0xfc) ; @@ -699,12 +785,17 @@ void laser_move(Actor* a) { // move enemy to effects list remove_actor(collided); add_actor(&effects_list, collided); + // play sound + sound_pia = 2; + // add score + score = bcd_add(score, 5); return; } // move laser // check for wall collisions a->x += a->u.laser.dx; - if (a->x > 255-8) a->shape = NULL; + if (a->u.laser.dx > 0 && a->x < 8) a->shape = NULL; + if (a->u.laser.dx < 0 && a->x > 255-8) a->shape = NULL; a->y += a->u.laser.dy; if (a->y > 255-8) a->shape = NULL; } @@ -765,11 +856,6 @@ Actor* new_actor() { return a; } -void redraw_playfield(Actor* a) { - a; - draw_box(0,0,303,255,0x11); -} - Actor* new_effect(ActorDrawFn draw) { Actor* a = new_actor(); a->draw = draw; @@ -782,13 +868,13 @@ void init() { blit_solid(0, 0, 255, 255, 0); memset(actors, 0, sizeof(actors)); memcpy(palette, palette_data, 16); - fill_char_table(); player_list = fast_list = obstacle_list = free_list = NULL; memset(slow_lists, 0, sizeof(slow_lists)); // add all actors to free list for (i=MAX_ACTORS-1; i>0; i--) { add_actor(&free_list, &actors[i]); } + score = 0; } void make_player_actors() { @@ -823,13 +909,42 @@ void make_enemy_actors() { } } +void draw_bcd_word(word bcd, word x, byte y, byte color) { + byte j; + x += 4*4; + for (j=0; j<4; j++) { + x -= 4; + draw_char('0'+(bcd & 0xf), x, y, color); + bcd >>= 4; + } +} + +void draw_score(Actor* a) { + a; + draw_string("Plyr 1", 278, 8, 0xee); + // draw digits in color 0 so the background is erased + draw_bcd_word(score, 278, 20, 0); + // last two digits of score are "00" + draw_char('0', 278+16, 20, 0); + draw_char('0', 278+20, 20, 0); +} + +void draw_playfield(Actor* a) { + a; + draw_box(0,0,275,255,0x11); +} + void main() { init(); make_player_actors(); make_enemy_actors(); - new_effect(redraw_playfield); - WATCHDOG; + // add low-priority effects here, because new effects + // are added to the head of the list + new_effect(draw_score); + new_effect(draw_playfield); + // main loop while (actors[PLAYER].shape) { + WATCHDOG; effects_new_frame(); while (video_counter >= 0x90) effects_next(); update_screen_section(1); @@ -837,11 +952,17 @@ void main() { update_screen_section(0); switch (frame & 7) { case 0: - draw_box(0,0,303,255,0x11); break; } frame++; - WATCHDOG; } main(); } + +// SOUND ROM + +const byte __at(0x9000) SOUND_ROM[] = { +0xdb,0x00,0xb7,0x20,0x01,0x76,0x11,0x02,0x40,0xdb,0x00,0x4f,0x0d,0x06,0x00,0x69,0x60,0x29,0x29,0x09,0x29,0x01,0xc5,0x00,0x09,0x01,0x0a,0x00,0xed,0xb0,0xcd,0x04,0x01,0x3e,0x00,0xd3,0x00,0x76,0xc9,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0xc0,0x40,0x80,0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,0xc0,0xc8,0xd0,0xd8,0xe0,0xe8,0xf0,0xf8,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50, +0x58,0x60,0x68,0x70,0x78,0x00,0x0c,0x18,0x24,0x2d,0x35,0x3b,0x3f,0x40,0x3f,0x3b,0x35,0x2d,0x24,0x18,0x0c,0x00,0xf4,0xe8,0xdc,0xd3,0xcb,0xc5,0xc1,0xc0,0xc1,0xc5,0xcb,0xd3,0xdc,0xe8,0xf4,0x60,0x37,0x3f,0x5c,0x16,0xca,0xc2,0xa5,0xfe,0xba,0x77,0x89,0xaa,0x77,0x13,0xd8,0xae,0x82,0xfd,0x22,0x9c,0x46,0xde,0x14,0x50,0xb4,0x97,0x46,0x54,0x9d,0x60,0x2b,0xd0,0x07,0x00,0x00,0xb8,0x0b,0xff,0xff,0x40,0x00,0xf4,0x01,0x00,0x00,0xd0,0x07,0xfc,0xff,0x60,0x00,0xed,0x4b,0x04,0x40,0x78,0x0f,0x0f,0x0f,0xe6,0x1f,0xe6,0x1f,0x5f,0x16,0x00,0xfd,0x21,0x00,0x40,0xfd,0x7e,0x00,0x83,0x5f,0xfd,0x7e,0x01,0x8a,0x57,0x1a,0xd3,0x00,0x2a,0x06,0x40,0x09,0x4d,0x44,0xed, +0x43,0x04,0x40,0xc9,0x01,0x27,0x00,0x21,0x0a,0x40,0x5e,0x6b,0x26,0x00,0x09,0x22,0x00,0x40,0xed,0x4b,0x02,0x40,0x59,0x50,0x1b,0xed,0x53,0x02,0x40,0x78,0xb1,0xc8,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xcd,0xd9,0x00,0xed,0x4b,0x06,0x40,0x2a,0x08,0x40,0x09,0x4d,0x44,0xed,0x43,0x06,0x40,0xed,0x4b,0x08,0x40,0x3a,0x0b,0x40,0x6f,0x17,0x9f,0x67,0x09,0x4d,0x44,0xed,0x43,0x08,0x40,0x18,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; diff --git a/src/audio/z80worker.js b/src/audio/z80worker.js index f94fb30e..36f4d8c0 100644 --- a/src/audio/z80worker.js +++ b/src/audio/z80worker.js @@ -51,6 +51,9 @@ var cpuFrequency = 18432000/6; // 3.072 MHz var cpuCyclesPerFrame = cpuFrequency/60; var cpuAudioFactor = 32; +rom = new RAM(0x4000).mem; +// sample: [0xe,0x0,0x6,0x0,0x78,0xb9,0x30,0x06,0xa9,0xd3,0x00,0x04,0x18,0xf6,0x0c,0x79,0xd6,0xff,0x38,0xee,0x76,0x18,0xea]; +rom.fill(0x76); // HALT opcodes function fillBuffer() { var t = cpu.getTstates() / cpuAudioFactor; @@ -63,9 +66,6 @@ function fillBuffer() { function start() { ram = new RAM(0x400); - rom = new RAM(0x4000).mem; - // sample: [0xe,0x0,0x6,0x0,0x78,0xb9,0x30,0x06,0xa9,0xd3,0x00,0x04,0x18,0xf6,0x0c,0x79,0xd6,0xff,0x38,0xee,0x76,0x18,0xea]; - rom.fill(0x76); // HALT opcodes membus = { read: new AddressDecoder([ [0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }], @@ -91,6 +91,7 @@ function start() { ioBus: iobus }); current_buffer = new Int16Array(bufferLength); + console.log('started audio'); } function timerCallback() { @@ -115,6 +116,7 @@ function timerCallback() { function reset() { if (!bufferLength) return; + cpu.setHalted(0); cpu.reset(); if (!timer) { curTime = new Date().getTime() - timerPeriod*4; diff --git a/src/platform/sound_williams.js b/src/platform/sound_williams.js index e8fe2f70..0bf1052b 100644 --- a/src/platform/sound_williams.js +++ b/src/platform/sound_williams.js @@ -1,7 +1,7 @@ "use strict"; var WILLIAMS_SOUND_PRESETS = [ - {id:'wavetable.c', name:'Wavetable Synth'}, + {id:'swave.c', name:'Wavetable Synth'}, ]; /**************************************************************************** diff --git a/src/platform/williams.js b/src/platform/williams.js index e9fbf635..546fe689 100644 --- a/src/platform/williams.js +++ b/src/platform/williams.js @@ -131,7 +131,7 @@ var WilliamsPlatform = function(mainElement, proto) { var iowrite_williams = new AddressDecoder([ [0x0, 0xf, 0xf, setPalette], - [0x803, 0x803, 0xf, function(a,v) { if (worker) worker.postMessage({command:v}); }], + [0x80c, 0x80c, 0xf, function(a,v) { if (worker) worker.postMessage({command:v}); }], //[0x804, 0x807, 0x3, function(a,v) { console.log('iowrite',a); }], // TODO: sound //[0x80c, 0x80f, 0x3, function(a,v) { console.log('iowrite',a+4); }], // TODO: sound [0x900, 0x9ff, 0, function(a,v) { banksel = v & 0x1; }], @@ -338,6 +338,7 @@ var WilliamsPlatform = function(mainElement, proto) { } this.loadSoundROM = function(data) { + console.log("loading sound ROM " + data.length + " bytes"); var soundrom = padBytes(data, 0x4000); worker.postMessage({rom:soundrom}); } @@ -346,10 +347,12 @@ var WilliamsPlatform = function(mainElement, proto) { if (data.length > 2) { if (data.length > 0xc000) { self.loadSoundROM(data.slice(0xc000)); - rom = rom.slice(data, 0, 0xc000); - } else { - rom = padBytes(data, 0xc000); + rom = rom.slice(0, 0xc000); } + else if (data.length > 0x9000 && data[0x9000]) { + self.loadSoundROM(data.slice(0x9000)); + } + rom = padBytes(data, 0xc000); } self.reset(); } diff --git a/tools/parsebdf4bit.py b/tools/parsebdf4bit.py new file mode 100755 index 00000000..1f3110fb --- /dev/null +++ b/tools/parsebdf4bit.py @@ -0,0 +1,71 @@ +#!/usr/bin/python + +import sys,string,argparse + +#lochar = 0x20 #48 +#hichar = 0x5e #57 + +parser = argparse.ArgumentParser() +parser.add_argument('-s', '--start', type=int, default=0, help="index of first character") +parser.add_argument('-e', '--end', type=int, default=255, help="index of last character") +parser.add_argument('-i', '--invert', action="store_true", help="invert bits") +parser.add_argument('-r', '--rotate', action="store_true", help="rotate bits (vertical)") +parser.add_argument('-f', '--flip', action="store_true", help="flip bits (horizontal)") +parser.add_argument('bdffile', help="BDF bitmap file") +args = parser.parse_args() + +lochar = args.start +hichar = args.end +invert = args.invert +flip = args.flip +rotate = args.rotate + +def tohex(v): + return '%02x'%v +def tohex2(v): + return '0x%02x'%v + +chars = {} +inbitmap = 0 +with open(sys.argv[1],'r') as f: + lines = f.readlines() + for l in lines: + l = l.strip() + toks = l.split() + #print l,toks + if toks[0] == 'ENCODING': + chord = int(toks[1]) + elif toks[0] == 'BITMAP': + inbitmap = True + bytes = [] + elif toks[0] == 'BBX': + bbx = [int(x) for x in toks[1:]] + elif toks[0] == 'ENDCHAR': + inbitmap = False + if chord >= lochar and chord <= hichar: + #bytes.reverse() + #print chord,bytes,bbx + width = bbx[0]+1 + height = bbx[1] + output = [(width+1)//2 + (width)*16, height + (height+bbx[3])*16] + for y in range(0,height): + for x in range(0,width,2): + b = 0 + if bytes[y] & (0x80 >> x): + b |= 0xf0 + if bytes[y] & (0x40 >> x): + b |= 0x0f + output.append(b) + print 'const char CH_%d[] = { %s };' % ( chord, string.join([tohex2(x) for x in output], ',') ) + chars[chord] = 'CH_%d' % chord + elif inbitmap and len(toks) == 1: + byte = int(toks[0],16) + bytes.append(byte) + +print 'const char* const FONT_TABLE[%d] = {' % (hichar-lochar+1), +for ch in range(lochar, hichar+1): + if chars.get(ch): + print '%s,' % chars[ch], + else: + print '0,', +print "};" diff --git a/tools/sintbl.py b/tools/sintbl.py index d21e75b4..487b1a24 100644 --- a/tools/sintbl.py +++ b/tools/sintbl.py @@ -7,6 +7,7 @@ import math n = 64 m = 127 + for i in range(0,n*4): print '%d,' % int(round(math.sin(i*math.pi/2/n)*m)), if i % 16 == 15: