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