#include <vectrex.h>
// 240 rather than 256 to leave a little slack for a margin
// BLOCK LENGTH is actually half a block. Hence 120 not 240 below.
#define BLOCKS_PER_SCREEN 15
#define BLOCK_LENGTH ((int)(120U / (unsigned int)BLOCKS_PER_SCREEN))

#define ROOF_SCALE 0xFF
//#define FLOOR_SCALE ((unsigned int)(((long)ROOF_SCALE * BLOCKS_PER_SCREEN) / (BLOCKS_PER_SCREEN+1L)))

#define set_scale(s) do { VIA_t1_cnt_lo = (unsigned int)s*2; } while (0)

static int oldy, oldx;
void LineAbs(int x, int y) {
  Draw_Line_d(y-oldy, x-oldx);
  oldx = x; oldy = y;
}

void MoveAbs(int x, int y) {
  Moveto_d(y-oldy, x-oldx);
  oldx = x; oldy = y;
}

int mapx(int x, int pass) {
  if (pass == 0) return x;
  return (int)(((long)x*7L)>>3L);
}

int mapy(int y, int pass) {
  if (pass == 0) return y;
  return (int)(((long)y*7L)>>3L);
}

void Line(int x1, int y1, int x2, int y2) {
  Reset0Ref(); oldx = oldy = 0;
  MoveAbs(x1, y1); LineAbs(x2, y2);
}

int main(void)
{
  int basex = -59, basey = 59;
  int pass, few = 0;
  int dx=-1, dy=1;

  set_scale(ROOF_SCALE);
  for (;;) {
    Wait_Recal();

    Reset0Ref(); oldx = oldy = 0;
    Intensity_a(0x60);

    for (pass = 0; pass <= 1; pass++) {
      // On the second pass, one or two of the base edges will not be visible
      // depending on the quadrant, and one or two of the other edges will be clipped.

      // Unfortunately using the center point as a test doesn't quite work, when the floor
      // square is entirely within the roof square, but still a little off-center.  The actual
      // test needs to be against the two corners corresponding to the quadrant.

      // problem could be avoided if floor and roof are drawn at the same scale.  Whether that
      // would have the right visual appeal remains to be seen... computation and verticals would
      // certainly be much cheaper!  I.e. isometric rather than perspective.

      // left edge
      if (pass == 1 && basex < 0) { } else
      Line(mapx(-BLOCK_LENGTH+basex, pass), mapy(-BLOCK_LENGTH+basey, pass),
           mapx(-BLOCK_LENGTH+basex, pass), mapy(BLOCK_LENGTH+basey, pass));

      // depending on the quadrant of the center of the block, some of the
      // z-edges will not be visible.

      // bottom left corner
      if (pass==0 && (!(basex < 0 && basey < 0)))
                   Line(mapx(-BLOCK_LENGTH+basex, 0), mapy(-BLOCK_LENGTH+basey, 0),
                        mapx(-BLOCK_LENGTH+basex, 1), mapy(-BLOCK_LENGTH+basey, 1));

      // top edge
      if (pass == 1 && basey > 0 ) { } else
      Line(mapx(-BLOCK_LENGTH+basex, pass), mapy(BLOCK_LENGTH+basey, pass),
           mapx(BLOCK_LENGTH+basex, pass), mapy(BLOCK_LENGTH+basey, pass));
      
      // top left corner
      if (pass==0 && (!(basex < 0 && basey > 0)))
                   Line(mapx(-BLOCK_LENGTH+basex, 0), mapy(BLOCK_LENGTH+basey, 0),
                        mapx(-BLOCK_LENGTH+basex, 1), mapy(BLOCK_LENGTH+basey, 1));

      // right edge
      if (pass == 1 && basex > 0) { } else
      Line(mapx(BLOCK_LENGTH+basex, pass), mapy(BLOCK_LENGTH+basey, pass),
           mapx(BLOCK_LENGTH+basex, pass), mapy(-BLOCK_LENGTH+basey, pass));

      // top right corner
      if (pass==0 && (!(basex > 0 && basey > 0)))
                  Line(mapx(BLOCK_LENGTH+basex, 0), mapy(BLOCK_LENGTH+basey, 0),
                        mapx(BLOCK_LENGTH+basex, 1), mapy(BLOCK_LENGTH+basey, 1));

      // bottom edge
      if (pass == 1 && basey < 0) { } else
      Line(mapx(BLOCK_LENGTH+basex, pass), mapy(-BLOCK_LENGTH+basey, pass),
           mapx(-BLOCK_LENGTH+basex, pass), mapy(-BLOCK_LENGTH+basey, pass));

      // bottom right corner
      if (pass==0 && (!(basex > 0 && basey < 0))) Line(mapx(BLOCK_LENGTH+basex, 0), mapy(-BLOCK_LENGTH+basey, 0),
                        mapx(BLOCK_LENGTH+basex, 1), mapy(-BLOCK_LENGTH+basey, 1));

    }
    if ((few&3)==3) {
      basex += dx; basey += dy;
      if (basex >= 60) dx = -dx; if (basey >= 60) dy = -dy;
      if (basex <= -60) dx = -dx; if (basey <= -60) dy = -dy;
    }
    few += 1;
  }
  return 0;
}