aboutsummaryrefslogtreecommitdiff
path: root/engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java')
-rw-r--r--engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java408
1 files changed, 408 insertions, 0 deletions
diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java
new file mode 100644
index 0000000..56e4293
--- /dev/null
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2009-2010 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.VertexBuffer.Format;
+import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.util.BufferUtils;
+import java.nio.FloatBuffer;
+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());
+
+ // texture UV coordinates types
+ public static final int TEXCO_ORCO = 1;
+ public static final int TEXCO_REFL = 2;
+ public static final int TEXCO_NORM = 4;
+ public static final int TEXCO_GLOB = 8;
+ public static final int TEXCO_UV = 16;
+ public static final int TEXCO_OBJECT = 32;
+ public static final int TEXCO_LAVECTOR = 64;
+ public static final int TEXCO_VIEW = 128;
+ public static final int TEXCO_STICKY = 256;
+ public static final int TEXCO_OSA = 512;
+ public static final int TEXCO_WINDOW = 1024;
+ public static final int NEED_UV = 2048;
+ public static final int TEXCO_TANGENT = 4096;
+ // still stored in vertex->accum, 1 D
+ public static final int TEXCO_PARTICLE_OR_STRAND = 8192; // strand is used
+ public static final int TEXCO_STRESS = 16384;
+ public static final int TEXCO_SPEED = 32768;
+
+ // 2D texture mapping (projection)
+ public static final int PROJECTION_FLAT = 0;
+ public static final int PROJECTION_CUBE = 1;
+ public static final int PROJECTION_TUBE = 2;
+ public static final int PROJECTION_SPHERE = 3;
+
+ /**
+ * This method generates UV coordinates for the given mesh.
+ * IMPORTANT! This method assumes that all geometries represent one node.
+ * Each containing mesh with separate material.
+ * So all meshes have the same reference to vertex table which stores all their vertices.
+ * @param texco
+ * texture coordinates type
+ * @param projection
+ * the projection type for 2D textures
+ * @param textureDimension
+ * the dimension of the texture (only 2D and 3D)
+ * @param coordinatesSwappingIndexes
+ * an array that tells how UV-coordinates need to be swapped
+ * @param geometries
+ * a list of geometries the UV coordinates will be applied to
+ * @return created UV-coordinates buffer
+ */
+ public static VertexBuffer generateUVCoordinates(int texco, int projection, int textureDimension, int[] coordinatesSwappingIndexes, List<Geometry> geometries) {
+ if (textureDimension != 2 && textureDimension != 3) {
+ throw new IllegalStateException("Unsupported texture dimension: " + textureDimension);
+ }
+
+ VertexBuffer result = new VertexBuffer(VertexBuffer.Type.TexCoord);
+ Mesh mesh = geometries.get(0).getMesh();
+ 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:
+ FloatBuffer uvCoordinatesBuffer = BufferUtils.createFloatBuffer(mesh.getVertexCount() * textureDimension);
+ 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];
+ uvCoordinatesBuffer.put(uv.x);
+ uvCoordinatesBuffer.put(uv.y);
+ if(textureDimension == 3) {
+ uvCoordinatesBuffer.put(0);
+ }
+ }
+ result.setupData(Usage.Static, textureDimension, Format.Float, uvCoordinatesBuffer);
+ 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
+ if (textureDimension == 2) {
+ switch (projection) {
+ case PROJECTION_FLAT:
+ inputData = UVProjectionGenerator.flatProjection(mesh, bb);
+ break;
+ case PROJECTION_CUBE:
+ inputData = UVProjectionGenerator.cubeProjection(mesh, bb);
+ break;
+ case PROJECTION_TUBE:
+ BoundingTube bt = UVCoordinatesGenerator.getBoundingTube(geometries);
+ inputData = UVProjectionGenerator.tubeProjection(mesh, bt);
+ break;
+ case PROJECTION_SPHERE:
+ BoundingSphere bs = UVCoordinatesGenerator.getBoundingSphere(geometries);
+ inputData = UVProjectionGenerator.sphereProjection(mesh, bs);
+ break;
+ default:
+ throw new IllegalStateException("Unknown projection type: " + projection);
+ }
+ } else {
+ 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 };
+
+ // 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];
+
+
+ inputData[i] = uvCoordsResults[coordinatesSwappingIndexes[0]];
+ inputData[i + 1] = uvCoordsResults[coordinatesSwappingIndexes[1]];
+ inputData[i + 2] = uvCoordsResults[coordinatesSwappingIndexes[2]];
+ }
+ }
+ result.setupData(Usage.Static, textureDimension, Format.Float, BufferUtils.createFloatBuffer(inputData));
+ }
+
+ // each mesh will have the same coordinates
+ for (Geometry geometry : geometries) {
+ mesh = geometry.getMesh();
+ mesh.clearBuffer(VertexBuffer.Type.TexCoord);// in case there are coordinates already set
+ mesh.setBuffer(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * This method returns the bounding box of the given geometries.
+ * @param geometries
+ * the list of geometries
+ * @return bounding box of the given geometries
+ */
+ /* package */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);
+ }
+
+ /**
+ * This method returns the radius of the tube.
+ * @return the radius of the tube
+ */
+ public float getRadius() {
+ return radius;
+ }
+
+ /**
+ * This method returns the height of the tube.
+ * @return the height of the tube
+ */
+ public float getHeight() {
+ return height;
+ }
+
+ /**
+ * This method returns the center of the tube.
+ * @return the center of the tube
+ */
+ public Vector3f getCenter() {
+ return center;
+ }
+ }
+}