/*-----------------------------------------------------------------------------

  Building.cpp

  2009 Shamus Young

-------------------------------------------------------------------------------

  This module contains the class to construct the buildings.  

-----------------------------------------------------------------------------*/

#define MAX_VBUFFER         256

#include <math.h>
#include <GL/gl.h>

#include "config.h"

#include "glTypes.h"
#include "Building.h"
#include "Deco.h"
#include "Light.h"
#include "Mesh.h"
#include "Macro.h"
#include "Math.h"
#include "Random.h"
#include "Texture.h"
#include "World.h"

//This is used by the recursive roof builder to decide what items may be added.
enum
{
  ADDON_NONE,
#ifdef HAVE_GLC
  ADDON_LOGO,
#endif
  ADDON_TRIM,
  ADDON_LIGHTS,
  ADDON_COUNT
};

static GLvector         vector_buffer[MAX_VBUFFER];

/*-----------------------------------------------------------------------------

  This is the constructor for our building constructor.

-----------------------------------------------------------------------------*/

CBuilding::CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color)
{

  _x = x;
  _y = y;
  _width = width;
  _depth = depth;
  _height = height;
  _center = glVector ((float)(_x + width / 2), 0.0f, (float)(_y + depth / 2));
  _seed = seed;
  _texture_type = RandomVal ();
  _color = color;
  _color.alpha = 0.1f;
  _have_lights = false;
  _have_logo = false;
  _have_trim = false;
  _roof_tiers = 0;
  //Pick a color for logos & roof lights
  _trim_color = WorldLightColor (seed);
  _mesh = new CMesh; //The main textured mesh for the building
  _mesh_flat = new CMesh; //Flat-color mesh for untextured detail items.
  switch (type) {
  case BUILDING_SIMPLE:
    CreateSimple ();
    break;  
  case BUILDING_MODERN: 
    CreateModern (); 
    break;
  case BUILDING_TOWER: 
    CreateTower (); 
    break;
  case BUILDING_BLOCKY:
    CreateBlocky (); 
    break;
  }

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

CBuilding::~CBuilding ()
{

  if (_mesh)
    delete _mesh;
  if (_mesh_flat)
    delete _mesh_flat;

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

unsigned CBuilding::Texture ()
{

  return TextureRandomBuilding (_texture_type);

}


/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

int CBuilding::PolyCount ()
{

  return _mesh->PolyCount () + _mesh_flat->PolyCount ();

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::Render ()
{ 

  glColor3fv (&_color.red);
  _mesh->Render ();

}


/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::RenderFlat (bool colored)
{ 

  if (colored)
    glColor3fv (&_color.red);
  _mesh_flat->Render ();

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::ConstructCube (int left, int right, int front, int back, int bottom, int top)
{

  GLvertex    p[10];
  float       x1, x2, z1, z2, y1, y2;
  int         i;
  cube        c;
  float       u, v1, v2;
  float       mapping;
  int         base_index;
  int         height;

  height = top - bottom;
  x1 = (float)left;
  x2 = (float)right;
  y1 = (float)bottom;
  y2 = (float)top;
  z1 = (float)front;
  z2 = (float)back;
  base_index = _mesh->VertexCount ();

  mapping = (float)SEGMENTS_PER_TEXTURE;
  u = (float)(RandomVal () % SEGMENTS_PER_TEXTURE) / (float)SEGMENTS_PER_TEXTURE;
  v1 = (float)bottom / (float)mapping;
  v2 = (float)top / (float)mapping;

  p[0].position = glVector (x1, y1, z1);  p[0].uv = glVector (u, v1);
  p[1].position = glVector (x1, y2, z1);  p[1].uv = glVector (u, v2);
  u += (float)_width / mapping;
  p[2].position = glVector (x2, y1, z1);  p[2].uv = glVector (u, v1);
  p[3].position = glVector (x2, y2, z1);  p[3].uv = glVector (u, v2);
  u += (float)_depth / mapping;
  p[4].position = glVector (x2, y1, z2);  p[4].uv = glVector (u, v1);
  p[5].position = glVector (x2, y2, z2);  p[5].uv = glVector (u, v2);
  u += (float)_width / mapping;
  p[6].position = glVector (x1, y1, z2);  p[6].uv = glVector (u, v1);
  p[7].position = glVector (x1, y2, z2);  p[7].uv = glVector (u, v2);
  u += (float)_width / mapping;
  p[8].position = glVector (x1, y1, z1);  p[8].uv = glVector (u, v1);
  p[9].position = glVector (x1, y2, z1);  p[9].uv = glVector (u, v2);
  for (i = 0; i < 10; i++) {
    p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE;
    _mesh->VertexAdd (p[i]);
    c.index_list.push_back(base_index + i);
  }
  _mesh->CubeAdd (c);

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::ConstructCube (float left, float right, float front, float back, float bottom, float top)
{

  GLvertex    p[10];
  float       x1, x2, z1, z2, y1, y2;
  int         i;
  cube        c;
  int         base_index;

  x1 = left;
  x2 = right;
  y1 = bottom;
  y2 = top;
  z1 = front;
  z2 = back;
  base_index = _mesh_flat->VertexCount ();

  p[0].position = glVector (x1, y1, z1);  p[0].uv = glVector (0.0f, 0.0f);
  p[1].position = glVector (x1, y2, z1);  p[1].uv = glVector (0.0f, 0.0f);
  p[2].position = glVector (x2, y1, z1);  p[2].uv = glVector (0.0f, 0.0f);
  p[3].position = glVector (x2, y2, z1);  p[3].uv = glVector (0.0f, 0.0f);
  p[4].position = glVector (x2, y1, z2);  p[4].uv = glVector (0.0f, 0.0f);
  p[5].position = glVector (x2, y2, z2);  p[5].uv = glVector (0.0f, 0.0f);
  p[6].position = glVector (x1, y1, z2);  p[6].uv = glVector (0.0f, 0.0f);
  p[7].position = glVector (x1, y2, z2);  p[7].uv = glVector (0.0f, 0.0f);
  p[8].position = glVector (x1, y1, z1);  p[8].uv = glVector (0.0f, 0.0f);
  p[9].position = glVector (x1, y2, z1);  p[9].uv = glVector (0.0f, 0.0f);
  for (i = 0; i < 10; i++) {
    p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE;
    _mesh_flat->VertexAdd (p[i]);
    c.index_list.push_back(base_index + i);
  }
  _mesh_flat->CubeAdd (c);

}

/*-----------------------------------------------------------------------------

  This will take the given area and populate it with rooftop stuff like
  air conditioners or light towers.

-----------------------------------------------------------------------------*/

void CBuilding::ConstructRoof (float left, float right, float front, float back, float bottom)
{

  int       air_conditioners;
  int       i;
  int       width, depth, height;
  int       addon;
  int       max_tiers;
  float     ac_x;
  float     ac_y;
  float     ac_base;
  float     ac_size;
  float     ac_height;
  float     tower_height;
  float     logo_offset;
  CDeco*    d;
#ifdef HAVE_GLC
  int       face;
  GLvector2 start, end;
#endif

  _roof_tiers++;
  max_tiers = _height / 10;
  width = (int)(right - left);
  depth = (int)(back - front);
  height = 5 - _roof_tiers;
  logo_offset = 0.2f;
  //See if this building is special and worthy of fancy roof decorations.
  if (bottom > 35.0f)
    addon = RandomVal (ADDON_COUNT);
  //Build the roof slab
  ConstructCube (left, right, front, back, bottom, bottom + (float)height);
  //Consider putting a logo on the roof, if it's tall enough
#ifdef HAVE_GLC
  if (addon == ADDON_LOGO && !_have_logo) {
    d = new CDeco;
    if (width > depth)
      face = COIN_FLIP ? NORTH : SOUTH;
    else
      face = COIN_FLIP ? EAST : WEST;
    switch (face) {
    case NORTH:
      start = glVector ((float)left, (float)back + logo_offset);
      end = glVector ((float)right, (float)back + logo_offset);
      break;
    case SOUTH:
      start = glVector ((float)right, (float)front - logo_offset);
      end = glVector ((float)left, (float)front - logo_offset);
      break;
    case EAST:
      start = glVector ((float)right + logo_offset, (float)back);
      end = glVector ((float)right + logo_offset, (float)front);
      break;
    case WEST:
    default:
      start = glVector ((float)left - logo_offset, (float)front);
      end = glVector ((float)left - logo_offset, (float)back);
      break;
    }
    d->CreateLogo (start, end, bottom, WorldLogoIndex (), _trim_color);
    _have_logo = true;
  } else 
#endif
  if (addon == ADDON_TRIM) {
    d = new CDeco;
    vector_buffer[0] = glVector (left, bottom, back);
    vector_buffer[1] = glVector (left, bottom, front);
    vector_buffer[2] = glVector (right, bottom, front);
    vector_buffer[3] = glVector (right, bottom, back);
    d->CreateLightTrim (vector_buffer, 4, (float)RandomVal (2) + 1.0f, _seed, _trim_color);
  } else if (addon == ADDON_LIGHTS && !_have_lights) {
    new CLight (glVector (left, (float)(bottom + 2), front), _trim_color, 2);
    new CLight (glVector (right, (float)(bottom + 2), front), _trim_color, 2);
    new CLight (glVector (right, (float)(bottom + 2), back), _trim_color, 2);
    new CLight (glVector (left, (float)(bottom + 2), back), _trim_color, 2);
    _have_lights = true;
  }
  bottom += (float)height;
  //If the roof is big enough, consider making another layer 
  if (width > 7 && depth > 7 && _roof_tiers < max_tiers) {
    ConstructRoof (left + 1, right - 1, front + 1, back - 1, bottom);
    return;
  }
  //1 air conditioner block for every 15 floors sounds reasonble
  air_conditioners = _height / 15;
  for (i = 0; i < air_conditioners; i++) {
    ac_size = (float)(10 + RandomVal (30)) / 10;
    ac_height = (float)RandomVal (20) / 10 + 1.0f;
    ac_x = left + (float)RandomVal (width);
    ac_y = front + (float)RandomVal (depth);
    //make sure the unit doesn't hang off the right edge of the building
    if (ac_x + ac_size > (float)right)
      ac_x = (float)right - ac_size;
    //make sure the unit doesn't hang off the back edge of the building
    if (ac_y + ac_size > (float)back)
      ac_y = (float)back - ac_size;
    ac_base = (float)bottom;
    //make sure it doesn't hang off the edge
    ConstructCube (ac_x, ac_x + ac_size, ac_y, ac_y + ac_size, ac_base, ac_base + ac_height);
  }

  if (_height > 45) {
    d = new CDeco;
    tower_height = (float)(12 + RandomVal (8));
    d->CreateRadioTower (glVector ((float)(left + right) / 2.0f, (float)bottom, (float)(front + back) / 2.0f), 15.0f);
  }
  

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::ConstructSpike (int left, int right, int front, int back, int bottom, int top)
{

  GLvertex    p;
  fan         f;
  int         i;
  GLvector    center;

  for (i = 0; i < 5; i++)
    f.index_list.push_back(_mesh_flat->VertexCount () + i);
  f.index_list.push_back(f.index_list[1]);
  p.uv = glVector (0.0f, 0.0f);
  center.x = ((float)left + (float)right) / 2.0f;
  center.z = ((float)front + (float)back) / 2.0f;
  p.position = glVector (center.x, (float)top, center.z);
  _mesh_flat->VertexAdd (p);
 
  p.position = glVector ((float)left, (float)bottom, (float)back);
  _mesh_flat->VertexAdd (p);

  p.position = glVector ((float)right, (float)bottom, (float)back);
  _mesh_flat->VertexAdd (p);

  p.position = glVector ((float)right, (float)bottom, (float)front);
  _mesh_flat->VertexAdd (p);
  
  p.position = glVector ((float)left, (float)bottom, (float)front);
  _mesh_flat->VertexAdd (p);
  
  _mesh_flat->FanAdd (f);

}

/*-----------------------------------------------------------------------------

  This builds an outer wall of a building, with blank (windowless) areas
  deliberately left.  It creates a chain of segments that alternate
  between windowed and windowless, and it always makes sure the wall
  is symetrical.  window_groups tells it how many windows to place in a row.

-----------------------------------------------------------------------------*/

float CBuilding::ConstructWall (int start_x, int start_y, int start_z, int direction, int length, int height, int window_groups, float uv_start, bool blank_corners)
{

  int         x, z;
  int         step_x, step_z;
  int         i;
  quad_strip  qs;
  int         column;
  int         mid;
  int         odd;
  GLvertex    v;
  bool        blank;
  bool        last_blank;

  qs.index_list.reserve(100);

  switch (direction) {
  case NORTH:
    step_z = 1; step_x = 0; break;
  case WEST:
    step_z = 0; step_x = -1; break;
  case SOUTH:
    step_z = -1; step_x = 0; break;
  case EAST:
    step_z = 0; step_x = 1; break;
  }
  x = start_x;;
  z = start_z;
  mid = (length / 2) - 1;
  odd = 1 - (length % 2);
  if (length % 2) 
    mid++;
  //mid = (length / 2);
  v.uv.x = (float)(x + z) / SEGMENTS_PER_TEXTURE;
  v.uv.x = uv_start;
  blank = false;
  for (i = 0; i <= length; i++) {
    //column counts up to the mid point, then back down, to make it symetrical
    if (i <= mid)
      column = i - odd;
    else 
      column = (mid) - (i - (mid));
    last_blank = blank;
    blank = (column % window_groups) > window_groups / 2;
    if (blank_corners && i == 0)
      blank = true;
    if (blank_corners && i == (length - 1))
      blank = true;
    if (last_blank != blank || i == 0 || i == length) {
      v.position = glVector ((float)x, (float)start_y, (float)z);
      v.uv.y = (float)start_y / SEGMENTS_PER_TEXTURE;
      _mesh->VertexAdd (v);
      qs.index_list.push_back(_mesh->VertexCount () - 1);
      v.position.y = (float)(start_y + height);
      v.uv.y = (float)(start_y + height) / SEGMENTS_PER_TEXTURE;;
      _mesh->VertexAdd (v);
      qs.index_list.push_back(_mesh->VertexCount () - 1);
    }
    //if (!blank && i != 0 && i != (length - 1))
    if (!blank && i != length)
      v.uv.x += 1.0f / SEGMENTS_PER_TEXTURE;
    x += step_x;
    z += step_z;
  }
  _mesh->QuadStripAdd (qs);  
  return v.uv.x;

}

/*-----------------------------------------------------------------------------

  This makes a big chunky building of intersecting cubes.  

-----------------------------------------------------------------------------*/

void CBuilding::CreateBlocky ()
{

  int         min_height;
  int         left, right, front, back;
  int         max_left, max_right, max_front, max_back;
  int         height;
  int         mid_x, mid_z;
  int         half_depth, half_width;
  int         tiers;
  int         max_tiers;
  int         grouping;
  float       lid_height;
  float       uv_start;
  bool        skip;
  bool        blank_corners;

  //Choose if the corners of the building are to be windowless.
  blank_corners = COIN_FLIP;
  //Choose a random column on our texture;
  uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE;
  //Choose how the windows are grouped
  grouping = 2 + RandomVal (4);
  //Choose how tall the lid should be on top of each section
  lid_height = (float)(RandomVal (3) + 1);
  //find the center of the building.
  mid_x = _x + _width / 2;
  mid_z = _y + _depth / 2;
  max_left = max_right = max_front = max_back = 1;
  height = _height;
  min_height = _height / 2;
  min_height = 3;
  half_depth = _depth / 2;
  half_width = _width / 2;
  tiers = 0;
  if (_height > 40)
    max_tiers = 15;
  else if (_height > 30)
    max_tiers = 10;
  else if (_height > 20)
    max_tiers = 5;
  else if (_height > 10)
    max_tiers = 2;
  else
    max_tiers = 1;
  //We begin at the top of the building, and work our way down.
  //Viewed from above, the sections of the building are randomly sized
  //rectangles that ALWAYS include the center of the building somewhere within 
  //their area.  
  while (1) {
    if (height < min_height)
      break;
    if (tiers >= max_tiers)
      break;
    //pick new locationsfor our four outer walls
    left = (RandomVal () % half_width) + 1;
    right = (RandomVal () % half_width) + 1;
    front = (RandomVal () % half_depth) + 1;
    back = (RandomVal () % half_depth) + 1;
    skip = false;
    //At least ONE of the walls must reach out beyond a previous maximum.
    //Otherwise, this tier would be completely hidden within a previous one.
    if (left <= max_left && right <= max_right && front <= max_front && back <= max_back) 
      skip = true;
    //If any of the four walls is in the same position as the previous max,then
    //skip this tier, or else the two walls will end up z-fightng.
    if (left == max_left || right == max_right || front == max_front || back == max_back) 
      skip = true;
    if (!skip) {
      //if this is the top, then put some lights up here
      max_left = MAX (left, max_left);
      max_right = MAX (right, max_right);
      max_front = MAX (front, max_front);
      max_back = MAX (back, max_back);
      //Now build the four walls of this part
      uv_start = ConstructWall (mid_x - left, 0, mid_z + back, SOUTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
      uv_start = ConstructWall (mid_x - left, 0, mid_z - front, EAST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
      uv_start = ConstructWall (mid_x + right, 0, mid_z - front, NORTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
      uv_start = ConstructWall (mid_x + right, 0, mid_z + back, WEST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
      if (!tiers)
        ConstructRoof ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height);
      else //add a flat-color lid onto this section
        ConstructCube ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height, (float)height + lid_height);
      height -= (RandomVal () % 10) + 1;
      tiers++;
    }
    height--;
  }
  ConstructCube (mid_x - half_width, mid_x + half_width, mid_z - half_depth, mid_z + half_depth, 0, 2);
  _mesh->Compile ();
  _mesh_flat->Compile ();

}

/*-----------------------------------------------------------------------------

  A single-cube building.  Good for low-rise buildings and stuff that will be 
  far from the camera;

-----------------------------------------------------------------------------*/

void CBuilding::CreateSimple ()
{

  GLvertex    p;
  float       x1, x2, z1, z2, y1, y2;
  quad_strip  qs;
  float       u, v1, v2;
  float       cap_height;
  float       ledge;

  for(int i=0; i<=10; i++)
    qs.index_list.push_back(i);

  //How tall the flat-color roof is
  cap_height = (float)(1 + RandomVal (4));
  //how much the ledge sticks out
  ledge = (float)RandomVal (10) / 30.0f;

  x1 = (float)_x;
  x2 = (float)(_x + _width);
  y1 = (float)0.0f;
  y2 = (float)_height;
  z2 = (float)_y;
  z1 = (float)(_y + _depth);

  u = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE;
  v1 = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE;
  v2 = v1 + (float)_height * ONE_SEGMENT;

  p.position = glVector (x1, y1, z1);  p.uv = glVector (u, v1);
  _mesh->VertexAdd (p);
  p.position = glVector (x1, y2, z1);  p.uv = glVector (u, v2);
  _mesh->VertexAdd (p);
  u += (float)_depth / SEGMENTS_PER_TEXTURE;

  p.position = glVector (x1, y1, z2);  p.uv = glVector (u, v1);
  _mesh->VertexAdd (p);
  p.position = glVector (x1, y2, z2);  p.uv = glVector (u, v2);
  _mesh->VertexAdd (p);
  u += (float)_width / SEGMENTS_PER_TEXTURE;
  
  p.position = glVector (x2, y1, z2);  p.uv = glVector (u, v1);
  _mesh->VertexAdd (p);
  p.position = glVector (x2, y2, z2);  p.uv = glVector (u, v2);
  _mesh->VertexAdd (p);
  u += (float)_depth / SEGMENTS_PER_TEXTURE;

  p.position = glVector (x2, y1, z1);  p.uv = glVector (u, v1);
  _mesh->VertexAdd (p);
  p.position = glVector (x2, y2, z1);  p.uv = glVector (u, v2);
  _mesh->VertexAdd (p);
  u += (float)_depth / SEGMENTS_PER_TEXTURE;

  p.position = glVector (x1, y1, z1);  p.uv = glVector (u, v1);
  _mesh->VertexAdd (p);
  p.position = glVector (x1, y2, z1);  p.uv = glVector (u, v2);
  _mesh->VertexAdd (p);

  _mesh->QuadStripAdd (qs);
  ConstructCube (x1 - ledge, x2 + ledge, z2 - ledge, z1 + ledge, (float)_height, (float)_height + cap_height);
  _mesh->Compile ();

}


/*-----------------------------------------------------------------------------

  This makes a deformed cylinder building.  

-----------------------------------------------------------------------------*/

void CBuilding::CreateModern ()
{

  GLvertex    p;
  GLvector    center;
  GLvector    pos;
  GLvector2   radius;
  GLvector2   start, end;
  int         angle;
  int         windows;
  int         cap_height;
  int         half_depth, half_width;
  float       dist;
  float       length;
  quad_strip  qs;
  fan         f;
  int         points;
  int         skip_interval;
  int         skip_counter;
  int         skip_delta;
  int         i;
  bool        logo_done;
  bool        do_trim;
  CDeco*      d;

  logo_done = false;
  //How tall the windowless section on top will be.
  cap_height = 1 + RandomVal (5);
  //How many 10-degree segments to build before the next skip.
  skip_interval = 1 + RandomVal (8);
  //When a skip happens, how many degrees should be skipped
  skip_delta = (1 + RandomVal (2)) * 30; //30 60 or 90
  //See if this is eligible for fancy lighting trim on top
  if (_height > 48 && RandomVal (3) == 0)
    do_trim = true;
  else
    do_trim = false;
  //Get the center and radius of the circle
  half_depth = _depth / 2;
  half_width = _width / 2;
  center = glVector ((float)(_x + half_width), 0.0f, (float)(_y + half_depth));
  radius = glVector ((float)half_width, (float)half_depth);
  dist = 0;
  windows = 0;
  p.uv.x = 0.0f;
  points = 0;
  skip_counter = 0;
  for (angle = 0; angle <= 360; angle += 10) {
    if (skip_counter >= skip_interval && (angle + skip_delta < 360)) {
      angle += skip_delta;
      skip_counter = 0;
    }
    pos.x = center.x - sinf ((float)angle * DEGREES_TO_RADIANS) * radius.x;
    pos.z = center.z + cosf ((float)angle * DEGREES_TO_RADIANS) * radius.y;
    if (angle > 0 && skip_counter == 0) {
      length = MathDistance (p.position.x, p.position.z, pos.x, pos.z);
      windows += (int)length;
      if (length > 10 && !logo_done) {
        logo_done = true;
        start = glVector (pos.x, pos.z);
        end = glVector (p.position.x, p.position.z);
#ifdef HAVE_GLC
        d = new CDeco;
        d->CreateLogo (start, end, (float)_height, WorldLogoIndex (), RANDOM_COLOR);
#endif
      }
    } else if (skip_counter != 1)
      windows++;
    p.position = pos;
    p.uv.x = (float)windows / (float)SEGMENTS_PER_TEXTURE;
    p.uv.y = 0.0f;
    p.position.y = 0.0f;
    _mesh->VertexAdd (p);
    p.position.y = (float)_height;
    p.uv.y = (float)_height / (float)SEGMENTS_PER_TEXTURE;
    _mesh->VertexAdd (p);
    _mesh_flat->VertexAdd (p);
    p.position.y += (float)cap_height;
    _mesh_flat->VertexAdd (p);
    vector_buffer[points / 2] = p.position;
    vector_buffer[points / 2].y = (float)_height + cap_height / 4;
    points += 2;
    skip_counter++;
  }
  //if this is a big building and it didn't get a logo, consider giving it a light strip
  if (!logo_done && do_trim) {
    d = new CDeco;
    d->CreateLightTrim (vector_buffer, (points / 2) - 2, (float)cap_height / 2, _seed, RANDOM_COLOR);
  }
  qs.index_list.reserve(points);   
  //Add the outer walls
  for (i = 0; i < points; i++)
    qs.index_list.push_back(i);
  _mesh->QuadStripAdd (qs);
  _mesh_flat->QuadStripAdd (qs);
  //add the fan to cap the top of the buildings
  f.index_list.push_back(points);
  for (i = 0; i < points / 2; i++)
    f.index_list.push_back(points - (1 + i * 2));
  p.position.x = _center.x;
  p.position.z = _center.z;
  _mesh_flat->VertexAdd (p);
  _mesh_flat->FanAdd (f);
  radius /= 2.0f;
  //ConstructRoof ((int)(_center.x - radius), (int)(_center.x + radius), (int)(_center.z - radius), (int)(_center.z + radius), _height + cap_height);
  _mesh->Compile ();
  _mesh_flat->Compile ();

}

/*-----------------------------------------------------------------------------

-----------------------------------------------------------------------------*/

void CBuilding::CreateTower ()
{

  int         left, right, front, back, bottom;
  int         section_height, section_width, section_depth;
  int         remaining_height;
  int         ledge_height;
  int         tier_fraction;
  int         grouping;
  int         foundation;
  int         narrowing_interval;
  int         tiers;
  float       ledge;
  float       uv_start;
  bool        blank_corners;
  bool        roof_spike;
  bool        tower;

  //How much ledges protrude from the building
  ledge = (float)RandomVal (3) * 0.25f;
  //How tall the ledges are, in stories
  ledge_height = RandomVal (4) + 1;
  //How the windows are grouped
  grouping = RandomVal (3) + 2;
  //if the corners of the building have no windows
  blank_corners = RandomVal (4) > 0;
  //if the roof is pointed or has infrastructure on it
  roof_spike = RandomVal (3) == 0;
  //What fraction of the remaining height should be given to each tier
  tier_fraction = 2 + RandomVal (4);
  //How often (in tiers) does the building get narrorwer?
  narrowing_interval = 1 + RandomVal (10);
  //The height of the windowsless slab at the bottom
  foundation = 2 + RandomVal (3);
  //The odds that we'll have a big fancy spikey top
  tower = RandomVal (5) != 0 && _height > 40;
  //set our initial parameters
  left = _x; 
  right = _x + _width;
  front = _y;
  back = _y + _depth;
  bottom = 0;
  tiers = 0;
  //build the foundations.
  ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)foundation);
  bottom += foundation;
  //now add tiers until we reach the top
  while (1) {
    remaining_height = _height - bottom;
    section_depth = back - front;
    section_width = right - left;
    section_height = MAX (remaining_height / tier_fraction, 2);
    if (remaining_height < 10)
      section_height = remaining_height;
    //Build the four walls
    uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE;
    uv_start = ConstructWall (left, bottom, back, SOUTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
    uv_start = ConstructWall (left, bottom, front, EAST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
    uv_start = ConstructWall (right, bottom, front, NORTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
    uv_start = ConstructWall (right, bottom, back, WEST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
    bottom += section_height;
    //Build the slab / ledges to cap this section.
    if (bottom + ledge_height > _height)
      break;
    ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)(bottom + ledge_height));
    bottom += ledge_height;
    if (bottom > _height)
      break;
    tiers++;
    if ((tiers % narrowing_interval) == 0) {
      if (section_width > 7) {
        left+=1;
        right-=1;
      }
      if (section_depth > 7) {
        front+=1;
        back-=1;
      }
    }
  }
  ConstructRoof ((float)left, (float)right, (float)front, (float)back, (float)bottom);
  _mesh->Compile ();
  _mesh_flat->Compile ();

}

