1/* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5package com.jme3.bullet.collision.shapes; 6 7import com.jme3.export.InputCapsule; 8import com.jme3.export.JmeExporter; 9import com.jme3.export.JmeImporter; 10import com.jme3.export.OutputCapsule; 11import com.jme3.math.FastMath; 12import com.jme3.math.Vector3f; 13import com.jme3.scene.Mesh; 14import com.jme3.util.BufferUtils; 15import java.io.IOException; 16import java.nio.ByteBuffer; 17import java.util.logging.Level; 18import java.util.logging.Logger; 19 20/** 21 * Uses Bullet Physics Heightfield terrain collision system. This is MUCH faster 22 * than using a regular mesh. 23 * There are a couple tricks though: 24 * -No rotation or translation is supported. 25 * -The collision bbox must be centered around 0,0,0 with the height above and below the y-axis being 26 * equal on either side. If not, the whole collision box is shifted vertically and things don't collide 27 * as they should. 28 * 29 * @author Brent Owens 30 */ 31public class HeightfieldCollisionShape extends CollisionShape { 32 33 protected int heightStickWidth; 34 protected int heightStickLength; 35 protected float[] heightfieldData; 36 protected float heightScale; 37 protected float minHeight; 38 protected float maxHeight; 39 protected int upAxis; 40 protected boolean flipQuadEdges; 41 protected ByteBuffer bbuf; 42// protected FloatBuffer fbuf; 43 44 public HeightfieldCollisionShape() { 45 } 46 47 public HeightfieldCollisionShape(float[] heightmap) { 48 createCollisionHeightfield(heightmap, Vector3f.UNIT_XYZ); 49 } 50 51 public HeightfieldCollisionShape(float[] heightmap, Vector3f scale) { 52 createCollisionHeightfield(heightmap, scale); 53 } 54 55 protected void createCollisionHeightfield(float[] heightmap, Vector3f worldScale) { 56 this.scale = worldScale; 57 this.heightScale = 1;//don't change away from 1, we use worldScale instead to scale 58 59 this.heightfieldData = heightmap; 60 61 float min = heightfieldData[0]; 62 float max = heightfieldData[0]; 63 // calculate min and max height 64 for (int i = 0; i < heightfieldData.length; i++) { 65 if (heightfieldData[i] < min) { 66 min = heightfieldData[i]; 67 } 68 if (heightfieldData[i] > max) { 69 max = heightfieldData[i]; 70 } 71 } 72 // we need to center the terrain collision box at 0,0,0 for BulletPhysics. And to do that we need to set the 73 // min and max height to be equal on either side of the y axis, otherwise it gets shifted and collision is incorrect. 74 if (max < 0) { 75 max = -min; 76 } else { 77 if (Math.abs(max) > Math.abs(min)) { 78 min = -max; 79 } else { 80 max = -min; 81 } 82 } 83 this.minHeight = min; 84 this.maxHeight = max; 85 86 this.upAxis = 1; 87 this.flipQuadEdges = false; 88 89 heightStickWidth = (int) FastMath.sqrt(heightfieldData.length); 90 heightStickLength = heightStickWidth; 91 92 93 createShape(); 94 } 95 96 protected void createShape() { 97 bbuf = BufferUtils.createByteBuffer(heightfieldData.length * 4); 98// fbuf = bbuf.asFloatBuffer();//FloatBuffer.wrap(heightfieldData); 99// fbuf.rewind(); 100// fbuf.put(heightfieldData); 101 for (int i = 0; i < heightfieldData.length; i++) { 102 float f = heightfieldData[i]; 103 bbuf.putFloat(f); 104 } 105// fbuf.rewind(); 106 objectId = createShape(heightStickWidth, heightStickLength, bbuf, heightScale, minHeight, maxHeight, upAxis, flipQuadEdges); 107 Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Created Shape {0}", Long.toHexString(objectId)); 108 setScale(scale); 109 setMargin(margin); 110 } 111 112 private native long createShape(int heightStickWidth, int heightStickLength, ByteBuffer heightfieldData, float heightScale, float minHeight, float maxHeight, int upAxis, boolean flipQuadEdges); 113 114 public Mesh createJmeMesh() { 115 //TODO return Converter.convert(bulletMesh); 116 return null; 117 } 118 119 public void write(JmeExporter ex) throws IOException { 120 super.write(ex); 121 OutputCapsule capsule = ex.getCapsule(this); 122 capsule.write(heightStickWidth, "heightStickWidth", 0); 123 capsule.write(heightStickLength, "heightStickLength", 0); 124 capsule.write(heightScale, "heightScale", 0); 125 capsule.write(minHeight, "minHeight", 0); 126 capsule.write(maxHeight, "maxHeight", 0); 127 capsule.write(upAxis, "upAxis", 1); 128 capsule.write(heightfieldData, "heightfieldData", new float[0]); 129 capsule.write(flipQuadEdges, "flipQuadEdges", false); 130 } 131 132 public void read(JmeImporter im) throws IOException { 133 super.read(im); 134 InputCapsule capsule = im.getCapsule(this); 135 heightStickWidth = capsule.readInt("heightStickWidth", 0); 136 heightStickLength = capsule.readInt("heightStickLength", 0); 137 heightScale = capsule.readFloat("heightScale", 0); 138 minHeight = capsule.readFloat("minHeight", 0); 139 maxHeight = capsule.readFloat("maxHeight", 0); 140 upAxis = capsule.readInt("upAxis", 1); 141 heightfieldData = capsule.readFloatArray("heightfieldData", new float[0]); 142 flipQuadEdges = capsule.readBoolean("flipQuadEdges", false); 143 createShape(); 144 } 145} 146