1package jme3test.terrain;
2
3import com.jme3.app.SimpleApplication;
4import com.jme3.app.state.ScreenshotAppState;
5import com.jme3.asset.plugins.HttpZipLocator;
6import com.jme3.asset.plugins.ZipLocator;
7import com.jme3.bullet.BulletAppState;
8import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
9import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
10import com.jme3.bullet.control.CharacterControl;
11import com.jme3.bullet.control.RigidBodyControl;
12import com.jme3.input.KeyInput;
13import com.jme3.input.controls.ActionListener;
14import com.jme3.input.controls.KeyTrigger;
15import com.jme3.light.AmbientLight;
16import com.jme3.light.DirectionalLight;
17import com.jme3.material.Material;
18import com.jme3.math.ColorRGBA;
19import com.jme3.math.Vector2f;
20import com.jme3.math.Vector3f;
21import com.jme3.renderer.Camera;
22import com.jme3.scene.Geometry;
23import com.jme3.scene.Node;
24import com.jme3.scene.Spatial;
25import com.jme3.scene.debug.Arrow;
26import com.jme3.terrain.geomipmap.TerrainGrid;
27import com.jme3.terrain.geomipmap.TerrainGridListener;
28import com.jme3.terrain.geomipmap.TerrainLodControl;
29import com.jme3.terrain.geomipmap.TerrainQuad;
30import com.jme3.terrain.geomipmap.grid.FractalTileLoader;
31import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
32import com.jme3.texture.Texture;
33import com.jme3.texture.Texture.WrapMode;
34import java.io.File;
35import java.util.ArrayList;
36import java.util.List;
37import com.jme3.terrain.noise.ShaderUtils;
38import com.jme3.terrain.noise.basis.FilteredBasis;
39import com.jme3.terrain.noise.filter.IterativeFilter;
40import com.jme3.terrain.noise.filter.OptimizedErode;
41import com.jme3.terrain.noise.filter.PerturbFilter;
42import com.jme3.terrain.noise.filter.SmoothFilter;
43import com.jme3.terrain.noise.fractal.FractalSum;
44import com.jme3.terrain.noise.modulator.NoiseModulator;
45
46public class TerrainGridAlphaMapTest extends SimpleApplication {
47
48    private TerrainGrid terrain;
49    private float grassScale = 64;
50    private float dirtScale = 16;
51    private float rockScale = 128;
52    private boolean usePhysics = false;
53
54    public static void main(final String[] args) {
55        TerrainGridAlphaMapTest app = new TerrainGridAlphaMapTest();
56        app.start();
57    }
58    private CharacterControl player3;
59    private FractalSum base;
60    private PerturbFilter perturb;
61    private OptimizedErode therm;
62    private SmoothFilter smooth;
63    private IterativeFilter iterate;
64    private Material material;
65    private Material matWire;
66
67    @Override
68    public void simpleInitApp() {
69        DirectionalLight sun = new DirectionalLight();
70        sun.setColor(ColorRGBA.White);
71        sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
72        rootNode.addLight(sun);
73
74        AmbientLight al = new AmbientLight();
75        al.setColor(ColorRGBA.White.mult(1.3f));
76        rootNode.addLight(al);
77
78        File file = new File("TerrainGridTestData.zip");
79        if (!file.exists()) {
80            assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/TerrainGridTestData.zip", HttpZipLocator.class);
81        } else {
82            assetManager.registerLocator("TerrainGridTestData.zip", ZipLocator.class);
83        }
84
85        this.flyCam.setMoveSpeed(100f);
86        ScreenshotAppState state = new ScreenshotAppState();
87        this.stateManager.attach(state);
88
89        // TERRAIN TEXTURE material
90        material = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
91        material.setBoolean("useTriPlanarMapping", false);
92        //material.setBoolean("isTerrainGrid", true);
93        material.setFloat("Shininess", 0.0f);
94
95        // GRASS texture
96        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
97        grass.setWrap(WrapMode.Repeat);
98        material.setTexture("DiffuseMap", grass);
99        material.setFloat("DiffuseMap_0_scale", grassScale);
100
101        // DIRT texture
102        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
103        dirt.setWrap(WrapMode.Repeat);
104        material.setTexture("DiffuseMap_1", dirt);
105        material.setFloat("DiffuseMap_1_scale", dirtScale);
106
107        // ROCK texture
108        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
109        rock.setWrap(WrapMode.Repeat);
110        material.setTexture("DiffuseMap_2", rock);
111        material.setFloat("DiffuseMap_2_scale", rockScale);
112
113        // WIREFRAME material
114        matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
115        matWire.getAdditionalRenderState().setWireframe(true);
116        matWire.setColor("Color", ColorRGBA.Green);
117
118        this.base = new FractalSum();
119        this.base.setRoughness(0.7f);
120        this.base.setFrequency(1.0f);
121        this.base.setAmplitude(1.0f);
122        this.base.setLacunarity(2.12f);
123        this.base.setOctaves(8);
124        this.base.setScale(0.02125f);
125        this.base.addModulator(new NoiseModulator() {
126
127            @Override
128            public float value(float... in) {
129                return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1);
130            }
131        });
132
133        FilteredBasis ground = new FilteredBasis(this.base);
134
135        this.perturb = new PerturbFilter();
136        this.perturb.setMagnitude(0.119f);
137
138        this.therm = new OptimizedErode();
139        this.therm.setRadius(5);
140        this.therm.setTalus(0.011f);
141
142        this.smooth = new SmoothFilter();
143        this.smooth.setRadius(1);
144        this.smooth.setEffect(0.7f);
145
146        this.iterate = new IterativeFilter();
147        this.iterate.addPreFilter(this.perturb);
148        this.iterate.addPostFilter(this.smooth);
149        this.iterate.setFilter(this.therm);
150        this.iterate.setIterations(1);
151
152        ground.addPreFilter(this.iterate);
153
154        this.terrain = new TerrainGrid("terrain", 33, 257, new FractalTileLoader(ground, 256));
155        this.terrain.setMaterial(this.material);
156
157        this.terrain.setLocalTranslation(0, 0, 0);
158        this.terrain.setLocalScale(2f, 1f, 2f);
159        this.rootNode.attachChild(this.terrain);
160
161        List<Camera> cameras = new ArrayList<Camera>();
162        cameras.add(this.getCamera());
163        TerrainLodControl control = new TerrainLodControl(this.terrain, cameras);
164        control.setLodCalculator( new DistanceLodCalculator(33, 2.7f) ); // patch size, and a multiplier
165        this.terrain.addControl(control);
166
167        final BulletAppState bulletAppState = new BulletAppState();
168        stateManager.attach(bulletAppState);
169
170
171        this.getCamera().setLocation(new Vector3f(0, 256, 0));
172
173        this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
174
175        if (usePhysics) {
176            CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1);
177            player3 = new CharacterControl(capsuleShape, 0.5f);
178            player3.setJumpSpeed(20);
179            player3.setFallSpeed(10);
180            player3.setGravity(10);
181
182            player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z));
183
184            bulletAppState.getPhysicsSpace().add(player3);
185
186        }
187        terrain.addListener(new TerrainGridListener() {
188
189            public void gridMoved(Vector3f newCenter) {
190            }
191
192            public void tileAttached(Vector3f cell, TerrainQuad quad) {
193                Texture alpha = null;
194                try {
195                    alpha = assetManager.loadTexture("TerrainAlphaTest/alpha_" + (int)cell.x+ "_" + (int)cell.z + ".png");
196                } catch (Exception e) {
197                    alpha = assetManager.loadTexture("TerrainAlphaTest/alpha_default.png");
198                }
199                quad.getMaterial().setTexture("AlphaMap", alpha);
200                if (usePhysics) {
201                    quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()), 0));
202                    bulletAppState.getPhysicsSpace().add(quad);
203                }
204                updateMarkerElevations();
205            }
206
207            public void tileDetached(Vector3f cell, TerrainQuad quad) {
208                if (usePhysics) {
209                    bulletAppState.getPhysicsSpace().remove(quad);
210                    quad.removeControl(RigidBodyControl.class);
211                }
212                updateMarkerElevations();
213            }
214        });
215
216        this.initKeys();
217
218        markers = new Node();
219        rootNode.attachChild(markers);
220        createMarkerPoints(1);
221    }
222
223    Node markers;
224
225
226    private void createMarkerPoints(float count) {
227        Node center = createAxisMarker(10);
228        markers.attachChild(center);
229
230        float xS = (count-1)*terrain.getTerrainSize() - (terrain.getTerrainSize()/2);
231        float zS = (count-1)*terrain.getTerrainSize() - (terrain.getTerrainSize()/2);
232        float xSi = xS;
233        float zSi = zS;
234        for (int x=0; x<count*2; x++) {
235            for (int z=0; z<count*2; z++) {
236                Node m = createAxisMarker(5);
237                m.setLocalTranslation(xSi, 0, zSi);
238                markers.attachChild(m);
239                zSi += terrain.getTerrainSize();
240            }
241            zSi = zS;
242            xSi += terrain.getTerrainSize();
243        }
244    }
245
246    private void updateMarkerElevations() {
247        for (Spatial s : markers.getChildren()) {
248            float h = terrain.getHeight(new Vector2f(s.getLocalTranslation().x, s.getLocalTranslation().z));
249            s.setLocalTranslation(s.getLocalTranslation().x, h+1, s.getLocalTranslation().z);
250        }
251    }
252
253    private void initKeys() {
254        // You can map one or several inputs to one named action
255        this.inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
256        this.inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
257        this.inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
258        this.inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
259        this.inputManager.addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE));
260        this.inputManager.addListener(this.actionListener, "Lefts");
261        this.inputManager.addListener(this.actionListener, "Rights");
262        this.inputManager.addListener(this.actionListener, "Ups");
263        this.inputManager.addListener(this.actionListener, "Downs");
264        this.inputManager.addListener(this.actionListener, "Jumps");
265    }
266    private boolean left;
267    private boolean right;
268    private boolean up;
269    private boolean down;
270    private final ActionListener actionListener = new ActionListener() {
271
272        @Override
273        public void onAction(final String name, final boolean keyPressed, final float tpf) {
274            if (name.equals("Lefts")) {
275                if (keyPressed) {
276                    TerrainGridAlphaMapTest.this.left = true;
277                } else {
278                    TerrainGridAlphaMapTest.this.left = false;
279                }
280            } else if (name.equals("Rights")) {
281                if (keyPressed) {
282                    TerrainGridAlphaMapTest.this.right = true;
283                } else {
284                    TerrainGridAlphaMapTest.this.right = false;
285                }
286            } else if (name.equals("Ups")) {
287                if (keyPressed) {
288                    TerrainGridAlphaMapTest.this.up = true;
289                } else {
290                    TerrainGridAlphaMapTest.this.up = false;
291                }
292            } else if (name.equals("Downs")) {
293                if (keyPressed) {
294                    TerrainGridAlphaMapTest.this.down = true;
295                } else {
296                    TerrainGridAlphaMapTest.this.down = false;
297                }
298            } else if (name.equals("Jumps")) {
299                TerrainGridAlphaMapTest.this.player3.jump();
300            }
301        }
302    };
303    private final Vector3f walkDirection = new Vector3f();
304
305    @Override
306    public void simpleUpdate(final float tpf) {
307        Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f);
308        Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f);
309        this.walkDirection.set(0, 0, 0);
310        if (this.left) {
311            this.walkDirection.addLocal(camLeft);
312        }
313        if (this.right) {
314            this.walkDirection.addLocal(camLeft.negate());
315        }
316        if (this.up) {
317            this.walkDirection.addLocal(camDir);
318        }
319        if (this.down) {
320            this.walkDirection.addLocal(camDir.negate());
321        }
322
323        if (usePhysics) {
324            this.player3.setWalkDirection(this.walkDirection);
325            this.cam.setLocation(this.player3.getPhysicsLocation());
326        }
327    }
328
329    protected Node createAxisMarker(float arrowSize) {
330
331        Material redMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
332        redMat.getAdditionalRenderState().setWireframe(true);
333        redMat.setColor("Color", ColorRGBA.Red);
334
335        Material greenMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
336        greenMat.getAdditionalRenderState().setWireframe(true);
337        greenMat.setColor("Color", ColorRGBA.Green);
338
339        Material blueMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
340        blueMat.getAdditionalRenderState().setWireframe(true);
341        blueMat.setColor("Color", ColorRGBA.Blue);
342
343        Node axis = new Node();
344
345        // create arrows
346        Geometry arrowX = new Geometry("arrowX", new Arrow(new Vector3f(arrowSize, 0, 0)));
347        arrowX.setMaterial(redMat);
348        Geometry arrowY = new Geometry("arrowY", new Arrow(new Vector3f(0, arrowSize, 0)));
349        arrowY.setMaterial(greenMat);
350        Geometry arrowZ = new Geometry("arrowZ", new Arrow(new Vector3f(0, 0, arrowSize)));
351        arrowZ.setMaterial(blueMat);
352        axis.attachChild(arrowX);
353        axis.attachChild(arrowY);
354        axis.attachChild(arrowZ);
355
356        //axis.setModelBound(new BoundingBox());
357        return axis;
358    }
359}
360