#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.

osg::Geode* createPyramid(osg::Group* root)
{
  ///! Attention qu'en copiant à partir du tutoriel, il manque les définitions des vertices !
    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
    /// - on éclaircit histoire de mieux voir les textures...
    osg::Vec4Array* colors = new osg::Vec4Array;
    colors->push_back(osg::Vec4(1.0f, 0.5f, 0.5f, 1.0f) ); //index 0 red
    colors->push_back(osg::Vec4(0.5f, 1.0f, 0.5f, 1.0f) ); //index 1 green
    colors->push_back(osg::Vec4(0.5f, 0.5f, 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);

   return pyramidGeode;
}

int main()
{
 ///On commence
   osgProducer::Viewer viewer;

   // Declare a group to act as root node of a scene:
   osg::Group* root = new osg::Group();
   osg::Geode* pyramidGeode = createPyramid(root);

 ///Création de la texture
   osg::Texture2D* KLN89FaceTexture = new osg::Texture2D;

   // protect from being optimized away as static state:
   KLN89FaceTexture->setDataVariance(osg::Object::DYNAMIC);

   // load an image by reading a file:
   osg::Image* klnFace = osgDB::readImageFile("osglogo2.0.jpg"); ///j'ai changé le nom... (avant c'était: "KLN89FaceB.tga")
   if (!klnFace)
   {
      std::cout << " couldn't find texture, quiting." << std::endl;
      return -1;
   }

   // Assign the texture to the image we read from file:
   KLN89FaceTexture->setImage(klnFace);

 ///Ensuite, seconde étape
   // Create a new StateSet with default settings:
   osg::StateSet* stateOne = new osg::StateSet();

   // Assign texture unit 0 of our new StateSet to the texture
   // we just created and enable the texture.
   stateOne->setTextureAttributeAndModes
      (0,KLN89FaceTexture,osg::StateAttribute::ON);
   // Associate this state set with the Geode that contains
   // the pyramid:
   pyramidGeode->setStateSet(stateOne);

 /// Dernière étape:
      //The final step is to set up and enter a simulation loop.
   viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
   viewer.setSceneData( root );
   viewer.realize();

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