#ifndef MESH_H
#define MESH_H

struct Normal // define o vetor normal
{
  float x,y,z;
};

struct UV
{
  float u,v;
};

struct Neighbors // define uma lista de triangulos vizinhos de um triangulo
{
  Neighbors(){tri=0;nbr=0;}
  ~Neighbors(){delete [] tri;}

  void addNeighbor(int triangle) // adiciona um vizinho na lista
  {
    for (int i=0;i<nbr;i++) if (tri[i]==triangle) return;
    int *temp=new int[nbr+1];
    for (int i=0;i<nbr;i++) temp[i]=tri[i];
    temp[nbr]=triangle;
    delete [] tri;
    tri=temp;
    nbr++;
  }

  int *tri; // lista de vizinhos
  int  nbr; // tamanho da lista
};


struct Color
{
  float r,g,b;
};

struct Vertex
{
  float x,y,z;
};

struct Triangle
{
  unsigned int vert[3];
};

struct Massa{
       float posicao[3];
       float velocidade[3];
       float massa;
       bool fixa;
};

struct Mola{
       float k; //rigidez da mola
       float comp_nominal; // o quanto a mola se distancia
       int massas[2];
};


class Mesh
{
public:
  Mesh();
  virtual ~Mesh();

  void initVerts(int nbrVerts);
  void initTris(int nbrTris);

  Vertex   *verts;
  int    nbrVerts;
  UV         *uvs;


  Color    *colors;
  Triangle *tris;
  int       nbrTris;
  
  Color matrix[256][256];
  
  void  initNeighbors();
  void  calcNormals();
  float invSqrt (float x);
  void  calcNormal(Vertex& p1,Vertex& p2,Vertex& p3,Normal& n);
  void  normalize(Normal& n);
  void criaPlano(int altura,int largura, float tamanho);
  Neighbors *vertNeigh; // triangles that are adjacent to a vertex
  Normal     *vertNorm;
  Normal      *triNorm;
};

class MassaMola: public Mesh{
   public:
      Massa *vMassa;
      Mola *vMola;
      
      void initMassas(int nbrMassas);
      void initMolas(int nbrMolas);
      
      int    nbrMassas;
      int    nbrMolas;
      
      void criaMassaMola(int n, int m, float offset);
      float calculaForca(int mola);
      void simulaFisica( float deltaT );
};

inline float Mesh::invSqrt (float x) // raiz inversa para normalizacao
{
  float xhalf = 0.5f*x;
  int i  = *(int*)&x;
  i = 0x5f3759df - (i >> 1);  // This line hides a LOT of math!
  x = *(float*)&i;
  x = x*(1.5f - xhalf*x*x);  // repeat this statement for a better approximation
  return x;
}

inline void Mesh::calcNormal(Vertex& p1,Vertex& p2,Vertex& p3,Normal& n) // dados 3 vertices, calcula a normal do triangulo formado por eles
{
  Vertex v1;
  Vertex v2;
  v1.x = p2.x-p1.x;
  v1.y = p2.y-p1.y;
  v1.z = p2.z-p1.z;

  v2.x = p3.x-p2.x;
  v2.y = p3.y-p2.y;
  v2.z = p3.z-p2.z;

  n.x = v1.y*v2.z - v1.z*v2.y;
  n.y = v1.z*v2.x - v1.x*v2.z;
  n.z = v1.x*v2.y - v1.y*v2.x;

  // normalization step
  float l=invSqrt(n.x*n.x+n.y*n.y+n.z*n.z);
  
  // Possibly unnecessary
  if (l==0.0) l=1.0;
  
  n.x*=l;
  n.y*=l;
  n.z*=l;
}

inline void Mesh::normalize(Normal& n) // normaliza qualquer vetor n dado
{
  float length=invSqrt(n.x*n.x+n.y*n.y+n.z*n.z);
  
  // Possibly unnecessary
  if(length == 0.0) length = 1.0;
  
  n.x *= length;
  n.y *= length;
  n.z *= length;
}


#endif
