#include "c_includ.h"
/*
 * c_draw.c
 * Todd W Mummert, CMU, January 1991
 *
 * This is an attempt at cleaning up the drawing routines.
 */

/*
 * this routine is for points which cannot change their bearing and have
 * no moving parts; i.e., blocks.
 */
void calcpointsI(dc, method, index, g, pl)
     DCp dc;
     Methodp method;
     int index;
     Genericp g, pl;
{
  int i;
  float xpoff, ypoff, prx, pry, prz, dx, dy;
  Coord2dp new;
  Coord3dp old;

  old = dc->s->object+index;
  new = dc->points+index;
  dx = pl->x - dc->pos.x;
  dy = pl->y - dc->pos.y;
  for (i=0; i<method->num; i++, old++, new++) {
      xpoff = old->x - dx;
      ypoff = old->y - dy;
      prx =  xpoff * pl->ca + ypoff * pl->sa;
      pry = -xpoff * pl->sa + ypoff * pl->ca;
      if (pry < 10.0)
        pry = 10.0;
      prz = old->z + dc->pos.z;
      new->x = 500 + prx / pry * 450;
      new->y = 260 - prz / pry * 450;
    }
}

/*
 * this routine is for points which may change their bearing, but do not
 * have moving parts.
 */
void calcpointsII(dc, method, index, g, pl)
     DCp dc;
     Methodp method;
     int index;
     Genericp g, pl;
{
  int i;
  float csa, ssa, dx, dy, xn, yn, cn, sn, prx, pry, prz, rx, ry;
  Coord2dp new;
  Coord3dp old;

  old = dc->s->object+index;
  new = dc->points+index;

  csa = cos(g->azm);
  ssa = sin(g->azm);
  dx = pl->x - dc->pos.x;
  dy = pl->y - dc->pos.y;
  xn =  dx * csa + dy * ssa;
  yn = -dx * ssa + dy * csa;
  cn = pl->ca * csa + pl->sa * ssa;
  sn = pl->sa * csa - ssa * pl->ca;
  for (i=0; i<method->num; i++, old++, new++) {
    rx =  old->x - xn;
    ry =  old->y - yn;
    prx =  rx * cn + ry * sn;
    pry = -rx * sn + ry * cn;
    if (pry < 10.0)
      pry = 10.0;
    prz = old->z + dc->pos.z;
    new->x = 500 + prx / pry * 450;
    new->y = 260 - prz / pry * 450;
  }
}

/*
 * this routine is for points which do not change their bearing,
 * but have moving parts which rotate around the center of the
 * object.
 */
void calcpointsIII(dc, method, index, g, pl)
     DCp dc;
     Methodp method;
     int index;
     Genericp g, pl;
{
  int i;
  float temp, dx, dy, xn, yn, cn, sn, prx, pry, prz, rx, ry;
  Coord2dp new;
  Coord3dp old;

  old = dc->s->object+index;
  new = dc->points+index;
  temp = dc->cta;
  dc->cta = dc->cta * method->vars[0] - dc->sta * method->vars[1];
  dc->sta = dc->sta * method->vars[0] + temp * method->vars[1];
  dx = pl->x - dc->pos.x;
  dy = pl->y - dc->pos.y;
  xn =  dx * dc->cta + dy * dc->sta;
  yn = -dx * dc->sta + dy * dc->cta;
  cn = pl->ca * dc->cta + pl->sa * dc->sta;
  sn = pl->sa * dc->cta - pl->ca * dc->sta;
  for (i=0; i<method->num; i++, old++, new++) {
    rx =  old->x - xn;
    ry =  old->y - yn;
    prx =  rx * cn + ry * sn;
    pry = -rx * sn + ry * cn;
    if (pry < 10.0)
      pry = 10.0;
    prz = old->z + dc->pos.z;
    new->x = 500 + prx / pry * 450;
    new->y = 260 - prz / pry * 450;
  }
}

/*
 * this routine is for points which do change their bearing,
 * and have moving parts which do not rotate around the center of the
 * object.  an example is the offset radar dish of the normal tanks.
 */
void calcpointsIV(dc, method, index, g, pl)
     DCp dc;
     Methodp method;
     int index;
     Genericp g, pl;
{
  int i;
  float temp, dx, dy, xn, yn, cn, sn, prx, pry, prz, rx, ry, csa, ssa;
  Coord2dp new;
  Coord3dp old;
  Float2d pivot;

  old = dc->s->object+index;
  new = dc->points+index;
  temp = dc->cta;
  dc->cta = dc->cta * method->vars[0] - dc->sta * method->vars[1];
  dc->sta = dc->sta * method->vars[0] + temp * method->vars[1];
  csa = cos(g->azm);
  ssa = sin(g->azm);
  dx = pl->x - dc->pos.x;
  dy = pl->y - dc->pos.y;
  xn =  dx * csa + dy * ssa;
  yn = -dx * ssa + dy * csa;
  cn = pl->ca * csa + pl->sa * ssa;
  sn = pl->sa * csa - ssa * pl->ca;
  pivot.x = method->vars[2] - xn;
  pivot.y = method->vars[3] - yn;
  for (i=0; i<method->num; i++, old++, new++) {
    rx = old->x * dc->cta - old->y * dc->sta + pivot.x;
    ry = old->x * dc->sta + old->y * dc->cta + pivot.y;
    prx =  rx * cn + ry * sn;
    pry = -rx * sn + ry * cn;
    if (pry < 10.0)
      pry = 10.0;
    prz = old->z + dc->pos.z;
    new->x = 500 + prx / pry * 450;
    new->y = 260 - prz / pry * 450;
  }
}

/*
 * draw plines and mlines
 *
 */
void displayobject(dc)
     DCp dc;
{
  Coord2dp point;
  int *i;

  point=dc->points;
  for (i=dc->s->pnum; *i; i++) {
    polyline(point, *i);
    point += *i;
  }
  for (i=dc->s->mnum; *i; i++) {
    multiline(point, *i>>1);
    point += *i;
  }
}

void drawobject(g, pl)
     Genericp g, pl;
{
  static Coord3d cube[] = {
    -40,  40, -40,   -40,  40,  40,    40,  40,  40,    40,  40, -40,
    -40,  40, -40,   -40, -40, -40,    40, -40, -40,    40, -40,  40,
    -40, -40,  40,   -40, -40, -40,   -40, -40,  40,   -40,  40,  40,
     40, -40,  40,    40,  40,  40,    40, -40, -40,    40,  40, -40};
  static int cubepnum[] = {10, 0};
  static int cubemnum[] = {6, 0};
  static Method cubemethods[] = {16, calcpointsI, NULL,
                                   0, NULL, NULL};

  static Coord3d pyramid[] = {
    -40,  40, -40,    40,  40, -40,     40, -40, -40,     40,  40, -40,
      0,   0,  40,   -40,  40, -40,    -40, -40, -40,      0,   0,  40,
     40, -40, -40,   -40, -40, -40};
  static int pyramidpnum[] = {10, 0};
  static int pyramidmnum[] = {0};
  static Method pyramidmethods[] = {10, calcpointsI, NULL,
                                      0, NULL, NULL};

  static Coord3d salvo[] = {
      0, -10,  -8,     8, -10,   0,      0, -10,   8,      8, -10,   0,
      0,  10,   0,     0, -10,   8,     -8, -10,   0,      0,  10,   0,
      0, -10,  -8,    -8, -10,   0};
  static int salvopnum[] = {10, 0};
  static int salvomnum[] = {0};
  static Method salvomethods[] = {10, calcpointsII, NULL,
                                    0, NULL, NULL};

  static Coord3d lander[] = {
      0,   0,  20,     80,   0, -20,     40,   0, -40,    -40,   0, -40,
    -80,   0, -20,      0,   0,  20,      0,  80, -20,      0,  40, -40,
      0, -40, -40,      0, -80, -20,      0,   0,  20,    -57, -57, -20,
    -28, -28, -40,     28,  28, -40,     57,  57, -20,      0,   0,  20,
     57, -57, -20,     28, -28, -40,    -28,  28, -40,    -57,  57, -20,
      0,   0,  20};
  static int landerpnum[] = {21, 0};
  static int landermnum[] = {0};
  static float landervars[] =  {0.996195, 0.087156};
  static Method landermethods[] = {21, calcpointsIII, landervars,
                                    0, NULL, NULL};

  static Coord3d missile[] = {
     15, -30, -25,     25, -30,   0,      0, -45,   0,     15, -30, -25,
    -15, -30, -25,      0, -45,   0,     15, -30,  25,    -15, -30,  25,
      0, -45,   0,    -25, -30,   0,    -15, -30,  25,     15, -30, -25,
      0,  50,   0,     25, -30,   0,     15, -30,  25,      0,  50,   0,
    -15, -30, -25,    -25, -30,   0,      0,  50,   0,    -15, -30,  25,
     13, -17, -21,     15, -30, -25,     23, -38, -40,     23,   0, -40,
     13, -17, -21,    -13, -17, -21,    -15, -30, -25,    -23, -38, -40,
    -23,   0, -40,    -13, -17, -21};
  static int missilepnum[] = {11, 9, 5, 5, 0};
  static int missilemnum[] = {0};
  static Method missilemethods[] = {30, calcpointsII, NULL,
                                    0, NULL, NULL};

  static Coord3d copter[] = {
       6,  100,   30,     -6, -100,   30,      6, -100,   30,
      -6,  100,   30,      6,  100,   30,      0, -114,  -10,
       7,  -30,  -34,     10,  -34,  -14,      0, -116,    0,
       0, -134,   28,      0, -144,   28,      0, -130,  -10,
       0, -114,  -10,     -7,  -30,  -34,    -10,  -34,  -14,
       0, -116,    0,    -14,   34,  -34,     14,   34,  -34,
       0,   60,  -14,    -14,   34,  -34,     -7,  -30,  -34,
       7,  -30,  -34,     14,   34,  -34,     26,   34,  -14,
       0,   60,  -14,    -26,   34,  -14,    -10,  -34,  -14,
      10,  -34,  -14,     26,   34,  -14,      4,   20,   16,
       0,   22,   16,     -4,   20,   16,     -4,  -22,   16,
       4,  -22,   16,      4,   20,   16,      0,    0,   16,
       0,    0,   36,    -14,  -30,  -40,    -14,   40,  -40,
     -14,   40,  -40,    -14,   44,  -36,     14,  -30,  -40,
      14,   40,  -40,     14,   40,  -40,     14,   44,  -36,
     -10,  -34,  -14,     -4,  -22,   16,     10,  -34,  -14,
       4,  -22,   16,      0,   22,   16,      0,   60,  -14,
     -14,   34,  -34,    -26,   34,  -14,    -26,   34,  -14,
      -4,   20,   16};
  static int copterpnum[] = {5, 11, 19, 0};
  static int coptermnum[] = {10, 10, 0};
  static float coptervars[] = {0.819152, 0.573576};
  static Method coptermethods[] = {5, calcpointsIII, coptervars,
                                     50, calcpointsII, NULL,
                                     0, NULL, NULL};

  static Coord3d super[] = {
      3,  55,  -6,     3,  55,   0,    -3,  55,   0,    -3,  55,  -6,
      3,  55,  -6,     0,  35, -33,    13, -60,  -6,    11, -60,   4,
     11, -25,   4,     0,  35, -33,   -13, -60,  -6,   -11, -60,   4,
    -11, -25,   4,     0,  35, -33,    15,  60, -40,    30, -60, -40,
     30, -60,  -6,    15,  60, -40,   -15,  60, -40,   -30, -60, -40,
    -30, -60,  -6,   -15,  60, -40,    22, -52,  -8,    22, -52,  28,
      3, -17,   0,     3,  55,   0,    -3, -17,   0,    -3,  55,   0,
      3,  -8,  -6,     3,  55,  -6,    -3,  -8,  -6,    -3,  55,  -6,
     11, -60,   4,   -11, -60,   4,    11, -25,   4,   -11, -25,   4,
    -30, -60,  -6,    30, -60,  -6,   -30, -60, -40,    30, -60, -40};
  static int superpnum[] = {5, 9, 8, 0};
  static int supermnum[] = {2, 8, 4, 4, 0};
  static Method supermethods[] = {40, calcpointsII, NULL,
                                    0, NULL, NULL};

  static Coord3d tank[] = {
      3,   0,  13,     5,   3,  15,     5,   3,  19,     3,   0,  21,
     -3,   0,  21,    -5,   3,  19,    -5,   3,  15,    -3,   0,  13,
      3,   0,  13,    -3,  60,  -3,     3,  60,  -3,     3,  60,   3,
     -3,  60,   3,    -3,  60,  -3,   -10, -45,  10,   -10, -13,  10,
     10, -13,  10,    10, -45,  10,    25, -50, -11,    25,  60, -20,
     10, -13,  10,   -10, -13,  10,   -25,  60, -20,   -25, -50, -11,
    -10, -45,  10,    10, -45,  10,    30, -53, -40,    35, -60, -10,
     35,  60, -20,    30,  37, -40,   -30,  37, -40,   -35,  60, -20,
    -35, -60, -10,   -30, -53, -40,    30, -53, -40,    30,  37, -40,
      5, -40,  10,     5, -40,  13,     3,   4,   3,     3,  60,   3,
     -3,   4,   3,    -3,  60,   3,    -3,  19,  -3,    -3,  60,  -3,
      3,  19,  -3,     3,  60,  -3,    35, -60, -10,   -35, -60, -10,
     35,  60, -20,   -35,  60, -20,   -30, -53, -40,   -30, 37, -40};
  static int tankpnum[] = {9, 5, 12, 10, 0};
  static int tankmnum[] = {2, 8, 6, 0};
  static float tankvars[] = {0.996195, 0.087156, 5, -40};
  static Method tankmethods[] = {9, calcpointsIV, tankvars,
                                   43, calcpointsII, NULL,
                                   0, NULL, NULL};

  static StaticDC staticdcs[] = {
    pyramid, pyramidpnum, pyramidmnum, pyramidmethods, COLOR_PYRAMID,
    cube, cubepnum, cubemnum, cubemethods, COLOR_CUBE,
    tank, tankpnum, tankmnum, tankmethods, COLOR_TANK,
    super, superpnum, supermnum, supermethods, COLOR_SUPER,
    missile, missilepnum, missilemnum, missilemethods, COLOR_MISSILE,
    copter, copterpnum, coptermnum, coptermethods, COLOR_COPTER,
    lander, landerpnum, landermnum, landermethods, COLOR_LANDER,
    salvo, salvopnum, salvomnum, salvomethods, COLOR_ESALVO };

  int color, i;
  DCp dc;
  Methodp methods;

  dc = &g->dc[0];
  if (dc->last) {
    gprsetdrawvalue(opt->cpi[COLOR_BG]);
    displayobject(dc);
  }
  if (g->attr & ERASE) return;

  if (!(g->attr & HAS_DC)) {
    g->attr |= HAS_DC;
    dc->s = staticdcs+g->lntype;

    switch (g->type) {
    case IS_CUBE:
    case IS_PYRAMID:
    case IS_LANDER:
    case IS_MISSILE:
    case IS_COPTER:
    case IS_SUPER:
    case IS_TANK:
      dc->fades = opt->fading_colors - 1;
      dc->basecolor = dc->s->basecolor;
      break;
    case IS_SALVO:
      dc->fades = False;
      if (g->salvo == pl)
        dc->basecolor = COLOR_PSALVO;
      else
        dc->basecolor = COLOR_ESALVO;
      break;
    }
  }

  if (dc->seen) {
    if (dc->fades) {
      color = g->range/OUT_OF_DRAWING_RANGE * opt->fading_colors;
      if (color >= opt->fading_colors)
        color = opt->fading_colors-1;
    }
    else
      color = 0;
    gprsetdrawvalue(color + opt->cpi[dc->basecolor]);

    dc->pos.x = g->x;
    dc->pos.y = g->y;
    dc->pos.z = g->z;

    methods = dc->s->methods;
    for (i=0; methods->num; methods++) {
      methods->calc(dc, methods, i, g, pl);
      i += methods->num;
    }

    displayobject(dc);
    dc->last = True;
  }
  else
    dc->last = False;
}
