more work on vector game; williams examples, tools

This commit is contained in:
Steven Hugg 2017-03-28 12:22:33 -04:00
parent c0e51bb460
commit ca479d6b8c
18 changed files with 1473 additions and 138 deletions

View File

@ -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": {

View File

@ -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++;

View File

@ -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;

View File

@ -0,0 +1,60 @@
#include <string.h>
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<h; j++) {
bitshift_value = 0;
for (i=0; i<w; i++) {
bitshift_value = *src++;
*dest++ = bitshift_read;
}
bitshift_value = 0;
*dest++ = bitshift_read;
dest += 31-w;
}
}
void clrscr() {
memset(vidmem, 0, sizeof(vidmem));
}
void main() {
byte x;
// TODO: clear memory
clrscr();
for (x=0; x<255; x++) {
draw_shifted_sprite(bitmap1, x, x);
watchdog_strobe++;
}
main();
}

View File

@ -1,6 +1,7 @@
#include <string.h>
#include <malloc.h>
#include <stdio.h>
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();
}

View File

@ -0,0 +1,151 @@
#include <string.h>
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; j<hdr->height; j++) {
byte* start = dest;
i = 0;
lastbyte = 0;
while (i<hdr->width) {
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;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,241 @@
#include <string.h>
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;
}
}

View File

@ -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; },
};

View File

@ -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),
}
}

View File

@ -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];

View File

@ -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?)

615
test/cli/test1.c Normal file
View File

@ -0,0 +1,615 @@
#include <string.h>
#include <malloc.h>
#include <stdio.h>
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; i<nv; i++) {
vec_mat_transform(dest++, src++, m);
}
}
void draw_wireframe_ortho(const Wireframe* wf, const Matrix* m) {
const char* e = wf->edges;
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++;
}
}

View File

@ -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 <string.h>\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);
});

View File

@ -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
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 $@

BIN
tools/badspacerobots.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -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

37
tools/pcx2will.py Executable file
View File

@ -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),',') + ','