// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "icosphere.h"

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

using namespace Eigen;

//--------------------------------------------------------------------------------
// icosahedron data
//--------------------------------------------------------------------------------
#define X .525731112119133606
#define Z .850650808352039932

static GLfloat vdata[12][3] = {
   {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
   {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
   {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
};

static GLint tindices[20][3] = {
   {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
   {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
   {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
   {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
//--------------------------------------------------------------------------------

IcoSphere::IcoSphere(unsigned int levels)
{
  // init with an icosahedron
  for (int i = 0; i < 12; i++)
    mVertices.push_back(Map<Vector3f>(vdata[i]));
  mIndices.push_back(new std::vector<int>);
  std::vector<int>& indices = *mIndices.back();
  for (int i = 0; i < 20; i++)
  {
    for (int k = 0; k < 3; k++)
      indices.push_back(tindices[i][k]);
  }
  mListIds.push_back(0);

  while(mIndices.size()<levels)
    _subdivide();
}

const std::vector<int>& IcoSphere::indices(int level) const
{
  while (level>=int(mIndices.size()))
    const_cast<IcoSphere*>(this)->_subdivide();
  return *mIndices[level];
}

void IcoSphere::_subdivide(void)
{
  typedef unsigned long long Key;
  std::map<Key,int> edgeMap;
  const std::vector<int>& indices = *mIndices.back();
  mIndices.push_back(new std::vector<int>);
  std::vector<int>& refinedIndices = *mIndices.back();
  int end = indices.size();
  for (int i=0; i<end; i+=3)
  {
    int ids0[3],  // indices of outer vertices
        ids1[3];  // indices of edge vertices
    for (int k=0; k<3; ++k)
    {
      int k1 = (k+1)%3;
      int e0 = indices[i+k];
      int e1 = indices[i+k1];
      ids0[k] = e0;
      if (e1>e0)
        std::swap(e0,e1);
      Key edgeKey = Key(e0) | (Key(e1)<<32);
      std::map<Key,int>::iterator it = edgeMap.find(edgeKey);
      if (it==edgeMap.end())
      {
        ids1[k] = mVertices.size();
        edgeMap[edgeKey] = ids1[k];
        mVertices.push_back( (mVertices[e0]+mVertices[e1]).normalized() );
      }
      else
        ids1[k] = it->second;
    }
    refinedIndices.push_back(ids0[0]); refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[2]);
    refinedIndices.push_back(ids0[1]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[0]);
    refinedIndices.push_back(ids0[2]); refinedIndices.push_back(ids1[2]); refinedIndices.push_back(ids1[1]);
    refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[2]);
  }
  mListIds.push_back(0);
}

void IcoSphere::draw(int level)
{
  while (level>=int(mIndices.size()))
    const_cast<IcoSphere*>(this)->_subdivide();
  if (mListIds[level]==0)
  {
    mListIds[level] = glGenLists(1);
    glNewList(mListIds[level], GL_COMPILE);
      glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
      glNormalPointer(GL_FLOAT, 0, mVertices[0].data());
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_NORMAL_ARRAY);
      glDrawElements(GL_TRIANGLES, mIndices[level]->size(), GL_UNSIGNED_INT, &(mIndices[level]->at(0)));
      glDisableClientState(GL_VERTEX_ARRAY);
      glDisableClientState(GL_NORMAL_ARRAY);
    glEndList();
  }
  glCallList(mListIds[level]);
}


