Hello to all,
I’ve been annoyed by the update to LWJGL 3.1.2 as all the native links to AWT have been removed. The board effect is that i had no mean with LWJGL3 rendering to display JMonkey application within an AWT / Swing canvas.
I’ve proposed an AppState dedicated to the use of an AWT component as a rendering support for JMonkey. This implementation is inspired by the @javasabr implementation of JavaFX link with JMonkey but does not use other libraries than JDK / JMonkey.
I’ve submitted a pull request (#828) for the AWT rendering related classes and you can test it with the following example:
package sample;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
import com.jme3.app.LegacyApplication;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AWTComponentAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.system.AWTContext;
import com.jme3.system.AWTFrameProcessor;
import com.jme3.system.AWTTaskExecutor;
import com.jme3.system.AppSettings;
/**
* <p>
* This example illustrates the use of an AWT component as the target of a JMonkey rendering.
* </p>
* @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
*
*/
public class AWTComponentRenderingSample {
/**
* Create a JMonkey simple application with basic capabilities.
* @return the created application.
*/
public static LegacyApplication createApplication(AppSettings settings){
final SimpleApplication application = new SimpleApplication() {
protected Geometry player;
Boolean isRunning = true;
@Override
public void update() {
AWTTaskExecutor.getInstance().execute();
super.update();
}
@Override
public void simpleInitApp() {
Box b = new Box(1, 1, 1);
player = new Geometry("Player", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Green);
player.setMaterial(mat);
rootNode.attachChild(player);
initKeys(); // load my custom keybinding
}
/** Custom Keybinding: Map named actions to inputs. */
private void initKeys() {
/** You can map one or several inputs to one named mapping. */
inputManager.addMapping("Pause", new KeyTrigger(keyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE), // spacebar!
new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // left click!
/** Add the named mappings to the action listeners. */
inputManager.addListener(actionListener, "Pause");
inputManager.addListener(analogListener, "Left", "Right", "Rotate");
}
/** Use this listener for KeyDown/KeyUp events */
private final ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("Pause") && !isPressed) {
isRunning = !isRunning;
}
}
};
/** Use this listener for continuous events */
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
if (isRunning) {
if (name.equals("Rotate")) {
player.rotate(0, value, 0);
}
if (name.equals("Right")) {
player.move((new Vector3f(value, 0, 0)));
}
if (name.equals("Left")) {
player.move(new Vector3f(-value, 0, 0));
}
} else {
System.out.println("Press P to unpause.");
}
}
};
};
application.setSettings(settings);
application.setShowSettings(false);
return application;
}
/**
* Run the example.
*/
public void runSample() {
// Create settings that are compatible with AWT rendering
AppSettings settings = new AppSettings(true);
settings.setFullscreen(false);
settings.setCustomRenderer(AWTContext.class);
// Create the component that will support the rendering.
// Any subclass of Component can be used.
Canvas component = new Canvas();
component.setSize(800, 600);
// Create the app state dedicated to AWT component rendering
AWTComponentAppState appState = new AWTComponentAppState(component);
// Create a demo application
LegacyApplication application = createApplication(settings);
// Attach the app state to the application
application.getStateManager().attach(appState);
// Start the application
Thread thread = new Thread() {
@Override
public void run() {
try {
application.start();
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
}
}
};
thread.start();
JFrame frame = new JFrame();
frame.setTitle("JMonkey AWT Component rendering Example");
frame.setSize(new Dimension(800, 600));
frame.setPreferredSize(new Dimension(800, 600));
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(component, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowListener(){
@Override
public void windowOpened(WindowEvent e) {}
@Override
public void windowClosing(WindowEvent e) {
System.out.print("Stopping JME Application");
application.stop(true);
System.out.println(" [OK]");
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {}
@Override
public void windowIconified(WindowEvent e) {}
@Override
public void windowDeiconified(WindowEvent e) {}
@Override
public void windowActivated(WindowEvent e) {}
@Override
public void windowDeactivated(WindowEvent e) {}
});
frame.setVisible(true);
}
/**
* The main method.
* @param args the command line arguments
*/
public static void main(String[] args) {
AWTComponentRenderingSample sample = new AWTComponentRenderingSample();
sample.runSample();
}
}
At this time, the problem is that an AWT binding is present within the sources but i’ts only handle LWJGL2 rendering. The implementation i propose could be used with any underlying rendering.
Maybe you can test this example and say to me if this work is interesting for you.
Thanks a lot,
Julien