Efficient JOGL machining cycle
I'm new to JOGL and I'm trying to figure out how to make a render loop with it ... I know there are animator and FPS classes that I can use, but they seem to be pretty restrictive. I've written a few render loops in the past that I like much better than I prefer to use, but I can't seem to implement it correctly with the JOGL GLEventListener class.
Here is my render loop (and the class it comes in)
package com.richardkase.game;
public class Game implements Runnable {
public final String TITLE = "Test Game";
private boolean running = false;
private Thread thread;
private FPSCounter fps;
////// Constructor //////
public Game() {
fps = new FPSCounter(150, 60);
}
////// Game Loop //////
@Override
public void run() {
while (running) {
fps.findDeltas();
// this executes at "the second argument" of fps times a second
if (fps.checkTickDelta())
tick();
// this executes at "the first argument" of fps times a second
if (fps.checkFrameDelta())
render();
// this code executes once a second
fps.checkPassingSecond();
}
}
////// Tick Methods //////
private void tick() {
long before = System.nanoTime();
// code goes here
fps.tick(before);
}
////// Render Methods //////
private void render() {
long before = System.nanoTime();
// code goes here
fps.render(before);
}
////// Thread Methods //////
private synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
System.exit(1);
e.printStackTrace();
}
}
///////// Main Method //////////
public static void main(String[] args) {
Game game = new Game();
JFrame frame = new JFrame(game.TITLE);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
}
here is the FPSCounter class just for reference, all it does is keep track of the time to make sure everything runs when it is supposed to
public class FPSCounter {
private long lastTime = System.nanoTime();
private double tickRate;
private double tickCheck;
private double tickDelta;
private double frameRate;
private double frameCheck;
private double frameDelta;
private int updates;
private int frames;
private long timer;
private long nanosPerFrame;
private long nanosPerUpdate;
////// Constructor ///////
public FPSCounter(double frameRate, double tickRate) {
this.frameRate = frameRate;
frameCheck = 1_000_000_000 / this.frameRate;
frameDelta = 0;
this.tickRate = tickRate;
tickCheck = 1_000_000_000 / this.tickRate;
tickDelta = 0;
updates = 0;
frames = 0;
timer = System.currentTimeMillis();
}
////// find delta //////
public void findDeltas() {
long now = System.nanoTime();
tickDelta += now - lastTime;
frameDelta += now - lastTime;
lastTime = now;
}
////// Delta Check //////
public boolean checkTickDelta() {
if (tickDelta >= tickCheck) {
tickDelta = 0;
return true;
}
return false;
}
public boolean checkFrameDelta() {
if (frameDelta >= frameCheck) {
frameDelta = 0;
return true;
}
return false;
}
////// Second Check //////
public void checkPassingSecond() {
if (System.currentTimeMillis() - timer > 1000) {
System.out.println(updates + " updates, fps is " + frames);
timer += 1000;
frames = 0;
updates = 0;
}
}
////// Game Loop Methods ///////
public void render(long before) {
long after = System.nanoTime();
nanosPerFrame = after - before;
frames++;
}
public void tick(long before) {
long after = System.nanoTime();
nanosPerUpdate = after - before;
updates++;
}
}
How do I add actual content to this game loop? should I have this class also extend the GLEventListener or have a reference to a class that extends it? Or is there a more efficient way to do this with an animator class that gives me the kind of control I'm overlooking?
any help would be greatly appreciated !! Thanks to
EDIT:
I must also add that I am very new to JOGL, found out about this a few days ago because I was trying to render things in 3d, so I hardly know more than the profile system in JOGL ... the explanations are GREAT appreciated!
I think I need to expand what I'm looking for here. I need a render loop that renders in a similar way above, where the game updates its state at one rate and redraws all graphics at a different rate.
source to share
This is how I got started with JOGL ... It's pretty simple and straightforward, but if required I can explain the code in detail;)
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;
import com.jogamp.opengl.util.FPSAnimator;
public class OpenGLMain implements GLEventListener {
private static FPSAnimator animator;
private static int width;
private static int height;
private static GL2 gl;
public static Rectangle screenSize;
public static JFrame frame;
public static void main(String[] args) {
GLProfile glprofile = GLProfile.getMaximum(true);
GLCapabilities capabilities = new GLCapabilities(glprofile);
GLCanvas canvas = new GLCanvas(capabilities);
screenSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
width = (int) screenSize.getWidth();
height = (int) screenSize.getHeight();
frame = new JFrame("Frame name");
frame.setAlwaysOnTop(false);
frame.setSize(width, height);
frame.add(canvas);
frame.setUndecorated(true);
frame.setVisible(true);
animator = new FPSAnimator(25);
animator.add(canvas);
animator.start();
canvas.addGLEventListener(new OpenGLMain());
canvas.requestFocus();
Listeners.keyClicks(canvas);
Listeners.mouseMovement(canvas);
Listeners.mouseClicks(canvas);
Listeners.mouseScrolled(canvas);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void display(GLAutoDrawable drawable) {
update();
render(drawable);
}
public void dispose(GLAutoDrawable drawable) {
}
public void init(GLAutoDrawable drawable) {
gl = drawable.getGL().getGL2();
Scenes.init(drawable, gl);
}
public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4) {
}
private void update() {
Scenes.update();
}
private void render(GLAutoDrawable drawable) {
Scenes.render(drawable);
}
}
public class OpenGLMain implements GLEventListener {
This line allows you to implement the GLEvents that come with JOGL
GLProfile glprofile = GLProfile.getMaximum(true);
GLCapabilities capabilities = new GLCapabilities(glprofile);
GLCanvas canvas = new GLCanvas(capabilities);
This will get the largest possible openGL context to use in the canvas
screenSize = GraphicsEnvironment .getLocalGraphicsEnvironment() .getMaximumWindowBounds(); width = (int) screenSize.getWidth(); height = (int) screenSize.getHeight();
The maximum window borders will give you a comfortable place on your desktop, but you can simply set the width and height to whatever size you want ...
frame = new JFrame("Frame name");
frame.setAlwaysOnTop(false);
frame.setSize(width, height);
frame.add(canvas);
frame.setUndecorated(true);
frame.setVisible(true);
This is the JFrame that will hold the OpenGL canvas. You can customize it the way you like :)
animator = new FPSAnimator(25);
animator.add(canvas);
animator.start();
This creates the animator at a frame rate of 25 frames per second, connects it to the canvas, and starts the animator thread
canvas.addGLEventListener(new OpenGLMain());
canvas.requestFocus();
This will add a GLEvent listener to the newly instantiated instance of your class, but I guess this is the point where you inject a separate GLEventListener class
Listeners.keyClicks(canvas);
Listeners.mouseMovement(canvas);
Listeners.mouseClicks(canvas);
Listeners.mouseScrolled(canvas);
This is my way of triggering listeners for keys, mouse movement, clicks and scrolls ... it's in a separate static class
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
It's just a listener for the window close event ...
public void display(GLAutoDrawable drawable) {
update();
render(drawable);
}
This is where the main loop comes in ... I split it into methods update();
and render();
so that everything is updated before it happens.
public void init(GLAutoDrawable drawable) {
gl = drawable.getGL().getGL2();
Scenes.init(drawable, gl);
}
An init method that happens before rendering ... I have a separate static Scenes class where I create layers and a logical structure of scenes to paint on the canvas.
source to share