159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met:
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer in the
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   documentation and/or other materials provided with the distribution.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   may be used to endorse or promote products derived from this software
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   without specific prior written permission.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.textures;
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingBox;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingSphere;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bounding.BoundingVolume;
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector2f;
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f;
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Geometry;
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh;
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer;
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Format;
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Usage;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List;
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger;
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This class is used for UV coordinates generation.
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas)
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class UVCoordinatesGenerator {
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final Logger	LOGGER						= Logger.getLogger(UVCoordinatesGenerator.class.getName());
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// texture UV coordinates types
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_ORCO					= 1;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_REFL					= 2;
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_NORM					= 4;
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_GLOB					= 8;
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_UV					= 16;
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_OBJECT				= 32;
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_LAVECTOR				= 64;
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_VIEW					= 128;
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_STICKY				= 256;
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_OSA					= 512;
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_WINDOW				= 1024;
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		NEED_UV						= 2048;
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_TANGENT				= 4096;
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// still stored in vertex->accum, 1 D
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_PARTICLE_OR_STRAND	= 8192;													// strand is used
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_STRESS				= 16384;
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		TEXCO_SPEED					= 32768;
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// 2D texture mapping (projection)
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		PROJECTION_FLAT				= 0;
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		PROJECTION_CUBE				= 1;
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		PROJECTION_TUBE				= 2;
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int		PROJECTION_SPHERE			= 3;
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method generates UV coordinates for the given mesh.
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * IMPORTANT! This method assumes that all geometries represent one node.
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Each containing mesh with separate material.
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * So all meshes have the same reference to vertex table which stores all their vertices.
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param texco
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        texture coordinates type
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param projection
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the projection type for 2D textures
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param textureDimension
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the dimension of the texture (only 2D and 3D)
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param coordinatesSwappingIndexes
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        an array that tells how UV-coordinates need to be swapped
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param geometries
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        a list of geometries the UV coordinates will be applied to
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return created UV-coordinates buffer
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static VertexBuffer generateUVCoordinates(int texco, int projection, int textureDimension, int[] coordinatesSwappingIndexes, List<Geometry> geometries) {
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (textureDimension != 2 && textureDimension != 3) {
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			throw new IllegalStateException("Unsupported texture dimension: " + textureDimension);
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		VertexBuffer result = new VertexBuffer(VertexBuffer.Type.TexCoord);
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Mesh mesh = geometries.get(0).getMesh();
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometries);
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float[] inputData = null;// positions, normals, reflection vectors, etc.
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		switch (texco) {
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_ORCO:
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Position));
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_UV:
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				FloatBuffer uvCoordinatesBuffer = BufferUtils.createFloatBuffer(mesh.getVertexCount() * textureDimension);
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				Vector2f[] data = new Vector2f[] { new Vector2f(0, 1), new Vector2f(0, 0), new Vector2f(1, 0) };
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				for (int i = 0; i < mesh.getVertexCount(); ++i) {
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					Vector2f uv = data[i % 3];
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					uvCoordinatesBuffer.put(uv.x);
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					uvCoordinatesBuffer.put(uv.y);
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					if(textureDimension == 3) {
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						uvCoordinatesBuffer.put(0);
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					}
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result.setupData(Usage.Static, textureDimension, Format.Float, uvCoordinatesBuffer);
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_NORM:
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				inputData = BufferUtils.getFloatArray(mesh.getFloatBuffer(VertexBuffer.Type.Normal));
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_REFL:
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_GLOB:
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_TANGENT:
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_STRESS:
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_LAVECTOR:
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_OBJECT:
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_OSA:
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_PARTICLE_OR_STRAND:
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_SPEED:
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_STICKY:
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_VIEW:
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case TEXCO_WINDOW:
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				LOGGER.warning("Texture coordinates type not currently supported: " + texco);
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			default:
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				throw new IllegalStateException("Unknown texture coordinates value: " + texco);
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (inputData != null) {// make calculations
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if (textureDimension == 2) {
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				switch (projection) {
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					case PROJECTION_FLAT:
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						inputData = UVProjectionGenerator.flatProjection(mesh, bb);
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						break;
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					case PROJECTION_CUBE:
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						inputData = UVProjectionGenerator.cubeProjection(mesh, bb);
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						break;
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					case PROJECTION_TUBE:
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						BoundingTube bt = UVCoordinatesGenerator.getBoundingTube(geometries);
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						inputData = UVProjectionGenerator.tubeProjection(mesh, bt);
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						break;
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					case PROJECTION_SPHERE:
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						BoundingSphere bs = UVCoordinatesGenerator.getBoundingSphere(geometries);
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						inputData = UVProjectionGenerator.sphereProjection(mesh, bs);
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						break;
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					default:
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						throw new IllegalStateException("Unknown projection type: " + projection);
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			} else {
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				Vector3f min = bb.getMin(null);
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				float[] uvCoordsResults = new float[4];//used for coordinates swapping
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				float[] ext = new float[] { bb.getXExtent() * 2, bb.getYExtent() * 2, bb.getZExtent() * 2 };
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				// now transform the coordinates so that they are in the range of <0; 1>
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				for (int i = 0; i < inputData.length; i += 3) {
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					uvCoordsResults[1] = (inputData[i] - min.x) / ext[0];
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					uvCoordsResults[2] = (inputData[i + 1] - min.y) / ext[1];
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					uvCoordsResults[3] = (inputData[i + 2] - min.z) / ext[2];
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					inputData[i] = uvCoordsResults[coordinatesSwappingIndexes[0]];
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					inputData[i + 1] = uvCoordsResults[coordinatesSwappingIndexes[1]];
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					inputData[i + 2] = uvCoordsResults[coordinatesSwappingIndexes[2]];
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setupData(Usage.Static, textureDimension, Format.Float, BufferUtils.createFloatBuffer(inputData));
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// each mesh will have the same coordinates
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (Geometry geometry : geometries) {
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			mesh = geometry.getMesh();
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			mesh.clearBuffer(VertexBuffer.Type.TexCoord);// in case there are coordinates already set
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			mesh.setBuffer(result);
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding box of the given geometries.
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param geometries
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the list of geometries
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding box of the given geometries
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingBox getBoundingBox(List<Geometry> geometries) {
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingBox result = null;
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (Geometry geometry : geometries) {
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometry.getMesh());
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if (result == null) {
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result = bb;
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			} else {
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result.merge(bb);
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding box of the given mesh.
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param mesh
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the mesh
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding box of the given mesh
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingBox getBoundingBox(Mesh mesh) {
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		mesh.updateBound();
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingVolume bv = mesh.getBound();
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (bv instanceof BoundingBox) {
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return (BoundingBox) bv;
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else if (bv instanceof BoundingSphere) {
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingSphere bs = (BoundingSphere) bv;
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float r = bs.getRadius();
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return new BoundingBox(bs.getCenter(), r, r, r);
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else {
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			throw new IllegalStateException("Unknown bounding volume type: " + bv.getClass().getName());
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding sphere of the given geometries.
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param geometries
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the list of geometries
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding sphere of the given geometries
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingSphere getBoundingSphere(List<Geometry> geometries) {
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingSphere result = null;
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (Geometry geometry : geometries) {
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingSphere bs = UVCoordinatesGenerator.getBoundingSphere(geometry.getMesh());
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if (result == null) {
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result = bs;
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			} else {
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result.merge(bs);
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding sphere of the given mesh.
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param mesh
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the mesh
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding sphere of the given mesh
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingSphere getBoundingSphere(Mesh mesh) {
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		mesh.updateBound();
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingVolume bv = mesh.getBound();
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (bv instanceof BoundingBox) {
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingBox bb = (BoundingBox) bv;
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float r = Math.max(bb.getXExtent(), bb.getYExtent());
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			r = Math.max(r, bb.getZExtent());
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return new BoundingSphere(r, bb.getCenter());
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else if (bv instanceof BoundingSphere) {
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return (BoundingSphere) bv;
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else {
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			throw new IllegalStateException("Unknown bounding volume type: " + bv.getClass().getName());
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding tube of the given mesh.
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param mesh
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the mesh
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding tube of the given mesh
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingTube getBoundingTube(Mesh mesh) {
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Vector3f center = new Vector3f();
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float maxx = -Float.MAX_VALUE, minx = Float.MAX_VALUE;
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float maxy = -Float.MAX_VALUE, miny = Float.MAX_VALUE;
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float maxz = -Float.MAX_VALUE, minz = Float.MAX_VALUE;
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int limit = positions.limit();
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (int i = 0; i < limit; i += 3) {
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float x = positions.get(i);
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float y = positions.get(i + 1);
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float z = positions.get(i + 2);
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			center.addLocal(x, y, z);
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			maxx = x > maxx ? x : maxx;
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			minx = x < minx ? x : minx;
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			maxy = y > maxy ? y : maxy;
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			miny = y < miny ? y : miny;
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			maxz = z > maxz ? z : maxz;
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			minz = z < minz ? z : minz;
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		center.divideLocal(limit / 3);
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float radius = Math.max(maxx - minx, maxy - miny) * 0.5f;
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return new BoundingTube(radius, maxz - minz, center);
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the bounding tube of the given geometries.
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param geometries
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the list of geometries
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bounding tube of the given geometries
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static BoundingTube getBoundingTube(List<Geometry> geometries) {
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BoundingTube result = null;
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (Geometry geometry : geometries) {
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingTube bt = UVCoordinatesGenerator.getBoundingTube(geometry.getMesh());
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if (result == null) {
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result = bt;
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			} else {
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				result.merge(bt);
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * A very simple bounding tube. Id holds only the basic data bout the bounding tube
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * and does not provide full functionality of a BoundingVolume.
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Should be replaced with a bounding tube that extends the BoundingVolume if it is ever created.
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @author Marcin Roguski (Kaelthas)
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* package */static class BoundingTube {
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		private float		radius;
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		private float		height;
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		private Vector3f	center;
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * Constructor creates the tube with the given params.
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @param radius
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *        the radius of the tube
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @param height
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *        the height of the tube
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @param center
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *        the center of the tube
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public BoundingTube(float radius, float height, Vector3f center) {
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.radius = radius;
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.height = height;
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.center = center;
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * This method merges two bounding tubes.
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @param boundingTube
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *        bounding tube to be merged woth the current one
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @return new instance of bounding tube representing the tubes' merge
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public BoundingTube merge(BoundingTube boundingTube) {
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			// get tubes (tube1.radius >= tube2.radius)
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BoundingTube tube1, tube2;
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if (this.radius >= boundingTube.radius) {
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				tube1 = this;
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				tube2 = boundingTube;
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			} else {
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				tube1 = boundingTube;
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				tube2 = this;
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float r1 = tube1.radius;
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float r2 = tube2.radius;
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float minZ = Math.min(tube1.center.z - tube1.height * 0.5f, tube2.center.z - tube2.height * 0.5f);
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float maxZ = Math.max(tube1.center.z + tube1.height * 0.5f, tube2.center.z + tube2.height * 0.5f);
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float height = maxZ - minZ;
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Vector3f distance = tube2.center.subtract(tube1.center);
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Vector3f center = tube1.center.add(distance.mult(0.5f));
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			distance.z = 0;// projecting this vector on XY plane
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float d = distance.length();
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			// d <= r1 - r2: tube2 is inside tube1 or touches tube1 from the inside
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			// d > r1 - r2: tube2 is outside or touches tube1 or crosses tube1
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float radius = d <= r1 - r2 ? tube1.radius : (d + r1 + r2) * 0.5f;
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return new BoundingTube(radius, height, center);
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * This method returns the radius of the tube.
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @return the radius of the tube
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public float getRadius() {
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return radius;
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * This method returns the height of the tube.
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @return the height of the tube
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public float getHeight() {
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return height;
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * This method returns the center of the tube.
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @return the center of the tube
40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public Vector3f getCenter() {
40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return center;
40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
409