#include <SPI.h>
#include <GD.h>
#include "debug.h"    // JCB

int atxy(int x, int y)
{
  return (y << 6) + x;
}

#include "bg.h"
#include "bgstripes.h"

class GDflashbits {
public:
  void begin(prog_uchar *s) {
    src = s;
    mask = 0x01;
  }
  byte get1(void) {
    byte r = (pgm_read_byte_near(src) & mask) != 0;
    mask <<= 1;
    if (!mask) {
      mask = 1;
      src++;
    }
    return r;
  }
  unsigned short getn(byte n) {
    unsigned short r = 0;
    while (n--) {
      r <<= 1;
      r |= get1();
    }
    return r;
  }
private:
  prog_uchar *src;
  byte mask;
};

static GDflashbits GDFB;

static void GD_uncompress(unsigned int addr, PROGMEM prog_uchar *src)
{
  GDFB.begin(src);
  byte b_off = GDFB.getn(4);
  byte b_len = GDFB.getn(4);
  byte minlen = GDFB.getn(2);
  unsigned short items = GDFB.getn(16);
  while (items--) {
    if (GDFB.get1() == 0) {
      GD.wr(addr++, GDFB.getn(8));
    } else {
      int offset = -GDFB.getn(b_off) - 1;
      int l = GDFB.getn(b_len) + minlen;
      while (l--) {
        GD.wr(addr, GD.rd(addr + offset));
        addr++;
      }
    }
  }
}

static void setup_sprites()
{
  GD.copy(PALETTE16A, palette16a, sizeof(palette16a));
  GD.copy(PALETTE16B, palette16b, sizeof(palette16b));
  GD_uncompress(RAM_SPRIMG, sprimg_cc);

  GD.wr(JK_MODE, 1);
}

static int shot = 0;

void setup()
{
  Serial.begin(1000000);   // JCB

  GD.begin();
  setup_sprites();
  GD_uncompress(RAM_CHR, dchr);
  GD_uncompress(RAM_PAL, dpal);
  GD.microcode(bgstripes_code, sizeof(bgstripes_code));
  GD.copy(0x3e80, desert, sizeof(desert));

  int ypos;
  int delta = 1;
  int speedup = 0;
  for (ypos = 2048 - 299; ypos > 0; ypos -= delta) {
    if (++speedup == 90) {
      speedup = 0;
      delta++;
    }
    GD.__wstartspr(0);
    int jy = (2048-44) - ypos;
    if (jy < 400)
      draw_walk(100, jy, 0, 0);
    GD.__end();

    int yd = ypos >> 4;

    GD.wr16(SCROLL_Y, ypos & 15);
    GD.wr(COMM+0, 236 - yd);
    int x, y;
    int fruit = 64;
    for (y = 0; y < 32; y++) {
      for (x = 0; x < 32; x++) {
        byte t = pgm_read_byte_near(level + ((y + yd) << 5) + x);
        if (t == 4) {
          GD.__wstartspr(fruit);
          draw_fruit(16 * x + 8, 16 * y - (ypos & 15) + 8, ((x + y + yd) % 6), 0);
          GD.__end();
          fruit++;
          t = 0;
        }
        PROGMEM prog_uchar *pt = tiles + (t << 2);
        int da = (x << 1) + (y << 7);
        GD.copy(da, pt, 2);
        GD.copy(da + 64, pt + 2, 2);
      }
    }

    // GD.screenshot(shot);
    shot++;
  }
}

void loop()
{
}
