@Override
    public void simpleInitApp() {
        test = this;
        getCamera().setLocation(new Vector3f(40, 30, 160));
        getCamera().lookAt(new Vector3f(40, -5, 0), Vector3f.UNIT_Y);
        getFlyByCamera().setMoveSpeed(25);

        DirectionalLight dl = new DirectionalLight();
        dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
        dl.setColor(ColorRGBA.Green);
        rootNode.addLight(dl);

        //Setup test instructions
        guiNode = getGuiNode();
        BitmapFont font = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText[] testInfo = new BitmapText[2];
        testInfo[0] = new BitmapText(font);
        testInfo[1] = new BitmapText(font);
        timeElapsedTxt = new BitmapText(font);
        solverNumIterationsTxt = new BitmapText(font);
        testScale = new BitmapText(font);

        float lineHeight = testInfo[0].getLineHeight();
        testInfo[0].setText("Camera move:W/A/S/D/Q/Z     Solver iterations: 1=10, 2=20, 3=30");
        testInfo[0].setLocalTranslation(5, test.settings.getHeight(), 0);
        guiNode.attachChild(testInfo[0]);
        testInfo[1].setText("P: Toggle pause     Inc/Dec object scale: +, -     Space: Restart test");
        testInfo[1].setLocalTranslation(5, test.settings.getHeight() - lineHeight, 0);
        guiNode.attachChild(testInfo[1]);

        timeElapsedTxt.setLocalTranslation(202, lineHeight * 1, 0);
        guiNode.attachChild(timeElapsedTxt);
        solverNumIterationsTxt.setLocalTranslation(202, lineHeight * 2, 0);
        guiNode.attachChild(solverNumIterationsTxt);
        testScale.setLocalTranslation(202, lineHeight * 3, 0);
        guiNode.attachChild(testScale);

        //Setup interactive test controls
        inputManager.addMapping("restart", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener((ActionListener) (String name, boolean isPressed, float tpf) -> {
            restart = true;
        }, "restart");

        inputManager.addMapping("pause", new KeyTrigger(KeyInput.KEY_P));
        inputManager.addListener((ActionListener) (String name, boolean isPressed, float tpf) -> {
            if (!isPressed) {
                return;
            }
            bulletAppState.setSpeed(bulletAppState.getSpeed() > 0.1 ? 0 : 1);
        }, "pause");

        inputManager.addMapping("1", new KeyTrigger(KeyInput.KEY_1));
        inputManager.addMapping("2", new KeyTrigger(KeyInput.KEY_2));
        inputManager.addMapping("3", new KeyTrigger(KeyInput.KEY_3));
        inputManager.addMapping("+", new KeyTrigger(KeyInput.KEY_ADD), new KeyTrigger(KeyInput.KEY_EQUALS));
        inputManager.addMapping("-", new KeyTrigger(KeyInput.KEY_SUBTRACT), new KeyTrigger(KeyInput.KEY_MINUS));
        inputManager.addListener((ActionListener) (String name, boolean isPressed, float tpf) -> {
            if (!isPressed) {
                return;
            }
            switch (name) {
                case "1":
                    solverNumIterations = 10;
                    break;
                case "2":
                    solverNumIterations = 20;
                    break;
                case "3":
                    solverNumIterations = 30;
                    break;
                case "+":
                    scaleMod += scaleMod < 1.9f ? 0.1f : 0;
                    break;
                case "-":
                    scaleMod -= scaleMod > 0.5f ? 0.1f : 0;
                    break;
            }
            restart = true;
        }, "1", "2", "3", "+", "-");

        initializeNewTest();
    }
This test demonstrates various GImpactCollisionShapes colliding against two identical curved surfaces. The
left surface is a MeshCollisionShape, right surface is another GImpactCollisionShape. An ideal result is
for all objects to land and change to a blue colored mesh indicating they are inactive. Falling through the
floor, or never going inactive (bouncing forever) are failure conditions.
<p>
Observations as of June 2019 (JME v3.3.0-alpha2):
<ol>
<li>
With default starting parameters, Native Bullet should pass the test parameters above. JBullet fails due to
the rocket/MeshCollisionShape never going inactive.
</li>
<li>
Native Bullet behaves better than JBullet. JBullet sometimes allows objects to "gain too much energy" after
a collision, such as the rocket or teapot. Native also does this, to a lesser degree. This generally
appears to happen at larger object scales.
</li>
<li>
JBullet allows some objects to get "stuck" inside the floor, which usually results in a fall-through
eventually, generally a larger scales for this test.
</li>
<li>
Some shapes such as PQTorus and signpost never go inactive at larger scales for both Native and JBullet (test
at 1.5 and 1.9 scale)
</li>
</ol>

@author lou
jme3-examples/src/main/java/jme3test/bullet/shape/TestGimpactShape.java