package p5.test_awt_applet; import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Timer; import java.util.TimerTask; import javax.media.opengl.*; import javax.media.opengl.awt.GLCanvas; import com.jogamp.opengl.util.AnimatorBase; public class MiniPApplet extends Applet implements MouseMotionListener { private static final long serialVersionUID = 1L; ///////////////////////////////////////////////////////////// // // Test parameters public int frameRate = 120; public int numSamples = 2; ///////////////////////////////////////////////////////////// // // Internal variables int width; int height; private Frame frame; private GLProfile profile; private GLCapabilities capabilities; private GLCanvas canvas; private SimpleListener listener; private CustomAnimator animator; private long beforeTime; private long overSleepTime; private long frameRatePeriod = 1000000000L / frameRate; private boolean initialized = false; private double theta = 0; private double s = 0; private double c = 0; private long millisOffset; private int fcount, lastm; private float frate; private int fint = 3; private boolean setFramerate = false; void run() { Thread loop = new Thread("Animation Thread") { public void run() { while (true) { if (!initialized) { setup(); } animator.requestRender(); clock(); } } }; loop.start(); } void setup() { millisOffset = System.currentTimeMillis(); // Frame setup ---------------------------------------------------------- width = 300; height = 300; MiniPApplet applet = this; GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice displayDevice = environment.getDefaultScreenDevice(); frame = new Frame(displayDevice.getDefaultConfiguration()); frame.setTitle("MiniPApplet"); frame.setLayout(null); frame.add(applet); frame.pack(); frame.setResizable(false); Insets insets = frame.getInsets(); int windowW = applet.width + insets.left + insets.right; int windowH = applet.height + insets.top + insets.bottom; int locationX = 100; int locationY = 100; frame.setSize(windowW, windowH); frame.setLocation(locationX, locationY); int usableWindowH = windowH - insets.top - insets.bottom; applet.setBounds((windowW - width)/2, insets.top + (usableWindowH - height)/2, width, height); frame.add(this); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); // Canvas setup ---------------------------------------------------------- profile = GLProfile.getDefault(); capabilities = new GLCapabilities(profile); capabilities.setSampleBuffers(true); capabilities.setNumSamples(numSamples); canvas = new GLCanvas(capabilities); canvas.setBounds(0, 0, width, height); this.setLayout(new BorderLayout()); this.add(canvas, BorderLayout.CENTER); canvas.addMouseMotionListener(this); // Setting up animation listener = new SimpleListener(); canvas.addGLEventListener(listener); animator = new CustomAnimator(canvas); animator.start(); initialized = true; } void restart() { System.out.println("Restarting surface..."); // Stopping animation, removing current canvas. animator.stop(); animator.remove(canvas); canvas.removeGLEventListener(listener); this.remove(canvas); capabilities = new GLCapabilities(profile); capabilities.setSampleBuffers(true); capabilities.setNumSamples(numSamples); canvas = new GLCanvas(capabilities); canvas.setBounds(0, 0, width, height); // Setting up animation again this.setLayout(new BorderLayout()); this.add(canvas, BorderLayout.CENTER); canvas.addMouseMotionListener(this); canvas.addGLEventListener(listener); animator.add(canvas); animator.start(); setFramerate = false; System.out.println("Done"); } void draw(GL2 gl) { if (!setFramerate) { if (60 < frameRate) { // Disables vsync gl.setSwapInterval(0); } else if (30 < frameRate) { gl.setSwapInterval(1); } else { gl.setSwapInterval(2); } setFramerate = true; } int[] temp = { 0 }; gl.glGetIntegerv(GL.GL_SAMPLES, temp, 0); if (numSamples != temp[0]) { System.err.println("Multisampling level requested " + numSamples + " not supported. Using " + temp[0] + " samples instead."); } gl.glClearColor(0, 0, 0, 1); gl.glClear(GL.GL_COLOR_BUFFER_BIT); theta += 0.01; s = Math.sin(theta); c = Math.cos(theta); gl.glBegin(GL.GL_TRIANGLES); gl.glColor3f(1, 0, 0); gl.glVertex2d(-c, -c); gl.glColor3f(0, 1, 0); gl.glVertex2d(0, c); gl.glColor3f(0, 0, 1); gl.glVertex2d(s, -s); gl.glEnd(); gl.glFlush(); fcount += 1; int m = (int) (System.currentTimeMillis() - millisOffset); if (m - lastm > 1000 * fint) { frate = (float)(fcount) / fint; fcount = 0; lastm = m; System.err.println("fps: " + frate); } } void clock() { long afterTime = System.nanoTime(); long timeDiff = afterTime - beforeTime; long sleepTime = (frameRatePeriod - timeDiff) - overSleepTime; if (sleepTime > 0) { // some time left in this cycle try { Thread.sleep(sleepTime / 1000000L, (int) (sleepTime % 1000000L)); } catch (InterruptedException ex) { } overSleepTime = (System.nanoTime() - afterTime) - sleepTime; } else { // sleepTime <= 0; the frame took longer than the period overSleepTime = 0L; } beforeTime = System.nanoTime(); } class SimpleListener implements GLEventListener { @Override public void display(GLAutoDrawable drawable) { draw(drawable.getGL().getGL2()); } @Override public void dispose(GLAutoDrawable drawable) { } @Override public void init(GLAutoDrawable drawable) { } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) { } } public void mouseDragged(MouseEvent ev) { System.err.println("Mouse dragged event: " + ev); } public void mouseMoved(MouseEvent ev) { System.err.println("Mouse moved event: " + ev); } public static void main(String[] args) { MiniPApplet mini; try { Class c = Thread.currentThread().getContextClassLoader().loadClass(MiniPApplet.class.getName()); mini = (MiniPApplet) c.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } if (mini != null) { mini.run(); } } /** An Animator subclass which renders one frame at the time * upon calls to the requestRender() method. **/ public class CustomAnimator extends AnimatorBase { private Timer timer = null; private TimerTask task = null; // private String threadName = null; private volatile boolean shouldRun; protected String getBaseName(String prefix) { return "Custom" + prefix + "Animator" ; } /** Creates an CustomAnimator with an initial drawable to * animate. */ public CustomAnimator(GLAutoDrawable drawable) { if (drawable != null) { add(drawable); } } // public void setThreadName(String name) { // threadName = name; // } public synchronized void requestRender() { shouldRun = true; } public final boolean isStarted() { stateSync.lock(); try { return (timer != null); } finally { stateSync.unlock(); } } public final boolean isAnimating() { stateSync.lock(); try { return (timer != null) && (task != null); } finally { stateSync.unlock(); } } private void startTask() { if(null != task) { return; } task = new TimerTask() { // private boolean firstRun = true; public void run() { // if (firstRun) { // if (threadName != null) Thread.currentThread().setName(threadName); // firstRun = false; // } if(CustomAnimator.this.shouldRun) { CustomAnimator.this.animThread = Thread.currentThread(); // display impl. uses synchronized block on the animator instance display(); synchronized (this) { // done with current frame. shouldRun = false; } } } }; fpsCounter.resetFPSCounter(); shouldRun = false; timer.schedule(task, 0, 1); } public synchronized boolean start() { if (timer != null) { return false; } stateSync.lock(); try { timer = new Timer(); startTask(); } finally { stateSync.unlock(); } return true; } /** Stops this CustomAnimator. */ public synchronized boolean stop() { if (timer == null) { return false; } stateSync.lock(); try { shouldRun = false; if(null != task) { task.cancel(); task = null; } if(null != timer) { timer.cancel(); timer = null; } animThread = null; try { Thread.sleep(20); // ~ 1/60 hz wait, since we can't ctrl stopped threads } catch (InterruptedException e) { } } finally { stateSync.unlock(); } return true; } public final boolean isPaused() { return false; } public synchronized boolean resume() { return false; } public synchronized boolean pause() { return false; } } }