hi i would like to submit my code so that it can be used by everyone, who knows someone might need it.
Symmetry
Current bugs :
- i dont know how to apply animationControl / skeletonControl to the new mesh.
- havent implemented “slice along mirror” operation yet.
[java]
package jme3test;
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.SkeletonControl;
import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TangentBinormalGenerator;
import java.util.logging.Level;
import java.util.logging.Logger;
/** BUG : each mesh loses animation. Because i dont know how to attach the skeleton/animation control to new mesh.*/
public class TestSymmetry extends SimpleApplication implements AnimEventListener
{
public static void main(String[] args)
{
TestSymmetry app = new TestSymmetry();
app.start();
}
@Override
public void simpleInitApp()
{
Logger.getLogger("").setLevel(Level.SEVERE);
flyCam.setMoveSpeed(50);
Node node = (Node)assetManager.loadModel(“Models/Sinbad/Sinbad.mesh.xml”);
SkeletonControl skeleton = node.getControl(SkeletonControl.class);
AnimControl animation = node.getControl(AnimControl.class);
//apply symmetry modifier to all model parts.
for(Spatial child : node.getChildren())
{
Geometry geom = (Geometry)child;
Mesh mesh = geom.getMesh();
MeshData data = new MeshData(mesh).createSymmetricMesh(Vector3f.ZERO, Vector3f.UNIT_Y, 0.1f);
mesh = data.createMesh();
geom.setMesh(mesh); //BUG : each mesh loses animation.
}
TangentBinormalGenerator.generate(node);
rootNode.attachChild(node);
AnimControl control = node.getControl(AnimControl.class);
if (control != null) //if it has animation
{
control.addListener(this);
AnimChannel channel = control.createChannel();
channel.setAnim(“SliceHorizontal”);
}
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(1, 0, -2).normalizeLocal());
sun.setColor(ColorRGBA.White);
rootNode.addLight(sun);
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.5f));
rootNode.addLight(al);
cam.setLocation(new Vector3f(-5f, 2f, 0f));
cam.lookAt(new Vector3f(0f, 1.5f, 0f), Vector3f.UNIT_Y);
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName)
{
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName)
{
}
}
[/java]
[java]
package jme3test;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.shape.Line;
import com.jme3.util.BufferUtils;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import jme3tools.optimize.GeometryBatchFactory;
public final class Utilities
{
/**
- Distance formula from Koen Samyn : http://knol.google.com/k/plane-equation-in-3d#
*
-
@param pointToBeMeasured the Point you want to find its distance from plane.
-
@param anyPointOfPlane any plane’s point e.g plane’s origin
-
@param planeNormal the plane’s Normal at the “anyPointOfPlane”
*/
public static float getDistanceOfPointFromPlane(Vector3f pointToBeMeasured, Vector3f anyPointOfPlane, Vector3f planeNormal)
{
return pointToBeMeasured.subtract(anyPointOfPlane).dot(planeNormal);
}
/**
- Symmetry formula from Koen Samyn : http://knol.google.com/k/mirroring-a-point-on-a-3d-plane#
- Same info on wikipedia : http://en.wikipedia.org/wiki/Reflection_(mathematics)
*
-
@param pointToBeMirrored the Point you want to find its symmetric
-
@param planeOrigin the planeOrigin e.g (0,0,0)
-
@param planeNormal the planeNormal is a vector that points upward from the plane e.g Vector3f.UNIT_Z
*/
public static Vector3f getSummetricPosition(Vector3f pointToBeMirrored, Vector3f planeOrigin, Vector3f planeNormal)
{
if (!planeNormal.isUnitVector())
{
throw new IllegalArgumentException("planeNormal " + planeNormal.toString() + " is not a unit vector");
}
Vector3f symmetricPoint = pointToBeMirrored.subtract(planeNormal.mult(2 * getDistanceOfPointFromPlane(pointToBeMirrored, planeOrigin, planeNormal)));
return symmetricPoint;
}
public static float[] merge(float[] f1, float[] f2)
{
if (f1 == null) return f2;
if (f2 == null) return f1;
float[] f = new float[f1.length + f2.length];
System.arraycopy(f1, 0, f, 0, f1.length);
System.arraycopy(f2, 0, f, f1.length, f2.length);
return f;
}
public static Type getTexCoordType(int i)
{
switch(i)
{
case 0: return Type.TexCoord;
case 1: return Type.TexCoord2;
case 2: return Type.TexCoord3;
case 3: return Type.TexCoord4;
case 4: return Type.TexCoord5;
case 5: return Type.TexCoord6;
case 6: return Type.TexCoord7;
case 7: return Type.TexCoord8;
default: throw new IllegalArgumentException("The specified tex coord type not found");
}
}
public static Vector3f getVector3FromArray(float[] array,int i)
{
return new Vector3f(array[i*3],array[i*3+1],array[i*3+2]);
}
public static Vector2f getVector2FromArray(float[] array,int i)
{
return new Vector2f(array[i*2],array[i*2+1]);
}
public static void setInArray(Vector3f p1, float[] array, int i)
{
array[i*3] = p1.x;
array[i*3+1] = p1.y;
array[i*3+2] = p1.z;
}
public static void setInArray(Vector2f p1, float[] array, int i)
{
array[i*2] = p1.x;
array[i*2+1] = p1.y;
}
public static Node createDebugNormals(Mesh mesh, Material mat)
{
Node debugNormals = new Node();
VertexBuffer vertex = mesh.getBuffer(Type.Position);
float[] vertexArray = BufferUtils.getFloatArray((FloatBuffer) vertex.getData());
VertexBuffer normals = mesh.getBuffer(Type.Normal);
float[] normalArray = BufferUtils.getFloatArray((FloatBuffer) normals.getData());
for (int i = 0; i < vertexArray.length; i += 3)
{
Vector3f p1 = new Vector3f(vertexArray, vertexArray, vertexArray);
Vector3f n1 = new Vector3f(normalArray, normalArray, normalArray);
debugNormals.attachChild(createLine("DebugShowNormalsLine", mat, p1, p1.add(n1.mult(0.1f))));
}
GeometryBatchFactory.optimize(debugNormals);
return debugNormals;
}
public static Geometry createLine(String name, Material mat, Vector3f startPosition, Vector3f endPosition)
{
Line line = new Line(startPosition, endPosition);
Geometry lineGeom = new Geometry(name, line);
lineGeom.setMaterial(mat);
return lineGeom;
}
/**
- Create a new short[] array and populate it with the given ShortBuffer’s
- contents.
*
-
@param buff
-
the ShortBuffer to read from<br />
-
@return a new short array populated from the ShortBuffer
*/
public static short[] getShortArray(ShortBuffer buff)
{
if (buff == null)
{
return null;
}
buff.clear();
short[] inds = new short[buff.limit()];
for (int x = 0; x < inds.length; x++)
{
inds[x] = buff.get();
}
return inds;
}
/**
- Create a new byte[] array and populate it with the given ByteBuffer’s
- contents.
*
-
@param buff
-
the ByteBuffer to read from<br />
-
@return a new byte array populated from the ByteBuffer
/
public static byte[] getByteArray(ByteBuffer buff)
{
if (buff == null)
{
return null;
}
buff.clear();
byte[] inds = new byte[buff.limit()];
for (int x = 0; x < inds.length; x++)
{
inds[x] = buff.get();
}
return inds;
}
}//Utilities
[/java]
[java]
package jme3test;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
import java.nio.ByteBuffer;
import java.util.HashSet;
/* Immutable class that transforms the mesh.
- It is immutable to minimize get/set/construct array operations, and doesnt copy data unless it has to modify it.
- Since it is immutable remember to use the returned value, because the class internal state / method arguments dont change.
-
@toDo Implement "slice along mirror" for symmetry.
-
@toDo Support animation. Bug : Only half of the mesh has animation (the symmetric part has no animation).
-
@toDo ability to apply Transformations to specific points (e.g not affecting the whole mesh but a part of it).
-
@toDo select uvs, vertexes etc based on mouse click.
/
public final class MeshData
{
private float[] vertexArray;
private float[] normalArray;
private float[][] uvArrays = new float[MAX_TEX_COORDS][];
private short[] indexArray;
private float[] bonePositionArray;
private float[] boneNormalArray;
private float[] boneWeightArray;
private byte[] boneIndexArray;
public static final HashSet<Short> SELECT_ALL_INDEXES = null;
public static final HashSet<Short> SELECT_NO_INDEXES = new HashSet<Short>();
public static final int MAX_TEX_COORDS = 8;
/* Creates an empty mesh /
private MeshData()
{
}
/* Creates a mesh without animation, and only 1 tex coord./
public MeshData(float[] vertexArray, float[] normalArray, float[] uvArray, short[] indexArray)
{
this.vertexArray = vertexArray;
this.normalArray = normalArray;
this.uvArrays[0] = uvArray;
this.indexArray = indexArray;
}
/** Creates a mesh with the specified values./
public MeshData(float[] vertexArray, float[] normalArray, float[][] uvArrays, short[] indexArray, float[] bonePositionArray, float[] boneNormalArray, float[] boneWeightArray, byte[] boneIndexArray)
{
this.vertexArray = vertexArray;
this.normalArray = normalArray;
for(int t=0;t<MAX_TEX_COORDS;t++) this.uvArrays[t] = uvArrays[t];
this.indexArray = indexArray;
this.bonePositionArray = bonePositionArray;
this.boneNormalArray = boneNormalArray;
this.boneWeightArray = boneWeightArray;
this.boneIndexArray = boneIndexArray;
}
/** creates MeshData from mesh */
public MeshData(Mesh mesh)
{
vertexArray = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Position));
normalArray = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Normal));
for(int i=0; i < MAX_TEX_COORDS; i++) uvArrays = BufferUtils.getFloatArray(mesh.getFloatBuffer(Utilities.getTexCoordType(i)));
indexArray = Utilities.getShortArray(mesh.getShortBuffer(Type.Index));
bonePositionArray = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.BindPosePosition));
boneNormalArray = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.BindPoseNormal));
boneWeightArray = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.BoneWeight));
VertexBuffer boneIndexBuffer = mesh.getBuffer(Type.BoneIndex);
if (boneIndexBuffer != null) boneIndexArray = (Utilities.getByteArray((ByteBuffer) boneIndexBuffer.getData()));
}
/**Merges 2 meshes into 1. The second’s mesh indexes change to point to their new position (after mesh1’s array).
-
@param shareSkeleton if the resulting mesh will have the skeleton of mesh1, (or mesh2 if mesh1 skeleton is null).
/
public MeshData merge(MeshData mesh2, boolean shareSkeleton)
{
MeshData mesh1 = this;
MeshData resultMesh = new MeshData();
resultMesh.vertexArray = Utilities.merge(mesh1.vertexArray, mesh2.vertexArray);
resultMesh.normalArray = Utilities.merge(mesh1.normalArray, mesh2.normalArray);
for (int i = 0; i < MAX_TEX_COORDS; i++)
{
resultMesh.uvArrays = Utilities.merge(mesh1.uvArrays, mesh2.uvArrays);
}
//make second’s mesh indexes point to their new position (after mesh1’s array)./
resultMesh.indexArray = new short[mesh1.indexArray.length + mesh2.indexArray.length];
System.arraycopy(mesh1.indexArray, 0, resultMesh.indexArray, 0, mesh1.indexArray.length);
for (int i = 0; i < mesh2.indexArray.length; i++)
{
resultMesh.indexArray[mesh1.indexArray.length + i] = (short) (mesh2.indexArray + mesh1.getNumberOfVertexElements());
}
if (mesh1.bonePositionArray != null && mesh1.boneNormalArray != null && mesh1.bonePositionArray != null && mesh1.boneWeightArray != null)
if (shareSkeleton)
{
if (mesh1.bonePositionArray != null) resultMesh.bonePositionArray = mesh1.bonePositionArray;
else resultMesh.bonePositionArray = mesh2.bonePositionArray;
if (mesh1.boneNormalArray != null) resultMesh.boneNormalArray = mesh1.boneNormalArray;
else resultMesh.boneNormalArray = mesh2.boneNormalArray;
if (mesh1.boneWeightArray != null) resultMesh.boneWeightArray = mesh1.boneWeightArray;
else resultMesh.boneWeightArray = mesh2.boneWeightArray;
if (mesh1.boneIndexArray != null) resultMesh.boneIndexArray = mesh1.boneIndexArray;
else resultMesh.boneIndexArray = mesh2.boneIndexArray;
}
else
{
resultMesh.bonePositionArray = Utilities.merge(mesh1.bonePositionArray, mesh2.bonePositionArray);
resultMesh.boneNormalArray = Utilities.merge(mesh1.boneNormalArray, mesh2.boneNormalArray);
resultMesh.boneWeightArray = Utilities.merge(mesh1.boneWeightArray, mesh2.boneWeightArray);
//make second’s mesh bone indexes point to their new position (after mesh1’s array).*/
resultMesh.boneIndexArray = new byte[mesh1.boneIndexArray.length + mesh2.boneIndexArray.length];
System.arraycopy(mesh1.boneIndexArray, 0, resultMesh.boneIndexArray, 0, mesh1.boneIndexArray.length);
for (int i = 0; i < mesh2.boneIndexArray.length; i++)
{
resultMesh.boneIndexArray[mesh1.boneIndexArray.length + i] = (byte) (mesh2.boneIndexArray + mesh1.bonePositionArray.length / 3);
}
}
return resultMesh;
}
/**
-
@param planeOrigin the planeOrigin e.g (0,0,0)
-
@param planeNormal the planeNormal is a vector that points upward from the plane e.g Vector3f.UNIT_Z
/
public MeshData mirror(Vector3f planeOrigin, Vector3f planeNormal, boolean mirrorSkeleton)
{
MeshData mesh = this;
MeshData resultMesh = mesh.shallowClone();
resultMesh.vertexArray = new float[mesh.vertexArray.length];
resultMesh.normalArray = new float[mesh.normalArray.length];
//mirror positions.
for (int i = 0; i < mesh.getNumberOfVertexElements(); i++)
{
Vector3f position = mesh.getVertex(i);
Vector3f summetricPosition = Utilities.getSummetricPosition(position, planeOrigin, planeNormal);
resultMesh.setVertex(summetricPosition, i);
}
//mirror normals.
for (int i = 0; i < mesh.getNumberOfNormalElements(); i++)
{
Vector3f normalPosition = mesh.getNormal(i);
Vector3f summetricNormalPosition = Utilities.getSummetricPosition(normalPosition, planeOrigin, planeNormal);
resultMesh.setNormal(summetricNormalPosition, i);
}
if (mirrorSkeleton && mesh.bonePositionArray != null && mesh.boneNormalArray != null && mesh.bonePositionArray != null && mesh.boneWeightArray != null)
{
resultMesh.bonePositionArray = new float[mesh.bonePositionArray.length];
resultMesh.boneNormalArray = new float[mesh.boneNormalArray.length];
//mirror bone positions.
for (int i = 0; i < mesh.getNumberOfBonePositionElements(); i++)
{
Vector3f bonePosition = mesh.getBonePosition(i);
Vector3f summetricBonePosition = Utilities.getSummetricPosition(bonePosition, planeOrigin, planeNormal);
resultMesh.setBonePosition(summetricBonePosition, i);
}
//mirror bone normals.
for (int i = 0; i < mesh.getNumberOfBoneNormalElements(); i++)
{
Vector3f boneNormalPosition = mesh.getBoneNormal(i);
Vector3f summetricBoneNormalPosition = Utilities.getSummetricPosition(boneNormalPosition, planeOrigin, planeNormal);
resultMesh.setBoneNormal(summetricBoneNormalPosition, i);
}
}
resultMesh = resultMesh.flipIndexes();
return resultMesh;
}
/* Applies symmetry modifier to mesh, and creates a new mesh from the 2 submeshes.
-
@param planeOrigin the planeOrigin e.g (0,0,0)
-
@param planeNormal the planeNormal is a vector that points upward from the plane e.g Vector3f.UNIT_Z
-
@param weldThreshold how much to smooth the vertices near the plane suggested amount from 0.001 until 0.1.
-
Set it to negative number to disable welding.<br />
/
public MeshData createSymmetricMesh(Vector3f planeOrigin, Vector3f planeNormal, float weldThreshold)
{
MeshData mesh = this.shallowClone();
MeshData mirrorMesh = mesh.mirror(planeOrigin, planeNormal, true);
float[] weldedMeshVertexArray = new float[mesh.vertexArray.length];
float[] weldedMirrorMeshVertexArray = new float[mirrorMesh.vertexArray.length];
float[] weldedMeshNormalArray = new float[mesh.normalArray.length];
float[] weldedMirrorMeshNormalArray = new float[mirrorMesh.normalArray.length];
for (int i = 0; i < mesh.getNumberOfIndexElements(); i++)
{
int index = mesh.getIndex(i);
Vector3f p1 = mesh.getVertex(index);
Vector3f mp1 = mirrorMesh.getVertex(index);
Vector3f n1 = mesh.getNormal(index);
Vector3f mn1 = mirrorMesh.getNormal(index);
if (Utilities.getDistanceOfPointFromPlane(p1, planeOrigin, planeNormal) <= weldThreshold)
{
p1 = p1.interpolate(mp1, 0.5f);
n1 = n1.interpolate(mn1, 0.5f);
mp1 = p1;
mn1 = n1;
}//if
Utilities.setInArray(p1, weldedMeshVertexArray, index);
Utilities.setInArray(mp1, weldedMirrorMeshVertexArray, index);
Utilities.setInArray(n1, weldedMeshNormalArray, index);
Utilities.setInArray(mn1, weldedMirrorMeshNormalArray, index);
}
mesh.vertexArray = weldedMeshVertexArray;
mesh.normalArray = weldedMeshNormalArray;
mirrorMesh.vertexArray = weldedMirrorMeshVertexArray;
mirrorMesh.normalArray = weldedMirrorMeshNormalArray;
MeshData resultMesh = mesh.merge(mirrorMesh, false);
return resultMesh;
}
/* Changes the order of indexes, e.g from 1,2,3 it becomes 3,2,1.
- This will allow an invisible mesh to be seen./
public MeshData flipIndexes()
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.indexArray = new short[mesh.indexArray.length];
for (int i = 0; i < mesh.indexArray.length; i += 3)
{
result.indexArray = mesh.indexArray;
result.indexArray = mesh.indexArray;
result.indexArray = mesh.indexArray;
}
return result;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0/
public MeshData flipU(int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = (1 - mesh.uvArrays[TexCoordNumber]) % 1;
result.uvArrays[TexCoordNumber] = mesh.uvArrays[TexCoordNumber] % 1;
}
return result;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public MeshData flipV(int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = mesh.uvArrays[TexCoordNumber] % 1;
result.uvArrays[TexCoordNumber] = (1 - mesh.uvArrays[TexCoordNumber]) % 1;
}
return result;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public MeshData moveUV(Vector2f uvMoveOffset, int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] + uvMoveOffset.x) % 1;
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] + uvMoveOffset.y) % 1;
}
return result;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public MeshData rotateUV(float uvRotateAngle, int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] * FastMath.cos(uvRotateAngle) - mesh.uvArrays[TexCoordNumber] * FastMath.sin(uvRotateAngle)) % 1;
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] * FastMath.sin(uvRotateAngle) + mesh.uvArrays[TexCoordNumber] * FastMath.cos(uvRotateAngle)) % 1;
}
return result;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public MeshData scaleUV(Vector2f uvScaleAmount, int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] * uvScaleAmount.x) % 1;
result.uvArrays[TexCoordNumber] = (mesh.uvArrays[TexCoordNumber] * uvScaleAmount.y) % 1;
}
return result;
}
/** switches u with v.
-
@param TexCoordNumber which array of tex coords to affect. Usual choice : 0
/
public MeshData switchUV(int TexCoordNumber)
{
MeshData mesh = this;
MeshData result = mesh.shallowClone();
result.uvArrays[TexCoordNumber] = new float[mesh.uvArrays[TexCoordNumber].length];
for (int i = 0; i < mesh.uvArrays[TexCoordNumber].length; i += 2)
{
result.uvArrays[TexCoordNumber] = result.uvArrays[TexCoordNumber];
result.uvArrays[TexCoordNumber] = result.uvArrays[TexCoordNumber];
}
return result;
}
/* sets mesh to have the same data as this./
public Mesh save(Mesh mesh)
{
if (vertexArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.Position);
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(vertexArray));
else mesh.setBuffer(Type.Position, 3, vertexArray);
}
if (normalArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.Normal);
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(normalArray));
else mesh.setBuffer(Type.Normal, 3, normalArray);
}
for (int i = 0; i < MAX_TEX_COORDS; i++)
{
if (uvArrays != null)
{
VertexBuffer vb = mesh.getBuffer(Utilities.getTexCoordType(i));
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(uvArrays));
else mesh.setBuffer(Type.TexCoord, 2, uvArrays);
}
}
if (indexArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.Index);
if (vb != null) vb.updateData(BufferUtils.createShortBuffer(indexArray));
else mesh.setBuffer(Type.Index, 3, indexArray);
}
if (bonePositionArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.BindPosePosition);
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(bonePositionArray));
else mesh.setBuffer(Type.BindPosePosition, 3, bonePositionArray);
}
if (boneNormalArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.BindPoseNormal);
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(boneNormalArray));
else mesh.setBuffer(Type.BindPoseNormal, 3, boneNormalArray);
}
if (boneWeightArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.BoneWeight);
if (vb != null) vb.updateData(BufferUtils.createFloatBuffer(boneWeightArray));
else mesh.setBuffer(Type.BoneWeight, 4, boneWeightArray);
}
if (boneIndexArray != null)
{
VertexBuffer vb = mesh.getBuffer(Type.BoneIndex);
if (vb != null) vb.updateData(BufferUtils.createByteBuffer(boneIndexArray));
else mesh.setBuffer(Type.BoneIndex, 4, boneIndexArray);
}
if (vertexArray != null) mesh.updateBound();
return mesh;
}
public Mesh createMesh()
{
Mesh mesh = new Mesh();
return save(mesh);
}
private MeshData shallowClone()
{
return new MeshData(vertexArray, normalArray, uvArrays, indexArray, bonePositionArray, boneNormalArray, boneWeightArray, boneIndexArray);
}
public MeshData setIndexArray(short[] indexArray)
{
MeshData mesh = this.shallowClone();
mesh.indexArray = indexArray;
return mesh;
}
public MeshData setNormalArray(float[] normalArray)
{
MeshData mesh = this.shallowClone();
mesh.normalArray = normalArray;
return mesh;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0/
public MeshData setUvArray(float[] uvArray, int TexCoordNumber)
{
MeshData mesh = this.shallowClone();
mesh.uvArrays[TexCoordNumber] = uvArray;
return mesh;
}
public MeshData setVertexArray(float[] vertexArray)
{
MeshData mesh = this.shallowClone();
mesh.vertexArray = vertexArray;
return mesh;
}
public MeshData setBonePositionArray(float[] bonePositionArray)
{
MeshData mesh = this.shallowClone();
mesh.bonePositionArray = bonePositionArray;
return mesh;
}
public MeshData setBoneNormalArray(float[] boneNormalArray)
{
MeshData mesh = this.shallowClone();
mesh.boneNormalArray = boneNormalArray;
return mesh;
}
public MeshData setBoneWeightArray(float[] boneWeightArray)
{
MeshData mesh = this.shallowClone();
mesh.boneWeightArray = boneWeightArray;
return mesh;
}
public MeshData setBoneIndexArray(byte[] boneIndexArray)
{
MeshData mesh = this.shallowClone();
mesh.boneIndexArray = boneIndexArray;
return mesh;
}
public Vector3f getVertex(int i)
{
return Utilities.getVector3FromArray(vertexArray, i);
}
public Vector3f getNormal(int i)
{
return Utilities.getVector3FromArray(normalArray, i);
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public Vector2f getUv(int i, int TexCoordNumber)
{
return Utilities.getVector2FromArray(uvArrays[TexCoordNumber], i);
}
public short getIndex(int i)
{
return indexArray;
}
public Vector3f getBonePosition(int i)
{
return Utilities.getVector3FromArray(bonePositionArray, i);
}
public Vector3f getBoneNormal(int i)
{
return Utilities.getVector3FromArray(boneNormalArray, i);
}
private void setVertex(Vector3f p, int i)
{
Utilities.setInArray(p, vertexArray, i);
}
private void setNormal(Vector3f p, int i)
{
Utilities.setInArray(p, normalArray, i);
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
private void setUv(Vector2f p, int i, int TexCoordNumber)
{
Utilities.setInArray(p, uvArrays[TexCoordNumber], i);
}
private void setIndex(Short p, int i)
{
indexArray = p;
}
private void setBonePosition(Vector3f p, int i)
{
Utilities.setInArray(p, bonePositionArray, i);
}
private void setBoneNormal(Vector3f p, int i)
{
Utilities.setInArray(p, boneNormalArray, i);
}
public int getNumberOfVertexElements()
{
if (vertexArray == null) return 0;
return vertexArray.length / 3;
}
public int getNumberOfNormalElements()
{
if (normalArray == null) return 0;
return normalArray.length / 3;
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public int getNumberOfUvElements(int TexCoordNumber)
{
if (uvArrays[TexCoordNumber] == null) return 0;
return uvArrays[TexCoordNumber].length / 2;
}
public int getNumberOfIndexElements()
{
if (indexArray == null) return 0;
return indexArray.length;
}
public int getNumberOfBonePositionElements()
{
if (bonePositionArray == null) return 0;
return bonePositionArray.length / 3;
}
public int getNumberOfBoneNormalElements()
{
if (boneNormalArray == null) return 0;
return boneNormalArray.length / 3;
}
public float[] getVertexArrayCopy()
{
if (vertexArray == null) return null;
return vertexArray.clone();
}
public float[] getNormalArrayCopy()
{
if (normalArray == null) return null;
return normalArray.clone();
}
/** @param TexCoordNumber which array of tex coords to affect. Usual choice : 0*/
public float[] getUvArrayCopy(int TexCoordNumber)
{
if (uvArrays[TexCoordNumber] == null) return null;
return uvArrays[TexCoordNumber].clone();
}
public short[] getIndexArrayCopy()
{
if (indexArray == null) return null;
return indexArray.clone();
}
public float[] getBonePositionArrayCopy()
{
if (bonePositionArray == null) return null;
return bonePositionArray.clone();
}
public float[] getBoneNormalArrayCopy()
{
if (boneNormalArray == null) return null;
return boneNormalArray.clone();
}
public float[] getBoneWeightArrayCopy()
{
if (boneWeightArray == null) return null;
return boneWeightArray.clone();
}
public byte[] getBoneIndexArrayCopy()
{
if (boneIndexArray == null) return null;
return boneIndexArray.clone();
}
}
[/java]