Display.setParent(canvas) on Mac

Started by eczkchtl, April 16, 2009, 14:45:21

Previous topic - Next topic

eczkchtl

I'm trying to do my opengl rendering to a canvas inside a swing JFrame. The code I've set up works on Windows and Linux but not on Mac for some reason. Heres a small example I put together:

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.security.AccessController;
import java.security.PrivilegedAction;

import javax.swing.*;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.*;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;

public class DisplayTest extends JFrame {
	private static final long serialVersionUID = 1L;
	
	public static boolean closing = false;
	public static boolean closed = false;

	public static class Game extends BasicGame {
		public Game() {
			super("Mac Display Test");
		}
		@Override
		public void init(GameContainer arg0) throws SlickException {
			
		}
		@Override
		public void update(GameContainer arg0, int arg1) throws SlickException {
			
		}
		public void render(GameContainer arg0, Graphics g) throws SlickException {
			g.getFont().drawString(60, 60, "It's working");
		}
	}
	
	public static class Container extends AppGameContainer {
		public Container(Game game) throws SlickException {
			super(game);
		}
		
		@Override
		public void start() throws SlickException {
			try {
				if (targetDisplayMode == null) {
					setDisplayMode(640,480,false);
				}
		
				Display.setTitle(game.getTitle());
		
				Log.info("LWJGL Version: "+Sys.getVersion());
				Log.info("OriginalDisplayMode: "+originalDisplayMode);
				Log.info("TargetDisplayMode: "+targetDisplayMode);
				
				AccessController.doPrivileged(new PrivilegedAction() {
		            public Object run() {
		        		try {
		        			PixelFormat format = new PixelFormat(8,8,0);
		        			if (SHARED_DRAWABLE == null) 
		        			{
		        				Display.create(format);
		        			}
		        			else
		        			{
		        				Display.create(format, SHARED_DRAWABLE);
		        			}
		        		} catch (Exception e) {
		        			Log.error(e);
		        			
		        			alphaSupport = false;
		        			Display.destroy();
		        			// if we couldn't get alpha, let us know
			        		try {
			        			if (SHARED_DRAWABLE == null) 
			        			{
			        				Display.create();
			        			}
			        			else
			        			{
			        				Display.create(new PixelFormat(), SHARED_DRAWABLE);
			        			}
			        		} catch (Exception x) {
			        			Log.error(x);
			        		}
		        		}
						
						return null;
		            }});
				
				if (!Display.isCreated()) {
					throw new SlickException("Failed to initialise the LWJGL display");
				}
				
				initSystem();
				enterOrtho();

				try {
					getInput().initControllers();
				} catch (SlickException e) {
					Log.info("Controllers not available");
				} catch (Throwable e) {
					Log.info("Controllers not available");
				}
				
				try {
					game.init(this);
				} catch (SlickException e) {
					Log.error(e);
					running = false;
				}
				
				getDelta();
				while (running()) {
					int delta = getDelta();
					
					if (!Display.isVisible() && updateOnlyOnVisible) {
						try { Thread.sleep(100); } catch (Exception e) {}
					} else {
						try {
							updateAndRender(delta);
						} catch (SlickException e) {
							Log.error(e);
							running = false;
							break;
						}
					}
					
					updateFPS();
					
					if (input.isKeyPressed(Input.KEY_ESCAPE)) {}
		
					Display.update();
					
					if (closing) {
						running = false;
					}
					
					if (Display.isCloseRequested()) {
						Log.info("Display close requested");
						/*if (game.closeRequested()) {
							running = false;
						}*/
					}
				}
			} finally {
				AL.destroy();
				//Display.destroy();
			}
			
			Log.info("Closing game");
			
			/*if (forceExit) {
				System.exit(0);
			}*/			
		}
	}
	
	public static void main(String[] args) throws LWJGLException, InterruptedException, SlickException {
		Log.info("LWJGL Version: "+Sys.getVersion());
		Log.info("Classpath: " + System.getProperties().get("java.class.path"));
		Log.info("Java VM: " + System.getProperties().get("java.vm.version"));
		Log.info("Java Runtime: " + System.getProperties().get("java.runtime.version"));
		Log.info("OS Name: " + System.getProperties().get("os.name"));		
		
		DisplayTest test = new DisplayTest();
		test.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		test.addWindowListener(new WindowAdapter() {
			public void windowClosed(WindowEvent arg0) {
				Log.info("Window closed");
				
			}
			public void windowClosing(WindowEvent arg0) {
				Log.info("Window closing");
				closing = true;
				while (!closed) {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		test.setVisible(true);
		
		if (args.length == 0) {
			Display.setParent(test.c);
			Log.info("Using parent canvas");
		} else {
			Log.info("Using separate window");
		}
		
		Container app = new Container(new Game());  
		app.setDisplayMode(640, 480, false);  
		app.start();
		
		Display.setParent(null);
		Display.destroy();
		
		closed = true;
	}
	
	Canvas c;
	
	public DisplayTest() {
		JPanel p = new JPanel();
		p.setPreferredSize(new Dimension(800,600));
		c = new Canvas();
		c.setBackground(Color.red);
		c.setSize(new Dimension(640,480));
		p.add(c);
		add(p);
		this.pack();
	}
}


Or a more readable version: http://codeviewer.org/view/code:753

It uses Slick to display text but I don't think the problem is related to Slick. I got it working for Windows long ago but postponed the Mac version to work on the actual project.

I would appreciate it if someone would have a look and check if something is wrong.

Also if you're a Mac user you could download and try the example (you would need the slick.jar and lwjgl.jar). I can upload a self-contained eclipse project tomorrow if someones interested.

eczkchtl

I got one person to test it on Mac and apparently it did work and it displayes the "It's working" text. However it wasn't possible to close the program and it had to be killed manually. We're using slick build #240 and lwjgl 2.0b1 by the way.

In the actual program I also need to toggle the visibility of the canvas so in the same JFrame I either show a text box or the canvas with opengl rendering. This works well on Windows and Linux but not on Mac. And since I don't have a Mac testing becomes cumbersome :)

How is the window dispose supposed to be done? Should you set the JFrame to DISPOSE_ON_CLOSE or DO_NOTHING_ON_CLOSE and when should the call to Display.destroy() occur? Currently I use DO_NOTHING_ON_CLOSE, set a flag in windowClosing() so the main thread can exit the game loop and call Display.destroy() and then I call frame.dispose(). If someone has code which they know works on Mac (doesn't hang when closing the JFrame) it would be nice if you posted it here.

broumbroum

I've impl. a AWTGLCanvas rendering that runs fine on Linux Windows and Mac OS X.
For your code sample is long, it's difficult to see where the stuff bugs. But, as I scrolled down to the end, I see that you extended JFrame and added then a JPanel in which you put the Canvas. This is locking an AWT EDT, and therefore you better change
AccessController.doPrivileged(new PrivilegedAction() {
		            public Object run() {
		        		}});
within the while(running) {} loop and
SwingUtilities.invokeAndWait(new Runnable() { public run() {
renderandupdate();
}});
that is safer and usually faster.
Plus, you may try the AWTGLCanvas instead of the Canvas; that'd be useless to setVisible()  the Canvas thereafter. :-[

lolcats