/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2008-2010 Pelican Mapping
 * http://osgearth.org
 *
 * osgEarth 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 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
#ifndef OSGEARTH_DROAM_ENGINE_AMR_GEOMETRY_H
#define OSGEARTH_DROAM_ENGINE_AMR_GEOMETRY_H 1

#include <osgEarth/Revisioning>
#include <osg/Geometry>
#include <osg/StateSet>
#include <osg/Program>

class MeshNode
{
public:
    osg::Vec3d _manifoldCoord;   // source coordinate (in manifold srs)
    osg::Vec3d _geodeticCoord;   // source coordinate (in lon/lat/alt)
    osg::Vec3f _vertex;          // world space vertex
    osg::Vec3f _normal;          // world space normal

    osg::Quat  _geodeticRot;     // geodetic rotation (lat/long rotation matrix as quat)
};

class AMRTriangle : public osg::Referenced
{
public:
    AMRTriangle();

    AMRTriangle(
        const MeshNode& node0, const osg::Vec2& t0,
        const MeshNode& node1, const osg::Vec2& t1,
        const MeshNode& node2, const osg::Vec2& t2 );

    void expand( osg::BoundingBox& box );

public:
    osg::ref_ptr<osg::StateSet> _stateSet;
    MeshNode _node0, _node1, _node2;
};

typedef std::vector< osg::ref_ptr<AMRTriangle> > AMRTriangleList;


class AMRDrawable : public osg::Referenced
{
public:
    AMRDrawable();
    void add( AMRTriangle* triangle ) { _triangles.push_back( triangle ); }

    osg::ref_ptr<osg::StateSet> _stateSet;
    AMRTriangleList _triangles;
};

typedef std::vector< osg::ref_ptr<AMRDrawable> > AMRDrawableList;


/**
 * Adaptive Mesh Refining Geometry.
 *
 * This class extends OSG's geometry object to perform adaptive mesh refinement
 * using a virtual vertex manifold and a globally shared VBO that contains the
 * refinement patches.
 */
class AMRGeometry : public osg::Drawable //osg::Geometry
{
public:
    AMRGeometry();
    AMRGeometry( const AMRGeometry& rhs, const osg::CopyOp& op =osg::CopyOp::DEEP_COPY_ALL );
    META_Object( osgEarth, AMRGeometry );

    virtual osg::BoundingBox computeBound() const;

public:
    /** Empties the draw list of manifold triangles. */
    void clearDrawList();

    /** Sets an entire new triangle list. */
    void setDrawList( const AMRDrawableList& drawList );

protected:
    /** renders the draw list. */
    virtual void drawImplementation( osg::RenderInfo& renderInfo ) const;

private:
    // list of manifold tris to render
    AMRDrawableList _drawList;

    // the adaptive refinement pattern that is permanently stores in the VBO.
    // in the future we may support more than one pattern (for LOD matching, e.g.)
    typedef std::vector< osg::ref_ptr<osg::DrawElements> > Pattern;
    Pattern _pattern;
    int _numPatternVerts;
    int _numPatternElements;
    int _numPatternStrips;
    int _numPatternTriangles;
    
    osg::ref_ptr<osg::Vec3Array>           _verts;
    osg::ref_ptr<osg::Vec2Array>           _texCoords;
    osg::ref_ptr<osg::VertexBufferObject>  _patternVBO;
    osg::ref_ptr<osg::ElementBufferObject> _patternEBO;

public: // temp
    // shader program that draws the virtual geometry
    osg::ref_ptr<osg::Program> _program;

private:

    void initShaders();
    void initPatterns();
};

#endif // OSGEARTH_DROAM_ENGINE_AMR_GEOMETRY_H
