glutDisplayFunc() in LWJGL?

Started by Kylearan, November 26, 2006, 18:59:37

Previous topic - Next topic

Kylearan

Hi,

I've used openGL a little bit using C++, and got used to the callback functions glutDisplayFunc(), glutMouseFunc() and glutKeyboardFunc(). Is there something equivalent to this in LWJGL?

The tutorials I've seen all use a polling main loop, something like this:

while (programRunning) {
    programLogic();
    display();
    if (some exit condition) programRunning = false;
}


This is probably fine for action games, but also uses up all the available CPU time. I'm using LWJGL for a turn-based strategy game where the program often has to wait for user input and nothing is changed on the screen, so it would be nice to have some kind of callback function, or a function to go idle until the screen has to be rendered again or some user input has happened.

Is there some kind of mechanism in LWJGL that supports this?

Thanks in advance,

       -Kylearan

aldacron

Quote from: "Kylearan"
I've used openGL a little bit using C++, and got used to the callback functions glutDisplayFunc(), glutMouseFunc() and glutKeyboardFunc(). Is there something equivalent to this in LWJGL?

FYI, GLUT is not part of OpenGL. It's just a third-party library developed by one guy in order to aid using OpenGL cross-platform, like SDL, GLFW, and even LWJGL. It sounds like you are associating the two as being related.

Quote
The tutorials I've seen all use a polling main loop, something like this:

while (programRunning) {
    programLogic();
    display();
    if (some exit condition) programRunning = false;
}


This is probably fine for action games, but also uses up all the available CPU time.

It doesn't have to use up all of the CPU time. Thread.yield will prevent that from happening.

QuoteI'm using LWJGL for a turn-based strategy game where the program often has to wait for user input and nothing is changed on the screen, so it would be nice to have some kind of callback function, or a function to go idle until the screen has to be rendered again or some user input has happened.

Even turn-based strategy games use the same game loop as other game types. To achieve what you want, you can still use a loop that polls for input -- just render only when needed and call Thread.yield at the end of your game loop. Alternatively, you could specify a set amount of time to sleep. Thread.yield is probably more efficient for what you want, though, as it surrenders the remainder of the timeslice allocated for a thread so that other threads/processes may run.

Regardless, whether you do it, LWJGL does it, Java does it, or it happens in the depths of the OS, something has to be polling for system events. Using the LWJGL native window, the only option is for you to do it. LWJGL's input classes do have an event mechanism, but you still have to poll them.

Kylearan

Hi,

Quote from: "aldacron"
FYI, GLUT is not part of OpenGL. It's just a third-party library developed by one guy in order to aid using OpenGL cross-platform, like SDL, GLFW, and even LWJGL. It sounds like you are associating the two as being related.
I didn't know that indeed - I'm still quite new to OpenGL. Thanks!

QuoteIt doesn't have to use up all of the CPU time. Thread.yield will prevent that from happening.
Does it really? I don't know much about Java threads either, but in my understanding it could be possible that yield() will only yield execution time to other Java threads scheduled by the VM - or is the VM smart enough to give processing time to other non-Java OS threads as well when encountering a yield() call? Also, it seems like only threads with equal (or higher) priority are considered.

I didn't found much about yield() on the internet (except for "use it in loops!" articles that unfortunately all lack a more in-depth analysis), only this:

http://www.mactech.com/articles/mactech/Vol.14/14.05/WritingJavaCross-Platform/index.html

This article suggests that, depending on the target machine, yield() might not be a good idea as it hogs all available CPU time (on Windows NT, for example).

QuoteEven turn-based strategy games use the same game loop as other game types. [...] Regardless, whether you do it, LWJGL does it, Java does it, or it happens in the depths of the OS, something has to be polling for system events.
Again I'm walking on thin ice here, but why would the OS need to poll for system events? Couldn't some kind of interrupt/signal event mechanism be used instead?

And even if that is not the case, I'd like some lower levels of the system to take care of the decision how to handle system events. They should know better how to do it, and this sounds like a better way from a software engineering perspective.


But if LWJGL won't support that, I'll have to resort to use polling (and will throw in a yield() or sleep() call for good measure). LWJGL is a really fine library otherwise. :)

-Kylearan

Fool Running

You could try use a AWTGLCanvas. It will have to be added to a Frame, so if you want to go fullscreen you would have to do it entirely in Java, but it should help you a lot with what you are struggling with (I think :lol: ).
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Kylearan

Hi,

as a follow-up and to support my point, I've written the following Java "program":

while (true) {
    Thread.yield();
}


It does nothing than yield(), and yet uses up 97% CPU time on a Linux system. A comparable C++ program using glutKeyboardFunc() uses no CPU time at all.

So I still think LWJGL really needs a non-polling mechanism for mouse/keyboard/display events. :)


Quote from: "Fool Running"You could try use a AWTGLCanvas. It will have to be added to a Frame, so if you want to go fullscreen you would have to do it entirely in Java, but it should help you a lot with what you are struggling with
Thanks for the suggestion, but I'd like not to use AWT at all, only LWJGL. :)

-Kylearan

Matzon

Quote from: "Kylearan"Hi,
So I still think LWJGL really needs a non-polling mechanism for mouse/keyboard/display events. :)
Why? I've yet to encounter a *proper* game that didn't use active rendering and polling.
If you're worried about performance, sleep longer instead of yielding

aldacron

Quote from: "Kylearan"
This article suggests that, depending on the target machine, yield() might not be a good idea as it hogs all available CPU time (on Windows NT, for example).

Then do this instead:

try {
   Thread.sleep(1);
} catch(InterruptedException ie) {}


I tried the Thread.yield loop on my system and found the process to be taking 98% of the CPU. Shows that my understanding of the method was flawed. Replacing with the Thread.sleep(1) as above, CPU usage by the process is less than 1%.

QuoteAgain I'm walking on thin ice here, but why would the OS need to poll for system events? Couldn't some kind of interrupt/signal event mechanism be used instead?

I don't know if any OSes actually poll for events or not. I'm just making the point that something, somewhere has to take raw input signals and generate event notifications/messages/signals, or whatever you want to call them, for the application to process. Windows requires the programmer to do so via a loop that is commonly known as "the Windows message pump". I have no idea how it's done on Linux, Mac, Solaris or anything else. But generally at some point, something has to take events out of an event queue and send them to the application.[/quote]

QuoteAnd even if that is not the case, I'd like some lower levels of the system to take care of the decision how to handle system events. They should know better how to do it, and this sounds like a better way from a software engineering perspective.

I'm not sure what you mean by this.

QuoteBut if LWJGL won't support that, I'll have to resort to use polling (and will throw in a yield() or sleep() call for good measure). LWJGL is a really fine library otherwise. :)

Use the sleep(1) in your game loop and you should be fine.

Kylearan

Hi,

Quote from: "Matzon"I've yet to encounter a *proper* game that didn't use active rendering and polling.
I don't know which games are "proper" in your view and which aren't, but all turn-based strategy games for example shouldn't poll when waiting for user input. I remember (commercial) games from the past where all other applications slowed down to a crawl once the game was started - bad. Today's games, like Civilization IV from Firaxis for example, can be run in windowed mode and other applications can be used at the same time without problems.

Of course I don't know whether they actively poll or use interrupts, signal handling, yield or whatever other method there may be, but they do it right from a user's point of view. Yield() in Java certainly isn't.

QuoteIf you're worried about performance, sleep longer instead of yielding
I will take a look at the sleep() method (also thanks to aldacron for suggesting this!), although the computer scientist in me would still prefer some kind of callback function. :)

-Kylearan

Kylearan

Hi,

Quote from: "aldacron"
I tried the Thread.yield loop on my system and found the process to be taking 98% of the CPU. Shows that my understanding of the method was flawed. Replacing with the Thread.sleep(1) as above, CPU usage by the process is less than 1%.
Thanks! I'll try that.

QuoteI'm just making the point that something, somewhere has to take raw input signals and generate event notifications/messages/signals, or whatever you want to call them, for the application to process. Windows requires the programmer to do so via a loop that is commonly known as "the Windows message pump". I have no idea how it's done on Linux, Mac, Solaris or anything else. But generally at some point, something has to take events out of an event queue and send them to the application.
Agreed. But my point is (and that is what I meant later with "better way from a software engineering perspective") that Java is a portable, high-level language, and that the programmer shouldn't have to be concerned about how the underlying OS processes these signals (software engineering: "Seperations of Concerns"). Callback functions are superior to a polling system, as they are more flexible, less error-prone and waste less resources (on OSes that use interrupts for this kind of things), so Java should do it this way - and does it everywhere else, except in the LWJGL. And I don't understand why that design decision was made. :)

-Kylearan

Fool Running

QuoteThanks for the suggestion, but I'd like not to use AWT at all, only LWJGL.
From what you've been talking about (wanting to use events and stuff), it seems like this would better suit your needs. Is there a reason you don't want to use AWT? I think it would give you almost exactly what you are looking for.
QuoteAnd I don't understand why that design decision was made.
Most, I won't say all, but most games use a "main loop," thus the reason most games use near 100% of the CPU when they are running. And also why that decision was made.

Hope that helps :D
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Kylearan

Hi,

Quote from: "Fool Running"From what you've been talking about (wanting to use events and stuff), it seems like this would better suit your needs. Is there a reason you don't want to use AWT?
Mainly because I need the fullscreen mode (and I don't know whether it's possible and how to do it in AWT :wink:). But the sleep(1) workaround works fine too, so it's more a matter of principle why I think LWJGL needs these callback functions.

You have a great signature, by the way!  :lol:

-Kylearan

Fool Running

QuoteMainly because I need the fullscreen mode (and I don't know whether it's possible and how to do it in AWT).
Its possible (GraphicsDevice.setFullScreenWindow() ), but if the sleep thing is working, just keep using that :)
QuoteYou have a great signature, by the way!
Thanks!  :D
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

aldacron

Quote from: "Kylearan"
I don't know which games are "proper" in your view and which aren't, but all turn-based strategy games for example shouldn't poll when waiting for user input. I remember (commercial) games from the past where all other applications slowed down to a crawl once the game was started - bad. Today's games, like Civilization IV from Firaxis for example, can be run in windowed mode and other applications can be used at the same time without problems.

Even windowed mode games poll for input. It's possible to create an event-driven interface, of course, use a native OS API, or AWT/Swing/SWT in Java. But most games absolutely do not want to do this. Many games have idle animations that take place even when there are no events to handle. One of my favorite turn-based strategy games, Lords of Magic (several years old now), had banners and flags which fluttered in the wind above units and cities. Such animations are possible without an active game loop, but through inefficient and unreliable techniques. That's why every introductory game programming book usually begins with an overview of the game loop. And these days, many games, even TBS, swap buffers at a constant frame rate even if there are no rendering updates.

There are games that do otherwise, but the standard is a game loop that polls for input, updates game logic, and renders the scene. I promise that even Civ IV does that :) The Thread.yield thing was bad advice on my part, but the intent was correct -- surrender the remainder of the time slice at the end of the loop. That takes care of your CPU usage concerns whill allowing you to render efficiently.