瀏覽代碼

* Initial commit for light-weight jME3 AWT panels

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8323 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
sha..rd 14 年之前
父節點
當前提交
a28d0d8baf

+ 14 - 15
engine/src/desktop/com/jme3/input/awt/AwtKeyInput.java

@@ -53,21 +53,27 @@ public class AwtKeyInput implements KeyInput, KeyListener {
 
     private static final Logger logger = Logger.getLogger(AwtKeyInput.class.getName());
     private RawInputListener listener;
-    private boolean inited = false;
     private List<KeyInputEvent> eventQueue = new LinkedList<KeyInputEvent>();
     private Component component;
 
-    public AwtKeyInput(Component comp){
-        this.component = comp;
+    public AwtKeyInput(){
     }
 
     public void initialize() {
-        inited = true;
-        component.addKeyListener(this);
-
-        logger.info("Key input initialized.");
+    }
+    
+    public void destroy() {
     }
 
+    public void setInputSource(Component comp){
+        if (component != null){
+            component.removeKeyListener(this);
+            eventQueue.clear();
+        }
+        component = comp;
+        component.addKeyListener(this);
+    }
+    
     public long getInputTimeNanos() {
         return System.nanoTime();
     }
@@ -84,15 +90,8 @@ public class AwtKeyInput implements KeyInput, KeyListener {
         eventQueue.clear();
     }
 
-    public void destroy() {
-        inited = false;
-
-        component.removeKeyListener(this);
-        logger.info("Key input destroyed.");
-    }
-
     public boolean isInitialized() {
-        return inited;
+        return true;
     }
 
     public void setInputListener(RawInputListener listener) {

+ 32 - 18
engine/src/desktop/com/jme3/input/awt/AwtMouseInput.java

@@ -68,8 +68,6 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
 
     private static final Logger logger = Logger.getLogger(AwtMouseInput.class.getName());
 
-    private boolean inited = false;
-
     private boolean visible = true;
 
     private RawInputListener listener;
@@ -92,8 +90,7 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
     private boolean isRecentering;
     private int eventsSinceRecenter;
 
-    public AwtMouseInput(Component comp) {
-        this.component = comp;
+    public AwtMouseInput() {
         location = new Point();
         centerLocation = new Point();
         centerLocationOnScreen = new Point();
@@ -105,28 +102,39 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
             logger.log(Level.SEVERE, "Could not create a robot, so the mouse cannot be grabbed! ", e);
         }
     }
+    
+    public void setInputSource(Component comp){
+        if (component != null){
+            component.removeMouseListener(this);
+            component.removeMouseMotionListener(this);
+            component.removeMouseWheelListener(this);
+            
+            wheelPos = 0;
+            isRecentering = false;
+            eventsSinceRecenter = 0;
+            lastEventX = 0;
+            lastEventY = 0;
+            lastEventWheel = 0;
+            location = new Point();
+            centerLocation = new Point();
+            centerLocationOnScreen = new Point();
+            lastKnownLocation = new Point();
+        }
 
-    public void initialize() {
-        inited = true;
+        component = comp;
         component.addMouseListener(this);
         component.addMouseMotionListener(this);
         component.addMouseWheelListener(this);
+    }
 
-        logger.info("Mouse input initialized.");
+    public void initialize() {
     }
 
     public void destroy() {
-        inited = false;
-        robot = null;
-
-        component.removeMouseListener(this);
-        component.removeMouseMotionListener(this);
-        component.removeMouseWheelListener(this);
-        logger.info("Mouse input destroyed.");
     }
 
     public boolean isInitialized() {
-        return inited;
+        return true;
     }
 
     public void setInputListener(RawInputListener listener){
@@ -139,10 +147,16 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
 
     public void setCursorVisible(boolean visible){
         if (this.visible != visible){
-            component.setCursor(visible ? null : getTransparentCursor());
             this.visible = visible;
-            if (!visible)
-                recenterMouse(component);
+            final boolean newVisible = visible;
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    component.setCursor(newVisible ? null : getTransparentCursor());
+                    if (!newVisible)
+                        recenterMouse(component);
+                }
+            });
+            
         }
     }
 

+ 218 - 0
engine/src/desktop/com/jme3/system/awt/AwtPanel.java

@@ -0,0 +1,218 @@
+package com.jme3.system.awt;
+
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image.Format;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.Screenshots;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferStrategy;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class AwtPanel extends Canvas implements SceneProcessor {
+
+    private BufferedImage img;
+    private FrameBuffer fb;
+    private ByteBuffer byteBuf;
+    private boolean activeUpdates = true;
+    private RenderManager rm;
+    private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>(); 
+    
+    // Visibility/drawing vars
+    private BufferStrategy strategy;
+    private AffineTransformOp transformOp;
+    private CyclicBarrier visibleBarrier = new CyclicBarrier(2);
+    private AtomicBoolean visible = new AtomicBoolean(false);
+    private boolean glVisible = false;
+    
+    // Reshape vars
+    private int newWidth  = 0;
+    private int newHeight = 0;
+    private CyclicBarrier reshapeBarrier = new CyclicBarrier(2);
+    private AtomicBoolean reshapeNeeded  = new AtomicBoolean(false);
+    
+    public AwtPanel(boolean activeUpdates){
+        this.activeUpdates = activeUpdates;
+        
+        setIgnoreRepaint(true);
+        addComponentListener(new ComponentAdapter(){
+            @Override
+            public void componentResized(ComponentEvent e) {
+                newWidth = Math.max(getWidth(), 1);
+                newHeight = Math.max(getHeight(), 1);
+                reshapeNeeded.set(true);
+
+                try {
+                    reshapeBarrier.await();
+                } catch (InterruptedException ex) {
+                    ex.printStackTrace();
+                } catch (BrokenBarrierException ex) {
+                    ex.printStackTrace();
+                }
+            }
+        });
+    }
+    
+    @Override
+    public void addNotify(){
+        super.addNotify();
+
+        try {
+            createBufferStrategy(2);
+            strategy = getBufferStrategy();
+            visible.set(true);
+            visibleBarrier.await();
+        } catch (InterruptedException ex) {
+            ex.printStackTrace();
+        } catch (BrokenBarrierException ex) {
+            ex.printStackTrace();
+        }
+        
+        requestFocusInWindow();
+    }
+
+    @Override
+    public void removeNotify(){
+        try {
+            visible.set(false);
+            visibleBarrier.await();
+            strategy = null;
+        } catch (InterruptedException ex) {
+            ex.printStackTrace();
+        } catch (BrokenBarrierException ex) {
+            ex.printStackTrace();
+        }
+        
+        super.removeNotify();
+    }
+    
+    private void checkVisibility(){
+        if (visible.get() != glVisible){
+            try {
+                glVisible = visible.get();
+                visibleBarrier.await();
+            } catch (InterruptedException ex) {
+                ex.printStackTrace();
+            } catch (BrokenBarrierException ex) {
+                ex.printStackTrace();
+            }
+        }
+    }
+    
+    public void drawFrame(){
+        checkVisibility();
+        if (!glVisible)
+            return;
+        
+        if (strategy.contentsLost()){
+            strategy.dispose();
+            createBufferStrategy(2);
+            strategy = getBufferStrategy();
+            System.out.println("BufferStrategy lost!");
+        }
+        
+        Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
+        g2d.drawImage(img, transformOp, 0, 0);
+        g2d.dispose();
+        strategy.show();
+    }
+    
+    public boolean isActiveUpdates() {
+        return activeUpdates;
+    }
+
+    public void setActiveUpdates(boolean activeUpdates) {
+        this.activeUpdates = activeUpdates;
+    }
+    
+    public void attachTo(ViewPort ... vps){
+        if (viewPorts.size() > 0){
+            for (ViewPort vp : viewPorts){
+                vp.setOutputFrameBuffer(null);
+            }
+            viewPorts.get(viewPorts.size()-1).removeProcessor(this);
+        }
+        
+        viewPorts.addAll(Arrays.asList(vps));
+        viewPorts.get(viewPorts.size()-1).addProcessor(this);
+    }
+    
+    public void initialize(RenderManager rm, ViewPort vp) {
+        if (this.rm == null){
+            // First time called in OGL thread
+            this.rm = rm;
+            reshapeInThread(1, 1);
+        }
+    }
+
+    private void reshapeInThread(int width, int height) {
+        byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
+        fb = new FrameBuffer(width, height, 1);
+        fb.setDepthBuffer(Format.Depth);
+        fb.setColorBuffer(Format.RGB8);
+        
+        img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
+        tx.translate(0, -img.getHeight());
+        transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+        
+        for (ViewPort vp : viewPorts){
+            vp.setOutputFrameBuffer(fb);
+            vp.getCamera().resize(width, height, true);
+        }
+    }
+
+    public boolean isInitialized() {
+        return fb != null;
+    }
+
+    public void preFrame(float tpf) {
+    }
+
+    public void postQueue(RenderQueue rq) {
+    }
+
+    public void postFrame(FrameBuffer out) {
+        if (out != fb)
+            throw new IllegalStateException("Why did you change the output framebuffer?");
+        
+        if (reshapeNeeded.getAndSet(false)){
+            reshapeInThread(newWidth, newHeight);
+            try {
+                reshapeBarrier.await();
+            } catch (InterruptedException ex) {
+                ex.printStackTrace();
+            } catch (BrokenBarrierException ex) {
+                ex.printStackTrace();
+            }
+        }else if (activeUpdates){
+            byteBuf.clear();
+            rm.getRenderer().readFrameBuffer(fb, byteBuf);
+            Screenshots.convertScreenShot2(byteBuf, img);
+            drawFrame();
+        }else{
+            checkVisibility();
+        }
+    }
+    
+    public void reshape(ViewPort vp, int w, int h) {
+    }
+
+    public void cleanup() {
+    }
+}

+ 176 - 0
engine/src/desktop/com/jme3/system/awt/AwtPanelsContext.java

@@ -0,0 +1,176 @@
+package com.jme3.system.awt;
+
+import com.jme3.input.JoyInput;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.TouchInput;
+import com.jme3.input.awt.AwtKeyInput;
+import com.jme3.input.awt.AwtMouseInput;
+import com.jme3.renderer.Renderer;
+import com.jme3.system.AppSettings;
+import com.jme3.system.JmeContext;
+import com.jme3.system.JmeSystem;
+import com.jme3.system.SystemListener;
+import com.jme3.system.Timer;
+import java.util.ArrayList;
+
+public class AwtPanelsContext implements JmeContext {
+
+    protected JmeContext actualContext;
+    protected AppSettings settings = new AppSettings(true);
+    protected SystemListener listener;
+    protected ArrayList<AwtPanel> panels = new ArrayList<AwtPanel>();
+    protected AwtPanel inputSource;
+    
+    protected AwtMouseInput mouseInput = new AwtMouseInput();
+    protected AwtKeyInput keyInput = new AwtKeyInput();
+    
+    private class AwtPanelsListener implements SystemListener {
+
+        public void initialize() {
+            initInThread();
+        }
+
+        public void reshape(int width, int height) {
+            throw new IllegalStateException();
+        }
+
+        public void update() {
+            updateInThread();
+        }
+
+        public void requestClose(boolean esc) {
+            // shouldn't happen
+            throw new IllegalStateException();
+        }
+
+        public void gainFocus() {
+            // shouldn't happen
+            throw new IllegalStateException();
+        }
+
+        public void loseFocus() {
+            // shouldn't happen
+            throw new IllegalStateException();
+        }
+
+        public void handleError(String errorMsg, Throwable t) {
+            listener.handleError(errorMsg, t);
+        }
+
+        public void destroy() {
+            destroyInThread();
+        }
+    }
+    
+    public void setInputSource(AwtPanel panel){
+        if (!panels.contains(panel))
+            throw new IllegalArgumentException();
+        
+        inputSource = panel;
+        mouseInput.setInputSource(panel);
+        keyInput.setInputSource(panel);
+    }
+    
+    public Type getType() {
+        return Type.OffscreenSurface;
+    }
+    
+    public void setSystemListener(SystemListener listener) {
+        this.listener = listener;
+    }
+
+    public AppSettings getSettings() {
+        return settings;
+    }
+
+    public Renderer getRenderer() {
+        return actualContext.getRenderer();
+    }
+
+    public MouseInput getMouseInput() {
+        return mouseInput;
+    }
+
+    public KeyInput getKeyInput() {
+        return keyInput;
+    }
+
+    public JoyInput getJoyInput() {
+        return null;
+    }
+
+    public TouchInput getTouchInput() {
+        return null;
+    }
+
+    public Timer getTimer() {
+        return actualContext.getTimer();
+    }
+
+    public boolean isCreated() {
+        return actualContext != null && actualContext.isCreated();
+    }
+
+    public boolean isRenderable() {
+        return actualContext != null && actualContext.isRenderable();
+    }
+    
+    public AwtPanelsContext(){
+    }
+    
+    public AwtPanel createPanel(boolean activeUpdates){
+        AwtPanel panel = new AwtPanel(activeUpdates);
+        panels.add(panel);
+        return panel;
+    }
+    
+    private void initInThread(){
+        listener.initialize();
+    }
+    
+    private void updateInThread(){
+        listener.update();
+    }
+    
+    private void destroyInThread(){
+        listener.destroy();
+    }
+    
+    public void setSettings(AppSettings settings) {
+        settings.copyFrom(settings);
+        if (actualContext != null){
+            actualContext.setSettings(settings);
+        }
+    }
+
+    public void create(boolean waitFor) {
+        if (actualContext != null)
+            throw new IllegalStateException("Already created");
+        
+        actualContext = JmeSystem.newContext(settings, Type.OffscreenSurface);
+        actualContext.setSystemListener(new AwtPanelsListener());
+        actualContext.create(waitFor);
+    }
+
+    public void destroy(boolean waitFor) {
+        if (actualContext == null)
+            throw new IllegalStateException("Not created");
+        
+        // destroy parent context
+        actualContext.destroy(waitFor);
+    }
+    
+    public void setTitle(String title) {
+        // not relevant, ignore
+    }
+    
+    public void setAutoFlushFrames(boolean enabled) {
+        // not relevant, ignore
+    }
+
+    public void restart() {
+        // only relevant if changing pixel format.
+    }
+    
+}

+ 26 - 0
engine/src/desktop/com/jme3/util/Screenshots.java

@@ -2,10 +2,36 @@ package com.jme3.util;
 
 import java.awt.image.BufferedImage;
 import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
 import java.awt.image.WritableRaster;
 import java.nio.ByteBuffer;
 
 public final class Screenshots {
+    
+    public static void convertScreenShot2(ByteBuffer bgraBuf, BufferedImage out){
+        WritableRaster wr = out.getRaster();
+        DataBufferInt db = (DataBufferInt) wr.getDataBuffer();
+        
+        int[] cpuArray = db.getData();
+        
+        bgraBuf.clear();
+        bgraBuf.asIntBuffer().get(cpuArray);
+        
+//        int width  = wr.getWidth();
+//        int height = wr.getHeight();
+//
+//        // flip the components the way AWT likes them
+//        for (int y = 0; y < height / 2; y++){
+//            for (int x = 0; x < width; x++){
+//                int inPtr  = (y * width + x);
+//                int outPtr = ((height-y-1) * width + x);
+//                int pixel = cpuArray[inPtr];
+//                cpuArray[inPtr] = cpuArray[outPtr];
+//                cpuArray[outPtr] = pixel;
+//            }
+//        }
+    }
+    
     public static void convertScreenShot(ByteBuffer bgraBuf, BufferedImage out){
         WritableRaster wr = out.getRaster();
         DataBufferByte db = (DataBufferByte) wr.getDataBuffer();

+ 86 - 0
engine/src/test/jme3test/awt/TestAwtPanels.java

@@ -0,0 +1,86 @@
+package jme3test.awt;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.system.AppSettings;
+import com.jme3.system.awt.AwtPanel;
+import com.jme3.system.awt.AwtPanelsContext;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+public class TestAwtPanels extends SimpleApplication {
+
+    private static TestAwtPanels app;
+    private static AwtPanel panel, panel2;
+    private static int panelsClosed = 0;
+    
+    private static void createWindowForPanel(AwtPanel panel, int location){
+        JFrame frame = new JFrame("Render Display " + location);
+        frame.getContentPane().setLayout(new BorderLayout());
+        frame.getContentPane().add(panel, BorderLayout.CENTER);
+        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        frame.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosed(WindowEvent e) {
+                if (++panelsClosed == 2){
+                    app.stop();
+                }
+            }
+        });
+        frame.pack();
+        frame.setLocation(location, Toolkit.getDefaultToolkit().getScreenSize().height - 400);
+        frame.setVisible(true);
+    }
+    
+    public static void main(String[] args){
+        Logger.getLogger("com.jme3").setLevel(Level.WARNING);
+        
+        app = new TestAwtPanels();
+        app.setShowSettings(false);
+        AppSettings settings = new AppSettings(true);
+        settings.setCustomRenderer(AwtPanelsContext.class);
+        app.setSettings(settings);
+        app.start();
+        
+        SwingUtilities.invokeLater(new Runnable(){
+            public void run(){
+                final AwtPanelsContext ctx = (AwtPanelsContext) app.getContext();
+                panel = ctx.createPanel(true);
+                panel.setPreferredSize(new Dimension(400, 300));
+                ctx.setInputSource(panel);
+                
+                panel2 = ctx.createPanel(true);
+                panel2.setPreferredSize(new Dimension(400, 300));
+                
+                createWindowForPanel(panel, 300);
+                createWindowForPanel(panel2, 700);
+            }
+        });
+    }
+    
+    @Override
+    public void simpleInitApp() {
+        flyCam.setDragToRotate(true);
+        
+        Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+        Geometry geom = new Geometry("Box", b);
+        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+        geom.setMaterial(mat);
+        rootNode.attachChild(geom);
+        
+        panel.attachTo(viewPort);
+        guiViewPort.setClearFlags(true, true, true);
+        panel2.attachTo(guiViewPort);
+    }
+}

+ 0 - 8
engine/src/test/jme3test/batching/TestCubeCluster.java

@@ -11,30 +11,22 @@ import com.jme3.input.controls.ActionListener;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Vector3f;
-import com.jme3.renderer.RenderManager;
-import com.jme3.renderer.ViewPort;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.shape.Box;
 import com.jme3.system.AppSettings;
 import com.jme3.input.controls.KeyTrigger;
 import java.util.ArrayList;
 import java.util.Random;
-import com.jme3.light.DirectionalLight;
 import com.jme3.math.FastMath;
-import com.jme3.math.Matrix3f;
 import com.jme3.math.Quaternion;
 import com.jme3.post.FilterPostProcessor;
 import com.jme3.post.filters.BloomFilter;
-import com.jme3.post.ssao.SSAOFilter;
 import com.jme3.scene.BatchedGeometry;
 import com.jme3.scene.GeometryBatch;
 import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
-import com.jme3.scene.control.AbstractControl;
-import com.jme3.scene.control.Control;
 import com.jme3.scene.debug.Arrow;
 import java.util.List;
-import jme3test.post.SSAOUI;
 
 public class TestCubeCluster extends SimpleApplication {