Additional features of AcorusDemo

TestAcorusDemo is a test application that demonstrates more built-in features of AcorusDemo:

  • display text on a solid background using an overlay

  • add world axes to a scene and toggle their visibility

  • pause animations and physics without disabling camera motion

  • scale a model to a specified height

  • translate a 3-D model so it rests on the X-Z plane, with its center on the Y axis

  • select among possible values, as in a menu

  • store materials in a "library" and retrieve them by name

Display text on a solid background

An overlay is a rounded rectangle with a solid background color, used to display multiple lines of text.

The concrete Overlay class is a subtype of BaseAppState and inherits its life-cycle hooks:

+ stateAttached(AppStateManager) + update(float) + render(RenderManager) + postRender() + stateDetached(AppStateManager)

Unlike most appstates, overlays are initially disabled. So at a minimum, you need to instantiate the overlay, attach it to your application, and enable it:

Overlay overlay = new Overlay(idString, widthPixels, numStatusLines);
stateManager.attach(overlay);
overlay.setEnabled(true);

Be default, overlays are set in from the upper-left corner of the GUI viewport. However, you can alter the location policy using overlay.setLocationPolicy(newPolicy).

If the policy is anything other than LowerLeft and the viewport is resizable, you should ensure the overlay’s location gets updated on every resize:

@Override
public void onViewPortResize(int newWidth, int newHeight) {
    super.onViewPortResize(newWidth, newHeight);
    overlay.onViewPortResize(newWidth, newHeight);
}

By default, overlay text is white and left-aligned on a black background. However, you can alter these properties:

overlay.setColor(lineIndex, textColor);
overlay.setAlignmentAll(globalAlignment);
overlay.setAlignment(lineIndex, alignment2);
overlay.setBackgroundColor(newColor);

World axes

The world axes are 3 arrows (red for +X, green for +Y, and blue for +Z) whose tails spring from the world origin (0,0,0).

By default, the axes are invisible. However, it’s often helpful to visualize these axes — during a demo, for instance, or while debugging.

AcorusDemo lays the groundwork so that an application can easily bind a hotkey that empowers the user to toggle visibility of the axes:

@Override
public void moreDefaultBindings() {
    InputMode dim = getDefaultInputMode();
    dim.bind(asToggleWorldAxes, KeyInput.KEY_SPACE);
}

Pausing animations

During a demo (or while debugging) one often wants to pause the action for close examination. SimpleApplication provides a setSpeed() interface to alter the global speed of the application. However, setting the speed to zero not only pauses animations, cinematics, and physics; it also freezes camera motion.

AcorusDemo lays the groundwork so that an application can easily bind a hotkey that empowers the user to pause animations (and cinematics and physics) without affecting the built-in FlyByCamera:

@Override
public void moreDefaultBindings() {
    InputMode dim = getDefaultInputMode();
    dim.bind(asTogglePause, KeyInput.KEY_PAUSE);
}

Scaling and centering a 3-D model

AcorusDemo provides a static setCgmHeight() method that scales a 3-D model to a specified height. The model’s height is calculated from the minimal axis-aligned bounding box (AABB) containing its mesh vertices.

AcorusDemo also provides a static centerCgm() method that translates a 3-D model so the center of its base rectangle lies at the world origin. The base rectangle is calculated from the minimal AABB containing its mesh vertices.

Used together, these methods facilitate display of 3-D models without needing to know their coordinates and/or dimensions in advance:

setCgmHeight(model, 2f); // Make the model 2 world units tall.
centerCgm(model);        // Position it above the origin.

Selecting among values

In lieu of mouse-driven menu widgets, AcorusDemo provides a framework for empowering users to interactively select a value from an array of possible values.

The selected value can be displayed in an Overlay that’s updated for every frame:

@Override
public void simpleUpdate(float tpf) {
    super.simpleUpdate(tpf);
    statusOverlay.setText(0, selectedValue);

and hotkeys can be bound to actions that cycle through the possible values:

public void moreDefaultBindings() {
    InputMode dim = getDefaultInputMode();
    dim.bind("next value", KeyInput.KEY_NUMPAD6);
    dim.bind("previous value", KeyInput.KEY_NUMPAD4);
@Override
public void onAction(String actionString, boolean ongoing, float tpf) {
    if (ongoing) {
        switch (actionString) {
            case "next value":
                // Select the next value in the array.
                selectedValue = advanceString(valueArray, selectedValue, +1);
                composer.setCurrentAction(clipName);
                return;
            case "previous value":
                // Select the previous name in the array.
                selectedValue = advanceString(valueArray, selectedValue, -1);
                composer.setCurrentAction(clipName);
                return;

Analogous with advanceString(), methods are also provided to select among float and int values.

A library of materials

JMonkeyEngine has a built-in mechanism to assign names to materials. Acorus goes one step further, implementing a material library that makes it easy to access materials by name.

To add a material to the library, invoke the registerMaterial() method.

To access a material by name, invoke the findMaterial() method.

During startup, Acorus invokes the generateMaterials() method to initialize the library. Applications may override this method, if desired.