////////////////////////////////////////////////
//
// decals
//
////////////////////////////////////////////////

// decaltype:
//    e -> reserve envmap texture slot
//    r -> envmap reflection
//    R -> modulate envmap reflection with spec map
//    s -> spec
//    S -> spec map
//    n -> normal map
//    p -> parallax
//    g -> glow
//    G -> pulse glow
//    b -> keep normals
//    0 -> pass 0
//    1 -> pass 1

dtopt = [ >= (strstr $decaltype $arg1) 0 ]

decalvariantshader = [
    local decaltype
    decaltype = $arg2
    stype = (? (dtopt "e") 3 1)
    srow = (? (dtopt "1") 0 -1)
    if (dtopt "G") [
        stype = (+ $stype 0x10)
        defuniformparam "glowcolor" 1 1 1 // glow color
        defuniformparam "pulseglowspeed" 1     // pulse frequency (Hz)
        defuniformparam "pulseglowcolor" 0 0 0 // pulse glow color
    ] [if (dtopt "g") [
        defuniformparam "glowcolor" 1 1 1  // glow color
    ]]
    if (dtopt "R") [
        defuniformparam "envscale" 1 1 1 // reflectivity map multiplier
    ] [if (dtopt "r") [
        defuniformparam "envscale" 0.2 0.2 0.2 // reflectivity
    ]]
    reuseuniformparam "gloss" 1 // glossiness
    if (dtopt "S") [
        defuniformparam "specscale" 2 2 2 // spec map multiplier
    ] [if (dtopt "s") [
        defuniformparam "specscale" 1 1 1 // spec multiplier
    ]]
    if (dtopt "p") [
        defuniformparam "parallaxscale" 0.06 -0.03 // parallax scaling
    ]
    if (dtopt "n") [
        defuniformparam "bumpblend" 1 // alpha-blend strength for normals
    ]
    variantshader $stype $arg1 $srow [
        in vec4 vvertex;
        @(? (dtopt "n") [
            in vec4 vtangent;
            out mat3 world;
        ] [
            out vec3 nvec;
        ])
        in vec4 vnormal;
        in vec3 vtexcoord0;
        uniform mat4 camprojmatrix;
        out vec4 texcoord0;
        @(? (|| (dtopt "p") (dtopt "r")) [
            uniform vec3 camera;
            out vec3 camvec;
        ])
        @(? (dtopt "G") [uniform float millis; flat out float pulse;])
        void main(void)
        {
            gl_Position = camprojmatrix * vvertex;
            texcoord0.xyz = vtexcoord0;
            texcoord0.w = 3.0*vnormal.w;

            @(? (dtopt "n") [
                vec3 bitangent = cross(vnormal.xyz, vtangent.xyz) * vtangent.w;
                // calculate tangent -> world transform
                world = mat3(vtangent.xyz, bitangent, vnormal.xyz);
            ] [
                nvec = vnormal.xyz;
            ])

            @(? (|| (dtopt "p") (dtopt "r")) [
                camvec = camera - vvertex.xyz;
            ])

            @(? (dtopt "G") [
                pulse = abs(fract(millis*pulseglowspeed.x)*2.0 - 1.0);
            ])
        }
    ] [
        @(cond [dtopt "0"] [result [
            layout(location = 0) out vec4 gcolor;
            layout(location = 0, index = 1) out vec4 gcolorblend;
        ]] [dtopt "1"] [
            ? $usepacknorm [
                layout(location = 0) out vec4 gnormal;
            ] [
                layout(location = 0) out vec4 gnormal;
                layout(location = 0, index = 1) out vec4 gnormalblend;
            ]
        ] [result [
            layout(location = 0) out vec4 gcolor;
            layout(location = 1) out vec4 gnormal;
        ]])
        uniform sampler2D diffusemap;
        uniform vec4 colorparams;
        in vec4 texcoord0;
        @(? (dtopt "n") [
            uniform sampler2D normalmap;
            in mat3 world;
        ] [
            in vec3 nvec;
        ])
        @(? (|| (dtopt "p") (dtopt "r")) [in vec3 camvec;])
        @(? (|| (dtopt "g") (dtopt "S")) [uniform sampler2D glowmap;])
        @(? (dtopt "G") [flat in float pulse;])
        @(? (dtopt "r") [uniform samplerCube envmap;])
        void main(void)
        {
            @(if (dtopt "n") [result [
                @(? (dtopt "p") [
                    float height = texture(normalmap, texcoord0.xy).a;
                    vec3 camvecn = normalize(camvec);
                    vec2 dtc = texcoord0.xy + (camvecn * world).xy*(height*parallaxscale.x + parallaxscale.y);
                ] [
                    #define dtc texcoord0.xy
                ])

                @(? (|| (! (dtopt "0")) (dtopt "r")) [
                    vec3 bump = texture(normalmap, dtc).rgb*2.0 - 1.0;
                    vec3 bumpw = world * bump;
                    #define nvec bumpw
                ])
            ]] [result [
                #define dtc texcoord0.xy
            ]])

            vec4 diffuse = texture(diffusemap, dtc);

            @(if (dtopt "g") [result [
                vec4 glowspec = texture(glowmap, dtc);
                #define glow glowspec.rgb
                #define spec glowspec.a
                glow *= @(? (dtopt "G") [mix(glowcolor.xyz, pulseglowcolor.xyz, pulse)] [glowcolor.xyz]);
                glow *= diffuse.a;
            ]])

            @(if (dtopt "0") [result [
                @(if (&& (dtopt "S") [! (dtopt "g")]) [result [
                    float spec = @(? (|| (! (dtopt "n")) (dtopt "p")) [texture(glowmap, dtc).r] [texture(normalmap, dtc).a]);
                ]])
                @(gspecpack [gloss.x] (if (dtopt "s") [? (dtopt "S") [spec * specscale.x] [specscale.x]]))
            ]])

            @(if (dtopt "1") [
                ? (dtopt "g") [
                   vec3 gcolor = diffuse.rgb*colorparams.rgb;
                ]
            ] [result [
                gcolor.rgb = diffuse.rgb*colorparams.rgb;

                @(if (dtopt "r") [result [
                    @(? (|| (! (dtopt "n")) (! (dtopt "p"))) [
                        vec3 camvecn = normalize(camvec);
                    ])
                    float invfresnel = dot(camvecn, nvec);
                    vec3 rvec = 2.0*nvec*invfresnel - camvecn;
                    vec3 reflect = texture(envmap, rvec).rgb * diffuse.a;
                    @(? (dtopt "R") [
                        vec3 rmod = envscale.xyz*spec;
                    ] [
                        #define rmod envscale.xyz
                    ])
                    reflect *= diffuse.a;
                    gcolor.rgb = mix(gcolor.rgb, reflect, rmod*clamp(1.0 - invfresnel, 0.0, 1.0));
                ]])
            ]])

            @(if (dtopt "g") [gglowpack glow packnorm])

            @(if (! (dtopt "0")) [result [
                vec3 normal = normalize(nvec);
                @(gnormpackdef normal packnorm)
            ]])

            float inside = clamp(texcoord0.z, 0.0, 1.0) * clamp(texcoord0.w, 0.0, 1.0);
            float alpha = inside * diffuse.a;
            @(cond [dtopt "0"] [result [
                gcolor.rgb *= inside;
                gcolor.a *= alpha;
                gcolorblend = vec4(alpha);
            ]] [dtopt "1"] [
                ? $usepacknorm [
                    gnormal.a = alpha * bumpblend.x;
                ] [
                    gnormalblend = vec4(alpha * bumpblend.x);
                ]
            ] [result [
                gcolor.rgb *= inside;
                gcolor.a = alpha;
                @(? (dtopt "b") [
                    gnormal = vec4(0.0);
                ] [
                    gnormal.rgb *= alpha * bumpblend.x;
                    gnormal.a = alpha * bumpblend.x;
                ])
            ]])
        }
    ]
]

decalshader = [
    decaltype = $arg2
    stype = (? (dtopt "e") 3 1)
    defershader $stype $arg1 [
        if $maxdualdrawbufs [
            decalvariantshader @@arg1 @@(concatword $arg2 "0")
            if @@(! (dtopt "b")) [
                decalvariantshader @@@arg1 @@@(concatword $arg2 "1")
            ]
        ] [
            decalvariantshader @@arg1 @@arg2
        ]
    ]
]

decalshader "stddecal" "b"
decalshader "specdecal" "bs"
decalshader "specmapdecal" "bsS"

decalshader "glowdecal" "g"
decalshader "pulseglowdecal" "gG"

decalshader "envdecal" "ber"
decalshader "envspecdecal" "besr"
decalshader "envspecmapdecal" "besSrR"
decalshader "envglowdecal" "erg"
decalshader "envpulseglowdecal" "ergG"

decalshader "bumpdecal" "n"
decalshader "bumpspecdecal" "ns"
decalshader "bumpspecmapdecal" "nsS"

decalshader "bumpglowdecal" "ng"
decalshader "bumpspecglowdecal" "nsg"
decalshader "bumpspecmapglowdecal" "nsSg"

decalshader "bumppulseglowdecal" "ngG"
decalshader "bumpspecpulseglowdecal" "nsgG"
decalshader "bumpspecmappulseglowdecal" "nsSgG"

decalshader "bumpparallaxdecal" "np"
decalshader "bumpspecparallaxdecal" "nps"
decalshader "bumpspecmapparallaxdecal" "npsS"

decalshader "bumpparallaxglowdecal" "npg"
decalshader "bumpspecparallaxglowdecal" "npsg"
decalshader "bumpspecmapparallaxglowdecal" "npsSg"

decalshader "bumpparallaxpulseglowdecal" "npgG"
decalshader "bumpspecparallaxpulseglowdecal" "npsgG"
decalshader "bumpspecmapparallaxpulseglowdecal" "npsSgG"

decalshader "bumpenvdecal" "ner"
decalshader "bumpenvspecdecal" "nesr"
decalshader "bumpenvspecmapdecal" "nesSrR"

decalshader "bumpenvglowdecal" "nerg"
decalshader "bumpenvspecglowdecal" "neosrg"
decalshader "bumpenvspecmapglowdecal" "nesSrRg"

decalshader "bumpenvpulseglowdecal" "neorgG"
decalshader "bumpenvspecpulseglowdecal" "nesrgG"
decalshader "bumpenvspecmappulseglowdecal" "nesSrRgG"

decalshader "bumpenvparallaxdecal" "nepr"
decalshader "bumpenvspecparallaxdecal" "nepsr"
decalshader "bumpenvspecmapparallaxdecal" "nepsSrR"

decalshader "bumpenvparallaxglowdecal" "neprg"
decalshader "bumpenvspecparallaxglowdecal" "nepsrg"
decalshader "bumpenvspecmapparallaxglowdecal" "nepsSrRg"

decalshader "bumpenvparallaxpulseglowdecal" "neprgG"
decalshader "bumpenvspecparallaxpulseglowdecal" "nepsrgG"
decalshader "bumpenvspecmapparallaxpulseglowdecal" "nepsSrRgG"

