1
2// uncomment the following lines for debugging light directions:
3// yellow: light up, blue: light down, turqoise: light right, pink: light left
4// brightness: light strength
5//#define LIGHT_DEBUG
6
7// uncomment the following lines for debugging light color:
8// the light will always come from the front and have a uniform brightness.
9//#define LIGHT_DEBUG_COLOR
10
11// uncomment the following lines to set the light color to pink for all lights for debugging:
12//#define LIGHT_DEBUG_PINK
13
14#ifdef OC_DYNAMIC_LIGHT
15uniform sampler2D ambientTex;
16
17uniform mat3x2 ambientTransform;
18uniform float ambientBrightness;
19
20uniform sampler2D lightTex;
21#endif
22
23// Gamma uniforms
24uniform vec3 gamma;
25
26// 0 if backface culling is enabled, 1 if it is disabled
27uniform float cullMode;
28
29// Light dot product, taking cull mode into account
30float lightDot(vec3 normal, vec3 lightDir) {
31	return abs(max(-cullMode, dot(normalize(normal), lightDir)));
32}
33
34// Converts the pixel range 0.0..1.0 into the integer range 0..255
35int f2i(float x) {
36	return int(x * 255.9);
37}
38
39slice(init)
40{
41
42	// At what point of light intensity we set the "darkness" point. This
43	// is to compensate for the fact that the engine "smoothes" the light
44	// and therefore will often never arrive at 0 light intensity.
45	float lightDarknessLevel = 8.0 / 256.0;
46
47	// "Height" of the light in front of the screen. The lower this
48	// value, the sharper the incoming light angles are. For
49	// orientation: A value of 1 means 45 degrees maximum.
50	float lightDepth = 0.5;
51
52	// Position of the ambient light. Note that for normal directional
53	// lights we have |X| <= 1.0 and |Y| <= 1.0, so it might be a good
54	// idea to keep within this values.
55	vec3 ambientLightPos = vec3(1.0, -1.0, lightDepth);
56
57	// Amount of ambience we put into the ambient light. The higher
58	// this is, the less directional ambient lighting is, and the
59	// "flatter" the shading appears.
60	float ambientAmbience = 1.0;
61
62	// The total brightness assigned by the ambient shader to a
63	// texture facing the viewer.
64	float maxAmbientBrightness = 1.0;
65
66	// The total brightness assigned by the ambient shader to a
67	// texture facing the viewer.
68	float maxLightBrightness = 3.0;
69
70}
71
72slice(texture+5)
73{
74#ifdef OC_DYNAMIC_LIGHT
75
76	// Query light texture
77	vec2 lightDirCoord = lightCoord;
78
79	vec4  lightPx = texture(lightTex, lightDirCoord);
80	float lightBright = maxLightBrightness * max(0.0, (lightPx.a-lightDarknessLevel)/(1.0-lightDarknessLevel));
81	vec3  lightDir = normalize(vec3(vec2(1.0, 1.0) - lightPx.yz * 3.0, lightDepth));
82
83	// Query light color texture (part of the light texture)
84	vec2 lightColorCoord = lightCoord - vec2(0.0, 0.5); // subtract offset for the color texture
85
86	vec3 lightColor = texture(lightTex, lightColorCoord.st).rgb;
87
88	// Normalise light colour
89	#ifdef LIGHT_DEBUG_COLOR
90		lightBright = 0.5;
91		lightColor = vec4(1.0, 0.0, 1.0, 1.0);
92	#endif
93
94	// Ambient light
95	// Edxtra .xy since some old intel drivers return a vec3
96	float ambient = texture(ambientTex, (ambientTransform * vec3(gl_FragCoord.xy, 1.0)).xy).r;
97	ambient *= ambientBrightness;
98#ifdef OC_SKY
99	ambient = 0.999; // TODO: = 1.0 causes bugs?
100#endif
101#else
102	// When lighting is disabled, put a light source coming from the camera.
103	// Note that in most cases this does not actually matter, since in the
104	// case with lighting disabled, ambient lighting takes fully over.
105	float lightBright = 1.0;
106	vec3  lightDir = vec3(0.0, 0.0, 1.0);
107	vec3  lightColor = vec3(1.0, 1.0, 1.0);
108	float ambient = 1.0;
109#endif
110}
111
112slice(light)
113{
114
115	// Light dot product, taking backface culling into account
116	float light = lightDot(normal, lightDir);
117	// Amount of reflection, depending on the angle where material reflects most
118	light = min(light / matAngle, 2.0 - light / matAngle);
119
120#ifdef OC_LANDSCAPE
121	normal2 = normalize(normal2);
122	float light2 = lightDot(normal2, lightDir);
123	light2 = min(light2 / matAngle2, 2.0 - light2 / matAngle2);
124#endif
125
126	// For landscape, ambient brightness is coming from top
127	vec3 ambientDir = normalize(ambientLightPos);
128	float ambientMul = maxAmbientBrightness / (ambientAmbience + lightDot(vec3(0.0,0.0,1.0), ambientDir));
129	// Add ambience to brightness
130	lightBright = mix(lightBright, 1.0, ambient);
131	light = mix(light, ambientMul * (ambientAmbience + lightDot(normal, ambientDir)), ambient);
132#ifdef OC_LANDSCAPE
133	light2 = mix(light2, ambientMul * (ambientAmbience + lightDot(normal2, ambientDir)), ambient);
134#endif
135	lightColor = mix(lightColor, vec3(1.0,1.0,1.0), ambient);
136}
137
138slice(color+5)
139{
140	// Normalize light colour
141	vec3 lightColorNorm = sqrt(3.0) * normalize(lightColor);
142
143	// Add light. Depending on material properties, we make it more
144	// "spotty" and allow the material to self-illuminate. The light
145	// brightness overrules everything though (= FoW is last factor).
146	vec3 spotLight = pow(vec3(light,light,light), matSpot);
147	fragColor.rgb = lightBright * fragColor.rgb * (matEmit + lightColorNorm * spotLight);
148#ifdef OC_LANDSCAPE
149	vec3 spotLight2 = pow(vec3(light2,light2,light2), matSpot2);
150	color2.rgb = lightBright * color2.rgb * (matEmit2 + lightColorNorm * spotLight2);
151#endif
152}
153
154slice(finish+5)
155{
156
157#ifdef LIGHT_DEBUG
158#ifdef OC_DYNAMIC_LIGHT
159	float lightYDir = lightPx.b - 1.0/3.0;
160	float lightXDir = lightPx.g - 1.0/3.0;
161	float lightStrength = lightPx.a;
162	fragColor =
163	  vec4(lightStrength * vec3(1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
164	                            1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
165	                            1.0-1.5*max(0.0, -lightYDir)),
166	       1.0);
167#else
168    fragColor = vec4(0.0, 0.0, 0.0, 0.0); // invisible
169#endif
170#endif
171
172}
173
174slice(finish+10) {
175	fragColor = vec4(pow(fragColor.rgb, gamma), fragColor.a);
176}
177