diff --git a/Effects/bumpspec.eff b/Effects/bumpspec.eff
new file mode 100644
index 000000000..1fa9fd0c9
--- /dev/null
+++ b/Effects/bumpspec.eff
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Bump and specular effect
+parameters :
+    texture[0] -> colormap
+    texture[2] -> normal map + specularity in alpha channel
+
+eg :
+in model.xml :
+    <effect>
+  <inherits-from>Aircraft/A320/Models/Effects/bumpspec</inherits-from>
+  <object-name>Fuselage</object-name>
+    </effect>
+
+in Aircraft/A320/Models/Effects/a320_bumpspec.eff ( or whatever, private to the model )
+
+<PropertyList>
+  <name>Aircraft/A320/Models/Effects/a320_bumpspec</name>
+  <inherits-from>Effects/bumpspec</inherits-from>
+  <parameters>
+    <texture n="2">
+      <image>Aircraft/A320/Models/Effects/textures/a320_normals.png</image>
+      <filter>linear-mipmap-linear</filter>
+      <wrap-s>repeat</wrap-s>
+      <wrap-t>repeat</wrap-t>
+      <internal-format>normalized</internal-format>
+    </texture>
+  </parameters>
+</PropertyList>
+-->
+<PropertyList>
+  <name>Effects/bumpspec</name>
+  <inherits-from>Effects/model-default</inherits-from>
+  <generate>
+    <normal type="int">15</normal>
+    <tangent type="int">6</tangent>
+    <binormal type="int">7</binormal>
+  </generate>
+  <technique n="10">
+    <predicate>
+      <and>
+        <property>/sim/rendering/shader-effects</property>
+        <or>
+          <less-equal>
+            <value type="float">2.0</value>
+            <glversion/>
+          </less-equal>
+          <and>
+            <extension-supported>GL_ARB_shader_objects</extension-supported>
+            <extension-supported>GL_ARB_shading_language_100</extension-supported>
+            <extension-supported>GL_ARB_vertex_shader</extension-supported>
+            <extension-supported>GL_ARB_fragment_shader</extension-supported>
+          </and>
+        </or>
+      </and>
+    </predicate>
+    <pass>
+      <texture-unit>
+        <unit>0</unit>
+        <image><use>texture[0]/image</use></image>
+        <filter><use>texture[0]/filter</use></filter>
+        <wrap-s><use>texture[0]/wrap-s</use></wrap-s>
+        <wrap-t><use>texture[0]/wrap-t</use></wrap-t>
+        <internal-format><use>texture[1]/internal-format</use></internal-format>
+      </texture-unit>
+      <texture-unit>
+        <unit>1</unit>
+        <image><use>texture[2]/image</use></image>
+        <filter><use>texture[2]/filter</use></filter>
+        <wrap-s><use>texture[2]/wrap-s</use></wrap-s>
+        <wrap-t><use>texture[2]/wrap-t</use></wrap-t>
+        <internal-format><use>texture[2]/internal-format</use></internal-format>
+      </texture-unit>
+      <program>
+        <vertex-shader n="0">Shaders/bumpspec.vert</vertex-shader>
+        <fragment-shader n="0">Shaders/bumpspec.frag</fragment-shader>
+        <uniform>
+          <name>tex_color</name>
+          <type>sampler-2d</type>
+          <value type="int">0</value>
+        </uniform>
+        <uniform>
+          <name>tex_normal</name>
+          <type>sampler-2d</type>
+          <value type="int">1</value>
+        </uniform>
+        <uniform>
+          <name>tex_specular</name>
+          <type>sampler-2d</type>
+          <value type="int">2</value>
+        </uniform>
+      </program>
+      <uniform>
+        <name>tex_color</name>
+        <type>sampler-2d</type>
+        <value type="int">0</value>
+      </uniform>
+      <uniform>
+        <name>tex_normal</name>
+        <type>sampler-2d</type>
+        <value type="int">1</value>
+      </uniform>
+    </pass>
+  </technique>
+</PropertyList>
diff --git a/Shaders/bumpspec.frag b/Shaders/bumpspec.frag
new file mode 100644
index 000000000..49ec8188e
--- /dev/null
+++ b/Shaders/bumpspec.frag
@@ -0,0 +1,53 @@
+// -*- mode: C; -*-
+// Licence: GPL v2
+// Authors: Original code by Thorsten Jordan, Luis Barrancos and others (dangerdeep.sf.net)
+//      Modified by Emilian Huminiuc (emilianh@gmail.com) (i4dnf on the flightgear forums).
+// fixme: maybe lookup texmap is faster than pow(). Quick tests showed that this is not the case...
+
+uniform sampler2D tex_color;   // (diffuse) color map, RGB
+uniform sampler2D tex_normal;   // normal map, RGB + A Specular
+
+
+varying vec4  ecPosition;
+varying vec3 lightdir, halfangle;
+
+void main()
+{
+    // get and normalize vector to light source
+    vec3 L = normalize(lightdir);
+
+    // get and normalize normal vector from texmap
+    vec4 v = texture2D(tex_normal, gl_TexCoord[0].st);
+    vec3 N = normalize(vec3(v.xyz * 2.0 - 1.0));
+    N.y = -N.y;
+    if (!gl_FrontFacing)
+        N = -N;
+
+    // compute specular color
+    // get and normalize half angle vector
+    vec3 H = normalize(halfangle);
+
+    // compute resulting specular color
+    vec3 specular_color = vec3(gl_FrontMaterial.specular) *
+      pow(max(dot(H, N), 0.0), gl_FrontMaterial.shininess);
+
+    // compute diffuse color
+    vec3 diffuse_color = vec3(texture2D(tex_color, gl_TexCoord[0].st));
+
+    // handle ambient
+    diffuse_color = diffuse_color * mix(max(dot(L, N), 0.0), 0.6, gl_LightSource[0].ambient.r);
+
+    specular_color = specular_color * v.a;
+
+    // final color of fragment
+    vec3 final_color = clamp((diffuse_color + specular_color) * vec3(gl_LightSource[0].diffuse /*light_color*/), 0.0, 1.0);
+
+    float fog_factor;
+    float fogCoord = ecPosition.z;
+    const float LOG2 = 1.442695;
+    fog_factor = exp2(-gl_Fog.density * gl_Fog.density * fogCoord * fogCoord * LOG2);
+    fog_factor = clamp(fog_factor, 0.0, 1.0);
+
+    // output color is a mix between fog and final color
+    gl_FragColor = vec4(mix(vec3(gl_Fog.color), final_color, fog_factor), 1.0);
+}
diff --git a/Shaders/bumpspec.vert b/Shaders/bumpspec.vert
new file mode 100644
index 000000000..9b49dcce6
--- /dev/null
+++ b/Shaders/bumpspec.vert
@@ -0,0 +1,53 @@
+// -*- mode: C; -*-
+// Licence: GPL v2
+// Authors: Original code by Thorsten Jordan, Luis Barrancos and others (dangerdeep.sf.net)
+//      Modified by Emilian Huminiuc (emilianh@gmail.com) (i4dnf on the flightgear forums).
+
+/* input:
+gl_Vertex
+gl_Normal      (tangentz)
+gl_MultiTexCoord0   (texcoord)
+tangentx_righthanded   (tangentx,righthanded-factor)
+*/
+
+/* can we give names to default attributes? or do we need to use named attributes for that?
+how to give named attributes with vertex buffer objects?
+we could assign them to a variable, but would that be efficient? an unnecessary copy.
+but the shader compiler should be able to optimize that...
+the way should be to use vertex attributes (together with vertex arrays or VBOs),
+that have a name and use that name here.
+until then, access sources directly or via a special variable.
+*/
+
+varying vec4  ecPosition;
+varying vec3 lightdir, halfangle;
+attribute vec4 tangent, binormal;
+
+void main()
+{
+    ecPosition = gl_ModelViewMatrix * gl_Vertex;
+
+    // compute direction to light in object space (L)
+    vec3 lightpos_obj = vec3(gl_ModelViewMatrixInverse * gl_LightSource[0].position);
+    vec3 lightdir_obj = normalize(lightpos_obj);
+
+    // direction to viewer (E)
+    // compute direction to viewer (E) in object space (mvinv*(0,0,0,1) - inputpos)
+    vec3 viewerdir_obj = normalize(vec3(gl_ModelViewMatrixInverse[3]) - vec3(gl_Vertex));
+
+    // compute halfangle vector (H = ||L+E||)
+    vec3 halfangle_obj = normalize(viewerdir_obj + lightdir_obj);
+
+    // transform light direction to tangent space
+    lightdir.x = dot(tangent, lightdir_obj);
+    lightdir.y = dot(binormal, lightdir_obj);
+    lightdir.z = dot(gl_Normal, lightdir_obj);
+
+    halfangle.x = dot(tangent, halfangle_obj);
+    halfangle.y = dot(binormal, halfangle_obj);
+    halfangle.z = dot(gl_Normal, halfangle_obj);
+
+    // finally compute position
+    gl_Position = ftransform();
+    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+}