Nifty XML Geometries?

Hello, first time post here,



I’m trying to add a spherical geometry integrated into my HUD via XML as a control (such that the sphere’s properties, such as size and color, can be changed at runtime). Is there any way to do so?



Thanks,



Amtie

My opening post was due to following paragraph in this webpage: Jme3: Advanced tutorial: HUDs


Displaying Geometries in the HUD

It is technically possible to attach Quads and 3D Geometries to the HUD. They show up as flat, static GUI elements. Note that if you use a lit Material, you must add a light to the guiNode. Also remember that size units are pixels in the HUD (a 2-wu cube is displayed tiny 2 pixels wide!).

Yes u can. Make you control an AppState and attach it to the state manager. Then your control will have access to the scenegraph. Read the Nifty Scenarios tutorial in jmp manual (F1).

@glaucomardano said:
Make you control an AppState and attach it to the state manager. Then your control will have access to the scenegraph. Read the Nifty Scenarios tutorial in jmp manual (F1).


The control, you mean the actual control in the XML (like buttons, checkboxes, etc?), or are you referring to the ScreenController? My ScreenController (which controls multiple screens, if thats of any useful information to you) already extends AbstractAppState and is attached to the StateManager like so:

[java]
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app = (SimpleApplication)app;
}[/java]

Is there an online version of the tutorial? I'm using Eclipse with a snapshot release of the jm3 libraries. Unless you're talking about this page:https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:nifty_gui_scenarios

I am also unsure of how to use (or even reference) the sceneGraph you are referring to.

Thanks

No. I meant the control definitions, as yourself said before, you create a control that implements NiftyControl (like the other nifty control definitions as well) and implement AppState on it, and then attach it to the appStateManager. Then you’ll have access to app, and consequently you’ll have access to the scene graph as well. Then you can create your geometries inside your controls and attach them to the root node.

1 Like

Alright, thanks for your help. I’ll try that.

Hello again,



I’m unsure on how to implement all of the inherited methods from AppState and NiftyControl. And whats worse is that the only custom-control tutorial (https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:loading_screen) doesn’t use AppState nor NiftyControl.



I’d have extended LabelControl but apparently that’s been deprecated…



An example of the Java class would be really helpful, if you can spare the time for one. I’d appreciate it. :slight_smile:

Well, you don’t need to implement LabelControl, and actually there’s no tutorial for creating custom control, but there’s a tutorial about creating a progress bar control definition. I learnet how to create my custom controls by checking the nifty source code, then you’ll have to do the same. It’s not needed to implement, LabelControl, implement NiftyControl and put the nifty controls there (label, image…). Tonight I can show you some examples that I have in my game.

Thank you! :smiley:

Have you managed to get the examples yet?

I would look into the nifty-default controls to see how other controls are made.

You will need: a xml control definition (should only contain a panel in your case i assume), A control Controller, BuildMyControl class to build the actual control instance, and a ControlBuilder class to use the java control builder (might not be needed if you only use xml). Again look in default controls for some examples (Button is a simple comprehensible one).



I’m not sure about the AppState method however. I think nifty will try to get an instance of your controller using an empty constructor. So you will have to figure out how to get access to the scenegraph from your controller. (I’m thinking of some static field somewhere but there has to be better solutions)



In your controller bind method, construct the sphere. Check your control’s panel bounds to see where you should put it and attach it to the guiNode. I guess that would work although i never tested. If you need to update it each frame, you can create an effect for this purpose.

@amt222 said:
Have you managed to get the examples yet?


Oh sorry. I forgot xD. Tonight ;).

Here is it ^^



progress-bar.xml



[xml]

<?xml version="1.0" encoding="UTF-8"?>

<nifty-controls>

<controlDefinition name = "progressBar" controller = "kinetrax.nifty.control.progressbar.ProgressBarControl">

<image id="progressBarBorder" filename="Interface/Skins/ProgressBar/border.png" childLayout="horizontal"

imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15">

<image id="progressBarInner" x="0" y="0" filename="$image" width="100%" height="100%"

imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15" childLayout="" valign="bottom">

</image>

</image>

</controlDefinition>

</nifty-controls>

[/xml]



controls.xml



[xml]

<?xml version="1.0" encoding="UTF-8"?>

<nifty-controls>

<useControls filename="Interface/Controls/ProgressBar/progress-bar.xml" />

<useControls filename="Interface/Controls/RhythmTrack/rhythm-track.xml" />

<useControls filename="Interface/Controls/MoveBar/move-bar.xml" />

<useControls filename="Interface/Controls/TrackSelect/track-select.xml" />

<useControls filename="Interface/Controls/Track/track.xml" />

</nifty-controls>

[/xml]



ProgressBar.java



[java]

/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.

    */

    package kinetrax.nifty.control.progressbar;



    import de.lessvoid.nifty.controls.NiftyControl;



    /**

    *
  • @author Glauco Márdano

    /

    public interface ProgressBar extends NiftyControl {



    public void setProgress(float progress);



    public float getProgress();



    public void setDirection(String direction);

    }

    [/java]



    ProgressBarControl.java



    [java]

    /

  • To change this template, choose Tools | Templates
  • and open the template in the editor.

    */

    package kinetrax.nifty.control.progressbar;



    import de.lessvoid.nifty.Nifty;

    import de.lessvoid.nifty.elements.Element;

    import de.lessvoid.nifty.layout.manager.HorizontalLayout;

    import de.lessvoid.nifty.layout.manager.VerticalLayout;

    import de.lessvoid.nifty.screen.Screen;

    import de.lessvoid.nifty.tools.SizeValue;

    import de.lessvoid.xml.xpp3.Attributes;

    import java.util.Properties;

    import kinetrax.nifty.control.KinetraxController;



    /**

    *
  • @author Glauco Márdano

    /

    public class ProgressBarControl extends KinetraxController implements ProgressBar {



    private float progressParam;

    private String directionParam;

    private Element progressBarInner;



    @Override

    public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {

    super.bind(nifty, screen, element, parameter, controlDefinitionAttributes);

    }



    @Override

    protected void initializeParameters(Properties parameter) {

    progressBarInner = getElement().findElementByName("progressBarInner");

    setDirection(parameter.getProperty("direction"));

    setProgress(Float.parseFloat(parameter.getProperty("progress")));

    setChildLayout(directionParam);

    progressBarInner.getParent().layoutElements();

    }



    public void setProgress(float progress) {

    assert progress >= 0f && progress <= 1f : "progress out of range " + progress;

    progressParam = progress;

    final int MIN_WIDTH = 32;

    final int MIN_HEIGHT = 32;

    if (directionParam.equals("horizontal")) {

    int pixelWidth = (int) (MIN_WIDTH + (progressBarInner.getParent().getWidth() - MIN_WIDTH) * progress);

    progressBarInner.setConstraintWidth(new SizeValue(pixelWidth + "px"));

    }

    if (directionParam.equals("vertical")) {

    int pixelHeight = (int) (MIN_HEIGHT + (progressBarInner.getParent().getHeight() - MIN_HEIGHT) * progress);

    progressBarInner.setConstraintHeight(new SizeValue(pixelHeight + "px"));

    }

    progressBarInner.getParent().layoutElements();

    }



    public float getProgress() {

    return progressParam;

    }



    public void setDirection(String direction) {

    assert direction.equals("horizontal") || direction.equals("vertical") : "direction unrecognized " + direction;

    this.directionParam = direction;

    }



    private void setChildLayout(String direction) {

    if (direction.equals("horizontal")) {

    progressBarInner.setLayoutManager(new VerticalLayout());

    }

    if (direction.equals("vertical")) {

    progressBarInner.setLayoutManager(new HorizontalLayout());

    }

    }



    public void update(float tpf) {

    }

    }

    [/java]



    KinetraxController.java



    [java]

    /

  • To change this template, choose Tools | Templates
  • and open the template in the editor.

    */

    package kinetrax.nifty.control;



    import com.jme3.app.Application;

    import com.jme3.app.state.AppState;

    import com.jme3.app.state.AppStateManager;

    import com.jme3.renderer.RenderManager;

    import de.lessvoid.nifty.Nifty;

    import de.lessvoid.nifty.controls.AbstractController;

    import de.lessvoid.nifty.elements.Element;

    import de.lessvoid.nifty.input.NiftyInputEvent;

    import de.lessvoid.nifty.screen.Screen;

    import de.lessvoid.xml.xpp3.Attributes;

    import java.util.Properties;

    import kinetrax.app.KinetraxApp;

    import kinetrax.audio.AudioManager;



    /**

    *
  • @author Glauco Márdano

    */

    public abstract class KinetraxController extends AbstractController implements AppState {



    private Nifty nifty;

    private Screen screen;

    private Element element;

    private Properties parameter;

    private Attributes controlDefinitionAttributes;

    private KinetraxApp app;

    private AppStateManager stateManager;

    private boolean initialized;

    private boolean enabled = true;

    private AudioManager audioManager;



    public KinetraxController() {

    super();

    }



    public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {

    this.nifty = nifty;

    this.screen = screen;

    this.element = element;

    this.parameter = parameter;

    this.controlDefinitionAttributes = controlDefinitionAttributes;

    initializeParameters(parameter);

    }



    protected abstract void initializeParameters(Properties parameter);



    public void onStartScreen() {

    }



    public boolean inputEvent(NiftyInputEvent inputEvent) {

    return false;

    }



    public Attributes getControlDefinitionAttributes() {

    return controlDefinitionAttributes;

    }



    public Nifty getNifty() {

    return nifty;

    }



    public void setNifty(Nifty nifty) {

    this.nifty = nifty;

    }



    @Override

    public Element getElement() {

    return element;

    }



    public Properties getParameter() {

    return parameter;

    }



    public Screen getScreen() {

    return screen;

    }



    public void setScreen(Screen screen) {

    this.screen = screen;

    }



    public void initialize(AppStateManager stateManager, Application app) {

    initialized = true;

    this.app = (KinetraxApp) app;

    this.stateManager = stateManager;

    audioManager = this.app.getAudioManager();

    }



    public void cleanup() {

    initialized = false;

    }



    public boolean isInitialized() {

    return initialized;

    }



    public void stateAttached(AppStateManager stateManager) {

    }



    public void stateDetached(AppStateManager stateManager) {

    }



    public void render(RenderManager rm) {

    }



    public void postRender() {

    }



    @Override

    public void setEnabled(boolean enabled) {

    this.enabled = enabled;

    }



    @Override

    public boolean isEnabled() {

    return enabled;

    }



    public KinetraxApp getApp() {

    return app;

    }



    public AppStateManager getStateManager() {

    return stateManager;

    }



    public void setStateManager(AppStateManager stateManager) {

    this.stateManager = stateManager;

    }



    public AudioManager getAudioManager() {

    return audioManager;

    }

    }

    [/java]



    Usage in StartScreen.xml



    [xml]

    <?xml version="1.0" encoding="UTF-8"?>

    <nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd">

    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <!-- start screen -->

    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <useStyles filename="Interface/Styles/styles.xml" />

    <useControls filename="nifty-default-controls.xml" />

    <useControls filename="Interface/Controls/controls.xml" />

    <screen id="startScreen" controller="kinetrax.nifty.control.screen.start.StartScreenControl">

    <layer id="startLoadingLayer" childLayout="horizontal">

    <panel height="10%"/>

    <panel id = "startLoadingPanel" childLayout="vertical" align="center" valign="center" height="32px" width="80%">

    <control image="Interface/Skins/ProgressBar/inner-orange.png" id="startLoadingBar" name="progressBar" align="center" valign="center" width="100%" height="100%" progress="0f" direction="horizontal" progresstext="Loading…"/>

    </panel>

    <panel height="10%"/>

    </layer>

    <layer id="startLoadingTextLayer" childLayout="horizontal">

    <panel height="10%"/>

    <panel id = "startLoadingTextPanel" childLayout="center" align="center" valign="center" height="32px" width="80%">

    <control id="startLoadingProgressText" text="Loading…" name="label" align="center" valign="center" width="100%"/>

    </panel>

    <panel height="10%"/>

    </layer>

    </screen>

    </nifty>

    [/xml]



    -Regards
1 Like

Thanks! I’ll try it soon.

Hello again,



Is there something missing from what you’ve posted? Because my equivalent of your ProgressBarControl class’ initializeParameters(Properties parameter) method isn’t been called. Oh, I’d just like to mention that I haven’t been working very long with jme or nifty. So I’m not very familiar with the API. However, I have done quite a few of the tutorials, and looked at all relevant tutorials (e.g. the nifty gui ones).



Here’s all the equivalent parts:



geometry-image.xml

[xml]<?xml version=“1.0” encoding=“UTF-8”?>

<nifty-controls>

<controlDefinition name=“geometryImage” controller=“ui.GeometryImageControl”>

<panel id=“panel” backgroundColor="#f00f">



</panel>

</controlDefinition>

</nifty-controls>[/xml]



controls.xml

[xml]<?xml version=“1.0” encoding=“UTF-8”?>

<nifty-controls>

<useControls filename=“Gui/geometry-image.xml” />

</nifty-controls>[/xml]



GeometryImage.java

[java]package ui;



import com.jme3.scene.Geometry;



import de.lessvoid.nifty.controls.NiftyControl;



public interface GeometryImage extends NiftyControl {



public void setGeometry(Geometry geometry);



public Geometry getGeometry();



}[/java]



GeometryImageControl.java

[java]package ui;



import java.util.Properties;



import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Sphere;



import de.lessvoid.nifty.Nifty;

import de.lessvoid.nifty.elements.Element;

import de.lessvoid.nifty.screen.Screen;

import de.lessvoid.xml.xpp3.Attributes;



public class GeometryImageControl extends StarMapController implements GeometryImage {



private Geometry geometry;



private Element geometryImage;



@Override

public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {

super.bind(nifty, screen, element, parameter, controlDefinitionAttributes);

}



@Override

public void update(float arg0) {}



@Override

public void setGeometry(Geometry geometry) {

this.geometry = geometry;

guiNode.attachChild(geometry);



//float x = geometryImage.getConstraintX().getValue(0.5f);

//float y = geometryImage.getConstraintY().getValue(0.5f);

geometry.setLocalTranslation(1, 1, 1);



geometryImage.getParent().layoutElements();

}



@Override

public Geometry getGeometry() {

return geometry;

}



@Override

protected void initializeParameters(Properties parameter) {

System.out.println(“TEST TWO”);

geometryImage = getElement().findElementByName(“geometryImage”);

float size = Float.parseFloat(parameter.getProperty(“size”));



float r = Float.parseFloat(parameter.getProperty(“colorR”));

float g = Float.parseFloat(parameter.getProperty(“colorG”));

float b = Float.parseFloat(parameter.getProperty(“colorB”));

float a = Float.parseFloat(parameter.getProperty(“colorA”));

ColorRGBA color = new ColorRGBA(r, g, b, a);



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, color);



Geometry star = new Geometry(“starImage”, new Sphere(30,30, size));

star.setMaterial(mat);



setGeometry(star);

}



}[/java]



StarMapController.java

[java]package ui;



import java.util.Properties;



import com.jme3.app.Application;

import com.jme3.app.state.AppState;

import com.jme3.app.state.AppStateManager;

import com.jme3.asset.AssetManager;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Node;



import de.lessvoid.nifty.Nifty;

import de.lessvoid.nifty.controls.AbstractController;

import de.lessvoid.nifty.elements.Element;

import de.lessvoid.nifty.input.NiftyInputEvent;

import de.lessvoid.nifty.screen.Screen;

import de.lessvoid.xml.xpp3.Attributes;



public abstract class StarMapController extends AbstractController implements AppState {



private Nifty nifty;

private Screen screen;

private Element element;

private Properties parameter;

private Attributes controlDefinitionAttributes;

private UIView app;

private AppStateManager stateManager;

private boolean initialized;

private boolean enabled = true;



protected Node guiNode;

protected AssetManager assetManager;



public StarMapController() {

super();

System.out.println(“TEST TEST TEST”);

}



@Override

public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {

this.nifty = nifty;

this.screen = screen;

this.element = element;

this.parameter = parameter;

this.controlDefinitionAttributes = controlDefinitionAttributes;

initializeParameters(parameter);

}



protected abstract void initializeParameters(Properties parameter);



@Override

public void onStartScreen() {}



@Override

public boolean inputEvent(NiftyInputEvent inputEvent) {

return false;

}



@Override

public void cleanup() {

initialized = false;

}



@Override

public void initialize(AppStateManager stateManager, Application app) {

initialized = true;

this.app = (UIView)app;

this.assetManager = this.app.getAssetManager(); // this method is not running!

this.stateManager = stateManager; System.out.println(“TEST TEST TEST TEST TEST TEST: " + app.getGuiViewPort().getScenes().get(0).getName());

}



@Override

public boolean isInitialized() {

return initialized;

}



@Override

public void postRender() {}



@Override

public void render(RenderManager rm) {}



@Override

public void stateAttached(AppStateManager stateManager) {}



@Override

public void stateDetached(AppStateManager stateManager) {}



}[/java]



Usage in gui.xml

[xml]<?xml version=“1.0” encoding=“UTF-8”?>

<nifty xmlns=“http://nifty-gui.sourceforge.net/nifty.xsd” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://nifty-gui.sourceforge.net/nifty.xsd http://nifty-gui.sourceforge.net/nifty.xsd”>



<useStyles filename=“nifty-default-styles.xml” />

<useControls filename=“nifty-default-controls.xml” />

<useControls filename=“Gui/controls.xml” />



<screen id=“start” controller=“ui.UIScreenController”>

<layer id=“background” backgroundColor=”#000f" childLayout=“center”>

<image filename=“Textures/background.png”></image>

</layer>

<layer id=“foreground” backgroundColor="#0009" childLayout=“vertical”>



</layer>

</screen>



<screen id=“starview” controller=“ui.UIScreenController”>

<layer id=“background”>

<!-- None -->

</layer>

<layer id=“foreground” childLayout=“horizontal”>

<panel id=“panel_left” width=“250px” height=“400px” childLayout=“vertical” backgroundColor="#0009">



<panel id=“panel_system_name” width=“100%” height=“20px” childLayout=“center”>

<control id=“starLabel” name=“textfield” color="#ffff" text=“123” width=“100%” height=“100%” />

</panel>



<panel id=“panel_main_system_info” width=“100%” height=“120px” childLayout=“horizontal”>



<!-- Planet/star size will range from 80px to 60px (size 10 to size 1) -->

<panel id=“panel_system_star” width=“120px” height=“100%” childLayout=“center”>

<control id=“geometryImage” name=“uiStar” width=“100%” height=“100%” size=“70”

colorR=“255” colorG=“255” colorB=“255” colorA=“127”/>

</panel>

</panel>



</panel>

</layer>

</screen>



</nifty>[/xml]

Well, I can’t see your xml screens referencing their respective screen controllers. Read the manual.

I’m planning on using the same screen controller for multiple screens. I was under the impression that ‘undefined’ controllers would use the same controller as the start screen, but I guess that’s wrong. Fixed that (see the last XML file).



Second, I saw that your StartScreenController has no (apparent) relation to your KinetrixController and subclassed ProgressBarController. Am I supposed to define my screen controller as my equivalents of one of the two above instead?

Well, you have to see my start-screen-control as well.



[java]

/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.

    */

    package kinetrax.nifty.control.screen.start;



    import de.lessvoid.nifty.Nifty;

    import de.lessvoid.nifty.controls.Label;

    import de.lessvoid.nifty.controls.label.LabelControl;

    import de.lessvoid.nifty.screen.Screen;

    import java.util.concurrent.Callable;

    import kinetrax.nifty.control.progressbar.ProgressBar;

    import kinetrax.nifty.control.progressbar.ProgressBarControl;

    import kinetrax.nifty.control.screen.KinetraxScreenController;



    /**

    *
  • @author Glauco Márdano

    */

    public class StartScreenControl extends KinetraxScreenController {



    private ProgressBar loadingBar;

    private Label startLoadingProgressText;

    private boolean load;



    @Override

    public void bind(Nifty nifty, Screen screen) {

    super.bind(nifty, screen);

    loadingBar = screen.findControl("startLoadingBar", ProgressBarControl.class);

    startLoadingProgressText = screen.findControl("startLoadingProgressText", LabelControl.class);

    }



    @Override

    public void onStartScreen() {

    super.onStartScreen();

    loadStuffs();

    }



    @Override

    public void loadStuffs() {

    getApp().getExecutor().submit(new Callable<Object>() {



    public Object call() throws Exception {

    getApp().loadStuffs(loadingBar, startLoadingProgressText);

    load = true;

    return null;

    }

    });

    }



    @Override

    public void update(float tpf) {

    super.update(tpf);

    if (load) {

    goToScreen("mainMenuScreen");

    getNifty().removeScreen("startScreen");

    load = false;

    getStateManager().detach(this);

    }

    }



    public ProgressBar getLoadingBar() {

    return loadingBar;

    }



    public Label getStartLoadingProgressText() {

    return startLoadingProgressText;

    }



    @Override

    public void addInputListener() {

    }



    @Override

    public void removeInputListener() {

    }

    }

    [/java]
1 Like

Sorry, I’ve done all of what you’ve said, but I haven’t managed to get it working. :frowning: It’s a minor thing, but I thought it’d be simple to do.

What’s the bug?