/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * Copyright (C)  2013 Frederik Heber. All rights reserved.
 *
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder is free software: 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.
 *
 *    MoleCuilder 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/*
 * GLMoleculeObject_shape.cpp
 *
 *  Created on: Aug 3, 2012
 *      Author: ankele
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "GLMoleculeObject_shape.hpp"
#include 
#include 
#include 
#include 
#include 
#include 
#include "CodePatterns/MemDebug.hpp"
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "Shapes/Shape.hpp"
#include "Shapes/ShapeFactory.hpp"
#include "LinearAlgebra/Vector.hpp"
#include "LinkedCell/PointCloudAdaptor.hpp"
#include "LinkedCell/linkedcell.hpp"
#include "Tesselation/tesselation.hpp"
#include "Tesselation/BoundaryLineSet.hpp"
#include "Tesselation/BoundaryTriangleSet.hpp"
#include "Tesselation/CandidateForTesselation.hpp"
#include "Atom/TesselPoint.hpp"
typedef QGLSceneNode *MeshList[GLMoleculeObject::DETAILTYPES_MAX];
static QGLSceneNode *createShapeMesh(Shape &shape, QObject *parent)
{
  size_t NumPointsonSurface = 200;
  // guess the surface area which divided by 200 determines rolling sphere's size
  const double surfacearea = shape.getSurfaceArea();
  const size_t EstimatedNumberTriangles = NumPointsonSurface*1;
  const double MeanAreaPerTriangle = surfacearea/((double)EstimatedNumberTriangles);
  // assume two triangles to form a square and take its diameter as the radius
  double minradius = sqrt(2. * 2.*MeanAreaPerTriangle);
  LOG(3, "DEBUG: Surface area is " << surfacearea << ", minradius is " << minradius << ".");
  if (minradius < 1.)
    minradius = 1.;
  LOG(2, "DEBUG: Tesselating shape " << shape.getName() << " with sphere of radius " << minradius << ".");
  // Create some points on our shape.
  std::vector points = shape.getHomogeneousPointsOnSurface(NumPointsonSurface);
  QGeometryData geo;
  // we need at least three points for tesselation
  if (points.size() >= 3) {
    // Fill the points into a tesselate-able container.
    TesselPointSTLList Corners;
    for (size_t i=0;isetPosition(points[i]);
      Walker->setName(toString(i));
      Walker->setNr(i);
      Corners.push_back(Walker);
    }
  
    // Tesselate the points.
    Tesselation T;
    PointCloudAdaptor cloud(&Corners, "TesselPointSTLList");
    T(cloud, minradius);
  
    // Fill the points into a Qt geometry.
    LinkedCell_deprecated LinkedList(cloud, minradius);
    std::vector normals;
    normals.resize(points.size(), zeroVec);
    for(size_t i=0;isecond->endpoints[i]->node->getNr();
  
      // Sort the vertices so the triangle is clockwise (relative to the normal vector).
      Vector cross = points[v[1]] - points[v[0]];
      cross.VectorProduct(points[v[2]] - points[v[0]]);
      if (cross.ScalarProduct(normals[v[0]] + normals[v[1]] + normals[v[2]]) > 0)
        geo.appendIndices(v[0], v[1], v[2]);
      else
        geo.appendIndices(v[0], v[2], v[1]);
    }
  }
  // Build a mesh from the geometry.
  QGLBuilder builder;
  builder.addTriangles(geo);
  QGLSceneNode *mesh = builder.finalizedSceneNode();
  return mesh;
}
GLMoleculeObject_shape::GLMoleculeObject_shape(Shape &shape, QObject *parent) :
    GLMoleculeObject(createShapeMesh(shape, parent), parent),
    m_shape(shape)
{
  // Create the material.
  QGLMaterial *material = new QGLMaterial(NULL);
  material->setAmbientColor( QColor(50, 60, 100, 255) );
  material->setDiffuseColor( QColor(150, 160, 200, 180) );
  material->setSpecularColor( QColor(60, 60, 60) );
  material->setShininess( 128 );
  setMaterial(material);
  m_enabled = false;
}
GLMoleculeObject_shape::~GLMoleculeObject_shape()
{
}
void GLMoleculeObject_shape::enable(bool enabled)
{
  m_enabled = enabled;
}
void GLMoleculeObject_shape::draw(QGLPainter *painter, const QVector4D &cameraPlane)
{
  if (!m_enabled)
    return;
  painter->modelViewMatrix().push();
  painter->setColor(m_material->diffuseColor());
  painter->setFaceMaterial(QGL::AllFaces, m_material);
  // Draw the transparent cube.
  painter->setStandardEffect(QGL::LitMaterial);
  glCullFace(GL_BACK);
  glEnable(GL_CULL_FACE);
  glEnable(GL_BLEND);
  glDepthMask(0);
  glDisable(GL_DEPTH_TEST);
  m_mesh[0]->draw(painter);
  glEnable(GL_DEPTH_TEST);
  glDepthMask(1);
  glDisable(GL_BLEND);
  glDisable(GL_CULL_FACE);
  painter->modelViewMatrix().pop();
}