* 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
This commit is contained in:
parent
a9f2df066a
commit
e3bff6d62a
@ -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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
strategy = getBufferStrategy();
|
||||
System.out.println("OGL: BufferStrategy lost!");
|
||||
}
|
||||
|
||||
Graphics2D g2d;
|
||||
|
||||
synchronized (lock){
|
||||
g2d = (Graphics2D) strategy.getDrawGraphics();
|
||||
return false;
|
||||
}
|
||||
|
||||
g2d.drawImage(img, transformOp, 0, 0);
|
||||
g2d.dispose();
|
||||
strategy.show();
|
||||
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.");
|
||||
}
|
||||
}
|
||||
return currentShowing;
|
||||
}
|
||||
|
||||
public boolean isActiveUpdates() {
|
||||
return activeUpdates;
|
||||
}
|
||||
|
||||
public void setActiveUpdates(boolean activeUpdates) {
|
||||
public void repaintInThread(){
|
||||
// Convert screenshot.
|
||||
byteBuf.clear();
|
||||
rm.getRenderer().readFrameBuffer(fb, byteBuf);
|
||||
|
||||
synchronized (lock){
|
||||
this.activeUpdates = activeUpdates;
|
||||
// All operations on img must be synchronized
|
||||
// as it is accessed from EDT.
|
||||
Screenshots.convertScreenShot2(intBuf, img);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawFrameInThread(){
|
||||
// Convert screenshot.
|
||||
byteBuf.clear();
|
||||
rm.getRenderer().readFrameBuffer(fb, byteBuf);
|
||||
Screenshots.convertScreenShot2(intBuf, img);
|
||||
|
||||
synchronized (lock){
|
||||
// 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…
x
Reference in New Issue
Block a user