com.alvermont.terraj.fracplanet.geom.TriangleBufferArray.java Source code

Java tutorial

Introduction

Here is the source code for com.alvermont.terraj.fracplanet.geom.TriangleBufferArray.java

Source

/*
 * Java Terrain and Stellar System Ports
 *
 * Copyright (C) 2006 Martin H. Smith based on work by original
 * authors.
 *
 * Released under the terms of the GNU General Public License
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * Linking TerraJ statically or dynamically with other modules is making a
 * combined work based on TerraJ. Thus, the terms and conditions of the
 * GNU General Public License cover the whole combination.
 *
 * In addition, as a special exception, the copyright holders of TerraJ
 * give you permission to combine this program with free software programs
 * or libraries that are released under the GNU LGPL and with code included
 * in the standard release of JOGL, Java Getopt and FreeMarker under the BSD
 * license (or modified versions of such code, with unchanged license) and with
 * Apache Commons and Log4J libraries under the Apache license (or modified versions
 * of such code. You may copy and distribute such a system following the terms
 * of the GNU GPL for TerraJ and the licenses of the other code concerned,
 * provided that you include the source code of that other code when and as the
 * GNU GPL requires distribution of source code.
 *
 * Note that people who make modified versions of TerraJ are not obligated to grant
 * this special exception for their modified versions; it is their choice whether
 * to do so. The GNU General Public License gives permission to release a modified
 * version without this exception; this exception also makes it possible to release
 * a modified version which carries forward this exception.
 */

/*
 * TriangleBufferArray.java
 *
 * Created on December 31, 2005, 1:14 PM
 *
 */
package com.alvermont.terraj.fracplanet.geom;

import com.alvermont.terraj.fracplanet.util.ByteBufferUtils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Implements an array of triangles using a buffer that can be passed
 * directly to rendering.
 *
 * @author martin
 * @version $Id: TriangleBufferArray.java,v 1.7 2006/07/06 06:58:35 martin Exp $
 */
public class TriangleBufferArray implements TriangleArray, BufferedElement {
    /** Our logging object */
    private static Log log = LogFactory.getLog(TriangleBufferArray.class);

    /** The default number of elements this buffer will initially be capable of holding */
    public static final int DEFAULT_CAPACITY = 30000;

    /** The percentage to increase the capacity by when a resize is required */
    public static final int CAPACITY_PCT_INCREASE = 70;

    /** Number of int values that make up each entry in this buffer */
    private static final int INTS_PER_ENTRY = 3;

    /** Size of an int value in bytes */
    private static final int SIZEOF_INT = 4;

    /** Value for 100 percent */
    private static final int PERCENT_100 = 100;

    // RequireThis OFF: DEFAULT_CAPACITY
    // RequireThis OFF: CAPACITY_PCT_INCREASE
    // RequireThis OFF: INTS_PER_ENTRY
    // RequireThis OFF: PERCENT_100
    // RequireThis OFF: SIZEOF_INT

    /** The IntBuffer used to store the data */
    private IntBuffer buffer;

    /** Creates a new instance of TriangleBufferArray */
    public TriangleBufferArray() {
        this.buffer = ByteBuffer.allocateDirect(DEFAULT_CAPACITY * INTS_PER_ENTRY * SIZEOF_INT)
                .order(ByteOrder.nativeOrder()).asIntBuffer();
        this.buffer.limit(0);
    }

    /**
     * Create a TriangleBufferArray with a specified capacity
     *
     * @param capacity The number of elements this buffer should be capable of holding
     */
    public TriangleBufferArray(int capacity) {
        this.buffer = ByteBuffer.allocateDirect(capacity * INTS_PER_ENTRY * SIZEOF_INT)
                .order(ByteOrder.nativeOrder()).asIntBuffer();
        this.buffer.limit(0);
    }

    /**
     * Resize this buffer to accomodate a larger number of elements
     */
    protected void resizeBuffer() {
        // we can't resize it so we have to allocate a new one and copy the data across
        final int slots = this.buffer.capacity() / INTS_PER_ENTRY;
        final int newCapacity = this.buffer.capacity()
                + (((slots * CAPACITY_PCT_INCREASE) / PERCENT_100) * INTS_PER_ENTRY);

        final IntBuffer newBuffer = ByteBuffer.allocateDirect(newCapacity * SIZEOF_INT)
                .order(ByteOrder.nativeOrder()).asIntBuffer();

        newBuffer.limit(this.buffer.limit());

        if (log.isDebugEnabled()) {
            log.debug("Resizing triangle buffer capacity to: " + newCapacity + " " + newBuffer.capacity());
        }

        this.buffer.rewind();
        newBuffer.put(this.buffer);

        this.buffer = newBuffer;
    }

    /**
     * Set a value in this triangle array
     *
     * @param index The index of the element to be set
     * @param t The triangle object to set this element to
     */
    public void set(int index, Triangle t) {
        // first make sure there's room
        while (buffer.capacity() < (index * INTS_PER_ENTRY)) {
            resizeBuffer();
        }

        if (index >= (this.buffer.limit() / INTS_PER_ENTRY)) {
            this.buffer.limit((index + 1) * INTS_PER_ENTRY);
        }

        this.buffer.put(index * INTS_PER_ENTRY, t.getVertex(0));
        this.buffer.put((index * INTS_PER_ENTRY) + 1, t.getVertex(1));
        this.buffer.put((index * INTS_PER_ENTRY) + 2, t.getVertex(2));
    }

    /**
     * Set a value in this triangle array
     *
     * @param index The index of the element to be set
     * @param vertex The vertex number to be set (0,1 or 2)
     * @param value The value to set this vertex to
     */
    public void set(int index, int vertex, int value) {
        // first make sure there's room
        while (this.buffer.capacity() < (index * INTS_PER_ENTRY)) {
            resizeBuffer();
        }

        if ((index + 1) >= (this.buffer.limit() / INTS_PER_ENTRY)) {
            this.buffer.limit((index + 1) * INTS_PER_ENTRY);
        }

        if (vertex > 2) {
            throw new ArrayIndexOutOfBoundsException("Illegal access to triangle vertex > 2: " + index);
        }

        this.buffer.put((index * INTS_PER_ENTRY) + vertex, value);
    }

    /**
     * Get a value from this triangle array
     *
     * @param index The index of the element to be retrieved
     * @return The <code>Triangle</code> object at this index
     */
    public Triangle get(int index) {
        if (index >= size()) {
            throw new ArrayIndexOutOfBoundsException(
                    "Request for invalid triangle index: " + index + " max is: " + size());
        }

        return new BufferedTriangle(index * INTS_PER_ENTRY);
    }

    /**
     * Get a vertex value from this triangle array
     *
     * @param index The index of the element to be retrieved
     * @param vertex The vertex number to be retrieved (0,1 or 2)
     * @return The value of the specified vertex at this index
     */
    public int get(int index, int vertex) {
        if (index >= size()) {
            throw new ArrayIndexOutOfBoundsException(
                    "Request for invalid triangle index: " + index + " max is: " + size());
        }

        if (vertex > 2) {
            throw new ArrayIndexOutOfBoundsException("Illegal access to triangle vertex > 2: " + index);
        }

        return this.buffer.get((index * INTS_PER_ENTRY) + vertex);
    }

    /**
     * Add a triangle to this array
     *
     * @param t The new triangle to be added
     */
    public void add(Triangle t) {
        // first make sure there's room
        final int slot = this.buffer.limit() / INTS_PER_ENTRY;

        final int slots = this.buffer.capacity() / INTS_PER_ENTRY;

        //System.out.println("slot=" + slot + " capacity = " + slots);
        if (slot >= slots) {
            resizeBuffer();
        }

        this.buffer.limit(this.buffer.limit() + INTS_PER_ENTRY);
        set(slot, t);
    }

    /**
     * Add a triangle composed of discrete vertices to this array
     *
     * @param vertex0 The first vertex of the triangle
     * @param vertex1 The second vertex of the triangle
     * @param vertex2 The third vertex of the triangle
     */
    public void add(int vertex0, int vertex1, int vertex2) {
        // first make sure there's room
        if (this.buffer.limit() == this.buffer.capacity()) {
            resizeBuffer();
        }

        set(this.buffer.limit(), 0, vertex0);
        set(this.buffer.limit(), 1, vertex1);
        set(this.buffer.limit(), 2, vertex2);

        this.buffer.limit(this.buffer.limit() + INTS_PER_ENTRY);
    }

    /**
     * Remove all triangles from this array, clearing it out completely
     */
    public void clear() {
        this.buffer.clear();
        this.buffer.limit(0);
    }

    /**
     * Add all triangles from another triangle array to this one
     *
     * @param source The triangle array to be added to this one. The original
     * array is not modified by this operation.
     */
    public void addAll(TriangleBufferArray source) {
        // first make sure there's room
        while (this.buffer.capacity() < (source.buffer.limit() + buffer.limit())) {
            resizeBuffer();
        }

        final int oldLimit = buffer.limit();

        source.buffer.rewind();

        this.buffer.limit(buffer.limit() + source.buffer.limit());
        this.buffer.position(oldLimit);

        this.buffer.put(source.buffer);
        this.buffer.position(0);
    }

    /**
     * Return the size of this array
     *
     * @return The number of triangles contained in this array
     */
    public int size() {
        return (this.buffer.limit()) / INTS_PER_ENTRY;
    }

    /**
     * Return the capacity of this array
     *
     * @return the number of elements this array can hold
     */
    public int capacity() {
        final int slots = this.buffer.capacity() / INTS_PER_ENTRY;

        return slots;
    }

    /**
     * Get the buffer from this object for passing to routines that need
     * direct access to it such as OpenGL rendering. The buffer will be
     * returned as an unmodifiable copy for read only access.
     *
     * @return An unmodifiable version of the data buffer
     */
    public IntBuffer getBuffer() {
        return this.buffer.asReadOnlyBuffer();
    }

    /**
     * Get the size of an element in this array
     *
     * @return The size of an array element in bytes
     */
    public int getElementSize() {
        return ByteBufferUtils.sizeofInt();
    }

    /**
     * Class that implements the triangle interface for elements stored in
     * this buffer and acts as a proxy to the data
     */
    protected class BufferedTriangle implements Triangle {
        /** The element offset in the buffer that this object is wrapping */
        private int offset;

        /**
         * Create a new instance of BufferedTriangle
         *
         * @param offset The offset in the buffer to be wrapped
         */
        protected BufferedTriangle(int offset) {
            this.offset = offset;
        }

        /**
         * Get the vertex at a particular index
         *
         * @param index The index of the vertex to retrieve (0, 1 or 2)
         * @return The value of the vertex specified for this triangle
         */
        public int getVertex(int index) {
            if (index > 2) {
                throw new ArrayIndexOutOfBoundsException("Illegal access to triangle vertex > 2: " + index);
            }

            return buffer.get(offset + index);
        }
    }
}