diff --git a/jme3-desktop/src/main/java/com/jme3/app/state/AWTComponentAppState.java b/jme3-desktop/src/main/java/com/jme3/app/state/AWTComponentAppState.java index 4a24f04958..435ecb8e8f 100644 --- a/jme3-desktop/src/main/java/com/jme3/app/state/AWTComponentAppState.java +++ b/jme3-desktop/src/main/java/com/jme3/app/state/AWTComponentAppState.java @@ -35,9 +35,8 @@ import com.jme3.app.Application; import com.jme3.app.state.AbstractAppState; -import com.jme3.app.state.AppStateManager; -import com.jme3.system.AWTFrameProcessor; -import com.jme3.system.AWTTaskExecutor; +import com.jme3.system.awt.AWTFrameProcessor; +import com.jme3.system.awt.AWTTaskExecutor; /** * An app state dedicated to the rendering of a JMonkey application within an AWT component. @@ -53,6 +52,8 @@ public class AWTComponentAppState extends AbstractAppState { private AWTFrameProcessor.TransferMode transferMode = AWTFrameProcessor.TransferMode.ON_CHANGES; + private boolean flipY = true; + @Override public void initialize(AppStateManager stateManager, Application app) { super.initialize(stateManager, app); @@ -61,6 +62,7 @@ public void initialize(AppStateManager stateManager, Application app) { @Override public void stateAttached(final AppStateManager stateManager) { processor = new AWTFrameProcessor(); + processor.setFlipY(flipY); processor.setTransferMode(transferMode); AWTTaskExecutor.getInstance().addToExecute(new Runnable() { @@ -116,20 +118,44 @@ public void setComponent(Component component) { } /** - * Get the {@link com.jme3.system.AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. - * @return the {@link com.jme3.system.AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. - * @see #setTransferMode(com.jme3.system.AWTFrameProcessor.TransferMode) + * Get the {@link AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. + * @return the {@link AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. + * @see #setTransferMode(AWTFrameProcessor.TransferMode) */ public AWTFrameProcessor.TransferMode getTransferMode(){ return transferMode; } /** - * Set the {@link com.jme3.system.AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. - * @param mode the {@link com.jme3.system.AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. + * Set the {@link AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. + * @param mode the {@link AWTFrameProcessor.TransferMode transfer mode} that is used by the underlying frame processor. * @see #getTransferMode() */ public void setTransferMode(AWTFrameProcessor.TransferMode mode) { this.transferMode = mode; } + + + /** + * Is the rendered image is Y flipped. + * @return true if the rendered image has to be Y flipped and false otherwise + * @see #setFlipY(boolean) + */ + public boolean isFlipY() { + return flipY; + } + + /** + * Set if the rendered image has to be Y flipped. + * @param flip true if the rendered image has to be Y flipped and false otherwise + * @see #isFlipY() + */ + public void setFlipY(boolean flip) { + + if (processor != null) { + processor.setFlipY(flip); + } + + this.flipY = flip; + } } diff --git a/jme3-desktop/src/main/java/com/jme3/input/AWTInput.java b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInput.java similarity index 91% rename from jme3-desktop/src/main/java/com/jme3/input/AWTInput.java rename to jme3-desktop/src/main/java/com/jme3/input/awt/AWTInput.java index cceab1d6e3..a316bfce4f 100644 --- a/jme3-desktop/src/main/java/com/jme3/input/AWTInput.java +++ b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInput.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.input; +package com.jme3.input.awt; import java.awt.Component; import java.util.Objects; @@ -37,8 +37,8 @@ import com.jme3.app.Application; import com.jme3.input.Input; import com.jme3.input.RawInputListener; -import com.jme3.system.AWTContext; -import com.jme3.system.AWTTaskExecutor; +import com.jme3.system.JmeContext; +import com.jme3.system.awt.AWTTaskExecutor; /** * The implementation of the {@link Input} dedicated to AWT {@link Component component}. @@ -55,7 +55,7 @@ public class AWTInput implements Input { /** * The context. */ - protected final AWTContext context; + protected final JmeContext context; /** * The raw listener. @@ -77,7 +77,11 @@ public class AWTInput implements Input { */ protected boolean initialized; - public AWTInput(final AWTContext context) { + public AWTInput() { + this.context = null; + } + + public AWTInput(final JmeContext context) { this.context = context; } @@ -102,7 +106,7 @@ protected void initializeImpl() { @Override public void update() { - if (!context.isRenderable()) return; + if ((context == null) || (!context.isRenderable())) return; updateImpl(); } diff --git a/jme3-desktop/src/main/java/com/jme3/input/AWTKeyInput.java b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputKeyboard.java similarity index 96% rename from jme3-desktop/src/main/java/com/jme3/input/AWTKeyInput.java rename to jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputKeyboard.java index 0280d8aedb..583172eca2 100644 --- a/jme3-desktop/src/main/java/com/jme3/input/AWTKeyInput.java +++ b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputKeyboard.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.input; +package com.jme3.input.awt; import java.awt.Component; import java.awt.event.KeyEvent; @@ -40,7 +40,7 @@ import com.jme3.input.KeyInput; import com.jme3.input.event.KeyInputEvent; -import com.jme3.system.AWTContext; +import com.jme3.system.JmeContext; /** @@ -51,7 +51,7 @@ * @author Julien Seinturier - COMEX SA - http://www.seinturier.fr * @author Alexander Brui (JavaSaBr) */ -public class AWTKeyInput extends AWTInput implements KeyInput, KeyListener{ +public class AWTInputKeyboard extends AWTInput implements KeyInput, KeyListener{ private static final Map KEY_CODE_TO_JME = new HashMap<>(); @@ -168,7 +168,12 @@ public class AWTKeyInput extends AWTInput implements KeyInput, KeyListener{ private final LinkedList keyInputEvents; - public AWTKeyInput(AWTContext context) { + public AWTInputKeyboard() { + super(); + keyInputEvents = new LinkedList(); + } + + public AWTInputKeyboard(JmeContext context) { super(context); keyInputEvents = new LinkedList(); } @@ -219,19 +224,16 @@ private int convertKeyCode(int keyCode) { @Override public void keyTyped(KeyEvent e) { - System.out.println("Key typed "+e.getKeyChar()); //onKeyEvent(e, false); } @Override public void keyPressed(KeyEvent e) { - System.out.println("Key pressed "+e.getKeyChar()); onKeyEvent(e, true); } @Override public void keyReleased(KeyEvent e) { - System.out.println("Key released "+e.getKeyChar()); onKeyEvent(e, false); } } diff --git a/jme3-desktop/src/main/java/com/jme3/input/AWTMouseInput.java b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputMouse.java similarity index 65% rename from jme3-desktop/src/main/java/com/jme3/input/AWTMouseInput.java rename to jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputMouse.java index 72b75a5d38..e4a9db4b83 100644 --- a/jme3-desktop/src/main/java/com/jme3/input/AWTMouseInput.java +++ b/jme3-desktop/src/main/java/com/jme3/input/awt/AWTInputMouse.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.input; +package com.jme3.input.awt; import java.awt.Component; import java.awt.event.MouseEvent; @@ -45,7 +45,8 @@ import com.jme3.input.MouseInput; import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseMotionEvent; -import com.jme3.system.AWTContext; +import com.jme3.system.JmeContext; +import com.jme3.system.awt.AWTContext; /** * The implementation of the {@link MouseInput} dedicated to AWT {@link Component component}. @@ -55,20 +56,14 @@ * @author Julien Seinturier - COMEX SA - http://www.seinturier.fr * @author Alexander Brui (JavaSaBr) */ -public class AWTMouseInput extends AWTInput implements MouseInput, MouseListener, MouseMotionListener, MouseWheelListener { - - private static final Map MOUSE_BUTTON_TO_JME = new HashMap<>(); - - static { - MOUSE_BUTTON_TO_JME.put(MouseEvent.BUTTON1, BUTTON_LEFT); - MOUSE_BUTTON_TO_JME.put(MouseEvent.BUTTON2, BUTTON_RIGHT); - MOUSE_BUTTON_TO_JME.put(MouseEvent.BUTTON3, BUTTON_MIDDLE); - } +public class AWTInputMouse extends AWTInput implements MouseInput, MouseListener, MouseMotionListener, MouseWheelListener { + private Map buttonMapping; + /** * The scale factor for scrolling. */ - private static final int WHEEL_SCALE = 10; + private int wheelScale = 10; private final LinkedList mouseMotionEvents; @@ -78,10 +73,46 @@ public class AWTMouseInput extends AWTInput implements MouseInput, MouseListener private int mouseY; private int mouseWheel; - public AWTMouseInput(AWTContext context) { + /** + * Create a new {@link MouseInput Mouse input} that is binded with AWT Mouse. By default, mouse button mapping is: + *
    + *
  • {@link MouseEvent.BUTTON1} is mapped with {@link BUTTON_LEFT} + *
  • {@link MouseEvent.BUTTON2} is mapped with {@link BUTTON_MIDDLE} + *
  • {@link MouseEvent.BUTTON3} is mapped with {@link BUTTON_RIGHT} + *
+ * The button mapping can be changed using {@link #setButtonMapping(Map) setButtonMapping() method}. + */ + public AWTInputMouse() { + super(); + mouseMotionEvents = new LinkedList(); + mouseButtonEvents = new LinkedList(); + + buttonMapping = new HashMap<>(); + buttonMapping.put(MouseEvent.BUTTON1, BUTTON_LEFT); + buttonMapping.put(MouseEvent.BUTTON2, BUTTON_MIDDLE); + buttonMapping.put(MouseEvent.BUTTON3, BUTTON_RIGHT); + } + + /** + * Create a new {@link MouseInput Mouse input} that is binded with AWT Mouse and the given context. + * By default, mouse button mapping is: + *
    + *
  • {@link MouseEvent.BUTTON1} is mapped with {@link BUTTON_LEFT} + *
  • {@link MouseEvent.BUTTON2} is mapped with {@link BUTTON_MIDDLE} + *
  • {@link MouseEvent.BUTTON3} is mapped with {@link BUTTON_RIGHT} + *
+ * The button mapping can be changed using {@link #setButtonMapping(Map) setButtonMapping() method}. + * @param context to context to use. + */ + public AWTInputMouse(JmeContext context) { super(context); mouseMotionEvents = new LinkedList(); mouseButtonEvents = new LinkedList(); + + buttonMapping = new HashMap<>(); + buttonMapping.put(MouseEvent.BUTTON1, BUTTON_LEFT); + buttonMapping.put(MouseEvent.BUTTON2, BUTTON_MIDDLE); + buttonMapping.put(MouseEvent.BUTTON3, BUTTON_RIGHT); } @Override @@ -112,6 +143,43 @@ protected void updateImpl() { } } + /** + * Get the scale to apply to Wheel motion. + * @return the scale to apply to Wheel motion. + * @see #getSetWheelScale(int) + */ + public int getWheelScale() { + return wheelScale; + } + + /** + * Set the scale to apply to Wheel motion. + * @param scale the scale to apply to Wheel motion. + * @see #getWheelScale() + */ + public void getSetWheelScale(int scale) { + wheelScale = scale; + } + + /** + * Get the button mapping between JME and AWT. + * Within the map, keys are the JME button and values are the AWT Mouse button that is affected. + * @return the button mapping between JME and AWT. + * @see #setButtonMapping(Map) + */ + public Map getButtonMapping() { + return buttonMapping; + } + + /** + * Set the button mapping between JME and AWT. + * @param mapping the button mapping between JME and AWT. + * @see #getButtonMapping() + */ + public void setButtonMapping(Map mapping) { + this.buttonMapping = mapping; + } + private void onWheelScroll(final double xOffset, final double yOffset) { mouseWheel += yOffset; @@ -134,8 +202,14 @@ private void onCursorPos(double xpos, double ypos) { int xDelta; int yDelta; int x = (int) Math.round(xpos); - int y = context.getHeight() - (int) Math.round(ypos); - + + int y = 0; + if ((context != null) && (context instanceof AWTContext)) { + y = ((AWTContext)context).getHeight() - (int) Math.round(ypos); + } else { + y = (int) Math.round(ypos); + } + if (mouseX == 0) mouseX = x; if (mouseY == 0) mouseY = y; @@ -176,7 +250,7 @@ public void run() { } private int convertButton(int i) { - final Integer result = MOUSE_BUTTON_TO_JME.get(i); + final Integer result = buttonMapping.get(i); return result == null ? 0 : result; } @@ -195,8 +269,7 @@ public void setNativeCursor(JmeCursor cursor) { @Override public void mouseDragged(java.awt.event.MouseEvent e) { - // TODO Auto-generated method stub - + onCursorPos(e.getX(), e.getY()); } @Override @@ -234,6 +307,6 @@ public void mouseExited(java.awt.event.MouseEvent e) { @Override public void mouseWheelMoved(MouseWheelEvent e) { - onWheelScroll(e.getWheelRotation() * WHEEL_SCALE, e.getWheelRotation() * WHEEL_SCALE); + onWheelScroll(e.getWheelRotation() * wheelScale, e.getWheelRotation() * wheelScale); } } \ No newline at end of file diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTComponentRenderer.java similarity index 80% rename from jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java rename to jme3-desktop/src/main/java/com/jme3/system/awt/AWTComponentRenderer.java index 99e7456754..e22affbd03 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTComponentRenderer.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system; +package com.jme3.system.awt; import java.awt.Component; import java.awt.EventQueue; @@ -49,7 +49,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; -import com.jme3.system.AWTFrameProcessor.TransferMode; +import com.jme3.system.awt.AWTFrameProcessor.TransferMode; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.util.BufferUtils; @@ -152,6 +152,11 @@ public class AWTComponentRenderer { private Graphics2D offGraphics = null; + /** + * Is the rendered image has to be flipped in Y. + */ + private boolean flipY = true; + /** * Create a new component renderer attached to the given {@link Component destination}. * The graphics of the destination are updated with the JMonkeyEngine rendering result. @@ -175,11 +180,26 @@ public AWTComponentRenderer(Component destination, final int width, final int he * @param height the height of the component in pixels. */ public AWTComponentRenderer(Component destination, TransferMode transferMode, FrameBuffer frameBuffer, int width, int height) { + this(destination, transferMode, frameBuffer, width, height, true); + } + + /** + * Create a new component renderer attached to the given {@link Component destination}. + * The graphics of the destination are updated with the JMonkeyEngine rendering result. + * @param destination the AWT component to use as target of the JMonkeyEngine rendering. + * @param transferMode the rendering mode that can be {@link TransferMode#ALWAYS} if the component has to be rendered at each update or {@link TransferMode#ON_CHANGES} if the component has to be rendered only when changes are occurring. + * @param frameBuffer the JMonkey frame buffer to use (if null is passed, a new default frame buffer is created) + * @param width the width of the component in pixels. + * @param height the height of the component in pixels. + * @param yFlipped true if the rendered image has to be Y flipped and false otherwise + */ + public AWTComponentRenderer(Component destination, TransferMode transferMode, FrameBuffer frameBuffer, int width, int height, boolean yFlipped) { this.transferMode = transferMode; this.frameState = new AtomicInteger(WAITING_STATE); this.imageState = new AtomicInteger(WAITING_STATE); this.width = frameBuffer != null ? frameBuffer.getWidth() : width; this.height = frameBuffer != null ? frameBuffer.getHeight() : height; + this.flipY = yFlipped; this.frameCount = 0; if (frameBuffer != null) { @@ -252,6 +272,24 @@ public int getHeight() { return height; } + /** + * Is the rendered image is Y flipped. + * @return true if the rendered image has to be Y flipped and false otherwise + * @see #setFlipY(boolean) + */ + public boolean isFlipY() { + return flipY; + } + + /** + * Set if the rendered image has to be Y flipped. + * @param flip true if the rendered image has to be Y flipped and false otherwise + * @see #isFlipY() + */ + public void setFlipY(boolean flip) { + this.flipY = flip; + } + /** * Copy the JMonkey frame buffer that has been rendered by the JMonkey engine and schedule the rendering of the component. * @param renderManager the JMonkey render manager. @@ -324,13 +362,31 @@ protected void writeFrame() { synchronized (byteBuffer) { - for(int i = 0; i < width * height; i++) { - imageDataBuffer[i] = ((0xff & byteBuffer[i*4+3]) << 24) // Alpha - | ((0xff & byteBuffer[i*4]) << 16) // Red - | ((0xff & byteBuffer[i*4+1]) << 8) // Green - | ((0xff & byteBuffer[i*4+2])); // BLue - - } + if (flipY) { + + int index = 0; + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + index = y*width+x; + + imageDataBuffer[(height - y - 1)*width+x] = ((0xff & byteBuffer[index*4+3]) << 24) // Alpha + | ((0xff & byteBuffer[index*4]) << 16) // Red + | ((0xff & byteBuffer[index*4+1]) << 8) // Green + | ((0xff & byteBuffer[index*4+2])); // BLue; + } + } + + } else { + for(int i = 0; i < width * height; i++) { + imageDataBuffer[i] = ((0xff & byteBuffer[i*4+3]) << 24) // Alpha + | ((0xff & byteBuffer[i*4]) << 16) // Red + | ((0xff & byteBuffer[i*4+1]) << 8) // Green + | ((0xff & byteBuffer[i*4+2])); // BLue + + } + } + + } DataBuffer buffer = new DataBufferInt(imageDataBuffer, imageDataBuffer.length); diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTContext.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTContext.java similarity index 65% rename from jme3-desktop/src/main/java/com/jme3/system/AWTContext.java rename to jme3-desktop/src/main/java/com/jme3/system/awt/AWTContext.java index d72ee71c82..489a280e54 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTContext.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTContext.java @@ -29,13 +29,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system; +package com.jme3.system.awt; +import java.util.logging.Level; +import java.util.logging.Logger; -import com.jme3.input.AWTKeyInput; -import com.jme3.input.AWTMouseInput; import com.jme3.input.JoyInput; import com.jme3.input.TouchInput; +import com.jme3.input.awt.AWTInputKeyboard; +import com.jme3.input.awt.AWTInputMouse; import com.jme3.opencl.Context; import com.jme3.renderer.Renderer; import com.jme3.system.AppSettings; @@ -49,11 +51,14 @@ *

* This class is based on the JavaFX original code provided by Alexander Brui (see JME3-FX) *

+ * It is possible to specify a system renderer to use by setting the system property jme3.system.renderer with a value that specifies the renderer to use (These values can be obtained from {@link AppSettings} class). * @author Julien Seinturier - COMEX SA - http://www.seinturier.fr * @author Alexander Brui (JavaSaBr) */ public class AWTContext implements JmeContext { + private static final Logger logger = Logger.getLogger(JmeContext.class.getName()); + /** * The settings. */ @@ -62,12 +67,12 @@ public class AWTContext implements JmeContext { /** * The key input. */ - protected final AWTKeyInput keyInput; + protected final AWTInputKeyboard keyInput; /** * The mouse input. */ - protected final AWTMouseInput mouseInput; + protected final AWTInputMouse mouseInput; /** * The current width. @@ -79,14 +84,19 @@ public class AWTContext implements JmeContext { */ private volatile int height; + private String underlyingRenderer = null; + /** * The background context. */ protected JmeContext backgroundContext; + /** + * Create a new AWT Context + */ public AWTContext() { - this.keyInput = new AWTKeyInput(this); - this.mouseInput = new AWTMouseInput(this); + this.keyInput = new AWTInputKeyboard(this); + this.mouseInput = new AWTInputMouse(this); this.settings = createSettings(); this.backgroundContext = createBackgroundContext(); this.height = 1; @@ -94,44 +104,85 @@ public AWTContext() { } /** + * Get the current display height of the context. * @return the current height. + * @see #getWidth() */ public int getHeight() { return height; } /** + * Set the current display height of the context. * @param height the current height. + * @see #setWidth(int) */ public void setHeight(final int height) { this.height = height; } /** + * Get the current display width of the context. * @return the current width. + * @see #getHeight() */ public int getWidth() { return width; } /** + * Set the current display width of the context. * @param width the current width. + * @see #setHeight(int) */ public void setWidth(final int width) { this.width = width; } /** - * @return new settings. + * Create a default application settings. + * @return the created application settings. */ protected AppSettings createSettings() { final AppSettings settings = new AppSettings(true); - settings.setRenderer(AppSettings.LWJGL_OPENGL32); + + String renderer = System.getProperty("jme3.system.renderer"); + + if (renderer != null) { + underlyingRenderer = renderer; + settings.setRenderer(underlyingRenderer); + logger.log(Level.INFO, "Using underlying renderer "+settings.getRenderer()+"."); + } else { + underlyingRenderer = settings.getRenderer(); + logger.log(Level.INFO, "Using default underlying renderer "+underlyingRenderer); + logger.log(Level.INFO, getClass().getSimpleName()+" underlying renderer can be set using jme3.awt.renderer property."); + } + return settings; } + @Override + public void setSettings(AppSettings settings) { + this.settings.copyFrom(settings); + + String renderer = System.getProperty("jme3.system.renderer"); + + if (renderer != null) { + underlyingRenderer = renderer; + this.settings.setRenderer(underlyingRenderer); + logger.log(Level.INFO, "Using underlying renderer "+this.settings.getRenderer()+"."); + } else { + this.settings.setRenderer(underlyingRenderer); + logger.log(Level.INFO, "Using default underlying renderer "+this.settings.getRenderer()); + logger.log(Level.INFO, getClass().getSimpleName()+" underlying renderer can be set using jme3.awt.renderer property."); + } + + this.backgroundContext.setSettings(this.settings); + } + /** - * @return new context/ + * Create a background context for displaying. + * @return the created context */ protected JmeContext createBackgroundContext() { return JmeSystem.newContext(settings, Type.OffscreenSurface); @@ -142,13 +193,6 @@ public Type getType() { return Type.OffscreenSurface; } - @Override - public void setSettings(AppSettings settings) { - this.settings.copyFrom(settings); - this.settings.setRenderer(AppSettings.LWJGL_OPENGL32); - this.backgroundContext.setSettings(settings); - } - @Override public void setSystemListener(final SystemListener listener) { backgroundContext.setSystemListener(listener); @@ -170,12 +214,12 @@ public Context getOpenCLContext() { } @Override - public AWTMouseInput getMouseInput() { + public AWTInputMouse getMouseInput() { return mouseInput; } @Override - public AWTKeyInput getKeyInput() { + public AWTInputKeyboard getKeyInput() { return keyInput; } @@ -215,9 +259,8 @@ public void setAutoFlushFrames(final boolean enabled) { @Override public void create(final boolean waitFor) { - String render = System.getProperty("awt.background.render", AppSettings.LWJGL_OPENGL33); - backgroundContext.getSettings().setRenderer(render); - backgroundContext.create(waitFor); + logger.log(Level.INFO, "Creating background renderer using "+backgroundContext.getSettings().getRenderer()+" renderer"); + backgroundContext.create(waitFor); } @Override diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTFrameProcessor.java similarity index 85% rename from jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java rename to jme3-desktop/src/main/java/com/jme3/system/awt/AWTFrameProcessor.java index bb254e450a..215d7c7d22 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTFrameProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 jMonkeyEngine + * Copyright (c) 2009-2018 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,10 +29,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system; +package com.jme3.system.awt; import java.awt.Component; import java.awt.EventQueue; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Iterator; @@ -40,8 +45,8 @@ import java.util.concurrent.atomic.AtomicInteger; import com.jme3.app.Application; -import com.jme3.input.AWTKeyInput; -import com.jme3.input.AWTMouseInput; +import com.jme3.input.awt.AWTInputKeyboard; +import com.jme3.input.awt.AWTInputMouse; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; import com.jme3.renderer.Camera; @@ -60,7 +65,7 @@ * @author Alexander Brui (JavaSaBr) * */ -public class AWTFrameProcessor implements SceneProcessor, PropertyChangeListener { +public class AWTFrameProcessor implements SceneProcessor, PropertyChangeListener, ComponentListener, HierarchyListener, HierarchyBoundsListener{ public enum TransferMode { ALWAYS, @@ -125,6 +130,8 @@ public enum TransferMode { private boolean askFixAspect; private boolean enabled; + private boolean flipY = true; + @Override public void initialize(RenderManager rm, ViewPort vp) { this.renderManager = rm; @@ -192,15 +199,71 @@ public void setProfiler(AppProfiler profiler) { @Override public void propertyChange(PropertyChangeEvent evt) { - System.out.println("Property changed: "+evt.getPropertyName()+" "+evt.getOldValue()+" -> "+evt.getNewValue()); + } + + @Override + public void componentResized(ComponentEvent e) { + if ((e != null) && (e.getComponent() == destination)){ + if (e.getComponent() != null) { + notifyChangedDimension(e.getComponent().getWidth(), e.getComponent().getHeight()); + } + } + } + + @Override + public void componentMoved(ComponentEvent e) { + } + + @Override + public void componentShown(ComponentEvent e) { + } + + @Override + public void componentHidden(ComponentEvent e) { + } + + @Override + public void hierarchyChanged(HierarchyEvent e) { + } + + @Override + public void ancestorMoved(HierarchyEvent e) {} + + @Override + public void ancestorResized(HierarchyEvent e) { + notifyChangedDimension(destination.getWidth(), destination.getHeight()); } public AWTFrameProcessor() { + this(true); + } + + public AWTFrameProcessor(boolean flipY) { transferMode = TransferMode.ALWAYS; askWidth = 1; askHeight = 1; main = true; reshapeNeeded = new AtomicInteger(2); + + this.flipY = flipY; + } + + /** + * Is the rendered image is Y flipped. + * @return true if the rendered image has to be Y flipped and false otherwise + * @see #setFlipY(boolean) + */ + public boolean isFlipY() { + return flipY; + } + + /** + * Set if the rendered image has to be Y flipped. + * @param flip true if the rendered image has to be Y flipped and false otherwise + * @see #isFlipY() + */ + public void setFlipY(boolean flip) { + this.flipY = flip; } /** @@ -208,7 +271,7 @@ public AWTFrameProcessor() { * * @param newValue the new value of the ratio. */ - protected void notifyChangedRatio(Boolean newValue) { + protected void notifyChangedpRatio(Boolean newValue) { notifyComponentResized(destination.getWidth(), destination.getHeight(), newValue); } @@ -230,6 +293,16 @@ protected void notifyChangedWidth(Number newValue) { notifyComponentResized(newValue.intValue(), destination.getHeight(), isPreserveRatio()); } + /** + * Notify about that the dimensions were changed. + * + * @param width the new value of the width. + * @param height the new value of the height. + */ + protected void notifyChangedDimension(Number width, Number height) { + notifyComponentResized(width.intValue(), height.intValue(), isPreserveRatio()); + } + /** * Gets the application. * @@ -331,8 +404,7 @@ public void setEnabled(final boolean enabled) { } /** - * Handle resizing. - * + * Handle rendering component resizing. * @param newWidth the new width. * @param newHeight the new height. * @param fixAspect true if need to fix aspect. @@ -488,9 +560,9 @@ protected void bindDestination(Application application, Component destination) { if (application.getContext() != null) { if (application.getContext() instanceof AWTContext) { AWTContext context = (AWTContext) application.getContext(); - AWTMouseInput mouseInput = context.getMouseInput(); + AWTInputMouse mouseInput = context.getMouseInput(); mouseInput.bind(destination); - AWTKeyInput keyInput = context.getKeyInput(); + AWTInputKeyboard keyInput = context.getKeyInput(); keyInput.bind(destination); setDestination(destination); @@ -518,9 +590,9 @@ protected void unbindDestination() { if (hasApplication() && isMain()) { final AWTContext context = (AWTContext) getApplication().getContext(); - final AWTMouseInput mouseInput = context.getMouseInput(); + final AWTInputMouse mouseInput = context.getMouseInput(); mouseInput.unbind(); - final AWTKeyInput keyInput = context.getKeyInput(); + final AWTInputKeyboard keyInput = context.getKeyInput(); keyInput.unbind(); } @@ -537,6 +609,11 @@ protected void bindListeners() { Component destination = getDestination(); destination.addPropertyChangeListener(this); destination.addPropertyChangeListener(this); + + destination.addComponentListener(this); + + destination.addHierarchyListener(this); + destination.addHierarchyBoundsListener(this); } @@ -544,6 +621,11 @@ protected void unbindListeners() { Component destination = getDestination(); destination.removePropertyChangeListener(this); destination.removePropertyChangeListener(this); + + destination.removeComponentListener(this); + + destination.removeHierarchyListener(this); + destination.removeHierarchyBoundsListener(this); } /** @@ -583,7 +665,7 @@ protected AWTComponentRenderer reshapeInThread(final int width, final int height * @return the new frame transfer. */ protected AWTComponentRenderer createFrameTransfer(FrameBuffer frameBuffer, int width, int height) { - return new AWTComponentRenderer(getDestination(), getTransferMode(), isMain() ? null : frameBuffer, width, height); + return new AWTComponentRenderer(getDestination(), getTransferMode(), isMain() ? null : frameBuffer, width, height, flipY); } /** diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTTaskExecutor.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTTaskExecutor.java similarity index 95% rename from jme3-desktop/src/main/java/com/jme3/system/AWTTaskExecutor.java rename to jme3-desktop/src/main/java/com/jme3/system/awt/AWTTaskExecutor.java index 8e9f586232..11d6065996 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTTaskExecutor.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AWTTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 jMonkeyEngine + * Copyright (c) 2009-2018 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system; +package com.jme3.system.awt; import java.util.LinkedList; import java.util.List; @@ -39,7 +39,7 @@ /** *

* This class is dedicated to the queuing of AWT related tasks and their execution. - * It's able to store tasks that have to be executed within an AWT context and execute them at the specified time. + * It's enable to store tasks that have to be executed within an AWT context and execute them at the specified time. *

*

* This class is an AWT implementation of the JavaFX original code provided by Alexander Brui (see JME3-FX) diff --git a/jme3-examples/src/main/java/jme3test/awt/AWTComponentAppStateSample.java b/jme3-examples/src/main/java/jme3test/awt/AWTComponentAppStateSample.java new file mode 100644 index 0000000000..61fa918c49 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/awt/AWTComponentAppStateSample.java @@ -0,0 +1,232 @@ +package jme3test.awt; + +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.Application; +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.AWTComponentAppState; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.Camera; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.system.awt.AWTContext; + +/** + * An example class that describe the use of an AWT component as render support. + * @author Julien Seinturier + * + */ +public class AWTComponentAppStateSample { + + + + /** + * The root node of the scene to display. + */ + private Node sceneRootNode = null; + + /** + * The camera used for rendering. + */ + private Camera camera = null; + + /** + * The camera target. This node is attached to the camera controler. + */ + private Node cameraTarget = null; + + /** + * Initialize the JMonkey Application that will render the scenes. + * @return the initialized JMonkey Application that will render the scenes. + */ + + protected SimpleApplication createJMEApplication(AppSettings settings){ + + SimpleApplication application = new SimpleApplication(){ + + @Override + public void initialize() { + System.out.println("Initialising JMonkey Application..."); + super.initialize(); + System.out.println("Initialising JMonkey Application [DONE]"); + } + + @Override + public void restart(){ + try { + System.out.println("Restarting application"); + super.restart(); + System.out.println("Restart done"); + } catch (Exception e) { + System.err.println("Cannot restart JMonkey underlying application: "+e.getMessage()); + e.printStackTrace(System.err); + } + } + + @Override + public void start(){ + System.out.println("Starting application... "); + super.start(); + System.out.print("Starting application [DONE]"); + } + + @Override + public void startCanvas(){ + System.out.println("Starting application canvas"); + super.startCanvas(); + } + + @Override + public void startCanvas(boolean waitFor){ + System.out.println("Starting application canvas and wait: "+waitFor); + super.startCanvas(waitFor); + } + + @Override + public void simpleInitApp() { + + System.out.println("Init application..."); + + // Preparing the scene to be rendered. + sceneRootNode = getRootNode(); + + Box b = new Box(1, 1, 1); + + Geometry greenBox = new Geometry("GreenBox", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Green); + greenBox.setMaterial(mat); + rootNode.attachChild(greenBox); + + cameraTarget = new Node("CameraTarget"); + cameraTarget.setLocalTranslation(sceneRootNode.getLocalTranslation()); + sceneRootNode.attachChild(cameraTarget); + + // Configuring the camera and its controler + camera = cam; + camera.setFrustumPerspective(45.0f, ((float)camera.getWidth()) / ((float)camera.getHeight()), 0.001f, 10000.0f); + camera.update(); + + System.out.println("Init application [DONE]"); + } + + }; + + application.setSettings(settings); + application.setShowSettings(false); + + return application; + } + + /** + * An example that shows how to render JME content within an AWT component. + * The use of this panel requires:
+ *

    + *
  • 1. The initialization of the JMonkey related object required by the system (application). + *
  • 2. The initialization of the AWT component to use as rendering target. + *
  • 2. The initialization of the link between JME underlying components and AWT component. + *
+ */ + public AWTComponentAppStateSample(){ + + // 1. Create settings that are compatible with AWT rendering + AppSettings settings = new AppSettings(true); + settings.setFullscreen(false); + settings.setCustomRenderer(AWTContext.class); + + // 2. Initialize the underlying JMonkey related objects + System.out.print("Initializing JME application... "); + final Application application = createJMEApplication(settings); + System.out.println(" [DONE]"); + + // 3. Create the component that will support the rendering. + // Any subclass of Component can be used. + Canvas component = new Canvas(); + component.setSize(800, 600); + + // 4. Create the app state dedicated to AWT component rendering + AWTComponentAppState appState = new AWTComponentAppState(component); + + // 5. Attach the app state to the application + application.getStateManager().attach(appState); + + // 6. 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 entry point. + * @param args the command line arguments. + */ + public static void main(String[] args){ + + // Instanciate the new sample. + new AWTComponentAppStateSample(); + + } +}