package org.geogebra.common.geogebra3D.euclidian3D.openGL; import java.util.Stack; import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D; import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawPoint3D; import org.geogebra.common.geogebra3D.euclidian3D.openGL.Manager.Type; import org.geogebra.common.kernel.Matrix.CoordMatrix4x4; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.main.Feature; /** * implementation for renderer using shaders * * @author mathieu * */ public abstract class RendererImplShaders extends RendererImpl { final static public int GLSL_ATTRIB_POSITION = 0; final static public int GLSL_ATTRIB_COLOR = 1; final static public int GLSL_ATTRIB_NORMAL = 2; final static public int GLSL_ATTRIB_TEXTURE = 3; final static public int GLSL_ATTRIB_INDEX = 4; final static protected int TEXTURE_TYPE_NONE = 0; final static protected int TEXTURE_TYPE_FADING = 1; final static protected int TEXTURE_TYPE_TEXT = 2; final static protected int TEXTURE_TYPE_DASH = 4; // location values for shader fields protected Object matrixLocation; // matrix protected Object lightPositionLocation, ambiantDiffuseLocation, enableLightLocation, enableShineLocation; // light protected Object eyePositionLocation; // eye position protected Object cullingLocation; // culling type protected Object colorLocation; // color protected Object centerLocation; // center protected Object enableClipPlanesLocation, clipPlanesMinLocation, clipPlanesMaxLocation; // enable / disable clip planes protected Object labelRenderingLocation, labelOriginLocation; protected Object normalLocation; // one normal for all vertices protected Object textureTypeLocation; // textures protected Object dashValuesLocation; // values for dash protected Object layerLocation; // layer value protected GPUBuffer vboVertices; protected GPUBuffer vboColors; protected GPUBuffer vboNormals; protected GPUBuffer vboTextureCoords; protected GPUBuffer vboIndices; protected float[] tmpNormal3 = new float[3]; protected CoordMatrix4x4 projectionMatrix = new CoordMatrix4x4(); protected CoordMatrix4x4 tmpMatrix1 = new CoordMatrix4x4(), tmpMatrix2 = new CoordMatrix4x4(); protected float[] tmpFloat16 = new float[16]; protected boolean oneNormalForAllVertices; protected Object shaderProgram; protected Object vertShader; protected Object fragShader; public RendererImplShaders(Renderer renderer, EuclidianView3D view) { super(renderer, view); } abstract protected void createBufferFor(GPUBuffer buffer); final private void createBuffer(GPUBuffer buffer, Stack<Object> stack) { if (stack.isEmpty()) { createBufferFor(buffer); } else { buffer.set(stack.pop()); } } private Stack<Object> removedBuffers = new Stack<Object>(); private Stack<Object> removedElementBuffers = new Stack<Object>(); @Override final public void createArrayBuffer(GPUBuffer buffer) { createBuffer(buffer, removedBuffers); } @Override final public void createElementBuffer(GPUBuffer buffer) { createBuffer(buffer, removedElementBuffers); } final private static void removeBuffer(GPUBuffer buffer, Stack<Object> stack) { stack.push(buffer.get()); } @Override public void removeArrayBuffer(GPUBuffer buffer) { removeBuffer(buffer, removedBuffers); } @Override public void removeElementBuffer(GPUBuffer buffer) { removeBuffer(buffer, removedElementBuffers); } @Override public void storeBuffer(GLBuffer fb, int length, int size, GPUBuffer buffer, int attrib) { // Select the VBO, GPU memory data bindBuffer(buffer); // transfer data to VBO, this perform the copy of data from CPU -> GPU // memory glBufferData(getStoreBufferNumBytes(length, size), fb); } /** * push buffer data * * @param numBytes * data size * @param fb * buffer array */ abstract protected void glBufferData(int numBytes, GLBuffer fb); abstract protected int getStoreBufferNumBytes(int length, int size); @Override final public void bindBufferForIndices(GPUBuffer buffer) { bindBuffer(getGL_ELEMENT_ARRAY_BUFFER(), buffer); } final protected void bindBuffer(GPUBuffer buffer) { bindBuffer(getGL_ARRAY_BUFFER(), buffer); } abstract protected void bindBuffer(int bufferType, GPUBuffer buffer); abstract protected int getGL_ELEMENT_ARRAY_BUFFER(); abstract protected int getGL_ARRAY_BUFFER(); /** * set vertex attribute pointer * * @param attrib * attribute * @param size * size */ abstract protected void vertexAttribPointer(int attrib, int size); final protected void vertexAttribPointerGlobal(int attrib, int size) { // vertexAttribPointer(attrib, size); } @Override final public void bindBufferForVertices(GPUBuffer buffer, int size) { // Select the VBO, GPU memory data bindBuffer(buffer); // Associate Vertex attribute 0 with the last bound VBO vertexAttribPointer(GLSL_ATTRIB_POSITION, size); // enable VBO glEnableVertexAttribArray(GLSL_ATTRIB_POSITION); } @Override final public void bindBufferForColors(GPUBuffer buffer, int size, GLBuffer fbColors) { if (fbColors == null || fbColors.isEmpty()) { glDisableVertexAttribArray(GLSL_ATTRIB_COLOR); return; } // prevent use of global color setColor(-1, -1, -1, -1); // Select the VBO, GPU memory data, to use for normals bindBuffer(buffer); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointer(GLSL_ATTRIB_COLOR, size); glEnableVertexAttribArray(GLSL_ATTRIB_COLOR); } abstract protected void glUniform3fv(Object location, float[] values); abstract protected void glUniform3f(Object location, float x, float y, float z); protected void resetOneNormalForAllVertices() { oneNormalForAllVertices = false; glUniform3f(normalLocation, 2, 2, 2); } @Override final public void bindBufferForNormals(GPUBuffer buffer, int size, GLBuffer fbNormals) { if (fbNormals == null || fbNormals.isEmpty()) { // no normals glDisableVertexAttribArray(GLSL_ATTRIB_NORMAL); return; } if (fbNormals.capacity() == 3) { // one normal for all vertices fbNormals.array(tmpNormal3); glUniform3fv(normalLocation, tmpNormal3); oneNormalForAllVertices = true; glDisableVertexAttribArray(GLSL_ATTRIB_NORMAL); return; } // /////////////////////////////////// // VBO - normals if (oneNormalForAllVertices) { resetOneNormalForAllVertices(); } // Select the VBO, GPU memory data, to use for normals bindBuffer(buffer); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointer(GLSL_ATTRIB_NORMAL, size); glEnableVertexAttribArray(GLSL_ATTRIB_NORMAL); } @Override public void bindBufferForTextures(GPUBuffer buffer, int size, GLBuffer fbTextures) { if (fbTextures == null || fbTextures.isEmpty()) { setCurrentGeometryHasNoTexture(); glDisableVertexAttribArray(GLSL_ATTRIB_TEXTURE); return; } setCurrentGeometryHasTexture(); // Select the VBO, GPU memory data, to use for normals bindBuffer(buffer); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointer(GLSL_ATTRIB_TEXTURE, size); glEnableVertexAttribArray(GLSL_ATTRIB_TEXTURE); } private boolean texturesEnabled; @Override final public void enableTextures() { texturesEnabled = true; setCurrentGeometryHasNoTexture(); // let first geometry init textures } @Override final public void disableTextures() { texturesEnabled = false; setCurrentTextureType(TEXTURE_TYPE_NONE); glDisableVertexAttribArray(GLSL_ATTRIB_TEXTURE); } /** * tells that current geometry has a texture */ final public void setCurrentGeometryHasTexture() { if (areTexturesEnabled() && currentTextureType == TEXTURE_TYPE_NONE) { setCurrentTextureType(oldTextureType); } } /** * tells that current geometry has no texture */ final public void setCurrentGeometryHasNoTexture() { if (areTexturesEnabled() && currentTextureType != TEXTURE_TYPE_NONE) { oldTextureType = currentTextureType; setCurrentTextureType(TEXTURE_TYPE_NONE); } } @Override public void enableFading() { enableTextures(); setCurrentTextureType(TEXTURE_TYPE_FADING); } private int currentDash = Textures.DASH_INIT; @Override public void enableDash() { currentDash = Textures.DASH_INIT; enableTextures(); setCurrentTextureType(TEXTURE_TYPE_DASH); } /** * enable text textures */ @Override final public void enableTexturesForText() { setCurrentTextureType(TEXTURE_TYPE_TEXT); } private int currentTextureType = TEXTURE_TYPE_NONE; private int oldTextureType = TEXTURE_TYPE_NONE; private void setCurrentTextureType(int type) { currentTextureType = type; glUniform1i(textureTypeLocation, type); } @Override public boolean areTexturesEnabled() { return texturesEnabled; } /** * dash values for shaders */ private static final float[][] DASH_SHADERS_VALUES = { // coeff, a, b, c // in shaders : x = mod(dashValues[0] * coordTexture.x, 1.0) // if (x > a || (x > b && x <= c)) then discard { 2.0f, 0.5f, -1f, -1f }, // {true, false, true, false}, // // DASH_SHORT { 1.0f, 0.25f, -1f, -1f }, // {true, false, false, false}, // // DASH_LONG_HIDDEN { 4.0f, 0.5f, -1f, -1f }, // {true, false, true, false, true, false, // true, false}, // DASH_DOTTED { 2.0f, 0.25f, -1f, -1f }, // {true, false, false, false, true, // false, false, false}, // // DASH_DOTTED_HIDDEN { 1.0f, 0.5f, -1f, -1f }, // {true, true, false, false}, // // DASH_NONE_HIDDEN { 1.0f, 0.25f, -1f, -1f }, // {true, false, false, false}, // // DASH_SHORT_HIDDEN { 1.0f, 0.5f, -1f, -1f }, // {true, true, false, false}, // // DASH_LONG { 1.0f, 12f / 16f, 7f / 16f, 11f / 16f }, // {true,true,true,true, // true,true,true,false, // false,false,false,true, // false,false,false,false}, // // DASH_DOTTED_DASHED { 1.0f, 12f / 16f, 3f / 16f, 11f / 16f }, // {false,false,true,true, // true,false,false,false, // false,false,false,true, // false,false,false,false} // // // DASH_DOTTED_DASHED_HIDDEN }; @Override public void setDashTexture(int index) { if (currentDash == index) { return; } currentDash = index; if (index == Textures.DASH_NONE) { disableTextures(); } else { enableTextures(); setCurrentTextureType(TEXTURE_TYPE_DASH + index); glUniform1fv(dashValuesLocation, 4, DASH_SHADERS_VALUES[index - 1]); } } abstract protected void glUniform1i(Object location, int value); abstract protected void glUniform1fv(Object location, int length, float[] values); abstract protected void glEnableVertexAttribArray(int attrib); abstract protected void glDisableVertexAttribArray(int attrib); @Override public void loadVertexBuffer(GLBuffer fbVertices, int length) { // /////////////////////////////////// // VBO - vertices // Select the VBO, GPU memory data, to use for vertices bindBuffer(vboVertices); // transfer data to VBO, this perform the copy of data from CPU -> GPU // memory int numBytes = length * 12; // 4 bytes per float * 3 coords per vertex glBufferData(numBytes, fbVertices); // Associate Vertex attribute 0 with the last bound VBO vertexAttribPointerGlobal(GLSL_ATTRIB_POSITION, 3); // VBO glEnableVertexAttribArray(GLSL_ATTRIB_POSITION); } @Override public void loadColorBuffer(GLBuffer fbColors, int length) { if (fbColors == null || fbColors.isEmpty()) { glDisableVertexAttribArray(GLSL_ATTRIB_COLOR); return; } // prevent use of global color setColor(-1, -1, -1, -1); // Select the VBO, GPU memory data, to use for normals bindBuffer(vboColors); int numBytes = length * 16; // 4 bytes per float * 4 color values (rgba) glBufferData(numBytes, fbColors); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointerGlobal(GLSL_ATTRIB_COLOR, 4); glEnableVertexAttribArray(GLSL_ATTRIB_COLOR); } @Override public void loadTextureBuffer(GLBuffer fbTextures, int length) { if (fbTextures == null || fbTextures.isEmpty()) { setCurrentGeometryHasNoTexture(); glDisableVertexAttribArray(GLSL_ATTRIB_TEXTURE); return; } setCurrentGeometryHasTexture(); // Select the VBO, GPU memory data, to use for normals bindBuffer(vboTextureCoords); int numBytes = length * 8; // 4 bytes per float * 2 coords per texture glBufferData(numBytes, fbTextures); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointerGlobal(GLSL_ATTRIB_TEXTURE, 2); glEnableVertexAttribArray(GLSL_ATTRIB_TEXTURE); } @Override public void loadNormalBuffer(GLBuffer fbNormals, int length) { if (fbNormals == null || fbNormals.isEmpty()) { // no normals glDisableVertexAttribArray(GLSL_ATTRIB_NORMAL); return; } if (fbNormals.capacity() == 3) { // one normal for all vertices glDisableVertexAttribArray(GLSL_ATTRIB_NORMAL); fbNormals.array(tmpNormal3); glUniform3fv(normalLocation, tmpNormal3); oneNormalForAllVertices = true; return; } // /////////////////////////////////// // VBO - normals if (oneNormalForAllVertices) { resetOneNormalForAllVertices(); } // Select the VBO, GPU memory data, to use for normals bindBuffer(vboNormals); int numBytes = length * 12; // 4 bytes per float * * 3 coords per normal glBufferData(numBytes, fbNormals); // Associate Vertex attribute 1 with the last bound VBO vertexAttribPointerGlobal(GLSL_ATTRIB_NORMAL, 3); glEnableVertexAttribArray(GLSL_ATTRIB_NORMAL); } @Override public void drawSurfacesOutline() { // TODO } @Override public void enableClipPlanes() { glUniform1i(enableClipPlanesLocation, 1); } @Override public void disableClipPlanes() { glUniform1i(enableClipPlanesLocation, 0); } @Override public void loadIndicesBuffer(GLBufferIndices arrayI, int length) { // /////////////////////////////////// // VBO - indices // Select the VBO, GPU memory data, to use for indices bindBufferForIndices(vboIndices); // transfer data to VBO, this perform the copy of data from CPU -> GPU // memory glBufferDataIndices(length * 2, arrayI); } abstract protected void glBufferDataIndices(int numBytes, GLBufferIndices arrayI); /** * attribute vertex pointers */ protected void attribPointers() { bindBuffer(vboVertices); vertexAttribPointer(GLSL_ATTRIB_POSITION, 3); bindBuffer(vboNormals); vertexAttribPointer(GLSL_ATTRIB_NORMAL, 3); bindBuffer(vboColors); vertexAttribPointer(GLSL_ATTRIB_COLOR, 4); bindBuffer(vboTextureCoords); vertexAttribPointer(GLSL_ATTRIB_TEXTURE, 2); } abstract protected int getGLType(Type type); protected final void setModelViewIdentity() { projectionMatrix.getForGL(tmpFloat16); glUniformMatrix4fv(matrixLocation, tmpFloat16); } abstract protected void glUniformMatrix4fv(Object location, float[] values); @Override public void draw() { resetOneNormalForAllVertices(); disableTextures(); setModelViewIdentity(); } @Override public void useShaderProgram() { glUseProgram(shaderProgram); } abstract protected void glUseProgram(Object program); @Override public void dispose() { glUseProgram(0); glDetachAndDeleteShader(shaderProgram, vertShader); glDetachAndDeleteShader(shaderProgram, fragShader); glDeleteProgram(shaderProgram); } abstract protected void glDetachAndDeleteShader(Object program, Object shader); abstract protected void glDeleteProgram(Object program); @Override public void setMatrixView() { if (renderer.isExportingImageEquirectangular()) { tmpMatrix2.set(renderer.getToScreenMatrix()); tmpMatrix2.set(3, 4, tmpMatrix2.get(3, 4) + renderer.getEyeToScreenDistance()); tmpMatrix1.setMul(projectionMatrix, tmpMatrix2); } else { tmpMatrix1.setMul(projectionMatrix, renderer.getToScreenMatrix()); } tmpMatrix1.getForGL(tmpFloat16); glUniformMatrix4fv(matrixLocation, tmpFloat16); } @Override public void unsetMatrixView() { setModelViewIdentity(); } abstract protected void glUniform4f(Object location, float a, float b, float c, float d); @Override public void setColor(float r, float g, float b, float a) { glUniform4f(colorLocation, r, g, b, a); } @Override public void initMatrix() { if (renderer.isExportingImageEquirectangular()) { tmpMatrix1.set(renderer.getToScreenMatrix()); tmpMatrix1.set(3, 4, tmpMatrix1.get(3, 4) + renderer.getEyeToScreenDistance()); tmpMatrix2.setMul(tmpMatrix1, renderer.getMatrix()); } else { tmpMatrix2.setMul(renderer.getToScreenMatrix(), renderer.getMatrix()); } tmpMatrix1.setMul(projectionMatrix, tmpMatrix2); tmpMatrix1.getForGL(tmpFloat16); glUniformMatrix4fv(matrixLocation, tmpFloat16); } @Override public void initMatrixForFaceToScreen() { tmpMatrix1.setMul(projectionMatrix, renderer.getMatrix()); tmpMatrix1.getForGL(tmpFloat16); glUniformMatrix4fv(matrixLocation, tmpFloat16); } @Override public void resetMatrix() { setMatrixView(); } @Override public void pushSceneMatrix() { // not used with shaders } private float[] eyeOrDirection = new float[4]; @Override public void setLightPosition(float[] values) { glUniform3fv(lightPositionLocation, values); view3D.getEyePosition().get4ForGL(eyeOrDirection); glUniform4fv(eyePositionLocation, eyeOrDirection); } abstract protected void glUniform4fv(Object location, float[] values); private float[][] ambiantDiffuse; @Override public void setLightAmbiantDiffuse(float ambiant0, float diffuse0, float ambiant1, float diffuse1) { float coeff = 1.414f; float a0 = ambiant0 * coeff; float d0 = 1 - a0; float a1 = ambiant1 * coeff; float d1 = 1 - a1; ambiantDiffuse = new float[][] { { a0, d0 }, { a1, d1 } }; } abstract protected void glUniform2fv(Object location, float[] values); @Override public void setLight(int light) { glUniform2fv(ambiantDiffuseLocation, ambiantDiffuse[light]); } @Override public void setLightModel() { // not used with shaders } @Override public void setAlphaFunc() { // not used with shaders } @Override final public void setView() { renderer.setProjectionMatrix(); // this part is needed for export image glViewPort(renderer.getWidthInPixels(), renderer.getHeightInPixels()); } abstract protected void glViewPort(int width, int height); @Override public void viewOrtho() { // the projection matrix is updated in updateOrthoValues() } @Override final public void updateOrthoValues() { projectionMatrix.set(1, 1, 2.0 / renderer.getWidth()); projectionMatrix.set(2, 2, 2.0 / renderer.getHeight()); projectionMatrix.set(3, 3, -2.0 / renderer.getVisibleDepth()); projectionMatrix.set(4, 4, 1); projectionMatrix.set(2, 1, 0); projectionMatrix.set(3, 1, 0); projectionMatrix.set(4, 1, 0); projectionMatrix.set(1, 2, 0); projectionMatrix.set(3, 2, 0); projectionMatrix.set(4, 2, 0); projectionMatrix.set(1, 3, 0); projectionMatrix.set(2, 3, 0); projectionMatrix.set(4, 3, 0); projectionMatrix.set(1, 4, 0); projectionMatrix.set(2, 4, 0); projectionMatrix.set(3, 4, 0); } @Override public void viewPersp() { // the projection matrix is updated in updatePerspValues() } @Override public void updatePerspValues() { projectionMatrix.set(1, 1, 2 * renderer.perspNear[renderer.eye] / (renderer.perspRight[renderer.eye] - renderer.perspLeft[renderer.eye])); projectionMatrix.set(2, 1, 0); projectionMatrix.set(3, 1, 0); projectionMatrix.set(4, 1, 0); projectionMatrix.set(1, 2, 0); projectionMatrix.set(2, 2, 2 * renderer.perspNear[renderer.eye] / (renderer.perspTop[renderer.eye] - renderer.perspBottom[renderer.eye])); projectionMatrix.set(3, 2, 0); projectionMatrix.set(4, 2, 0); perspXZ = (renderer.perspRight[renderer.eye] + renderer.perspLeft[renderer.eye]) / (renderer.perspRight[renderer.eye] - renderer.perspLeft[renderer.eye]); projectionMatrix.set(1, 3, perspXZ); perspYZ = (renderer.perspTop[renderer.eye] + renderer.perspBottom[renderer.eye]) / (renderer.perspTop[renderer.eye] - renderer.perspBottom[renderer.eye]); projectionMatrix.set(2, 3, perspYZ); projectionMatrix.set(3, 3, -2.0 / renderer.getVisibleDepth()); projectionMatrix.set(4, 3, -1); projectionMatrix.set(1, 4, 0); projectionMatrix.set(2, 4, 0); projectionMatrix.set(3, 4, 0); projectionMatrix.set(4, 4, -renderer.perspFocus[renderer.eye]); } private double perspXZ, perspYZ; private double[] glassesXZ = new double[2], glassesYZ = new double[2]; @Override public void updateGlassesValues() { for (int i = 0; i < 2; i++) { glassesXZ[i] = 2 * renderer.perspNear[i] / (renderer.perspFocus[i] * (renderer.perspRight[i] - renderer.perspLeft[i])) * renderer.glassesEyeX[i]; glassesYZ[i] = 2 * renderer.perspNear[i] / (renderer.perspFocus[i] * (renderer.perspTop[i] - renderer.perspBottom[i])) * renderer.glassesEyeY[i]; } } @Override public void viewGlasses() { projectionMatrix.set(1, 3, perspXZ + glassesXZ[renderer.eye]); projectionMatrix.set(2, 3, perspYZ + glassesYZ[renderer.eye]); } @Override public void viewOblique() { // the projection matrix is updated in updateProjectionObliqueValues() } @Override public void updateProjectionObliqueValues() { projectionMatrix.set(1, 1, 2.0 / renderer.getWidth()); projectionMatrix.set(2, 1, 0); projectionMatrix.set(3, 1, 0); projectionMatrix.set(4, 1, 0); projectionMatrix.set(1, 2, 0); projectionMatrix.set(2, 2, 2.0 / renderer.getHeight()); projectionMatrix.set(3, 2, 0); projectionMatrix.set(4, 2, 0); projectionMatrix.set(1, 3, renderer.obliqueX * 2.0 / renderer.getWidth()); projectionMatrix.set(2, 3, renderer.obliqueY * 2.0 / renderer.getHeight()); projectionMatrix.set(3, 3, -2.0 / renderer.getVisibleDepth()); projectionMatrix.set(4, 3, 0); projectionMatrix.set(1, 4, 0); projectionMatrix.set(2, 4, 0); projectionMatrix.set(3, 4, 0); projectionMatrix.set(4, 4, 1); } private float[] clipPlanesMin = new float[3]; private float[] clipPlanesMax = new float[3]; @Override public void setClipPlanes(double[][] minMax) { if (view3D.getApplication().has(Feature.DIFFERENT_AXIS_RATIO_3D)) { for (int i = 0; i < 3; i++) { double scale = view3D.getScale(i); clipPlanesMin[i] = (float) (minMax[i][0] * scale); clipPlanesMax[i] = (float) (minMax[i][1] * scale); } } else { for (int i = 0; i < 3; i++) { clipPlanesMin[i] = (float) minMax[i][0]; clipPlanesMax[i] = (float) minMax[i][1]; } } } final private void setClipPlanesToShader() { glUniform3fv(clipPlanesMinLocation, clipPlanesMin); glUniform3fv(clipPlanesMaxLocation, clipPlanesMax); } @Override public void initRenderingValues() { // clip planes setClipPlanesToShader(); // layer initLayer(); } @Override public void drawFaceToScreenAbove() { glUniform1i(labelRenderingLocation, 1); resetCenter(); } @Override public void drawFaceToScreenBelow() { glUniform1i(labelRenderingLocation, 0); } @Override public void setLabelOrigin(float[] origin) { glUniform3fv(labelOriginLocation, origin); } @Override public void enableLighting() { if (view3D.getUseLight()) { glUniform1i(enableLightLocation, 1); } } @Override public void initLighting() { if (view3D.getUseLight()) { glUniform1i(enableLightLocation, 1); } else { glUniform1i(enableLightLocation, 0); } glUniform1i(enableShineLocation, 0); } @Override public void disableLighting() { if (view3D.getUseLight()) { glUniform1i(enableLightLocation, 0); } } @Override public void disableShine() { if (view3D.getUseLight()) { glUniform1i(enableShineLocation, 0); } } @Override public void enableShine() { if (view3D.getUseLight()) { glUniform1i(enableShineLocation, 1); } } private float[] pointCenter = new float[4]; @Override final public void setCenter(Coords center) { center.get4ForGL(pointCenter); // set radius info pointCenter[3] = view3D .unscale(pointCenter[3] * DrawPoint3D.DRAW_POINT_FACTOR); glUniform4fv(centerLocation, pointCenter); } private float[] resetCenter = { 0f, 0f, 0f, 0f }; @Override final public void resetCenter() { glUniform4fv(centerLocation, resetCenter); } @Override final public void disableCulling() { glDisable(getGL_CULL_FACE()); glUniform1i(cullingLocation, 1); } abstract protected void glCullFace(int flag); abstract protected int getGL_FRONT(); abstract protected int getGL_BACK(); @Override final public void setCullFaceFront() { glCullFace(getGL_FRONT()); glUniform1i(cullingLocation, -1); } @Override final public void setCullFaceBack() { glCullFace(getGL_BACK()); glUniform1i(cullingLocation, 1); } @Override public void drawTranspNotCurved() { renderer.enableCulling(); renderer.setCullFaceFront(); renderer.drawable3DLists.drawTransp(renderer); renderer.drawable3DLists.drawTranspClosedNotCurved(renderer); renderer.setCullFaceBack(); renderer.drawable3DLists.drawTransp(renderer); renderer.drawable3DLists.drawTranspClosedNotCurved(renderer); } @Override public void enableLightingOnInit() { // no need for shaders } @Override public void initCulling() { // no need for shaders } @Override public boolean useShaders() { return true; } abstract protected void glDepthMask(boolean flag); @Override final public void enableDepthMask() { glDepthMask(true); } @Override final public void disableDepthMask() { glDepthMask(false); } @Override public void setStencilLines() { // not implemented yet with shaders } abstract protected Object glGetUniformLocation(String name); /** * set uniform locations for shaders */ final protected void setShaderLocations() { matrixLocation = glGetUniformLocation("matrix"); lightPositionLocation = glGetUniformLocation("lightPosition"); ambiantDiffuseLocation = glGetUniformLocation("ambiantDiffuse"); eyePositionLocation = glGetUniformLocation("eyePosition"); enableLightLocation = glGetUniformLocation("enableLight"); cullingLocation = glGetUniformLocation("culling"); enableShineLocation = glGetUniformLocation("enableShine"); dashValuesLocation = glGetUniformLocation("dashValues"); // texture textureTypeLocation = glGetUniformLocation("textureType"); // color colorLocation = glGetUniformLocation("color"); // normal normalLocation = glGetUniformLocation("normal"); // center centerLocation = glGetUniformLocation("center"); // clip planes enableClipPlanesLocation = glGetUniformLocation("enableClipPlanes"); clipPlanesMinLocation = glGetUniformLocation("clipPlanesMin"); clipPlanesMaxLocation = glGetUniformLocation("clipPlanesMax"); // label rendering labelRenderingLocation = glGetUniformLocation("labelRendering"); labelOriginLocation = glGetUniformLocation("labelOrigin"); // layer layerLocation = glGetUniformLocation("layer"); } @Override final public void initShaders() { compileShadersProgram(); // Each shaderProgram must have // one vertex shader and one fragment shader. shaderProgram = glCreateProgram(); glAttachShader(vertShader); glAttachShader(fragShader); glBindAttribLocation(GLSL_ATTRIB_POSITION, "attribute_Position"); glBindAttribLocation(GLSL_ATTRIB_NORMAL, "attribute_Normal"); glBindAttribLocation(GLSL_ATTRIB_COLOR, "attribute_Color"); glBindAttribLocation(GLSL_ATTRIB_TEXTURE, "attribute_Texture"); glLinkProgram(); setShaderLocations(); createVBOs(); attribPointers(); } abstract protected void compileShadersProgram(); abstract protected Object glCreateProgram(); abstract protected void glAttachShader(Object shader); abstract protected void glBindAttribLocation(int index, String name); abstract protected void glLinkProgram(); abstract protected void createVBOs(); @Override public void enableAlphaTest() { // done by shader } @Override public void disableAlphaTest() { // done by shader } @Override public void setLayer(int layer) { if (layer == currentLayer) { return; } currentLayer = layer; glUniform1i(layerLocation, currentLayer); } private int currentLayer; final private void initLayer() { currentLayer = 0; glUniform1i(layerLocation, 0); } }