I am new to JOGL and I am trying to figure out how to make a render loop with it... I know that there is the animator and FPS animator classes that I can use, but they seem fairly restrictive. I have written a few render loops in the past that I like a lot better that I would rather use but I can't seem to properly implement it with JOGL's 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 FPSCounter class just for reference, all it does is keep track of time to make sure everything executes when it is suppose 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 should I add the actual content to this game loop? should I have this class also extend GLEventListener or have a reference to a class that extends it? Or is there a more efficient way of doing it with the animator class that gives me the this kind of control that I am overlooking?
any help would be greatly appreciated!! Thanks
EDIT:
I should also add that I am very new to JOGL, found out about it a few days ago because I was trying to render things in 3d, so I barely know more than the profile system in JOGL... explainations are GREATLY appreciated!
I think I should layout what I'm looking for here. I need a rendering loop that renders in a similar way above, where the game updates its state at one rate, and redraws all the graphics at another rate.
This is how I started with JOGL... It is pretty straightforward and self-explanatory, but if requested, 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 GLEvents that come with JOGL
GLProfile glprofile = GLProfile.getMaximum(true);
GLCapabilities capabilities = new GLCapabilities(glprofile);
GLCanvas canvas = new GLCanvas(capabilities);
This will get the maximum possible openGL context to use in the canvas
screenSize = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getMaximumWindowBounds();
width = (int) screenSize.getWidth();
height = (int) screenSize.getHeight();
Maximum window bounds will give you usable desktop space, but you could just set width and height to any other 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 set it up any way you like :)
animator = new FPSAnimator(25);
animator.add(canvas);
animator.start();
This creates animator with framerate of 25fps, 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 created instance of your class, but I guess this is the point at which you would insert a separate GLEventListener class
Listeners.keyClicks(canvas);
Listeners.mouseMovement(canvas);
Listeners.mouseClicks(canvas);
Listeners.mouseScrolled(canvas);
This is my way of starting listeners for keys, mouse movement, clicks and scrolls... it is located in a separate static class
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
This is just a listener for window closing event...
public void display(GLAutoDrawable drawable) {
update();
render(drawable);
}
Here is where the main loop happens... I've split it up into update();
and render();
methods, so that everything gets updated before it gets rendered.
public void init(GLAutoDrawable drawable) {
gl = drawable.getGL().getGL2();
Scenes.init(drawable, gl);
}
The init method that happens before rendering... I have a separate static class Scenes, where I create layers and logical structure of the scenes to draw on canvas.