All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.util.GLUTessellatorSupport Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.util;

import gov.nasa.worldwind.geom.*;

import com.jogamp.opengl.*;
import com.jogamp.opengl.glu.*;
import java.nio.IntBuffer;
import java.util.*;

/**
 * GLUTessellatorSupport is a utility class for configuring and using a {@link com.jogamp.opengl.glu.GLUtessellator} to
 * tessellate complex polygons into triangles.
 * 

* The standard pattern for using GLUTessellatorSupport to prepare a GLUtessellator is as follows: * GLUTessellatorSupport glts = new GLUTessellatorSupport();
GLUtessellatorCallback cb = ...; // Reference to an * implementation of GLUtessellatorCallback.
Vec4 normal = new Vec4(0, 0, 1); // The polygon's normal. This example * shows an appropriate normal for tessellating x-y coordinates.


glts.beginTessellation(cb, new Vec4(0, * 0, 1));
try
{
GLUtessellator tess = glts.getGLUtessellator();
}
finally
{
* glts.endTessellation();
}
* * @author dcollins * @version $Id: GLUTessellatorSupport.java 3427 2015-09-30 23:24:13Z dcollins $ */ public class GLUTessellatorSupport { protected GLUtessellator tess; /** Creates a new GLUTessellatorSupport, but otherwise does nothing. */ public GLUTessellatorSupport() { } /** * Returns this GLUTessellatorSupport's internal {@link com.jogamp.opengl.glu.GLUtessellator} instance. This * returns a valid GLUtessellator instance if called between {@link #beginTessellation(com.jogamp.opengl.glu.GLUtessellatorCallback, * gov.nasa.worldwind.geom.Vec4)} and {@link #endTessellation()}. This returns null if called from outside a * beginTessellation/endTessellation block. * * @return the internal GLUtessellator instance, or null if called from outside a beginTessellation/endTessellation * block. */ public GLUtessellator getGLUtessellator() { return this.tess; } /** * Prepares this GLUTessellatorSupport's internal GLU tessellator for use. This initializes the internal * GLUtessellator to a new instance by invoking {@link com.jogamp.opengl.glu.GLU#gluNewTess()}, and configures the * tessellator with the specified callback and normal with calls to {@link com.jogamp.opengl.glu.GLU#gluTessCallback(com.jogamp.opengl.glu.GLUtessellator, * int, com.jogamp.opengl.glu.GLUtessellatorCallback)} and {@link com.jogamp.opengl.glu.GLU#gluTessNormal(com.jogamp.opengl.glu.GLUtessellator, * double, double, double)}, respectively. * * @param callback the callback to configure the GLU tessellator with. * @param normal the normal to configure the GLU tessellator with. * * @throws IllegalArgumentException if the callback or the normal is null. */ public void beginTessellation(GLUtessellatorCallback callback, Vec4 normal) { if (callback == null) { String message = Logging.getMessage("nullValue.CallbackIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (normal == null) { String message = Logging.getMessage("nullValue.NormalIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.tess = GLU.gluNewTess(); GLU.gluTessNormal(this.tess, normal.x, normal.y, normal.z); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_BEGIN, callback); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_VERTEX, callback); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_END, callback); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_COMBINE, callback); } /** * Frees any GLU resources used by this GLUTessellatorSupport, and invalidates this instance's internal GLU * tessellator. */ public void endTessellation() { GLU.gluTessCallback(this.tess, GLU.GLU_TESS_BEGIN, null); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_VERTEX, null); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_END, null); GLU.gluTessCallback(this.tess, GLU.GLU_TESS_COMBINE, null); this.tess = null; } /** * Creates a new {@link com.jogamp.opengl.glu.GLUtessellatorCallback} that draws tessellated polygons as OpenGL * primitives by calling glBegin, glEnd, and glVertex. * * @param gl the GL context to draw into. * * @return a new GLUtessellatorCallback for drawing tessellated polygons as OpenGL primtives. * * @throws IllegalArgumentException if the GL is null. */ public static GLUtessellatorCallback createOGLDrawPrimitivesCallback(GL2 gl) { if (gl == null) { String message = Logging.getMessage("nullValue.GLIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return new OGLDrawPrimitivesCallback(gl); } /** * Converts the specified GLU tessellator error number to a string description. This returns "unknown" if the error * number is not recognized. * * @param errno a GLU enumeration indicating the error. * * @return a string description of the error number. */ public static String convertGLUTessErrorToString(int errno) { switch (errno) { case GLU.GLU_TESS_MISSING_BEGIN_POLYGON: return "missing begin polygon"; case GLU.GLU_TESS_MISSING_END_POLYGON: return "missing end polygon"; case GLU.GLU_TESS_MISSING_BEGIN_CONTOUR: return "missing begin contour"; case GLU.GLU_TESS_MISSING_END_CONTOUR: return "missing end contour"; case GLU.GLU_TESS_COORD_TOO_LARGE: return "coordinate too large"; case GLU.GLU_TESS_NEED_COMBINE_CALLBACK: return "need combine callback"; default: return "unknown"; } } protected static class OGLDrawPrimitivesCallback extends GLUtessellatorCallbackAdapter { protected final GL2 gl; public OGLDrawPrimitivesCallback(GL2 gl) { if (gl == null) { String message = Logging.getMessage("nullValue.GLIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.gl = gl; } public void begin(int type) { this.gl.glBegin(type); } public void vertex(Object vertexData) { double[] coords = (double[]) vertexData; this.gl.glVertex3f((float) coords[0], (float) coords[1], (float) coords[2]); } public void end() { this.gl.glEnd(); } public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { outData[0] = coords; } } /** Provides the callback class used to capture the shapes determined by the tessellator. */ public static class CollectIndexListsCallback extends GLUtessellatorCallbackAdapter { protected int numIndices; protected int currentType; protected List currentPrim; protected List> prims = new ArrayList>(); protected List primTypes = new ArrayList(); public List> getPrims() { return prims; } public List getPrimTypes() { return primTypes; } public int getNumIndices() { return this.numIndices; } public void begin(int type) { this.currentType = type; this.currentPrim = new ArrayList(); } public void vertex(Object vertexData) { this.currentPrim.add((Integer) vertexData); ++this.numIndices; } @Override public void end() { this.primTypes.add(this.currentType); this.prims.add(this.currentPrim); this.currentPrim = null; } public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { // System.out.println("COMBINE CALLED"); outData[0] = data[0]; } } /** Provides a container for associating a tessellator's vertex with its index and application-specified edge flag. */ public static class VertexData { public final int index; public final boolean edgeFlag; public VertexData(int index, boolean edgeFlag) { this.index = index; this.edgeFlag = edgeFlag; } } /** Provides the callback class used to capture triangle and line primitive indices determined by the tessellator. */ public static class CollectPrimitivesCallback extends GLUtessellatorCallbackAdapter { protected List triangles = new ArrayList(); protected List lines = new ArrayList(); protected IntBuffer triangleBuffer = IntBuffer.allocate(0); protected IntBuffer lineBuffer = IntBuffer.allocate(0); protected int error = 0; protected int index = 0; protected VertexData[] vertices = {null, null, null}; protected boolean[] edgeFlags = {true, true, true}; protected boolean edgeFlag = true; public CollectPrimitivesCallback() { } public IntBuffer getTriangleIndices() { return (IntBuffer) this.triangleBuffer.flip(); } public IntBuffer getLineIndices() { return (IntBuffer) this.lineBuffer.flip(); } public int getError() { return this.error; } public void attach(GLUtessellator tessellator) { GLU.gluTessCallback(tessellator, GLU.GLU_TESS_BEGIN, this); GLU.gluTessCallback(tessellator, GLU.GLU_TESS_END, this); GLU.gluTessCallback(tessellator, GLU.GLU_TESS_VERTEX, this); GLU.gluTessCallback(tessellator, GLU.GLU_TESS_EDGE_FLAG, this); GLU.gluTessCallback(tessellator, GLU.GLU_TESS_ERROR, this); } public void reset() { this.triangles.clear(); this.lines.clear(); this.triangleBuffer.clear(); this.lineBuffer.clear(); this.error = 0; this.index = 0; this.edgeFlag = true; } @Override public void begin(int type) { if (type != GL.GL_TRIANGLES) { String msg = Logging.getMessage("generic.UnexpectedPrimitiveType", type); Logging.logger().warning(msg); } } @Override public void end() { this.triangleBuffer = IntBuffer.allocate(this.triangles.size()); for (Integer index : this.triangles) { this.triangleBuffer.put(index); } this.lineBuffer = IntBuffer.allocate(this.lines.size()); for (Integer index : this.lines) { this.lineBuffer.put(index); } } @Override public void vertex(Object vertexData) { this.vertices[this.index] = (VertexData) vertexData; this.edgeFlags[this.index] = this.edgeFlag; this.index++; if (this.index == 3) { VertexData i = this.vertices[0]; VertexData j = this.vertices[1]; VertexData k = this.vertices[2]; this.triangles.add(i.index); this.triangles.add(j.index); this.triangles.add(k.index); if (this.edgeFlags[0] && (i.edgeFlag || j.edgeFlag)) { this.lines.add(i.index); this.lines.add(j.index); } if (this.edgeFlags[1] && (j.edgeFlag || k.edgeFlag)) { this.lines.add(j.index); this.lines.add(k.index); } if (this.edgeFlags[2] && (k.edgeFlag || i.edgeFlag)) { this.lines.add(k.index); this.lines.add(i.index); } this.index = 0; } } @Override public void edgeFlag(boolean flag) { this.edgeFlag = flag; } @Override public void error(int errno) { this.error = errno; } } /** * Recursively forwards boundary tessellation results from one GLU tessellator to another. The GLU tessellator this * callback forwards to may be configured in any way the caller chooses. *

* RecursiveCallback must be used as the GLUtessellatorCallback for the begin, end, vertex, and combine callbacks * for a GLU tessellator configured to generate line loops. A GLU tessellator can be configured generate line loops * by calling gluTessProperty(GLU_TESS_BOUNDARY_ONLY, GL_TRUE). Additionally, the caller specified vertex data * passed to gluTessVertex must be a double array containing three elements - the x, y and z coordinates associated * with the vertex. */ public static class RecursiveCallback extends GLUtessellatorCallbackAdapter { /** * The GLU tessellator that receives the tessellation results sent to this callback. */ protected GLUtessellator tess; /** * Creates a new RecursiveCallback with the GLU tessellator that receives boundary tessellation results. * * @param tessellator the GLU tessellator that receives the tessellation results sent to this callback. This * tessellator may be configured in any way the caller chooses, but should be prepared to * receive contour input from this callback. * * @throws java.lang.IllegalArgumentException if the tessellator is null. */ public RecursiveCallback(GLUtessellator tessellator) { if (tessellator == null) { String msg = Logging.getMessage("nullValue.TessellatorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.tess = tessellator; } /** * Called by the GLU tessellator to indicate the beginning of a new line loop. This recursively begins a new * contour with the GLU tessellator specified during construction by calling gluTessBeginContour(tessellator). * * @param type the GL primitive type. Must be GL_LINE_LOOP. */ @Override public void begin(int type) { GLU.gluTessBeginContour(this.tess); } /** * Called by the GLU tessellator to indicate the next vertex of the current contour. The vertex data must be a * double array containing three elements - the x, y and z coordinates associated with the vertex. This * recursively indicates the next contour vertex with the GLU tessellator specified during construction by * calling gluTessVertex(tessellator, (double[]) vertexData, 0, vertexData). * * @param vertexData the caller specified vertex data. Must be a double array containing three elements - the x, * y and z coordinates associated with the vertex. */ @Override public void vertex(Object vertexData) { GLU.gluTessVertex(this.tess, (double[]) vertexData, 0, vertexData); } /** * Called by the GLU tessellator to indicate the end of the current line loop. This recursively ends the current * contour with the GLU tessellator specified during construction by calling gluTessEndContour(tessellator). */ @Override public void end() { GLU.gluTessEndContour(this.tess); } /** * Called by the GLU tessellator to indicate that up to four vertices must be merged into a new vertex. The new * vertex is a linear combination of the original vertices. This assigns the first element of outData to coords, * the coordinates of the new vertex. * * @param coords A three element array containing the x, y and z coordinates of the new vertex. * @param vertexData The caller specified vertex data of the original vertices. * @param weight The coefficients of the linear combination. These weights sum to 1. * @param outData A one element array that must contain the caller specified data associated with the new * vertex after this method returns. */ @Override public void combine(double[] coords, Object[] vertexData, float[] weight, Object[] outData) { outData[0] = coords; } /** * Called by the GLU tessellator when the tessellation algorithm encounters an error. This logs a severe message * describing the error. * * @param errno a GLU enumeration indicating the error. */ @Override public void error(int errno) { String errstr = convertGLUTessErrorToString(errno); String msg = Logging.getMessage("generic.ExceptionWhileTessellating", errstr); Logging.logger().severe(msg); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy