Pārlūkot izejas kodu

* Moved checkFrameBufferError() to part that sets up framebuffer. Can prevent odd crashes on some systems before any framebuffer is active.
* AWT Panels
- Added automatic throttling to update loop if none of the panels are visible to the user (e.g. covered by another tab)
- Fixed NPE that could occur when an AwtPanel becomes invisible
- Called reshape() on all viewports to which an AwtPanel is attached when the panel is resized
- Fixed inverted mouse coordinates

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8344 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

sha..rd 14 gadi atpakaļ
vecāks
revīzija
e3bff6d62a

+ 6 - 1
engine/src/desktop/com/jme3/input/awt/AwtMouseInput.java

@@ -148,6 +148,9 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
 
 
     public void setCursorVisible(boolean visible){
     public void setCursorVisible(boolean visible){
         if (this.visible != visible){
         if (this.visible != visible){
+            
+            lastKnownLocation.x = lastKnownLocation.y = 0;
+            
             this.visible = visible;
             this.visible = visible;
             final boolean newVisible = visible;
             final boolean newVisible = visible;
             SwingUtilities.invokeLater(new Runnable() {
             SwingUtilities.invokeLater(new Runnable() {
@@ -168,7 +171,9 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
             int newWheel = wheelPos;
             int newWheel = wheelPos;
 
 
             // invert DY
             // invert DY
-            MouseMotionEvent evt = new MouseMotionEvent(newX, newY,
+            int actualX = lastKnownLocation.x;
+            int actualY = component.getHeight() - lastKnownLocation.y;
+            MouseMotionEvent evt = new MouseMotionEvent(actualX, actualY,
                                                         newX - lastEventX,
                                                         newX - lastEventX,
                                                         lastEventY - newY,
                                                         lastEventY - newY,
                                                         wheelPos, lastEventWheel - wheelPos);
                                                         wheelPos, lastEventWheel - wheelPos);

+ 123 - 43
engine/src/desktop/com/jme3/system/awt/AwtPanel.java

@@ -11,9 +11,11 @@ import com.jme3.util.Screenshots;
 import java.awt.AWTException;
 import java.awt.AWTException;
 import java.awt.BufferCapabilities;
 import java.awt.BufferCapabilities;
 import java.awt.Canvas;
 import java.awt.Canvas;
+import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Graphics2D;
 import java.awt.Image;
 import java.awt.Image;
 import java.awt.ImageCapabilities;
 import java.awt.ImageCapabilities;
+import java.awt.RenderingHints;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentEvent;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.AffineTransform;
@@ -32,14 +34,16 @@ public class AwtPanel extends Canvas implements SceneProcessor {
     private FrameBuffer fb;
     private FrameBuffer fb;
     private ByteBuffer byteBuf;
     private ByteBuffer byteBuf;
     private IntBuffer intBuf;
     private IntBuffer intBuf;
-    private boolean activeUpdates = true;
     private RenderManager rm;
     private RenderManager rm;
+    private PaintMode paintMode;
     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>(); 
     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>(); 
     
     
     // Visibility/drawing vars
     // Visibility/drawing vars
     private BufferStrategy strategy;
     private BufferStrategy strategy;
     private AffineTransformOp transformOp;
     private AffineTransformOp transformOp;
-    private AtomicBoolean visible = new AtomicBoolean(false);
+    private AtomicBoolean hasNativePeer = new AtomicBoolean(false);
+    private AtomicBoolean showing = new AtomicBoolean(false);
+    private AtomicBoolean repaintRequest = new AtomicBoolean(false);
     
     
     // Reshape vars
     // Reshape vars
     private int newWidth  = 1;
     private int newWidth  = 1;
@@ -47,10 +51,13 @@ public class AwtPanel extends Canvas implements SceneProcessor {
     private AtomicBoolean reshapeNeeded  = new AtomicBoolean(false);
     private AtomicBoolean reshapeNeeded  = new AtomicBoolean(false);
     private final Object lock = new Object();
     private final Object lock = new Object();
     
     
-    public AwtPanel(boolean activeUpdates){
-        this.activeUpdates = activeUpdates;
+    public AwtPanel(PaintMode paintMode){
+        this.paintMode = paintMode;
+        
+        if (paintMode == PaintMode.Accelerated){
+            setIgnoreRepaint(true);
+        }
         
         
-        setIgnoreRepaint(true);
         addComponentListener(new ComponentAdapter(){
         addComponentListener(new ComponentAdapter(){
             @Override
             @Override
             public void componentResized(ComponentEvent e) {
             public void componentResized(ComponentEvent e) {
@@ -73,7 +80,7 @@ public class AwtPanel extends Canvas implements SceneProcessor {
         super.addNotify();
         super.addNotify();
 
 
         synchronized (lock){
         synchronized (lock){
-            visible.set(true);
+            hasNativePeer.set(true);
             System.out.println("EDT: addNotify");
             System.out.println("EDT: addNotify");
         }
         }
         
         
@@ -83,58 +90,102 @@ public class AwtPanel extends Canvas implements SceneProcessor {
     @Override
     @Override
     public void removeNotify(){
     public void removeNotify(){
         synchronized (lock){
         synchronized (lock){
-            visible.set(false);
-//            strategy.dispose();
-//            strategy = null;
+            hasNativePeer.set(false);
             System.out.println("EDT: removeNotify");
             System.out.println("EDT: removeNotify");
         }
         }
         
         
         super.removeNotify();
         super.removeNotify();
     }
     }
     
     
-    public void drawFrameInThread(){
-        if (!visible.get()){
+    @Override
+    public void paint(Graphics g){
+        Graphics2D g2d = (Graphics2D) g;
+        synchronized (lock){
+            g2d.drawImage(img, transformOp, 0, 0);
+        }
+    }
+    
+    public boolean checkVisibilityState(){
+        if (!hasNativePeer.get()){
             if (strategy != null){
             if (strategy != null){
                 strategy.dispose();
                 strategy.dispose();
                 strategy = null;
                 strategy = null;
+                System.out.println("OGL: Not visible. Destroy strategy.");
             }
             }
-            return;
+            return false;
         }
         }
-
-        if (strategy == null || strategy.contentsLost()){
-            if (strategy != null){
-                strategy.dispose();
-            }
-            try {
-                createBufferStrategy(1, new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.UNDEFINED));
-            } catch (AWTException ex) {
-                ex.printStackTrace();
+        
+        boolean currentShowing = isShowing();
+        if (showing.getAndSet(currentShowing) != currentShowing){
+            if (currentShowing){
+                System.out.println("OGL: Enter showing state.");
+            }else{
+                System.out.println("OGL: Exit showing state.");
             }
             }
-            strategy = getBufferStrategy();
-            System.out.println("OGL: BufferStrategy lost!");
         }
         }
-
-        Graphics2D g2d;
+        return currentShowing;
+    }
+    
+    public void repaintInThread(){
+        // Convert screenshot.
+        byteBuf.clear();
+        rm.getRenderer().readFrameBuffer(fb, byteBuf);
         
         
         synchronized (lock){
         synchronized (lock){
-            g2d = (Graphics2D) strategy.getDrawGraphics();
+            // All operations on img must be synchronized
+            // as it is accessed from EDT.
+            Screenshots.convertScreenShot2(intBuf, img);
+            repaint();
         }
         }
-        
-        g2d.drawImage(img, transformOp, 0, 0);
-        g2d.dispose();
-        strategy.show();        
     }
     }
     
     
-    public boolean isActiveUpdates() {
-        return activeUpdates;
-    }
-
-    public void setActiveUpdates(boolean activeUpdates) {
+    public void drawFrameInThread(){
+        // Convert screenshot.
+        byteBuf.clear();
+        rm.getRenderer().readFrameBuffer(fb, byteBuf);
+        Screenshots.convertScreenShot2(intBuf, img);
+        
         synchronized (lock){
         synchronized (lock){
-            this.activeUpdates = activeUpdates;
+            // All operations on strategy should be synchronized (?)
+            if (strategy == null){
+                try {
+                    createBufferStrategy(1, 
+                            new BufferCapabilities(
+                                new ImageCapabilities(true), 
+                                new ImageCapabilities(true), 
+                                BufferCapabilities.FlipContents.UNDEFINED)
+                                        );
+                } catch (AWTException ex) {
+                    ex.printStackTrace();
+                }
+                strategy = getBufferStrategy();
+                System.out.println("OGL: Visible. Create strategy.");
+            }
+            
+            // Draw screenshot.
+            do {
+                do {
+                    Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
+                    if (g2d == null){
+                        System.out.println("OGL: DrawGraphics was null.");
+                        return;
+                    }
+                    
+                    g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
+                                         RenderingHints.VALUE_RENDER_SPEED);
+                    
+                    g2d.drawImage(img, transformOp, 0, 0);
+                    g2d.dispose();
+                    strategy.show();
+                } while (strategy.contentsRestored());
+            } while (strategy.contentsLost());
         }
         }
     }
     }
     
     
+    public boolean isActiveDrawing(){
+        return paintMode != PaintMode.OnRequest && showing.get();
+    }
+    
     public void attachTo(ViewPort ... vps){
     public void attachTo(ViewPort ... vps){
         if (viewPorts.size() > 0){
         if (viewPorts.size() > 0){
             for (ViewPort vp : viewPorts){
             for (ViewPort vp : viewPorts){
@@ -158,14 +209,19 @@ public class AwtPanel extends Canvas implements SceneProcessor {
     private void reshapeInThread(int width, int height) {
     private void reshapeInThread(int width, int height) {
         byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
         byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
         intBuf = byteBuf.asIntBuffer();
         intBuf = byteBuf.asIntBuffer();
+        
         fb = new FrameBuffer(width, height, 1);
         fb = new FrameBuffer(width, height, 1);
         fb.setDepthBuffer(Format.Depth);
         fb.setDepthBuffer(Format.Depth);
         fb.setColorBuffer(Format.RGB8);
         fb.setColorBuffer(Format.RGB8);
         
         
-        img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        synchronized (lock){
+            img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        }
+        
 //        synchronized (lock){
 //        synchronized (lock){
 //            img = (BufferedImage) getGraphicsConfiguration().createCompatibleImage(width, height);
 //            img = (BufferedImage) getGraphicsConfiguration().createCompatibleImage(width, height);
 //        }
 //        }
+        
         AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
         AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
         tx.translate(0, -img.getHeight());
         tx.translate(0, -img.getHeight());
         transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
         transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
@@ -173,6 +229,12 @@ public class AwtPanel extends Canvas implements SceneProcessor {
         for (ViewPort vp : viewPorts){
         for (ViewPort vp : viewPorts){
             vp.setOutputFrameBuffer(fb);
             vp.setOutputFrameBuffer(fb);
             vp.getCamera().resize(width, height, true);
             vp.getCamera().resize(width, height, true);
+            
+            // NOTE: Hack alert. This is done ONLY for custom framebuffers.
+            // Main framebuffer should use RenderManager.notifyReshape().
+            for (SceneProcessor sp : vp.getProcessors()){
+                sp.reshape(vp, width, height);
+            }
         }
         }
     }
     }
 
 
@@ -185,6 +247,12 @@ public class AwtPanel extends Canvas implements SceneProcessor {
 
 
     public void postQueue(RenderQueue rq) {
     public void postQueue(RenderQueue rq) {
     }
     }
+    
+    @Override
+    public void invalidate(){
+        // For "PaintMode.OnDemand" only.
+        repaintRequest.set(true);
+    }
 
 
     public void postFrame(FrameBuffer out) {
     public void postFrame(FrameBuffer out) {
         if (out != fb){
         if (out != fb){
@@ -193,13 +261,25 @@ public class AwtPanel extends Canvas implements SceneProcessor {
         
         
         if (reshapeNeeded.getAndSet(false)){
         if (reshapeNeeded.getAndSet(false)){
             reshapeInThread(newWidth, newHeight);
             reshapeInThread(newWidth, newHeight);
-        }else if (activeUpdates){
-            byteBuf.clear();
-            rm.getRenderer().readFrameBuffer(fb, byteBuf);
-            Screenshots.convertScreenShot2(intBuf, img);
-            drawFrameInThread();
+        }else{
+            if (!checkVisibilityState()){
+                return;
+            }
+            
+            switch (paintMode){
+                case Accelerated:
+                    drawFrameInThread();
+                    break;
+                case Repaint:
+                    repaintInThread();
+                    break;
+                case OnRequest:
+                    if (repaintRequest.getAndSet(false)){
+                        repaintInThread();
+                    }
+                    break;
+            }
         }
         }
-        
     }
     }
     
     
     public void reshape(ViewPort vp, int w, int h) {
     public void reshape(ViewPort vp, int w, int h) {

+ 32 - 3
engine/src/desktop/com/jme3/system/awt/AwtPanelsContext.java

@@ -25,6 +25,8 @@ public class AwtPanelsContext implements JmeContext {
     protected AwtMouseInput mouseInput = new AwtMouseInput();
     protected AwtMouseInput mouseInput = new AwtMouseInput();
     protected AwtKeyInput keyInput = new AwtKeyInput();
     protected AwtKeyInput keyInput = new AwtKeyInput();
     
     
+    protected boolean lastThrottleState = false;
+    
     private class AwtPanelsListener implements SystemListener {
     private class AwtPanelsListener implements SystemListener {
 
 
         public void initialize() {
         public void initialize() {
@@ -119,8 +121,8 @@ public class AwtPanelsContext implements JmeContext {
     public AwtPanelsContext(){
     public AwtPanelsContext(){
     }
     }
     
     
-    public AwtPanel createPanel(boolean activeUpdates){
-        AwtPanel panel = new AwtPanel(activeUpdates);
+    public AwtPanel createPanel(PaintMode paintMode){
+        AwtPanel panel = new AwtPanel(paintMode);
         panels.add(panel);
         panels.add(panel);
         return panel;
         return panel;
     }
     }
@@ -130,6 +132,32 @@ public class AwtPanelsContext implements JmeContext {
     }
     }
     
     
     private void updateInThread(){
     private void updateInThread(){
+        // Check if throttle required
+        boolean needThrottle = true;
+        
+        for (AwtPanel panel : panels){
+            if (panel.isActiveDrawing()){
+                needThrottle = false;
+                break;
+            }
+        }
+        
+        if (lastThrottleState != needThrottle){
+            lastThrottleState = needThrottle;
+            if (lastThrottleState){
+                System.out.println("OGL: Throttling update loop.");
+            }else{
+                System.out.println("OGL: Ceased throttling update loop.");
+            }
+        }
+        
+        if (needThrottle){
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+            }
+        }
+        
         listener.update();
         listener.update();
     }
     }
     
     
@@ -146,8 +174,9 @@ public class AwtPanelsContext implements JmeContext {
     }
     }
 
 
     public void create(boolean waitFor) {
     public void create(boolean waitFor) {
-        if (actualContext != null)
+        if (actualContext != null){
             throw new IllegalStateException("Already created");
             throw new IllegalStateException("Already created");
+        }
         
         
         actualContext = JmeSystem.newContext(settings, Type.OffscreenSurface);
         actualContext = JmeSystem.newContext(settings, Type.OffscreenSurface);
         actualContext.setSystemListener(new AwtPanelsListener());
         actualContext.setSystemListener(new AwtPanelsListener());

+ 9 - 8
engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -1633,15 +1633,16 @@ public class LwjglRenderer implements Renderer {
 
 
             assert fb.getId() >= 0;
             assert fb.getId() >= 0;
             assert context.boundFBO == fb.getId();
             assert context.boundFBO == fb.getId();
+            
             lastFb = fb;
             lastFb = fb;
-        }
-        
-        try {
-            checkFrameBufferError();
-        } catch (IllegalStateException ex) {
-            logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb);
-            printRealFrameBufferInfo(fb);
-            throw ex;
+            
+            try {
+                checkFrameBufferError();
+            } catch (IllegalStateException ex) {
+                logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb);
+                printRealFrameBufferInfo(fb);
+                throw ex;
+            }
         }
         }
     }
     }
 
 

+ 1 - 6
engine/src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java

@@ -114,17 +114,12 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
             pbuffer.destroy();
             pbuffer.destroy();
             try{
             try{
                 pbuffer = new Pbuffer(width, height, pixelFormat, null);
                 pbuffer = new Pbuffer(width, height, pixelFormat, null);
+                pbuffer.makeCurrent();
             }catch (LWJGLException ex){
             }catch (LWJGLException ex){
                 listener.handleError("Failed to restore pbuffer content", ex);
                 listener.handleError("Failed to restore pbuffer content", ex);
             }
             }
         }
         }
 
 
-        try{
-            pbuffer.makeCurrent();
-        }catch (LWJGLException ex){
-            listener.handleError( "Error occured while making pbuffer current", ex);
-        }
-
         listener.update();
         listener.update();
         assert checkGLError();
         assert checkGLError();
         
         

+ 3 - 2
engine/src/test/jme3test/awt/TestAwtPanels.java

@@ -8,6 +8,7 @@ import com.jme3.scene.shape.Box;
 import com.jme3.system.AppSettings;
 import com.jme3.system.AppSettings;
 import com.jme3.system.awt.AwtPanel;
 import com.jme3.system.awt.AwtPanel;
 import com.jme3.system.awt.AwtPanelsContext;
 import com.jme3.system.awt.AwtPanelsContext;
+import com.jme3.system.awt.PaintMode;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.awt.Toolkit;
 import java.awt.Toolkit;
@@ -56,11 +57,11 @@ public class TestAwtPanels extends SimpleApplication {
         SwingUtilities.invokeLater(new Runnable(){
         SwingUtilities.invokeLater(new Runnable(){
             public void run(){
             public void run(){
                 final AwtPanelsContext ctx = (AwtPanelsContext) app.getContext();
                 final AwtPanelsContext ctx = (AwtPanelsContext) app.getContext();
-                panel = ctx.createPanel(true);
+                panel = ctx.createPanel(PaintMode.Accelerated);
                 panel.setPreferredSize(new Dimension(400, 300));
                 panel.setPreferredSize(new Dimension(400, 300));
                 ctx.setInputSource(panel);
                 ctx.setInputSource(panel);
                 
                 
-                panel2 = ctx.createPanel(true);
+                panel2 = ctx.createPanel(PaintMode.Accelerated);
                 panel2.setPreferredSize(new Dimension(400, 300));
                 panel2.setPreferredSize(new Dimension(400, 300));
                 
                 
                 createWindowForPanel(panel, 300);
                 createWindowForPanel(panel, 300);