Home | History | Annotate | Download | only in shaders
      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 
     72 		public Config () {
     73 		}
     74 
     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 
    202 			public Bones (final int numBones) {
    203 				this.bones = new float[numBones * 16];
    204 			}
    205 
    206 			@Override
    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 
    345 			public ACubemap (final int dirLightsOffset, final int pointLightsOffset) {
    346 				this.dirLightsOffset = dirLightsOffset;
    347 				this.pointLightsOffset = pointLightsOffset;
    348 			}
    349 
    350 			@Override
    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 
    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 
    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 
    506 	public DefaultShader (final Renderable renderable) {
    507 		this(renderable, new Config());
    508 	}
    509 
    510 	public DefaultShader (final Renderable renderable, final Config config) {
    511 		this(renderable, config, createPrefix(renderable, config));
    512 	}
    513 
    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 
    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 
    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
    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 
    622 	private static final boolean and (final long mask, final long flag) {
    623 		return (mask & flag) == flag;
    624 	}
    625 
    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?
    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 
    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
    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
    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
    728 	public boolean equals (Object obj) {
    729 		return (obj instanceof DefaultShader) ? equals((DefaultShader)obj) : false;
    730 	}
    731 
    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
    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
    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
    765 	public void end () {
    766 		super.end();
    767 	}
    768 
    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 
    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
    887 	public void dispose () {
    888 		program.dispose();
    889 		super.dispose();
    890 	}
    891 
    892 	public int getDefaultCullFace () {
    893 		return config.defaultCullFace == -1 ? defaultCullFace : config.defaultCullFace;
    894 	}
    895 
    896 	public void setDefaultCullFace (int cullFace) {
    897 		config.defaultCullFace = cullFace;
    898 	}
    899 
    900 	public int getDefaultDepthFunc () {
    901 		return config.defaultDepthFunc == -1 ? defaultDepthFunc : config.defaultDepthFunc;
    902 	}
    903 
    904 	public void setDefaultDepthFunc (int depthFunc) {
    905 		config.defaultDepthFunc = depthFunc;
    906 	}
    907 }
    908