* 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
3.0
sha..rd 14 years ago
parent a9f2df066a
commit e3bff6d62a
  1. 7
      engine/src/desktop/com/jme3/input/awt/AwtMouseInput.java
  2. 166
      engine/src/desktop/com/jme3/system/awt/AwtPanel.java
  3. 35
      engine/src/desktop/com/jme3/system/awt/AwtPanelsContext.java
  4. 17
      engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java
  5. 7
      engine/src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java
  6. 5
      engine/src/test/jme3test/awt/TestAwtPanels.java

@ -148,6 +148,9 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
public void setCursorVisible(boolean visible){
if (this.visible != visible){
lastKnownLocation.x = lastKnownLocation.y = 0;
this.visible = visible;
final boolean newVisible = visible;
SwingUtilities.invokeLater(new Runnable() {
@ -168,7 +171,9 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
int newWheel = wheelPos;
// 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,
lastEventY - newY,
wheelPos, lastEventWheel - wheelPos);

@ -11,9 +11,11 @@ import com.jme3.util.Screenshots;
import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.ImageCapabilities;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.AffineTransform;
@ -32,14 +34,16 @@ public class AwtPanel extends Canvas implements SceneProcessor {
private FrameBuffer fb;
private ByteBuffer byteBuf;
private IntBuffer intBuf;
private boolean activeUpdates = true;
private RenderManager rm;
private PaintMode paintMode;
private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
// Visibility/drawing vars
private BufferStrategy strategy;
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
private int newWidth = 1;
@ -47,10 +51,13 @@ public class AwtPanel extends Canvas implements SceneProcessor {
private AtomicBoolean reshapeNeeded = new AtomicBoolean(false);
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(){
@Override
public void componentResized(ComponentEvent e) {
@ -73,7 +80,7 @@ public class AwtPanel extends Canvas implements SceneProcessor {
super.addNotify();
synchronized (lock){
visible.set(true);
hasNativePeer.set(true);
System.out.println("EDT: addNotify");
}
@ -83,58 +90,102 @@ public class AwtPanel extends Canvas implements SceneProcessor {
@Override
public void removeNotify(){
synchronized (lock){
visible.set(false);
// strategy.dispose();
// strategy = null;
hasNativePeer.set(false);
System.out.println("EDT: 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){
strategy.dispose();
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){
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){
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){
if (viewPorts.size() > 0){
for (ViewPort vp : viewPorts){
@ -158,14 +209,19 @@ public class AwtPanel extends Canvas implements SceneProcessor {
private void reshapeInThread(int width, int height) {
byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
intBuf = byteBuf.asIntBuffer();
fb = new FrameBuffer(width, height, 1);
fb.setDepthBuffer(Format.Depth);
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){
// img = (BufferedImage) getGraphicsConfiguration().createCompatibleImage(width, height);
// }
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -img.getHeight());
transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
@ -173,6 +229,12 @@ public class AwtPanel extends Canvas implements SceneProcessor {
for (ViewPort vp : viewPorts){
vp.setOutputFrameBuffer(fb);
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) {
}
@Override
public void invalidate(){
// For "PaintMode.OnDemand" only.
repaintRequest.set(true);
}
public void postFrame(FrameBuffer out) {
if (out != fb){
@ -193,13 +261,25 @@ public class AwtPanel extends Canvas implements SceneProcessor {
if (reshapeNeeded.getAndSet(false)){
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) {

@ -25,6 +25,8 @@ public class AwtPanelsContext implements JmeContext {
protected AwtMouseInput mouseInput = new AwtMouseInput();
protected AwtKeyInput keyInput = new AwtKeyInput();
protected boolean lastThrottleState = false;
private class AwtPanelsListener implements SystemListener {
public void initialize() {
@ -119,8 +121,8 @@ public class AwtPanelsContext implements JmeContext {
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);
return panel;
}
@ -130,6 +132,32 @@ public class AwtPanelsContext implements JmeContext {
}
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();
}
@ -146,8 +174,9 @@ public class AwtPanelsContext implements JmeContext {
}
public void create(boolean waitFor) {
if (actualContext != null)
if (actualContext != null){
throw new IllegalStateException("Already created");
}
actualContext = JmeSystem.newContext(settings, Type.OffscreenSurface);
actualContext.setSystemListener(new AwtPanelsListener());

@ -1633,15 +1633,16 @@ public class LwjglRenderer implements Renderer {
assert fb.getId() >= 0;
assert context.boundFBO == fb.getId();
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;
}
}
}

@ -114,17 +114,12 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
pbuffer.destroy();
try{
pbuffer = new Pbuffer(width, height, pixelFormat, null);
pbuffer.makeCurrent();
}catch (LWJGLException 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();
assert checkGLError();

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

Loading…
Cancel
Save