Package com.jme3.scene.plugins.blender.textures

Source Code of com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator$BoundingTube

/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
*   notice, this list of conditions and the following disclaimer in the
*   documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
*   may be used to endorse or promote products derived from this software
*   without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.scene.plugins.blender.textures;

import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.plugins.blender.textures.UVProjectionGenerator.UVProjectionType;
import com.jme3.util.BufferUtils;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
* This class is used for UV coordinates generation.
*
* @author Marcin Roguski (Kaelthas)
*/
public class UVCoordinatesGenerator {
    private static final Logger LOGGER = Logger.getLogger(UVCoordinatesGenerator.class.getName());

    public static enum UVCoordinatesType {
        TEXCO_ORCO(1), TEXCO_REFL(2), TEXCO_NORM(4), TEXCO_GLOB(8), TEXCO_UV(16), TEXCO_OBJECT(32), TEXCO_LAVECTOR(64), TEXCO_VIEW(128),
        TEXCO_STICKY(256), TEXCO_OSA(512), TEXCO_WINDOW(1024), NEED_UV(2048), TEXCO_TANGENT(4096),
        TEXCO_PARTICLE_OR_STRAND(8192), //TEXCO_PARTICLE (since blender 2.6x) has also the value of: 8192 but is used for halo materials instead of normal materials
        TEXCO_STRESS(16384), TEXCO_SPEED(32768);

        public final int blenderValue;

        private UVCoordinatesType(int blenderValue) {
            this.blenderValue = blenderValue;
        }

        public static UVCoordinatesType valueOf(int blenderValue) {
            for (UVCoordinatesType coordinatesType : UVCoordinatesType.values()) {
                if (coordinatesType.blenderValue == blenderValue) {
                    return coordinatesType;
                }
            }
            return null;
        }
    }

    /**
     * Generates a UV coordinates for 2D texture.
     *
     * @param mesh
     *            the mesh we generate UV's for
     * @param texco
     *            UV coordinates type
     * @param projection
     *            projection type
     * @param geometries
     *            the geometris the given mesh belongs to (required to compute
     *            bounding box)
     * @return UV coordinates for the given mesh
     */
    public static List<Vector2f> generateUVCoordinatesFor2DTexture(Mesh mesh, UVCoordinatesType texco, UVProjectionType projection, List<Geometry> geometries) {
        List<Vector2f> result = new ArrayList<Vector2f>();
        BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometries);
        float[] inputData = null;// positions, normals, reflection vectors, etc.

        switch (texco) {
            case TEXCO_ORCO:
                inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Position));
                break;
            case TEXCO_UV:// this should be used if not defined by user explicitly
                Vector2f[] data = new Vector2f[] { new Vector2f(0, 1), new Vector2f(0, 0), new Vector2f(1, 0) };
                for (int i = 0; i < mesh.getVertexCount(); ++i) {
                    result.add(data[i % 3]);
                }
                break;
            case TEXCO_NORM:
                inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Normal));
                break;
            case TEXCO_REFL:
            case TEXCO_GLOB:
            case TEXCO_TANGENT:
            case TEXCO_STRESS:
            case TEXCO_LAVECTOR:
            case TEXCO_OBJECT:
            case TEXCO_OSA:
            case TEXCO_PARTICLE_OR_STRAND:
            case TEXCO_SPEED:
            case TEXCO_STICKY:
            case TEXCO_VIEW:
            case TEXCO_WINDOW:
                LOGGER.warning("Texture coordinates type not currently supported: " + texco);
                break;
            default:
                throw new IllegalStateException("Unknown texture coordinates value: " + texco);
        }

        if (inputData != null) {// make projection calculations
            switch (projection) {
                case PROJECTION_FLAT:
                    inputData = UVProjectionGenerator.flatProjection(inputData, bb);
                    break;
                case PROJECTION_CUBE:
                    inputData = UVProjectionGenerator.cubeProjection(inputData, bb);
                    break;
                case PROJECTION_TUBE:
                    BoundingTube bt = UVCoordinatesGenerator.getBoundingTube(geometries);
                    inputData = UVProjectionGenerator.tubeProjection(inputData, bt);
                    break;
                case PROJECTION_SPHERE:
                    BoundingSphere bs = UVCoordinatesGenerator.getBoundingSphere(geometries);
                    inputData = UVProjectionGenerator.sphereProjection(inputData, bs);
                    break;
                default:
                    throw new IllegalStateException("Unknown projection type: " + projection);
            }
            for (int i = 0; i < inputData.length; i += 2) {
                result.add(new Vector2f(inputData[i], inputData[i + 1]));
            }
        }
        return result;
    }

    /**
     * Generates a UV coordinates for 3D texture.
     *
     * @param mesh
     *            the mesh we generate UV's for
     * @param texco
     *            UV coordinates type
     * @param coordinatesSwappingIndexes
     *            coordinates swapping indexes
     * @param geometries
     *            the geometris the given mesh belongs to (required to compute
     *            bounding box)
     * @return UV coordinates for the given mesh
     */
    public static List<Vector3f> generateUVCoordinatesFor3DTexture(Mesh mesh, UVCoordinatesType texco, int[] coordinatesSwappingIndexes, List<Geometry> geometries) {
        List<Vector3f> result = new ArrayList<Vector3f>();
        BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometries);
        float[] inputData = null;// positions, normals, reflection vectors, etc.

        switch (texco) {
            case TEXCO_ORCO:
                inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Position));
                break;
            case TEXCO_UV:
                Vector2f[] data = new Vector2f[] { new Vector2f(0, 1), new Vector2f(0, 0), new Vector2f(1, 0) };
                for (int i = 0; i < mesh.getVertexCount(); ++i) {
                    Vector2f uv = data[i % 3];
                    result.add(new Vector3f(uv.x, uv.y, 0));
                }
                break;
            case TEXCO_NORM:
                inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Normal));
                break;
            case TEXCO_REFL:
            case TEXCO_GLOB:
            case TEXCO_TANGENT:
            case TEXCO_STRESS:
            case TEXCO_LAVECTOR:
            case TEXCO_OBJECT:
            case TEXCO_OSA:
            case TEXCO_PARTICLE_OR_STRAND:
            case TEXCO_SPEED:
            case TEXCO_STICKY:
            case TEXCO_VIEW:
            case TEXCO_WINDOW:
                LOGGER.warning("Texture coordinates type not currently supported: " + texco);
                break;
            default:
                throw new IllegalStateException("Unknown texture coordinates value: " + texco);
        }

        if (inputData != null) {// make calculations
            Vector3f min = bb.getMin(null);
            float[] uvCoordsResults = new float[4];// used for coordinates swapping
            float[] ext = new float[] { bb.getXExtent() * 2, bb.getYExtent() * 2, bb.getZExtent() * 2 };
            for (int i = 0; i < ext.length; ++i) {
                if (ext[i] == 0) {
                    ext[i] = 1;
                }
            }
            // now transform the coordinates so that they are in the range of
            // <0; 1>
            for (int i = 0; i < inputData.length; i += 3) {
                uvCoordsResults[1] = (inputData[i] - min.x) / ext[0];
                uvCoordsResults[2] = (inputData[i + 1] - min.y) / ext[1];
                uvCoordsResults[3] = (inputData[i + 2] - min.z) / ext[2];
                result.add(new Vector3f(uvCoordsResults[coordinatesSwappingIndexes[0]], uvCoordsResults[coordinatesSwappingIndexes[1]], uvCoordsResults[coordinatesSwappingIndexes[2]]));
            }
        }
        return result;
    }

    /**
     * This method should be used to determine if the texture will ever be
     * computed. If the texture coordinates are not supported then the try of
     * flattening the texture might result in runtime exceptions occurence.
     *
     * @param texco
     *            the texture coordinates type
     * @return <b>true</b> if the type is supported and false otherwise
     */
    public static boolean isTextureCoordinateTypeSupported(UVCoordinatesType texco) {
        switch (texco) {
            case TEXCO_ORCO:
            case TEXCO_UV:
            case TEXCO_NORM:
                return true;
            case TEXCO_REFL:
            case TEXCO_GLOB:
            case TEXCO_TANGENT:
            case TEXCO_STRESS:
            case TEXCO_LAVECTOR:
            case TEXCO_OBJECT:
            case TEXCO_OSA:
            case TEXCO_PARTICLE_OR_STRAND:
            case TEXCO_SPEED:
            case TEXCO_STICKY:
            case TEXCO_VIEW:
            case TEXCO_WINDOW:
                return false;
            default:
                throw new IllegalStateException("Unknown texture coordinates value: " + texco);
        }
    }

    /**
     * This method returns the bounding box of the given geometries.
     *
     * @param geometries
     *            the list of geometries
     * @return bounding box of the given geometries
     */
    public static BoundingBox getBoundingBox(List<Geometry> geometries) {
        BoundingBox result = null;
        for (Geometry geometry : geometries) {
            BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometry.getMesh());
            if (result == null) {
                result = bb;
            } else {
                result.merge(bb);
            }
        }
        return result;
    }

    /**
     * This method returns the bounding box of the given mesh.
     *
     * @param mesh
     *            the mesh
     * @return bounding box of the given mesh
     */
    /* package */static BoundingBox getBoundingBox(Mesh mesh) {
        mesh.updateBound();
        BoundingVolume bv = mesh.getBound();
        if (bv instanceof BoundingBox) {
            return (BoundingBox) bv;
        } else if (bv instanceof BoundingSphere) {
            BoundingSphere bs = (BoundingSphere) bv;
            float r = bs.getRadius();
            return new BoundingBox(bs.getCenter(), r, r, r);
        } else {
            throw new IllegalStateException("Unknown bounding volume type: " + bv.getClass().getName());
        }
    }

    /**
     * This method returns the bounding sphere of the given geometries.
     *
     * @param geometries
     *            the list of geometries
     * @return bounding sphere of the given geometries
     */
    /* package */static BoundingSphere getBoundingSphere(List<Geometry> geometries) {
        BoundingSphere result = null;
        for (Geometry geometry : geometries) {
            BoundingSphere bs = UVCoordinatesGenerator.getBoundingSphere(geometry.getMesh());
            if (result == null) {
                result = bs;
            } else {
                result.merge(bs);
            }
        }
        return result;
    }

    /**
     * This method returns the bounding sphere of the given mesh.
     *
     * @param mesh
     *            the mesh
     * @return bounding sphere of the given mesh
     */
    /* package */static BoundingSphere getBoundingSphere(Mesh mesh) {
        mesh.updateBound();
        BoundingVolume bv = mesh.getBound();
        if (bv instanceof BoundingBox) {
            BoundingBox bb = (BoundingBox) bv;
            float r = Math.max(bb.getXExtent(), bb.getYExtent());
            r = Math.max(r, bb.getZExtent());
            return new BoundingSphere(r, bb.getCenter());
        } else if (bv instanceof BoundingSphere) {
            return (BoundingSphere) bv;
        } else {
            throw new IllegalStateException("Unknown bounding volume type: " + bv.getClass().getName());
        }
    }

    /**
     * This method returns the bounding tube of the given mesh.
     *
     * @param mesh
     *            the mesh
     * @return bounding tube of the given mesh
     */
    /* package */static BoundingTube getBoundingTube(Mesh mesh) {
        Vector3f center = new Vector3f();
        float maxx = -Float.MAX_VALUE, minx = Float.MAX_VALUE;
        float maxy = -Float.MAX_VALUE, miny = Float.MAX_VALUE;
        float maxz = -Float.MAX_VALUE, minz = Float.MAX_VALUE;

        FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
        int limit = positions.limit();
        for (int i = 0; i < limit; i += 3) {
            float x = positions.get(i);
            float y = positions.get(i + 1);
            float z = positions.get(i + 2);
            center.addLocal(x, y, z);
            maxx = x > maxx ? x : maxx;
            minx = x < minx ? x : minx;
            maxy = y > maxy ? y : maxy;
            miny = y < miny ? y : miny;
            maxz = z > maxz ? z : maxz;
            minz = z < minz ? z : minz;
        }
        center.divideLocal(limit / 3);

        float radius = Math.max(maxx - minx, maxy - miny) * 0.5f;
        return new BoundingTube(radius, maxz - minz, center);
    }

    /**
     * This method returns the bounding tube of the given geometries.
     *
     * @param geometries
     *            the list of geometries
     * @return bounding tube of the given geometries
     */
    /* package */static BoundingTube getBoundingTube(List<Geometry> geometries) {
        BoundingTube result = null;
        for (Geometry geometry : geometries) {
            BoundingTube bt = UVCoordinatesGenerator.getBoundingTube(geometry.getMesh());
            if (result == null) {
                result = bt;
            } else {
                result.merge(bt);
            }
        }
        return result;
    }

    /**
     * A very simple bounding tube. Id holds only the basic data bout the
     * bounding tube and does not provide full functionality of a
     * BoundingVolume. Should be replaced with a bounding tube that extends the
     * BoundingVolume if it is ever created.
     *
     * @author Marcin Roguski (Kaelthas)
     */
    /* package */static class BoundingTube {
        private float    radius;
        private float    height;
        private Vector3f center;

        /**
         * Constructor creates the tube with the given params.
         *
         * @param radius
         *            the radius of the tube
         * @param height
         *            the height of the tube
         * @param center
         *            the center of the tube
         */
        public BoundingTube(float radius, float height, Vector3f center) {
            this.radius = radius;
            this.height = height;
            this.center = center;
        }

        /**
         * This method merges two bounding tubes.
         *
         * @param boundingTube
         *            bounding tube to be merged woth the current one
         * @return new instance of bounding tube representing the tubes' merge
         */
        public BoundingTube merge(BoundingTube boundingTube) {
            // get tubes (tube1.radius >= tube2.radius)
            BoundingTube tube1, tube2;
            if (this.radius >= boundingTube.radius) {
                tube1 = this;
                tube2 = boundingTube;
            } else {
                tube1 = boundingTube;
                tube2 = this;
            }
            float r1 = tube1.radius;
            float r2 = tube2.radius;

            float minZ = Math.min(tube1.center.z - tube1.height * 0.5f, tube2.center.z - tube2.height * 0.5f);
            float maxZ = Math.max(tube1.center.z + tube1.height * 0.5f, tube2.center.z + tube2.height * 0.5f);
            float height = maxZ - minZ;
            Vector3f distance = tube2.center.subtract(tube1.center);
            Vector3f center = tube1.center.add(distance.mult(0.5f));
            distance.z = 0;// projecting this vector on XY plane
            float d = distance.length();
            // d <= r1 - r2: tube2 is inside tube1 or touches tube1 from the
            // inside
            // d > r1 - r2: tube2 is outside or touches tube1 or crosses tube1
            float radius = d <= r1 - r2 ? tube1.radius : (d + r1 + r2) * 0.5f;
            return new BoundingTube(radius, height, center);
        }

        /**
         * @return the radius of the tube
         */
        public float getRadius() {
            return radius;
        }

        /**
         * @return the height of the tube
         */
        public float getHeight() {
            return height;
        }

        /**
         * @return the center of the tube
         */
        public Vector3f getCenter() {
            return center;
        }
    }
}
TOP

Related Classes of com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator$BoundingTube

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.