1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5
6package com.jme3.bullet.collision.shapes;
7
8import com.bulletphysics.dom.HeightfieldTerrainShape;
9import com.jme3.bullet.util.Converter;
10import com.jme3.export.InputCapsule;
11import com.jme3.export.JmeExporter;
12import com.jme3.export.JmeImporter;
13import com.jme3.export.OutputCapsule;
14import com.jme3.math.FastMath;
15import com.jme3.math.Vector3f;
16import com.jme3.scene.Mesh;
17import 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 */
30public 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