package org.geogebra.common.geogebra3D.euclidian3D.openGL; import java.util.ArrayList; import java.util.Stack; import java.util.TreeMap; import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D; /** * * Manager using shaders * * @author ggb3D * */ public class ManagerShaders extends Manager { protected Renderer renderer; /** * common constructor * * @param renderer * @param view3D * 3D view */ public ManagerShaders(Renderer renderer, EuclidianView3D view3D) { super(renderer, view3D); } public enum TypeElement { NONE, CURVE, SURFACE, FAN_DIRECT, FAN_INDIRECT } private ArrayList<Double> vertices, normals, textures, colors; private int verticesLength, verticesSize, normalsLength, normalsSize, texturesLength, texturesSize, colorsLength, colorsSize; @Override protected void initGeometriesList() { geometriesSetList = new TreeMap<Integer, ManagerShaders.GeometriesSet>(); geometriesSetMaxIndex = -1; indicesRemoved = new Stack<Integer>(); vertices = new ArrayList<Double>(); verticesSize = 0; normals = new ArrayList<Double>(); normalsSize = 0; textures = new ArrayList<Double>(); texturesSize = 0; colors = new ArrayList<Double>(); colorsSize = 0; } @Override protected void setRenderer(Renderer renderer) { this.renderer = renderer; } @Override protected Renderer getRenderer() { return renderer; } // /////////////////////////////////////////// // LISTS METHODS // /////////////////////////////////////////// /** * Geometry (set of vertices, normals, etc. for e.g. triangles) * * @author mathieu * */ public class Geometry { /** * type of primitives */ private Type type; private GLBuffer v, n, t, c; private int length; /** * Start a new geometry * * @param type * of primitives */ public Geometry(Type type) { this.type = type; this.v = GLFactory.getPrototype().newBuffer(); this.n = GLFactory.getPrototype().newBuffer(); this.t = GLFactory.getPrototype().newBuffer(); this.c = GLFactory.getPrototype().newBuffer(); } /** * set the geometry type and mark buffers as empty * * @param type * geometry type */ public void setType(Type type) { this.type = type; this.v.setEmpty(); this.n.setEmpty(); this.t.setEmpty(); this.c.setEmpty(); } /** * allocate memory for buffers (for direct write) * * @param size * vertices size */ public void allocateBuffers(int size) { // Log.debug("allocateBuffers: "+size); v.allocate(size * 3); n.allocate(size * 3); length = 0; } /** * put vertex values into buffer * * @param x * @param y * @param z */ public void vertexDirect(double x, double y, double z) { v.put(x); v.put(y); v.put(z); length++; } /** * put normal values into buffer * * @param x * @param y * @param z */ public void normalDirect(double x, double y, double z) { n.put(x); n.put(y); n.put(z); } /** * ends geometry */ public void end() { v.setLimit(length * 3); n.setLimit(length * 3); } /** * * @return type of primitives */ public Type getType() { return type; } /** * set double buffer for vertices * * @param array * double array * @param length * length to copy */ public void setVertices(ArrayList<Double> array, int length) { // this.v = GLFactory.prototype.newBuffer(); this.v.set(array, length); } /** * * @return vertices buffer */ public GLBuffer getVertices() { return v; } /** * set double buffer for normals * * @param array * double array * @param length * length to copy */ public void setNormals(ArrayList<Double> array, int length) { this.n.set(array, length); } /** * * @return normals buffer */ public GLBuffer getNormals() { return n; } /** * set double buffer for texture * * @param array * double array * @param length * length to copy */ public void setTextures(ArrayList<Double> array, int length) { this.t.set(array, length); } /** * set textures to empty */ public void setTexturesEmpty() { this.t.setEmpty(); } /** * * @return texture buffer */ public GLBuffer getTextures() { return t; } /** * set double buffer for colors * * @param array * double array * @param length * length to copy */ public void setColors(ArrayList<Double> array, int length) { this.c.set(array, length); } /** * * @return colors buffer */ public GLBuffer getColors() { return c; } /** * set vertices length * * @param l * vertices length */ public void setLength(int l) { this.length = l; } /** * * @return vertices length */ public int getLength() { return length; } /** * draw to renderer * * @param r * renderer to draw into */ public void draw(RendererShadersInterface r) { r.loadVertexBuffer(getVertices(), getLength()); r.loadNormalBuffer(getNormals(), getLength()); r.loadColorBuffer(getColors(), getLength()); if (r.areTexturesEnabled()) { r.loadTextureBuffer(getTextures(), getLength()); } r.draw(getType(), getLength()); } /** * draw as label to renderer * * @param r * renderer to draw into */ public void drawLabel(RendererShadersInterface r) { r.loadVertexBuffer(getVertices(), getLength()); if (r.areTexturesEnabled()) { r.loadTextureBuffer(getTextures(), getLength()); } r.draw(getType(), getLength()); } } /** * Set of geometries * * @author mathieu * */ @SuppressWarnings("serial") public class GeometriesSet extends ArrayList<Geometry> { protected Geometry currentGeometry; private int currentGeometryIndex; private int geometriesLength; public GeometriesSet() { reset(); } /** * says this geometry set is reset */ public void reset() { currentGeometryIndex = 0; geometriesLength = 0; } /** * * @return geometries length */ public int getGeometriesLength() { return geometriesLength; } /** * start a new geometry * * @param type * type of primitives */ public void startGeometry(Type type) { if (currentGeometryIndex < size()) { currentGeometry = get(currentGeometryIndex); currentGeometry.setType(type); } else { currentGeometry = newGeometry(type); add(currentGeometry); } currentGeometryIndex++; geometriesLength++; } /** * * @param type * geometry type * @return new geometry for the given type */ protected Geometry newGeometry(Type type) { return new Geometry(type); } /** * allocate buffers of current geometry * * @param size * memory size */ public void allocate(int size) { currentGeometry.allocateBuffers(size); } /** * put vertex values into buffer * * @param x * @param y * @param z */ public void vertexDirect(double x, double y, double z) { currentGeometry.vertexDirect(x, y, z); } /** * put normal values into buffer * * @param x * @param y * @param z */ public void normalDirect(double x, double y, double z) { currentGeometry.normalDirect(x, y, z); } /** * ends current geometry */ public void endGeometry() { currentGeometry.end(); } /** * bind current geometry to its buffer * * @param size * indices size * @param type * type for element indices */ public void bindGeometry(int size, TypeElement type) { // not used here } /** * set vertices for current geometry * * @param vertices * vertices * @param length * vertices length */ public void setVertices(ArrayList<Double> vertices, int length) { currentGeometry.setVertices(vertices, length); currentGeometry.setLength(length / 3); } public void setNormals(ArrayList<Double> normals, int length) { if (length == 3) { // only one normal for all vertices currentGeometry.setNormals(normals, length); } else if (length == 3 * currentGeometry.getLength()) { currentGeometry.setNormals(normals, length); } } public void setTextures(ArrayList<Double> textures, int length) { if (length == 2 * currentGeometry.getLength()) { currentGeometry.setTextures(textures, length); } else { currentGeometry.setTexturesEmpty(); } } public void setColors(ArrayList<Double> colors, int length) { if (length == 4 * currentGeometry.getLength()) { currentGeometry.setColors(colors, length); } } } protected TreeMap<Integer, GeometriesSet> geometriesSetList; private int geometriesSetMaxIndex; protected GeometriesSet currentGeometriesSet; private Stack<Integer> indicesRemoved; private int currentOld; @Override public int startNewList(int old) { currentOld = old; if (currentOld >= 0) { currentGeometriesSet = geometriesSetList.get(old); } else { currentGeometriesSet = null; } int index = currentOld; if (currentGeometriesSet == null) { currentOld = -1; if (indicesRemoved.empty()) { geometriesSetMaxIndex++; index = geometriesSetMaxIndex; } else { index = indicesRemoved.pop(); } currentGeometriesSet = newGeometriesSet(); geometriesSetList.put(index, currentGeometriesSet); // Log.debug("newGeometriesSet : " + index); } else { currentGeometriesSet.reset(); // Log.debug("reuse : " + index); } return index; } /** * * @return new geometries set */ protected GeometriesSet newGeometriesSet() { return new GeometriesSet(); } @Override public void endList() { // renderer.getGL2().glEndList(); } // /////////////////////////////////////////// // GEOMETRY METHODS // /////////////////////////////////////////// @Override public void startGeometry(Type type) { currentGeometriesSet.startGeometry(type); verticesLength = 0; normalsLength = 0; texturesLength = 0; colorsLength = 0; } @Override public void endGeometry() { currentGeometriesSet.setVertices(vertices, verticesLength); currentGeometriesSet.setNormals(normals, normalsLength); currentGeometriesSet.setTextures(textures, texturesLength); currentGeometriesSet.setColors(colors, colorsLength); currentGeometriesSet.bindGeometry(-1, TypeElement.NONE); // TODO remove // that } @Override public void endGeometry(int size, TypeElement type) { currentGeometriesSet.setVertices(vertices, verticesLength); currentGeometriesSet.setNormals(normals, normalsLength); currentGeometriesSet.setTextures(textures, texturesLength); currentGeometriesSet.setColors(colors, colorsLength); currentGeometriesSet.bindGeometry(size, type); } // /////////////////////////////////////////// // POLYGONS METHODS // /////////////////////////////////////////// @Override public int startPolygons(int old) { int index = startNewList(old); return index; } @Override public void endPolygons() { endList(); } @Override public void remove(int index) { if (index >= 0 && index != currentOld) { // negative index is for no // geometry indicesRemoved.push(index); removeGeometrySet(index); } currentOld = -1; } /** * remove geometry set at index * * @param index * index */ protected void removeGeometrySet(int index) { geometriesSetList.remove(index); } // /////////////////////////////////////////// // DRAWING METHODS // /////////////////////////////////////////// @Override public void draw(int index) { currentGeometriesSet = geometriesSetList.get(index); if (currentGeometriesSet != null) { for (int i = 0; i < currentGeometriesSet .getGeometriesLength(); i++) { currentGeometriesSet.get(i) .draw((RendererShadersInterface) renderer); } } } public Geometry getGeometry(int index) { return geometriesSetList.get(index).get(0); } public GeometriesSet getGeometrySet(int index) { return geometriesSetList.get(index); } @Override public void drawLabel(int index) { currentGeometriesSet = geometriesSetList.get(index); if (currentGeometriesSet != null) { for (int i = 0; i < currentGeometriesSet .getGeometriesLength(); i++) { currentGeometriesSet.get(i) .drawLabel((RendererShadersInterface) renderer); } } } @Override protected void texture(double x, double y) { if (texturesLength == texturesSize) { textures.add(x); textures.add(y); texturesSize += 2; } else { textures.set(texturesLength, x); textures.set(texturesLength + 1, y); } texturesLength += 2; } @Override protected void setDummyTexture() { // nothing needed for the shader } @Override protected void normal(double x, double y, double z) { if (normalsLength == normalsSize) { normals.add(x); normals.add(y); normals.add(z); normalsSize += 3; } else { normals.set(normalsLength, x); normals.set(normalsLength + 1, y); normals.set(normalsLength + 2, z); } normalsLength += 3; } @Override protected void vertex(double x, double y, double z) { if (verticesLength == verticesSize) { vertices.add(x); vertices.add(y); vertices.add(z); verticesSize += 3; } else { vertices.set(verticesLength, x); vertices.set(verticesLength + 1, y); vertices.set(verticesLength + 2, z); } verticesLength += 3; } @Override protected void vertexInt(double x, double y, double z) { vertex(x, y, z); } @Override protected void color(double r, double g, double b) { color(r, g, b, 1f); } @Override protected void color(double r, double g, double b, double a) { if (colorsLength == colorsSize) { colors.add(r); colors.add(g); colors.add(b); colors.add(a); colorsSize += 4; } else { colors.set(colorsLength, r); colors.set(colorsLength + 1, g); colors.set(colorsLength + 2, b); colors.set(colorsLength + 3, a); } colorsLength += 4; } @Override protected void pointSize(double size) { // renderer.getGL2().glPointSize(size); } @Override protected void vertices(double[] vert) { // TODO Auto-generated method stub } @Override public void rectangleGeometry(double x, double y, double z, double width, double height) { startGeometry(Manager.Type.TRIANGLE_STRIP); texture(0, 0); vertexInt(x, y, z); texture(1, 0); vertexInt(x + width, y, z); texture(0, 1); vertexInt(x, y + height, z); texture(1, 1); vertexInt(x + width, y + height, z); endGeometry(); } /* * @Override public void rectangleBounds(int x, int y, int z, int width, int * height){ getText().rectangleBounds(x, y, z, width, height); } */ @Override public void startGeometryDirect(Type type, int size) { startGeometry(type); currentGeometriesSet.allocate(size); } @Override protected void vertexDirect(double x, double y, double z) { currentGeometriesSet.vertexDirect(x, y, z); } @Override protected void normalDirect(double x, double y, double z) { currentGeometriesSet.normalDirect(x, y, z); } @Override public void endGeometryDirect() { currentGeometriesSet.endGeometry(); } }