
#include "Tlake3d_med_1.h"

// shader et plan en fin

// -----------------------
// --- le constructeur ---
// -----------------------

Tlake3d_med_1::Tlake3d_med_1()
{
	//
}

// ----------------------
// --- le destructeur ---
// ----------------------

Tlake3d_med_1::~Tlake3d_med_1()
{
    //
}


void Tlake3d_med_1::create(int size, float scale_uv)
{
	OTextureList::P_setPath(PATH_IMAGE);
	OTextureList::P_setMipmap(true);

    textureList.add("colorMap3.png");
    textureList.add("normal_3_1024.png");
    textureList.add("dudv.png");

    OTextureList::P_setMipmap(false);

    m_colorMap = textureList.getID("colorMap3.png");
    m_normalMap = textureList.getID("normal_3_1024.png");
    m_dudv = textureList.getID("dudv.png");

    // ---

    plan.create(size, scale_uv);

    // ---

    shLake_med.create();
    shLake_med_w.create();
}


void Tlake3d_med_1::create(std::string file_obj)
{
	OTextureList::P_setPath(PATH_IMAGE);
	OTextureList::P_setMipmap(true);

    textureList.add("colorMap3.png");
    textureList.add("normal_3_1024.png");
    textureList.add("dudv.png");

    OTextureList::P_setMipmap(false);

    m_colorMap = textureList.getID("colorMap3.png");
    m_normalMap = textureList.getID("normal_3_1024.png");
    m_dudv = textureList.getID("dudv.png");

    // ---

    plan.create(file_obj);

    // ---

    shLake_med.create();
    shLake_med_w.create();
}




void Tlake3d_med_1::draw(OMat4& vp, OVec3_f& eyePos, uint32_t reflectionMap)
{
    static float time = 100.0f;
    time++;

    //glEnable(GL_CULL_FACE);
    glDisable(GL_CULL_FACE);

    // on pourrait passer en multi
    if (plan.getSize() == 1)
    {
        shLake_med.enable();
            shLake_med.setVP(vp);
            shLake_med.setModel( plan.getModel() );

            shLake_med.setTime(time);
            shLake_med.setEyePos(eyePos);
            shLake_med.setTextures(m_colorMap, m_normalMap, reflectionMap, m_dudv);

            plan.draw();

        shLake_med.disable();
        return;
    }

    shLake_med.enable();
        shLake_med.setVP(vp);
        shLake_med.setMulti(true);

        shLake_med.setTime(time);
        shLake_med.setEyePos(eyePos);
        shLake_med.setTextures(m_colorMap, m_normalMap, reflectionMap, m_dudv);

        plan.draw_multi();
        shLake_med.setMulti(false);

    shLake_med.disable();

    glCullFace(GL_BACK);
}

void Tlake3d_med_1::draw_water_reflection(OMat4& vp)
{
    static float time = 100.0f;
    time++;

    //glEnable(GL_CULL_FACE);
    glDisable(GL_CULL_FACE);

    // on pourrait passer en multi
    if (plan.getSize() == 1)
    {
        shLake_med_w.enable();
            shLake_med_w.setVP(vp);
            shLake_med_w.setModel( plan.getModel() );

            plan.draw();

        shLake_med_w.disable();
        return;
    }

    shLake_med_w.enable();
        shLake_med_w.setVP(vp);
        shLake_med_w.setMulti(true);

        plan.draw_multi();
        shLake_med_w.setMulti(false);

    shLake_med_w.disable();
}




void Tlake3d_med_1::setLight(float ambient, OVec3_f& dir, OVec3_f& color)
{
    shLake_med.enable();
        shLake_med.setLight(ambient, dir, color);
    shLake_med.disable();
}



// --- grille map plan carte


// -----------------------
// --- le constructeur ---
// -----------------------

Tlake3d_med_1_plan::Tlake3d_med_1_plan()
{
    //
}

// ----------------------
// --- le destructeur ---
// ----------------------

Tlake3d_med_1_plan::~Tlake3d_med_1_plan()
{
    //
}

// --------------------
// --- les méthodes ---
// --------------------

// px py pz
void Tlake3d_med_1_plan::addModel(std::string flux)
{
    std::vector<std::string> strList;
    size_t idx = m_pos.size();

    ECO_strCut(strList, flux, ' ');

    m_pos.push_back(OVec3_f());
    m_model.push_back(OMat4());
    m_model_multi.push_back(OMat4());

	m_pos[idx].x = ECO_strToFloat(strList[0]);
	m_pos[idx].y = ECO_strToFloat(strList[1]);
	m_pos[idx].z = ECO_strToFloat(strList[2]);

    _setModel(idx);
}

// px py pz
void Tlake3d_med_1_plan::addModel(float px, float py, float pz)
{
    size_t idx = m_pos.size();

    m_pos.push_back(OVec3_f());
    m_model.push_back(OMat4());
    m_model_multi.push_back(OMat4());

	m_pos[idx].set(px,py,pz);

    _setModel(idx);
}





void Tlake3d_med_1_plan::create(uint32_t size, float scale_uv)
{
    m_pos.push_back(OVec3_f());
    m_model.push_back(OMat4());
    m_model_multi.push_back(OMat4());

    _setModel(0);

    // ---

    OVec3_f vertex[] = {
    {-1,-1,0}, {1,-1,0}, {1,1,0}, {-1,1,0}
    };
    OVec3_f normal[] = {
        {0.0f, 0.5f, 1.0f}
    };
    OVec2_f uv[] = {
        {0,0}, {1,0}, {1,1}, {0,1}
    };

    // 2 faces de 3 points
    int ivertex[] = {0,1,2, 2,3,0};
    int inormal[] = {0,0,0, 0,0,0};
    int iuv[]     = {0,1,2, 2,3,0};

    float radius = size * 0.5f;

    for (size_t pt = 0; pt < ECO_sizeOf(ivertex); pt++)
    {
        m_vertex.push_back(vertex[ivertex[pt]] * radius);
        m_normal.push_back(normal[inormal[pt]]);
        m_uv.push_back(uv[iuv[pt]] * scale_uv);
        m_indice.push_back(pt);
    }

	_make_vao();
}


// il faut une grille avec normal et uv > objet en faces triangulées uniquement
void Tlake3d_med_1_plan::create(std::string file)
{
    std::ifstream flux;
    std::string code;
	float x,y,z;

	std::vector<OVec3_f> vertex;
	std::vector<OVec2_f> uv;
	std::vector<OVec3_f> normal;

    flux.open( file.c_str(), std::ios::in);
    if (!flux)
    {
        ECO_error_set("Impossible d'ouvrir : %s >Tlake3d_med_1_plan.create", file.c_str());
        return;
    }

    // ---

    m_pos.push_back(OVec3_f());
    m_model.push_back(OMat4());
    m_model_multi.push_back(OMat4());

    _setModel(0);

    // ---

    //index OBJ commence à 1 !
    vertex.push_back( OVec3_f(0,0,0) );
	uv.push_back( OVec2_f(0,0) );
	normal.push_back( OVec3_f(0,0,0) );

    while( _readLine(flux) )
	{
        //lecture du code du fichier
        if (!(flux >> code))
            break; //erreur;

		//skip comments
		if (code == "#")
			continue;

		else if (code == "v")
		{
		    flux >> x >> y >> z;
		    //convertion des y up en z up de notre systeme
		    //if (p_z_verticale)
		    //{
                vertex.push_back( OVec3_f(x, -z, y) );
		    //}
		    //else
            //{
            //    vertex.push_back( OVec3_f(x, y, z) );
            //}
		}
		else if (code == "vn") //process vertex normal
		{
		    flux >> x >> y >> z;
		    //if (p_z_verticale)
		    //{
                normal.push_back( OVec3_f(x, -z, y) );
		    //}
		    //else
            //{
            //    normal.push_back( OVec3_f(x, y, z) );
            //}
		}
		else if (code == "vt") //process uv texture
		{
            flux >> x >> y;
			uv.push_back( OVec2_f(x, y) );
		}
		else if (code == "f")
		{
            int v,t,n;
            // face à 3 vertices !!!
            int i = 0;

            for (char c; i < 99; i++)
            {
                v = 0; t = 0; n = 0;
				//v uv n commencent à 1 !
				if (uv.size() == 1  && normal.size() == 1)
                    flux >> v;
                else if (uv.size() == 1)
                    flux >> v >> c >> c >> n;   // "//"
                else if (normal.size() == 1)
                    flux >> v >> c >> t;        // "/"
                else
                    flux >> v >> c >> t >> c >> n;
                if (!flux.good()) break;

                size_t i_som = m_vertex.size();

                m_vertex.push_back(vertex[v]);
                m_normal.push_back(normal[n]);
                m_uv.push_back(uv[t]);

                m_indice.push_back(i_som);
            }
		}

		flux.clear();
	}

    _make_vao();
}

bool Tlake3d_med_1_plan::_readLine(std::istream& flux)
{
	char next;
	while( flux >> std::skipws >> next )
    {
		flux.putback(next);
		if ('#' == next)
			_skipLine(flux);
		else
			return true;
    }

    return false;
}

void Tlake3d_med_1_plan::_skipLine(std::istream& flux)
{
    char next;
	flux >> std::noskipws;
    while( (flux >> next) && ('\n' != next) );
}





void Tlake3d_med_1_plan::draw()
{
    glBindVertexArray(m_vao);

    //if (mode == 0) {
        glDrawElements(GL_TRIANGLES, m_indice.size(), GL_UNSIGNED_INT, 0);
    //}
    //else if (mode == 1) {
    //	glDrawElements(GL_POINTS, m_indice.size(), GL_UNSIGNED_INT, 0);
    //}
    glBindVertexArray(0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glActiveTexture(GL_TEXTURE0);
}

void Tlake3d_med_1_plan::draw_multi()
{
    glBindVertexArray(m_vao);

        glDrawElementsInstanced(GL_TRIANGLES, m_indice.size(), GL_UNSIGNED_INT, 0, m_model_multi.size());

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glActiveTexture(GL_TEXTURE0);
}


// grille unique
OMat4& Tlake3d_med_1_plan::getModel()
{
    return m_model[0];
}

size_t Tlake3d_med_1_plan::getSize()
{
    return m_pos.size();
}







void Tlake3d_med_1_plan::_make_vao()
{
    //génération de l'identifiant du VAO
    glGenVertexArrays(1, &m_vao);
    //activation du VAO
    glBindVertexArray(m_vao);

    // créations des buffers
    //obj_nbr_vao_buffer = 10;
    glGenBuffers(10, m_vao_buffer);

    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(OVec3_f) * m_vertex.size(), &m_vertex[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(LOCATION_POSITION);
    glVertexAttribPointer(LOCATION_POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(OVec3_f) * m_normal.size(), &m_normal[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(LOCATION_NORMAL);
    glVertexAttribPointer(LOCATION_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(OVec2_f) * m_uv.size(), &m_uv[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(LOCATION_TEXCOORD);
    glVertexAttribPointer(LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, 0);

    // 3 4 5 6
    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[LOCATION_MODEL]);
        for (int i = 0; i < 4 ; i++)
        {
            glEnableVertexAttribArray(LOCATION_MODEL + i);
            glVertexAttribPointer(LOCATION_MODEL + i, 4, GL_FLOAT, GL_FALSE, sizeof(OMat4), (const void*)(sizeof(float) * i * 4));
            glVertexAttribDivisor(LOCATION_MODEL + i, 1);
        }

    // >>> il faut définir les buffers pour nos shaders avec bones
    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[7]);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(uint16_t) * meshPart[i_part].boneWeight.size(), &meshPart[i_part].boneWeight[0], GL_STATIC_DRAW);
    glBufferData(GL_ARRAY_BUFFER, sizeof(uint16_t), 0, GL_STATIC_DRAW);
    // !!! notez glVertex(AttribI)Pointer
    glEnableVertexAttribArray(LOCATION_BONE);
    glVertexAttribIPointer(LOCATION_BONE, 4, GL_UNSIGNED_SHORT, 0, BUFFER_OFFSET(0));

    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[8]);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(float) * meshPart[i_part].weight.size(), &meshPart[i_part].weight[0], GL_STATIC_DRAW);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float), 0, GL_STATIC_DRAW);
    glEnableVertexAttribArray(LOCATION_WEIGHT);
    glVertexAttribPointer(LOCATION_WEIGHT, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    //---

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vao_buffer[9]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * m_indice.size(), &m_indice[0], GL_STATIC_DRAW);

    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}





void Tlake3d_med_1_plan::_setModel(size_t idx)
{
    m_model[idx].loadIdentity();
    m_model[idx].translate(m_pos[idx]);

    m_model_multi[idx] = m_model[idx];
    m_model_multi[idx].transpose(); // avec mat4 'horizontale'

    //_setModelMulti(m_model_multi);
    glBindVertexArray(m_vao);
    glBindBuffer(GL_ARRAY_BUFFER, m_vao_buffer[LOCATION_MODEL]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(OMat4) * m_model_multi.size(), &m_model_multi[0], GL_DYNAMIC_DRAW);

    //désactivation du VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

void Tlake3d_med_1_plan::setPos(OVec3_f& pos, size_t idx)
{
    m_pos[idx] = pos;
    _setModel(idx);
}

void Tlake3d_med_1_plan::setPos(float px, float py, float pz, size_t idx)
{
    m_pos[idx].set(px, py, pz);
    _setModel(idx);
}


// --- shader



static const char* pVS = " \n\
#version 330 \n\
 \n\
layout (location = 0) in vec3 in_vertex; \n\
layout (location = 1) in vec3 in_normal; \n\
layout (location = 2) in vec2 in_uv; \n\
layout (location = 3) in mat4 in_model; \n\
 \n\
uniform mat4 uVP; \n\
uniform mat4 uModel; \n\
uniform bool uMulti = false; \n\
 \n\
out vec2 var_uv; \n\
out vec3 var_model; \n\
out vec4 var_clipSpace; \n\
 \n\
void main(){ \n\
  \n\
    if (uMulti) \n\
    { \n\
        gl_Position = uVP * in_model * vec4(in_vertex, 1.0); \n\
        var_clipSpace = gl_Position; \n\
        var_uv = in_uv * 10.0; \n\
        var_model = (in_model * vec4(in_vertex, 1.0)).xyz; \n\
        //var_normal = (in_model * vec4(in_normal, 0.0)).xyz; \n\
        //var_normal = normalize(var_normal); \n\
    } \n\
    else \n\
    { \n\
        gl_Position = uVP * uModel * vec4(in_vertex, 1.0); \n\
        var_clipSpace = gl_Position; \n\
        var_uv = in_uv * 10.0; // tiling \n\
        var_model = (uModel * vec4(in_vertex, 1.0)).xyz; \n\
        //var_normal = (uModel * vec4(in_normal, 0.0)).xyz; \n\
        //var_normal = normalize(var_normal); \n\
    } \n\
}";


static const char* pFS = " \n\
#version 330 core \n\
 \n\
in vec2 var_uv; \n\
in vec3 var_model; \n\
in vec4 var_clipSpace; \n\
 \n\
uniform sampler2D uReflectionMap; \n\
uniform sampler2D uRefractionMap; \n\
uniform sampler2D uDudvMap; \n\
uniform sampler2D uNormalMap; \n\
uniform float uTime; \n\
uniform vec3 uEyePos; \n\
uniform float uLight_ambient = 0.75; \n\
uniform vec3 uLight_dir = vec3(-0.5,0.5,-0.5); // z verticale \n\
uniform vec3 uLight_color = vec3(1.0,1.0,0.9); \n\
uniform float uTurbidity = 0.1; \n\
uniform float uRefractiveFactor = 0.5; \n\
uniform float uWindSpeed = 15.0; \n\
uniform float uWaveStrength = 0.1; // 0->0.25 grosses vaguellettes \n\
// quand la reflection n'est pas correctement possitionnée \n\
uniform vec2 uCorrectif_reflection = vec2(1.02, 1.01); \n\
 \n\
out vec4 out_color; \n\
 \n\
const float shineDamper = 20.0; \n\
const float reflectivity = 0.6; \n\
 \n\
void main(void) { \n\
    vec2 ndc = ((var_clipSpace.xy/var_clipSpace.w) / 2.0) + 0.5; \n\
    vec2 uv_reflection = vec2(ndc.x*uCorrectif_reflection.x, -ndc.y*uCorrectif_reflection.y); \n\
    vec2 uv_refraction = vec2(ndc.x*uCorrectif_reflection.x,  ndc.y*uCorrectif_reflection.y); \n\
 \n\
    // decalage vaguelette \n\
    float move = uTime * (0.0005 + uWindSpeed*0.00005); \n\
    vec2 distortedTexCoords = texture(uDudvMap, vec2(var_uv.x + move, var_uv.y)).rg * uWaveStrength; \n\
    distortedTexCoords = var_uv + vec2(distortedTexCoords.x, distortedTexCoords.y+move); \n\
    vec2 totalDistortion = (texture(uDudvMap, distortedTexCoords).rg * 2.0 - 1.0); \n\
 \n\
    uv_reflection += totalDistortion * 0.1; \n\
    //uv_reflection.x = clamp(uv_reflection.x, 0.001,0.999); \n\
    //uv_reflection.y = clamp(uv_reflection.y, -0.999, -0.001); \n\
 \n\
    uv_refraction += totalDistortion; \n\
    uv_refraction = clamp(uv_refraction, 0.001, 0.999); \n\
 \n\
    vec4 reflectColor = texture(uReflectionMap, uv_reflection); \n\
    vec4 refractColor = texture(uRefractionMap, uv_refraction); \n\
 \n\
    vec3 viewVector = normalize(uEyePos - var_model); \n\
 \n\
    vec4 normalMapColor = texture(uNormalMap, distortedTexCoords); \n\
    vec3 normal = normalize(normalMapColor.rgb); \n\
 \n\
    vec3 reflectedLight = reflect(uLight_dir,normal); \n\
    float specular = max(dot(reflectedLight, viewVector), 0.0); \n\
    specular = pow(specular, shineDamper); \n\
    vec3 specularHighlights = uLight_color * specular * reflectivity; \n\
 \n\
    out_color = mix(refractColor, reflectColor, uRefractiveFactor); \n\
    //out_color = mix(out_color, vec4(0.0,0.03,0.5,1.0), 0.1) + vec4(specularHighlights,0.0); \n\
    out_color = (out_color + vec4(specularHighlights,0.0)) * (uLight_ambient + 0.15); // ambient est généralement limité à 0.8 \n\
    float alpha = length(uEyePos - var_model) * uTurbidity; \n\
    out_color.a = clamp(alpha, 1.0-uLight_ambient, 1.0); \n\
}";



Tlake3d_med_1_sh::Tlake3d_med_1_sh()
{
	//
}

bool Tlake3d_med_1_sh::create()
{
	if (!OShader::init())
	{
		ECO_error_set("erreur Tlake3d_med_1_sh.init");
		return false;
	}
	if (!addShader(GL_VERTEX_SHADER, pVS))
	{
		ECO_error_set("erreur Tlake3d_med_1_sh.addShader vs");
		return false;
	}
	if (!addShader(GL_FRAGMENT_SHADER, pFS))
	{
		ECO_error_set("erreur Tlake3d_med_1_sh.addShader fs");
		return false;
	}
	if (!finalize())
	{
		ECO_error_set("erreur Tlake3d_med_1_sh.finalize");
		return false;
	}

	m_vp = getUniformLocation("uVP");
    m_model = getUniformLocation("uModel");
    m_multi = getUniformLocation("uMulti");

    m_time = getUniformLocation("uTime");
    m_eyePos = getUniformLocation("uEyePos");

    m_refractionMap = getUniformLocation("uRefractionMap");
    m_reflectionMap = getUniformLocation("uReflectionMap");
    m_normalMap = getUniformLocation("uNormalMap");
    m_dudvMap = getUniformLocation("uDudvMap");

    m_light_ambient = getUniformLocation("uLight_ambient");
    m_light_dir = getUniformLocation("uLight_dir");
    m_light_color = getUniformLocation("uLight_color");

    m_turbidity = getUniformLocation("uTurbidity");
    m_waveStrength = getUniformLocation("uWaveStrength");
    m_windSpeed = getUniformLocation("uWindSpeed");

/*
    if (m_vp == INVALID_UNIFORM_LOCATION
    || m_model == INVALID_UNIFORM_LOCATION
    || m_time == INVALID_UNIFORM_LOCATION
    || m_eyePos == INVALID_UNIFORM_LOCATION
    || m_refractionMap == INVALID_UNIFORM_LOCATION
    || m_reflectionMap == INVALID_UNIFORM_LOCATION
    || m_normalMap == INVALID_UNIFORM_LOCATION
    || m_waterMap == INVALID_UNIFORM_LOCATION
    || m_light_ambient == INVALID_UNIFORM_LOCATION
    || m_light_dir == INVALID_UNIFORM_LOCATION
    || m_light_color == INVALID_UNIFORM_LOCATION
    || m_turbidity == INVALID_UNIFORM_LOCATION
    || m_waveStrength == INVALID_UNIFORM_LOCATION
    || m_windSpeed == INVALID_UNIFORM_LOCATION
    )
    {
        ECO_error_set("Echec Tlake3d_med_1_sh 0");
        return false;
    }
*/

    return true;
}

void Tlake3d_med_1_sh::setVP(const OMat4& vp)
{
    glUniformMatrix4fv(m_vp, 1, GL_TRUE, vp.getFv());
}

void Tlake3d_med_1_sh::setModel(const OMat4& model)
{
    glUniformMatrix4fv(m_model, 1, GL_TRUE, model.getFv());
}

void Tlake3d_med_1_sh::setMulti(bool mode)
{
    glUniform1i(m_multi, mode);
}



void Tlake3d_med_1_sh::setEyePos(const OVec3_f& eyePos)
{
    glUniform3f(m_eyePos, eyePos.x, eyePos.y, eyePos.z);
}




void Tlake3d_med_1_sh::setLight(float ambient, const OVec3_f& direction, const OVec3_f& color)
{
    glUniform1f(m_light_ambient, ambient);
    glUniform3f(m_light_color, color.r, color.g, color.b);

    OVec3_f dir = direction;
    dir.normalize();
    glUniform3f(m_light_dir, dir.x, dir.y, dir.z);
}




void Tlake3d_med_1_sh::setTextures(uint32_t refraction, uint32_t normal, uint32_t reflection, uint32_t dudv)
{

    glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, refraction);
    glUniform1i(m_refractionMap, 3);

    glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, normal);
    glUniform1i(m_normalMap, 2);

    glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, dudv);
    glUniform1i(m_dudvMap, 1);

    glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, reflection);
    glUniform1i(m_reflectionMap, 0);

    //glActiveTexture(GL_TEXTURE0);
}

// m_time +1.0f
void Tlake3d_med_1_sh::setTime(float value)
{
    glUniform1f(m_time, value);
}

void Tlake3d_med_1_sh::setTurbidity(float value)
{
    glUniform1f(m_turbidity, value);
}




void Tlake3d_med_1_sh::setWaveStrength(float value)
{
    glUniform1f(m_waveStrength, value);
}

void Tlake3d_med_1_sh::setWindSpeed(float value)
{
    glUniform1f(m_windSpeed, value);
}


// --- shader pour l'affichage eau dans le stencil ---
// !!! idem shader principal !!!

static const char* pVS_w = " \n\
#version 330 core \n\
 \n\
layout (location = 0) in vec3 in_vertex; \n\
layout (location = 1) in vec3 in_normal; \n\
layout (location = 2) in vec2 in_uv; \n\
layout (location = 3) in mat4 in_model; \n\
 \n\
uniform mat4 uVP; \n\
uniform mat4 uModel; \n\
uniform bool uMulti = false; \n\
 \n\
void main() \n\
{ \n\
    if (uMulti) \n\
    { \n\
        gl_Position = uVP * in_model * vec4(in_vertex, 1.0); \n\
    } \n\
    else \n\
    { \n\
        gl_Position = uVP * uModel * vec4(in_vertex, 1.0); \n\
    } \n\
}";


static const char* pFS_w = " \n\
#version 330 core \n\
 \n\
out vec4 out_color; \n\
 \n\
void main(){ \n\
    out_color = vec4(1,1,1,1); \n\
}";



Tlake3d_med_1_shw::Tlake3d_med_1_shw()
{
	//
}

bool Tlake3d_med_1_shw::create()
{
    if (!OShader::init())
    {
        ECO_error_set("echec init Tlake3d_med_1_shw");
        return false;
    }
    if (!addShader(GL_VERTEX_SHADER, pVS_w))
    {
        ECO_error_set("echec add vertex Tlake3d_med_1_shw");
        return false;
    }
    if (!addShader(GL_FRAGMENT_SHADER, pFS_w))
    {
        ECO_error_set("echec add fragment Tlake3d_med_1_shw");
        return false;
    }
    if (!finalize())
    {
        ECO_error_set("echec finalize Tlake3d_med_1_shw");
        return false;
    }

    m_vp = getUniformLocation("uVP");
    m_model = getUniformLocation("uModel");
    m_multi = getUniformLocation("uMulti");

/*
	if (m_vp == INVALID_UNIFORM_LOCATION
    || m_model == INVALID_UNIFORM_LOCATION
    || m_multi == INVALID_UNIFORM_LOCATION
    || m_colorGray == INVALID_UNIFORM_LOCATION
    || m_colorMul == INVALID_UNIFORM_LOCATION
    || m_colorMap == INVALID_UNIFORM_LOCATION
    || m_normalMap == INVALID_UNIFORM_LOCATION
    || m_specularMap == INVALID_UNIFORM_LOCATION
    )
    {
        ECO_error_set("Echec Tlake3d_med_1_shw");
        return false;
    }
*/
    return true;
}

void Tlake3d_med_1_shw::setVP(const OMat4& vp)
{
    glUniformMatrix4fv(m_vp, 1, GL_TRUE, vp.getFv());
}

void Tlake3d_med_1_shw::setModel(const OMat4& model)
{
    glUniformMatrix4fv(m_model, 1, GL_TRUE, model.getFv());
}

void Tlake3d_med_1_shw::setMulti(bool mode)
{
    glUniform1i(m_multi, mode);
}





