uniform sampler2D    uColorMap; // paintmap in Alpha. Blue channel used as spec int
uniform sampler2D    uNormalMap; // Illummap in A
uniform sampler2D    uEffectsMap;
uniform sampler2D    uDecalMap;

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

// Constants
const float KspecExponent = 6.0;
const float kDecalCount = 1.0; // Match the number of Decals in your texture

// Decal position, scale & rotation
 const  vec4  Decal1_Scale_and_Position = vec4(0.49, 0.25, 7.000, 1.2);
 const  vec4  Decal2_Scale_and_Position = vec4(0.858, 0.25, 7.000, -1.2);

// Uniforms from Oolite
   uniform float  uTime;
   uniform bool   nearly_dead;
   uniform bool   isHostile;   
   uniform float  hull_heat_level;
   uniform float  laser_heat_level;   
   uniform float  engine_power;    
   uniform vec4   PaintColor1; // used with paintmask map to tint diffuse texture
   uniform vec4   DecalColor; // used to tint decal
   uniform float  uDecalSelect; // used to decide which decal to select   

// 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.6, 0.0);
        return result * 2.0;    
     }  
     
// Blink_on_off_function.
   float Blink_on_off(float timeScale)
   {
   float result = step(0.5, sin(uTime * timeScale));
   return result;
   }     

// Cyan color exhaust glow effect
   vec3 cyanGlow(float level)
   {
      vec3 result;
      result.rgb = vec3(0.1, 0.6, 1.0) * level * 1.6;
      return result;
   }     
     
// Red/Orange color heated metal effect
   vec3 redGlow(float level)
   {
      vec3 result;
      result.rgb = vec3(1.5, 0.55, 0.2) * level * 1.4;
      return result;
   }

// Heated weapon glow effect
   vec3 WeaponGlow(float level)
   {
      vec3 result;
      result.rgb = vec3(1.38, 0.35, 0.20) * level;    
      return result;
   } 

#endif

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 
/*
   "the_decaliser" - this function scales & positions the decal image using data passed 
   to it from the main shader (see lines 105 & 106 below)
*/ 
vec4 the_decaliser(vec4 Your_Decal_Settings) 
{ 
    
// 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);

    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. 
       vec4 decal_Tex = texture2D(uDecalMap, decal_TexCoord); 

// Modify the Decals texture co-oords 
    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); 

// Use the Alpha in the decal as a transparency mask so you can 'cutout' your decal from it's background
   float alpha = decal_Tex.a; 
   
// Return the scaled, position & rotated decal, it's mixed into the colour texture further on in the shader . 
   return alpha * decal_Tex;
}                      
#endif  

void main()
{
   vec3 eyeVector = normalize(vEyeVector);
   vec2 texCoord = vTexCoord;
   vec3 normal = normalize(texture2D(uNormalMap, vTexCoord).rgb - 0.5); 
   vec3 colorMap = texture2D(uColorMap, texCoord).rgb;
   vec4 effectsMap = texture2D(uEffectsMap, texCoord);
   vec3 diffuse = vec3(0.0), specular = vec3(0);
   float specIntensity = texture2D(uColorMap, texCoord).a;
   float glowMap = texture2D(uNormalMap, texCoord).a;
   vec3  LampColor = vec3(0.9926, 0.9686, 0.7325);
 
#ifdef OO_LIGHT_0_FIX
   LIGHT(0, normalize(vLight0Vector));
#endif
   LIGHT(1, normalize(vLight1Vector)); // change the 0 to 1 when exporting back to oolite
   diffuse += gl_FrontMaterial.ambient.rgb * gl_LightModel.ambient.rgb;

#ifndef OO_REDUCED_COMPLEXITY 
// Full Shader Mode - Repaint the hull
   colorMap += effectsMap.a * PaintColor1.rgb;

// Apply the Decals - we want a matte finish for these   
   vec4 decals = the_decaliser(Decal1_Scale_and_Position) +  
                 the_decaliser(Decal2_Scale_and_Position); // send decal 1 & 2 to the decaliser function
                 
   vec3 color_temp = colorMap * diffuse; // temp vec3 to store the texturemap & lighting for the hull   
// Calculate the lighting for full shader mode and add in into the colour_temp vec3
   color_temp += specular * specIntensity;    
   
// mix the decals and colour_temp together,
   vec3 color = mix(color_temp, decals.rgb * diffuse + (0.2 * specular), decals.a);   
#endif

// Simple Shader Mode - Calculate lighting only, ignore repainting & decals
   #ifdef OO_REDUCED_COMPLEXITY    
   vec3 color = diffuse * colorMap;
   color += specular * specIntensity;
   // add in standard illumination map for simple shader mode
   color += LampColor * glowMap;   
   #endif

// these next glow effects are only available in full shader mode   
#ifndef OO_REDUCED_COMPLEXITY 
// check if ship is hostile, adjust lampColor accordingly
   if (isHostile)
      { 
    LampColor = vec3(1.0, 0.1, 0.0)  * max(mod(uTime, 1.0), 0.5);
      }  
 
// Add the hull lights glow effects, check if ship is throwingSparks, if so flicker the effects
   if (nearly_dead)
      { 
  // flicker the Illumination map, add it in twice at 2 different frequencies to vary the blinking effect
     color += LampColor * glowMap * 1.5 * Blink_on_off(Pulse(1.0, 0.9)) +  LampColor * glowMap *  Blink_on_off(Pulse(1.0, 0.8));  
  // add in engine cyan glow - flicker it to show ship damage
     color += cyanGlow(effectsMap.b * Pulse(min(engine_power, 1.0), 1.0)) * Blink_on_off(Pulse(1.0, 0.7));  
      }  

   if (!nearly_dead) 
      { 
  // add in standard Illumination map 
    color += LampColor * glowMap * Pulse(1.0, 0.3);
  // add in engine cyan glow  
    color += cyanGlow(effectsMap.b * Pulse(min(engine_power, 1.0), 1.0));
      }

// Add in the red heated metal glow around the exhaust. 
   color += redGlow(effectsMap.r * Pulse(min(engine_power, 1.0), 1.0));
   
//Add in the laser firing gun barrel flash effect    
   color += WeaponGlow(effectsMap.g * Pulse(min(laser_heat_level, 1.0), 1.0));

// 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);
}
