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