//MeshObject.cpp

//Created/Programmed by Jonathan DeKlotz
// 5/10/04 minor changes ZJW


#include "MeshObject.h"

using namespace std;

inline void MeshObject_MakeAABB(float v0[3], float v1[3], float v2[3], float v3[3], float v4[3],
                                float v5[3], float v6[3], float v7[3], float min[3], float max[3])
{
  v0[0] = min[0]; v1[0] = min[0]; v2[0] = max[0]; v3[0] = max[0];
  v0[1] = min[1]; v1[1] = min[1]; v2[1] = min[1]; v3[1] = min[1];
  v0[2] = min[2]; v1[2] = max[2]; v2[2] = max[2]; v3[2] = min[2];
  v4[0] = min[0]; v5[0] = min[0]; v6[0] = max[0]; v7[0] = max[0];
  v4[1] = max[1]; v5[1] = max[1]; v6[1] = max[1]; v7[1] = max[1];
  v4[2] = min[2]; v5[2] = max[2]; v6[2] = max[2]; v7[2] = min[2];
}

MeshObject::MeshObject()
{
  mesh = 0;
}

MeshObject::MeshObject(std::string meshFileName)
{
  mesh = 0;
  LoadMeshFromFile(meshFileName);
}

MeshObject::~MeshObject()
{
  mesh ? delete mesh : 0;
}

void MeshObject::LoadMeshFromFile(std::string meshFileName)
{
  mesh ? delete mesh : 0;
  mesh = new MeshStructure;
  
  std::ifstream meshStream(meshFileName.c_str());
  
  if (!meshStream)
  {
    std::cout << "Error opening file" << meshFileName;
    meshStream.close();
    return;
  }
  
  LoadMeshFromStream(meshStream);
  meshStream.close();
}

void MeshObject::LoadMeshFromStream(std::istream &meshStream)
{
  char str[256];
  while (meshStream) {
    meshStream >> std::ws;
    meshStream.get(str,sizeof(str));
    if (!meshStream) break;
    meshStream.ignore(9999,'\n');
    readLine(str);
  }
  mesh->CenterMesh();
  mesh->NormalizeMeshScale(12.0f);
  mesh->ComputeVertexNormals();
  mesh->GetAABB(minVtx, maxVtx);
  MeshObject_MakeAABB(AABB_v0, AABB_v1, AABB_v2, AABB_v3, 
    AABB_v4, AABB_v5, AABB_v6, AABB_v7, minVtx, maxVtx);
}

void MeshObject::GLDraw()
{
  if (!mesh)
    return;
  
  std::list<MeshStructure::Triangle *>::iterator triIter = mesh->TriangleIterBegin();
  std::list<MeshStructure::Triangle *>::iterator triIterEnd = mesh->TriangleIterEnd();
  MeshStructure::Triangle *tri = 0;
  float v0[3], v1[3], v2[3], n0[3];
  
  //ZJW draw as solid
  if(draw_mode == 0 ) {
    glBegin(GL_TRIANGLES);
    for (;triIter != triIterEnd; ++triIter)
    {
      //cout << "drawing a tri " << endl;
      tri = *triIter;
      
      //get the normal and vertices
      tri->GetNormal(n0[0], n0[1], n0[2]);
      tri->GetVertex(0)->GetVertexLocation(v0);
      tri->GetVertex(1)->GetVertexLocation(v1);
      tri->GetVertex(2)->GetVertexLocation(v2);
      
      //pass to opengl
      glNormal3fv(n0);
      glVertex3fv(v0);
      glVertex3fv(v1);
      glVertex3fv(v2);
    }
    glEnd();
  } else {
    //ZJW: just draw edges
    for (;triIter != triIterEnd; ++triIter)
    {
      tri = *triIter;
  
      //get the normal and vertices
      tri->GetVertex(0)->GetVertexLocation(v0);
      tri->GetVertex(1)->GetVertexLocation(v1);
      tri->GetVertex(2)->GetVertexLocation(v2);
      glBegin(GL_LINE_LOOP);      
        //pass to opengl
       glVertex3fv(v0);
       glVertex3fv(v1);
       glVertex3fv(v2);
      glEnd();
    }
  }
  
}


void MeshObject::GLDrawAABB()
{
  if (!mesh)
    return;
  
  glShadeModel(GL_FLAT);
  glDisable(GL_LIGHTING);
  glColor3f(0.15f, 0.15f, 0.9f);
  glBegin(GL_LINE_LOOP);
		glVertex3fv(AABB_v0);
    glVertex3fv(AABB_v1);
    glVertex3fv(AABB_v2);
    glVertex3fv(AABB_v3);
    glVertex3fv(AABB_v0);
    glVertex3fv(AABB_v4);
    glVertex3fv(AABB_v5);
    glVertex3fv(AABB_v6);
    glVertex3fv(AABB_v7);
    glVertex3fv(AABB_v4);
    glEnd();
    glBegin(GL_LINES);
    glVertex3fv(AABB_v5);
    glVertex3fv(AABB_v1);
    glVertex3fv(AABB_v6);
    glVertex3fv(AABB_v2);
    glVertex3fv(AABB_v7);
    glVertex3fv(AABB_v3);
    glEnd();
    glEnable(GL_LIGHTING);
}

void MeshObject::SmoothMesh() {
//fill in....
}

float MeshObject::GetBottom()
{
  return minVtx[1];
}

void MeshObject::readLine(char *str)
{
  int indx = 0, vi = 0;
  float x = 0, y = 0, z = 0;
  
  //cout << "str[0] " << str[0] << endl;
  
  if (str[0]=='#')
    return;
  else if (str[0]=='V' && !strncmp(str,"Vertex ",7)) 
  {
    sscanf(str, "Vertex %d %g %g %g", &vi, &x, &y, &z);
    mesh->AddVertex(x, y, z, vi);
  } 
  else if (str[0]=='F' && !strncmp(str,"Face ",5)) 
  {
    int id[3];
    int triID, ndx, value;
    char *stringLoc = str + 4;
    for (ndx = 0;; ndx++)
    {
      while (*stringLoc && isspace(*stringLoc)) stringLoc++;
      if (!*stringLoc) break;
      char *valueStr = stringLoc;
      while (*stringLoc && isdigit(*stringLoc)) stringLoc++;
      value = atoi(valueStr);
      !ndx ? triID = value : id[ndx-1] = value;
    }
    mesh->AddTriangle(id[0], id[1], id[2]);
  }
}

void MeshObject::GetMinVtx(float vtx[3])
{
  for (int ndx = 0; ndx < 3; ++ndx) vtx[ndx] = minVtx[ndx];
}

void MeshObject::GetMaxVtx(float vtx[3])
{
  for (int ndx = 0; ndx < 3; ++ndx) vtx[ndx] = maxVtx[ndx];
}
