blob: 9bcd48a61ba22ba16b6e24dd9a9f646cdfdb2aec [file] [log] [blame]
/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jme3test.terrain;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.app.SimpleApplication;
import com.jme3.bounding.BoundingBox;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import jme3tools.converters.ImageToAwt;
/**
* Creates a terrain object and a collision node to go with it. Then
* drops several balls from the sky that collide with the terrain
* and roll around.
* Left click to place a sphere on the ground where the crosshairs intersect the terrain.
* Hit keys 1 or 2 to raise/lower the terrain at that spot.
*
* @author Brent Owens
*/
public class TerrainTestCollision extends SimpleApplication {
TerrainQuad terrain;
Node terrainPhysicsNode;
Material matRock;
Material matWire;
boolean wireframe = false;
protected BitmapText hintText;
PointLight pl;
Geometry lightMdl;
Geometry collisionMarker;
private BulletAppState bulletAppState;
Geometry collisionSphere;
Geometry collisionBox;
Geometry selectedCollisionObject;
public static void main(String[] args) {
TerrainTestCollision app = new TerrainTestCollision();
app.start();
}
@Override
public void initialize() {
super.initialize();
loadHintText();
initCrossHairs();
}
@Override
public void simpleInitApp() {
bulletAppState = new BulletAppState();
bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
stateManager.attach(bulletAppState);
setupKeys();
matRock = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
matRock.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
matRock.setTexture("Tex1", grass);
matRock.setFloat("Tex1Scale", 64f);
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
matRock.setTexture("Tex2", dirt);
matRock.setFloat("Tex2Scale", 32f);
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
rock.setWrap(WrapMode.Repeat);
matRock.setTexture("Tex3", rock);
matRock.setFloat("Tex3Scale", 128f);
matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matWire.getAdditionalRenderState().setWireframe(true);
matWire.setColor("Color", ColorRGBA.Green);
AbstractHeightMap heightmap = null;
try {
heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
heightmap.load();
} catch (Exception e) {
}
terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
terrain.addControl(control);
terrain.setMaterial(matRock);
terrain.setLocalScale(new Vector3f(2, 2, 2));
terrain.setLocked(false); // unlock it so we can edit the height
rootNode.attachChild(terrain);
/**
* Create PhysicsRigidBodyControl for collision
*/
terrain.addControl(new RigidBodyControl(0));
bulletAppState.getPhysicsSpace().addAll(terrain);
// Add 5 physics spheres to the world, with random sizes and positions
// let them drop from the sky
for (int i = 0; i < 5; i++) {
float r = (float) (8 * Math.random());
Geometry sphere = new Geometry("cannonball", new Sphere(10, 10, r));
sphere.setMaterial(matWire);
float x = (float) (20 * Math.random()) - 40; // random position
float y = (float) (20 * Math.random()) - 40; // random position
float z = (float) (20 * Math.random()) - 40; // random position
sphere.setLocalTranslation(new Vector3f(x, 100 + y, z));
sphere.addControl(new RigidBodyControl(new SphereCollisionShape(r), 2));
rootNode.attachChild(sphere);
bulletAppState.getPhysicsSpace().add(sphere);
}
collisionBox = new Geometry("collisionBox", new Box(2, 2, 2));
collisionBox.setModelBound(new BoundingBox());
collisionBox.setLocalTranslation(new Vector3f(20, 95, 30));
collisionBox.setMaterial(matWire);
rootNode.attachChild(collisionBox);
selectedCollisionObject = collisionBox;
DirectionalLight dl = new DirectionalLight();
dl.setDirection(new Vector3f(1, -0.5f, -0.1f).normalizeLocal());
dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f));
rootNode.addLight(dl);
cam.setLocation(new Vector3f(0, 25, -10));
cam.lookAtDirection(new Vector3f(0, -1, 0).normalizeLocal(), Vector3f.UNIT_Y);
}
public void loadHintText() {
hintText = new BitmapText(guiFont, false);
hintText.setSize(guiFont.getCharSet().getRenderedSize());
hintText.setLocalTranslation(0, getCamera().getHeight(), 0);
//hintText.setText("Hit T to switch to wireframe");
hintText.setText("");
guiNode.attachChild(hintText);
}
protected void initCrossHairs() {
//guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+"); // crosshairs
ch.setLocalTranslation( // center
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
guiNode.attachChild(ch);
}
private void setupKeys() {
flyCam.setMoveSpeed(50);
inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
inputManager.addListener(actionListener, "wireframe");
inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H));
inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U));
inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Forwards", new KeyTrigger(KeyInput.KEY_Y));
inputManager.addMapping("Backs", new KeyTrigger(KeyInput.KEY_I));
inputManager.addListener(actionListener, "Lefts");
inputManager.addListener(actionListener, "Rights");
inputManager.addListener(actionListener, "Ups");
inputManager.addListener(actionListener, "Downs");
inputManager.addListener(actionListener, "Forwards");
inputManager.addListener(actionListener, "Backs");
inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, "shoot");
inputManager.addMapping("cameraDown", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addListener(actionListener, "cameraDown");
}
@Override
public void update() {
super.update();
}
private void createCollisionMarker() {
Sphere s = new Sphere(6, 6, 1);
collisionMarker = new Geometry("collisionMarker");
collisionMarker.setMesh(s);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Orange);
collisionMarker.setMaterial(mat);
rootNode.attachChild(collisionMarker);
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String binding, boolean keyPressed, float tpf) {
if (binding.equals("wireframe") && !keyPressed) {
wireframe = !wireframe;
if (!wireframe) {
terrain.setMaterial(matWire);
} else {
terrain.setMaterial(matRock);
}
} else if (binding.equals("shoot") && !keyPressed) {
Vector3f origin = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.0f);
Vector3f direction = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.3f);
direction.subtractLocal(origin).normalizeLocal();
Ray ray = new Ray(origin, direction);
CollisionResults results = new CollisionResults();
int numCollisions = terrain.collideWith(ray, results);
if (numCollisions > 0) {
CollisionResult hit = results.getClosestCollision();
if (collisionMarker == null) {
createCollisionMarker();
}
Vector2f loc = new Vector2f(hit.getContactPoint().x, hit.getContactPoint().z);
float height = terrain.getHeight(loc);
System.out.println("collide " + hit.getContactPoint() + ", height: " + height + ", distance: " + hit.getDistance());
collisionMarker.setLocalTranslation(new Vector3f(hit.getContactPoint().x, height, hit.getContactPoint().z));
}
} else if (binding.equals("cameraDown") && !keyPressed) {
getCamera().lookAtDirection(new Vector3f(0, -1, 0), Vector3f.UNIT_Y);
} else if (binding.equals("Lefts") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(-0.5f, 0, 0);
testCollision(oldLoc);
} else if (binding.equals("Rights") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(0.5f, 0, 0);
testCollision(oldLoc);
} else if (binding.equals("Forwards") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(0, 0, 0.5f);
testCollision(oldLoc);
} else if (binding.equals("Backs") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(0, 0, -0.5f);
testCollision(oldLoc);
} else if (binding.equals("Ups") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(0, 0.5f, 0);
testCollision(oldLoc);
} else if (binding.equals("Downs") && !keyPressed) {
Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone();
selectedCollisionObject.move(0, -0.5f, 0);
testCollision(oldLoc);
}
}
};
private void testCollision(Vector3f oldLoc) {
if (terrain.collideWith(selectedCollisionObject.getWorldBound(), new CollisionResults()) > 0) {
selectedCollisionObject.setLocalTranslation(oldLoc);
}
}
}