package org.geogebra.desktop.geogebra3D.euclidian3D.opengl;
import java.io.UnsupportedEncodingException;
import java.nio.ShortBuffer;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL2GL3;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.GLBuffer;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.GLBufferIndices;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.GPUBuffer;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.Manager;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.Manager.Type;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.ManagerShadersElementsGlobalBuffer;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.Renderer;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.RendererImplShaders;
import org.geogebra.common.geogebra3D.main.FragmentShader;
import org.geogebra.common.geogebra3D.main.VertexShader;
import org.geogebra.common.jre.openGL.GLBufferIndicesJavaNio;
import org.geogebra.common.util.Charsets;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.main.AppD;
/**
* Renderer using shaders
*
* @author mathieu
*
*/
public class RendererImplShadersD extends RendererImplShaders {
private RendererJogl jogl;
/**
* Constructor
*
* @param renderer
* GL renderer
*
* @param view
* view
* @param jogl
* java openGL implementation
*/
public RendererImplShadersD(Renderer renderer, EuclidianView3D view,
RendererJogl jogl) {
super(renderer, view);
this.jogl = jogl;
Log.debug(
"============== RendererImplShadersD: Renderer with shaders created (shaders checked ok)");
}
private GL getGL() {
return jogl.getGL2ES2();
}
// private int normalMatrixLocation;
private int[] vboHandles;
@Override
final protected void compileShadersProgram() {
String vertexShaderString, fragmentShaderString;
vertexShaderString = VertexShader.getVertexShaderShiny(false);
// vertexShaderString = loadTextFile("vertexShaderSpecular");
fragmentShaderString = FragmentShader.getFragmentShaderShiny(0.2f,
false);
// fragmentShaderString = loadTextFile("fragmentShaderSpecular");
if (jogl.getGL2ES2().isGL3core()) {
Log.debug(
"GL3 core detected: explicitly add #version 130 to shaders");
vertexShaderString = "#version 130\n" + vertexShaderString;
fragmentShaderString = "#version 130\n" + fragmentShaderString;
}
// Create GPU shader handles
// OpenGL ES returns an index id to be stored for future reference.
vertShader = jogl.getGL2ES2()
.glCreateShader(GL2ES2.GL_VERTEX_SHADER);
fragShader = jogl.getGL2ES2()
.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER);
// Compile the vertexShader String into a program.
String[] vlines = new String[] { vertexShaderString };
// for (int i = 0; i < vlines.length; i++)
// System.out.println(vlines[i]);
int[] vlengths = new int[] { vlines[0].length() };
jogl.getGL2ES2().glShaderSource((Integer) vertShader, vlines.length,
vlines, vlengths, 0);
jogl.getGL2ES2().glCompileShader((Integer) vertShader);
// Check compile status.
int[] compiled = new int[1];
jogl.getGL2ES2().glGetShaderiv((Integer) vertShader,
GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] != 0) {
Log.debug("Vertex shader compiled");
} else {
int[] logLength = new int[1];
jogl.getGL2ES2().glGetShaderiv((Integer) vertShader,
GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
byte[] log = new byte[logLength[0]];
jogl.getGL2ES2().glGetShaderInfoLog((Integer) vertShader,
logLength[0], (int[]) null, 0, log, 0);
try {
Log.error("Error compiling the vertex shader: "
+ new String(log, Charsets.UTF_8));
} catch (UnsupportedEncodingException e) {
// do nothing
}
AppD.exit(1);
}
// Compile the fragmentShader String into a program.
String[] flines = new String[] { fragmentShaderString };
int[] flengths = new int[] { flines[0].length() };
jogl.getGL2ES2().glShaderSource((Integer) fragShader, flines.length,
flines, flengths, 0);
jogl.getGL2ES2().glCompileShader((Integer) fragShader);
// Check compile status.
jogl.getGL2ES2().glGetShaderiv((Integer) fragShader,
GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] != 0) {
Log.debug("Fragment shader compiled");
} else {
int[] logLength = new int[1];
jogl.getGL2ES2().glGetShaderiv((Integer) fragShader,
GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
byte[] log = new byte[logLength[0]];
jogl.getGL2ES2().glGetShaderInfoLog((Integer) fragShader,
logLength[0], (int[]) null, 0, log, 0);
try {
Log.error("Error compiling the fragment shader: "
+ new String(log, Charsets.UTF_8));
} catch (UnsupportedEncodingException e) {
// do nothing
}
AppD.exit(1);
}
}
@Override
final protected Object glCreateProgram() {
return jogl.getGL2ES2().glCreateProgram();
}
@Override
final protected void glAttachShader(Object shader) {
jogl.getGL2ES2().glAttachShader((Integer) shaderProgram,
(Integer) shader);
}
@Override
final protected void glBindAttribLocation(int index, String name) {
jogl.getGL2ES2().glBindAttribLocation((Integer) shaderProgram, index,
name);
}
@Override
final protected void glLinkProgram() {
jogl.getGL2ES2().glLinkProgram((Integer) shaderProgram);
}
@Override
final protected Object glGetUniformLocation(String name) {
return jogl.getGL2ES2().glGetUniformLocation((Integer) shaderProgram,
name);
}
@Override
final protected void createVBOs() {
vboHandles = new int[5];
jogl.getGL2ES2().glGenBuffers(5, vboHandles, 0);
vboColors = new GPUBufferD();
vboVertices = new GPUBufferD();
vboNormals = new GPUBufferD();
vboTextureCoords = new GPUBufferD();
vboIndices = new GPUBufferD();
vboColors.set(vboHandles[GLSL_ATTRIB_COLOR]);
vboVertices.set(vboHandles[GLSL_ATTRIB_POSITION]);
vboNormals.set(vboHandles[GLSL_ATTRIB_NORMAL]);
vboTextureCoords.set(vboHandles[GLSL_ATTRIB_TEXTURE]);
vboIndices.set(vboHandles[GLSL_ATTRIB_INDEX]);
}
@Override
final protected void createBufferFor(GPUBuffer buffer) {
int[] b = new int[1];
jogl.getGL2ES2().glGenBuffers(1, b, 0);
buffer.set(b[0]);
}
@Override
final protected int getStoreBufferNumBytes(int length, int size) {
return length * size * 4; // 4 bytes per float
}
@Override
public void storeElementBuffer(short[] fb, int length, GPUBuffer buffers) {
// Select the VBO, GPU memory data
bindBufferForIndices(buffers);
// transfer data to VBO, this perform the copy of data from CPU -> GPU
// memory
jogl.getGL2ES2().glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, length * 2L,
ShortBuffer.wrap(fb), RendererJogl.GL_STREAM_DRAW);
}
@Override
final protected void bindBuffer(int bufferType, GPUBuffer buffer) {
jogl.getGL2ES2().glBindBuffer(bufferType, ((GPUBufferD) buffer).get());
}
@Override
final protected int getGL_ELEMENT_ARRAY_BUFFER() {
return GL.GL_ELEMENT_ARRAY_BUFFER;
}
@Override
final protected int getGL_ARRAY_BUFFER() {
return GL.GL_ARRAY_BUFFER;
}
@Override
protected void vertexAttribPointer(int attrib, int size) {
jogl.getGL2ES2().glVertexAttribPointer(attrib, size, GL.GL_FLOAT, false,
0, 0);
}
@Override
protected void glUniform3fv(Object location, float[] values) {
jogl.getGL2ES2().glUniform3fv((Integer) location, 1, values, 0);
}
@Override
protected void glUniform3f(Object location, float x, float y, float z) {
jogl.getGL2ES2().glUniform3f((Integer) location, x, y, z);
}
@Override
protected void glEnableVertexAttribArray(int attrib) {
jogl.getGL2ES2().glEnableVertexAttribArray(attrib);
}
@Override
protected void glBufferData(int numBytes, GLBuffer fb) {
jogl.getGL2ES2().glBufferData(GL.GL_ARRAY_BUFFER, numBytes,
((GLBufferD) fb).getBuffer(), RendererJogl.GL_STREAM_DRAW);
}
@Override
protected void glBufferDataIndices(int numBytes, GLBufferIndices arrayI) {
jogl.getGL2ES2().glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, numBytes,
((GLBufferIndicesJavaNio) arrayI).getBuffer(),
RendererJogl.GL_STREAM_DRAW);
}
@Override
public void draw(Manager.Type type, int length) {
jogl.getGL2().glDrawElements(getGLType(type), length,
GL.GL_UNSIGNED_SHORT, 0);
}
@Override
protected int getGLType(Type type) {
switch (type) {
case TRIANGLE_STRIP:
return GL.GL_TRIANGLE_STRIP;
case TRIANGLE_FAN:
return GL.GL_TRIANGLE_STRIP;
case TRIANGLES:
return GL.GL_TRIANGLES;
case LINE_LOOP:
return GL.GL_LINE_LOOP;
case LINE_STRIP:
return GL.GL_LINE_STRIP;
}
return 0;
}
@Override
protected final void glUniformMatrix4fv(Object location, float[] values) {
jogl.getGL2ES2().glUniformMatrix4fv((Integer) location, 1, false,
values, 0);
}
@Override
final protected void glUseProgram(Object program) {
jogl.getGL2ES2().glUseProgram((Integer) program);
}
@Override
final protected void glDisableVertexAttribArray(int attrib) {
jogl.getGL2ES2().glDisableVertexAttribArray(attrib);
}
@Override
final protected void glDetachAndDeleteShader(Object program,
Object shader) {
jogl.getGL2ES2().glDetachShader((Integer) program, (Integer) shader);
jogl.getGL2ES2().glDeleteShader((Integer) shader);
}
@Override
final protected void glDeleteProgram(Object program) {
jogl.getGL2ES2().glDeleteProgram((Integer) program);
}
@Override
final protected void glUniform4f(Object location, float a, float b, float c,
float d) {
jogl.getGL2ES2().glUniform4f((Integer) location, a, b, c, d);
}
@Override
final protected void glUniform4fv(Object location, float[] values) {
jogl.getGL2ES2().glUniform4fv((Integer) location, 1, values, 0);
}
@Override
final protected void glUniform2fv(Object location, float[] values) {
jogl.getGL2ES2().glUniform2fv((Integer) location, 1, values, 0);
}
@Override
public void setColorMaterial() {
getGL().glEnable(GLLightingFunc.GL_COLOR_MATERIAL);
}
@Override
protected void glViewPort(int width, int height) {
jogl.getGL2ES2().glViewport(0, 0, width, height);
}
@Override
public Manager createManager() {
return new ManagerShadersElementsGlobalBuffer(renderer, view3D);
}
@Override
protected void glUniform1i(Object location, int value) {
jogl.getGL2ES2().glUniform1i((Integer) location, value);
}
@Override
protected void glUniform1fv(Object location, int length, float[] values) {
jogl.getGL2ES2().glUniform1fv((Integer) location, length, values, 0);
}
@Override
public float[] getLightPosition() {
return Renderer.LIGHT_POSITION_D;
}
@Override
final protected void glCullFace(int flag) {
getGL().glCullFace(flag);
}
@Override
final protected int getGL_FRONT() {
return GL.GL_FRONT;
}
@Override
final protected int getGL_BACK() {
return GL.GL_BACK;
}
@Override
public void setBufferLeft() {
jogl.getGL2().glDrawBuffer(GL2GL3.GL_BACK_LEFT);
// zspace seems to be swapped
// jogl.getGL2().glDrawBuffer(GLlocal.GL_BACK_RIGHT);
}
@Override
public void setBufferRight() {
jogl.getGL2().glDrawBuffer(GL2GL3.GL_BACK_RIGHT);
// zspace seems to be swapped
// jogl.getGL2().glDrawBuffer(GLlocal.GL_BACK_LEFT);
}
@Override
public void setStencilFunc(int value) {
getGL().glStencilFunc(GL.GL_EQUAL, value, 0xFF);
}
@Override
final protected void glDepthMask(boolean flag) {
getGL().glDepthMask(flag);
}
@Override
public void setColorMask(boolean r, boolean g, boolean b, boolean a) {
getGL().glColorMask(r, g, b, a);
}
@Override
public void setClearColor(float r, float g, float b, float a) {
getGL().glClearColor(r, g, b, a);
}
@Override
public void setPolygonOffset(float factor, float units) {
getGL().glPolygonOffset(factor, units);
}
@Override
public void genTextures2D(int number, int[] index) {
getGL().glGenTextures(number, index, 0);
}
@Override
public void bindTexture(int index) {
getGL().glBindTexture(GL.GL_TEXTURE_2D, index);
}
@Override
public void glEnable(int flag) {
getGL().glEnable(flag);
}
@Override
public void glDisable(int flag) {
getGL().glDisable(flag);
}
@Override
public final void enableMultisample() {
glEnable(GL.GL_MULTISAMPLE);
}
@Override
public final void disableMultisample() {
glDisable(GL.GL_MULTISAMPLE);
}
@Override
public int getGL_BLEND() {
return GL.GL_BLEND;
}
@Override
public int getGL_CULL_FACE() {
return GL.GL_CULL_FACE;
}
@Override
public void glClear(int flag) {
getGL().glClear(flag);
}
@Override
public int getGL_COLOR_BUFFER_BIT() {
return GL.GL_COLOR_BUFFER_BIT;
}
@Override
public int getGL_DEPTH_BUFFER_BIT() {
return GL.GL_DEPTH_BUFFER_BIT;
}
@Override
public int getGL_DEPTH_TEST() {
return GL.GL_DEPTH_TEST;
}
@Override
protected void bindFramebuffer(Object id) {
getGL().glBindFramebuffer(GL.GL_FRAMEBUFFER, (Integer) id);
}
@Override
protected void bindRenderbuffer(Object id) {
getGL().glBindRenderbuffer(GL.GL_RENDERBUFFER, (Integer) id);
}
@Override
protected void unbindFramebuffer() {
bindFramebuffer(0);
}
@Override
protected void unbindRenderbuffer() {
bindRenderbuffer(0);
}
@Override
protected void textureParametersNearest() {
getGL().glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
GL.GL_NEAREST);
getGL().glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
GL.GL_NEAREST);
}
@Override
protected void textureImage2DForBuffer(int width, int height) {
getGL().glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0,
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null);
}
@Override
protected void renderbufferStorage(int width, int height) {
getGL().glRenderbufferStorage(GL.GL_RENDERBUFFER,
GL2ES2.GL_DEPTH_COMPONENT, width, height);
}
private int[] tmp = new int[1];
@Override
protected Object genRenderbuffer() {
getGL().glGenRenderbuffers(1, tmp, 0);
return tmp[0];
}
@Override
protected Object genFramebuffer() {
getGL().glGenFramebuffers(1, tmp, 0);
return tmp[0];
}
@Override
protected void framebuffer(Object colorId, Object depthId) {
getGL().glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D,
(Integer) colorId, 0);
getGL().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER,
(Integer) depthId);
}
@Override
protected boolean checkFramebufferStatus() {
return getGL().glCheckFramebufferStatus(
GL.GL_FRAMEBUFFER) == GL.GL_FRAMEBUFFER_COMPLETE;
}
}