//#####################################################################
// Copyright 2021, Craig Schroeder.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################

#include <Core/Log/DEBUG_UTILITIES.h>
#include "QT_FRAGMENT_SHADER.h"
#include "QT_SHADER_FLAGS.h"
#include <string>
namespace PhysBAM{

std::string Generate_Fragment_Shader_Shaded(SHADER_FLAGS flags)
{
    // !(flags&(flag_select|flag_flat_col))
    bool c=flags.col==2;
    bool C=flags.col==1;
    bool b=flags.bg_col==2;
    bool B=flags.bg_col==1;
    bool g=flags.bg_col>0;
    std::string x;
    PHYSBAM_ASSERT(c||C);
    PHYSBAM_ASSERT(!g||b||B);

    if(1) x+="#version 420\n";
    if(1) x+="layout(location = 0) out vec4 frag_color;\n";
    if(1) x+="float pi=4.0*atan(1.0);\n";
    if(1) x+="\n";
    if(1) x+="in vec4 world_pos;\n";
    if(c) x+="in vec3 col;\n";
    if(b) x+="in vec3 bgcol;\n";
    if(1) x+="in vec3 normal;\n";
    if(1) x+="\n";
    if(1) x+="uniform float shininess;\n";
    if(1) x+="uniform float ambient_brightness;\n";
    if(1) x+="uniform vec3 specular_color;\n";
    if(1) x+="uniform vec3 camera_pos;\n";
    if(1) x+="uniform vec3 light_pos[2];//={vec3(0.3,0.3,1),vec3(-0.3,0.3,1)};\n";
    if(C) x+="uniform vec3 col;\n";
    if(B) x+="uniform vec3 bgcol;\n";
    if(1) x+="\n";
    if(1) x+="float light_power[2]={0.3,0.3};\n";
    if(1) x+="int num_light=2;\n";
    if(1) x+="\n";
    if(1) x+="void main() {\n";
    if(1) x+="   vec3 color=col;\n";
    if(g) x+="   if(!gl_FrontFacing) color = bgcol;\n";
    if(1) x+="   vec3 result = ambient_brightness * color;\n";
    if(1) x+="   for(int l=0;l<num_light;l++)\n";
    if(1) x+="   {\n";
    if(1) x+="       vec3 light_vec=(light_pos[l] - world_pos.xyz);\n";
    if(1) x+="       vec3 dir = normalize(light_vec);\n";
    if(1) x+="       vec3 N = normalize(normal);\n";
    if(1) x+="       vec3 eye_dir = normalize(camera_pos-world_pos.xyz);\n";
    if(1) x+="       if(dot(N,eye_dir)<0) N=-N;\n";
    if(1) x+="       float L_dot_N = dot(dir,N);\n";
    if(1) x+="       if(L_dot_N<=0) continue;\n";
    if(1) x+="       float L_N = L_dot_N;\n";
    if(1) x+="       float falloff=4.0*pi/dot(light_vec,light_vec);falloff=1;\n";
    if(1) x+="       float light=light_power[l]*falloff;\n";
    if(1) x+="       result += L_N * color * light;\n";
    if(1) x+="       if(shininess<=0) continue;\n";
    if(1) x+="       vec3 reflected_dir=N*(2.0*L_dot_N)-dir;\n";
    if(1) x+="       float R_dot_N = max(dot(eye_dir,reflected_dir),0.0);\n";
    if(1) x+="       float R = pow(R_dot_N,shininess);\n";
    if(1) x+="       result += R * specular_color * light;\n";
    if(1) x+="   }\n";
    if(1) x+="   frag_color = vec4(result,1);\n";
    if(1) x+="}\n";

    return x;
}

std::string Generate_Fragment_Shader_Select(SHADER_FLAGS flags)
{
    PHYSBAM_ASSERT(flags.col==0);
    PHYSBAM_ASSERT(flags.bg_col==0);
    PHYSBAM_ASSERT(flags.flat_col);

    // flags.select
    std::string x;

    if(1) x+="#version 420\n";
    if(1) x+="layout(location = 0) out vec4 frag_color;\n";
    if(1) x+="\n";
    if(1) x+="in vec4 world_pos;\n";
    if(1) x+="uniform int first_id;\n";
    if(1) x+="void main() {\n";
    if(1) x+="   int id=first_id+gl_PrimitiveID;\n";
    if(1) x+="   int r=id%256;id/=256;\n";
    if(1) x+="   int g=id%256;id/=256;\n";
    if(1) x+="   int b=id%256;\n";
    if(1) x+="   int a=255;\n";
    if(1) x+="   frag_color = vec4(r/255.0,g/255.0,b/255.0,a/255.0);\n";
    if(1) x+="}\n";

    return x;
}

std::string Generate_Fragment_Shader_Flat(SHADER_FLAGS flags)
{
    // !flags.select && flags.flat_col
    bool c=flags.col==2;
    bool C=flags.col==1;
    bool b=flags.bg_col==2;
    bool B=flags.bg_col==1;
    bool g=flags.bg_col>0;
    std::string x;
    PHYSBAM_ASSERT(c||C);
    PHYSBAM_ASSERT(!g||b||B);

    if(1) x+="#version 420\n";
    if(1) x+="layout(location = 0) out vec4 frag_color;\n";
    if(1) x+="\n";
    if(1) x+="in vec4 world_pos;\n";
    if(c) x+="in vec3 col;\n";
    if(b) x+="in vec3 bgcol;\n";
    if(1) x+="\n";
    if(C) x+="uniform vec3 col;\n";
    if(B) x+="uniform vec3 bgcol;\n";
    if(1) x+="\n";
    if(1) x+="void main() {\n";
    if(1) x+="   vec3 color=col;\n";
    if(g) x+="   if(!gl_FrontFacing) color = bgcol;\n";
    if(1) x+="   frag_color = vec4(color,1);\n";
    if(1) x+="}\n";

    return x;
}

std::string Generate_Fragment_Shader(SHADER_FLAGS flags)
{
    if(flags.select) return Generate_Fragment_Shader_Select(flags);
    if(flags.flat_col) return Generate_Fragment_Shader_Flat(flags);
    return Generate_Fragment_Shader_Shaded(flags);
}

}
