| /* |
| * To change this template, choose Tools | Templates |
| * and open the template in the editor. |
| */ |
| |
| package com.jme3.bullet.collision.shapes; |
| |
| import com.bulletphysics.dom.HeightfieldTerrainShape; |
| import com.jme3.bullet.util.Converter; |
| import com.jme3.export.InputCapsule; |
| import com.jme3.export.JmeExporter; |
| import com.jme3.export.JmeImporter; |
| import com.jme3.export.OutputCapsule; |
| import com.jme3.math.FastMath; |
| import com.jme3.math.Vector3f; |
| import com.jme3.scene.Mesh; |
| import java.io.IOException; |
| |
| /** |
| * Uses Bullet Physics Heightfield terrain collision system. This is MUCH faster |
| * than using a regular mesh. |
| * There are a couple tricks though: |
| * -No rotation or translation is supported. |
| * -The collision bbox must be centered around 0,0,0 with the height above and below the y-axis being |
| * equal on either side. If not, the whole collision box is shifted vertically and things don't collide |
| * as they should. |
| * |
| * @author Brent Owens |
| */ |
| public class HeightfieldCollisionShape extends CollisionShape { |
| |
| //protected HeightfieldTerrainShape heightfieldShape; |
| protected int heightStickWidth; |
| protected int heightStickLength; |
| protected float[] heightfieldData; |
| protected float heightScale; |
| protected float minHeight; |
| protected float maxHeight; |
| protected int upAxis; |
| protected boolean flipQuadEdges; |
| |
| public HeightfieldCollisionShape() { |
| |
| } |
| |
| public HeightfieldCollisionShape(float[] heightmap) { |
| createCollisionHeightfield(heightmap, Vector3f.UNIT_XYZ); |
| } |
| |
| public HeightfieldCollisionShape(float[] heightmap, Vector3f scale) { |
| createCollisionHeightfield(heightmap, scale); |
| } |
| |
| protected void createCollisionHeightfield(float[] heightmap, Vector3f worldScale) { |
| this.scale = worldScale; |
| this.heightScale = 1;//don't change away from 1, we use worldScale instead to scale |
| |
| this.heightfieldData = heightmap; |
| |
| float min = heightfieldData[0]; |
| float max = heightfieldData[0]; |
| // calculate min and max height |
| for (int i=0; i<heightfieldData.length; i++) { |
| if (heightfieldData[i] < min) |
| min = heightfieldData[i]; |
| if (heightfieldData[i] > max) |
| max = heightfieldData[i]; |
| } |
| // we need to center the terrain collision box at 0,0,0 for BulletPhysics. And to do that we need to set the |
| // min and max height to be equal on either side of the y axis, otherwise it gets shifted and collision is incorrect. |
| if (max < 0) |
| max = -min; |
| else { |
| if (Math.abs(max) > Math.abs(min)) |
| min = -max; |
| else |
| max = -min; |
| } |
| this.minHeight = min; |
| this.maxHeight = max; |
| |
| this.upAxis = HeightfieldTerrainShape.YAXIS; |
| this.flipQuadEdges = false; |
| |
| heightStickWidth = (int) FastMath.sqrt(heightfieldData.length); |
| heightStickLength = heightStickWidth; |
| |
| |
| createShape(); |
| } |
| |
| protected void createShape() { |
| |
| HeightfieldTerrainShape shape = new HeightfieldTerrainShape(heightStickWidth, heightStickLength, heightfieldData, heightScale, minHeight, maxHeight, upAxis, flipQuadEdges); |
| shape.setLocalScaling(new javax.vecmath.Vector3f(scale.x, scale.y, scale.z)); |
| cShape = shape; |
| cShape.setLocalScaling(Converter.convert(getScale())); |
| cShape.setMargin(margin); |
| } |
| |
| public Mesh createJmeMesh(){ |
| //TODO return Converter.convert(bulletMesh); |
| return null; |
| } |
| |
| public void write(JmeExporter ex) throws IOException { |
| super.write(ex); |
| OutputCapsule capsule = ex.getCapsule(this); |
| capsule.write(heightStickWidth, "heightStickWidth", 0); |
| capsule.write(heightStickLength, "heightStickLength", 0); |
| capsule.write(heightScale, "heightScale", 0); |
| capsule.write(minHeight, "minHeight", 0); |
| capsule.write(maxHeight, "maxHeight", 0); |
| capsule.write(upAxis, "upAxis", 1); |
| capsule.write(heightfieldData, "heightfieldData", new float[0]); |
| capsule.write(flipQuadEdges, "flipQuadEdges", false); |
| } |
| |
| public void read(JmeImporter im) throws IOException { |
| super.read(im); |
| InputCapsule capsule = im.getCapsule(this); |
| heightStickWidth = capsule.readInt("heightStickWidth", 0); |
| heightStickLength = capsule.readInt("heightStickLength", 0); |
| heightScale = capsule.readFloat("heightScale", 0); |
| minHeight = capsule.readFloat("minHeight", 0); |
| maxHeight = capsule.readFloat("maxHeight", 0); |
| upAxis = capsule.readInt("upAxis", 1); |
| heightfieldData = capsule.readFloatArray("heightfieldData", new float[0]); |
| flipQuadEdges = capsule.readBoolean("flipQuadEdges", false); |
| createShape(); |
| } |
| |
| } |