
#include "Tscene.h"

void Tscene::draw()
{
    _draw_reflection();
	_draw_models();

	interface_draw();

	ECO_swapBuffers();
}


void Tscene::_draw_models()
{
    OMat4 view, vp;

    //glClearColor(m_backColor[0], m_backColor[1], m_backColor[2], m_backColor[3]);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    m_select_size = 0;

    // ----------------------------
    // >>> debut de scene 'normale'
    // ----------------------------

    view.loadIdentity();
    camera.lookAt(view);
    vp = m_proj3d * view;

    // ---

    dshGeo.enable();
        dshGeo.setVP(vp);

    dshNull.enable();
        dshNull.setVP(vp);

    dshDir.enable();
        dshDir.setEyePos(camera.getPos());

    dshPoint.enable();
        dshPoint.setVP(vp);

    //

    dshMask.enable();
        dshMask.setVP(vp);

    dshFreeze.enable();
        dshFreeze.setVP(vp);

    //

    shLight.enable();
        shLight.setVP(vp);

    shLight_pbr.enable();
        shLight_pbr.setVP(vp);
        shLight_pbr.setEyePos(camera.getPos());

    shParticle3d.enable();
        //matrice horizontale !
        shParticle3d.setCameraRight(view[0], view[1], view[2]);
		shParticle3d.setCameraUp(view[4], view[5], view[6]);
		shParticle3d.setVP(vp);

    shBillboard.enable();
        shBillboard.setVP(vp);
        shBillboard.setCameraPos(camera.getPos());

    shGlow.enable();
        shGlow.setVP(vp);

    // ---

    // >>> debut de scene
    defered_buffer.enableWritting();

    //
    // --- geometry pass ---
    //
    defered_buffer.startGeometryPass();

        // le sol en dernier = gain car masqué par étendue d'eau et objets
        //for (size_t i = 0; i < zone.size(); i++)
        //{
        //    zone[i].draw(dshMask);
        //}
        for (size_t i = 0; i < deco.size(); i++)
        {
            deco[i].draw(dshGeo);
            //m_select_size += deco[i].getSelect();
        }
        for (size_t i = 0; i < perso.size(); i++)
        {
            perso[i].draw(dshGeo, dshFreeze);
            m_select_size += perso[i].getSelect();
        }
        for (size_t i = 0; i < objet.size(); i++)
        {
            objet[i].draw(dshGeo);
            m_select_size += objet[i].getSelect();
        }
        for (size_t i = 0; i < meca.size(); i++)
        {
            // meca_obj[i].update dans Mcycle
            meca[i].draw(dshGeo);
            m_select_size += meca[i].getSelect();
        }

        fontaine.draw(dshGeo); // update (jet) dans Mcycle
        bassin.draw(dshGeo);
        flag_med.draw(vp, dshGeo);
        flag_low.draw(vp, dshGeo);
        for (size_t i = 0; i < torche.size(); i++)
        {
            torche[i].draw(dshGeo);
        }

        // c'est bien un mode defered shader
        if (rbtTree.getChecked() == 0) tree.draw(vp);  else wood.draw(vp);

        // le sol en dernier = gain car masqué par étendue d'eau et objets
        for (size_t i = 0; i < zone.size(); i++)
        {
            zone[i].draw(dshMask);
        }

        dshGeo.disable();
    defered_buffer.endGeometryPass();

    //
    // --- light passe ---
    //

    defered_buffer.startLightPass();
        dshDir.enable();
            //dshDir.setTextureUnit();
        dshDir.draw_plan();
        dshDir.disable();
    defered_buffer.endLightPass();

    //
    // --- shader simple réagissant à la lumiere
    //

    // rappeller les effets de transparence
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // actualisez la lumiere > Mlight
    switch(rbtEau.getChecked())
    {
    case WATER_LAKE_LOW:
        //lake3d_low.draw(vp, camera.getPos(), 0);
        lake3d_low.draw(vp, camera.getPos(), water_buffer.getColorMap());
        break;
    case WATER_LAKE_MED:
        lake3d_med.draw(vp, camera.getPos(), water_buffer.getColorMap());
        break;
    case WATER_LAKE_HIG:
        //lake3d_hig.draw(vp, camera.getPos(), 0); //water_buffer.getColorMap());
        break;

    case WATER_SEA_LOW:
        sea3d_low.draw(vp, camera.getPos(), water_buffer.getColorMap()); // refractionMap
        break;
    case WATER_SEA_MED:
        //
        break;
    }

    float ambient = skyEarth.sun.getAmbient();

    fontaine.draw_water(vp, ambient);
    bassin.draw_water(vp, ambient);
    if (m_mode_shader == 0)
    {
        barrel.draw(shLight);
    }
    else
    {
        barrel.draw(shLight_pbr);
    }
    // effets feu sur les persos
    for (size_t i = 0; i < perso.size(); i++)
    {
        perso[i].draw(shLight, camera.getPos() );
    }

    //
    // --- lumières ponctuelles ---
    //

    // active la lecture sur 4 tampons
    defered_buffer.startStencilPass();
        for (size_t i = 0; i < torche.size(); i++)
        {
            torche[i].draw_light_point(defered_buffer, dshNull, dshPoint);
        }
    // fin des lumieres
    defered_buffer.endStencilPass();

    // --------------------
    // --- shader simple (ne réagissant pas aux points de lumière) ---
    // ---------------------
    // désactive l'écriture sur les quatres tampons
    defered_buffer.endDeferedWritting();

    skyEarth.draw(vp, view);

    // --- emissive ---

    glDepthFunc(GL_EQUAL);

    for (size_t i_dec = 0; i_dec < deco.size(); i_dec++)
    {
        deco[i_dec].draw_emissive(shGlow); // le cube !!!
    }
    for (size_t i_obj = 0; i_obj < objet.size(); i_obj++)
    {
        objet[i_obj].draw_emissive(shGlow); // l'orbe
    }
    for (size_t i_per = 0; i_per < perso.size(); i_per++)
    {
        perso[i_per].draw_emissive(shGlow);
    }

    glDepthFunc(GL_LESS);

    // --- particules ---


    shParticle3d.enable();

    glDepthMask(GL_FALSE); // va permettre un effet de densification des particules, sinon elles s'éffacent les unes les autres
        fontaine.draw_particle();

        for (size_t i = 0; i < torche.size(); i++)
        {
            torche[i].draw_particle();
        }
    glDepthMask(GL_TRUE);

    // --- billboards ---

    for (size_t i = 0; i < billboard.size(); i++)
    {
        billboard[i].draw(shBillboard);
    }

    // --- et autres

    switch(rbtGrass.getChecked())
    {
    case GRASS_GEOMETRY:
        grass_geo.draw(vp, camera.getPos(), ambient);
        break;
    case GRASS_INSTANCED:
        grass_ins.draw(vp, camera.getPos(), ambient);
        break;
    }

    // en dernier si depthmask false
    fire1.draw(vp);

    // <<< fin de scene
    defered_buffer.disableWritting();

    // parametres de base
    //glDisable(GL_DEPTH_TEST);
    //glEnable(GL_TEXTURE_2D);
    //glEnable(GL_BLEND);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    if (m_select_size > 0)
    {
        glDisable(GL_BLEND);

        fboPostProcess.enableWriting();
            ppOutline.enable();
                //ppOutline.setScreenSize(m_width,m_height);
                ppOutline.setTextures(defered_buffer.getFinalTexture(), defered_buffer.getMaskTexture(), defered_buffer.getDepthTexture());

                fboPostProcess.draw_null(); // ne tient pas compte de la texture color de fboPostProcess
            ppOutline.disable();
        fboPostProcess.disableWriting();
        // affichage du contenu de colormap de fboPostProcess
        //fboPostProcess.draw();
    }

    // ---

    switch(rbtProcess.getChecked())
    {
    case PP_NULL:
        defered_buffer.draw();
        break;
    case PP_ALIASING:
        ppAliasing.enable();
            //ppAliasing.setScreenSize(m_width,m_height);
            // draw_free > ne tient pas compte du shader interne
            if (m_select_size) fboPostProcess.draw_free(); else defered_buffer.draw_free();
        ppAliasing.disable();
        break;
    case PP_FOG:
        ppFog.update(); // ou bloquer pour visu en direct
        if (ppFog.getState() == OPPFOG_NULL) rbtProcess.setChecked(PP_ALIASING);
        ppFog.shFog.enable();
            //ppFog.shFog.setScreenSize(m_width,m_height);
            ppFog.shFog.setTextures(defered_buffer.getFinalTexture(), defered_buffer.getDepthTexture());
            defered_buffer.draw_free();
        ppFog.shFog.disable();
        break;
    case PP_RAIN:
        ppRain.update();
        if (ppRain.getState() == OPPRAIN_NULL)
        {
            rbtProcess.setChecked(1); // gardez l'ordre ! 1 = PP_ALIASING
            rbtProcess.setChecked(PP_ALIASING);
        }
        ppRain.shRain.enable();
            //ppRain.shRain.setScreenSize(m_width,m_height);
            ppRain.shRain.setTextures(defered_buffer.getFinalTexture(), defered_buffer.getDepthTexture());
            defered_buffer.draw_free();
        ppRain.shRain.disable();
        break;
    case PP_SNOW:
        ppSnow.update();
        if (ppSnow.getState() == OPPSNOW_NULL)
        {
            rbtProcess.setChecked(1);
            rbtProcess.setChecked(PP_ALIASING);
        }
        ppSnow.shSnow.enable();
            //ppSnow.shSnow.setScreenSize(m_width,m_height);
            ppSnow.shSnow.setTextures(defered_buffer.getFinalTexture(), defered_buffer.getDepthTexture());
            defered_buffer.draw_free();
        ppSnow.shSnow.disable();
        break;
    }

}


void Tscene::_draw_reflection()
{
    OMat4 view, vp;

    //glClearColor(m_backColor[0], m_backColor[1], m_backColor[2], m_backColor[3]);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // -----------------------------------
    // --- l'image reflection de l'eau ---
    // -----------------------------------

    // positionne la camera sous l'eau, en reflection
    OVec3_f pos = camera.getPos();
    float angleV = camera.getAngleV();
    //
    OVec3_f p2 = camera.getPos();
    p2.z *= -1.01f;
    camera.setPos(p2);
    float a2 = angleV;
    camera.setAngleV(-a2);

    view.loadIdentity();
    camera.lookAt(view);
    vp = m_proj3d * view;

/*
    + redonne la camera en fin
    camera.setAngleV(angleV);
    camera.setPos(pos);
*/

    // ---

    dshGeo.enable();
        dshGeo.setVP(vp);

    dshNull.enable();
        dshNull.setVP(vp);

    dshDir.enable();
        dshDir.setEyePos(camera.getPos());

    dshPoint.enable();
        dshPoint.setVP(vp);

    //

    dshMask.enable();
        dshMask.setVP(vp);

    dshFreeze.enable();
        dshFreeze.setVP(vp);

    // ---

/*
    shLight.enable();
        shLight.setVP(vp);

    shLight_pbr.enable();
        shLight_pbr.setVP(vp);
        shLight_pbr.setEyePos(camera.getPos());

    shParticle3d.enable();
        //matrice horizontale !
        shParticle3d.setCameraRight(view[0], view[1], view[2]);
		shParticle3d.setCameraUp(view[4], view[5], view[6]);
		shParticle3d.setVP(vp);

    shBillboard.enable();
        shBillboard.setVP(vp);
        shBillboard.setCameraPos(camera.getPos());

    shGlow.enable();
        shGlow.setVP(vp);
    */
    // ---

	// le water_buffer active le stencil buffer pour créer un masque là où il doit y avoir reflection.
	// la valeur de cliping est le plan de l'eau
	// la scene sera affichée, sauf là où il y de l'eau (et sous l'eau)
	water_buffer.startMask();

        switch(rbtEau.getChecked())
        {
        case WATER_LAKE_LOW:
            lake3d_low.draw_water_reflection(vp);
            break;
        case WATER_LAKE_MED:
            lake3d_med.draw_water_reflection(vp);
            break;
        case WATER_LAKE_HIG:
            //lake3d_hig.draw_water_reflection(vp);
            break;

        case WATER_SEA_LOW:
            sea3d_low.draw_water_reflection(vp);
            break;
        case WATER_SEA_MED:
            //sea3d_med.draw_water_reflection(vp);
            break;
        }

	water_buffer.endMask();

	//
	// --- geometry pass ---
	//

    water_buffer.startGeometryPass();

        for (size_t i = 0; i < deco.size(); i++)
        {
            deco[i].draw(dshGeo);
        }
        for (size_t i = 0; i < perso.size(); i++)
        {
            perso[i].draw(dshGeo, dshFreeze);
        }
        for (size_t i = 0; i < objet.size(); i++)
        {
            objet[i].draw(dshGeo);
        }

        fontaine.draw(dshGeo); // update (jet) dans Mcycle
        bassin.draw(dshGeo);

        //for (size_t i = 0; i < torche.size(); i++)
        //{
        //    torche[i].draw(dshGeo);
        //}
        flag_med.draw(vp, dshGeo);
        flag_low.draw(vp, dshGeo);
        for (size_t i = 0; i < meca.size(); i++)
        {
            // meca_obj[i].update dans Mcycle
            meca[i].draw(dshGeo);
        }

        // c'est bien un mode defered shader
        if (rbtTree.getChecked() == 0) tree.draw(vp);  else wood.draw(vp);

        // le sol en dernier = gain car masqué par étendue d'eau et objets
        for (size_t i = 0; i < zone.size(); i++)
        {
            zone[i].draw(dshMask);
        }

        dshGeo.disable();
    water_buffer.endGeometryPass();

    //
    // --- light passe ---
    //

    water_buffer.startLightPass();
        dshDir.enable();
            //dshDir.setTextureUnit();
        dshDir.draw_plan();
        dshDir.disable();
    water_buffer.endLightPass();

    //
    // --- shader simple réagissant à la lumière
    //

    // >>> pas l'eau !

    //
    // --- lumières ponctuelles ---
    //
/*
    // active la lecture sur 4 tampons
    water_buffer.startStencilPass();

        for (size_t i = 0; i < torche.size(); i++)
        {
            torche[i].draw_light_point(water_buffer, dshNull, dshPoint);
        }

    // fin des lumieres
    water_buffer.endStencilPass();
*/
    //
    // --- shader simple (ne réagissant pas aux points de lumière) ---
    //

    // désactive l'écriture sur les quatres tampons
    water_buffer.endDeferedWritting();

    skyEarth.draw(vp, view);

    // rappeller les effets de transparence
    //glEnable(GL_DEPTH_TEST);
    //glEnable(GL_TEXTURE_2D);
    //glEnable(GL_BLEND);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // --- emissive ---

    // --- particules ---

    // inutile en général

    // --- billboards ---

    // <<<
    water_buffer.endReflection();

    // redonne la camera en fin
    camera.setAngleV(angleV);
    camera.setPos(pos);
}

