diff --git a/package.json b/package.json index ba05287b..4fb9cf30 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "scripts": { "test": "npm run test-node && npm run test-browser", - "test-node": "mocha --recursive --timeout 5000 test/cli", + "test-node": "mocha --recursive --timeout 20000 test/cli", "test-browser": "mocha-phantomjs ./testemu.html" }, "repository": { diff --git a/presets/galaxian-scramble/gfxtest.c b/presets/galaxian-scramble/gfxtest.c index 18d65618..fc4554a4 100644 --- a/presets/galaxian-scramble/gfxtest.c +++ b/presets/galaxian-scramble/gfxtest.c @@ -97,26 +97,6 @@ void putstring(byte x, byte y, const char* string) { static int frame; -void testpattern() { - byte i; - watchdog++; - for (i=0; i<32; i++) { - columns[i].attrib = i; - columns[i].scroll = frame; - } - for (i=0; i<8; i++) { - sprites[i].xpos = i*16-frame; - sprites[i].ypos = i*32; - sprites[i].code = i*8; - sprites[i].color = i; - } - for (i=0; i<8; i++) { - missiles[i].xpos = i*32; - missiles[i].ypos = i*16-frame; - } - frame++; -} - void draw_all_chars() { byte i; i = 0; @@ -129,16 +109,6 @@ void draw_all_chars() { } while (++i); } -void draw_test_sprites() { - byte i; - for (i=0; i<8; i++) { - sprites[i].xpos = i*16-frame; - sprites[i].ypos = 190; - sprites[i].code = i+16; - sprites[i].color = 2; - } -} - void putshape(byte x, byte y, byte ofs) { putchar(x, y, ofs+2); putchar(x+1, y, ofs); @@ -146,7 +116,7 @@ void putshape(byte x, byte y, byte ofs) { putchar(x+1, y+1, ofs+1); } -void draw_alien(byte ofs, byte y) { +void draw_sprites(byte ofs, byte y) { byte i; byte x = 0; columns[y].attrib = 1; @@ -175,17 +145,36 @@ void draw_explosion(byte ofs, byte y) { } } +void draw_missiles() { + byte i; + for (i=0; i<7; i++) { + missiles[i].ypos = i + 24; + missiles[i].xpos = i*16 + frame; + sprites[i].xpos = i*32 + frame; + sprites[i].ypos = i*24 + frame; + } +} + +void draw_corners() { + vram[2][0]++; + vram[2][31]++; + vram[29][0]++; + vram[29][31]++; +} + void main() { clrscr(); while (1) { draw_all_chars(); - //draw_test_sprites(); - draw_alien(0x30, 18); - draw_alien(0x50, 21); - draw_alien(0x70, 24); - draw_alien(0xa0, 27); + draw_sprites(0x30, 18); + draw_sprites(0x50, 21); + draw_sprites(0x70, 24); + draw_sprites(0xa0, 27); + draw_sprites(0x0, 29); draw_explosion(0xc0, 12); - putstring(0, 0, "HELLO@WORLD@123"); + draw_missiles(); + putstring(7, 0, "HELLO@WORLD@123"); + draw_corners(); columns[1].attrib = frame; enable_stars = 0&0xff; frame++; diff --git a/presets/galaxian-scramble/shoot2.c b/presets/galaxian-scramble/shoot2.c index 4b8b8500..039cbd3c 100644 --- a/presets/galaxian-scramble/shoot2.c +++ b/presets/galaxian-scramble/shoot2.c @@ -28,8 +28,8 @@ byte __at (0x5080) xram[128]; byte __at (0x6801) enable_irq; byte __at (0x6804) enable_stars; -byte __at (0x6805) missile_width; -byte __at (0x6806) missile_offset; +byte __at (0x6808) missile_width; +byte __at (0x6809) missile_offset; byte __at (0x7000) watchdog; byte __at (0x8100) input0; byte __at (0x8101) input1; diff --git a/presets/mw8080bw/shifter.c b/presets/mw8080bw/shifter.c new file mode 100644 index 00000000..61b7c616 --- /dev/null +++ b/presets/mw8080bw/shifter.c @@ -0,0 +1,60 @@ + +#include + +typedef unsigned char byte; +typedef unsigned char word; + +__sfr __at (0x2) bitshift_offset; +__sfr __at (0x3) bitshift_read; +__sfr __at (0x4) bitshift_value; +__sfr __at (0x6) watchdog_strobe; + +byte __at (0x2400) vidmem[224][32]; // 256x224x1 video memory + +void main(); +// start routine @ 0x0 +// set stack pointer, enable interrupts +void start() { +__asm + LD SP,#0x2400 + DI +__endasm; + main(); +} + +const byte bitmap1[] = +{9,56,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,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x00,0x00,0x00,0x00,0x80,0xfb,0xff,0xf0,0x01,0x00,0x00,0x00,0x00,0x40,0x04,0x80,0xf3,0x01,0x00,0x00,0x00,0x00,0xb8,0x00,0x00,0xfa,0x01,0x00,0x00,0x00,0x00,0x06,0xfe,0x03,0xfa,0x01,0x00,0x00,0x00,0x00,0x83,0xff,0x03,0xfd,0x01,0x80,0x00,0x00,0x00,0x81,0xcf,0x00,0xfc,0x00,0x80,0x01,0xc0,0x9f,0x01,0x00,0x00,0xfc,0x00,0x80,0x01,0x30,0xe0,0x00,0x00,0x00,0xf8,0x00,0xc0,0x01,0x0c,0x84,0x41,0x00,0x00,0xf8,0x01,0xc0,0x07,0x04,0xf8,0xc2,0x00,0x00,0xf8,0x03,0xc0,0x07,0x06,0x00,0x43,0x00,0x00,0xf2,0x03,0xc0,0x07,0x02,0x80,0x00,0xf8,0x0f,0xe4,0x03,0xe0,0xff,0x04,0xf8,0x00,0xfe,0x1f,0xe8,0x07,0xe0,0x03,0x07,0x80,0x00,0xbe,0x0f,0xec,0x07,0xe0,0x01,0x06,0x80,0x00,0x3c,0x00,0x92,0x07,0xe0,0x00,0x0a,0xff,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x24,0x08,0x01,0x00,0x00,0x00,0x07,0x60,0x00,0xc6,0x88,0x01,0x00,0x00,0x00,0x07,0x60,0x00,0x02,0x7e,0x03,0x00,0x00,0x80,0x07,0x60,0x00,0xfe,0x27,0x02,0x00,0x00,0x80,0x07,0x60,0x00,0xc1,0x43,0x02,0x00,0x00,0xc0,0x07,0x70,0xc0,0xc0,0x43,0x04,0x00,0x00,0xc0,0x03,0x70,0x40,0xc1,0x67,0x08,0x00,0x00,0xe0,0x03,0x70,0x00,0xe1,0x7f,0x10,0x00,0x1c,0xf0,0x01,0xf0,0x00,0xfa,0xff,0xa0,0x01,0x7f,0xfe,0x00,0xf0,0x00,0xe2,0x1f,0xc1,0x60,0xfe,0x7f,0x00,0xe0,0x81,0x87,0x0f,0x82,0x81,0xfe,0x3f,0x00,0xe0,0x83,0xc8,0x0f,0x02,0xa5,0xfe,0x0f,0x00,0xe0,0x7f,0xf9,0xbf,0x13,0x9f,0xfd,0x00,0x00,0xe0,0x03,0x81,0xff,0x1f,0x61,0x00,0x00,0x06,0xe0,0x03,0x02,0xfe,0x8f,0x01,0x00,0x6c,0x04,0x80,0x01,0x02,0xfc,0x83,0x01,0x00,0xc0,0x04,0x80,0x01,0x03,0x0e,0x81,0x00,0x04,0x80,0x03,0x80,0x01,0xfe,0x01,0x62,0x50,0x08,0x00,0x00,0x80,0x01,0x48,0x00,0x1c,0x80,0x08,0x00,0x00,0x80,0x03,0x50,0x00,0x1c,0x00,0x07,0x00,0x00,0x80,0x03,0x50,0x00,0x34,0x00,0x00,0x00,0x00,0x80,0x03,0x50,0x00,0x24,0x00,0x00,0x00,0x00,0x80,0x07,0x90,0x00,0x3a,0x00,0x00,0x00,0x00,0x80,0x0f,0x98,0x00,0x10,0x00,0x00,0x00,0x00,0x80,0x3f,0x0c,0x07,0x10,0x00,0x00,0x00,0x00,0x00,0xc1,0x03,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,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,0x00,0x00} +; + +void draw_shifted_sprite(const byte* src, byte x, byte y) { + byte i,j; + byte* dest = &vidmem[x][y>>3]; + byte w = *src++; + byte h = *src++; + bitshift_offset = y & 7; + for (j=0; j #include +#include typedef unsigned char byte; typedef unsigned short word; @@ -9,14 +10,16 @@ typedef signed char sbyte; word __at(0xa000) dvgram[0x1000]; byte __at(0x8840) _dvgstart; -int __at(0x8100) mathbox_sum; +volatile int __at(0x8100) mathbox_sum; sbyte __at(0x8102) mathbox_arg1; sbyte __at(0x8103) mathbox_arg2; byte __at(0x810f) mathbox_go_mul; -byte __at (0x8000) input0; -byte __at (0x8001) input1; -byte __at (0x8002) input2; +volatile byte __at (0x8000) input0; +volatile byte __at (0x8001) input1; +volatile byte __at (0x8002) input2; +volatile byte __at (0x8980) watchdog; +volatile byte __at (0x800f) vidframe; #define LEFT1 !(input1 & 0x8) #define RIGHT1 !(input1 & 0x4) @@ -103,6 +106,10 @@ 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); } @@ -204,7 +211,7 @@ void draw_char(char ch) { byte x2 = b>>4; byte y2 = b&15; SVEC((char)(x2-x), (char)(y2-y), bright); - bright = 4; + bright = 2; x = x2; y = y2; } @@ -212,9 +219,21 @@ void draw_char(char ch) { 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 draw_string(const char* str, byte spacing) { while (*str) { - draw_char(*str++); + JSRL(font_shapes[*str++ - 0x20]); if (spacing) SVEC(spacing, 0, 0); } } @@ -305,8 +324,8 @@ void mat_rotate(Matrix* m, byte axis, byte angle) { break; case 2: m->m[0][0] = cos; - m->m[1][0] = sin; - m->m[0][1] = -sin; + m->m[1][0] = -sin; + m->m[0][1] = sin; m->m[1][1] = cos; break; } @@ -358,22 +377,44 @@ 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 ship_v[] = { {0,-86,0},{-30,30,0},{-50,0,0},{50,0,0},{30,30,0} }; +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 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 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); @@ -383,9 +424,19 @@ void make_cached_shapes() { RTSL(); tetra_shapes[i] = dvgwrofs; mat_rotate(&mat, 0, i<<3); - draw_wireframe_ortho(&tetra_wf, &mat); + 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(); } // MAIN PROGRAM @@ -401,12 +452,14 @@ typedef struct Actor { 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 @@ -435,31 +488,9 @@ Actor* new_actor(const Actor* base) { return a; } -void obstacle_update_fn(struct Actor* a) { - a->angle += 1; -} - -const Actor ship_actor = { - ship_shapes, NULL, 3, 0xb0, WHITE, 7, 0, -}; - -const Actor tetra_actor = { - tetra_shapes, obstacle_update_fn, 3, 0x80, CYAN, 7, 0, -}; - -void create_obstacles(byte count) { - while (count--) { - Actor* a = new_actor(&tetra_actor); - a->xx = rand(); - a->yy = rand(); - a->velx = (int)rand()<<8>>8; - a->vely = (int)rand()<<8>>8; - } -} - -void update_actors() { +void draw_and_update_actors() { Actor* a = first_actor; - while (a) { + while (a != NULL) { draw_actor(a); move_actor(a); if (a->update_fn) a->update_fn(a); @@ -467,6 +498,24 @@ void update_actors() { } } +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 { + // get address of next pointer + prev = &a->next; + } + } +} + void draw_actor_rect(Actor* a) { CNTR(); // center beam (0,0) SCAL(WORLD_SCALE); // world scale @@ -484,28 +533,100 @@ inline byte abs(sbyte x) { return (x>=0) ? x : -x; } -inline sbyte get_distance(byte x1, byte y1, byte x2, byte y2) { - sbyte dx = abs(x2-x1); - sbyte dy = abs(y2-y1); - return (dx>>1) + (dy>>1); +inline word get_distance_squared(byte dx, byte dy) { + mathbox_sum = 0; + mul16(dx,dx); + mul16(dy,dy); + return mathbox_sum; } -Actor* test_actor_distance(ActorUpdateFn* fn, Actor* act1, byte mindist) { +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) { - if (a != act1) { - sbyte dist = get_distance(xx1, yy1, a->xx >> 8, a->yy >> 8); - if (dist < mindist) fn(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; +static Actor* curship = NULL; void draw_thrust() { word rnd = rand(); @@ -530,7 +651,7 @@ void thrust_ship() { sbyte sin = isin(curship->angle); sbyte cos = icos(curship->angle); curship->velx += sin>>3; - curship->vely -= cos>>3; + curship->vely += cos>>3; } int apply_friction(int vel) { @@ -539,37 +660,89 @@ int apply_friction(int vel) { return vel - delta; } -void move_player() { +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&3)==1) { + + 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 colorful flame + // draw flame draw_thrust(); // thrust every 4 frames, to avoid precision issues if (!(frame&3)) thrust_ship(); } - test_actor_distance(draw_actor_rect, curship, 32); + 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() { memset(dvgram, 0x20, sizeof(dvgram)); // HALTs dvgwrofs = 0x800; - //draw_string("HELLO WORLD", 0); - //RTSL(); + make_cached_font(); make_cached_shapes(); create_obstacles(5); - curship = new_actor(&ship_actor); - while (1) { + new_player_ship(); + while (!just_one_actor_left()) { dvgreset(); - update_actors(); - move_player(); + control_player(); + draw_and_update_actors(); + CNTR(); HALT(); dvgstart(); + remove_expired_actors(); frame++; + watchdog=0; + while (vidframe == (frame & 0x3)) {} } + main(); } diff --git a/presets/williams-z80/bitmap_rle.c b/presets/williams-z80/bitmap_rle.c new file mode 100644 index 00000000..9fabcc51 --- /dev/null +++ b/presets/williams-z80/bitmap_rle.c @@ -0,0 +1,151 @@ + +#include + +typedef unsigned char byte; +typedef unsigned short word; + +byte __at (0xc000) palette[16]; +byte __at (0xc800) input0; +byte __at (0xc802) input1; +byte __at (0xc804) input2; +byte __at (0xc900) rom_select; +byte __at (0xcb00) video_counter; +byte __at (0xcbff) watchdog0x39; +byte __at (0xcc00) nvram[0x400]; + +byte __at (0x0) vidmem[152][256]; // 256x304x4bpp video memory + +void main(); + +// start routine @ 0x0 +// set stack pointer, enable interrupts +void start() { +__asm + LD SP,#0xc000 + DI +__endasm; + main(); +} + +const byte example_tga[] = { +0x00,0x01,0x09,0x00,0x00,0x08,0x00,0x18,0x00,0x00,0x00,0x00,0x80,0x00,0x60,0x00,0x08,0x00,0x01,0x01,0x01,0x67,0x3b,0x4e,0x9f,0x43,0x58,0xc5,0x56,0xbe,0xac,0xa8,0xac,0xe3,0xe0,0xe0,0xde,0xab,0xbc,0xd6,0xa5,0x72,0xff,0x00,0xff,0x00,0xd1,0x00,0x02,0x01,0x03,0x03,0xaa,0x00,0xd1,0x00,0x01,0x03,0x03,0xab,0x00,0xd1,0x00,0x01,0x03,0x03,0xab,0x00,0xcf,0x00,0x02,0x01,0x03,0x03,0xac,0x00,0xd0,0x00,0x01,0x03,0x03,0xac,0x00,0xb3,0x00,0x02,0x03,0x03,0x00,0x82,0x03,0x95,0x00,0x01,0x03,0x03,0xad,0x00,0xb2,0x00,0x86,0x03,0x95,0x00,0x02,0x03,0x03,0x01,0xac,0x00,0xb1,0x00,0x83,0x03,0x03,0x01,0x01,0x03,0x03,0x94,0x00,0x01,0x03,0x03,0xae,0x00,0xb0,0x00, +0x00,0x01,0x82,0x03,0x04,0x00,0x01,0x01,0x06,0x03,0x94,0x00,0x00,0x03,0xaf,0x00,0xb0,0x00,0x82,0x03,0x04,0x01,0x01,0x03,0x03,0x06,0x95,0x00,0x00,0x03,0xaf,0x00,0xb0,0x00,0x01,0x03,0x03,0x82,0x01,0x82,0x03,0x90,0x00,0x05,0x01,0x03,0x03,0x01,0x03,0x03,0xaf,0x00,0xaf,0x00,0x82,0x03,0x01,0x01,0x01,0x82,0x03,0x91,0x00,0x84,0x03,0xb0,0x00,0xae,0x00,0x00,0x01,0x82,0x03,0x00,0x02,0x82,0x03,0x02,0x01,0x00,0x01,0x84,0x00,0x82,0x03,0x86,0x00,0x85,0x03,0x00,0x01,0xaf,0x00,0xae,0x00,0x8b,0x03,0x83,0x00,0x82,0x03,0x85,0x00,0x83,0x03,0x01,0x06,0x03,0xb1,0x00,0x96,0x00,0x08,0x05,0x03,0x06,0x03,0x03,0x06,0x03,0x06,0x06,0x82,0x03,0x01,0x05,0x06,0x82, +0x03,0x06,0x06,0x03,0x06,0x06,0x03,0x06,0x06,0x8c,0x03,0x00,0x06,0x8e,0x03,0x01,0x06,0x03,0x82,0x00,0x00,0x05,0x82,0x03,0x82,0x06,0x00,0x07,0x84,0x06,0x00,0x07,0x82,0x06,0x82,0x07,0x02,0x06,0x07,0x07,0x83,0x06,0x93,0x00,0x96,0x00,0x00,0x06,0x9c,0x03,0x82,0x01,0x87,0x03,0x00,0x02,0x88,0x03,0x02,0x02,0x03,0x03,0x84,0x00,0x05,0x03,0x01,0x02,0x03,0x02,0x07,0x84,0x02,0x00,0x07,0x83,0x02,0x05,0x07,0x02,0x07,0x07,0x02,0x02,0x82,0x07,0x00,0x06,0x93,0x00,0x97,0x00,0x06,0x03,0x03,0x01,0x02,0x01,0x01,0x03,0x82,0x01,0x04,0x03,0x03,0x01,0x01,0x03,0x85,0x01,0x85,0x03,0x84,0x01,0x82,0x03,0x00,0x02,0x83,0x03,0x00,0x01,0x88,0x03,0x02,0x02,0x03,0x06, +0x83,0x00,0x01,0x03,0x02,0x82,0x01,0x02,0x02,0x01,0x02,0x82,0x01,0x00,0x02,0x82,0x01,0x82,0x02,0x00,0x01,0x84,0x02,0x01,0x07,0x06,0x94,0x00,0x97,0x00,0x01,0x06,0x03,0x84,0x01,0x04,0x03,0x01,0x01,0x03,0x03,0x87,0x01,0x84,0x03,0x07,0x01,0x00,0x01,0x00,0x01,0x02,0x03,0x06,0x85,0x03,0x00,0x01,0x84,0x03,0x00,0x06,0x82,0x03,0x00,0x01,0x82,0x03,0x83,0x00,0x04,0x03,0x01,0x01,0x02,0x02,0x83,0x01,0x82,0x02,0x84,0x01,0x01,0x02,0x02,0x83,0x01,0x01,0x02,0x07,0x95,0x00,0x98,0x00,0x0a,0x03,0x03,0x01,0x01,0x00,0x01,0x03,0x01,0x01,0x03,0x03,0x88,0x01,0x04,0x03,0x03,0x01,0x01,0x00,0x83,0x01,0x00,0x02,0x82,0x03,0x00,0x01,0x83,0x03,0x00,0x01,0x8b,0x03, +0x83,0x00,0x0c,0x03,0x01,0x01,0x02,0x01,0x01,0x02,0x02,0x01,0x02,0x01,0x01,0x02,0x83,0x01,0x01,0x02,0x02,0x83,0x01,0x02,0x02,0x07,0x06,0x95,0x00,0x99,0x00,0x00,0x03,0x87,0x01,0x01,0x03,0x03,0x86,0x01,0x82,0x03,0x86,0x01,0x82,0x03,0x01,0x02,0x02,0x82,0x03,0x02,0x02,0x03,0x06,0x8a,0x03,0x83,0x00,0x00,0x02,0x84,0x01,0x02,0x07,0x02,0x02,0x86,0x01,0x08,0x02,0x01,0x01,0x02,0x01,0x01,0x02,0x02,0x07,0x96,0x00,0x99,0x00,0x01,0x03,0x03,0x83,0x01,0x04,0x03,0x01,0x01,0x03,0x03,0x86,0x01,0x02,0x03,0x06,0x03,0x84,0x01,0x00,0x02,0x82,0x03,0x82,0x01,0x82,0x03,0x00,0x02,0x85,0x03,0x01,0x01,0x06,0x84,0x03,0x82,0x00,0x02,0x03,0x01,0x00,0x83,0x01,0x05, +0x02,0x07,0x02,0x01,0x01,0x02,0x82,0x01,0x03,0x02,0x02,0x01,0x02,0x82,0x01,0x02,0x02,0x07,0x06,0x96,0x00,0x9a,0x00,0x01,0x03,0x03,0x83,0x01,0x04,0x03,0x01,0x01,0x03,0x03,0x84,0x01,0x82,0x03,0x00,0x02,0x84,0x01,0x82,0x03,0x82,0x01,0x00,0x02,0x83,0x03,0x00,0x02,0x83,0x03,0x0d,0x01,0x01,0x03,0x03,0x01,0x01,0x02,0x06,0x00,0x00,0x03,0x02,0x01,0x02,0x83,0x01,0x01,0x02,0x02,0x89,0x01,0x05,0x02,0x01,0x01,0x02,0x02,0x06,0x97,0x00,0x9a,0x00,0x01,0x06,0x03,0x83,0x01,0x04,0x03,0x01,0x01,0x03,0x03,0x84,0x01,0x82,0x03,0x84,0x01,0x83,0x03,0x83,0x01,0x83,0x03,0x06,0x01,0x01,0x02,0x03,0x02,0x00,0x02,0x83,0x00,0x00,0x02,0x83,0x03,0x00,0x00,0x90,0x01, +0x00,0x02,0x82,0x01,0x01,0x02,0x07,0x98,0x00,0x9b,0x00,0x01,0x03,0x03,0x82,0x01,0x05,0x03,0x03,0x01,0x01,0x03,0x03,0x83,0x01,0x82,0x03,0x83,0x01,0x82,0x03,0x0c,0x01,0x00,0x01,0x01,0x02,0x01,0x01,0x03,0x02,0x00,0x01,0x01,0x00,0x82,0x01,0x07,0x02,0x02,0x01,0x02,0x02,0x01,0x02,0x02,0x85,0x01,0x0c,0x02,0x02,0x01,0x01,0x02,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x02,0x83,0x01,0x02,0x02,0x02,0x06,0x98,0x00,0x9b,0x00,0x01,0x03,0x03,0x83,0x01,0x01,0x03,0x01,0x82,0x03,0x82,0x01,0x83,0x03,0x02,0x01,0x01,0x02,0x82,0x03,0x87,0x01,0x01,0x00,0x00,0x83,0x01,0x00,0x00,0x85,0x01,0x03,0x02,0x01,0x00,0x00,0x83,0x01,0x01,0x02,0x02,0x84,0x01,0x00,0x02,0x84, +0x01,0x83,0x02,0x03,0x01,0x02,0x02,0x06,0x99,0x00,0x9c,0x00,0x02,0x03,0x03,0x02,0x82,0x01,0x03,0x03,0x01,0x03,0x03,0x82,0x01,0x88,0x03,0x07,0x01,0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x82,0x01,0x07,0x02,0x01,0x02,0x01,0x01,0x02,0x02,0x01,0x86,0x02,0x82,0x01,0x0a,0x02,0x02,0x01,0x02,0x02,0x01,0x02,0x02,0x01,0x02,0x02,0x82,0x01,0x82,0x02,0x04,0x01,0x01,0x02,0x07,0x06,0x99,0x00,0x9c,0x00,0x07,0x05,0x03,0x03,0x01,0x01,0x02,0x03,0x04,0x83,0x03,0x00,0x01,0x86,0x03,0x0a,0x01,0x00,0x01,0x02,0x01,0x02,0x01,0x02,0x02,0x01,0x01,0x82,0x02,0x09,0x01,0x02,0x01,0x01,0x02,0x01,0x02,0x02,0x01,0x01,0x84,0x02,0x00,0x01,0x83,0x02,0x08,0x01,0x02,0x01,0x02, +0x01,0x02,0x01,0x02,0x01,0x86,0x02,0x01,0x07,0x06,0x9a,0x00,0x9d,0x00,0x06,0x03,0x03,0x02,0x01,0x03,0x01,0x02,0x82,0x03,0x00,0x01,0x82,0x03,0x06,0x01,0x01,0x02,0x01,0x00,0x01,0x01,0x84,0x02,0x00,0x01,0x82,0x02,0x01,0x01,0x01,0x84,0x02,0x07,0x01,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x83,0x02,0x06,0x01,0x02,0x01,0x02,0x01,0x02,0x02,0x82,0x01,0x01,0x02,0x01,0x87,0x02,0x01,0x07,0x05,0x9a,0x00,0x9e,0x00,0x01,0x03,0x03,0x82,0x01,0x01,0x03,0x02,0x85,0x03,0x84,0x01,0x02,0x02,0x01,0x01,0x82,0x02,0x04,0x01,0x01,0x02,0x02,0x01,0x84,0x02,0x00,0x01,0x84,0x02,0x00,0x01,0x82,0x02,0x00,0x01,0x85,0x02,0x00,0x01,0x87,0x02,0x00,0x01,0x85,0x02,0x01,0x07, +0x06,0x9b,0x00,0x9e,0x00,0x04,0x05,0x03,0x01,0x03,0x01,0x87,0x03,0x83,0x01,0x02,0x02,0x02,0x03,0x98,0x02,0x00,0x01,0x86,0x02,0x00,0x01,0x8c,0x02,0x01,0x06,0x06,0x9b,0x00,0x9e,0x00,0x13,0x05,0x05,0x03,0x03,0x06,0x04,0x04,0x03,0x06,0x06,0x03,0x01,0x03,0x04,0x03,0x03,0x04,0x03,0x03,0x01,0x8c,0x02,0x08,0x03,0x06,0x03,0x04,0x03,0x06,0x03,0x04,0x06,0x82,0x03,0x89,0x02,0x0d,0x01,0x04,0x06,0x03,0x04,0x06,0x06,0x03,0x04,0x04,0x07,0x07,0x05,0x06,0x9b,0x00,0x86,0x00,0xa1,0x05,0x82,0x04,0x85,0x05,0x82,0x03,0x82,0x02,0x00,0x03,0x85,0x02,0x00,0x07,0x8a,0x05,0x00,0x03,0x87,0x02,0x00,0x07,0xaa,0x05,0x84,0x00,0x02,0x05,0x05,0x04,0x94,0x05,0x00,0x04, +0x8c,0x05,0x00,0x04,0x83,0x05,0x00,0x06,0x82,0x05,0x01,0x03,0x03,0x84,0x02,0x03,0x03,0x02,0x02,0x07,0x8b,0x05,0x00,0x03,0x85,0x02,0x0a,0x07,0x06,0x05,0x05,0x04,0x05,0x06,0x05,0x05,0x04,0x06,0x8b,0x05,0x00,0x04,0x83,0x05,0x07,0x04,0x05,0x04,0x05,0x05,0x06,0x05,0x04,0x85,0x05,0x03,0x04,0x05,0x06,0x05,0x82,0x00,0x86,0x05,0x00,0x06,0x92,0x05,0x04,0x04,0x05,0x04,0x05,0x06,0x82,0x05,0x03,0x04,0x05,0x05,0x04,0x82,0x05,0x00,0x04,0x85,0x05,0x82,0x03,0x01,0x02,0x03,0x83,0x02,0x05,0x07,0x07,0x05,0x04,0x05,0x04,0x87,0x05,0x00,0x03,0x84,0x02,0x00,0x07,0x82,0x05,0x00,0x06,0x85,0x05,0x07,0x04,0x05,0x05,0x04,0x05,0x06,0x05,0x06,0x85,0x05,0x00,0x04, +0x87,0x05,0x07,0x04,0x05,0x05,0x04,0x04,0x05,0x04,0x04,0x82,0x05,0x01,0x06,0x00,0x01,0x00,0x00,0x8d,0x05,0x00,0x04,0x89,0x05,0x04,0x06,0x05,0x06,0x05,0x04,0x84,0x05,0x00,0x04,0x88,0x05,0x07,0x04,0x05,0x05,0x04,0x04,0x05,0x03,0x03,0x85,0x02,0x00,0x03,0x8c,0x05,0x00,0x03,0x83,0x02,0x00,0x07,0x86,0x05,0x01,0x06,0x04,0x83,0x05,0x00,0x04,0x84,0x05,0x01,0x04,0x04,0x82,0x05,0x00,0x04,0x82,0x05,0x12,0x04,0x05,0x05,0x04,0x05,0x04,0x05,0x05,0x04,0x04,0x05,0x04,0x05,0x04,0x05,0x05,0x04,0x05,0x00,0x00,0x00,0x83,0x05,0x07,0x04,0x04,0x05,0x05,0x04,0x05,0x05,0x04,0x8a,0x05,0x0a,0x04,0x05,0x03,0x06,0x05,0x06,0x05,0x05,0x04,0x05,0x04,0x82,0x05,0x06, +0x04,0x05,0x05,0x04,0x05,0x04,0x04,0x83,0x05,0x00,0x04,0x82,0x05,0x12,0x06,0x03,0x03,0x02,0x03,0x03,0x02,0x07,0x07,0x05,0x06,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x82,0x05,0x0b,0x03,0x03,0x02,0x07,0x07,0x05,0x05,0x06,0x05,0x05,0x04,0x04,0x82,0x05,0x03,0x04,0x05,0x05,0x04,0x82,0x05,0x02,0x04,0x05,0x04,0x84,0x05,0x04,0x04,0x05,0x04,0x05,0x05,0x82,0x04,0x09,0x05,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x82,0x04,0x01,0x00,0x00,0x05,0x00,0x05,0x05,0x04,0x04,0x05,0x82,0x04,0x02,0x05,0x05,0x04,0x86,0x05,0x00,0x04,0x85,0x05,0x03,0x03,0x06,0x05,0x04,0x85,0x05,0x04,0x04,0x04,0x05,0x05,0x04,0x83,0x05,0x00,0x04,0x88,0x05,0x05,0x03,0x02, +0x03,0x02,0x02,0x07,0x88,0x05,0x00,0x06,0x83,0x05,0x06,0x03,0x07,0x02,0x07,0x05,0x05,0x04,0x8d,0x05,0x00,0x04,0x86,0x05,0x10,0x04,0x05,0x05,0x04,0x04,0x05,0x04,0x05,0x05,0x04,0x05,0x05,0x04,0x05,0x04,0x05,0x04,0x82,0x05,0x03,0x04,0x05,0x00,0x00,0x05,0x00,0x05,0x04,0x05,0x05,0x04,0x82,0x05,0x06,0x04,0x05,0x05,0x04,0x05,0x05,0x04,0x86,0x05,0x0b,0x04,0x05,0x06,0x03,0x06,0x05,0x06,0x05,0x04,0x05,0x04,0x04,0x83,0x05,0x04,0x04,0x04,0x05,0x05,0x04,0x82,0x05,0x15,0x04,0x05,0x04,0x05,0x06,0x05,0x06,0x05,0x03,0x03,0x02,0x02,0x03,0x07,0x05,0x06,0x06,0x04,0x04,0x05,0x04,0x06,0x85,0x05,0x03,0x03,0x02,0x07,0x07,0x86,0x05,0x07,0x04,0x05,0x04,0x05, +0x04,0x05,0x05,0x04,0x84,0x05,0x06,0x06,0x05,0x05,0x06,0x07,0x05,0x04,0x82,0x05,0x12,0x04,0x05,0x05,0x04,0x05,0x04,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x04,0x05,0x04,0x05,0x00,0x00,0x82,0x05,0x05,0x04,0x04,0x05,0x04,0x05,0x05,0x82,0x04,0x11,0x05,0x05,0x04,0x05,0x05,0x06,0x05,0x05,0x04,0x05,0x06,0x06,0x05,0x03,0x03,0x07,0x05,0x04,0x82,0x05,0x0c,0x04,0x05,0x05,0x06,0x05,0x06,0x06,0x04,0x04,0x06,0x04,0x05,0x04,0x83,0x05,0x13,0x04,0x05,0x05,0x04,0x05,0x03,0x03,0x02,0x04,0x07,0x05,0x05,0x04,0x05,0x05,0x04,0x04,0x05,0x04,0x04,0x82,0x05,0x09,0x06,0x05,0x03,0x03,0x07,0x05,0x05,0x04,0x05,0x04,0x84,0x05,0x82,0x06,0x0e,0x04,0x05,0x04,0x05,0x06, +0x04,0x05,0x04,0x04,0x05,0x06,0x07,0x07,0x05,0x04,0x83,0x05,0x82,0x04,0x05,0x05,0x06,0x04,0x05,0x04,0x05,0x82,0x04,0x02,0x05,0x04,0x05,0x82,0x00,0x00,0x05,0x84,0x04,0x02,0x05,0x04,0x04,0x8e,0x05,0x04,0x06,0x03,0x02,0x07,0x05,0x82,0x04,0x03,0x05,0x05,0x04,0x04,0x8a,0x05,0x11,0x04,0x04,0x05,0x05,0x04,0x05,0x04,0x05,0x06,0x03,0x02,0x02,0x07,0x05,0x04,0x05,0x04,0x04,0x84,0x05,0x07,0x04,0x05,0x05,0x04,0x05,0x03,0x07,0x06,0x86,0x05,0x02,0x04,0x05,0x04,0x8b,0x05,0x00,0x06,0x82,0x07,0x07,0x06,0x05,0x05,0x04,0x04,0x05,0x05,0x04,0x8b,0x05,0x83,0x00,0x06,0x05,0x04,0x04,0x05,0x05,0x04,0x04,0x82,0x05,0x00,0x06,0x82,0x03,0x08,0x04,0x06,0x03,0x04, +0x03,0x03,0x06,0x03,0x04,0x82,0x03,0x11,0x02,0x07,0x05,0x07,0x04,0x05,0x04,0x04,0x05,0x04,0x04,0x05,0x06,0x06,0x04,0x04,0x06,0x06,0x82,0x05,0x0f,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x04,0x05,0x03,0x02,0x07,0x05,0x05,0x04,0x04,0x82,0x05,0x14,0x04,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x03,0x06,0x05,0x05,0x06,0x05,0x05,0x04,0x05,0x04,0x05,0x04,0x82,0x05,0x16,0x07,0x06,0x05,0x05,0x06,0x06,0x07,0x06,0x05,0x06,0x07,0x02,0x07,0x07,0x06,0x05,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x8e,0x00,0x00,0x05,0x86,0x04,0x09,0x05,0x06,0x03,0x03,0x02,0x01,0x03,0x02,0x02,0x03,0x82,0x02,0x00,0x03,0x82,0x02,0x0f,0x03,0x02,0x07,0x05,0x04,0x05,0x04,0x04,0x05, +0x04,0x04,0x06,0x05,0x06,0x03,0x02,0x82,0x03,0x10,0x06,0x06,0x05,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x03,0x02,0x04,0x05,0x05,0x85,0x04,0x1d,0x05,0x04,0x05,0x04,0x05,0x05,0x06,0x05,0x03,0x07,0x05,0x06,0x05,0x04,0x05,0x05,0x04,0x05,0x04,0x05,0x05,0x06,0x03,0x07,0x06,0x05,0x06,0x07,0x07,0x03,0x83,0x07,0x02,0x02,0x07,0x07,0x82,0x04,0x05,0x05,0x04,0x05,0x04,0x04,0x05,0x8e,0x00,0x00,0x05,0x86,0x04,0x01,0x06,0x05,0x83,0x03,0x00,0x02,0x87,0x03,0x09,0x02,0x02,0x03,0x02,0x03,0x05,0x07,0x04,0x05,0x05,0x82,0x04,0x82,0x06,0x14,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x05,0x05,0x04,0x04,0x05,0x04,0x04,0x06,0x06,0x05,0x03,0x07,0x05,0x06,0x88, +0x04,0x08,0x05,0x04,0x04,0x06,0x04,0x05,0x06,0x07,0x05,0x82,0x04,0x11,0x05,0x04,0x05,0x04,0x04,0x05,0x06,0x03,0x07,0x07,0x06,0x06,0x07,0x03,0x07,0x07,0x06,0x07,0x82,0x02,0x0a,0x07,0x07,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x04,0x05,0x8e,0x00,0x01,0x05,0x05,0x84,0x04,0x01,0x05,0x04,0x82,0x05,0x07,0x06,0x05,0x06,0x06,0x05,0x05,0x03,0x05,0x84,0x03,0x82,0x02,0x00,0x05,0x83,0x04,0x0e,0x05,0x05,0x04,0x05,0x03,0x03,0x05,0x03,0x03,0x02,0x03,0x03,0x07,0x05,0x06,0x86,0x04,0x04,0x06,0x03,0x06,0x05,0x06,0x84,0x04,0x00,0x05,0x84,0x04,0x0a,0x05,0x04,0x04,0x05,0x06,0x05,0x05,0x04,0x05,0x04,0x06,0x82,0x04,0x0c,0x05,0x05,0x03,0x02,0x07,0x06,0x06,0x07, +0x03,0x07,0x02,0x03,0x07,0x83,0x02,0x05,0x07,0x07,0x05,0x04,0x04,0x05,0x84,0x04,0x00,0x05,0x88,0x00,0x00,0x05,0x83,0x00,0x00,0x05,0x88,0x04,0x00,0x05,0x83,0x04,0x01,0x06,0x05,0x82,0x04,0x00,0x06,0x82,0x05,0x82,0x03,0x05,0x07,0x05,0x07,0x04,0x04,0x05,0x82,0x04,0x0b,0x06,0x05,0x03,0x06,0x03,0x03,0x04,0x03,0x06,0x05,0x05,0x06,0x85,0x04,0x04,0x06,0x05,0x07,0x05,0x05,0x8e,0x04,0x03,0x05,0x06,0x05,0x05,0x86,0x04,0x0b,0x05,0x06,0x03,0x02,0x03,0x06,0x03,0x03,0x07,0x07,0x03,0x07,0x84,0x02,0x01,0x07,0x07,0x84,0x04,0x0b,0x05,0x04,0x04,0x05,0x04,0x05,0x04,0x05,0x05,0x04,0x05,0x06,0x82,0x04,0x00,0x05,0x82,0x00,0x01,0x00,0x05,0x89,0x04,0x01,0x05, +0x05,0x83,0x04,0x0a,0x05,0x05,0x04,0x04,0x06,0x05,0x05,0x03,0x03,0x02,0x05,0x83,0x04,0x02,0x05,0x04,0x04,0x8a,0x05,0x86,0x04,0x83,0x05,0x86,0x04,0x01,0x05,0x05,0x86,0x04,0x03,0x05,0x06,0x05,0x06,0x86,0x04,0x0a,0x05,0x03,0x02,0x07,0x06,0x07,0x07,0x03,0x02,0x03,0x07,0x82,0x02,0x00,0x07,0x82,0x02,0x01,0x07,0x05,0x85,0x04,0x02,0x05,0x04,0x05,0x89,0x04,0x00,0x05,0x82,0x00,0x03,0x00,0x05,0x04,0x05,0x93,0x04,0x04,0x05,0x05,0x03,0x04,0x05,0x8d,0x04,0x01,0x05,0x05,0x88,0x04,0x83,0x05,0x86,0x04,0x01,0x05,0x05,0x86,0x04,0x02,0x05,0x06,0x05,0x87,0x04,0x09,0x05,0x03,0x02,0x06,0x06,0x07,0x03,0x07,0x02,0x03,0x85,0x02,0x02,0x01,0x07,0x07,0x85,0x04, +0x03,0x05,0x04,0x05,0x05,0x8a,0x04,0x82,0x00,0x02,0x00,0x05,0x05,0x96,0x04,0x02,0x05,0x03,0x05,0x98,0x04,0x01,0x05,0x05,0x88,0x04,0x01,0x05,0x05,0x86,0x04,0x05,0x05,0x04,0x05,0x06,0x04,0x07,0x84,0x04,0x09,0x05,0x03,0x02,0x06,0x06,0x07,0x02,0x02,0x07,0x07,0x83,0x02,0x04,0x01,0x02,0x02,0x07,0x07,0x93,0x04,0x00,0x05,0x82,0x00,0x03,0x00,0x00,0x05,0x04,0x91,0x01,0x06,0x00,0x01,0x01,0x04,0x05,0x05,0x06,0x84,0x01,0x03,0x00,0x01,0x04,0x01,0x82,0x00,0x84,0x01,0x06,0x00,0x01,0x00,0x01,0x00,0x01,0x01,0x82,0x05,0x04,0x04,0x01,0x01,0x04,0x00,0x82,0x01,0x02,0x05,0x05,0x04,0x85,0x01,0x08,0x04,0x04,0x05,0x04,0x04,0x00,0x01,0x01,0x00,0x82,0x01,0x09, +0x05,0x03,0x06,0x06,0x03,0x02,0x07,0x07,0x02,0x07,0x86,0x02,0x05,0x07,0x07,0x04,0x01,0x04,0x01,0x86,0x04,0x01,0x01,0x04,0x82,0x01,0x00,0x00,0x82,0x01,0x00,0x05,0x82,0x00,0x82,0x00,0x01,0x05,0x01,0x83,0x00,0x01,0x01,0x00,0x88,0x01,0x85,0x00,0x03,0x04,0x05,0x05,0x01,0x85,0x00,0x01,0x01,0x05,0x8d,0x00,0x00,0x04,0x82,0x05,0x00,0x04,0x83,0x00,0x10,0x01,0x01,0x04,0x05,0x05,0x04,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x04,0x04,0x05,0x04,0x86,0x00,0x08,0x05,0x03,0x05,0x07,0x07,0x02,0x03,0x02,0x07,0x86,0x02,0x03,0x01,0x07,0x07,0x04,0x85,0x01,0x02,0x04,0x01,0x04,0x84,0x01,0x84,0x00,0x00,0x04,0x82,0x00,0x82,0x00,0x02,0x05,0x05,0x04,0x82,0x01,0x03, +0x00,0x01,0x00,0x00,0x83,0x01,0x00,0x04,0x82,0x01,0x08,0x00,0x01,0x00,0x00,0x01,0x04,0x05,0x05,0x01,0x85,0x00,0x02,0x04,0x05,0x04,0x8b,0x00,0x00,0x04,0x82,0x05,0x01,0x04,0x00,0x83,0x01,0x01,0x00,0x01,0x82,0x05,0x01,0x04,0x00,0x82,0x01,0x06,0x00,0x01,0x00,0x04,0x06,0x05,0x07,0x83,0x00,0x0a,0x01,0x00,0x00,0x04,0x05,0x05,0x07,0x03,0x02,0x03,0x07,0x82,0x02,0x00,0x01,0x83,0x02,0x03,0x01,0x07,0x07,0x04,0x84,0x01,0x00,0x04,0x89,0x01,0x03,0x00,0x01,0x00,0x04,0x82,0x00,0x84,0x00,0x82,0x05,0x8a,0x04,0x03,0x01,0x01,0x00,0x01,0x82,0x00,0x03,0x01,0x05,0x05,0x01,0x85,0x00,0x03,0x01,0x05,0x05,0x01,0x85,0x00,0x03,0x01,0x00,0x01,0x01,0x83,0x05,0x00, +0x04,0x82,0x01,0x00,0x00,0x82,0x01,0x0f,0x04,0x05,0x06,0x07,0x04,0x01,0x01,0x00,0x01,0x01,0x00,0x01,0x06,0x06,0x07,0x04,0x86,0x00,0x06,0x04,0x05,0x03,0x03,0x02,0x07,0x03,0x87,0x02,0x04,0x01,0x07,0x02,0x07,0x04,0x83,0x01,0x03,0x04,0x01,0x04,0x04,0x82,0x05,0x82,0x04,0x00,0x05,0x83,0x04,0x83,0x00,0x8f,0x00,0x82,0x05,0x84,0x01,0x08,0x00,0x01,0x04,0x05,0x05,0x01,0x00,0x01,0x01,0x82,0x00,0x02,0x04,0x05,0x05,0x89,0x04,0x05,0x05,0x05,0x03,0x04,0x05,0x04,0x86,0x01,0x04,0x05,0x03,0x02,0x07,0x04,0x86,0x01,0x0d,0x05,0x06,0x05,0x04,0x01,0x01,0x00,0x01,0x00,0x01,0x01,0x04,0x05,0x04,0x83,0x07,0x89,0x02,0x04,0x07,0x07,0x04,0x01,0x04,0x84,0x01,0x01, +0x04,0x05,0x8d,0x00,0x91,0x00,0x01,0x04,0x04,0x86,0x01,0x04,0x05,0x05,0x01,0x01,0x00,0x82,0x01,0x02,0x00,0x04,0x05,0x86,0x00,0x0b,0x05,0x06,0x05,0x05,0x06,0x04,0x07,0x05,0x05,0x01,0x01,0x04,0x83,0x01,0x05,0x04,0x05,0x03,0x07,0x06,0x04,0x86,0x01,0x05,0x04,0x05,0x07,0x05,0x01,0x00,0x82,0x01,0x04,0x00,0x01,0x01,0x05,0x05,0x82,0x03,0x89,0x02,0x08,0x01,0x01,0x04,0x04,0x01,0x01,0x04,0x04,0x01,0x82,0x04,0x8e,0x00,0x91,0x00,0x01,0x05,0x05,0x85,0x01,0x03,0x04,0x05,0x05,0x04,0x85,0x01,0x00,0x04,0x87,0x00,0x08,0x05,0x03,0x03,0x06,0x03,0x06,0x06,0x05,0x04,0x82,0x01,0x06,0x04,0x01,0x01,0x04,0x05,0x04,0x03,0x83,0x04,0x85,0x01,0x04,0x05,0x03,0x04, +0x05,0x02,0x85,0x01,0x82,0x04,0x04,0x05,0x03,0x02,0x03,0x03,0x85,0x02,0x05,0x07,0x02,0x02,0x07,0x07,0x04,0x82,0x01,0x04,0x04,0x01,0x04,0x01,0x05,0x8e,0x00,0x91,0x00,0x0a,0x05,0x04,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x05,0x05,0x86,0x01,0x00,0x04,0x88,0x00,0x06,0x06,0x03,0x02,0x03,0x06,0x05,0x05,0x83,0x04,0x0f,0x01,0x01,0x04,0x04,0x05,0x03,0x06,0x04,0x05,0x04,0x01,0x04,0x01,0x04,0x01,0x01,0x83,0x04,0x01,0x05,0x04,0x82,0x01,0x05,0x04,0x01,0x04,0x01,0x01,0x04,0x82,0x05,0x83,0x06,0x02,0x05,0x06,0x07,0x83,0x06,0x01,0x05,0x05,0x86,0x04,0x02,0x01,0x04,0x05,0x8d,0x00,0x02,0x00,0x04,0x06,0x82,0x05,0x04,0x04,0x06,0x05,0x04,0x06,0x82,0x05,0x10, +0x04,0x05,0x04,0x05,0x04,0x04,0x01,0x04,0x04,0x01,0x04,0x01,0x04,0x05,0x05,0x04,0x04,0x82,0x01,0x02,0x04,0x01,0x04,0x89,0x00,0x02,0x03,0x03,0x06,0x82,0x05,0x83,0x04,0x00,0x01,0x82,0x04,0x82,0x05,0x06,0x04,0x05,0x04,0x01,0x04,0x01,0x01,0x83,0x04,0x07,0x03,0x07,0x07,0x05,0x04,0x04,0x01,0x04,0x82,0x01,0x82,0x04,0x00,0x06,0x85,0x04,0x10,0x07,0x06,0x04,0x04,0x06,0x04,0x04,0x05,0x04,0x01,0x04,0x03,0x04,0x01,0x04,0x04,0x05,0x8c,0x04,0x01,0x00,0x00,0x00,0x05,0x95,0x04,0x08,0x03,0x01,0x04,0x04,0x05,0x05,0x01,0x04,0x01,0x84,0x04,0x89,0x00,0x06,0x06,0x03,0x07,0x05,0x05,0x04,0x05,0x92,0x04,0x09,0x01,0x04,0x04,0x02,0x07,0x05,0x04,0x01,0x04,0x01, +0x84,0x04,0x00,0x03,0x8d,0x04,0x00,0x05,0x8c,0x04,0x00,0x06,0x87,0x04,0x01,0x05,0x00,0x00,0x05,0x98,0x04,0x82,0x05,0x85,0x04,0x01,0x01,0x04,0x8a,0x00,0x01,0x03,0x06,0x82,0x05,0x94,0x04,0x05,0x05,0x03,0x02,0x07,0x07,0x05,0x82,0x04,0x00,0x02,0x8a,0x04,0x00,0x03,0x86,0x04,0x00,0x06,0x94,0x04,0x02,0x01,0x05,0x00,0x00,0x05,0x98,0x04,0x82,0x05,0x86,0x04,0x00,0x05,0x8a,0x00,0x03,0x06,0x05,0x05,0x06,0x82,0x05,0x82,0x04,0x01,0x05,0x05,0x87,0x04,0x0d,0x03,0x04,0x04,0x01,0x04,0x03,0x05,0x03,0x03,0x02,0x07,0x05,0x05,0x06,0x94,0x04,0x01,0x05,0x06,0x94,0x04,0x01,0x05,0x00,0x00,0x05,0x8a,0x04,0x01,0x06,0x06,0x8a,0x04,0x03,0x05,0x00,0x00,0x05,0x87, +0x04,0x8a,0x00,0x83,0x05,0x02,0x04,0x04,0x05,0x82,0x04,0x01,0x05,0x05,0x8d,0x04,0x07,0x05,0x03,0x03,0x02,0x07,0x07,0x05,0x05,0x84,0x04,0x00,0x06,0x8e,0x04,0x00,0x05,0x87,0x04,0x00,0x06,0x8c,0x04,0x01,0x05,0x00,0x02,0x05,0x05,0x06,0x83,0x04,0x03,0x06,0x04,0x04,0x05,0x83,0x04,0x03,0x06,0x06,0x04,0x05,0x83,0x04,0x01,0x06,0x05,0x82,0x00,0x03,0x05,0x06,0x04,0x06,0x83,0x04,0x00,0x05,0x8a,0x00,0x82,0x05,0x05,0x06,0x05,0x04,0x04,0x06,0x04,0x82,0x05,0x87,0x04,0x00,0x06,0x84,0x04,0x01,0x05,0x06,0x82,0x02,0x00,0x07,0x82,0x05,0x84,0x04,0x00,0x06,0x83,0x04,0x02,0x06,0x04,0x06,0x82,0x04,0x0c,0x06,0x04,0x06,0x04,0x05,0x05,0x04,0x05,0x04,0x04,0x06, +0x04,0x05,0x82,0x04,0x04,0x06,0x04,0x05,0x04,0x06,0x82,0x04,0x04,0x06,0x04,0x04,0x05,0x00,0x02,0x05,0x04,0x06,0x82,0x04,0x00,0x06,0x82,0x04,0x00,0x06,0x82,0x04,0x00,0x06,0x82,0x04,0x05,0x06,0x04,0x04,0x06,0x05,0x05,0x83,0x00,0x02,0x05,0x04,0x06,0x82,0x04,0x02,0x06,0x04,0x05,0x8a,0x00,0x04,0x05,0x06,0x05,0x05,0x04,0x82,0x06,0x19,0x05,0x05,0x06,0x06,0x05,0x04,0x06,0x06,0x04,0x04,0x05,0x04,0x06,0x06,0x04,0x04,0x06,0x04,0x05,0x03,0x03,0x02,0x03,0x07,0x06,0x06,0x84,0x05,0x0c,0x06,0x06,0x04,0x05,0x04,0x04,0x06,0x04,0x04,0x05,0x04,0x04,0x05,0x82,0x04,0x18,0x05,0x05,0x04,0x04,0x06,0x04,0x05,0x04,0x06,0x04,0x04,0x06,0x04,0x04,0x06,0x04,0x04, +0x05,0x04,0x04,0x06,0x04,0x04,0x05,0x00,0x95,0x05,0x85,0x00,0x84,0x05,0x00,0x06,0x82,0x05,0x89,0x00,0x89,0x05,0x02,0x06,0x03,0x07,0x82,0x05,0x02,0x06,0x05,0x04,0x88,0x05,0x04,0x03,0x02,0x07,0x03,0x06,0x82,0x07,0x00,0x00,0x87,0x05,0x00,0x06,0x84,0x05,0x00,0x06,0x87,0x05,0x01,0x06,0x04,0x86,0x05,0x00,0x06,0x89,0x05,0x00,0x00,0xb2,0x00,0x85,0x05,0x03,0x03,0x02,0x02,0x06,0x8d,0x05,0x06,0x03,0x02,0x02,0x06,0x06,0x02,0x03,0xad,0x00,0xb3,0x00,0x03,0x06,0x03,0x06,0x06,0x84,0x02,0x05,0x07,0x03,0x02,0x07,0x02,0x04,0x82,0x02,0x03,0x03,0x02,0x02,0x04,0x82,0x02,0x04,0x07,0x06,0x03,0x03,0x07,0xad,0x00,0xb3,0x00,0x00,0x06,0x83,0x03,0x06,0x02,0x01, +0x02,0x02,0x01,0x02,0x01,0x84,0x02,0x00,0x01,0x85,0x02,0x04,0x07,0x06,0x06,0x03,0x03,0xae,0x00,0xb4,0x00,0x00,0x06,0x82,0x03,0x86,0x02,0x02,0x01,0x02,0x01,0x87,0x02,0x04,0x03,0x03,0x06,0x07,0x02,0xaf,0x00,0xb4,0x00,0x00,0x06,0x82,0x03,0x03,0x02,0x01,0x02,0x01,0x87,0x02,0x00,0x01,0x85,0x02,0x03,0x07,0x06,0x02,0x03,0xaf,0x00,0xb5,0x00,0x83,0x03,0x83,0x02,0x05,0x01,0x02,0x02,0x01,0x02,0x01,0x86,0x02,0x03,0x03,0x06,0x03,0x07,0xb0,0x00,0xb5,0x00,0x00,0x05,0x82,0x03,0x8e,0x02,0x04,0x03,0x07,0x06,0x06,0x03,0xb1,0x00,0xb5,0x00,0x01,0x06,0x05,0x82,0x03,0x04,0x07,0x07,0x02,0x07,0x07,0x85,0x02,0x83,0x07,0x03,0x06,0x06,0x03,0x07,0xb1,0x00,0xa7, +0x00,0x85,0x05,0x84,0x00,0x84,0x05,0x03,0x06,0x07,0x07,0x06,0x84,0x05,0x04,0x06,0x07,0x02,0x03,0x02,0x85,0x05,0x02,0x07,0x06,0x06,0x85,0x05,0x83,0x00,0x82,0x05,0xa3,0x00,0xa7,0x00,0x86,0x05,0x82,0x00,0x85,0x05,0x82,0x06,0x86,0x05,0x03,0x07,0x02,0x07,0x06,0x85,0x05,0x01,0x06,0x07,0x86,0x05,0x82,0x00,0x84,0x05,0xa2,0x00,0xa7,0x00,0x86,0x05,0x82,0x00,0x86,0x05,0x01,0x06,0x07,0x86,0x05,0x02,0x06,0x07,0x07,0x86,0x05,0x01,0x06,0x00,0x86,0x05,0x01,0x00,0x00,0x86,0x05,0xa1,0x00,0xa7,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x06,0x06,0x82,0x05,0x00,0x00,0x82,0x05,0x02,0x07,0x03,0x07,0x82, +0x05,0x00,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x83,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0xa1,0x00,0xa6,0x00,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x82,0x00,0x82,0x05,0x05,0x00,0x00,0x05,0x05,0x06,0x06,0x83,0x05,0x00,0x00,0x82,0x05,0x06,0x07,0x07,0x06,0x05,0x05,0x00,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x83,0x00,0x05,0x05,0x05,0x00,0x00,0x05,0x05,0xa2,0x00,0xa6,0x00,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x82,0x00,0x82,0x05,0x05,0x00,0x00,0x05,0x05,0x06,0x07,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x07,0x02,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x83,0x00,0x01,0x05,0x05,0x83,0x00,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0xa2,0x00,0xa6,0x00,0x82,0x05, +0x03,0x00,0x00,0x05,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x83,0x05,0x05,0x06,0x06,0x05,0x05,0x00,0x00,0x82,0x05,0x06,0x07,0x02,0x06,0x05,0x05,0x00,0x00,0x82,0x05,0x83,0x00,0x01,0x05,0x05,0x83,0x00,0x82,0x05,0xa6,0x00,0xa6,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x03,0x02,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x83,0x00,0x01,0x05,0x05,0x84,0x00,0x82,0x05,0xa5,0x00,0xa6,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x86,0x05,0x02,0x06,0x02,0x07,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x82,0x00,0x82,0x05,0x84, +0x00,0x82,0x05,0xa5,0x00,0xa6,0x00,0x86,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x86,0x05,0x82,0x07,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x85,0x00,0x82,0x05,0xa4,0x00,0xa6,0x00,0x85,0x05,0x82,0x00,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x86,0x05,0x02,0x03,0x02,0x07,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x86,0x00,0x82,0x05,0xa3,0x00,0xa6,0x00,0x85,0x05,0x82,0x00,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x02,0x07,0x07,0x06,0x82,0x05,0x00,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x86,0x00,0x82,0x05,0xa3,0x00,0xa5,0x00,0x82,0x05,0x02, +0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x01,0x06,0x07,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x87,0x00,0x01,0x05,0x05,0xa3,0x00,0xa5,0x00,0x82,0x05,0x02,0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x01,0x07,0x06,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x83,0x00,0x01,0x05,0x05,0x88,0x00,0x01,0x05,0x05,0xa3,0x00,0xa5,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x01,0x07,0x06,0x82,0x05,0x01,0x00,0x00,0x82,0x05,0x83,0x00,0x01,0x05, +0x05,0x83,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0xa3,0x00,0xa5,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x01,0x06,0x06,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0xa3,0x00,0xa5,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0x01,0x00,0x00,0x88,0x05,0x00,0x07,0x82,0x05,0x03,0x00,0x00,0x05,0x05,0x83,0x00,0x82,0x05,0x83,0x00,0x82,0x05,0x00,0x00,0x82,0x05,0xa3,0x00,0xa5,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x85,0x05,0x82,0x00,0x87,0x05,0x01,0x00,0x00,0x86, +0x05,0x83,0x00,0x82,0x05,0x83,0x00,0x85,0x05,0xa4,0x00,0xa5,0x00,0x03,0x05,0x05,0x00,0x00,0x82,0x05,0x82,0x00,0x85,0x05,0x82,0x00,0x85,0x05,0x84,0x00,0x84,0x05,0x84,0x00,0x82,0x05,0x83,0x00,0x85,0x05,0xa4,0x00,0xb1,0x00,0x01,0x05,0x05,0x90,0x00,0x01,0x05,0x05,0x8f,0x00,0x01,0x05,0x05,0xa6,0x00,0xff,0x00,0xff,0x00 +}; + +// http://paulbourke.net/dataformats/tga/ + + +typedef struct { + char idlength; + char colourmaptype; + char datatypecode; + short colourmaporigin; + short colourmaplength; + char colourmapdepth; + short x_origin; + short y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; + struct { byte r,g,b; } palette[8]; + byte data[0]; +} TGAHeader; + +void draw_tga(const byte* tgadata, byte x, byte y) { + const TGAHeader* hdr = (TGAHeader*) tgadata; + const byte* src = hdr->data; + byte* dest = &vidmem[x][y]; + byte i,j,lastbyte; + for (i=0; i<8; i++) { + byte pal = 0; + pal |= (hdr->palette[i].r >> 5); + pal |= (hdr->palette[i].g >> 2) & 0x38; + pal |= (hdr->palette[i].b) & 0xc0; + palette[i] = pal; + } + for (j=0; jheight; j++) { + byte* start = dest; + i = 0; + lastbyte = 0; + while (iwidth) { + byte count = *src++; + byte rle = count & 0x80; + byte color = 0; + if (rle) { + color = *src++; // fetch RLE byte + count &= 0x7f; + } + do { + if (!rle) + color = *src++; // fetch raw data + if ((i&1)==0) { + *dest = lastbyte = (color << 4); // even byte + } else { + *dest = lastbyte | color; // odd byte + dest += 256; + } + i++; + } while (count--); + } + dest = start+1; + watchdog0x39 = 0x39; + } +} + +void clrscr() { + // doesn't work because memset uses LDIR + // and reads come from ROM + //memset(vidmem, 0, sizeof(vidmem)); + word i = sizeof(vidmem)-1; + do { + vidmem[0][i] = 0; + watchdog0x39 = 0x39; + } while (i--); +} + +void main() { + clrscr(); + draw_tga(example_tga, 45, 76); // array, so no & + while (1) { + watchdog0x39 = 0x39; + } +} diff --git a/presets/williams/gfxtest.c b/presets/williams-z80/gfxtest.c similarity index 78% rename from presets/williams/gfxtest.c rename to presets/williams-z80/gfxtest.c index a71045ee..99857bad 100644 --- a/presets/williams/gfxtest.c +++ b/presets/williams-z80/gfxtest.c @@ -32,7 +32,7 @@ struct { byte height; } __at (0xca00) blitter; -byte __at (0x0) vidmem[128][304]; // 256x304x4bpp video memory +byte __at (0x0) vidmem[152][256]; // 256x304x4bpp video memory void main(); @@ -54,13 +54,23 @@ const byte font8x8[HICHAR-LOCHAR+1][8] = { }; const byte sprite1[] = { - 4,6, - 0x33,0x33,0x33,0x32, - 0x33,0x33,0x32,0x33, - 0x33,0x32,0x00,0x33, - 0x32,0x00,0x00,0x33, - 0x33,0x00,0x00,0x33, - 0x33,0x33,0x33,0x33 +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,0x00,0x00,0x40,0x00,0x00,0x00,0x00, }; inline word swapw(word j) { @@ -69,7 +79,7 @@ inline word swapw(word j) { // x1: 0-151 // y1: 0-255 -void blit_solid(byte x1, byte y1, byte w, byte h, byte color) { +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 @@ -77,7 +87,7 @@ void blit_solid(byte x1, byte y1, byte w, byte h, byte color) { blitter.flags = DSTSCREEN|SOLID; } -void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) { +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); @@ -86,7 +96,7 @@ void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) { blitter.flags = DSTSCREEN|FGONLY; } -void draw_sprite(const byte* data, byte x, byte y) { +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)); @@ -122,20 +132,26 @@ void draw_string(const char* str, byte x, byte y, byte color) { } while (ch); } +inline void blit_pixel(word xx, byte y, byte color) { + blitter.width = 1^4; + blitter.height = 1^4; + blitter.dstart = (xx>>1)+y*256; // swapped + blitter.solid = color; + blitter.flags = (xx&1) ? SOLID|ODDONLY : SOLID|EVENONLY; +} + void main() { int i; + blit_solid(0, 0, 152, 255, 0x00); for (i=0; i<16; i++) - palette[i] = i*5; - for (i=0; i<128; i+=8) { - vidmem[0][i] += 16; - vidmem[i][2] += 32; - //blit_solid(i/2,i,149-i,255-i*2,i*0x11+1); + palette[i] = i*7; + for (i=0; i<152; i++) { + vidmem[0][i] = 16; + vidmem[i][2] = 32; + blit_pixel(i, i, 0x77); + blit_pixel(i+1, i, 0x33); } - draw_sprite(sprite1, 10, 20); - draw_char('A', 5, 5, 0xff); + draw_sprite(sprite1, 35, 20); draw_string("HELLO WORLD", 20, 5, 0x88); - //blit_solid(0,0,100,100,0x11); - //blit_solid(10,20,100,200,0x22); - watchdog0x39 = 0x39; - main(); + while (1) watchdog0x39 = 0x39; } diff --git a/presets/williams-z80/sprites.c b/presets/williams-z80/sprites.c new file mode 100644 index 00000000..cf50289d --- /dev/null +++ b/presets/williams-z80/sprites.c @@ -0,0 +1,241 @@ + +#include + +typedef unsigned char byte; +typedef unsigned short word; + +byte __at (0xc000) palette[16]; +byte __at (0xc800) input0; +byte __at (0xc802) input1; +byte __at (0xc804) input2; +byte __at (0xc900) rom_select; +byte __at (0xcb00) video_counter; +byte __at (0xcbff) watchdog0x39; +byte __at (0xcc00) nvram[0x400]; + +// 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 + +struct { + byte flags; + byte solid; + word sstart; + word dstart; + byte width; + byte height; +} __at (0xca00) blitter; + +byte __at (0x0) vidmem[128][304]; // 256x304x4bpp video memory + +void main(); + +// start routine @ 0x0 +// set stack pointer, enable interrupts +void start() { +__asm + LD SP,#0xc000 + DI +__endasm; + main(); +} + +const byte palette_data[16] = { + 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, }; + +const byte sprite_data[] = { +8,128, +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,0x00,0x00,0x40,0x00,0x00,0x00,0x00, +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, +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, +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, +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,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, +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,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, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +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, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +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, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +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 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.solid = 0; + 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; +} + +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+y*256; // swapped + blitter.solid = 0; + blitter.flags = DSTSCREEN|FGONLY; +} + +void main() { + byte y = 0; + byte i; + blit_solid(0, 0, 255, 255, 0); + memcpy(palette, palette_data, 16); + draw_sprite(sprite_data, 20, 20); + while (1) { + for (i=0; i<8; i++) { + byte xpos = 40+i*12; + const byte* sprdata = sprite_data+2+i*8*16; + blit_copy_solid(xpos, y-1, 8, 16, sprdata, 0); + blit_copy(xpos, y, 8, 16, sprdata); + } + y++; + watchdog0x39 = 0x39; + } +} diff --git a/src/platform/galaxian.js b/src/platform/galaxian.js index 5ececa79..cf81282a 100644 --- a/src/platform/galaxian.js +++ b/src/platform/galaxian.js @@ -60,7 +60,7 @@ var GalaxianPlatform = function(mainElement, options) { var vsyncFrequency = hsyncFrequency/132/2; // 60.606060 Hz var vblankDuration = 1/vsyncFrequency * (20/132); // 2500 us var cpuCyclesPerLine = cpuFrequency/hsyncFrequency; - var INITIAL_WATCHDOG = 256; + var INITIAL_WATCHDOG = 8; var showOffscreenObjects = false; var stars = []; for (var i=0; i<256; i++) @@ -225,9 +225,10 @@ var GalaxianPlatform = function(mainElement, options) { [0x5000, 0x5fff, 0xff, function(a,v) { oram.mem[a] = v; }], [0x6801, 0x6801, 0, function(a,v) { interruptEnabled = 1; }], [0x6802, 0x6802, 0, function(a,v) { /* TODO: coin counter */ }], - [0x6804, 0x6804, 0, function(a,v) { starsEnabled = v; }], - [0x6805, 0x6805, 0, function(a,v) { missileWidth = v; }], // not on h/w - [0x6806, 0x6806, 0, function(a,v) { missileOffset = v; }], // not on h/w + [0x6803, 0x6803, 0, function(a,v) { /* TODO: backgroundColor = (v & 1) ? 0xFF000056 : 0xFF000000; */ }], + [0x6804, 0x6804, 0, function(a,v) { starsEnabled = v & 1; }], + [0x6808, 0x6808, 0, function(a,v) { missileWidth = v; }], // not on h/w + [0x6809, 0x6809, 0, function(a,v) { missileOffset = v; }], // not on h/w [0x8202, 0x8202, 0, scramble_protection_w], //[0x8100, 0x8103, 0, function(a,v){ /* PPI 0 */ }], //[0x8200, 0x8203, 0, function(a,v){ /* PPI 1 */ }], @@ -256,8 +257,8 @@ var GalaxianPlatform = function(mainElement, options) { //[0x6800, 0x6807, 0x7, function(a,v) { }], // sound //[0x7800, 0x7800, 0x7, function(a,v) { }], // pitch [0x6000, 0x6003, 0x3, function(a,v) { outlatches.mem[a] = v; }], - [0x7001, 0x7001, 0, function(a,v) { interruptEnabled = v; }], - [0x7004, 0x7004, 0, function(a,v) { starsEnabled = v; }], + [0x7001, 0x7001, 0, function(a,v) { interruptEnabled = v & 1; }], + [0x7004, 0x7004, 0, function(a,v) { starsEnabled = v & 1; }], ]), isContended: function() { return false; }, }; diff --git a/src/platform/vector.js b/src/platform/vector.js index 676f2964..f5791947 100644 --- a/src/platform/vector.js +++ b/src/platform/vector.js @@ -153,6 +153,7 @@ var AtariVectorPlatform = function(mainElement) { cpu.loadState(state.c); cpuram.mem.set(state.cb); dvgram.mem.set(state.db); + switches.set(state.sw); nmicount = state.nmic; } this.saveState = function() { @@ -160,6 +161,7 @@ var AtariVectorPlatform = function(mainElement) { c:cpu.saveState(), cb:cpuram.mem.slice(0), db:dvgram.mem.slice(0), + sw:switches.slice(0), nmic:nmicount } } @@ -295,6 +297,7 @@ var AtariColorVectorPlatform = function(mainElement) { cpu.loadState(state.c); cpuram.mem.set(state.cb); dvgram.mem.set(state.db); + switches.set(state.sw); nmicount = state.nmic; } this.saveState = function() { @@ -302,6 +305,7 @@ var AtariColorVectorPlatform = function(mainElement) { c:cpu.saveState(), cb:cpuram.mem.slice(0), db:dvgram.mem.slice(0), + sw:switches.slice(0), nmic:nmicount } } @@ -314,7 +318,7 @@ var AtariColorVectorPlatform = function(mainElement) { var Z80ColorVectorPlatform = function(mainElement, proto) { var self = this; - var cpuFrequency = 3000000.0; + var cpuFrequency = 4000000.0; var cpuCyclesPerFrame = Math.round(cpuFrequency/60); var cpu, cpuram, dvgram, rom, bus, dvg; var video, audio, timer; @@ -361,6 +365,7 @@ var Z80ColorVectorPlatform = function(mainElement, proto) { [0x810f, 0x810f, 0, function(a,v) { do_math(); } ], [0x8840, 0x8840, 0, function(a,v) { dvg.runUntilHalt(0); }], [0x8880, 0x8880, 0, function(a,v) { dvg.reset(); }], + [0x8980, 0x8980, 0, function(a,v) { switches[0xe] = 16; }], [0xa000, 0xdfff, 0x3fff, function(a,v) { dvgram.mem[a] = v; }], [0xe000, 0xffff, 0x1fff, function(a,v) { cpuram.mem[a] = v; }], ]) @@ -377,6 +382,11 @@ var Z80ColorVectorPlatform = function(mainElement, proto) { self.runCPU(cpu, cpuCyclesPerFrame); cpu.requestInterrupt(); self.restartDebugState(); + switches[0xf] = (switches[0xf] + 1) & 0x3; + if (--switches[0xe] <= 0) { + console.log("WATCHDOG FIRED"); // TODO: alert on video + self.reset(); // watchdog reset + } }); setKeyboardFromMap(video, switches, GRAVITAR_KEYCODE_MAP); } @@ -402,6 +412,7 @@ var Z80ColorVectorPlatform = function(mainElement, proto) { audio.start(); } this.reset = function() { + switches[0xe] = 16; cpu.reset(); } this.readAddress = function(addr) { @@ -412,6 +423,7 @@ var Z80ColorVectorPlatform = function(mainElement, proto) { cpu.loadState(state.c); cpuram.mem.set(state.cb); dvgram.mem.set(state.db); + switches.set(state.sw); mathram.set(state.mr); } this.saveState = function() { @@ -419,6 +431,7 @@ var Z80ColorVectorPlatform = function(mainElement, proto) { c:cpu.saveState(), cb:cpuram.mem.slice(0), db:dvgram.mem.slice(0), + sw:switches.slice(0), mr:mathram.slice(0), } } diff --git a/src/platform/williams.js b/src/platform/williams.js index 20c5625d..6ea8859b 100644 --- a/src/platform/williams.js +++ b/src/platform/williams.js @@ -1,6 +1,9 @@ "use strict"; var WILLIAMS_PRESETS = [ + {id:'gfxtest.c', name:'Graphics Test'}, + {id:'sprites.c', name:'Sprite Test'}, + {id:'bitmap_rle.c', name:'RLE Bitmap'}, ]; var WilliamsPlatform = function(mainElement, proto) { @@ -18,13 +21,14 @@ var WilliamsPlatform = function(mainElement, proto) { var blitregs = new RAM(8).mem; var video, timer, pixels, displayPCs; - var membus, iobus; var screenNeedsRefresh = false; + var membus, iobus; var video_counter; var xtal = 12000000; var cpuFrequency = xtal/3/4; var cpuCyclesPerFrame = cpuFrequency/60; // TODO + var cpuScale = 1; var INITIAL_WATCHDOG = 64; var PIXEL_ON = 0xffeeeeee; var PIXEL_OFF = 0xff000000; @@ -132,15 +136,15 @@ var WilliamsPlatform = function(mainElement, proto) { ]); var memread_williams = new AddressDecoder([ - [0x0000, 0x8fff, 0xffff, function(a) { return banksel ? rom[a] : ram.mem[a]; }], - [0x9000, 0xbfff, 0xffff, function(a) { return ram.mem[a]; }], + [0x0000, 0x97ff, 0xffff, function(a) { return banksel ? rom[a] : ram.mem[a]; }], + [0x9800, 0xbfff, 0xffff, function(a) { return ram.mem[a]; }], [0xc000, 0xcfff, 0x0fff, ioread_williams], [0xd000, 0xffff, 0xffff, function(a) { return rom ? rom[a-0x4000] : 0; }], ]); var memwrite_williams = new AddressDecoder([ - [0x0000, 0x8fff, 0, write_display_byte], - [0x9000, 0xbfff, 0, function(a,v) { ram.mem[a] = v; }], + [0x0000, 0x97ff, 0, write_display_byte], + [0x9800, 0xbfff, 0, function(a,v) { ram.mem[a] = v; }], [0xc000, 0xcfff, 0x0fff, iowrite_williams], //[0x0000, 0xffff, 0, function(a,v) { console.log(hex(a), hex(v)); }], ]); @@ -173,7 +177,7 @@ var WilliamsPlatform = function(mainElement, proto) { blitregs[a] = v; } else { var cycles = doBlit(v); - cpu.setTstates(cpu.getTstates() + cycles); + cpu.setTstates(cpu.getTstates() + cycles * cpuScale); } } @@ -242,7 +246,7 @@ var WilliamsPlatform = function(mainElement, proto) { curpix |= (solid & ~keepmask); else curpix |= (srcdata & ~keepmask); - if (dstaddr < 0x9000) // can cause recursion otherwise + if (dstaddr < 0x9800) // can cause recursion otherwise memwrite_williams(dstaddr, curpix); } @@ -362,11 +366,20 @@ var WilliamsPlatform = function(mainElement, proto) { this.readAddress = function(addr) { return membus.read(addr); } + this.scaleCPUFrequency = function(scale) { + cpuScale = scale; + cpuFrequency *= scale; + cpuCyclesPerFrame *= scale; + } } var WilliamsZ80Platform = function(mainElement) { this.__proto__ = new WilliamsPlatform(mainElement, BaseZ80Platform); + // Z80 @ 4 MHz + // also scale bitblt clocks + this.scaleCPUFrequency(4); + this.ramStateToLongString = function(state) { var blt = state.blt; var sstart = (blt[2] << 8) + blt[3]; diff --git a/src/worker/workermain.js b/src/worker/workermain.js index 223da7d2..36b9dca2 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -27,9 +27,9 @@ var PLATFORM_PARAMS = { }, 'williams-z80': { code_start: 0x0, - code_size: 0x9000, - data_start: 0x9000, - data_size: 0x3000, + code_size: 0x9800, + data_start: 0x9800, + data_size: 0x2800, }, 'vector-z80color': { code_start: 0x0, @@ -662,6 +662,7 @@ function compileSDCC(code, platform) { '--less-pedantic', //'--fomit-frame-pointer', '--opt-code-speed', + '--oldralloc', // TODO: does this make it fater? '-o', 'main.asm']); /* // ignore if all are warnings (TODO?) diff --git a/test/cli/test1.c b/test/cli/test1.c new file mode 100644 index 00000000..fd5864f6 --- /dev/null +++ b/test/cli/test1.c @@ -0,0 +1,615 @@ + +#include +#include +#include + +typedef unsigned char byte; +typedef unsigned short word; +typedef signed char sbyte; + +word __at(0xa000) dvgram[0x1000]; +byte __at(0x8840) _dvgstart; + +int __at(0x8100) mathbox_sum; +sbyte __at(0x8102) mathbox_arg1; +sbyte __at(0x8103) mathbox_arg2; +byte __at(0x810f) mathbox_go_mul; + +byte __at (0x8000) input0; +byte __at (0x8001) input1; +byte __at (0x8002) input2; + +#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() + +void start() { +__asm + LD SP,#0x0 + DI +; copy initialized data + LD BC, #l__INITIALIZER + LD A, B + LD DE, #s__INITIALIZED + LD HL, #s__INITIALIZER + LDIR +__endasm; + // init heap for malloc() and run main pgm. + _sdcc_heap_init(); + main(); +} + +// VECTOR ROUTINES + +int dvgwrofs; // write offset for DVG buffer + +inline word ___swapw(word j) { + return ((j << 8) | (j >> 8)); +} + +inline void dvgreset() { + dvgwrofs = 0; +} + +inline void dvgstart() { + _dvgstart = 0; +} + +void dvgwrite(word w) { + dvgram[dvgwrofs++] = w; +} + +inline void VCTR(int dx, int dy, byte bright) { + dvgwrite((dy & 0x1fff)); + dvgwrite(((bright & 7) << 13) | (dx & 0x1fff)); +} + +inline void SVEC(signed char dx, signed char dy, byte bright) { + dvgwrite(0x4000 | (dx & 0x1f) | ((bright&7)<<5) | ((dy & 0x1f)<<8)); +} + +inline void JSRL(word offset) { + dvgwrite(0xa000 | offset); +} + +inline void JMPL(word offset) { + dvgwrite(0xe000 | offset); +} + +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; + + +// 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; +} + +inline void mul16(sbyte a, sbyte b) { + mathbox_arg1 = a; + mathbox_arg2 = b; + mathbox_go_mul=0; +} + +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; + } +} + +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, +}; + +sbyte isin(byte x0) { + byte x = x0; + if (x0 & 0x40) x = 127-x; + if (x0 & 0x80) { + return -sintbl[x+128]; + } else { + return sintbl[x]; + } +} + +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() { + word lsb = lfsr & 1; + lfsr >>= 1; + if (lsb) lfsr ^= 0xd400; + return lfsr; +} + +// 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 make_cached_shapes() { + Matrix mat; + byte i; + for (i=0; i<32; i++) { + 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(); +} + +// MAIN PROGRAM + +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 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 { + // get address of next pointer + prev = &a->next; + } + } +} + +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); +} + +inline byte abs(sbyte x) { + return (x>=0) ? x : -x; +} + +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, 20, 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; + +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() { + 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, 20, 0x2)) { + explode_at(curship); + curship->removed = 1; + curship = NULL; + newship_timer = 255; + } +} + +void main() { + memset(dvgram, 0x20, sizeof(dvgram)); // HALTs + dvgwrofs = 0x800; + make_cached_shapes(); + create_obstacles(5); + new_player_ship(); + while (1) { + dvgreset(); + draw_and_update_actors(); + control_player(); + remove_expired_actors(); + CNTR(); + HALT(); + dvgstart(); + frame++; + } +} diff --git a/test/cli/testworker.js b/test/cli/testworker.js index bffc0dde..30ceff87 100644 --- a/test/cli/testworker.js +++ b/test/cli/testworker.js @@ -81,6 +81,10 @@ function compile(tool, code, platform, callback, outlen, nlines, nerrors) { }); } +function ab2str(buf) { + return String.fromCharCode.apply(null, new Uint16Array(buf)); +} + describe('Worker', function() { it('should assemble DASM', function(done) { compile('dasm', '\tprocessor 6502\n\torg $f000\nfoo lda #0\n', 'vcs', done, 2, 1); @@ -127,6 +131,10 @@ describe('Worker', function() { it('should compile SDCC w/ include', function(done) { compile('sdcc', '#include \nvoid main() {\nstrlen(0);\n}\n', 'mw8080bw', done, 8192, 2, 0); }); + it('should compile big SDCC file', function(done) { + var csource = ab2str(fs.readFileSync('test/cli/test1.c')); + compile('sdcc', csource, 'vector-z80color', done, 32768, 298, 0); + }); it('should NOT compile SDCC', function(done) { compile('sdcc', 'foobar', 'mw8080bw', done, 0, 0, 1); }); diff --git a/tools/Makefile b/tools/Makefile index cc5f70d8..a80d98ab 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -11,5 +11,22 @@ %-48.pbm: %.jpg convert $< -resize 48x192\! -colorspace Gray -dither FloydSteinberg $@ +%.tga: %.png + convert $< -resize 128x96\! +dither $<.gif + convert $<.gif -type palette -compress RLE -colors 8 +dither -flip $@ + convert $@ $@.png + +%.pcx: %.png + convert $< -format raw -type palette -compress none -colors 15 +dither $@ + ship1.pbm: ship1.png - convert ship1.png -negate -flop ship1.pbm \ No newline at end of file + convert ship1.png -negate -flop ship1.pbm + +%.h: + cat $* | hexdump -v -e '"\n" 128/1 "0x%02x,"' + +%.prom: + cat $* | hexdump -v -e '" \n defb " 32/1 "$$%02x,"' | cut -c 2-134 + +%.rot.pbm: %.pbm + convert $< -transpose -bordercolor white -border 4x4 $@ diff --git a/tools/badspacerobots.png b/tools/badspacerobots.png new file mode 100644 index 00000000..329d8326 Binary files /dev/null and b/tools/badspacerobots.png differ diff --git a/tools/pbm_to_c.py b/tools/pbm_to_c.py index 0c66261a..0b6f5b02 100755 --- a/tools/pbm_to_c.py +++ b/tools/pbm_to_c.py @@ -22,7 +22,7 @@ with open(sys.argv[1],'rb') as f: header = f.readline().strip() assert(header == 'P4') dims = f.readline().strip() - if dims[0] == '#': + while dims[0] == '#': dims = f.readline().strip() width,height = map(int, dims.split()) wbytes = (width+7)/8 diff --git a/tools/pcx2will.py b/tools/pcx2will.py new file mode 100755 index 00000000..0c7d7e5f --- /dev/null +++ b/tools/pcx2will.py @@ -0,0 +1,37 @@ +#!/usr/bin/python + +import sys, array, string + + +def tohex2(v): + return '0x%02x'%v + +with open(sys.argv[1],'rb') as f: + data = array.array('B', f.read()) + assert data[0] == 0xa + assert data[3] == 8 + + # palette + print "byte palette[16] = {", + for i in range(0,16): + r = data[16+i*3] + g = data[17+i*3] + b = data[18+i*3] + entry = (r>>5) | ((g>>2)&0x38) | (b&0xc0) + print '%s,' % (tohex2(entry)), + print "}" + + # image data + width = (data[9] << 8) + data[8] + 1 + height = (data[11] << 8) + data[10] + 1 + rowlen = (data[0x43] << 8) + data[0x42] + print "%d,%d," % ((width+1)/2,height) + for y in range(0,height): + ofs = 0x80 + y*rowlen + output = [] + for x in range(0,width,2): + b = (data[ofs] << 4) + (data[ofs+1]) + output.append(b) + ofs += 2 + print string.join(map(tohex2,output),',') + ',' +