
#include "Tsh_rain.h"


static const char* pVS = " \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\
out vec2 var_uv; \n\
 \n\
void main() \n\
{ \n\
    if (uMulti) \n\
    { \n\
        gl_Position = uVP * in_model * vec4(in_vertex, 1.0); \n\
        var_uv = in_uv; \n\
    } \n\
    else \n\
    { \n\
        gl_Position = uVP * uModel * vec4(in_vertex, 1.0); \n\
        var_uv = in_uv; \n\
    } \n\
}";


static const char* pFS = " \n\
#version 330 core \n\
 \n\
in vec2 var_uv; \n\
 \n\
uniform sampler2D uColorMap; // 'couleur' de l'eau \n\
uniform float uTime; // +1.0 \n\
uniform float uTurbidity = 0.85; // 0.1 clair 0.9 opaque \n\
uniform float uAmbient; \n\
 \n\
out vec4 out_color; \n\
 \n\
// Maximum number of cells a ripple can cross. \n\
#define MAX_RADIUS 2 \n\
// Set to 1 to hash twice. Slower, but less patterns. \n\
//#define DOUBLE_HASH 0 \n\
// Hash functions shamefully stolen from: \n\
// https://www.shadertoy.com/view/4djSRW \n\
#define HASHSCALE1 .1031 \n\
#define HASHSCALE3 vec3(.1031, .1030, .0973) \n\
 \n\
float hash12(vec2 p) \n\
{ \n\
	vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1); \n\
	p3 += dot(p3, p3.yzx + 19.19); \n\
	return fract((p3.x + p3.y) * p3.z); \n\
} \n\
 \n\
vec2 hash22(vec2 p) \n\
{ \n\
	vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3); \n\
	p3 += dot(p3, p3.yzx+19.19); \n\
	return fract((p3.xx+p3.yz)*p3.zy); \n\
} \n\
 \n\
void main() \n\
{ \n\
    vec2 nbripple = vec2(80,50); \n\
    vec3 color = texture(uColorMap, var_uv).rgb; \n\
    float resolution = nbripple.x * exp2(-3.0); \n\
	vec2 uv2 = var_uv / 1.0 * resolution; \n\
    vec2 pos = floor(uv2); \n\
    float time = (uTime*0.25) / nbripple.y; \n\
 \n\
    vec2 circles = vec2(0.); \n\
    for (int j = -MAX_RADIUS; j <= MAX_RADIUS; j++) \n\
    { \n\
        for (int i = -MAX_RADIUS; i <= MAX_RADIUS; i++) \n\
        { \n\
			vec2 pi = pos + vec2(i, j); \n\
            //#if DOUBLE_HASH \n\
            //vec2 hsh = hash22(pi); \n\
            //#else \n\
            vec2 hsh = pi; \n\
            //#endif \n\
            vec2 p = pi + hash22(hsh); \n\
 \n\
            float t = fract(0.3*time + hash12(hsh)); \n\
            vec2 v = p - uv2; \n\
            float d = length(v) - (float(MAX_RADIUS) + 1.)*t; \n\
 \n\
            float h = 1e-3; \n\
            float d1 = d - h; \n\
            float d2 = d + h; \n\
            float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); \n\
            float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); \n\
            circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t)); \n\
        } \n\
    } \n\
    circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1)); \n\
 \n\
    float intensity = mix(0.01, 0.15, smoothstep(0.1, 0.6, abs(fract(0.05*time + 0.5)*2.-1.))); \n\
    vec3 n = vec3(circles, sqrt(1. - dot(circles, circles))); \n\
    color = texture(uColorMap, uv2/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n, normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.); \n\
 \n\
	out_color = vec4(color, uTurbidity) * uAmbient; \n\
}";




Tsh_rain::Tsh_rain()
{
    //
}

bool Tsh_rain::create()
{
    if (!OShader::init())
    {
        ECO_error_set("err Tsh_rain init");
        return false;
    }
    if (!addShader(GL_VERTEX_SHADER, pVS))
    {
        ECO_error_set("err Tsh_rain pvs");
        return false;
    }
    if (!addShader(GL_FRAGMENT_SHADER, pFS))
    {
        ECO_error_set("err Tsh_rain pfs");
        return false;
    }
    if (!finalize())
    {
        ECO_error_set("err Tsh_rain finalize");
        return false;
    }

    m_vp = getUniformLocation("uVP");
    m_model = getUniformLocation("uModel");
    m_colorMap = getUniformLocation("uColorMap");
    m_time = getUniformLocation("uTime");
    m_multi = getUniformLocation("uMulti");
    m_turbidity = getUniformLocation("uTurbidity");
    m_ambient = getUniformLocation("uAmbient");
/*
    if (m_vp == INVALID_UNIFORM_LOCATION
        || m_model == INVALID_UNIFORM_LOCATION
        || m_colorMap == INVALID_UNIFORM_LOCATION
        || m_time == INVALID_UNIFORM_LOCATION
        || m_multi == INVALID_UNIFORM_LOCATION
        || m_turbidity == INVALID_UNIFORM_LOCATION
        || m_ambient == INVALID_UNIFORM_LOCATION
        )
        return false;
*/
    return true;
}

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

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

void Tsh_rain::setTexture(uint32_t texture)
{
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glUniform1i(m_colorMap, 0);

    //glActiveTexture(GL_TEXTURE0);
}

void Tsh_rain::setTime(float value)
{
    glUniform1f(m_time, value);
}

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

void Tsh_rain::setAmbient(float value)
{
    glUniform1f(m_ambient, value);
}

