/*********************************************************************** * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***********************************************************************/ package org.mt4j.util.opengl; import java.util.ArrayList; import java.util.List; import javax.media.opengl.glu.GLU; import javax.media.opengl.glu.GLUtessellator; import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; import org.mt4j.MTApplication; import org.mt4j.components.visibleComponents.GeometryInfo; import org.mt4j.components.visibleComponents.shapes.mesh.MTTriangleMesh; import org.mt4j.util.math.Vertex; import processing.core.PApplet; /** * This tesselator produces no triangle strips/fans but only pure triangles. * * @author Chris */ public class GluTrianglulator extends GLUtessellatorCallbackAdapter{ /** The glu. */ private GLU glu; /** The tesselator. */ private GLUtessellator tesselator; /** The tri list. */ private List<Vertex> triList; /** The p. */ private PApplet p; public static final int WINDING_RULE_ABS_GEQ_TWO = GLU.GLU_TESS_WINDING_ABS_GEQ_TWO; public static final int WINDING_RULE_NEGATIVE = GLU.GLU_TESS_WINDING_NEGATIVE; public static final int WINDING_RULE_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; public static final int WINDING_RULE_ODD = GLU.GLU_TESS_WINDING_ODD; public static final int WINDING_RULE_POSITIVE = GLU.GLU_TESS_WINDING_POSITIVE; /** * Creates a new GLU tesselator object and defines callback methods, which the * tesselator will later call. These are defined in this class. * <br><strong>NOTE:</strong> always remember to delete the used triangulator with * deleteTess() after use to prevent memory leaking! * * @param p the processing context */ public GluTrianglulator(PApplet p) { this.p = p; this.glu = new GLU(); tesselator = glu.gluNewTess(); glu.gluTessCallback(tesselator, GLU.GLU_TESS_VERTEX, this);// glVertex3dv); glu.gluTessCallback(tesselator, GLU.GLU_TESS_BEGIN, this);// beginCallback); glu.gluTessCallback(tesselator, GLU.GLU_TESS_END, this);// endCallback); glu.gluTessCallback(tesselator, GLU.GLU_TESS_COMBINE, this);// combineCallback); glu.gluTessCallback(tesselator, GLU.GLU_TESS_ERROR, this);// errorCallback); // when you register a GLU_TESS_EDGE_FLAG (or GLU_TESS_EDGE_FLAG_DATA) callback, the // GLU library converts all triangle strips and triangle fans to simple triangle lists. glu.gluTessCallback(this.getTesselator(), GLU.GLU_TESS_EDGE_FLAG, this);// errorCallback); triList = new ArrayList<Vertex>(); } /* (non-Javadoc) * @see javax.media.opengl.glu.GLUtessellatorCallbackAdapter#edgeFlag(boolean) */ public void edgeFlag(boolean boundaryEdge){ //even the empty implementation of this method forces the tesselator to //procuce _triangle_ lists only! - no fans or strips } /** * Delete tess. */ public void deleteTess(){ if (tesselator != null){ glu.gluDeleteTess(tesselator); tesselator = null; } } @Override protected void finalize() throws Throwable { if (this.p instanceof MTApplication ) { MTApplication mtApp = (MTApplication) this.p; mtApp.invokeLater(new Runnable() { public void run() { deleteTess(); } }); }else{ //TODO use registerPre()? //is the object even valid after finalize() is called?? } super.finalize(); } /** * Triangulates the given vertex arrays and creates a single triangle mesh. * * @param contours the contours * @return the MT triangle mesh */ public MTTriangleMesh toTriangleMesh(Vertex[] contours){ List<Vertex[]> contoursList = new ArrayList<Vertex[]>(); contoursList.add(contours); return this.toTriangleMesh(contoursList, WINDING_RULE_ODD); } /** * Triangulates the given vertex arrays and creates a single triangle mesh. * * @param contours the contours * @return the MT triangle mesh */ public MTTriangleMesh toTriangleMesh(List<Vertex[]> contours){ return this.toTriangleMesh(contours, WINDING_RULE_ODD); } /** * Triangulates the given vertex arrays and creates a single triangle mesh. * * @param contours the contours * @param windingRule the winding rule * * @return the MT triangle mesh */ public MTTriangleMesh toTriangleMesh(List<Vertex[]> contours, int windingRule){ this.triList.clear(); this.tesselate(contours, windingRule); List<Vertex> tris = this.getTriList(); Vertex[] verts = tris.toArray(new Vertex[tris.size()]); GeometryInfo geom = new GeometryInfo(p, verts); MTTriangleMesh mesh = new MTTriangleMesh(p, geom, false); return mesh; } /** * Tesselate. * * @param contours the contours * * @return the list< vertex> */ public List<Vertex> tesselate(List<Vertex[]> contours){ this.triList.clear(); this.tesselate(contours, GLU.GLU_TESS_WINDING_ODD); return this.getTriList(); } public Vertex[] tesselate(Vertex[] contour){ this.triList.clear(); List<Vertex[]> v = new ArrayList<Vertex[]>(); v.add(contour); this.tesselate(v, WINDING_RULE_ODD); return this.getTriList().toArray(new Vertex[this.getTriList().size()]); } /** * Tesselates/triangulates the given contours with the given * winding rule (ie. GLU.GLU_TESS_WINDING_ODD). * * @param contour the contour * @param windingRule the winding rule * * @return the list< vertex> */ public List<Vertex> tesselate(Vertex[] contour, int windingRule){ this.triList.clear(); List<Vertex[]> v = new ArrayList<Vertex[]>(); v.add(contour); this.tesselate(v, windingRule); return this.getTriList(); } /** * Triangulates the given vertex contours and returns a list of triangles. * * @param contours the vertex arrays to triangulate into one list of triangles * @param windingRule the winding rule which determines which parts of the specified shape is "inside" or "outside" the shape. * @return the produced triangles list * @see GLU#GLU_TESS_WINDING_ODD * */ public List<Vertex> tesselate(List<Vertex[]> contours, int windingRule){ this.triList.clear(); glu.gluTessProperty(tesselator, GLU.GLU_TESS_WINDING_RULE, windingRule); // gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); //FIXME TEST! glu.gluTessNormal(tesselator, 0.0, 0.0, 1.0); glu.gluTessBeginPolygon(tesselator, null); //Go through all contours for (Vertex[] varr : contours){ /* glu.gluTessBeginContour(tesselator); //Go through all vertices of the contour for(Vertex v : varr){ double[] pv = {v.x, v.y, 0, v.getR()/255.0, v.getG()/255.0, v.getB()/255.0, v.getA()/255.0}; //{v.x,v.y,v.z}; glu.gluTessVertex(tesselator, pv, 0, pv); } glu.gluTessEndContour(tesselator); */ tesselateContour(varr, windingRule); } glu.gluTessEndPolygon(tesselator); return this.getTriList(); } /** * Tesselate contour. * * @param contour the contour * @param windingRule the winding rule * * @return the list< vertex> */ private List<Vertex> tesselateContour(Vertex[] contour, int windingRule){ if (contour.length == 3){ for (Vertex v : contour){ triList.add(v); } return this.triList; } glu.gluTessBeginContour(tesselator); for(int i = 0; i < contour.length; i++) { Vertex v = contour[i]; double[] pv = {v.x,v.y,v.z, v.getR()/255.0,v.getG()/255.0,v.getB()/255.0,v.getA()/255.0}; //{v.x,v.y,v.z}; glu.gluTessVertex(tesselator, pv, 0, pv); } glu.gluTessEndContour(tesselator); return this.getTriList(); } //remove? /* (non-Javadoc) * @see javax.media.opengl.glu.GLUtessellatorCallbackAdapter#begin(int) */ public void begin(int type) { /* switch (type) { case GL.GL_TRIANGLE_FAN: System.out.println("GL_TRIANGLE_FAN"); break; case GL.GL_TRIANGLE_STRIP: System.out.println("GL_TRIANGLE_STRIP"); break; case GL.GL_TRIANGLES:System.out.println("GL_TRIANGLES");break; case GL.GL_POLYGON:System.out.println("GL_TRIANGLES");break; case GL.GL_POINTS: System.out.println("GL_POINTS"); break; case GL.GL_LINES: System.out.println("GL_LINES"); break; case GL.GL_LINE_LOOP: System.out.println("GL_LINE_LOOP"); break; case GL.GL_LINE_STRIP: System.out.println("GL_LINE_STRIP"); break; case GL.GL_QUADS :System.out.println("GL_QUADS");break; case GL.GL_QUAD_STRIP:System.out.println("GL_QUAD_STRIP");break; default: System.out.println("OTHER?!"); break; } */ } //TODO rather save the vertex data in a list for later use, but we //would have to remember which drawing mode the tesselator inteded //the vertices for.. /** * Callback function. * Gets called by the tesselator when a new vertex should * be drawn. * * @param vertexData the vertex data */ public void vertex(Object vertexData) { // double[] dv = (double[]) vertexData; // gl.glColor4d(dv[3], dv[4], dv[5], dv[6]); //System.out.println(((double[]) vertexData).length); // /* double[] pointer; if (vertexData instanceof double[]){ pointer = (double[]) vertexData; Vertex v = new Vertex(); if (pointer.length >= 7){ // gl.glColor4dv(pointer, 3); // v.setR((float) pointer[3]); // v.setG((float) pointer[4]); // v.setB((float) pointer[5]); v.setR((float) pointer[3]*255); //FIXME wirklich *255 interpolaten? v.setG((float) pointer[4]*255); v.setB((float) pointer[5]*255); } // gl.glVertex3dv(pointer, 0); //TODO v.x = (float) pointer[0]; v.y = (float) pointer[1]; v.z = (float) pointer[2]; triList.add(v); } // */ } /* (non-Javadoc) * @see javax.media.opengl.glu.GLUtessellatorCallbackAdapter#vertexData(java.lang.Object, java.lang.Object) */ @Override public void vertexData(Object vertexData, Object polygonData) { /* if (polygonData instanceof Vertex){ Vertex v = (Vertex)polygonData; gl.glColor4f(v.getR()/255,v.getG()/255,v.getB()/255,v.getA()/255); } gl.glVertex3dv((double[]) vertexData, 0); */ // double[] dv = (double[]) vertexData; // gl.glVertex3d(dv[0],dv[1],dv[2]); // double[] dv = (double[]) polygonData; // gl.glColor4d(dv[4], dv[5], dv[6], dv[7]); // gl.glVertex3dv((double[]) vertexData, 0); } /** * CombineCallback is used to create a new vertex when edges intersect. * coordinate location is trivial to calculate, but weight[4] may be * used to average color, normal, or texture coordinate data. * <p> * This is called before the call to the vertex-callback method, * * @param coords the coords * @param data the data * @param weight the weight * @param outData the out data */ public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { // double[] vertex = new double[3]; // vertex[0] = coords[0]; // vertex[1] = coords[1]; // vertex[2] = coords[2]; // // outData[0] = vertex; //TODO calculate weighted normal!? //Interpolate the new vertix' color with the 4 intersecting verts double[] vertex = new double[7]; vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2]; vertex[3] = weight[0]*((double[]) data[0])[3] + weight[1]*((double[]) data[0])[3] + weight[2]*((double[]) data[0])[3] + weight[3]*((double[]) data[0])[3]; vertex[4] = weight[0]*((double[]) data[0])[4] + weight[1]*((double[]) data[0])[4] + weight[2]*((double[]) data[0])[4] + weight[3]*((double[]) data[0])[4]; vertex[5] = weight[0]*((double[]) data[0])[5] + weight[1]*((double[]) data[0])[5] + weight[2]*((double[]) data[0])[5] + weight[3]*((double[]) data[0])[5]; vertex[6] = weight[0]*((double[]) data[0])[6] + weight[1]*((double[]) data[0])[6] + weight[2]*((double[]) data[0])[6] + weight[3]*((double[]) data[0])[6]; outData[0] = vertex; } /* (non-Javadoc) * @see javax.media.opengl.glu.GLUtessellatorCallbackAdapter#end() */ public void end() { } /* (non-Javadoc) * @see javax.media.opengl.glu.GLUtessellatorCallbackAdapter#error(int) */ public void error(int errnum) { System.err.println("Tessellation Error: " + glu.gluErrorString(errnum)); // System.exit(0); } /** * Gets the tesselator. * * @return the tesselator */ public GLUtessellator getTesselator(){ return this.tesselator; } /** * Gets the tri list. * * @return the tri list */ public List<Vertex> getTriList(){ return this.triList; } }