/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.tests.g3d.shadows.system.classical;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.Attributes;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.DepthTestAttribute;
import com.badlogic.gdx.graphics.g3d.environment.BaseLight;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.environment.PointLight;
import com.badlogic.gdx.graphics.g3d.environment.SpotLight;
import com.badlogic.gdx.graphics.g3d.shaders.BaseShader;
import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
/** This shader accumulates shadow with blending
* @author realitix */
public class Pass2Shader extends DefaultShader {
public static class Config extends DefaultShader.Config {
public ClassicalShadowSystem shadowSystem;
public Config (ClassicalShadowSystem shadowSystem) {
super();
this.shadowSystem = shadowSystem;
}
}
public static class Inputs extends DefaultShader.Inputs {
public final static Uniform shadowMapProjViewTrans = new Uniform("u_shadowMapProjViewTrans");
public final static Uniform shadowTexture = new Uniform("u_shadowTexture");
public final static Uniform uvTransform = new Uniform("u_uvTransform");
public final static Uniform lightColor = new Uniform("u_lightColor");
public final static Uniform lightDirection = new Uniform("u_lightDirection");
public final static Uniform lightIntensity = new Uniform("u_lightIntensity");
public final static Uniform lightPosition = new Uniform("u_lightPosition");
public final static Uniform lightCutoffAngle = new Uniform("u_lightCutoffAngle");
public final static Uniform lightExponent = new Uniform("u_lightExponent");
}
public static class Setters extends DefaultShader.Setters {
public final static Setter shadowMapProjViewTrans = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
shader.set(inputID, shadowSystem.getCurrentLightProperties().camera.combined);
}
};
public final static Setter shadowTexture = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
shader.set(inputID, shadowSystem.getTexture(0));
}
};
public final static Setter uvTransform = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
final TextureRegion tr = shadowSystem.getCurrentLightProperties().region;
shader.set(inputID, tr.getU(), tr.getV(), tr.getU2() - tr.getU(), tr.getV2() - tr.getV());
}
};
public final static Setter lightColor = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
BaseLight l = shadowSystem.getCurrentLight();
float intensity = 1;
if (l instanceof PointLight) intensity = ((PointLight)l).intensity;
if (l instanceof SpotLight) intensity = ((SpotLight)l).intensity;
shader.set(inputID, l.color.r * intensity, l.color.g * intensity, l.color.b * intensity);
}
};
public final static Setter lightDirection = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
BaseLight l = shadowSystem.getCurrentLight();
if (l instanceof DirectionalLight) {
shader.set(inputID, ((DirectionalLight)l).direction);
}
if (l instanceof SpotLight) {
shader.set(inputID, ((SpotLight)l).direction);
}
if (l instanceof PointLight) {
shader.set(inputID, shadowSystem.getCurrentLightProperties().camera.direction);
}
}
};
public final static Setter lightIntensity = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
BaseLight l = shadowSystem.getCurrentLight();
if (l instanceof PointLight) {
shader.set(inputID, ((PointLight)l).intensity);
}
if (l instanceof SpotLight) {
shader.set(inputID, ((SpotLight)l).intensity);
}
}
};
public final static Setter lightPosition = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
BaseLight l = shadowSystem.getCurrentLight();
if (l instanceof PointLight) {
shader.set(inputID, ((PointLight)l).position);
}
if (l instanceof SpotLight) {
shader.set(inputID, ((SpotLight)l).position);
}
}
};
public final static Setter lightCutoffAngle = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
if (!(shadowSystem.getCurrentLight() instanceof DirectionalLight)) {
shader.set(inputID, ((PerspectiveCamera)shadowSystem.getCurrentLightProperties().camera).fieldOfView);
}
}
};
public final static Setter lightExponent = new GlobalSetter() {
@Override
public void set (BaseShader shader, int inputID, Renderable renderable, Attributes combinedAttributes) {
BaseLight l = shadowSystem.getCurrentLight();
if (l instanceof SpotLight) {
shader.set(inputID, ((SpotLight)l).exponent);
}
if (l instanceof PointLight) {
shader.set(inputID, (float)0);
}
}
};
}
protected static ClassicalShadowSystem shadowSystem;
private static String defaultVertexShader = null;
public static String getDefaultVertexShader () {
if (defaultVertexShader == null)
defaultVertexShader = Gdx.files.classpath("com/badlogic/gdx/tests/g3d/shadows/system/classical/pass2.vertex.glsl")
.readString();
return defaultVertexShader;
}
private static String defaultFragmentShader = null;
public static String getDefaultFragmentShader () {
if (defaultFragmentShader == null)
defaultFragmentShader = Gdx.files.classpath("com/badlogic/gdx/tests/g3d/shadows/system/classical/pass2.fragment.glsl")
.readString();
return defaultFragmentShader;
}
protected BlendingAttribute blend = new BlendingAttribute(GL20.GL_ONE, GL20.GL_ONE);
protected DepthTestAttribute depth = new DepthTestAttribute(GL20.GL_LEQUAL);
protected int lightType = -1;
public static final int LIGHT_SPOT = 0;
public static final int LIGHT_DIR = 1;
public Pass2Shader (final Renderable renderable, final Config config) {
this(renderable, config, createPrefix(renderable, config));
}
public Pass2Shader (final Renderable renderable, final Config config, final String prefix) {
this(renderable, config, prefix, config.vertexShader != null ? config.vertexShader : getDefaultVertexShader(),
config.fragmentShader != null ? config.fragmentShader : getDefaultFragmentShader());
}
public Pass2Shader (final Renderable renderable, final Config config, final String prefix, final String vertexShader,
final String fragmentShader) {
this(renderable, config, new ShaderProgram(prefix + vertexShader, prefix + fragmentShader));
}
public Pass2Shader (final Renderable renderable, final Config config, final ShaderProgram shaderProgram) {
super(renderable, config, shaderProgram);
shadowSystem = config.shadowSystem;
register(Inputs.shadowMapProjViewTrans, Setters.shadowMapProjViewTrans);
register(Inputs.shadowTexture, Setters.shadowTexture);
register(Inputs.uvTransform, Setters.uvTransform);
register(Inputs.lightColor, Setters.lightColor);
register(Inputs.lightDirection, Setters.lightDirection);
register(Inputs.lightPosition, Setters.lightPosition);
register(Inputs.lightIntensity, Setters.lightIntensity);
register(Inputs.lightCutoffAngle, Setters.lightCutoffAngle);
register(Inputs.lightExponent, Setters.lightExponent);
}
public static String createPrefix (final Renderable renderable, final Config config) {
String prefix = DefaultShader.createPrefix(renderable, config);
boolean dir = (config.shadowSystem.getCurrentLight() instanceof DirectionalLight);
if (dir)
prefix += "#define directionalLight\n";
else
prefix += "#define spotLight\n";
return prefix;
}
@Override
public void render (Renderable renderable, Attributes combinedAttributes) {
if (shadowSystem.isFirstCallPass2())
combinedAttributes.remove(BlendingAttribute.Type);
else
combinedAttributes.set(blend);
combinedAttributes.set(depth);
super.render(renderable, combinedAttributes);
}
@Override
public boolean canRender (Renderable renderable) {
boolean ok = super.canRender(renderable);
boolean dir = (shadowSystem.getCurrentLight() instanceof DirectionalLight);
if (lightType == -1) {
lightType = LIGHT_SPOT;
if (dir) lightType = LIGHT_DIR;
}
if (dir && lightType != LIGHT_DIR) ok = false;
if (!dir && lightType != LIGHT_SPOT) ok = false;
return ok;
}
}