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

gov.nasa.worldwind.render.PolygonTessellator Maven / Gradle / Ivy

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

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

/**
 * @author dcollins
 * @version $Id: PolygonTessellator.java 2067 2014-06-20 20:59:29Z dcollins $
 */
public class PolygonTessellator
{
    protected static class TessCallbackAdapter extends GLUtessellatorCallbackAdapter
    {
        @Override
        public void beginData(int type, Object userData)
        {
            ((PolygonTessellator) userData).tessBegin(type);
        }

        @Override
        public void edgeFlagData(boolean boundaryEdge, Object userData)
        {
            ((PolygonTessellator) userData).tessEdgeFlag(boundaryEdge);
        }

        @Override
        public void vertexData(Object vertexData, Object userData)
        {
            ((PolygonTessellator) userData).tessVertex(vertexData);
        }

        @Override
        public void endData(Object userData)
        {
            ((PolygonTessellator) userData).tessEnd();
        }

        @Override
        public void combineData(double[] coords, Object[] vertexData, float[] weight, Object[] outData, Object userData)
        {
            ((PolygonTessellator) userData).tessCombine(coords, vertexData, weight, outData);
        }
    }

    protected boolean enabled = true;
    protected GLUtessellator tess;
    protected IntBuffer interiorIndices;
    protected IntBuffer boundaryIndices;
    protected boolean isBoundaryEdge;
    protected double[] vertexCoord = new double[3];

    public PolygonTessellator()
    {
        this.tess = GLU.gluNewTess();
        TessCallbackAdapter callback = new TessCallbackAdapter();
        GLU.gluTessCallback(this.tess, GLU.GLU_TESS_BEGIN_DATA, callback);
        GLU.gluTessCallback(this.tess, GLU.GLU_TESS_EDGE_FLAG_DATA, callback);
        GLU.gluTessCallback(this.tess, GLU.GLU_TESS_VERTEX_DATA, callback);
        GLU.gluTessCallback(this.tess, GLU.GLU_TESS_END_DATA, callback);
        GLU.gluTessCallback(this.tess, GLU.GLU_TESS_COMBINE_DATA, callback);

        this.interiorIndices = IntBuffer.allocate(10);
        this.boundaryIndices = IntBuffer.allocate(10);
    }

    public boolean isEnabled()
    {
        return this.enabled;
    }

    public void setEnabled(boolean enabled)
    {
        this.enabled = enabled;
    }

    public IntBuffer getInteriorIndices()
    {
        return this.interiorIndices;
    }

    public IntBuffer getBoundaryIndices()
    {
        return this.boundaryIndices;
    }

    public void reset()
    {
        if (!this.enabled)
            return;

        this.interiorIndices.clear();
        this.boundaryIndices.clear();
    }

    public void setPolygonNormal(double x, double y, double z)
    {
        if (!this.enabled)
            return;

        GLU.gluTessNormal(this.tess, x, y, z);
    }

    public void beginPolygon()
    {
        if (!this.enabled)
            return;

        GLU.gluTessBeginPolygon(this.tess, this); // Use this as the polygon user data to enable callbacks to this instance.
    }

    public void beginContour()
    {
        if (!this.enabled)
            return;

        GLU.gluTessBeginContour(this.tess);
    }

    public void addVertex(double x, double y, double z, int index)
    {
        if (!this.enabled)
            return;

        this.vertexCoord[0] = x;
        this.vertexCoord[1] = y;
        this.vertexCoord[2] = z;

        GLU.gluTessVertex(this.tess, this.vertexCoord, 0, index); // Associate the vertex with its index in the vertex array.
    }

    public void endContour()
    {
        if (!this.enabled)
            return;

        GLU.gluTessEndContour(this.tess);
    }

    public void endPolygon()
    {
        if (!this.enabled)
            return;

        GLU.gluTessEndPolygon(this.tess);
    }

    protected void tessBegin(int type)
    {
        // Intentionally left blank.
    }

    protected void tessEdgeFlag(boolean boundaryEdge)
    {
        this.isBoundaryEdge = boundaryEdge;
    }

    protected void tessVertex(Object vertexData)
    {
        // Accumulate interior indices appropriate for use as GL_interiorIndices primitives. Based on the GLU tessellator
        // documentation we can assume that the tessellator is providing interiorIndices because it's configured with the
        // edgeFlag callback.
        int index = (Integer) vertexData;
        this.interiorIndices = this.addIndex(this.interiorIndices, index);

        // Accumulate outline indices appropriate for use as GL_boundaryIndices. The tessBoundaryEdge flag indicates whether or
        // not the triangle edge starting with the current vertex is a boundary edge.
        if ((this.boundaryIndices.position() % 2) == 1)
        {
            this.boundaryIndices = this.addIndex(this.boundaryIndices, index);
        }
        if (this.isBoundaryEdge)
        {
            this.boundaryIndices = this.addIndex(this.boundaryIndices, index);

            int interiorCount = this.interiorIndices.position();
            if (interiorCount > 0 && (interiorCount % 3) == 0)
            {
                int firstTriIndex = this.interiorIndices.get(interiorCount - 3);
                this.boundaryIndices = this.addIndex(this.boundaryIndices, firstTriIndex);
            }
        }

    }

    protected void tessEnd()
    {
        // Intentionally left blank.
    }

    protected void tessCombine(double[] coords, Object[] vertexData, float[] weight, Object[] outData)
    {
        // TODO: Implement the combine callback to handle complex polygons.
    }

    protected IntBuffer addIndex(IntBuffer buffer, int index)
    {
        if (!buffer.hasRemaining())
        {
            int newCapacity = buffer.capacity() + buffer.capacity() / 2; // increase capacity by 50%
            IntBuffer newBuffer = IntBuffer.allocate(newCapacity);
            newBuffer.put((IntBuffer) buffer.flip());
            return newBuffer.put(index);
        }
        else
        {
            return buffer.put(index);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy