byte* COLS = $d800;
byte* BGCOL = $d020;
byte* FGCOL = $d021;
byte* SCROLL = $d016;
byte* D018 = $d018;

byte* D011 = $d011;
byte RST8 = %10000000;
byte ECM =  %01000000;
byte BMM =  %00100000;
byte DEN =  %00010000;
byte RSEL =  %00001000;

byte* D016 = $d016;
byte MCM =  %00010000;
byte CSEL = %00001000;

byte* SCREEN = $400;
const byte* BITMAP = $2000;

const byte[256] plot_xlo;
const byte[256] plot_xhi;
const byte[256] plot_ylo;
const byte[256] plot_yhi;
const byte[256] plot_bit;

byte[] lines_x = { 60, 80, 110, 80, 60, 40, 10, 40, 60 };
byte[] lines_y = { 10, 40, 60, 80, 110, 80, 60, 40, 10 };
byte lines_cnt = 8;

void main() {
    *BGCOL = 0;
    *FGCOL = 0;
    *D011 = BMM|DEN|RSEL|3;
    *D018 = (byte)(((word)SCREEN/$40)|((word)BITMAP/$400));
    init_screen();
    init_plot_tables();
    do {
        lines();
    } while (true);
}

void lines() {
    for(byte l=0; l<lines_cnt;l++) {
        line(lines_x[l], lines_x[l+1], lines_y[l], lines_y[l+1]);
    }
}

void line(byte x0, byte x1, byte y0, byte y1) {
    byte xd;
    byte yd;
    if(x0<x1) {
        xd = x1-x0;
        if(y0<y1) {
            yd = y1-y0;
            if(yd<xd) {
                line_xdyi(x0, y0, x1, xd, yd);
            } else {
                line_ydxi(y0, x0, y1, yd, xd);
            }
        } else {
            yd = y0-y1;
            if(yd<xd) {
                line_xdyd(x0, y0, x1, xd, yd);
            } else {
                line_ydxd(y1, x1, y0, yd, xd);
            }
        }
    } else {
        xd = x0-x1;
        if(y0<y1) {
            yd = y1-y0;
            if(yd<xd) {
                line_xdyd(x1, y1, x0, xd, yd);
            } else {
                line_ydxd(y0, x0, y1, yd, xd);
            }
        } else {
            yd = y0-y1;
            if(yd<xd) {
                line_xdyi(x1, y1, x0, xd, yd);
            } else {
                line_ydxi(y1, x1, y0, yd, xd);
            }
        }
    }
}

void line_xdyi(byte x, byte y, byte x1, byte xd, byte yd) {
  byte e = yd>>1;
  do  {
      plot(x,y);
      x++;
      e = e+yd;
      if(xd<e) {
          y++;
          e = e - xd;
      }
  } while (x!=(x1+1));
}

void line_xdyd(byte x, byte y, byte x1, byte xd, byte yd) {
  byte e = yd>>1;
  do  {
      plot(x,y);
      x++;
      e = e+yd;
      if(xd<e) {
          y--;
          e = e - xd;
      }
  } while (x!=(x1+1));
}

void line_ydxi(byte y, byte x, byte y1, byte yd, byte xd) {
  byte e = xd>>1;
  do  {
      plot(x,y);
      y++;
      e = e+xd;
      if(yd<e) {
          x++;
          e = e - yd;
      }
  } while (y!=(y1+1));
}

void line_ydxd(byte y, byte x, byte y1, byte yd, byte xd) {
  byte e = xd>>1;
  do  {
      plot(x,y);
      y = y++;
      e = e+xd;
      if(yd<e) {
          x--;
          e = e - yd;
      }
  } while (y!=(y1+1));
}

void plot(byte x, byte y) {
    word plotter_x = { plot_xhi[x], plot_xlo[x] };  // Needs word arrays arranged as two underlying byte arrays to allow byte* plotter_x = plot_x[x]; - and eventually - byte* plotter = plot_x[x] + plot_y[y];
    word plotter_y = { plot_yhi[y], plot_ylo[y] };
    byte* plotter = plotter_x+plotter_y;
    *plotter = *plotter | plot_bit[x];
}

void init_plot_tables() {
    byte bits = $80;
    for(byte x : 0..255) {
        plot_xlo[x] = x&$f8;
        plot_xhi[x] = >BITMAP;
        plot_bit[x] = bits;
        bits = bits>>1;
        if(bits==0) {
          bits = $80;
        }
    }
    byte* yoffs = $0;
    for(byte y : 0..255) {
        plot_ylo[y] = y&$7 | <yoffs;
        plot_yhi[y] = >yoffs;
        if((y&$7)==7) {
            yoffs = yoffs + 40*8;
        }
    }
}

void init_screen() {
    for(byte* b = BITMAP; b!=BITMAP+$2000; b++) {
        *b = 0;
    }
    for(byte* c = SCREEN; c!=SCREEN+$400;c++) {
        *c = $14;
    }
}
