+struct LightSourceParameters
+{
+ vec4 position;
+ vec4 diffuse;
+ vec4 specular;
+};
+
+struct MaterialParameters
+{
+ vec4 ambient;
+ vec4 diffuse;
+ vec4 specular;
+ float shininess;
+};
+
+struct ClipPlane
+{
+ vec4 equation;
+};
+
+uniform mat4 eye_obj_matrix;
+uniform mat3 eye_obj_normal_matrix;
+uniform Transform
+{
+ mat4 projection_matrix;
+};
+
+uniform Material
+{
+ MaterialParameters material;
+ float reflectivity;
+};
+
+const bool use_vertex_color = false;
+
+const bool use_lighting = false;
+const bool use_specular = false;
+const bool use_sky = false;
+const bool use_fog = false;
+uniform Lighting
+{
+ // Declared as an array for compatibility reasons
+ LightSourceParameters light_sources[1];
+ vec4 ambient_color;
+ vec4 sky_color;
+ vec3 eye_sky_dir;
+ float horizon_limit;
+ vec4 fog_color;
+ float fog_density;
+};
+
+const bool use_diffuse_map = false;
+uniform sampler2D diffuse_map;
+
+const bool use_normal_map = false;
+uniform sampler2D normal_map;
+
+const bool use_shadow_map = false;
+uniform sampler2DShadow shadow;
+uniform ShadowMap
+{
+ float shadow_darkness;
+ mat4 shd_eye_matrix;
+};
+
+const bool use_reflection = false;
+const bool use_environment_map = false;
+uniform samplerCube environment;
+uniform EnvMap
+{
+ mat3 env_eye_matrix;
+};
+
+const int max_clip_planes = 0;
+uniform Clipping
+{
+ ClipPlane clip_planes[max_clip_planes];
+};
+
+////// vertex
+in vec4 vertex;
+in vec4 texcoord;
+in vec4 color;
+in vec3 normal;
+in vec3 tangent;
+in vec3 binormal;
+
+vec4 get_vertex_position()
+{
+ return vertex;
+}
+
+vec3 get_vertex_normal()
+{
+ return normal;
+}
+
+void singlepass_transform_and_lighting()
+{
+ out vec4 eye_vertex = eye_obj_matrix*get_vertex_position();
+ gl_Position = projection_matrix*eye_vertex;
+
+ out vec3 eye_normal = eye_obj_normal_matrix*get_vertex_normal();
+ vec3 eye_tangent = eye_obj_normal_matrix*tangent;
+ vec3 eye_binormal = eye_obj_normal_matrix*binormal;
+ out mat3 eye_tbn_matrix = mat3(eye_tangent, eye_binormal, eye_normal);
+
+ out vec3 incident_dir = normalize(eye_vertex.xyz);
+ if(use_normal_map)
+ incident_dir = incident_dir*eye_tbn_matrix;
+
+ vec3 ldir = normalize(light_sources[0].position.xyz-eye_vertex.xyz*light_sources[0].position.w);
+ if(use_normal_map)
+ ldir = ldir*eye_tbn_matrix;
+ out vec3 light_dir = ldir;
+
+ out vec3 tbn_sky_dir = eye_sky_dir*eye_tbn_matrix;
+ out vec3 shadow_coord = (shd_eye_matrix*eye_vertex).xyz;
+ out float fog_coord = eye_vertex.z;
+
+ for(int i=0; i<max_clip_planes; ++i)
+ gl_ClipDistance[i] = dot(eye_vertex, clip_planes[i].equation);
+}
+
+void main()
+{
+ singlepass_transform_and_lighting();
+ passthrough;
+}
+
+////// fragment
+out vec4 frag_color;
+
+vec4 get_diffuse_sample()
+{
+ return texture(diffuse_map, texcoord.xy);
+}
+
+vec3 get_normal_sample()
+{
+ return texture(normal_map, texcoord.xy).xyz*2.0-1.0;
+}
+
+vec3 normal;
+vec4 diffuse_sample;
+
+vec3 singlepass_lighting()
+{
+ float shadow_sample = texture(shadow, shadow_coord);
+ float shadow_intensity = mix(1.0, shadow_sample, shadow_darkness);
+
+ vec3 ambient_light = ambient_color.rgb;
+ if(use_sky)
+ {
+ vec3 sky_dir;
+ if(use_normal_map)
+ sky_dir = tbn_sky_dir;
+ else
+ sky_dir = eye_sky_dir;
+ float skylight_intensity = dot(normal, sky_dir)*0.5+0.5;
+ ambient_light += skylight_intensity*sky_color.rgb;
+ }
+
+ vec3 n_light_dir = normalize(light_dir);
+ float diffuse_intensity = max(dot(normal, n_light_dir), 0.0);
+ if(use_shadow_map)
+ diffuse_intensity *= shadow_intensity;
+ vec3 diffuse_light = diffuse_intensity*light_sources[0].diffuse.rgb;
+
+ vec3 half_vec = normalize(light_dir-incident_dir);
+ float specular_intensity = pow(max(dot(half_vec, normal), 0.0), material.shininess);
+ if(use_shadow_map)
+ specular_intensity *= shadow_intensity;
+ vec3 specular_light = specular_intensity*light_sources[0].specular.rgb;
+
+ vec3 result = material.ambient.rgb*ambient_light+material.diffuse.rgb*diffuse_light;
+ if(use_diffuse_map)
+ result *= diffuse_sample.rgb;
+ if(use_specular)
+ result += material.specular.rgb*specular_light;
+
+ return result;
+}
+
+float singlepass_transparency()
+{
+ float alpha = material.diffuse.a;
+ if(use_diffuse_map)
+ alpha *= diffuse_sample.a;
+ return alpha;
+}
+
+vec3 singlepass_reflection()
+{
+ vec3 reflect_dir = reflect(incident_dir, normal);
+ if(use_normal_map)
+ reflect_dir = eye_tbn_matrix*reflect_dir;
+ vec3 result = vec3(0.0);
+
+ if(use_environment_map)
+ result += texture(environment, env_eye_matrix*reflect_dir).rgb*reflectivity;
+
+ if(use_sky && use_specular)
+ {
+ float reflect_altitude = clamp(dot(reflect_dir, eye_sky_dir)-horizon_limit, -1.0, 0.0);
+ float sky_specular_intensity = pow((1.0-reflect_altitude*reflect_altitude), material.shininess/2.0);
+ result += sky_specular_intensity*sky_color.rgb;
+ }
+
+ return result;
+}
+
+vec4 singlepass_color()
+{
+ vec4 result = vec4(1.0);
+ if(use_vertex_color)
+ result *= color;
+ if(use_diffuse_map)
+ result *= get_diffuse_sample();
+ return result;
+}
+
+void main()
+{
+ if(use_normal_map)
+ normal = get_normal_sample();
+ else
+ normal = normalize(eye_normal);
+
+ diffuse_sample = get_diffuse_sample();
+
+ vec4 final_color;
+ if(use_lighting)
+ final_color = vec4(singlepass_lighting(), singlepass_transparency());
+ else
+ final_color = singlepass_color();
+
+ if(use_reflection)
+ final_color += vec4(singlepass_reflection(), 0.0);
+ if(use_fog)
+ {
+ float fog_value = exp(fog_coord*fog_density);
+ final_color = vec4(mix(fog_color.rgb, final_color.rgb, fog_value), final_color.a);
+ }
+
+ frag_color = final_color;
+}