/*
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package com.bulletphysics.collision.shapes;
import com.bulletphysics.linearmath.AabbUtil2;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.VectorUtil;
import cz.advel.stack.Stack;
import javax.vecmath.Matrix3f;
import javax.vecmath.Vector3f;
/**
* Concave triangle mesh abstract class. Use {@link BvhTriangleMeshShape} as concrete
* implementation.
*
* @author jezek2
*/
public abstract class TriangleMeshShape extends ConcaveShape {
protected final Vector3f localAabbMin = new Vector3f();
protected final Vector3f localAabbMax = new Vector3f();
protected StridingMeshInterface meshInterface;
/**
* TriangleMeshShape constructor has been disabled/protected, so that users will not mistakenly use this class.
* Don't use btTriangleMeshShape but use btBvhTriangleMeshShape instead!
*/
protected TriangleMeshShape(StridingMeshInterface meshInterface) {
this.meshInterface = meshInterface;
// JAVA NOTE: moved to BvhTriangleMeshShape
//recalcLocalAabb();
}
public Vector3f localGetSupportingVertex(Vector3f vec, Vector3f out) {
Vector3f tmp = Stack.alloc(Vector3f.class);
Vector3f supportVertex = out;
Transform ident = Stack.alloc(Transform.class);
ident.setIdentity();
SupportVertexCallback supportCallback = new SupportVertexCallback(vec, ident);
Vector3f aabbMax = Stack.alloc(Vector3f.class);
aabbMax.set(1e30f, 1e30f, 1e30f);
tmp.negate(aabbMax);
processAllTriangles(supportCallback, tmp, aabbMax);
supportCallback.getSupportVertexLocal(supportVertex);
return out;
}
public Vector3f localGetSupportingVertexWithoutMargin(Vector3f vec, Vector3f out) {
assert (false);
return localGetSupportingVertex(vec, out);
}
public void recalcLocalAabb() {
for (int i = 0; i < 3; i++) {
Vector3f vec = Stack.alloc(Vector3f.class);
vec.set(0f, 0f, 0f);
VectorUtil.setCoord(vec, i, 1f);
Vector3f tmp = localGetSupportingVertex(vec, Stack.alloc(Vector3f.class));
VectorUtil.setCoord(localAabbMax, i, VectorUtil.getCoord(tmp, i) + collisionMargin);
VectorUtil.setCoord(vec, i, -1f);
localGetSupportingVertex(vec, tmp);
VectorUtil.setCoord(localAabbMin, i, VectorUtil.getCoord(tmp, i) - collisionMargin);
}
}
@Override
public void getAabb(Transform trans, Vector3f aabbMin, Vector3f aabbMax) {
Vector3f tmp = Stack.alloc(Vector3f.class);
Vector3f localHalfExtents = Stack.alloc(Vector3f.class);
localHalfExtents.sub(localAabbMax, localAabbMin);
localHalfExtents.scale(0.5f);
Vector3f localCenter = Stack.alloc(Vector3f.class);
localCenter.add(localAabbMax, localAabbMin);
localCenter.scale(0.5f);
Matrix3f abs_b = Stack.alloc(trans.basis);
MatrixUtil.absolute(abs_b);
Vector3f center = Stack.alloc(localCenter);
trans.transform(center);
Vector3f extent = Stack.alloc(Vector3f.class);
abs_b.getRow(0, tmp);
extent.x = tmp.dot(localHalfExtents);
abs_b.getRow(1, tmp);
extent.y = tmp.dot(localHalfExtents);
abs_b.getRow(2, tmp);
extent.z = tmp.dot(localHalfExtents);
Vector3f margin = Stack.alloc(Vector3f.class);
margin.set(getMargin(), getMargin(), getMargin());
extent.add(margin);
aabbMin.sub(center, extent);
aabbMax.add(center, extent);
}
@Override
public void processAllTriangles(TriangleCallback callback, Vector3f aabbMin, Vector3f aabbMax) {
FilteredCallback filterCallback = new FilteredCallback(callback, aabbMin, aabbMax);
meshInterface.internalProcessAllTriangles(filterCallback, aabbMin, aabbMax);
}
@Override
public void calculateLocalInertia(float mass, Vector3f inertia) {
// moving concave objects not supported
assert (false);
inertia.set(0f, 0f, 0f);
}
@Override
public void setLocalScaling(Vector3f scaling) {
meshInterface.setScaling(scaling);
recalcLocalAabb();
}
@Override
public Vector3f getLocalScaling(Vector3f out) {
return meshInterface.getScaling(out);
}
public StridingMeshInterface getMeshInterface() {
return meshInterface;
}
public Vector3f getLocalAabbMin(Vector3f out) {
out.set(localAabbMin);
return out;
}
public Vector3f getLocalAabbMax(Vector3f out) {
out.set(localAabbMax);
return out;
}
@Override
public String getName() {
return "TRIANGLEMESH";
}
////////////////////////////////////////////////////////////////////////////
private class SupportVertexCallback extends TriangleCallback {
private final Vector3f supportVertexLocal = new Vector3f(0f, 0f, 0f);
public final Transform worldTrans = new Transform();
public float maxDot = -1e30f;
public final Vector3f supportVecLocal = new Vector3f();
public SupportVertexCallback(Vector3f supportVecWorld,Transform trans) {
this.worldTrans.set(trans);
MatrixUtil.transposeTransform(supportVecLocal, supportVecWorld, worldTrans.basis);
}
public void processTriangle(Vector3f[] triangle, int partId, int triangleIndex) {
for (int i = 0; i < 3; i++) {
float dot = supportVecLocal.dot(triangle[i]);
if (dot > maxDot) {
maxDot = dot;
supportVertexLocal.set(triangle[i]);
}
}
}
public Vector3f getSupportVertexWorldSpace(Vector3f out) {
out.set(supportVertexLocal);
worldTrans.transform(out);
return out;
}
public Vector3f getSupportVertexLocal(Vector3f out) {
out.set(supportVertexLocal);
return out;
}
}
private static class FilteredCallback extends InternalTriangleIndexCallback {
public TriangleCallback callback;
public final Vector3f aabbMin = new Vector3f();
public final Vector3f aabbMax = new Vector3f();
public FilteredCallback(TriangleCallback callback, Vector3f aabbMin, Vector3f aabbMax) {
this.callback = callback;
this.aabbMin.set(aabbMin);
this.aabbMax.set(aabbMax);
}
public void internalProcessTriangleIndex(Vector3f[] triangle, int partId, int triangleIndex) {
if (AabbUtil2.testTriangleAgainstAabb2(triangle, aabbMin, aabbMax)) {
// check aabb in triangle-space, before doing this
callback.processTriangle(triangle, partId, triangleIndex);
}
}
}
}