/*******************************************************************************
* 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.realistic;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.Attributes;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.attributes.DirectionalLightsAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.SpotLightsAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.environment.SpotLight;
import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.tests.g3d.shadows.system.BaseShadowSystem.LightProperties;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
/** This shader is used by the realistic shadow system. This shader supports normal mapping and specular mapping
* @author realitix */
public class MainShader extends DefaultShader {
public static class Config extends DefaultShader.Config {
public RealisticShadowSystem shadowSystem;
public Config (RealisticShadowSystem shadowSystem) {
super();
numBones = 12;
numPointLights = 2;
numSpotLights = 5;
numDirectionalLights = 2;
this.shadowSystem = shadowSystem;
}
}
/** **** Directional shadow **** */
protected final int u_dirShadows0uvTransform = register(new Uniform("u_dirShadows[0].uvTransform"));
protected final int u_dirShadows1uvTransform = register(new Uniform("u_dirShadows[1].uvTransform"));
protected int dirShadowsLoc;
protected int dirShadowsUvTransformOffset;
protected int dirShadowsSize;
// Shadow projViewTrans
protected int u_dirShadowMapProjViewTrans0 = register(new Uniform("u_dirShadowMapProjViewTrans[0]"));
protected int u_dirShadowMapProjViewTrans1 = register(new Uniform("u_dirShadowMapProjViewTrans[1]"));
protected int dirShadowMapProjViewTransLoc;
protected int dirShadowMapProjViewTransSize;
// Shadow UVTransform
protected int u_dirShadowMapUVTransform0 = register(new Uniform("u_dirShadowMapUVTransform[0]"));
protected int u_dirShadowMapUVTransform1 = register(new Uniform("u_dirShadowMapUVTransform[1]"));
protected int dirShadowMapUVTransformLoc;
protected int dirShadowMapUVTransformSize;
/** **** Spot shadow **** */
protected final int u_spotShadows0uvTransform = register(new Uniform("u_spotShadows[0].uvTransform"));
protected final int u_spotShadows1uvTransform = register(new Uniform("u_spotShadows[1].uvTransform"));
protected int spotShadowsLoc;
protected int spotShadowsUvTransformOffset;
protected int spotShadowsSize;
// Shadow projViewTrans
protected int u_spotShadowMapProjViewTrans0 = register(new Uniform("u_spotShadowMapProjViewTrans[0]"));
protected int u_spotShadowMapProjViewTrans1 = register(new Uniform("u_spotShadowMapProjViewTrans[1]"));
protected int spotShadowMapProjViewTransLoc;
protected int spotShadowMapProjViewTransSize;
// Shadow UVTransform
protected int u_spotShadowMapUVTransform0 = register(new Uniform("u_spotShadowMapUVTransform[0]"));
protected int u_spotShadowMapUVTransform1 = register(new Uniform("u_spotShadowMapUVTransform[1]"));
protected int spotShadowMapUVTransformLoc;
protected int spotShadowMapUVTransformSize;
protected RealisticShadowSystem shadowSystem;
private static String defaultVertexShader = null;
public static String getDefaultVertexShader () {
if (defaultVertexShader == null)
defaultVertexShader = Gdx.files.classpath("com/badlogic/gdx/tests/g3d/shadows/system/realistic/main.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/realistic/main.fragment.glsl")
.readString();
return defaultFragmentShader;
}
public static String createPrefix (final Renderable renderable, final Config config) {
return DefaultShader.createPrefix(renderable, config);
}
public MainShader (final Renderable renderable, final Config config) {
this(renderable, config, createPrefix(renderable, config));
}
public MainShader (final Renderable renderable, final Config config, final String prefix) {
this(renderable, config, prefix, getDefaultVertexShader(), getDefaultFragmentShader());
}
public MainShader (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 MainShader (final Renderable renderable, final Config config, final ShaderProgram shaderProgram) {
super(renderable, config, shaderProgram);
this.shadowSystem = config.shadowSystem;
}
@Override
public void init () {
super.init();
// Directional Shadow
dirShadowsLoc = loc(u_dirShadows0uvTransform);
dirShadowsUvTransformOffset = loc(u_dirShadows0uvTransform) - dirShadowsLoc;
dirShadowsSize = loc(u_dirShadows1uvTransform) - dirShadowsLoc;
if (dirShadowsSize < 0) dirShadowsSize = 0;
dirShadowMapProjViewTransLoc = loc(u_dirShadowMapProjViewTrans0);
dirShadowMapProjViewTransSize = loc(u_dirShadowMapProjViewTrans1) - dirShadowMapProjViewTransLoc;
dirShadowMapUVTransformLoc = loc(u_dirShadowMapUVTransform0);
dirShadowMapUVTransformSize = loc(u_dirShadowMapUVTransform1) - dirShadowMapUVTransformLoc;
// Spot Shadow
spotShadowsLoc = loc(u_spotShadows0uvTransform);
spotShadowsUvTransformOffset = loc(u_spotShadows0uvTransform) - spotShadowsLoc;
spotShadowsSize = loc(u_spotShadows1uvTransform) - spotShadowsLoc;
if (spotShadowsSize < 0) spotShadowsSize = 0;
spotShadowMapProjViewTransLoc = loc(u_spotShadowMapProjViewTrans0);
spotShadowMapProjViewTransSize = loc(u_spotShadowMapProjViewTrans1) - spotShadowMapProjViewTransLoc;
spotShadowMapUVTransformLoc = loc(u_spotShadowMapUVTransform0);
spotShadowMapUVTransformSize = loc(u_spotShadowMapUVTransform1) - spotShadowMapUVTransformLoc;
}
@Override
protected void bindLights (final Renderable renderable, final Attributes attributes) {
super.bindLights(renderable, attributes);
final Environment environment = renderable.environment;
bindDirectionalShadows(attributes);
bindSpotShadows(attributes);
if (shadowSystem.getTexture() != null) {
set(u_shadowTexture, shadowSystem.getTexture());
}
}
public void bindDirectionalShadows (final Attributes attributes) {
final DirectionalLightsAttribute dla = attributes.get(DirectionalLightsAttribute.class, DirectionalLightsAttribute.Type);
final Array<DirectionalLight> dirs = dla == null ? null : dla.lights;
if (dirLightsLoc >= 0) {
for (int i = 0; i < directionalLights.length; i++) {
if (dirs == null || dirs.size <= i) {
continue;
}
int idx = dirShadowsLoc + i * dirShadowsSize;
// Shadow
ObjectMap<DirectionalLight, LightProperties> dirCameras = shadowSystem.getDirectionalCameras();
DirectionalLight dl = dirs.get(i);
if (shadowSystem.hasLight(dl)) {
// UVTransform
final TextureRegion tr = dirCameras.get(dl).region;
Camera cam = dirCameras.get(dl).camera;
if (cam != null) {
program.setUniformf(idx + dirShadowsUvTransformOffset, tr.getU(), tr.getV(), tr.getU2() - tr.getU(), tr.getV2()
- tr.getV());
// ProjViewTrans
idx = dirShadowMapProjViewTransLoc + i * dirShadowMapProjViewTransSize;
program.setUniformMatrix(idx, dirCameras.get(dl).camera.combined);
}
}
if (dirLightsSize <= 0) break;
}
}
}
public void bindSpotShadows (final Attributes attributes) {
final SpotLightsAttribute sla = attributes.get(SpotLightsAttribute.class, SpotLightsAttribute.Type);
final Array<SpotLight> spots = sla == null ? null : sla.lights;
if (spotLightsLoc >= 0) {
for (int i = 0; i < spotLights.length; i++) {
if (spots == null || spots.size <= i) {
continue;
}
int idx = spotShadowsLoc + i * spotShadowsSize;
// Shadow
ObjectMap<SpotLight, LightProperties> spotCameras = shadowSystem.getSpotCameras();
SpotLight sl = spots.get(i);
if (shadowSystem.hasLight(sl)) {
// UVTransform
final TextureRegion tr = spotCameras.get(sl).region;
Camera cam = spotCameras.get(sl).camera;
if (cam != null) {
program.setUniformf(idx + spotShadowsUvTransformOffset, tr.getU(), tr.getV(), tr.getU2() - tr.getU(),
tr.getV2() - tr.getV());
// ProjViewTrans
idx = spotShadowMapProjViewTransLoc + i * spotShadowMapProjViewTransSize;
program.setUniformMatrix(idx, spotCameras.get(sl).camera.combined);
}
}
if (spotLightsSize <= 0) break;
}
}
}
}