// percy.c: perspective projection without overhead of fixed point
// multiplications and divisions, by using lookup tables instead.


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// After having messed around with 3D objects and perspective projection
// in the past, using traditional maths more suited to fast machines and
// floating point (or even fixed point), I decided this week to bite the
// bullet and finally make a serious effort to write some Vectrex-friendly
// code in C to do 3D graphics a bit faster than my previous efforts.

// This is for games in the style of Tailgunner and Battlezone.  I have
// previously written code for both of those games that implements many
// parts of the games, but I've never managed to perform 3D graphics at
// an acceptable speed.  Hopefully, this entirely table-based approach
// should do a bit better.  (So far I've just been developing on my Linux,
// but I'll be moving this to the Vectrex soon for graphical testing.)

// (The code is almost entirely 8-bit arithmetic.  There are a couple of
// edge cases in this early code where the numbers seem to be causing overflow
// and faulty mappings but I'm not worried about those at the moment - the
// majority of examples I've tried so far do correctly place the projected
// objects where they should be on the screen.)

// The table-lookup approximation to the perspective calculation is usually
// within 1 Vectrex unit of the accurately-calculated value.  The small
// differences caused by using approximations are not going to matter at all
// in fast-moving video games.

//#define DEBUG_INTERPOLATION 1

typedef   int8_t XYCOORD;
typedef u_int8_t  ZCOORD;
typedef   int8_t  SCREEN;

/*
   I'm not using it yet, but the 'scale' table below is for an experiment that
I'm planning where a model is projected at a fixed distance but scaled using
Vectrex hardware scaling rather than requiring 16 bit arithmetic to extend the
range of viewing the object.  Basically the 'world' is a 256x256x256 cube and
the model will be placed in the center of that cube, projected with perspective,
and then scaled to apply distance outside of the 0:255 range from the viewer.

This is to avoid the need for excessive 16-bit arithmetic (or 32-bit in many
cases if using 16.16 fixed point).  The original Tailgunner game, for example,
takes place in a world that is a 1024x1024x1024 cube (which is helped by the
Cinematronics CPU supporting larger integers).

 */

const u_int8_t scale[64] = {
  255, 217, 191, 169, 151, 137, 127, 117, 107, 101, 95, 89, 83, 79, 75, 71,
  67, 65, 63, 59, 57, 55, 53, 51, 49, 47, 47, 45, 43, 41, 41, 39,
  39, 37, 37, 35, 35, 33, 33, 33, 31, 31, 31, 29, 29, 29, 27, 27,
  27, 25, 25, 25, 25, 25, 23, 23, 23, 23, 23, 21, 21, 21, 21, 21,
};


/*
      These lookup tables allow us to map any point in a 256x256x256 cube to a
   Vectrex screen coordinate.  The tables are reduced in size by using both
   symmetry and linear interpolation (with the interpolation using shifts
   rather than divides).

      What I have not yet done (only because I haven't yet started on the code)
   is anything to rotate the models within that 256x256x256 space, in order to
   get the 3D coordinates of the points in the model before doing the perspective
   projection.  I *may* switch to using 3D polar coordinates for the models to
   simplify those rotations or I may stick to the common cartesian coordinates.
   Either way, the rotations will have to be performed using sin and cos which
   will be also be done using lookup tables.
 */

const int8_t sx[8][/*9*/1][64] = {
  {
    
    // *** TO DO ***
    // The z sub-tables are all identical for the different values of Y, so these
    // arrays could be considerably reduced in size!  However if calculated properly
    // they *should not* all be the same because a 100 unit wide line from left
    // to right at y=0 (eye level) should look wider than the same line at Y=127
    // because the same line at the top of the view space (for the same z distance
    // away) is actually farther from the eye, being at the end of the hypotenuse
    // of a right-angled triangle rather than at the end of the base of that same
    // triangle.  This means that I calculated the perspective wrongly, but that
    // is a detail that can be corrected and does not affect the algorithm at all,
    // only the contents of these lookup tables.  I will either fix that later,
    // *or* after testing it on the display, I may just leave the tables with
    // these values and reduce the size of the lookup tables by a factor of 8,
    // if the visual difference is not large enough to be worth correcting...

    // Note that if we do conflate the y entries below, the entire sx[][][] table
    // takes up a mere 512 bytes.
    
    { /* [x=-128][y=-128][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
#ifdef NEVER
    { /* [x=-128][y=-112][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-96][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-80][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-64][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-48][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-32][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=-16][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
    { /* [x=-128][y=0][z=0:63] */
       -128, -109, -96, -85, -76, -69, -64, -59, -54, -51, -48, -45, -42, -40, -38, -36, 
       -34, -33, -32, -30, -29, -28, -27, -26, -25, -24, -24, -23, -22, -21, -21, -20, 
       -20, -19, -19, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, 
       -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -12, -11, -11, -11, -11, -11, 
    },
#endif
  },
  {
    { /* [x=-112][y=-128][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
#ifdef NEVER
    { /* [x=-112][y=-112][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-96][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-80][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-64][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-48][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-32][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=-16][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
    { /* [x=-112][y=0][z=0:63] */
       -112, -96, -84, -74, -67, -61, -56, -51, -48, -44, -42, -39, -37, -35, -33, -32, 
       -30, -29, -28, -26, -25, -24, -24, -23, -22, -21, -21, -20, -19, -19, -18, -18, 
       -17, -17, -16, -16, -16, -15, -15, -14, -14, -14, -14, -13, -13, -13, -12, -12, 
       -12, -12, -12, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -9, -9, 
    },
#endif
  },
  {
    { /* [x=-96][y=-128][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
#ifdef NEVER
    { /* [x=-96][y=-112][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-96][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-80][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-64][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-48][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-32][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=-16][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
    { /* [x=-96][y=0][z=0:63] */
       -96, -82, -72, -64, -57, -52, -48, -44, -41, -38, -36, -33, -32, -30, -28, -27, 
       -26, -25, -24, -23, -22, -21, -20, -19, -19, -18, -18, -17, -16, -16, -16, -15, 
       -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, -10, 
       -10, -10, -10, -10, -9, -9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, 
    },
#endif
  },
  {
    { /* [x=-80][y=-128][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
#ifdef NEVER
    { /* [x=-80][y=-112][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-96][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-80][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-64][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-48][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-32][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=-16][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
    { /* [x=-80][y=0][z=0:63] */
       -80, -68, -60, -53, -48, -43, -40, -36, -34, -32, -30, -28, -26, -25, -24, -22, 
       -21, -20, -20, -19, -18, -17, -17, -16, -16, -15, -15, -14, -14, -13, -13, -12, 
       -12, -12, -12, -11, -11, -11, -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, 
       -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -6, 
    },
#endif
  },
  {
    { /* [x=-64][y=-128][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
#ifdef NEVER
    { /* [x=-64][y=-112][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-96][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-80][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-64][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-48][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-32][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=-16][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
    { /* [x=-64][y=0][z=0:63] */
       -64, -54, -48, -42, -38, -34, -32, -29, -27, -25, -24, -22, -21, -20, -19, -18, 
       -17, -16, -16, -15, -14, -14, -13, -13, -12, -12, -12, -11, -11, -10, -10, -10, 
       -10, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, 
       -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
    },
#endif
  },
  {
    { /* [x=-48][y=-128][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
#ifdef NEVER
    { /* [x=-48][y=-112][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-96][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-80][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-64][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-48][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-32][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=-16][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
    { /* [x=-48][y=0][z=0:63] */
       -48, -41, -36, -32, -28, -26, -24, -22, -20, -19, -18, -16, -16, -15, -14, -13, 
       -13, -12, -12, -11, -11, -10, -10, -9, -9, -9, -9, -8, -8, -8, -8, -7, 
       -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 
    },
#endif
  },
  {
    { /* [x=-32][y=-128][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
#ifdef NEVER
    { /* [x=-32][y=-112][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-96][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-80][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-64][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-48][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-32][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=-16][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
    { /* [x=-32][y=0][z=0:63] */
       -32, -27, -24, -21, -19, -17, -16, -14, -13, -12, -12, -11, -10, -10, -9, -9, 
       -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, 
       -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, 
       -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
    },
#endif
  },
  {
    { /* [x=-16][y=-128][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
#ifdef NEVER
    { /* [x=-16][y=-112][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-96][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-80][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-64][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-48][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-32][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=-16][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
    { /* [x=-16][y=0][z=0:63] */
       -16, -13, -12, -10, -9, -8, -8, -7, -6, -6, -6, -5, -5, -5, -4, -4, 
       -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, 
       -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    },
#endif
  },
#ifdef NEVER
  {
    { /* [x=0][y=-128][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
#ifdef NEVER
    { /* [x=0][y=-112][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-96][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-80][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-64][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-48][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-32][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=-16][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
    { /* [x=0][y=0][z=0:63] */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    },
#endif
  },
#endif
};

// rom space used: 5248 bytes

static inline const SCREEN *lookupxmap(XYCOORD x, XYCOORD y, ZCOORD z, int *N) { // N is the sign of what the value should be.
  *N = 1;
  if (x > 0) {*N = -1; x = -x;}  // symmetric, 0:127 -> 1:-127
  if (y > 0) {*N = -1; y = -y;}
  //fprintf(stderr, "lookupxmap: x=%02x  y=%02x  z=%02x  ->  %d\n", x+128,y+128,z, sx[(x+128)>>4][/*(y+128)>>4*/0][z>>2]);
  return &sx[(x+128)>>4][/*(y+128)>>4*/0][z>>2];  // map from -128:0 to 0:128
}

static inline SCREEN lookupx(XYCOORD x, XYCOORD y, ZCOORD z) {
  if (x == 0) return 0;
  int N;
  XYCOORD x0 =  (x>>4)   <<4;
  XYCOORD x1;
  x1 = ((x>>4)+1)<<4; // BEWARE END CASE WHERE +1 WRAPS IN A BYTE.
  int frac = x&15;
  const SCREEN *X0 = lookupxmap(x0,y,z,&N);
  SCREEN sX0 = *X0*N;
  if (x == x0) {
#ifdef DEBUG_INTERPOLATION
    fprintf(stderr, "lookupx: sx [%c%02x][y][z] = %c%02x *\n\n", x <0?'-':' ',  x <0?-x &0xff:x &0xFF, sX0<0?'-':' ', sX0<0?-sX0&0xFF:sX0 &0xFF);
#endif
    return sX0;
  }
  const SCREEN *X1 = lookupxmap(x1,y,z,&N);
  SCREEN sX1 = *X1*N;
  if (sX0 == sX1) {
#ifdef DEBUG_INTERPOLATION
    fprintf(stderr, "lookupx: sx [%c%02x][y][z] = %c%02x *\n\n", x <0?'-':' ',  x <0?-x &0xff:x &0xFF, sX0<0?'-':' ', sX0<0?-sX0&0xFF:sX0 &0xFF);
#endif
    return sX0;
  }
  SCREEN sX;
  sX = sX0 + (((sX1-sX0)*frac)>>4); // BEWARE INTERMEDIATE VALUES OUTSIDE OF BYTE RANGE.
#ifdef DEBUG_INTERPOLATION
  fprintf(stderr, "lookupx: sx0[%c%02x][y][z] = %c%02x\n",   x0<0?'-':' ',  x0<0?-x0&0xff:x0&0xFF, sX0<0?'-':' ', sX0<0?-sX0&0xFF:sX0&0xFF);
  fprintf(stderr, "lookupx: sx [%c%02x][y][z] = %c%02x *\n", x <0?'-':' ',  x <0?-x &0xff:x &0xFF, sX <0?'-':' ', sX <0?-sX &0xFF:sX &0xFF);
  fprintf(stderr, "lookupx: sx1[%c%02x][y][z] = %c%02x\n\n", x1<0?'-':' ',  x1<0?-x1&0xff:x1&0xFF, sX1<0?'-':' ', sX1<0?-sX1&0xFF:sX1&0xFF);
#endif  
  return sX;
}

static inline SCREEN lookupy(XYCOORD x, XYCOORD y, ZCOORD z) {
  // sy[x][y][z] == sx[y][x][z]  so parameters swapped
  SCREEN tmp=lookupx(y, x, z);
  //fprintf(stderr, "lookupy:  x=%02x  y=%02x  z=%02x  ->  %d\n", x,y,z,  tmp);
  return tmp;
}

void perspective(XYCOORD x, XYCOORD y, ZCOORD z, SCREEN *X, SCREEN *Y) {
  // x or y at -128 will give the wrong answer for now. 
  *X = lookupx(x,y,z);
  *Y = lookupy(x,y,z);
  if (*X < 0) *X = -(1+*X);
  if (*Y < 0) *Y = -(1+*Y);
  if (x < 0) *X = -*X;
  if (y < 0) *Y = -*Y;
  //fprintf(stderr, "perspective:  x=%02x  y=%02x  z=%02x  ->  %d,%d\n", x&255,y&255,z,  *X,*Y);
}

void moveto(SCREEN x, SCREEN y) {
  fprintf(stdout, "moveto(%d,%d);\n", x, y);
  //fprintf(stdout, "moveto(%3.1f,%3.1f);\n", x, y);
}

void lineto(SCREEN x, SCREEN y) {
  fprintf(stdout, "lineto(%d,%d);\n", x, y);
  //fprintf(stdout, "lineto(%3.1f,%3.1f);\n", x, y);
}

void mv(XYCOORD x, XYCOORD y, ZCOORD z) {
  SCREEN X, Y;
  perspective(x, y, z, &X, &Y);
  moveto(X, Y);
}

void dw(XYCOORD x, XYCOORD y, ZCOORD z) {
  SCREEN X, Y;
  perspective(x, y, z, &X, &Y);
  lineto(X, Y);
}

int main(int argc, char **argv) {
  int h = 91;

  mv(h, -h, -h); dw(h, h, -h);
  dw( -h, h, -h);
  dw( -h, h, h);
  dw( -h, -h, h);
  dw(h, -h, h);
  dw(h, -h, -h);
  mv(h, h, -h); dw(h, h, h);
  dw( -h, h, h);
  mv(h, h, h); dw(h, -h, h);
  mv(h, -h, -h); dw(-h, -h, -h);
  dw( -h, h, -h);
  mv(-h, -h, -h); dw(-h, -h, h);

  fprintf(stderr, "perspective lookup table uses %zu bytes.\n", sizeof(sx));
  
  exit(EXIT_SUCCESS);
  return EXIT_FAILURE;
}
