package com.jogamp.opengl.test.bugs; import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Frame; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.common.util.InterruptSource; import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.LandscapeES2; import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; /** * Difference to orig. Bug735Inv0AppletAWT: * <pre> * - Use GLEventListener * - Add GLEventListener to GLAutoDrawable * - Use GLAutoDrawable.display() instead of GLAutoDrawable.invoke(true, GLRunnable { init / render }) * - Removed MANUAL_FRAME_HANDLING, obsolete due to GLAutoDrawable/GLEventListener * </pre> * OSX Results: * <pre> * - Visible content * - Fluent animation * </pre> */ @SuppressWarnings("serial") public class Bug735Inv2AppletAWT extends Applet implements Runnable { static public final int AWT = 0; static public final int NEWT = 1; static public final int APPLET_WIDTH = 500; static public final int APPLET_HEIGHT = 290; static public final int TARGET_FPS = 120; static public final int TOOLKIT = NEWT; static public final boolean IGNORE_AWT_REPAINT = false; static public boolean USE_ECT = false; static public int SWAP_INTERVAL = 1; ////////////////////////////////////////////////////////////////////////////// static boolean waitForKey = false; static private Frame frame; static private Bug735Inv2AppletAWT applet; private GLCanvas awtCanvas; private GLWindow newtWindow; private GLAutoDrawable glad; private NewtCanvasAWT newtCanvas; private GLEventListener demo; private int width; private int height; private Thread thread; private final long frameRatePeriod = 1000000000L / TARGET_FPS; private int frameCount; public void init() { setSize(APPLET_WIDTH, APPLET_HEIGHT); setPreferredSize(new Dimension(APPLET_WIDTH, APPLET_HEIGHT)); width = APPLET_WIDTH; height = APPLET_HEIGHT; initGL(); } public void start() { initDraw(); thread = new InterruptSource.Thread(null, this, "Animation Thread"); thread.start(); } public void run() { int noDelays = 0; // Number of frames with a delay of 0 ms before the // animation thread yields to other running threads. final int NO_DELAYS_PER_YIELD = 15; final int TIMEOUT_SECONDS = 2; long beforeTime = System.nanoTime(); long overSleepTime = 0L; frameCount = 1; while (Thread.currentThread() == thread) { if (frameCount == 1) { EventQueue.invokeLater(new Runnable() { public void run() { requestFocusInWindow(); } }); if( USE_ECT ) { glad.setExclusiveContextThread(thread); } } final CountDownLatch latch = new CountDownLatch(1); requestDraw(latch); try { latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS); } catch (final InterruptedException e) { e.printStackTrace(); } final long afterTime = System.nanoTime(); final long timeDiff = afterTime - beforeTime; final long sleepTime = (frameRatePeriod - timeDiff) - overSleepTime; if (sleepTime > 0) { // some time left in this cycle try { Thread.sleep(sleepTime / 1000000L, (int) (sleepTime % 1000000L)); noDelays = 0; // Got some sleep, not delaying anymore } catch (final InterruptedException ex) { } overSleepTime = (System.nanoTime() - afterTime) - sleepTime; } else { // sleepTime <= 0; the frame took longer than the period overSleepTime = 0L; noDelays++; if (noDelays > NO_DELAYS_PER_YIELD) { Thread.yield(); // give another thread a chance to run noDelays = 0; } } beforeTime = System.nanoTime(); } } public void requestDraw(final CountDownLatch latch) { glad.display(); if (latch != null) { latch.countDown(); } } private void initGL() { final GLProfile profile = GLProfile.getDefault(); final GLCapabilities caps = new GLCapabilities(profile); caps.setBackgroundOpaque(true); caps.setOnscreen(true); caps.setSampleBuffers(false); if (TOOLKIT == AWT) { awtCanvas = new GLCanvas(caps); awtCanvas.setBounds(0, 0, applet.width, applet.height); awtCanvas.setBackground(new Color(0xFFCCCCCC, true)); awtCanvas.setFocusable(true); applet.setLayout(new BorderLayout()); applet.add(awtCanvas, BorderLayout.CENTER); if (IGNORE_AWT_REPAINT) { awtCanvas.setIgnoreRepaint(true); } glad = awtCanvas; } else if (TOOLKIT == NEWT) { newtWindow = GLWindow.create(caps); newtCanvas = new NewtCanvasAWT(newtWindow); newtCanvas.setBounds(0, 0, applet.width, applet.height); newtCanvas.setBackground(new Color(0xFFCCCCCC, true)); newtCanvas.setFocusable(true); applet.setLayout(new BorderLayout()); applet.add(newtCanvas, BorderLayout.CENTER); if (IGNORE_AWT_REPAINT) { newtCanvas.setIgnoreRepaint(true); } glad = newtWindow; } demo = new LandscapeES2(SWAP_INTERVAL); glad.addGLEventListener(demo); } private void initDraw() { if (TOOLKIT == AWT) { awtCanvas.setVisible(true); // Force the realization awtCanvas.display(); if (awtCanvas.getDelegatedDrawable().isRealized()) { // Request the focus here as it cannot work when the window is not visible awtCanvas.requestFocus(); } } else if (TOOLKIT == NEWT) { newtCanvas.setVisible(true); // Force the realization newtWindow.display(); if (newtWindow.isRealized()) { // Request the focus here as it cannot work when the window is not visible newtCanvas.requestFocus(); } } } static public void main(final String[] args) { for(int i=0; i<args.length; i++) { if(args[i].equals("-vsync")) { i++; SWAP_INTERVAL = MiscUtils.atoi(args[i], SWAP_INTERVAL); } else if(args[i].equals("-exclctx")) { USE_ECT = true; } else if(args[i].equals("-wait")) { waitForKey = true; } } System.err.println("swapInterval "+SWAP_INTERVAL); System.err.println("exclusiveContext "+USE_ECT); if(waitForKey) { JunitTracer.waitForKey("Start"); } final GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); final GraphicsDevice displayDevice = environment.getDefaultScreenDevice(); frame = new Frame(displayDevice.getDefaultConfiguration()); frame.setBackground(new Color(0xCC, 0xCC, 0xCC)); frame.setTitle("TestBug735Inv2AppletAWT"); try { final Class<?> c = Thread.currentThread().getContextClassLoader(). loadClass(Bug735Inv2AppletAWT.class.getName()); applet = (Bug735Inv2AppletAWT) c.newInstance(); } catch (final Exception e) { throw new RuntimeException(e); } frame.setLayout(null); frame.add(applet); frame.pack(); frame.setResizable(false); applet.init(); final Insets insets = frame.getInsets(); final int windowW = applet.width + insets.left + insets.right; final int windowH = applet.height + insets.top + insets.bottom; frame.setSize(windowW, windowH); final Rectangle screenRect = displayDevice.getDefaultConfiguration().getBounds(); frame.setLocation(screenRect.x + (screenRect.width - applet.width) / 2, screenRect.y + (screenRect.height - applet.height) / 2); final int usableWindowH = windowH - insets.top - insets.bottom; applet.setBounds((windowW - applet.width)/2, insets.top + (usableWindowH - applet.height)/2, applet.width, applet.height); // This allows to close the frame. frame.addWindowListener(new WindowAdapter() { public void windowClosing(final WindowEvent e) { System.exit(0); } }); frame.setVisible(true); applet.start(); } }