/*
 * Mesh.h
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * This program 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.
 *
 * This program 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 this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#ifndef _MESH_H
#define _MESH_H

#ifndef _ARRAY_H
#include "Array.h"
#endif

#ifndef _LIST_H
#include "List.h"
#endif

#ifndef _VEC4F_H
#include "Vec4f.h"
#endif

#ifndef _VEC3F_H
#include "Vec3f.h"
#endif

#ifndef _VEC2F_H
#include "Vec2f.h"
#endif

enum {
    MESH_CCW                 = 1<<1,
    MESH_COLOR_PER_VERTEX    = 1<<2, 
    MESH_CONVEX              = 1<<3, 
    MESH_NORMAL_PER_VERTEX   = 1<<4, 
    MESH_SOLID               = 1<<5,
    MESH_COLOR_RGBA          = 1<<6 
};

class Face;
class MFFloat;
class MFVec3f;
class MFVec2f;
class MFInt32;

#ifdef HAVE_GLUNEWTESS
struct VertexInfo {
   GLdouble vertex[3];
   float normal[3];
   float color[4];
   float texCoord[2];
};
#endif

class Mesh {
public:
                        Mesh(MFVec3f *vertices, MFInt32 *coordIndex,
                             MFVec3f *normals, MFInt32 *normalIndex,
                             MFFloat *colors, MFInt32 *colorIndex,
                             MFVec2f *texCoords, MFInt32 *texCoordIndex,
                             float creaseAngle, int meshFlags, 
                             float transparency = 0);
                       ~Mesh();
                
    void                draw() { draw(-1); }
    void                draw(int meshFlags);
    void                drawNormals(void);
    void                sort();

    MFVec3f            *getVertices(void)      { return _vertices; }
    MFInt32            *getCoordIndex(void)    { return _coordIndex; }
    MFFloat            *getColors(void)        { return _colors; }
    MFInt32            *getColorIndex(void)    { return _colorIndex; }
    MFVec3f            *getNormals(void)       { return _normals; }
    MFInt32            *getNormalIndex(void)   { return _normalIndex; }
    MFVec2f            *getTexCoords(void)     { return _texCoords; }
    MFInt32            *getTexCoordIndex(void) { return _texCoordIndex; }
    float               creaseAngle()          { return _creaseAngle; }
    bool                solid()                { return _solid; }
    bool                ccw()                  { return _ccw; }
    bool                convex()               { return _convex; }
    bool                colorPerVertex()       { return _colorPerVertex; }
    bool                normalPerVertex()      { return _normalPerVertex; }

    MFVec2f            *generateTextureCoordinates();
    void                generateFaceNormals();
    void                smoothNormals(bool optimizeNormals = true);

    bool                onlyPlanarFaces(void);
    int                 getNumFaces(void) { return _numFaces; }
    Face               *getFace(int i) { return _faces[i]; }

    void                setCreaseAngle(float angle) { _creaseAngle = angle; }
    void                setNormals(MFVec3f *normals);

    void                optimize(void);
    MFInt32            *optimizeCoordIndex(void);
    void                optimizeVertices(MFVec3f *newCoord, 
                                         MFInt32 *newCoordIndex);
    int                 getMaxNumberEdgesPerFace(void);
    bool                hasColorRGBA(void) { return _colorRGBA; }
#ifdef HAVE_GLUNEWTESS
    Mesh               *triangulate(void);
    void                addNewVertex(VertexInfo * vertexInfo);
    void                endNewPolygon(void);
    void                startTesselation(GLenum type);
    void                collectMemoryToFree(VertexInfo * vertexInfo);
#endif

protected:
    void                buildFaces(void);
#ifdef HAVE_GLUNEWTESS
    void                initialiseTriangulation(GLUtesselator *tess);
    int                 searchInOriginalVertices(GLdouble* vertex);
    int                 searchInNewVertices(GLdouble* vertex);
    Mesh               *buildNewTriangulatedMesh(void); 
#endif 

private:
    MFVec3f            *_vertices;
    MFVec3f            *_normals;
    MFFloat            *_colors;
    MFVec2f            *_texCoords;

    MFInt32            *_coordIndex;
    MFInt32            *_colorIndex;
    MFInt32            *_normalIndex;
    MFInt32            *_texCoordIndex;

    int                 _numFaces;
    Face              **_faces;

    float               _creaseAngle;
    bool                _ccw;
    bool                _convex;
    bool                _solid;
    bool                _normalPerVertex;
    bool                _colorPerVertex;
    bool                _colorRGBA;
    float               _transparency;

    bool                _isTriangulated;

    int                 _tesselationStart;
    GLenum              _tesselationType;
    bool                _evenTriangleStrip;
    int                 _drawCounter;
    unsigned int        _listIndex;
    int                 _currentFace;
#ifdef HAVE_GLUNEWTESS
    Array<VertexInfo>   _verticesInfo;

    Array<float>        _triangulatedVertices;
    Array<int>          _triangulatedIndices;

    Array<float>        _triangulatedNormals;
    bool                _triangulatedHasNormals;

    Array<float>        _triangulatedColors;
    bool                _triangulatedHasColors;
    bool                _triangulatedHasColorsRGBA;

    Array<float>        _triangulatedTexCoords;
    bool                _triangulatedHasTexCoords;

    List<VertexInfo *>  _newMemory4VerticesInfo;
#endif 
};

MFVec2f *generateTextureCoordinates(MFVec3f *points, MFInt32* cindex);

#endif // _MESH_H

