uniform sampler2D    uColorMap; // Diffuse & reflectionMap Mask
uniform sampler2D    uNormalMap; // Normal Map & Illum Map (could be Spec Int)
uniform sampler2D    uDecalMap; // Decals
uniform sampler2D    uFlashermap; // Flasher & reflection Map

varying vec2         vTexCoord;
varying vec3         vEyeVector;   // These are all in tangent space
varying vec3         vLight0Vector;
varying vec3         vLight1Vector;

// Constants
   const float KspecExponent = 5.0;
   const float kDecalCount = 1.0;
   const vec4  Decal1_Scale_and_Position = vec4(0.48, 0.48, 7.0, 1.15); //  decal 1
// Set up 'Flasher' colours
   const vec3 blueflasher = vec3(0.0, 0.0, 1.0);
   const vec3 purpleflasher = vec3(1.0, 0.0, 1.0);

// Uniforms from Oolite
   uniform float  uTime;
   uniform bool   nearly_dead;
   uniform bool   isHostile;   
   uniform float  hull_heat_level;
   uniform float  uDecalSelect; // used to decide which decal to select   
   uniform vec4   DecalColor;

// Irregular flickering function
   #ifdef OO_REDUCED_COMPLEXITY 
   #define Pulse(v, ts) ((v) * 0.95) 
   #define Blink_on_off(value) (1.0)
   #else
     float Pulse(float value, float timeScale)
     {
        float t = uTime * timeScale;   

        float s0 = t;
        s0 -= floor(s0);
        float sum = abs( s0 - 0.5);
   
        float s1 = t * 0.7 - 0.05;
        s1 -= floor(s1);
        sum += abs(s1 - 0.5) - 0.25;
   
        float s2 = t * 1.3 - 0.3;
        s2 -= floor(s2);
        sum += abs(s2 - 0.5) - 0.25;
   
        float s3 = t * 5.09 - 0.6;
        s3 -= floor(s3);
        sum += abs(s3 - 0.5) - 0.25;

        return (sum * 0.1 + 0.9) * value;
      }

// Hull Temperate heat glow effect
     vec3 TemperatureGlow(float level) 
     { 
        vec3 result = vec3(0); 
    
        result.r = level; 
        result.g = level * level * level; 
        result.b = max(level - 0.7, 0.0) * 2.0;
        return result;    
     } 
     
// Blink_on_off_function.
   float Blink_on_off(float timeScale)
   {
   float result = step(0.5, sin(uTime * timeScale));
   return result;
   }     
     
#endif

float wave(float t) // Wave function from freaky Thargoids (used here to animate the emergency 'flashers'
{
   return sin(t * 6.28318530718) * 0.8 + 0.25;
}  

void Light(in vec3 lightVector, in vec3 normal, in vec3 lightColor, in vec3 eyeVector, 
           in float KspecExponent, inout vec3 totalDiffuse, inout vec3 totalSpecular)
{
   lightVector = normalize(lightVector);
   vec3 reflection = normalize(-reflect(lightVector, normal));
   
   totalDiffuse += gl_FrontMaterial.diffuse.rgb * lightColor * max(dot(normal, lightVector), 0.0);
   totalSpecular += lightColor * pow(max(dot(reflection, eyeVector), 0.0), KspecExponent);
}


#define LIGHT(idx, vector) Light(vector, normal, gl_LightSource[idx].diffuse.rgb, eyeVector, KspecExponent, diffuse, specular)

#ifndef OO_REDUCED_COMPLEXITY 
/* function to read in the colour map then scale and position the decal map onto it.
   This is slightly different to the cobraIII shader as the viper has an extra 'environment'
   or 'reflection' component */  
vec3 diffuseColor(vec4 Your_Decal_Settings) 
{ 
   vec3 eyeVector = normalize(vEyeVector);
   vec2 reflectioneffect = vTexCoord  * eyeVector.xy * vec2(-1.0, 1.0);
  
  // Setup the basic texture co-ords for the decals 
     vec2 decal_TexCoord = vTexCoord; 
    
// Position the decal     
    decal_TexCoord -= vec2(Your_Decal_Settings.s, Your_Decal_Settings.t - (0.5 / Your_Decal_Settings.p)); 

// Orientate & scale the decal  
    float decal_s = sin(Your_Decal_Settings.q); 
    float decal_c = cos(Your_Decal_Settings.q); 
    decal_TexCoord *= mat2(decal_c, decal_s, -decal_s, decal_c);  // i'ts  -decal_s when exported back to oolite

    decal_TexCoord += vec2(0.5 / Your_Decal_Settings.p); 
    decal_TexCoord *= vec2(Your_Decal_Settings.p / kDecalCount, Your_Decal_Settings.p); 
     
// Select the desired decal from the set. 
    float offset = floor(uDecalSelect * kDecalCount) / kDecalCount; 
    decal_TexCoord.s += offset; 
    
// Get texture values. 
   vec3 baseTex = texture2D(uColorMap, vTexCoord).rgb;
   float reflecmaskMap = texture2D(uColorMap, vTexCoord).a; 
   float decal_Tex = texture2D(uDecalMap, decal_TexCoord).g;
   float reflectionMap = texture2D(uFlashermap, reflectioneffect).g;
    decal_Tex *= step(offset, decal_TexCoord.s) * 
                step(0.0, decal_TexCoord.t) * 
                step(-1.0 / kDecalCount - offset, -decal_TexCoord.s) * 
                step(-1.0, -decal_TexCoord.t); 
 // float mask = baseTex.a - decalTex;

// return mix(reflectionMap * vec3(0.5531, 0.8296, 0.8296) * reflecmaskMap, baseTex + decal_Tex * DecalColor.rgb, 0.6); 
   return reflectionMap * vec3(0.5531, 0.8296, 0.8296) * reflecmaskMap + baseTex + decal_Tex * DecalColor.rgb; 
}      
#endif  

void main()
{
   vec3 eyeVector = normalize(vEyeVector);
   vec3 normal = normalize(texture2D(uNormalMap, vTexCoord).rgb - 0.5);
   float IllumMap = texture2D(uNormalMap, vTexCoord).a;
   vec3 colorMap = texture2D(uColorMap, vTexCoord).rgb;
   vec4 flasherMap = texture2D(uFlashermap, vTexCoord); 
   vec3 diffuse = vec3(0.0), specular = vec3(0);
   float specIntensity = 4.0;
   vec3 LampColor = vec3(1.0, 0.6839, 0.0);
#ifdef OO_LIGHT_0_FIX
   LIGHT(0, normalize(vLight0Vector));
#endif
   LIGHT(1, normalize(vLight1Vector));
   diffuse += gl_FrontMaterial.ambient.rgb * gl_LightModel.ambient.rgb;
   
   #ifndef OO_REDUCED_COMPLEXITY 
// Calculate the lighting for full shader mode   
   vec3 color = diffuse * diffuseColor(Decal1_Scale_and_Position).rgb;   
   color += colorMap * specular * specIntensity;     
   #endif
   
// Calculate the lighting for simple shader mode
   #ifdef OO_REDUCED_COMPLEXITY    
   vec3 color = diffuse * colorMap;
   color += colorMap * specular * specIntensity;
// add simple shader lights
   color += LampColor * IllumMap;    

// simple shader mode emergency lights
   if (isHostile)
      { 
       LampColor = vec3(1.0, 0.0, 0.0) * max(mod(uTime, 1.0) * 2.0, 0.5);
       // Add in the emergency lights    
       color += max(wave(uTime), 0.0) * (flasherMap.r * blueflasher + flasherMap.b * purpleflasher);
      }  

   #endif


// these next glow effects are only available in full shader mode   
   #ifndef OO_REDUCED_COMPLEXITY 

// Set up the emergency lights animation
   float t1 = 1.4 * uTime + flasherMap.a;
   float lightLevel = clamp(wave(t1), 0.0, 4.0);
 
   if (nearly_dead)
      { 
      lightLevel *= Blink_on_off(Pulse(1.3, 1.0));      
      } 
      
// check if ship is hostile, adjust lampColor & add in flashers accordingly
   if (isHostile)
      { 
       LampColor = vec3(1.0, 0.0, 0.0) * max(mod(uTime, 1.0) * 2.0, 0.5);
   // Add in the emergency lights    
       color += lightLevel * (flasherMap.r * blueflasher + flasherMap.b * purpleflasher);
      }  
    
// Add the hull lights glow effects, check if ship is throwingSparks, if so flicker the effects
   if (nearly_dead)
      { 
      color += LampColor * IllumMap * 7.0 * Blink_on_off(Pulse(1.0, 1.0));      
      }  
   if (!nearly_dead) 
      { 
     color += LampColor * IllumMap * 7.0 * Pulse(1.0, 0.3);       
      } 

// Add the all over hull temperature glow. Full Shader mode only
   float hullHeat = max(hull_heat_level - 0.5, 0.0) * 2.0; 
   hullHeat = Pulse(hullHeat * hullHeat, 0.1); 
   color += TemperatureGlow(hullHeat); 
#endif   

    
   gl_FragColor = vec4(color.rgb, 1.0);
}
