#include <osg/Node>
#include <osg/Group>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgProducer/Viewer>
#include <osg/PositionAttitudeTransform>
#include <osgGA/TrackballManipulator>


/// Les commentaires sont laissés en Anglais. Cependant, je me suis permis d'en ajouter
/// un ou l'autre pour mieux situer chaque portion de code.

int main()
{
    /// Initialisation
    osgProducer::Viewer viewer;
    osg::Group* root = new osg::Group();
    osg::Geode* pyramidGeode = new osg::Geode();
    osg::Geometry* pyramidGeometry = new osg::Geometry();

    pyramidGeode->addDrawable(pyramidGeometry);
    root->addChild(pyramidGeode);

    /// Sommets
    osg::Vec3Array* pyramidVertices = new osg::Vec3Array;
    pyramidVertices->push_back( osg::Vec3( 0, 0, 0) ); // front left
    pyramidVertices->push_back( osg::Vec3(10, 0, 0) ); // front right
    pyramidVertices->push_back( osg::Vec3(10,10, 0) ); // back right
    pyramidVertices->push_back( osg::Vec3( 0,10, 0) ); // back left
    pyramidVertices->push_back( osg::Vec3( 5, 5,10) ); // peak

    pyramidGeometry->setVertexArray( pyramidVertices );

    /// Faces
    osg::DrawElementsUInt* pyramidBase =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidBase->push_back(3);
    pyramidBase->push_back(2);
    pyramidBase->push_back(1);
    pyramidBase->push_back(0);
    pyramidGeometry->addPrimitiveSet(pyramidBase);

    osg::DrawElementsUInt* pyramidFaceOne =
        new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
    pyramidFaceOne->push_back(0);
    pyramidFaceOne->push_back(1);
    pyramidFaceOne->push_back(4);
    pyramidGeometry->addPrimitiveSet(pyramidFaceOne);

    osg::DrawElementsUInt* pyramidFaceTwo =
        new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
    pyramidFaceTwo->push_back(1);
    pyramidFaceTwo->push_back(2);
    pyramidFaceTwo->push_back(4);
    pyramidGeometry->addPrimitiveSet(pyramidFaceTwo);

    osg::DrawElementsUInt* pyramidFaceThree =
        new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
    pyramidFaceThree->push_back(2);
    pyramidFaceThree->push_back(3);
    pyramidFaceThree->push_back(4);
    pyramidGeometry->addPrimitiveSet(pyramidFaceThree);

    osg::DrawElementsUInt* pyramidFaceFour =
        new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
    pyramidFaceFour->push_back(3);
    pyramidFaceFour->push_back(0);
    pyramidFaceFour->push_back(4);
    pyramidGeometry->addPrimitiveSet(pyramidFaceFour);

    /// Couleurs et assignation
    osg::Vec4Array* colors = new osg::Vec4Array;
    colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) ); //index 0 red
    colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) ); //index 1 green
    colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); //index 2 blue
    colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 3 white

    osg::TemplateIndexArray
        <unsigned int, osg::Array::UIntArrayType,4,4> *colorIndexArray;
    colorIndexArray =
        new osg::TemplateIndexArray<unsigned int, osg::Array::UIntArrayType,4,4>;
    colorIndexArray->push_back(0); // vertex 0 assigned color array element 0
    colorIndexArray->push_back(1); // vertex 1 assigned color array element 1
    colorIndexArray->push_back(2); // vertex 2 assigned color array element 2
    colorIndexArray->push_back(3); // vertex 3 assigned color array element 3
    colorIndexArray->push_back(0); // vertex 4 assigned color array element 0

    pyramidGeometry->setColorArray(colors);
    pyramidGeometry->setColorIndices(colorIndexArray);
    pyramidGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

    osg::Vec2Array* texcoords = new osg::Vec2Array(5);
    (*texcoords)[0].set(0.00f,0.0f);
    (*texcoords)[1].set(0.25f,0.0f);
    (*texcoords)[2].set(0.50f,0.0f);
    (*texcoords)[3].set(0.75f,0.0f);
    (*texcoords)[4].set(0.50f,1.0f);
    pyramidGeometry->setTexCoordArray(0,texcoords);

    /// Seconde pyramide
    // Declare and initialize a transform node.
    osg::PositionAttitudeTransform* pyramidTwoXForm =
        new osg::PositionAttitudeTransform();

    // Use the 'addChild' method of the osg::Group class to
    // add the transform as a child of the root node and the
    // pyramid node as a child of the transform.
    root->addChild(pyramidTwoXForm);
    pyramidTwoXForm->addChild(pyramidGeode);

    // Declare and initialize a Vec3 instance to change the
    // position of the tank model in the scene
    osg::Vec3 pyramidTwoPosition(15,0,0);
    pyramidTwoXForm->setPosition( pyramidTwoPosition );

    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
    viewer.setSceneData( root );

    viewer.realize();

    while( !viewer.done() )
    {
      viewer.sync();
      viewer.update();
      viewer.frame();
    }

   return 0;
}

