Multiple input manager in multiple viewport

Hi everybody,

I would like to know if it is possible to have different inputmanager for multiple view port (for instance, one per viewport).

What I would like to have is a screen splitted in two: in the first one I display a nifty gui by projection on a geometry and on the other one I have the nifty gui that I project with wich I can interact using the mouse.

Thanks.

Why do u think u need 2 input managers for this? Most likely it can be done with just 1 (dont think 2 is even possible, although never really looked), and check which side of the screen was selected. I.e if inputManager.getcursorposition.getx() < screen.width * 0.5, then u clicked the left side, so left viewport can process the click

If you want to swap input mappings, then check out appstates

You only have one operating system on your computer at a time (certainly only one running your application) so then you only have one InputManager.

Wezrule is right. You do not really want to do what you think you want to do.

You’re rigth, it’s not what I want to do… :stuck_out_tongue:

What I want to do is to Have 2 windows (maybe 2 SimpleApps). In the first one the Nifty GUI Overlay will be displayed so I can interact with it with the mouse.
In the second one a geometry using the Nifty GUI as texture (using projection) will be displayed.

The purpose is to interact with the GUI in the first window and to see the interactions replicated in the second window. I want to use this system because we can’t directly interact with a projected NiftyGUI (at least with the mouse) because it’s just a texture.

I made this implementation and it’s working (at least I think ^^) and I post it if somebody is interested. In fact if you see something terrible wrong or weird do not esitate to comment!

Remember that I’m new to Jmonkey engine and maybe I don’t understand all the “implementation details” so to make this example work I just modified/combinedTestNiftyToMesh.java and TestNiftyGui.java.


import render_3d.MyChaseCamera;

import com.jme3.app.SimpleApplication;
import com.jme3.input.ChaseCamera;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.MagFilter;
import com.jme3.texture.Texture.MinFilter;
import com.jme3.texture.Texture2D;
import de.lessvoid.nifty.Nifty;

public class TestNiftyToMesh extends SimpleApplication{

Nifty nifty;
ViewPort niftyViewPort;
MyChaseCamera chaseCam;
Camera cam2;
Texture2D depthTex;
Texture2D tex;

public static void main(String[] args){
	TestNiftyToMesh app = new TestNiftyToMesh();
	app.setShowSettings(false);
	app.start();
}
public void initChaseCamera(){
	// camera initialization
	// Disable the default first-person cam
	flyCam.setEnabled(false);

	// Enable a chase cam
	chaseCam = new MyChaseCamera(cam, inputManager);
	chaseCam.setMinVerticalRotation(-FastMath.PI/2);
	chaseCam.setMaxVerticalRotation(FastMath.PI/2);
	chaseCam.setInvertVerticalAxis(true);
	chaseCam.setRotationSpeed(4f);
	chaseCam.setMinDistance(2f);
	chaseCam.setMaxDistance(30f);
	chaseCam.setDefaultHorizontalRotation(FastMath.PI/2);
	chaseCam.setDefaultVerticalRotation(0f);
	chaseCam.setDefaultDistance(9f);
	chaseCam.setDragToRotate(true);
	cam.setViewPort(0.0f, 1.0f, 0.0f, 1.0f);
	
	//Create overlaping viewport for nifty
	cam2 = cam.clone();
	cam2.setViewPort(0.0f, 1.0f, 0.0f, 1.0f);
	niftyViewPort = renderManager.createMainView(&quot;View of camera #2&quot;, cam2);
	niftyViewPort.setClearFlags(true, true, true);
	niftyViewPort.attachScene(rootNode);
	niftyViewPort.setBackgroundColor(ColorRGBA.Gray);
}

public void simpleInitApp() {
	initChaseCamera();
	
	NiftyJmeDisplay niftyDisplayGui = new NiftyJmeDisplay(assetManager,
			inputManager,
			audioRenderer,
			guiViewPort);
	
	NiftyJmeDisplay niftyDisplayOff = new NiftyJmeDisplay(assetManager,
			inputManager,
			audioRenderer,
			niftyViewPort);
	

	Nifty nifty = niftyDisplayGui.getNifty();
	nifty.fromXml(&quot;Interfaces/HellowJmePerso.xml&quot;, &quot;start&quot;);
	
	
	niftyViewPort.addProcessor(niftyDisplayGui);
	guiViewPort.addProcessor(niftyDisplayGui);

	//Texture init
	depthTex = new Texture2D(1024, 768, Format.Depth);
	FrameBuffer fb = new FrameBuffer(1024, 768, 1);
	fb.setDepthTexture(depthTex);

	tex = new Texture2D(1024, 768, Format.RGBA8);
	tex.setMinFilter(MinFilter.Trilinear);
	tex.setMagFilter(MagFilter.Bilinear);

	fb.setColorTexture(tex);
	niftyViewPort.setClearFlags(true, true, true);
	niftyViewPort.setOutputFrameBuffer(fb);
	

	//Geometry that uses the texture (will be in another SimpleApp)
	Box b = new Box(Vector3f.ZERO, 2, 2, 2);
	Geometry geom = new Geometry(&quot;Box&quot;, b);
	Material mat = new Material(assetManager, &quot;Common/MatDefs/Misc/Unshaded.j3md&quot;);
	mat.setTexture(&quot;ColorMap&quot;, tex);
	geom.setMaterial(mat);
            //scale the texture because it does not fit the shape (dont know why..?)
	geom.getMesh().scaleTextureCoordinates(new Vector2f(0.6f,0.6f));
            rootNode.attachChild(geom);

}

}

Here’s the ChaseCamera I’(m using :


import com.jme3.input.ChaseCamera;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;

public class MyChaseCamera extends ChaseCamera{

	private boolean shiftDown = false;
	private boolean controlDown = false;
	private float moveSpeed = 3f;
	private static Spatial centerTarget = new Geometry("rotationCenter", new Box(Vector3f.ZERO, 0.1f,0.1f,0.1f));

	public MyChaseCamera(Camera cam,  InputManager inputManager) {
		
		super(cam, centerTarget, inputManager);
		registerKeys(inputManager);
	}

	public void setRotationSpeed(float speed){
		this.rotationSpeed = speed;
	}
	

	public void onAction(String name, boolean keyPressed, float tpf) {
		
		if (dragToRotate) {
			if (name.equals(ChaseCamToggleRotate) && enabled && shiftDown) {
				if (keyPressed) {
					canRotate = true;
					if (hideCursorOnRotate) {
						inputManager.setCursorVisible(false);
					}
				} else {
					canRotate = false;
					if (hideCursorOnRotate) {
						inputManager.setCursorVisible(true);
					}
				}
			}
		}
		if (name.equals("shiftDown")){
			shiftDown = (shiftDown) ? false : true;
		}
		if (name.equals("controlDown")){
			controlDown = (controlDown) ? false : true;
		}

	}

	public void onAnalog(String name, float value, float tpf){
		super.onAnalog(name, value, tpf);
		if (name.equals("CAM_UP")){
			System.out.println("up");
			 riseCamera(value);
		}
		else if (name.equals("CAM_DOWN")){
			 riseCamera(-value);
		}
		else if(name.equals("CAM_LEFT")){
			moveCamera(-value, true);
		}
		else if(name.equals("CAM_RIGHT")){
			moveCamera(value, true);
		}
		updateCamera(tpf);
	}
	public void registerKeys(InputManager inputManager) {
		inputManager.addMapping("shiftDown", new KeyTrigger(KeyInput.KEY_LSHIFT));
		inputManager.addMapping("controlDown", new KeyTrigger(KeyInput.KEY_LCONTROL));
		inputManager.addMapping("CAM_UP", new KeyTrigger(KeyInput.KEY_UP));
		inputManager.addMapping("CAM_DOWN", new KeyTrigger(KeyInput.KEY_DOWN));
		inputManager.addMapping("CAM_LEFT", new KeyTrigger(KeyInput.KEY_LEFT));
		inputManager.addMapping("CAM_RIGHT", new KeyTrigger(KeyInput.KEY_RIGHT));
		inputManager.addListener(this, "shiftDown", "controlDown", "CAM_UP", "CAM_DOWN", "CAM_LEFT","CAM_RIGHT");
	}

	public boolean isShiftDown(){
		return shiftDown;
	}

	protected void riseCamera(float value){
		centerTarget.move(0f, value*moveSpeed, 0f);
		
	}

	protected void moveCamera(float value, boolean sideways){
		centerTarget.move(value*moveSpeed, 0f,0f);
	}

}

And there is my XML file defining the Nifty GUI:


<?xml version="1.0" encoding="UTF-8"?>
<nifty>
  <screen id="start" controller="jme3test.niftygui.TestNiftyGui">
    <layer id="layer" backgroundColor="#0000" childLayout="center">
      <panel id="panel" height="30%" width="30%" align="center" valign="center" backgroundColor="#f60f" childLayout="center" visibleToMouse="true">
        <interact onClick="quit()"/>
        <effect>
          <onStartScreen name="move" mode="in" direction="top" length="300" startDelay="0" inherit="true"/>
          <onEndScreen name="move" mode="out" direction="bottom" length="300" startDelay="0" inherit="true"/>
          <onHover name="pulsate" scaleFactor="0.008" startColor="#f600" endColor="#ffff" post="true"/>
        </effect>
        <text id="text" font="aurulent-sans-16.fnt" color="#000f" text="Hello from jME3 perso" align="center" valign="center" />
      </panel>
    </layer>
  </screen>
  <screen id="end">
  </screen>
</nifty>

Fell free to comment if someting is wrong or what… :slight_smile:

oops, in fact something is terrible wrong: I can’t have 2 simple apps running at the same time…!

So do you have an Idea how to have two separate window so I can apply my technique?

@jafa said: oops, in fact something is terrible wrong: I can't have 2 simple apps running at the same time....!

So do you have an Idea how to have two separate window so I can apply my technique?

Do you really mean two separate windows… like OS-level windows? Or do you just mean two GUIs inside your one game window?

It would be great if a cant get 2 different OS windows but I don’t think it’s possible…

So it okay if a have something like that:

image here

The problem with my current implementation is that the gui overlay inputs are responding on the entire window even the gui overlay is only displayed on viewport separate viewport (meaing: a viewport that not cover all the screen)

You mean like in the TestMultipleViewports example?

Yes like that.

But how can I have a nifty gui on one viewport (in overlay mode) and a scene on the other viewport (using projection) without having the entire screen responding to gui events.

Another picture to explain my issue:

image here

In the top figure I have my overlay gui wich is a orange panel centered on the screen with size 30%width and 30%height. It lays on a viewport diefined used setViewPort(0.0f, 1.0f, 0.0f, 1.0f); (so its overlaping the main viewport).

Behind you have the geometry on wich I applied the projection.

The second figure represents the state where my mouse is over the pannel and it is painted in white (it s the behaviour I defined for the panel).

This situation is Okay. But when I resize the viewport on which the overlay is painted using setViewPort(0.5f, 1.0f, 0.5f, 1.0f), the viewport is correcly resized and the overlay occupies 100% of this viewport correctly but the interaction area of the panel stays in the center of the screen! So it seems that the nifty GUI is not resized and not following the dimension of the viewport…

I know this situation is a little bit strange but I hop you can help.

@jafa, it migh be an offtopic, but from my experience: after having much troubles with nifty gui, i just implemented my own gui via standard jmonkeyengine facilities and it works just perfectly. maybe you can try that - coz it really givs you full control over everything (nifty is uncontrollable, it blows up just on any change, imhe). and if you have just simple buttons, implementing it - is a matter of minutes.

1 Like

Yeah, there is t0neg0dGUI and lemur gui both built using standard jme components and available as libraries (plugins?).

It might be worth you investigating them as since they are in the scene graph they should cope with things like viewports much better.

Yes I was thinking of building my own gui system but I just wanted to know i nifty gui provided more functionality… It seems that pretty difficult to achieve what I want using nifty so I will go in this way since I don’t need very complex user interface.

I will do some research about t0neg0dgGUI and lemur thank you for the tip!

Again thanks to everyone for your help! :slight_smile:

@jafa said: Yes I was thinking of building my own gui system but I just wanted to know i nifty gui provided more functionality... It seems that pretty difficult to achieve what I want using nifty so I will go in this way since I don't need very complex user interface.

I will do some research about t0neg0dgGUI and lemur thank you for the tip!

Again thanks to everyone for your help! :slight_smile:

Lemur was even sort of specifically designed for creating custom user interfaces. I mean, it tries to be a nice base for anyone who thinks “I will just write my own UI library”. The default components (Button, Label, etc.) are there to build UIs but also as examples of how one might use the base parts to build fully custom stuff while still taking advantage of some of the best practices I learned writing custom JME UIs over the years.

I just have a look at the example code of lemur and it seems nice a very easy to use! Thanks :wink: