1#version 150
2
3in vec3 oPos;
4in vec4 oNormAndFogVal;
5in vec3 oEyePos;
6
7#if LIGHT0
8uniform vec4 lightPosition0;
9uniform vec4 spotlightDir0;
10uniform vec4 lightDiffuse0;
11uniform vec4 lightSpecular0;
12uniform vec4 lightAttenuation0;
13uniform vec4 lightSpotlight0;
14#endif
15#if LIGHT1
16uniform vec4 lightPosition1;
17uniform vec4 spotlightDir1;
18uniform vec4 lightDiffuse1;
19uniform vec4 lightSpecular1;
20uniform vec4 lightAttenuation1;
21uniform vec4 lightSpotlight1;
22#endif
23#if LIGHT2
24uniform vec4 lightPosition2;
25uniform vec4 spotlightDir2;
26uniform vec4 lightDiffuse2;
27uniform vec4 lightSpecular2;
28uniform vec4 lightAttenuation2;
29uniform vec4 lightSpotlight2;
30#endif
31
32uniform mat4 world;
33uniform float exponent;
34uniform float texScale;
35uniform float plateauSize;
36uniform float transitionSpeed;
37
38#if FOGLINEAR || FOGEXPONENTIAL || FOGEXPONENTIAL2
39uniform vec4 fogColour;
40#endif
41
42uniform vec4 ambient;
43uniform sampler2D texFromX;
44uniform sampler2D texFromXNormal;
45uniform sampler2D texFromY;
46uniform sampler2D texFromYNormal;
47uniform sampler2D texFromZ;
48uniform sampler2D texFromZNormal;
49
50out vec4 fragColour;
51
52vec3 expand(vec3 v)
53{
54	return (v - 0.5) * 2;
55}
56
57vec4 lit(float NdotL, float NdotH, float m)
58{
59    float ambient = 1.0;
60    float diffuse = max(NdotL, 0.0);
61    float specular = step(0.0, NdotL) * max(NdotH * m, 0.0);
62
63    return vec4(ambient, diffuse, specular, 1.0);
64}
65
66vec4 doLighting(
67	vec3 oPos,
68	vec3 normal,
69	vec3 eyeDir,
70	float exponent,
71	float specularFactor,
72	vec3 lightDir,
73	vec4 lightPosition,
74	vec4 lightDiffuse,
75	vec4 lightSpecular,
76	vec4 lightAttenuation,
77	vec4 lightSpotlight,
78	vec3 lightSpotDir
79) {
80	vec3 halfAngle = normalize(lightDir + eyeDir);
81
82	float nDotL = dot(lightDir, normal);
83	float nDotH = dot(halfAngle, normal);
84	vec4 lighting = lit(nDotL, nDotH, exponent);
85
86	float attenuation = 1;
87	#if ATTENUATION
88	if (lightPosition.w != 0) {
89		float distance = length(lightPosition.xyz - oPos);
90		attenuation = 1.0 / (lightAttenuation.y + lightAttenuation.z * distance  + lightAttenuation.w * distance * distance);
91	}
92	#endif
93
94	float spot = 1;
95	if (!(lightSpotlight.x == 1 && lightSpotlight.y == 0 && lightSpotlight.z == 0 && lightSpotlight.w == 1)) {
96		spot = clamp(
97			(dot(lightDir, normalize(-lightSpotDir)) - lightSpotlight.y) /
98			(lightSpotlight.x - lightSpotlight.y), 0.0, 1.0);
99	}
100
101	return attenuation * spot * (lightDiffuse * lighting.y + specularFactor * lightSpecular * lighting.z);
102}
103
104void main()
105{
106
107	vec3 unitNormal = normalize(oNormAndFogVal.xyz);
108	vec3 eyeDir = normalize(oEyePos - oPos);
109
110	// Ported from http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html
111	vec3 blendWeights = abs(unitNormal);
112	blendWeights = blendWeights - plateauSize;
113	blendWeights = pow(max(blendWeights, 0), vec3(transitionSpeed));
114	blendWeights /= vec3(blendWeights.x + blendWeights.y + blendWeights.z );
115	// Move the planar mapping a bit according to the normal length to avoid bad looking skirts.
116	float nLength = length(oNormAndFogVal.xyz - 1.0);
117	vec2 coord1 = (oPos.yz + nLength) * texScale;
118	vec2 coord2 = (oPos.zx + nLength) * texScale;
119	vec2 coord3 = (oPos.xy + nLength) * texScale;
120
121	vec4 col1 = texture(texFromX, coord1);
122	vec4 col2 = texture(texFromY, coord2);
123	vec4 col3 = texture(texFromZ, coord3);
124	vec4 textColour = vec4(col1.xyz * blendWeights.x +
125		col2.xyz * blendWeights.y +
126		col3.xyz * blendWeights.z, 1);
127
128	// Normal Mapping
129	#if LIGHTNORMALMAPPING
130	vec3 tangent = vec3(1, 0, 0);
131	vec3 binormal = normalize(cross(tangent, unitNormal));
132	tangent = normalize(cross(unitNormal, binormal));
133	mat3 TBN = mat3(tangent, binormal, unitNormal);
134	vec3 eyeDir2 = normalize(TBN * eyeDir);
135	vec3 bumpFetch1 = expand(texture(texFromXNormal, coord1).rgb);
136    vec3 bumpFetch2 = expand(texture(texFromYNormal, coord2).rgb);
137    vec3 bumpFetch3 = expand(texture(texFromZNormal, coord3).rgb);
138	vec3 normal2 = bumpFetch1.xyz * blendWeights.x +
139		bumpFetch2.xyz * blendWeights.y +
140		bumpFetch3.xyz * blendWeights.z;
141	#else
142	vec3 eyeDir2 = eyeDir;
143	vec3 normal2 = unitNormal;
144	#endif
145
146	#if USESPECULARMAP
147	float specularFactor = textColour.a;
148	#else
149	float specularFactor = 1.0;
150	#endif
151
152	// Light
153	vec4 lightContribution = vec4(0, 0, 0, 0);
154	#if LIGHT0
155	vec3 lightSpotDir0 = (world * spotlightDir0).xyz;
156	vec3 lightDir0 = normalize(lightPosition0.xyz - oPos * lightPosition0.w);
157	#if LIGHTNORMALMAPPING
158	vec3 lightSpotDir02 = normalize(TBN * lightSpotDir0);
159	vec3 lightDir02 = normalize(TBN * lightDir0);
160	#else
161	vec3 lightSpotDir02 = lightSpotDir0;
162	vec3 lightDir02 = lightDir0;
163	#endif
164	lightContribution += doLighting(oPos, normal2, eyeDir2, exponent, specularFactor, lightDir02, lightPosition0, lightDiffuse0, lightSpecular0, lightAttenuation0, lightSpotlight0, lightSpotDir02);
165	#endif
166
167	#if LIGHT1
168	vec3 lightSpotDir1 = (world * spotlightDir1).xyz;
169	vec3 lightDir1 = normalize(lightPosition1.xyz - oPos * lightPosition1.w);
170	#if LIGHTNORMALMAPPING
171	vec3 lightSpotDir12 = normalize(TBN * lightSpotDir1);
172	vec3 lightDir12 = normalize(TBN * lightDir1);
173	#else
174	vec3 lightSpotDir12 = lightSpotDir1;
175	vec3 lightDir12 = lightDir1;
176	#endif
177	lightContribution += doLighting(oPos, normal2, eyeDir2, exponent, specularFactor, lightDir12, lightPosition1, lightDiffuse1, lightSpecular1, lightAttenuation1, lightSpotlight1, lightSpotDir12);
178	#endif
179
180	#if LIGHT2
181	vec3 lightSpotDir2 = (world * spotlightDir2).xyz;
182	vec3 lightDir2 = normalize(lightPosition2.xyz - oPos * lightPosition2.w);
183	#if LIGHTNORMALMAPPING
184	vec3 lightSpotDir22 = normalize(TBN * lightSpotDir2);
185	vec3 lightDir22 = normalize(TBN * lightDir2);
186	#else
187	vec3 lightSpotDir22 = lightSpotDir2;
188	vec3 lightDir22 = lightDir2;
189	#endif
190	lightContribution += doLighting(oPos, normal2, eyeDir2, exponent, specularFactor, lightDir22, lightPosition2, lightDiffuse2, lightSpecular2, lightAttenuation2, lightSpotlight2, lightSpotDir22);
191	#endif
192
193	fragColour = clamp(textColour * (lightContribution + ambient), 0.0, 1.0);
194	#if FOGLINEAR || FOGEXPONENTIAL || FOGEXPONENTIAL2
195	fragColour = mix(oColor, fogColour, oNormAndFogVal.w);
196	#endif
197
198}
199