• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.graphics.g3d.shaders;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.graphics.Camera;
21 import com.badlogic.gdx.graphics.GL20;
22 import com.badlogic.gdx.graphics.VertexAttribute;
23 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
24 import com.badlogic.gdx.graphics.g3d.Attribute;
25 import com.badlogic.gdx.graphics.g3d.Attributes;
26 import com.badlogic.gdx.graphics.g3d.Environment;
27 import com.badlogic.gdx.graphics.g3d.Renderable;
28 import com.badlogic.gdx.graphics.g3d.Shader;
29 import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute;
30 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
31 import com.badlogic.gdx.graphics.g3d.attributes.CubemapAttribute;
32 import com.badlogic.gdx.graphics.g3d.attributes.DepthTestAttribute;
33 import com.badlogic.gdx.graphics.g3d.attributes.DirectionalLightsAttribute;
34 import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
35 import com.badlogic.gdx.graphics.g3d.attributes.IntAttribute;
36 import com.badlogic.gdx.graphics.g3d.attributes.PointLightsAttribute;
37 import com.badlogic.gdx.graphics.g3d.attributes.SpotLightsAttribute;
38 import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
39 import com.badlogic.gdx.graphics.g3d.environment.AmbientCubemap;
40 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
41 import com.badlogic.gdx.graphics.g3d.environment.PointLight;
42 import com.badlogic.gdx.graphics.g3d.environment.SpotLight;
43 import com.badlogic.gdx.graphics.g3d.utils.RenderContext;
44 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
45 import com.badlogic.gdx.math.Matrix3;
46 import com.badlogic.gdx.math.Matrix4;
47 import com.badlogic.gdx.math.Vector3;
48 import com.badlogic.gdx.utils.Array;
49 import com.badlogic.gdx.utils.GdxRuntimeException;
50 
51 public class DefaultShader extends BaseShader {
52 	public static class Config {
53 		/** The uber vertex shader to use, null to use the default vertex shader. */
54 		public String vertexShader = null;
55 		/** The uber fragment shader to use, null to use the default fragment shader. */
56 		public String fragmentShader = null;
57 		/** The number of directional lights to use */
58 		public int numDirectionalLights = 2;
59 		/** The number of point lights to use */
60 		public int numPointLights = 5;
61 		/** The number of spot lights to use */
62 		public int numSpotLights = 0;
63 		/** The number of bones to use */
64 		public int numBones = 12;
65 		/** */
66 		public boolean ignoreUnimplemented = true;
67 		/** Set to 0 to disable culling, -1 to inherit from {@link DefaultShader#defaultCullFace} */
68 		public int defaultCullFace = -1;
69 		/** Set to 0 to disable depth test, -1 to inherit from {@link DefaultShader#defaultDepthFunc} */
70 		public int defaultDepthFunc = -1;
71 
Config()72 		public Config () {
73 		}
74 
Config(final String vertexShader, final String fragmentShader)75 		public Config (final String vertexShader, final String fragmentShader) {
76 			this.vertexShader = vertexShader;
77 			this.fragmentShader = fragmentShader;
78 		}
79 	}
80 
81 	public static class Inputs {
82 		public final static Uniform projTrans = new Uniform("u_projTrans");
83 		public final static Uniform viewTrans = new Uniform("u_viewTrans");
84 		public final static Uniform projViewTrans = new Uniform("u_projViewTrans");
85 		public final static Uniform cameraPosition = new Uniform("u_cameraPosition");
86 		public final static Uniform cameraDirection = new Uniform("u_cameraDirection");
87 		public final static Uniform cameraUp = new Uniform("u_cameraUp");
88 		public final static Uniform cameraNearFar = new Uniform("u_cameraNearFar");
89 
90 		public final static Uniform worldTrans = new Uniform("u_worldTrans");
91 		public final static Uniform viewWorldTrans = new Uniform("u_viewWorldTrans");
92 		public final static Uniform projViewWorldTrans = new Uniform("u_projViewWorldTrans");
93 		public final static Uniform normalMatrix = new Uniform("u_normalMatrix");
94 		public final static Uniform bones = new Uniform("u_bones");
95 
96 		public final static Uniform shininess = new Uniform("u_shininess", FloatAttribute.Shininess);
97 		public final static Uniform opacity = new Uniform("u_opacity", BlendingAttribute.Type);
98 		public final static Uniform diffuseColor = new Uniform("u_diffuseColor", ColorAttribute.Diffuse);
99 		public final static Uniform diffuseTexture = new Uniform("u_diffuseTexture", TextureAttribute.Diffuse);
100 		public final static Uniform diffuseUVTransform = new Uniform("u_diffuseUVTransform", TextureAttribute.Diffuse);
101 		public final static Uniform specularColor = new Uniform("u_specularColor", ColorAttribute.Specular);
102 		public final static Uniform specularTexture = new Uniform("u_specularTexture", TextureAttribute.Specular);
103 		public final static Uniform specularUVTransform = new Uniform("u_specularUVTransform", TextureAttribute.Specular);
104 		public final static Uniform emissiveColor = new Uniform("u_emissiveColor", ColorAttribute.Emissive);
105 		public final static Uniform emissiveTexture = new Uniform("u_emissiveTexture", TextureAttribute.Emissive);
106 		public final static Uniform emissiveUVTransform = new Uniform("u_emissiveUVTransform", TextureAttribute.Emissive);
107 		public final static Uniform reflectionColor = new Uniform("u_reflectionColor", ColorAttribute.Reflection);
108 		public final static Uniform reflectionTexture = new Uniform("u_reflectionTexture", TextureAttribute.Reflection);
109 		public final static Uniform reflectionUVTransform = new Uniform("u_reflectionUVTransform", TextureAttribute.Reflection);
110 		public final static Uniform normalTexture = new Uniform("u_normalTexture", TextureAttribute.Normal);
111 		public final static Uniform normalUVTransform = new Uniform("u_normalUVTransform", TextureAttribute.Normal);
112 		public final static Uniform ambientTexture = new Uniform("u_ambientTexture", TextureAttribute.Ambient);
113 		public final static Uniform ambientUVTransform = new Uniform("u_ambientUVTransform", TextureAttribute.Ambient);
114 		public final static Uniform alphaTest = new Uniform("u_alphaTest");
115 
116 		public final static Uniform ambientCube = new Uniform("u_ambientCubemap");
117 		public final static Uniform dirLights = new Uniform("u_dirLights");
118 		public final static Uniform pointLights = new Uniform("u_pointLights");
119 		public final static Uniform spotLights = new Uniform("u_spotLights");
120 		public final static Uniform environmentCubemap = new Uniform("u_environmentCubemap");
121 	}
122 
123 	public static class Setters {
124 		public final static Setter projTrans = new GlobalSetter() {
125 			@Override
126 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
127 				shader.set(inputID, shader.camera.projection);
128 			}
129 		};
130 		public final static Setter viewTrans = new GlobalSetter() {
131 			@Override
132 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
133 				shader.set(inputID, shader.camera.view);
134 			}
135 		};
136 		public final static Setter projViewTrans = new GlobalSetter() {
137 			@Override
138 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
139 				shader.set(inputID, shader.camera.combined);
140 			}
141 		};
142 		public final static Setter cameraPosition = new GlobalSetter() {
143 			@Override
144 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
145 				shader.set(inputID, shader.camera.position.x, shader.camera.position.y, shader.camera.position.z,
146 					1.1881f / (shader.camera.far * shader.camera.far));
147 			}
148 		};
149 		public final static Setter cameraDirection = new GlobalSetter() {
150 			@Override
151 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
152 				shader.set(inputID, shader.camera.direction);
153 			}
154 		};
155 		public final static Setter cameraUp = new GlobalSetter() {
156 			@Override
157 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
158 				shader.set(inputID, shader.camera.up);
159 			}
160 		};
161 		public final static Setter cameraNearFar = new GlobalSetter() {
162 			@Override
163 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
164 				shader.set(inputID, shader.camera.near, shader.camera.far);
165 			}
166 		};
167 		public final static Setter worldTrans = new LocalSetter() {
168 			@Override
169 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
170 				shader.set(inputID, renderable.worldTransform);
171 			}
172 		};
173 		public final static Setter viewWorldTrans = new LocalSetter() {
174 			final Matrix4 temp = new Matrix4();
175 
176 			@Override
177 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
178 				shader.set(inputID, temp.set(shader.camera.view).mul(renderable.worldTransform));
179 			}
180 		};
181 		public final static Setter projViewWorldTrans = new LocalSetter() {
182 			final Matrix4 temp = new Matrix4();
183 
184 			@Override
185 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
186 				shader.set(inputID, temp.set(shader.camera.combined).mul(renderable.worldTransform));
187 			}
188 		};
189 		public final static Setter normalMatrix = new LocalSetter() {
190 			private final Matrix3 tmpM = new Matrix3();
191 
192 			@Override
193 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
194 				shader.set(inputID, tmpM.set(renderable.worldTransform).inv().transpose());
195 			}
196 		};
197 
198 		public static class Bones extends LocalSetter {
199 			private final static Matrix4 idtMatrix = new Matrix4();
200 			public final float bones[];
201 
Bones(final int numBones)202 			public Bones (final int numBones) {
203 				this.bones = new float[numBones * 16];
204 			}
205 
206 			@Override
set(BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes)207 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
208 				for (int i = 0; i < bones.length; i++) {
209 					final int idx = i / 16;
210 					bones[i] = (renderable.bones == null || idx >= renderable.bones.length || renderable.bones[idx] == null) ? idtMatrix.val[i % 16]
211 						: renderable.bones[idx].val[i % 16];
212 				}
213 				shader.program.setUniformMatrix4fv(shader.loc(inputID), bones, 0, bones.length);
214 			}
215 		}
216 
217 		public final static Setter shininess = new LocalSetter() {
218 			@Override
219 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
220 				shader.set(inputID, ((FloatAttribute)(combinedAttributes.get(FloatAttribute.Shininess))).value);
221 			}
222 		};
223 		public final static Setter diffuseColor = new LocalSetter() {
224 			@Override
225 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
226 				shader.set(inputID, ((ColorAttribute)(combinedAttributes.get(ColorAttribute.Diffuse))).color);
227 			}
228 		};
229 		public final static Setter diffuseTexture = new LocalSetter() {
230 			@Override
231 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
232 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
233 					.get(TextureAttribute.Diffuse))).textureDescription);
234 				shader.set(inputID, unit);
235 			}
236 		};
237 		public final static Setter diffuseUVTransform = new LocalSetter() {
238 			@Override
239 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
240 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Diffuse));
241 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
242 			}
243 		};
244 		public final static Setter specularColor = new LocalSetter() {
245 			@Override
246 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
247 				shader.set(inputID, ((ColorAttribute)(combinedAttributes.get(ColorAttribute.Specular))).color);
248 			}
249 		};
250 		public final static Setter specularTexture = new LocalSetter() {
251 			@Override
252 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
253 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
254 					.get(TextureAttribute.Specular))).textureDescription);
255 				shader.set(inputID, unit);
256 			}
257 		};
258 		public final static Setter specularUVTransform = new LocalSetter() {
259 			@Override
260 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
261 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Specular));
262 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
263 			}
264 		};
265 		public final static Setter emissiveColor = new LocalSetter() {
266 			@Override
267 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
268 				shader.set(inputID, ((ColorAttribute)(combinedAttributes.get(ColorAttribute.Emissive))).color);
269 			}
270 		};
271 		public final static Setter emissiveTexture = new LocalSetter() {
272 			@Override
273 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
274 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
275 					.get(TextureAttribute.Emissive))).textureDescription);
276 				shader.set(inputID, unit);
277 			}
278 		};
279 		public final static Setter emissiveUVTransform = new LocalSetter() {
280 			@Override
281 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
282 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Emissive));
283 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
284 			}
285 		};
286 		public final static Setter reflectionColor = new LocalSetter() {
287 			@Override
288 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
289 				shader.set(inputID, ((ColorAttribute)(combinedAttributes.get(ColorAttribute.Reflection))).color);
290 			}
291 		};
292 		public final static Setter reflectionTexture = new LocalSetter() {
293 			@Override
294 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
295 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
296 					.get(TextureAttribute.Reflection))).textureDescription);
297 				shader.set(inputID, unit);
298 			}
299 		};
300 		public final static Setter reflectionUVTransform = new LocalSetter() {
301 			@Override
302 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
303 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Reflection));
304 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
305 			}
306 		};
307 		public final static Setter normalTexture = new LocalSetter() {
308 			@Override
309 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
310 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
311 					.get(TextureAttribute.Normal))).textureDescription);
312 				shader.set(inputID, unit);
313 			}
314 		};
315 		public final static Setter normalUVTransform = new LocalSetter() {
316 			@Override
317 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
318 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Normal));
319 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
320 			}
321 		};
322 		public final static Setter ambientTexture = new LocalSetter() {
323 			@Override
324 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
325 				final int unit = shader.context.textureBinder.bind(((TextureAttribute)(combinedAttributes
326 					.get(TextureAttribute.Ambient))).textureDescription);
327 				shader.set(inputID, unit);
328 			}
329 		};
330 		public final static Setter ambientUVTransform = new LocalSetter() {
331 			@Override
332 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
333 				final TextureAttribute ta = (TextureAttribute)(combinedAttributes.get(TextureAttribute.Ambient));
334 				shader.set(inputID, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV);
335 			}
336 		};
337 
338 		public static class ACubemap extends LocalSetter {
339 			private final static float ones[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
340 			private final AmbientCubemap cacheAmbientCubemap = new AmbientCubemap();
341 			private final static Vector3 tmpV1 = new Vector3();
342 			public final int dirLightsOffset;
343 			public final int pointLightsOffset;
344 
ACubemap(final int dirLightsOffset, final int pointLightsOffset)345 			public ACubemap (final int dirLightsOffset, final int pointLightsOffset) {
346 				this.dirLightsOffset = dirLightsOffset;
347 				this.pointLightsOffset = pointLightsOffset;
348 			}
349 
350 			@Override
set(BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes)351 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
352 				if (renderable.environment == null)
353 					shader.program.setUniform3fv(shader.loc(inputID), ones, 0, ones.length);
354 				else {
355 					renderable.worldTransform.getTranslation(tmpV1);
356 					if (combinedAttributes.has(ColorAttribute.AmbientLight))
357 						cacheAmbientCubemap.set(((ColorAttribute)combinedAttributes.get(ColorAttribute.AmbientLight)).color);
358 
359 					if (combinedAttributes.has(DirectionalLightsAttribute.Type)) {
360 						Array<DirectionalLight> lights = ((DirectionalLightsAttribute)combinedAttributes
361 							.get(DirectionalLightsAttribute.Type)).lights;
362 						for (int i = dirLightsOffset; i < lights.size; i++)
363 							cacheAmbientCubemap.add(lights.get(i).color, lights.get(i).direction);
364 					}
365 
366 					if (combinedAttributes.has(PointLightsAttribute.Type)) {
367 						Array<PointLight> lights = ((PointLightsAttribute)combinedAttributes.get(PointLightsAttribute.Type)).lights;
368 						for (int i = pointLightsOffset; i < lights.size; i++)
369 							cacheAmbientCubemap.add(lights.get(i).color, lights.get(i).position, tmpV1, lights.get(i).intensity);
370 					}
371 
372 					cacheAmbientCubemap.clamp();
373 					shader.program.setUniform3fv(shader.loc(inputID), cacheAmbientCubemap.data, 0, cacheAmbientCubemap.data.length);
374 				}
375 			}
376 		}
377 
378 		public final static Setter environmentCubemap = new LocalSetter() {
379 			@Override
380 			public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
381 				if (combinedAttributes.has(CubemapAttribute.EnvironmentMap)) {
382 					shader.set(inputID, shader.context.textureBinder.bind(((CubemapAttribute)combinedAttributes
383 						.get(CubemapAttribute.EnvironmentMap)).textureDescription));
384 				}
385 			}
386 		};
387 	}
388 
389 	private static String defaultVertexShader = null;
390 
getDefaultVertexShader()391 	public static String getDefaultVertexShader () {
392 		if (defaultVertexShader == null)
393 			defaultVertexShader = Gdx.files.classpath("com/badlogic/gdx/graphics/g3d/shaders/default.vertex.glsl").readString();
394 		return defaultVertexShader;
395 	}
396 
397 	private static String defaultFragmentShader = null;
398 
getDefaultFragmentShader()399 	public static String getDefaultFragmentShader () {
400 		if (defaultFragmentShader == null)
401 			defaultFragmentShader = Gdx.files.classpath("com/badlogic/gdx/graphics/g3d/shaders/default.fragment.glsl").readString();
402 		return defaultFragmentShader;
403 	}
404 
405 	protected static long implementedFlags = BlendingAttribute.Type | TextureAttribute.Diffuse | ColorAttribute.Diffuse
406 		| ColorAttribute.Specular | FloatAttribute.Shininess;
407 
408 	/** @deprecated Replaced by {@link Config#defaultCullFace} Set to 0 to disable culling */
409 	@Deprecated public static int defaultCullFace = GL20.GL_BACK;
410 	/** @deprecated Replaced by {@link Config#defaultDepthFunc} Set to 0 to disable depth test */
411 	@Deprecated public static int defaultDepthFunc = GL20.GL_LEQUAL;
412 
413 	// Global uniforms
414 	public final int u_projTrans;
415 	public final int u_viewTrans;
416 	public final int u_projViewTrans;
417 	public final int u_cameraPosition;
418 	public final int u_cameraDirection;
419 	public final int u_cameraUp;
420 	public final int u_cameraNearFar;
421 	public final int u_time;
422 	// Object uniforms
423 	public final int u_worldTrans;
424 	public final int u_viewWorldTrans;
425 	public final int u_projViewWorldTrans;
426 	public final int u_normalMatrix;
427 	public final int u_bones;
428 	// Material uniforms
429 	public final int u_shininess;
430 	public final int u_opacity;
431 	public final int u_diffuseColor;
432 	public final int u_diffuseTexture;
433 	public final int u_diffuseUVTransform;
434 	public final int u_specularColor;
435 	public final int u_specularTexture;
436 	public final int u_specularUVTransform;
437 	public final int u_emissiveColor;
438 	public final int u_emissiveTexture;
439 	public final int u_emissiveUVTransform;
440 	public final int u_reflectionColor;
441 	public final int u_reflectionTexture;
442 	public final int u_reflectionUVTransform;
443 	public final int u_normalTexture;
444 	public final int u_normalUVTransform;
445 	public final int u_ambientTexture;
446 	public final int u_ambientUVTransform;
447 	public final int u_alphaTest;
448 	// Lighting uniforms
449 	protected final int u_ambientCubemap;
450 	protected final int u_environmentCubemap;
451 	protected final int u_dirLights0color = register(new Uniform("u_dirLights[0].color"));
452 	protected final int u_dirLights0direction = register(new Uniform("u_dirLights[0].direction"));
453 	protected final int u_dirLights1color = register(new Uniform("u_dirLights[1].color"));
454 	protected final int u_pointLights0color = register(new Uniform("u_pointLights[0].color"));
455 	protected final int u_pointLights0position = register(new Uniform("u_pointLights[0].position"));
456 	protected final int u_pointLights0intensity = register(new Uniform("u_pointLights[0].intensity"));
457 	protected final int u_pointLights1color = register(new Uniform("u_pointLights[1].color"));
458 	protected final int u_spotLights0color = register(new Uniform("u_spotLights[0].color"));
459 	protected final int u_spotLights0position = register(new Uniform("u_spotLights[0].position"));
460 	protected final int u_spotLights0intensity = register(new Uniform("u_spotLights[0].intensity"));
461 	protected final int u_spotLights0direction = register(new Uniform("u_spotLights[0].direction"));
462 	protected final int u_spotLights0cutoffAngle = register(new Uniform("u_spotLights[0].cutoffAngle"));
463 	protected final int u_spotLights0exponent = register(new Uniform("u_spotLights[0].exponent"));
464 	protected final int u_spotLights1color = register(new Uniform("u_spotLights[1].color"));
465 	protected final int u_fogColor = register(new Uniform("u_fogColor"));
466 	protected final int u_shadowMapProjViewTrans = register(new Uniform("u_shadowMapProjViewTrans"));
467 	protected final int u_shadowTexture = register(new Uniform("u_shadowTexture"));
468 	protected final int u_shadowPCFOffset = register(new Uniform("u_shadowPCFOffset"));
469 	// FIXME Cache vertex attribute locations...
470 
471 	protected int dirLightsLoc;
472 	protected int dirLightsColorOffset;
473 	protected int dirLightsDirectionOffset;
474 	protected int dirLightsSize;
475 	protected int pointLightsLoc;
476 	protected int pointLightsColorOffset;
477 	protected int pointLightsPositionOffset;
478 	protected int pointLightsIntensityOffset;
479 	protected int pointLightsSize;
480 	protected int spotLightsLoc;
481 	protected int spotLightsColorOffset;
482 	protected int spotLightsPositionOffset;
483 	protected int spotLightsDirectionOffset;
484 	protected int spotLightsIntensityOffset;
485 	protected int spotLightsCutoffAngleOffset;
486 	protected int spotLightsExponentOffset;
487 	protected int spotLightsSize;
488 
489 	protected final boolean lighting;
490 	protected final boolean environmentCubemap;
491 	protected final boolean shadowMap;
492 	protected final AmbientCubemap ambientCubemap = new AmbientCubemap();
493 	protected final DirectionalLight directionalLights[];
494 	protected final PointLight pointLights[];
495 	protected final SpotLight spotLights[];
496 
497 	/** The renderable used to create this shader, invalid after the call to init */
498 	private Renderable renderable;
499 	/** The attributes that this shader supports */
500 	protected final long attributesMask;
501 	private final long vertexMask;
502 	protected final Config config;
503 	/** Attributes which are not required but always supported. */
504 	private final static long optionalAttributes = IntAttribute.CullFace | DepthTestAttribute.Type;
505 
DefaultShader(final Renderable renderable)506 	public DefaultShader (final Renderable renderable) {
507 		this(renderable, new Config());
508 	}
509 
DefaultShader(final Renderable renderable, final Config config)510 	public DefaultShader (final Renderable renderable, final Config config) {
511 		this(renderable, config, createPrefix(renderable, config));
512 	}
513 
DefaultShader(final Renderable renderable, final Config config, final String prefix)514 	public DefaultShader (final Renderable renderable, final Config config, final String prefix) {
515 		this(renderable, config, prefix, config.vertexShader != null ? config.vertexShader : getDefaultVertexShader(),
516 			config.fragmentShader != null ? config.fragmentShader : getDefaultFragmentShader());
517 	}
518 
DefaultShader(final Renderable renderable, final Config config, final String prefix, final String vertexShader, final String fragmentShader)519 	public DefaultShader (final Renderable renderable, final Config config, final String prefix, final String vertexShader,
520 		final String fragmentShader) {
521 		this(renderable, config, new ShaderProgram(prefix + vertexShader, prefix + fragmentShader));
522 	}
523 
DefaultShader(final Renderable renderable, final Config config, final ShaderProgram shaderProgram)524 	public DefaultShader (final Renderable renderable, final Config config, final ShaderProgram shaderProgram) {
525 		final Attributes attributes = combineAttributes(renderable);
526 		this.config = config;
527 		this.program = shaderProgram;
528 		this.lighting = renderable.environment != null;
529 		this.environmentCubemap = attributes.has(CubemapAttribute.EnvironmentMap)
530 			|| (lighting && attributes.has(CubemapAttribute.EnvironmentMap));
531 		this.shadowMap = lighting && renderable.environment.shadowMap != null;
532 		this.renderable = renderable;
533 		attributesMask = attributes.getMask() | optionalAttributes;
534 		vertexMask = renderable.meshPart.mesh.getVertexAttributes().getMask();
535 
536 		this.directionalLights = new DirectionalLight[lighting && config.numDirectionalLights > 0 ? config.numDirectionalLights : 0];
537 		for (int i = 0; i < directionalLights.length; i++)
538 			directionalLights[i] = new DirectionalLight();
539 		this.pointLights = new PointLight[lighting && config.numPointLights > 0 ? config.numPointLights : 0];
540 		for (int i = 0; i < pointLights.length; i++)
541 			pointLights[i] = new PointLight();
542 		this.spotLights = new SpotLight[lighting && config.numSpotLights > 0 ? config.numSpotLights : 0];
543 		for (int i = 0; i < spotLights.length; i++)
544 			spotLights[i] = new SpotLight();
545 
546 		if (!config.ignoreUnimplemented && (implementedFlags & attributesMask) != attributesMask)
547 			throw new GdxRuntimeException("Some attributes not implemented yet (" + attributesMask + ")");
548 
549 		// Global uniforms
550 		u_projTrans = register(Inputs.projTrans, Setters.projTrans);
551 		u_viewTrans = register(Inputs.viewTrans, Setters.viewTrans);
552 		u_projViewTrans = register(Inputs.projViewTrans, Setters.projViewTrans);
553 		u_cameraPosition = register(Inputs.cameraPosition, Setters.cameraPosition);
554 		u_cameraDirection = register(Inputs.cameraDirection, Setters.cameraDirection);
555 		u_cameraUp = register(Inputs.cameraUp, Setters.cameraUp);
556 		u_cameraNearFar = register(Inputs.cameraNearFar, Setters.cameraNearFar);
557 		u_time = register(new Uniform("u_time"));
558 		// Object uniforms
559 		u_worldTrans = register(Inputs.worldTrans, Setters.worldTrans);
560 		u_viewWorldTrans = register(Inputs.viewWorldTrans, Setters.viewWorldTrans);
561 		u_projViewWorldTrans = register(Inputs.projViewWorldTrans, Setters.projViewWorldTrans);
562 		u_normalMatrix = register(Inputs.normalMatrix, Setters.normalMatrix);
563 		u_bones = (renderable.bones != null && config.numBones > 0) ? register(Inputs.bones, new Setters.Bones(config.numBones))
564 			: -1;
565 
566 		u_shininess = register(Inputs.shininess, Setters.shininess);
567 		u_opacity = register(Inputs.opacity);
568 		u_diffuseColor = register(Inputs.diffuseColor, Setters.diffuseColor);
569 		u_diffuseTexture = register(Inputs.diffuseTexture, Setters.diffuseTexture);
570 		u_diffuseUVTransform = register(Inputs.diffuseUVTransform, Setters.diffuseUVTransform);
571 		u_specularColor = register(Inputs.specularColor, Setters.specularColor);
572 		u_specularTexture = register(Inputs.specularTexture, Setters.specularTexture);
573 		u_specularUVTransform = register(Inputs.specularUVTransform, Setters.specularUVTransform);
574 		u_emissiveColor = register(Inputs.emissiveColor, Setters.emissiveColor);
575 		u_emissiveTexture = register(Inputs.emissiveTexture, Setters.emissiveTexture);
576 		u_emissiveUVTransform = register(Inputs.emissiveUVTransform, Setters.emissiveUVTransform);
577 		u_reflectionColor = register(Inputs.reflectionColor, Setters.reflectionColor);
578 		u_reflectionTexture = register(Inputs.reflectionTexture, Setters.reflectionTexture);
579 		u_reflectionUVTransform = register(Inputs.reflectionUVTransform, Setters.reflectionUVTransform);
580 		u_normalTexture = register(Inputs.normalTexture, Setters.normalTexture);
581 		u_normalUVTransform = register(Inputs.normalUVTransform, Setters.normalUVTransform);
582 		u_ambientTexture = register(Inputs.ambientTexture, Setters.ambientTexture);
583 		u_ambientUVTransform = register(Inputs.ambientUVTransform, Setters.ambientUVTransform);
584 		u_alphaTest = register(Inputs.alphaTest);
585 
586 		u_ambientCubemap = lighting ? register(Inputs.ambientCube, new Setters.ACubemap(config.numDirectionalLights,
587 			config.numPointLights)) : -1;
588 		u_environmentCubemap = environmentCubemap ? register(Inputs.environmentCubemap, Setters.environmentCubemap) : -1;
589 	}
590 
591 	@Override
init()592 	public void init () {
593 		final ShaderProgram program = this.program;
594 		this.program = null;
595 		init(program, renderable);
596 		renderable = null;
597 
598 		dirLightsLoc = loc(u_dirLights0color);
599 		dirLightsColorOffset = loc(u_dirLights0color) - dirLightsLoc;
600 		dirLightsDirectionOffset = loc(u_dirLights0direction) - dirLightsLoc;
601 		dirLightsSize = loc(u_dirLights1color) - dirLightsLoc;
602 		if (dirLightsSize < 0) dirLightsSize = 0;
603 
604 		pointLightsLoc = loc(u_pointLights0color);
605 		pointLightsColorOffset = loc(u_pointLights0color) - pointLightsLoc;
606 		pointLightsPositionOffset = loc(u_pointLights0position) - pointLightsLoc;
607 		pointLightsIntensityOffset = has(u_pointLights0intensity) ? loc(u_pointLights0intensity) - pointLightsLoc : -1;
608 		pointLightsSize = loc(u_pointLights1color) - pointLightsLoc;
609 		if (pointLightsSize < 0) pointLightsSize = 0;
610 
611 		spotLightsLoc = loc(u_spotLights0color);
612 		spotLightsColorOffset = loc(u_spotLights0color) - spotLightsLoc;
613 		spotLightsPositionOffset = loc(u_spotLights0position) - spotLightsLoc;
614 		spotLightsDirectionOffset = loc(u_spotLights0direction) - spotLightsLoc;
615 		spotLightsIntensityOffset = has(u_spotLights0intensity) ? loc(u_spotLights0intensity) - spotLightsLoc : -1;
616 		spotLightsCutoffAngleOffset = loc(u_spotLights0cutoffAngle) - spotLightsLoc;
617 		spotLightsExponentOffset = loc(u_spotLights0exponent) - spotLightsLoc;
618 		spotLightsSize = loc(u_spotLights1color) - spotLightsLoc;
619 		if (spotLightsSize < 0) spotLightsSize = 0;
620 	}
621 
and(final long mask, final long flag)622 	private static final boolean and (final long mask, final long flag) {
623 		return (mask & flag) == flag;
624 	}
625 
or(final long mask, final long flag)626 	private static final boolean or (final long mask, final long flag) {
627 		return (mask & flag) != 0;
628 	}
629 
630 	private final static Attributes tmpAttributes = new Attributes();
631 
632 	// TODO: Perhaps move responsibility for combining attributes to RenderableProvider?
combineAttributes(final Renderable renderable)633 	private static final Attributes combineAttributes (final Renderable renderable) {
634 		tmpAttributes.clear();
635 		if (renderable.environment != null) tmpAttributes.set(renderable.environment);
636 		if (renderable.material != null) tmpAttributes.set(renderable.material);
637 		return tmpAttributes;
638 	}
639 
createPrefix(final Renderable renderable, final Config config)640 	public static String createPrefix (final Renderable renderable, final Config config) {
641 		final Attributes attributes = combineAttributes(renderable);
642 		String prefix = "";
643 		final long attributesMask = attributes.getMask();
644 		final long vertexMask = renderable.meshPart.mesh.getVertexAttributes().getMask();
645 		if (and(vertexMask, Usage.Position)) prefix += "#define positionFlag\n";
646 		if (or(vertexMask, Usage.ColorUnpacked | Usage.ColorPacked)) prefix += "#define colorFlag\n";
647 		if (and(vertexMask, Usage.BiNormal)) prefix += "#define binormalFlag\n";
648 		if (and(vertexMask, Usage.Tangent)) prefix += "#define tangentFlag\n";
649 		if (and(vertexMask, Usage.Normal)) prefix += "#define normalFlag\n";
650 		if (and(vertexMask, Usage.Normal) || and(vertexMask, Usage.Tangent | Usage.BiNormal)) {
651 			if (renderable.environment != null) {
652 				prefix += "#define lightingFlag\n";
653 				prefix += "#define ambientCubemapFlag\n";
654 				prefix += "#define numDirectionalLights " + config.numDirectionalLights + "\n";
655 				prefix += "#define numPointLights " + config.numPointLights + "\n";
656 				prefix += "#define numSpotLights " + config.numSpotLights + "\n";
657 				if (attributes.has(ColorAttribute.Fog)) {
658 					prefix += "#define fogFlag\n";
659 				}
660 				if (renderable.environment.shadowMap != null) prefix += "#define shadowMapFlag\n";
661 				if (attributes.has(CubemapAttribute.EnvironmentMap)) prefix += "#define environmentCubemapFlag\n";
662 			}
663 		}
664 		final int n = renderable.meshPart.mesh.getVertexAttributes().size();
665 		for (int i = 0; i < n; i++) {
666 			final VertexAttribute attr = renderable.meshPart.mesh.getVertexAttributes().get(i);
667 			if (attr.usage == Usage.BoneWeight)
668 				prefix += "#define boneWeight" + attr.unit + "Flag\n";
669 			else if (attr.usage == Usage.TextureCoordinates) prefix += "#define texCoord" + attr.unit + "Flag\n";
670 		}
671 		if ((attributesMask & BlendingAttribute.Type) == BlendingAttribute.Type)
672 			prefix += "#define " + BlendingAttribute.Alias + "Flag\n";
673 		if ((attributesMask & TextureAttribute.Diffuse) == TextureAttribute.Diffuse) {
674 			prefix += "#define " + TextureAttribute.DiffuseAlias + "Flag\n";
675 			prefix += "#define " + TextureAttribute.DiffuseAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
676 		}
677 		if ((attributesMask & TextureAttribute.Specular) == TextureAttribute.Specular) {
678 			prefix += "#define " + TextureAttribute.SpecularAlias + "Flag\n";
679 			prefix += "#define " + TextureAttribute.SpecularAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
680 		}
681 		if ((attributesMask & TextureAttribute.Normal) == TextureAttribute.Normal) {
682 			prefix += "#define " + TextureAttribute.NormalAlias + "Flag\n";
683 			prefix += "#define " + TextureAttribute.NormalAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
684 		}
685 		if ((attributesMask & TextureAttribute.Emissive) == TextureAttribute.Emissive) {
686 			prefix += "#define " + TextureAttribute.EmissiveAlias + "Flag\n";
687 			prefix += "#define " + TextureAttribute.EmissiveAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
688 		}
689 		if ((attributesMask & TextureAttribute.Reflection) == TextureAttribute.Reflection) {
690 			prefix += "#define " + TextureAttribute.ReflectionAlias + "Flag\n";
691 			prefix += "#define " + TextureAttribute.ReflectionAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
692 		}
693 		if ((attributesMask & TextureAttribute.Ambient) == TextureAttribute.Ambient) {
694 			prefix += "#define " + TextureAttribute.AmbientAlias + "Flag\n";
695 			prefix += "#define " + TextureAttribute.AmbientAlias + "Coord texCoord0\n"; // FIXME implement UV mapping
696 		}
697 		if ((attributesMask & ColorAttribute.Diffuse) == ColorAttribute.Diffuse)
698 			prefix += "#define " + ColorAttribute.DiffuseAlias + "Flag\n";
699 		if ((attributesMask & ColorAttribute.Specular) == ColorAttribute.Specular)
700 			prefix += "#define " + ColorAttribute.SpecularAlias + "Flag\n";
701 		if ((attributesMask & ColorAttribute.Emissive) == ColorAttribute.Emissive)
702 			prefix += "#define " + ColorAttribute.EmissiveAlias + "Flag\n";
703 		if ((attributesMask & ColorAttribute.Reflection) == ColorAttribute.Reflection)
704 			prefix += "#define " + ColorAttribute.ReflectionAlias + "Flag\n";
705 		if ((attributesMask & FloatAttribute.Shininess) == FloatAttribute.Shininess)
706 			prefix += "#define " + FloatAttribute.ShininessAlias + "Flag\n";
707 		if ((attributesMask & FloatAttribute.AlphaTest) == FloatAttribute.AlphaTest)
708 			prefix += "#define " + FloatAttribute.AlphaTestAlias + "Flag\n";
709 		if (renderable.bones != null && config.numBones > 0) prefix += "#define numBones " + config.numBones + "\n";
710 		return prefix;
711 	}
712 
713 	@Override
canRender(final Renderable renderable)714 	public boolean canRender (final Renderable renderable) {
715 		final Attributes attributes = combineAttributes(renderable);
716 		return (attributesMask == (attributes.getMask() | optionalAttributes))
717 			&& (vertexMask == renderable.meshPart.mesh.getVertexAttributes().getMask()) && (renderable.environment != null) == lighting;
718 	}
719 
720 	@Override
compareTo(Shader other)721 	public int compareTo (Shader other) {
722 		if (other == null) return -1;
723 		if (other == this) return 0;
724 		return 0; // FIXME compare shaders on their impact on performance
725 	}
726 
727 	@Override
equals(Object obj)728 	public boolean equals (Object obj) {
729 		return (obj instanceof DefaultShader) ? equals((DefaultShader)obj) : false;
730 	}
731 
equals(DefaultShader obj)732 	public boolean equals (DefaultShader obj) {
733 		return (obj == this);
734 	}
735 
736 	private final Matrix3 normalMatrix = new Matrix3();
737 	private float time;
738 	private boolean lightsSet;
739 
740 	@Override
begin(final Camera camera, final RenderContext context)741 	public void begin (final Camera camera, final RenderContext context) {
742 		super.begin(camera, context);
743 
744 		for (final DirectionalLight dirLight : directionalLights)
745 			dirLight.set(0, 0, 0, 0, -1, 0);
746 		for (final PointLight pointLight : pointLights)
747 			pointLight.set(0, 0, 0, 0, 0, 0, 0);
748 		for (final SpotLight spotLight : spotLights)
749 			spotLight.set(0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0);
750 		lightsSet = false;
751 
752 		if (has(u_time)) set(u_time, time += Gdx.graphics.getDeltaTime());
753 	}
754 
755 	@Override
render(Renderable renderable, Attributes combinedAttributes)756 	public void render (Renderable renderable, Attributes combinedAttributes) {
757 		if (!combinedAttributes.has(BlendingAttribute.Type))
758 			context.setBlending(false, GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
759 		bindMaterial(combinedAttributes);
760 		if (lighting) bindLights(renderable, combinedAttributes);
761 		super.render(renderable, combinedAttributes);
762 	}
763 
764 	@Override
end()765 	public void end () {
766 		super.end();
767 	}
768 
bindMaterial(final Attributes attributes)769 	protected void bindMaterial (final Attributes attributes) {
770 		int cullFace = config.defaultCullFace == -1 ? defaultCullFace : config.defaultCullFace;
771 		int depthFunc = config.defaultDepthFunc == -1 ? defaultDepthFunc : config.defaultDepthFunc;
772 		float depthRangeNear = 0f;
773 		float depthRangeFar = 1f;
774 		boolean depthMask = true;
775 
776 		for (final Attribute attr : attributes) {
777 			final long t = attr.type;
778 			if (BlendingAttribute.is(t)) {
779 				context.setBlending(true, ((BlendingAttribute)attr).sourceFunction, ((BlendingAttribute)attr).destFunction);
780 				set(u_opacity, ((BlendingAttribute)attr).opacity);
781 			} else if ((t & IntAttribute.CullFace) == IntAttribute.CullFace)
782 				cullFace = ((IntAttribute)attr).value;
783 			else if ((t & FloatAttribute.AlphaTest) == FloatAttribute.AlphaTest)
784 				set(u_alphaTest, ((FloatAttribute)attr).value);
785 			else if ((t & DepthTestAttribute.Type) == DepthTestAttribute.Type) {
786 				DepthTestAttribute dta = (DepthTestAttribute)attr;
787 				depthFunc = dta.depthFunc;
788 				depthRangeNear = dta.depthRangeNear;
789 				depthRangeFar = dta.depthRangeFar;
790 				depthMask = dta.depthMask;
791 			} else if (!config.ignoreUnimplemented) throw new GdxRuntimeException("Unknown material attribute: " + attr.toString());
792 		}
793 
794 		context.setCullFace(cullFace);
795 		context.setDepthTest(depthFunc, depthRangeNear, depthRangeFar);
796 		context.setDepthMask(depthMask);
797 	}
798 
799 	private final Vector3 tmpV1 = new Vector3();
800 
bindLights(final Renderable renderable, final Attributes attributes)801 	protected void bindLights (final Renderable renderable, final Attributes attributes) {
802 		final Environment lights = renderable.environment;
803 		final DirectionalLightsAttribute dla = attributes.get(DirectionalLightsAttribute.class, DirectionalLightsAttribute.Type);
804 		final Array<DirectionalLight> dirs = dla == null ? null : dla.lights;
805 		final PointLightsAttribute pla = attributes.get(PointLightsAttribute.class, PointLightsAttribute.Type);
806 		final Array<PointLight> points = pla == null ? null : pla.lights;
807 		final SpotLightsAttribute sla = attributes.get(SpotLightsAttribute.class, SpotLightsAttribute.Type);
808 		final Array<SpotLight> spots = sla == null ? null : sla.lights;
809 
810 		if (dirLightsLoc >= 0) {
811 			for (int i = 0; i < directionalLights.length; i++) {
812 				if (dirs == null || i >= dirs.size) {
813 					if (lightsSet && directionalLights[i].color.r == 0f && directionalLights[i].color.g == 0f
814 						&& directionalLights[i].color.b == 0f) continue;
815 					directionalLights[i].color.set(0, 0, 0, 1);
816 				} else if (lightsSet && directionalLights[i].equals(dirs.get(i)))
817 					continue;
818 				else
819 					directionalLights[i].set(dirs.get(i));
820 
821 				int idx = dirLightsLoc + i * dirLightsSize;
822 				program.setUniformf(idx + dirLightsColorOffset, directionalLights[i].color.r, directionalLights[i].color.g,
823 					directionalLights[i].color.b);
824 				program.setUniformf(idx + dirLightsDirectionOffset, directionalLights[i].direction.x,
825 					directionalLights[i].direction.y, directionalLights[i].direction.z);
826 				if (dirLightsSize <= 0) break;
827 			}
828 		}
829 
830 		if (pointLightsLoc >= 0) {
831 			for (int i = 0; i < pointLights.length; i++) {
832 				if (points == null || i >= points.size) {
833 					if (lightsSet && pointLights[i].intensity == 0f) continue;
834 					pointLights[i].intensity = 0f;
835 				} else if (lightsSet && pointLights[i].equals(points.get(i)))
836 					continue;
837 				else
838 					pointLights[i].set(points.get(i));
839 
840 				int idx = pointLightsLoc + i * pointLightsSize;
841 				program.setUniformf(idx + pointLightsColorOffset, pointLights[i].color.r * pointLights[i].intensity,
842 					pointLights[i].color.g * pointLights[i].intensity, pointLights[i].color.b * pointLights[i].intensity);
843 				program.setUniformf(idx + pointLightsPositionOffset, pointLights[i].position.x, pointLights[i].position.y,
844 					pointLights[i].position.z);
845 				if (pointLightsIntensityOffset >= 0) program.setUniformf(idx + pointLightsIntensityOffset, pointLights[i].intensity);
846 				if (pointLightsSize <= 0) break;
847 			}
848 		}
849 
850 		if (spotLightsLoc >= 0) {
851 			for (int i = 0; i < spotLights.length; i++) {
852 				if (spots == null || i >= spots.size) {
853 					if (lightsSet && spotLights[i].intensity == 0f) continue;
854 					spotLights[i].intensity = 0f;
855 				} else if (lightsSet && spotLights[i].equals(spots.get(i)))
856 					continue;
857 				else
858 					spotLights[i].set(spots.get(i));
859 
860 				int idx = spotLightsLoc + i * spotLightsSize;
861 				program.setUniformf(idx + spotLightsColorOffset, spotLights[i].color.r * spotLights[i].intensity,
862 					spotLights[i].color.g * spotLights[i].intensity, spotLights[i].color.b * spotLights[i].intensity);
863 				program.setUniformf(idx + spotLightsPositionOffset, spotLights[i].position);
864 				program.setUniformf(idx + spotLightsDirectionOffset, spotLights[i].direction);
865 				program.setUniformf(idx + spotLightsCutoffAngleOffset, spotLights[i].cutoffAngle);
866 				program.setUniformf(idx + spotLightsExponentOffset, spotLights[i].exponent);
867 				if (spotLightsIntensityOffset >= 0)
868 					program.setUniformf(idx + spotLightsIntensityOffset, spotLights[i].intensity);
869 				if (spotLightsSize <= 0) break;
870 			}
871 		}
872 
873 		if (attributes.has(ColorAttribute.Fog)) {
874 			set(u_fogColor, ((ColorAttribute)attributes.get(ColorAttribute.Fog)).color);
875 		}
876 
877 		if (lights != null && lights.shadowMap != null) {
878 			set(u_shadowMapProjViewTrans, lights.shadowMap.getProjViewTrans());
879 			set(u_shadowTexture, lights.shadowMap.getDepthMap());
880 			set(u_shadowPCFOffset, 1.f / (2f * lights.shadowMap.getDepthMap().texture.getWidth()));
881 		}
882 
883 		lightsSet = true;
884 	}
885 
886 	@Override
dispose()887 	public void dispose () {
888 		program.dispose();
889 		super.dispose();
890 	}
891 
getDefaultCullFace()892 	public int getDefaultCullFace () {
893 		return config.defaultCullFace == -1 ? defaultCullFace : config.defaultCullFace;
894 	}
895 
setDefaultCullFace(int cullFace)896 	public void setDefaultCullFace (int cullFace) {
897 		config.defaultCullFace = cullFace;
898 	}
899 
getDefaultDepthFunc()900 	public int getDefaultDepthFunc () {
901 		return config.defaultDepthFunc == -1 ? defaultDepthFunc : config.defaultDepthFunc;
902 	}
903 
setDefaultDepthFunc(int depthFunc)904 	public void setDefaultDepthFunc (int depthFunc) {
905 		config.defaultDepthFunc = depthFunc;
906 	}
907 }
908