package Graphics;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_NO_ERROR;
import static org.lwjgl.opengl.GL11.GL_ONE;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glDrawElements;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glGetError;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
import static org.lwjgl.opengl.GL13.GL_TEXTURE2;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import static org.lwjgl.opengl.GL14.GL_FUNC_ADD;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL14.glBlendEquation;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glGetAttribLocation;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glUniform1f;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUniform2f;
import static org.lwjgl.opengl.GL20.glUniform3f;
import static org.lwjgl.opengl.GL20.glUniformMatrix4;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL30.glBindFragDataLocation;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
public class LightAccumulationBufferShader extends Shader{
private int vert_id;
private int frag_id;
private int wMatIndex;
private int vpMatIndex;
private int camDirIndex;
private Matrix4f viewProjection;
private Matrix4f invView;
private Vector3f camPosition;
protected int position_attr;
protected int radUni, centerUni, colorUni;
protected int outCol;
private int colTex, normTex, posTex;
private int screenRect;
public LightAccumulationBufferShader()
{
active = false;
vert_id = loadShader("light.glslv", GL_VERTEX_SHADER);
frag_id = loadShader("light.glslf", GL_FRAGMENT_SHADER);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vert_id);
glAttachShader(shaderProgram, frag_id);
//set render target frag locations
glBindFragDataLocation( shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
//Get the input texture positions
colTex = glGetUniformLocation(shaderProgram, "colTex");
normTex = glGetUniformLocation(shaderProgram, "normTex");
posTex = glGetUniformLocation(shaderProgram, "posTex");
screenRect = glGetUniformLocation(shaderProgram, "screenRect");
glUniform1i(colTex, 0);//bind fbo color indices to them
glUniform1i(normTex, 1);
glUniform1i(posTex, 2);
wMatIndex = glGetUniformLocation(shaderProgram, "worldMatrix");
vpMatIndex = glGetUniformLocation(shaderProgram, "vpMatrix");
radUni = glGetUniformLocation( shaderProgram, "radius");
centerUni = glGetUniformLocation( shaderProgram, "center");
colorUni = glGetUniformLocation( shaderProgram, "lightColor");
camDirIndex = glGetAttribLocation(shaderProgram, "camDir");
position_attr = glGetAttribLocation( shaderProgram, "position");
setRectSize();//TODO: make this more extensible 600 800
viewProjection = new Matrix4f();
invView = new Matrix4f();
camPosition = new Vector3f();
}
private void setTransform(Light l, Matrix4f world, Matrix4f vp)
{
Matrix4f modelMat = new Matrix4f();
//compensate for internal light surfaces
Vector3f camDist = new Vector3f();
Vector3f.sub(camPosition, l.getPosition(), camDist);
if(camDist.lengthSquared() < l.rad*l.rad)
{
Matrix4f offsetMat= new Matrix4f();
//forward offset matrix
offsetMat.m03 = 0.0f;
offsetMat.m13 = 0.0f;
offsetMat.m23 = -1.0f;
//rotate to face camera direction
Matrix4f.mul(offsetMat, this.invView, offsetMat);
//add to position
modelMat.m03 = camPosition.x + offsetMat.m03;
modelMat.m13 = camPosition.y + offsetMat.m13;
modelMat.m23 = camPosition.z + offsetMat.m23;
//rotate billboard to face to camera
Matrix4f.mul(this.invView, modelMat, modelMat);
}
else
{
Matrix4f.mul(this.invView, world, modelMat);
}
//glUniformMatrix4(wMatIndex, true, genFloatBuffer(world));
glUniformMatrix4(wMatIndex, true, genFloatBuffer(modelMat));
glUniformMatrix4(vpMatIndex, true, genFloatBuffer(vp));
}
private void setUniforms(Light l)
{
glUniform3f(centerUni, l.getPosition().x, l.getPosition().y, l.getPosition().z );
glUniform1f(radUni, l.rad);
glUniform3f(colorUni, l.getColor().x, l.getColor().y, l.getColor().z);
}
protected void useCam(Camera cam)
{
Matrix4f camProj = new Matrix4f(cam.projection);
Matrix4f camView = new Matrix4f(cam.viewMat);
Matrix4f camVP = new Matrix4f();
camVP = Matrix4f.mul(camView, camProj, null);
//store inverse view matrix
Matrix4f.invert(cam.viewMat, this.invView);
this.invView.m30 = 0.0f;
this.invView.m31 = 0.0f;
this.invView.m32 = 0.0f;
this.invView.m03 = 0.0f;
this.invView.m13 = 0.0f;
this.invView.m23 = 0.0f;
this.invView.m33 = 1.0f;
this.viewProjection = camVP;
this.camPosition = cam.position;
glUniform3f(camDirIndex, cam.direction.x, cam.direction.y, cam.direction.z);
}
protected void setRectSize()
{
//1/800, 1/600
glUniform2f(screenRect, 0.00125f, 0.001666f);
}
protected void begin()
{
super.begin();
glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
//glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glBlendEquation(GL_FUNC_ADD);
}
protected void end()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
// glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
super.end();
}
protected void draw(Light l, View v)
{
if(!active)
{
System.out.println("Shader has not begun");
return;
}
setUniforms(l);
setTransform(l, l.getModelMat(), viewProjection); //good good, also make sure to set the radius and color
glBindVertexArray(Light.mesh.vao);
//bind all the texture info from the Gbuffer
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, v.getColorTexture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, v.getNormalTexture());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, v.getPosTexture());
glDrawElements(GL_TRIANGLES, Light.mesh.elementCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
public int getPositionAttr()
{
return position_attr;
}
}