345 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			345 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package electrosphere.collision;
 | |
| 
 | |
| import java.nio.IntBuffer;
 | |
| 
 | |
| import org.joml.Quaterniond;
 | |
| import org.joml.Vector3d;
 | |
| import org.lwjgl.PointerBuffer;
 | |
| import org.lwjgl.assimp.AIFace;
 | |
| import org.lwjgl.assimp.AIMesh;
 | |
| import org.lwjgl.assimp.AIScene;
 | |
| import org.lwjgl.assimp.AIVector3D;
 | |
| import org.ode4j.math.DMatrix3;
 | |
| import org.ode4j.ode.DBody;
 | |
| import org.ode4j.ode.DBox;
 | |
| import org.ode4j.ode.DCapsule;
 | |
| import org.ode4j.ode.DCylinder;
 | |
| import org.ode4j.ode.DGeom;
 | |
| import org.ode4j.ode.DMass;
 | |
| import org.ode4j.ode.DSphere;
 | |
| import org.ode4j.ode.DTriMesh;
 | |
| 
 | |
| import electrosphere.entity.types.terrain.TerrainChunkData;
 | |
| 
 | |
| /**
 | |
|  * Utilities for creating types of rigid bodies
 | |
|  */
 | |
| public class CollisionBodyCreation {
 | |
| 
 | |
|     //Matrix for correcting initial axis of eg cylinders or capsules
 | |
|     //this rotates by 90 degrees along the x axis
 | |
|     public static final DMatrix3 AXIS_CORRECTION_MATRIX = new DMatrix3(
 | |
|         1.0000000,  0.0000000,  0.0000000,
 | |
|         0.0000000,  0.0000000, -1.0000000,
 | |
|         0.0000000,  1.0000000,  0.0000000
 | |
|     );
 | |
| 
 | |
| 
 | |
|     
 | |
|     //The width of a plane rigid body
 | |
|     //It's really a box under the hood
 | |
|     static final double PLANE_WIDTH = 0.3;
 | |
| 
 | |
|     /**
 | |
|      * Creates a plane DBody. Dimensions x and z control the length and width of the plane;
 | |
|      * @param dimensions The dimensions of the plane
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody createPlaneBody(CollisionEngine collisionEngine, Vector3d dimensions, long categoryBits){
 | |
|         DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions.x,PLANE_WIDTH,dimensions.z),categoryBits);
 | |
|         return collisionEngine.createDBody(geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a cube DBody. Dimensions controlled by the dimensions vector.
 | |
|      * @param collisionEngine The collision engine to create the body inside of
 | |
|      * @param dimensions The dimensions of the cube
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody createCubeBody(CollisionEngine collisionEngine, Vector3d dimensions, long categoryBits){
 | |
|         DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions),categoryBits);
 | |
|         return collisionEngine.createDBody(geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a cylinder DBody. Dimensions controlled by the dimensions vector.
 | |
|      * @param collisionEngine The collision engine to create the body inside of
 | |
|      * @param dimensions The dimensions of the cube
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody createCylinderBody(CollisionEngine collisionEngine, double radius, double length, long categoryBits){
 | |
|         DCylinder geom = collisionEngine.createCylinderGeom(radius,length,categoryBits);
 | |
|         DBody returnBody = collisionEngine.createDBody(geom);
 | |
|         collisionEngine.setOffsetRotation(geom); //ode4j required geom to already be on body before rotating for some reason
 | |
|         return returnBody;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a sphere body in the collision engine
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param radius The radius of the sphere
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody createSphereBody(CollisionEngine collisionEngine, double radius, long categoryBits){
 | |
|         DSphere geom = collisionEngine.createSphereGeom(radius,categoryBits);
 | |
|         return collisionEngine.createDBody(geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a capsule body in the collision engine
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param length The length of the capsule (not including round part at ends)
 | |
|      * @param radius The radius of the sphere
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody createCapsuleBody(CollisionEngine collisionEngine, double length, double radius, long categoryBits){
 | |
|         DCapsule geom = collisionEngine.createCapsuleGeom(radius,length,categoryBits);
 | |
|         return collisionEngine.createDBody(geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a dbody with existing shapes that are provided
 | |
|      * @param collisionEngine the collision engine to create it in
 | |
|      * @param geoms the geometries to attach
 | |
|      * @return the dbody
 | |
|      */
 | |
|     public static DBody createBodyWithShapes(CollisionEngine collisionEngine, DGeom ... geoms){
 | |
|         return collisionEngine.createDBody(geoms);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a sphere shape
 | |
|      * @param collisionEngine the collision engine
 | |
|      * @param radius the radius of the sphere
 | |
|      * @param categoryBits the category bits for the shape
 | |
|      * @return the sphere shape
 | |
|      */
 | |
|     public static DSphere createShapeSphere(CollisionEngine collisionEngine, double radius, long categoryBits){
 | |
|         return collisionEngine.createSphereGeom(radius, categoryBits);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a capsule shape
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param radius the radius of the capsule
 | |
|      * @param length the length of the capsule
 | |
|      * @param categoryBits the category bits for the shape
 | |
|      * @return the capsule shape
 | |
|      */
 | |
|     public static DCapsule createCapsuleShape(CollisionEngine collisionEngine, double radius, double length, long categoryBits){
 | |
|         return collisionEngine.createCapsuleGeom(radius, length, categoryBits);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the mass on the dbody
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param mass The mass value
 | |
|      * @param radius The radius of the cylinder
 | |
|      * @param length The length of the cylinder
 | |
|      * @return The DMass object
 | |
|      */
 | |
|     public static DMass setCylinderMass(CollisionEngine collisionEngine, DBody body, double mass, double radius, double length, Vector3d offset, Quaterniond rotation){
 | |
|         return collisionEngine.createCylinderMass(mass, radius, length, body, offset, rotation);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the mass on the dbody
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param mass The mass value
 | |
|      * @param dims The dimensions of the box
 | |
|      * @return The DMass object
 | |
|      */
 | |
|     public static DMass setBoxMass(CollisionEngine collisionEngine, DBody body, double mass, Vector3d dims, Vector3d offset, Quaterniond rotation){
 | |
|         return collisionEngine.createBoxMass(mass, dims, body, offset, rotation);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the mass on the dbody
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param mass The mass value
 | |
|      * @param radius The radius of the capsule
 | |
|      * @param length The length of the capsule
 | |
|      * @return The DMass object
 | |
|      */
 | |
|     public static DMass setCapsuleMass(CollisionEngine collisionEngine, DBody body, double mass, double radius, double length, Vector3d offset, Quaterniond rotation){
 | |
|         return collisionEngine.createCapsuleMass(mass, radius, length, body, offset, rotation);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the autodisable flags on the body
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param autoDisable true to autodisable, false otherwise
 | |
|      * @param linearThreshold the linear velocity threshold to disable under
 | |
|      * @param angularThreshold the angular velocity threshold to disable under
 | |
|      * @param steps the number of simulation steps below thresholds before autodisable
 | |
|      */
 | |
|     public static void setAutoDisable(CollisionEngine collisionEngine, DBody body, boolean autoDisable, double linearThreshold, double angularThreshold, int steps){
 | |
|         collisionEngine.setAutoDisableFlags(body, autoDisable, linearThreshold, angularThreshold, steps);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the damping for the body
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param linearDamping The linear damping
 | |
|      * @param angularDamping The angular damping
 | |
|      */
 | |
|     public static void setDamping(CollisionEngine collisionEngine, DBody body, double linearDamping, double angularDamping){
 | |
|         collisionEngine.setDamping(body, linearDamping, angularDamping);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the provided body to be a kinematic body (no gravity applied)
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      */
 | |
|     public static void setKinematic(CollisionEngine collisionEngine, DBody body){
 | |
|         collisionEngine.setKinematic(body);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the gravity mode of the body
 | |
|      * @param collisionEngine the collision engine
 | |
|      * @param body the body
 | |
|      * @param gravityMode the gravity mode value
 | |
|      */
 | |
|     public static void setGravityMode(CollisionEngine collisionEngine, DBody body, boolean gravityMode){
 | |
|         collisionEngine.setGravityMode(body, gravityMode);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the offset position of the first geometry in a given body
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param body The body
 | |
|      * @param offsetPosition The position to offset the first geometry by
 | |
|      */
 | |
|     public static void setOffsetPosition(CollisionEngine collisionEngine, DBody body, Vector3d offsetPosition){
 | |
|         collisionEngine.setOffsetPosition(body, offsetPosition);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Removes a geom from a body
 | |
|      * @param collisionEngine the collision engine
 | |
|      * @param body the body
 | |
|      * @param geom the geometry
 | |
|      */
 | |
|     public static void removeShapeFromBody(CollisionEngine collisionEngine, DBody body, DGeom geom){
 | |
|         collisionEngine.removeGeometryFromBody(body, geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Destroys a geometry
 | |
|      * @param collisionEngine The collision engine
 | |
|      * @param geom the geometry
 | |
|      */
 | |
|     public static void destroyShape(CollisionEngine collisionEngine, DGeom geom){
 | |
|         collisionEngine.destroyGeom(geom);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Attaches a geom to a body
 | |
|      * @param collisionEngine the collision engine
 | |
|      * @param body the body
 | |
|      * @param geom the geometry
 | |
|      */
 | |
|     public static void attachGeomToBody(CollisionEngine collisionEngine, DBody body, DGeom geom){
 | |
|         collisionEngine.attachGeomToBody(body, geom);
 | |
|     }
 | |
| 
 | |
|     
 | |
|     /**
 | |
|      * Creates an ode DBody from a terrain chunk data object
 | |
|      * @param data The terrain data
 | |
|      * @return The DBody
 | |
|      */
 | |
|     public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data, long categoryBits){
 | |
|         DBody body = null;
 | |
|         
 | |
|         int elementCount = data.getFaceElements().size();
 | |
| 
 | |
|         float[] vertices = new float[elementCount * 3];
 | |
|         int vertexInserterPos = 0;
 | |
|         int[] indices = new int[elementCount];
 | |
|         int indexInserterPos = 0;
 | |
|         
 | |
|         for(int element : data.getFaceElements()){
 | |
|             //add a new vertex
 | |
|             vertices[vertexInserterPos*3+0] = data.getVertices().get(element*3+0);
 | |
|             vertices[vertexInserterPos*3+1] = data.getVertices().get(element*3+1);
 | |
|             vertices[vertexInserterPos*3+2] = data.getVertices().get(element*3+2);
 | |
|             vertexInserterPos = vertexInserterPos + 1;
 | |
| 
 | |
|             //push faces -- instead of pushing the element directly, instead use the incrementer because we want to draw a new vertex
 | |
|             //there should be no vertex-sharing between triangles. This keeps the meshes from blurring texture/lighting
 | |
|             indices[indexInserterPos] = indexInserterPos;
 | |
|             indexInserterPos++;
 | |
|         }
 | |
| 
 | |
|         //create trimesh
 | |
|         if(vertices.length > 0){
 | |
|             DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices,categoryBits);
 | |
|             body = collisionEngine.createDBody(triMesh);
 | |
|             collisionEngine.setKinematic(body);
 | |
|             collisionEngine.setGravityMode(body, false);
 | |
|         }
 | |
| 
 | |
|         return body;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Generates a body from an AIScene
 | |
|      * @param scene The AIScene to generate a rigid body off of
 | |
|      * @return A rigid body based on the AIScene
 | |
|      */
 | |
|     public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene, long categoryBits){
 | |
| 
 | |
|         DBody body = collisionEngine.createDBody((DGeom[])null);
 | |
| 
 | |
|         PointerBuffer meshesBuffer = scene.mMeshes();
 | |
|         while(meshesBuffer.hasRemaining()){
 | |
|             float[] verts;
 | |
|             int numVertices;
 | |
|             int[] indices;
 | |
|             int numTriangles;
 | |
| 
 | |
|             AIMesh aiMesh = AIMesh.create(meshesBuffer.get());
 | |
|             //allocate array for vertices
 | |
|             numVertices = aiMesh.mNumVertices();
 | |
|             verts = new float[numVertices * 3];
 | |
|             //read vertices
 | |
|             AIVector3D.Buffer vertexBuffer = aiMesh.mVertices();
 | |
|             int vertPos = 0;
 | |
|             while(vertexBuffer.hasRemaining()){
 | |
|                 AIVector3D vector = vertexBuffer.get();
 | |
|                 verts[vertPos+0] = vector.x();
 | |
|                 verts[vertPos+1] = vector.y();
 | |
|                 verts[vertPos+2] = vector.z();
 | |
|                 vertPos = vertPos + 3;
 | |
|             }
 | |
|             numTriangles = aiMesh.mNumFaces();
 | |
|             indices = new int[numTriangles * 3];
 | |
|             int indicesPos = 0;
 | |
|             //read faces
 | |
|             AIFace.Buffer faceBuffer = aiMesh.mFaces();
 | |
|             while(faceBuffer.hasRemaining()){
 | |
|                 AIFace currentFace = faceBuffer.get();
 | |
|                 IntBuffer indexBuffer = currentFace.mIndices();
 | |
|                 while(indexBuffer.hasRemaining()){
 | |
|                     int index = indexBuffer.get();
 | |
|                     indices[indicesPos] = index;
 | |
|                     indicesPos++;
 | |
|                 }
 | |
|             }
 | |
|             DTriMesh meshGeom = collisionEngine.createTrimeshGeom(verts, indices,categoryBits);
 | |
|             meshGeom.setBody(body);
 | |
|         }
 | |
|         
 | |
|         return body;
 | |
|     }
 | |
|     
 | |
| }
 |