/* VERY cut-down demo program to find cause of crashing */


#include <vectrex.h>

#define REDUCE_WOBBLE       /* Add some extra 'zero_beam's to align better */

#define MAX_BRIGHTNESS (0x7f)

static unsigned char scale;
static int stackp;

/* This nastiness is necessary to avoid a 6809 GCC compiler bug :-( */
static char *lookup;

static char private_stack[256];

static inline void set_lookup(unsigned char *local_lookup)
{
  lookup = local_lookup;
}


static unsigned char tg_lookup[7*8*3] = {
  0x17, 0x25, 0x20, /* TAIL */
  0x1b, 0x25, 0x20,
  0x19, 0x25, 0x20,
  0x19, 0x20, 0x20,
  0x1c, 0x20, 0x20,
  0x1d, 0x25, 0x20,
  0x1f, 0x20, 0x20,
  0x1d, 0x23, 0x20,
  0x1e, 0x23, 0x20,
  0x22, 0x20, 0x20,
  0x22, 0x25, 0x20,
  0x25, 0x25, 0x20,
  0x25, 0x20, 0x20,
  0x28, 0x20, 0x20,
  0x29, 0x1f, 0x20,
  0x29, 0x1a, 0x20,

  0x29, 0x1f, 0x20, /* GUN */
  0x2c, 0x1f, 0x20,
  0x2c, 0x1d, 0x20,
  0x2c, 0x1e /* 1d */, 0x20,
  0x2c, 0x1a, 0x20,
  0x29, 0x1d, 0x20,
  0x28, 0x1a, 0x20,
  0x25, 0x1a, 0x20,
  0x25, 0x1f, 0x20,
  0x28, 0x1f, 0x20,
  0x26, 0x1d, 0x20,
  0x25, 0x1d, 0x20,
  0x23, 0x1f, 0x20,
  0x23, 0x1a, 0x20,
  0x20, 0x1f, 0x20,
  0x20, 0x1a, 0x20,

  0x1f, 0x1f, 0x20, /* NER */
  0x1f, 0x1a, 0x20,
  0x1c, 0x1f, 0x20,
  0x1c, 0x1a, 0x20,
  0x1a, 0x1f, 0x20,
  0x1a, 0x1a, 0x20,
  0x17, 0x1a, 0x20,
  0x17, 0x1f, 0x20,
  0x17, 0x1c, 0x20,
  0x15, 0x1c, 0x20,
  0x16, 0x1c, 0x20,
  0x16, 0x1a, 0x20,
  0x13, 0x1a, 0x20,
  0x13, 0x1f, 0x20,
  0x16, 0x1f, 0x20,
  0x00, 0x00, 0x20,

  0x23, 0x4d, 0x40, /* rectangles */
  0x5c, 0x4d, 0x40,
  0x5c, 0x32, 0x40,
  0x23, 0x32, 0x40,
  0x1f, 0x51, 0x40,
  0x60, 0x51, 0x40,
  0x60, 0x2e, 0x40,
  0x1f, 0x2e, 0x40,
};

const unsigned char tg[39*2] = {
  0x00, 0x01,  /* TAIL */
  0x02, 0x03,
  0x04, 0x05,
  0x05, 0x06,
  0x07, 0x08,
  0x09, 0x0a,
  0x0b, 0x0c,
  0x0c, 0x0d,
  0x0e, 0x0f,

  0x10, 0x11, /* GUN */
  0x11, 0x12,
  0x13, 0x14,
  0x12, 0x15,
  0x16, 0x17,
  0x17, 0x18,
  0x18, 0x19,
  0x1a, 0x1b,
  0x1c, 0x1d,
  0x1d, 0x1e,
  0x1e, 0x1f,

  0x20, 0x21, /* NER */
  0x21, 0x22,
  0x22, 0x23,
  0x24, 0x25,
  0x25, 0x26,
  0x26, 0x27,
  0x28, 0x29,
  0x2a, 0x2b,
  0x2b, 0x2c,
  0x2c, 0x2d,
  0x2d, 0x2e,

  0x30, 0x31, /* rectangles */
  0x31, 0x32,
  0x32, 0x33,
  0x33, 0x30,
  0x34, 0x35,
  0x35, 0x36,
  0x36, 0x37,
  0x37, 0x34,
};


static inline void print_seg_relative(int nib1, int nib2)
{
  char fromx, fromy, fromz, tox, toy, toz, dx, dy;

  nib1 = nib1 + nib1 + nib1;          /*  mult by 3 gives compiler bug */
  fromx = lookup[nib1]; nib1 += 1;
  fromy = lookup[nib1]; nib1 += 1;
  fromz = lookup[nib1];
  move_to(fromx, fromy);

  nib2 = nib2 + nib2 + nib2;
  tox = lookup[nib2]; nib2 += 1;
  toy = lookup[nib2]; nib2 += 1;
  toz = lookup[nib2];

  dx = tox-fromx; dy = toy-fromy;
  draw_line(dx, dy);
  move_to(-dx, -dy);
  move_to(-fromx, -fromy);
}

static inline void print_tg(void)
{
  /* These had to be moved inside the procedure to prevent a crash - GCC bug */
 
  int i;

  zero_beam();
  set_scale(scale);
  /* Now use local, relative, and smaller coordinates for crosshair */
  move_to(-0x40,-0x40);

  set_lookup(tg_lookup);
  for (i = 0; i < 39*2; i += 2) {
    print_seg_relative(/* from code */ tg[i], /* to code */ tg[i+1]);
  }
}


/* Shields get a special proc because they're one continuous line */
static char shieldvec[] = {
  24,24,  96,-96, 24,24, -72,72, -72,-72, 24,-24, 96,96, 24,-24, -72,-72, -72,72
};

/* Shields on the vectrex are sideways wrt the 'real' tailgunner */
static inline void draw_shields(void)
{
  int i;
  char *ptr;
  char x1, y1;

  ptr = shieldvec;
  asm("pshs   d,x,y,u");
  zero_beam();
  asm("puls   d,x,y,u");

  asm("pshs   d,x,y,u");
  set_scale(scale);
  asm("puls   d,x,y,u");

  asm("pshs   d,x,y,u");
  move_to(24, -72); /* Manually tweaked */
  asm("puls   d,x,y,u");

#ifdef NEVER
  for (i = 0; i < 10; i++) {
    /* DRAW THE VECTOR */
    y1 = (*ptr++);
    x1 = (*ptr++);
    asm("pshs   d,x,y,u");
    draw_line(x1, y1);
    asm("puls   d,x,y,u");
  }
#endif
}

/* still to modify the struct below to match the 'tailgunner' indirection system */
static char crosshair_points[60] = { /* Should be placed in rom */
 0x03, 0x20, 0,  0x3e, 0x20, 0,
 0x34, 0x16, 0,  0x34, 0x2a, 0,
 0x16, 0x34, 0,  0x2a, 0x34, 0,
 0x20, 0x02, 0,  0x20, 0x3e, 0,
 0x16, 0x0c, 0,  0x2a, 0x0c, 0,
 0x0c, 0x16, 0,  0x0c, 0x2a, 0,
 0x1b, 0x2a, 0,  0x25, 0x2a, 0,
 0x2a, 0x1b, 0,  0x2a, 0x25, 0,
 0x1b, 0x16, 0,  0x25, 0x16, 0,
 0x16, 0x1b, 0,  0x16, 0x25, 0,
};

static char crosshair[20] = {
 0, 1,
 2, 3,
 4, 5,
 6, 7,
 8, 9,
10, 11,
12, 13,
14, 15,
16, 17,
18, 19
};

static char x, y;  /* global rather than param because of compiler bug */

static inline void draw_crosshair(void)
{
#ifdef NEVER
  char x1, y1, z1, x2, y2, z2, dx, dy;
  char *ptr;

  zero_beam();
  set_scale(0x80);                  /* 80 matches scale for text in main loop */
  move_to(x,y);

  /* Now use local, relative, and smaller coordinates for crosshair */
  set_scale(scale);                  /* keep movement same but adjust cursor size */
  move_to(-0x20, -0x20);

  ptr = crosshair_points;
  for (;;) {
    /* DRAW THE VECTOR */
    x1 = *ptr++; if (x1 == 0) break; y1 = *ptr++; z1 = *ptr++;
    x2 = *ptr++; y2 = *ptr++; z2 = *ptr++;

    dx = x2-x1; dy = y2-y1;

    move_to(x1, y1); draw_line(dx, dy);
    move_to(-dx, -dy); move_to(-x1, -y1);    
    /* back at relative 0,0 */

#ifdef REDUCE_WOBBLE
    zero_beam();
    set_scale(0x80);                  /* 80 matches scale for text in main loop */
    /* Now use local, relative, and smaller coordinates for crosshair */
    move_to(x,y);
    set_scale(scale);                  /* keep movement same but adjust cursor size */
    move_to(-0x20, -0x20);
#endif
  }
#endif
}

/* the C release, and the emulator, both only support joy_digital :-( */

#define joy_analog() \
                              {save_frame_x() \
                              asm("jsr \t0HF1F5 \t; joy_analog":::"a","b","d","x");\
                              restore_frame_x()}

#define INIT_BOX_SCALE 0x0

int main(int argc, char **argv) {
  char msg[10];
  const char hex[17] = "0123456789ABCDEF";
  unsigned char boxscale = INIT_BOX_SCALE;
  unsigned char step = 1;
  x = 0; y = 0;

#ifdef DEBUGGING
  stackp = (int)&private_stack[128]; /* not sue if it grows down or up so get an address in the middle */
  asm("tfr   u,s");
#endif
  set_dp_c8();                        /* vectrex internal... dp must point */

  enable_joystick_1x();
  enable_joystick_1y();
  disable_joystick_2x();
  disable_joystick_2y();
  joy_analog();

  /* read it twice, I had trouble doing it once only :-( */
  read_buttons(); wait_recal();
  read_buttons(); wait_recal();

  for (;;) {
    asm("pshs   d,x,y,u");
    wait_recal();        /* Once each frame */
    asm("puls   d,x,y,u");

    asm("pshs   d,x,y,u");
    zero_beam();
    asm("puls   d,x,y,u");

    asm("pshs   d,x,y,u");
    intensity(MAX_BRIGHTNESS);        /* set some brightness */
    asm("puls   d,x,y,u");

#ifdef DEBUGGING
    asm("sts   _stackp");

    msg[3] = hex[stackp&15];
    stackp = stackp >> 4;
    msg[2] = hex[stackp&15];
    stackp = stackp >> 4;
    msg[1] = hex[stackp&15];
    stackp = stackp >> 4;
    msg[0] = hex[stackp&15];
    msg[4] = '\0';
    print_str(0, -80, msg); /* a message! */
#else
    asm("pshs   d,x,y,u");
    print_str(0, -80, "RUNNING"); /* a message! */
    asm("puls   d,x,y,u");
#endif

    x = joystick1_x; y = joystick1_y;
    scale = 0xf0; draw_shields();
#ifdef NEVER
    scale = 0x30; draw_crosshair();
    scale = boxscale;
    /* We make the box containing the word 'tailgunner' appear,
       and move towards us one magstep every second frame */
    step = 1-step;
    if (boxscale >= 0x40) { /* Off-screen for a time, and start at a suitable size */
      print_tg();
    }
    boxscale += step;
    if (boxscale >= 0xb0) boxscale = INIT_BOX_SCALE;
#endif
    asm("pshs   d,x,y,u");
    joy_analog();                        /* call once per round, to insure */
    asm("puls   d,x,y,u");
  }
}
