Package com.ardor3d.util.geom

Source Code of com.ardor3d.util.geom.GeometryTool

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.util.geom;

import java.util.EnumSet;
import java.util.Map;
import java.util.logging.Logger;

import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.Vector2;
import com.ardor3d.math.Vector3;
import com.ardor3d.scenegraph.IndexBufferData;
import com.ardor3d.scenegraph.Mesh;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.scenegraph.Spatial;
import com.google.common.collect.Maps;

/**
* This tool assists in reducing geometry information.<br>
*
* Note: Does not work with geometry using texcoords other than 2d coords. <br>
* TODO: Consider adding an option for "close enough" vertex matches... ie, smaller than X distance apart.<br>
*/
public abstract class GeometryTool {
    private static final Logger logger = Logger.getLogger(GeometryTool.class.getName());

    /**
     * Condition options for determining if one vertex is "equal" to another.
     */
    public enum MatchCondition {
        /** Vertices must have identical normals. */
        Normal,
        /** Vertices must have identical texture coords on all channels. */
        UVs,
        /** Vertices must have identical vertex coloring. */
        Color,
        /** Vertices must be in same group. */
        Group;
    }

    /**
     * Attempt to collapse duplicate vertex data in a given mesh. Vertices are considered duplicate if they occupy the
     * same place in space and match the supplied conditions. All vertices in the mesh are considered part of the same
     * vertex "group".
     *
     * @param mesh
     *            the mesh to reduce
     * @param conditions
     *            our match conditions.
     * @return a mapping of old vertex positions to their new positions.
     */
    public static VertMap minimizeVerts(final Mesh mesh, final EnumSet<MatchCondition> conditions) {
        final VertGroupData groupData = new VertGroupData();
        groupData.setGroupConditions(VertGroupData.DEFAULT_GROUP, conditions);
        return minimizeVerts(mesh, groupData);
    }

    /**
     * Attempt to collapse duplicate vertex data in a given mesh. Vertices are consider duplicate if they occupy the
     * same place in space and match the supplied conditions. The conditions are supplied per vertex group.
     *
     * @param mesh
     *            the mesh to reduce
     * @param groupData
     *            grouping data for the vertices in this mesh.
     * @return a mapping of old vertex positions to their new positions.
     */
    public static VertMap minimizeVerts(final Mesh mesh, final VertGroupData groupData) {
        final long start = System.currentTimeMillis();

        int vertCount = -1;
        final int oldCount = mesh.getMeshData().getVertexCount();
        int newCount = 0;

        final VertMap result = new VertMap(mesh);

        // while we have not run through this optimization and ended up the same...
        // XXX: could optimize this to run all in arrays, then write to buffer after while loop.
        while (vertCount != newCount) {
            vertCount = mesh.getMeshData().getVertexCount();
            // go through each vert...
            final Vector3[] verts = BufferUtils.getVector3Array(mesh.getMeshData().getVertexCoords(), Vector3.ZERO);
            Vector3[] norms = null;
            if (mesh.getMeshData().getNormalBuffer() != null) {
                norms = BufferUtils.getVector3Array(mesh.getMeshData().getNormalCoords(), Vector3.UNIT_Y);
            }

            // see if we have vertex colors
            ColorRGBA[] colors = null;
            if (mesh.getMeshData().getColorBuffer() != null) {
                colors = BufferUtils.getColorArray(mesh.getMeshData().getColorCoords(), ColorRGBA.WHITE);
            }

            // see if we have uv coords
            final Vector2[][] tex = new Vector2[mesh.getMeshData().getNumberOfUnits()][];
            for (int x = 0; x < tex.length; x++) {
                if (mesh.getMeshData().getTextureCoords(x) != null) {
                    tex[x] = BufferUtils.getVector2Array(mesh.getMeshData().getTextureCoords(x), Vector2.ZERO);
                }
            }

            final Map<VertKey, Integer> store = Maps.newHashMap();
            final Map<Integer, Integer> indexRemap = Maps.newHashMap();
            int good = 0;
            long group;
            for (int x = 0, max = verts.length; x < max; x++) {
                group = groupData.getGroupForVertex(x);
                final VertKey vkey = new VertKey(verts[x], norms != null ? norms[x] : null, colors != null ? colors[x]
                        : null, getTexs(tex, x), groupData.getGroupConditions(group), group);
                // if we've already seen it, swap it for the max, and decrease max.
                if (store.containsKey(vkey)) {
                    final int newInd = store.get(vkey);
                    if (indexRemap.containsKey(x)) {
                        indexRemap.put(max, newInd);
                    } else {
                        indexRemap.put(x, newInd);
                    }
                    max--;
                    if (x != max) {
                        indexRemap.put(max, x);
                        verts[x] = verts[max];
                        verts[max] = null;
                        if (norms != null) {
                            norms[newInd].addLocal(norms[x].normalizeLocal());
                            norms[x] = norms[max];
                        }
                        if (colors != null) {
                            colors[x] = colors[max];
                        }
                        for (int y = 0; y < tex.length; y++) {
                            if (mesh.getMeshData().getTextureCoords(y) != null) {
                                tex[y][x] = tex[y][max];
                            }
                        }
                        x--;
                    } else {
                        verts[max] = null;
                    }
                }

                // otherwise just store it
                else {
                    store.put(vkey, x);
                    good++;
                }
            }

            if (norms != null) {
                for (final Vector3 norm : norms) {
                    norm.normalizeLocal();
                }
            }

            mesh.getMeshData().setVertexBuffer(BufferUtils.createFloatBuffer(0, good, verts));
            if (norms != null) {
                mesh.getMeshData().setNormalBuffer(BufferUtils.createFloatBuffer(0, good, norms));
            }
            if (colors != null) {
                mesh.getMeshData().setColorBuffer(BufferUtils.createFloatBuffer(0, good, colors));
            }

            for (int x = 0; x < tex.length; x++) {
                if (tex[x] != null) {
                    mesh.getMeshData().setTextureBuffer(BufferUtils.createFloatBuffer(0, good, tex[x]), x);
                }
            }

            if (mesh.getMeshData().getIndices() == null || mesh.getMeshData().getIndices().getBufferCapacity() == 0) {
                final IndexBufferData<?> indexBuffer = BufferUtils.createIndexBufferData(oldCount, oldCount);
                mesh.getMeshData().setIndices(indexBuffer);
                for (int i = 0; i < oldCount; i++) {
                    if (indexRemap.containsKey(i)) {
                        indexBuffer.put(indexRemap.get(i));
                    } else {
                        indexBuffer.put(i);
                    }
                }
            } else {
                final IndexBufferData<?> indexBuffer = mesh.getMeshData().getIndices();
                final int[] inds = BufferUtils.getIntArray(indexBuffer);
                indexBuffer.rewind();
                for (final int i : inds) {
                    if (indexRemap.containsKey(i)) {
                        indexBuffer.put(indexRemap.get(i));
                    } else {
                        indexBuffer.put(i);
                    }
                }
            }
            result.applyRemapping(indexRemap);
            newCount = mesh.getMeshData().getVertexCount();
        }

        logger.info("Vertex reduction complete on: " + mesh + "  old vertex count: " + oldCount + " new vertex count: "
                + newCount + " (in " + (System.currentTimeMillis() - start) + " ms)");

        return result;
    }

    private static Vector2[] getTexs(final Vector2[][] tex, final int i) {
        final Vector2[] res = new Vector2[tex.length];
        for (int x = 0; x < tex.length; x++) {
            if (tex[x] != null) {
                res[x] = tex[x][i];
            }
        }
        return res;
    }

    public static void trimEmptyBranches(final Spatial spatial) {
        if (spatial instanceof Node) {
            final Node node = (Node) spatial;
            for (int i = node.getNumberOfChildren(); --i >= 0;) {
                trimEmptyBranches(node.getChild(i));
            }
            if (node.getNumberOfChildren() <= 0) {
                spatial.removeFromParent();
            }
        }
    }
}
TOP

Related Classes of com.ardor3d.util.geom.GeometryTool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.