package org.osm2world.core.target.jogl;
import static javax.media.opengl.GL.GL_REPEAT;
import static javax.media.opengl.GL.GL_TEXTURE_2D;
import static javax.media.opengl.GL.GL_TEXTURE_WRAP_S;
import static javax.media.opengl.GL.GL_TEXTURE_WRAP_T;
import static javax.media.opengl.GL2GL3.GL_CLAMP_TO_BORDER;
import static javax.media.opengl.GL2GL3.GL_TEXTURE_BORDER_COLOR;
import static org.osm2world.core.target.jogl.AbstractJOGLTarget.getFloatBuffer;
import java.awt.Color;
import java.nio.FloatBuffer;
import javax.media.opengl.GL;
import javax.media.opengl.GL3;
import org.osm2world.core.target.common.TextureData;
import org.osm2world.core.target.common.TextureData.Wrap;
import org.osm2world.core.target.common.material.Material;
import org.osm2world.core.target.common.material.Material.Transparency;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.texture.Texture;
/**
* Shader that renders the depth buffer only. Supports transparent texture layers with {@link #USE_TRANSPARENCY}.
*/
public class DepthBufferShader extends AbstractPrimitiveShader {
public static final boolean USE_TRANSPARENCY = true;
private int modelViewProjectionMatrixID;
private int vertexPositionID;
private int[] vertexTexCoordID = new int[DefaultShader.MAX_TEXTURE_LAYERS];
public DepthBufferShader(GL3 gl) {
super(gl, "/shaders/shadowmap");
// get indices of named attributes
vertexPositionID = gl.glGetAttribLocation(shaderProgram, "VertexPosition");
for (int i=0; i<DefaultShader.MAX_TEXTURE_LAYERS; i++)
vertexTexCoordID[i] = gl.glGetAttribLocation(shaderProgram, "VertexTexCoord"+i+"");
// get indices of uniform variables
modelViewProjectionMatrixID = gl.glGetUniformLocation(shaderProgram, "ModelViewProjectionMatrix");
this.validateShader();
}
/**
* Send uniform matrices "ProjectionMatrix, ModelViewMatrix and ModelViewProjectionMatrix" to vertex shader
* @param pmvMatrix
*/
public void setPMVMatrix(PMVMatrix pmvMatrix) {
FloatBuffer pmvMat = FloatBuffer.allocate(16);
FloatUtil.multMatrixf(pmvMatrix.glGetPMatrixf(), pmvMatrix.glGetMvMatrixf(), pmvMat);
gl.glUniformMatrix4fv(this.getModelViewProjectionMatrixID(), 1, false, pmvMat);
}
@Override
public int getVertexPositionID() {
return vertexPositionID;
}
/**
* Returns the id to use to bind the ModelViewProjectionMatrix attribute.
*/
public int getModelViewProjectionMatrixID() {
return modelViewProjectionMatrixID;
}
@Override
public boolean setMaterial(Material material, JOGLTextureManager textureManager) {
if (!USE_TRANSPARENCY) {
return true;
}
/*
* only set textures (needed for transparency)
*/
int numTexLayers = 0;
if (material.getTextureDataList() != null) {
numTexLayers = material.getTextureDataList().size();
}
/* set textures and associated parameters */
gl.glUniform1i(gl.glGetUniformLocation(shaderProgram, "useAlphaTreshold"), material.getTransparency() == Transparency.BINARY ? 1 : 0);
if (material.getTransparency() == Transparency.BINARY) {
gl.glUniform1f(gl.glGetUniformLocation(shaderProgram, "alphaTreshold"), 0.5f );
}
for (int i = 0; i < DefaultShader.MAX_TEXTURE_LAYERS; i++) {
if (i < numTexLayers) {
gl.glActiveTexture(getGLTextureConstant(i));
TextureData textureData = material.getTextureDataList().get(i);
if (textureData.isBumpMap) {
gl.glUniform1i(gl.glGetUniformLocation(shaderProgram, "useTexture["+i+"]"), 0);
continue;
} else {
gl.glUniform1i(gl.glGetUniformLocation(shaderProgram, "useTexture["+i+"]"), 1);
}
Texture texture = textureManager.getTextureForFile(textureData.file);
texture.bind(gl);
/* wrapping behavior */
int wrap = 0;
switch (textureData.wrap) {
case CLAMP: System.out.println("Warning: CLAMP is no longer supported. Using CLAMP_TO_BORDER instead."); wrap = GL_CLAMP_TO_BORDER; break;
case REPEAT: wrap = GL_REPEAT; break;
case CLAMP_TO_BORDER: wrap = GL_CLAMP_TO_BORDER; break;
}
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
if (textureData.wrap == Wrap.CLAMP_TO_BORDER) {
/* TODO: make the RGB configurable - for some reason,
* it shows up in lowzoom even if fully transparent */
gl.glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,
getFloatBuffer(new Color(1f, 1f, 1f, 0f)));
}
int loc = gl.glGetUniformLocation(shaderProgram, "Tex["+i+"]");
if (loc < 0) {
//throw new RuntimeException("Tex["+i+"] not found in shader program.");
}
gl.glUniform1i(loc, getGLTextureNumber(i));
} else {
gl.glUniform1i(gl.glGetUniformLocation(shaderProgram, "useTexture["+i+"]"), 0);
}
}
return true;
}
static final int getGLTextureConstant(int textureNumber) {
switch (getGLTextureNumber(textureNumber)) {
//case 0: return GL.GL_TEXTURE0;
case 1: return GL.GL_TEXTURE1;
case 2: return GL.GL_TEXTURE2;
case 3: return GL.GL_TEXTURE3;
case 4: return GL.GL_TEXTURE4;
default: throw new Error("programming error: unhandled texture number");
}
}
static final int getGLTextureNumber(int textureNumber) {
return textureNumber + 1;
}
@Override
public int getVertexNormalID() {
return -1; // unused
}
@Override
public int getVertexTexCoordID(int i) {
return vertexTexCoordID[i];
}
@Override
public int getVertexBumpMapCoordID() {
return -1; // unused
}
@Override
public int getVertexTangentID() {
return -1; // unused
}
}