1 package jme3test.terrain; 2 3 import com.jme3.app.SimpleApplication; 4 import com.jme3.app.state.ScreenshotAppState; 5 import com.jme3.asset.plugins.HttpZipLocator; 6 import com.jme3.asset.plugins.ZipLocator; 7 import com.jme3.bullet.BulletAppState; 8 import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; 9 import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; 10 import com.jme3.bullet.control.CharacterControl; 11 import com.jme3.bullet.control.RigidBodyControl; 12 import com.jme3.input.KeyInput; 13 import com.jme3.input.controls.ActionListener; 14 import com.jme3.input.controls.KeyTrigger; 15 import com.jme3.material.Material; 16 import com.jme3.math.ColorRGBA; 17 import com.jme3.math.Vector3f; 18 import com.jme3.terrain.geomipmap.TerrainGrid; 19 import com.jme3.terrain.geomipmap.TerrainGridListener; 20 import com.jme3.terrain.geomipmap.TerrainLodControl; 21 import com.jme3.terrain.geomipmap.TerrainQuad; 22 import com.jme3.terrain.geomipmap.grid.AssetTileLoader; 23 import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; 24 import com.jme3.texture.Texture; 25 import com.jme3.texture.Texture.WrapMode; 26 import java.io.File; 27 28 public class TerrainGridTileLoaderTest extends SimpleApplication { 29 30 private Material mat_terrain; 31 private TerrainGrid terrain; 32 private float grassScale = 64; 33 private float dirtScale = 16; 34 private float rockScale = 128; 35 private boolean usePhysics = true; 36 private boolean physicsAdded = false; 37 38 public static void main(final String[] args) { 39 TerrainGridTileLoaderTest app = new TerrainGridTileLoaderTest(); 40 app.start(); 41 } 42 private CharacterControl player3; 43 44 @Override 45 public void simpleInitApp() { 46 File file = new File("TerrainGridTestData.zip"); 47 if (!file.exists()) { 48 assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/TerrainGridTestData.zip", HttpZipLocator.class); 49 } else { 50 assetManager.registerLocator("TerrainGridTestData.zip", ZipLocator.class); 51 } 52 53 this.flyCam.setMoveSpeed(100f); 54 ScreenshotAppState state = new ScreenshotAppState(); 55 this.stateManager.attach(state); 56 57 // TERRAIN TEXTURE material 58 this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); 59 60 // Parameters to material: 61 // regionXColorMap: X = 1..4 the texture that should be appliad to state X 62 // regionX: a Vector3f containing the following information: 63 // regionX.x: the start height of the region 64 // regionX.y: the end height of the region 65 // regionX.z: the texture scale for the region 66 // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) 67 // slopeColorMap: the texture to be used for cliffs, and steep mountain sites 68 // slopeTileFactor: the texture scale for slopes 69 // terrainSize: the total size of the terrain (used for scaling the texture) 70 // GRASS texture 71 Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); 72 grass.setWrap(WrapMode.Repeat); 73 this.mat_terrain.setTexture("region1ColorMap", grass); 74 this.mat_terrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); 75 76 // DIRT texture 77 Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); 78 dirt.setWrap(WrapMode.Repeat); 79 this.mat_terrain.setTexture("region2ColorMap", dirt); 80 this.mat_terrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); 81 82 // ROCK texture 83 Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); 84 rock.setWrap(WrapMode.Repeat); 85 this.mat_terrain.setTexture("region3ColorMap", rock); 86 this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); 87 88 this.mat_terrain.setTexture("region4ColorMap", rock); 89 this.mat_terrain.setVector3("region4", new Vector3f(198, 260, this.rockScale)); 90 91 this.mat_terrain.setTexture("slopeColorMap", rock); 92 this.mat_terrain.setFloat("slopeTileFactor", 32); 93 94 this.mat_terrain.setFloat("terrainSize", 129); 95 //quad.getHeightMap(), terrain.getLocalScale()), 0 96 AssetTileLoader grid = new AssetTileLoader(assetManager, "testgrid", "TerrainGrid"); 97 this.terrain = new TerrainGrid("terrain", 65, 257, grid); 98 99 this.terrain.setMaterial(this.mat_terrain); 100 this.terrain.setLocalTranslation(0, 0, 0); 101 this.terrain.setLocalScale(2f, 1f, 2f); 102 // try { 103 // BinaryExporter.getInstance().save(terrain, new File("/Users/normenhansen/Documents/Code/jme3/engine/src/test-data/TerrainGrid/" 104 // + "TerrainGrid.j3o")); 105 // } catch (IOException ex) { 106 // Logger.getLogger(TerrainFractalGridTest.class.getName()).log(Level.SEVERE, null, ex); 107 // } 108 109 this.rootNode.attachChild(this.terrain); 110 111 TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera()); 112 control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier 113 this.terrain.addControl(control); 114 115 final BulletAppState bulletAppState = new BulletAppState(); 116 stateManager.attach(bulletAppState); 117 118 this.getCamera().setLocation(new Vector3f(0, 256, 0)); 119 120 this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); 121 122 if (usePhysics) { 123 CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); 124 player3 = new CharacterControl(capsuleShape, 0.5f); 125 player3.setJumpSpeed(20); 126 player3.setFallSpeed(10); 127 player3.setGravity(10); 128 129 player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z)); 130 131 bulletAppState.getPhysicsSpace().add(player3); 132 133 terrain.addListener(new TerrainGridListener() { 134 135 public void gridMoved(Vector3f newCenter) { 136 } 137 138 public Material tileLoaded(Material material, Vector3f cell) { 139 return material; 140 } 141 142 public void tileAttached(Vector3f cell, TerrainQuad quad) { 143 while(quad.getControl(RigidBodyControl.class)!=null){ 144 quad.removeControl(RigidBodyControl.class); 145 } 146 quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()), 0)); 147 bulletAppState.getPhysicsSpace().add(quad); 148 } 149 150 public void tileDetached(Vector3f cell, TerrainQuad quad) { 151 bulletAppState.getPhysicsSpace().remove(quad); 152 quad.removeControl(RigidBodyControl.class); 153 } 154 155 }); 156 } 157 158 this.initKeys(); 159 } 160 161 private void initKeys() { 162 // You can map one or several inputs to one named action 163 this.inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A)); 164 this.inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D)); 165 this.inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W)); 166 this.inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S)); 167 this.inputManager.addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE)); 168 this.inputManager.addListener(this.actionListener, "Lefts"); 169 this.inputManager.addListener(this.actionListener, "Rights"); 170 this.inputManager.addListener(this.actionListener, "Ups"); 171 this.inputManager.addListener(this.actionListener, "Downs"); 172 this.inputManager.addListener(this.actionListener, "Jumps"); 173 } 174 private boolean left; 175 private boolean right; 176 private boolean up; 177 private boolean down; 178 private final ActionListener actionListener = new ActionListener() { 179 180 @Override 181 public void onAction(final String name, final boolean keyPressed, final float tpf) { 182 if (name.equals("Lefts")) { 183 if (keyPressed) { 184 TerrainGridTileLoaderTest.this.left = true; 185 } else { 186 TerrainGridTileLoaderTest.this.left = false; 187 } 188 } else if (name.equals("Rights")) { 189 if (keyPressed) { 190 TerrainGridTileLoaderTest.this.right = true; 191 } else { 192 TerrainGridTileLoaderTest.this.right = false; 193 } 194 } else if (name.equals("Ups")) { 195 if (keyPressed) { 196 TerrainGridTileLoaderTest.this.up = true; 197 } else { 198 TerrainGridTileLoaderTest.this.up = false; 199 } 200 } else if (name.equals("Downs")) { 201 if (keyPressed) { 202 TerrainGridTileLoaderTest.this.down = true; 203 } else { 204 TerrainGridTileLoaderTest.this.down = false; 205 } 206 } else if (name.equals("Jumps")) { 207 TerrainGridTileLoaderTest.this.player3.jump(); 208 } 209 } 210 }; 211 private final Vector3f walkDirection = new Vector3f(); 212 213 @Override 214 public void simpleUpdate(final float tpf) { 215 Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f); 216 Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f); 217 this.walkDirection.set(0, 0, 0); 218 if (this.left) { 219 this.walkDirection.addLocal(camLeft); 220 } 221 if (this.right) { 222 this.walkDirection.addLocal(camLeft.negate()); 223 } 224 if (this.up) { 225 this.walkDirection.addLocal(camDir); 226 } 227 if (this.down) { 228 this.walkDirection.addLocal(camDir.negate()); 229 } 230 231 if (usePhysics) { 232 this.player3.setWalkDirection(this.walkDirection); 233 this.cam.setLocation(this.player3.getPhysicsLocation()); 234 } 235 } 236 } 237