LWJGL Game loop pauses whenever the GLFW window head is clicked - lwjgl

I have a very simple game loop.
public void gameLoop() {
long now;
long updateTime;
long wait;
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
while (!window.shouldClose()) {
now = System.nanoTime();
update();
render();
frame++;
updateTime = System.nanoTime() - now;
wait = (OPTIMAL_TIME - updateTime) / 1000000;
try {
Thread.sleep(wait);
} catch (Exception e) {
}
}
glfwTerminate();
}
Whenever I click the head of the window (the bar where the close and minimize buttons are), the loop for some reason pauses. The sounds in game continue to play (I use AL10), so this causes music and sounds to get out of sync with the game. I want to pause the window whenever this happens.
I but looking through the GLFW callbacks, there doesn't seem to be one which fixes this. The focus callback only works if I click outside of the window, and the windowPos callback only works whenever the window is moved, NOT when you simply click and hold the window head.
Is there a way to fix this problem.

This is actually expected behaviour on some platforms like Windows, where effectively glfwPollEvents will block inside of a Win32 API call for as long as you hold down the mouse button and/or potentially drag/move the window around.
In order to fix this, you should make your game loop independent of the window event processing loop, by using separate threads.
The main thread must be the one that is doing the window event processing (glfwPollEvents or glfwWaitEvents) to stay consistent with the requirements of some other platforms like macOS where this is a requirement, while another thread can do the game update and rendering.

Related

MediaCapture and Window VisibilityChanged

[Question]
On Windows Phone 8.1, what exactly happens in between the time when the user leaves the app and the OnSuspended event fires? I'm having trouble with the ability to manage objects in that span, in particular MediaCpture object.
To better explain the problem, here is the scenario:
The user is on a page with a video preview being pumped to a CaptureElement
The user taps the Start button
The user taps Back button and returns to the page with a broken MediaCapture
With WinRT there isn't an ObscuredEvent and OnNavigatingFrom doesn’t fire unless you’re going to another page in the same Frame. After some investigation, I've found that the only event that fires is Window.Current.VisibilityChanged
I've gone ahead and hook it when the page is NavigatedTo and unhooked in OnNavigatedFrom (see ex2 below). Inside the event, I check for parameter that tells if the app is hiding or showing and dispose/initialize accordingly(see ex.1 below).
[Problem]
However, this only works with the debugger attached. If I do this without the debugger attached, it doesn't reinitialize and frequently crashes the camera and I have to literally reboot the device.
Code Example 1 (note: e.Visible == false is leaving the app and true when returning)
async void Current_VisibilityChanged(object sender, VisibilityChangedEventArgs e)
{
if (!e.Visible) //means leaving the app
{
await DisposeAll(); //cleans the MediaCapture and CaptureElement
}
else
{
if(mediaCaptureManager != null) await DisposeAll();
await Initialization(); //set up camera again
}
}
Example 2 (hooking into the event)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Window.Current.VisibilityChanged += Current_VisibilityChanged;
this.navigationHelper.OnNavigatedTo(e);
}
protected async override void OnNavigatedFrom(NavigationEventArgs e)
{
Window.Current.VisibilityChanged -= Current_VisibilityChanged;
this.navigationHelper.OnNavigatedFrom(e);
}
[Update: Resolution]
Instead of using VisibilityChanged, hook into Window.Current.Activated on the page's constructor. With the debugger completely detached, the Activated event will provide the WindowActivationState parameter in the WindowActivatedEventArgs. Like this:
private async void CurrentOnActivated(object sender, WindowActivatedEventArgs e)
{
if(e.WindowActivationState == CoreWindowActivationState.Deactivated)
{
//dispose MediaCapture here
}
else if(e.WindowActivationState == CoreWindowActivationState.CodeActivated || e.WindowActivationState == CoreWindowActivationState.PointerActivated)
{
//initialize MediaCapture here
}
}
See my answer in https://stackoverflow.com/a/28592882/3998132. Using Window.VisibilityChanged in conjunction with your Page\UserControl Loaded\Unloaded handler should solve your issue I believe.
Using Window.Activated is less desirable than Window.VisibilityChanged because Activated relates to being visible AND having focus where as VisibilityChanged only pertains to visibility. For showing a preview having focus is not applicable. Since Windows Store apps on Windows Phone can only have one Window showing there is no difference in using either however if your app becomes universal and runs on let's say on Windows 8+ Modern shell (which can show multiple Store apps with the Snap window feature) or Windows 10 desktop (which can support multiple Store apps showing at the same time) you will not want to stop preview when a user changes focus from your app but your app is still showing.
I'm not sure if it wouldn't be more suitable to use Suspending/Resuming events. Note only that in this case, you will have to debug it properly - it behaves little different while being run with/without debugger attached.
As for the code - hooking your event in OnNavigatedTo/OnNavigatedFrom is not a good idea - when the OS suspends the app and you are using SuspensionManager then OnNavigatedFrom will be called, but when you go back to your app (resume it), then OnNavigatedTo will not be called.
Using Window events may also work here, but why not subscribe it once, somewhere in constructor? - it's window-wide and hence in phone there is only one window, which stands for app, then subscribe once. In this case, you may add a line that recognizes the current page in window and if that page contains mediacapture then dispose (create similar). Then you can also dispose/initialize in navigation events in case user doesn't leave your app and just navigate.

as3 Air - AddChild works but is slooooooooooow

I am creating an app where when a button is pressed a very large picture is added to the stage (it is larger than the screen but can be dragged around by the user)
When the button is pressed the picture (well, movieClip) does come up and it able to be dragged fine, buttons inside it work.
The problem though is that there is a pause of about 6 seconds between the button press and the image appearing. I am using one .fla file for publishing and compiling (let's just call it Main.fla for now), and another one to hold all the graphics. The graphics are then added with this embed command:
[Embed (source = "assets/graphic.swf", symbol = "Content")]
private var Content:Class;
private var _content:*;
I have these lines where all the variables are declared (in between the class definition and the constructor function) I was under the impression that embedding it like this was equivalent to loading it at compile time. Is this true? What could be causing this lag when the button is pressed?
If I can't cut out the lag, another idea I had was to make some spinning circle or something to tell the user, "hey, don't worry. It's loading!"
If the slowness is at addChild you can add the asset to the stage much earlier and set it's visiblility to false, then when the button is clicked set it back to true. Obviously this is a small hack but might be sufficient for what you are doing.
var asset:MovieClip;
private function init():void
{
asset = new Content();
assset.visible = false;
addChild(asset);
button.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function onMouseClick(e:MouseEvent):void
{
asset.visible = true;
}
Embedding your SWF is probably not what is causing the delay.. or rather it would not likely be better if you imported the SWF into your FLA. Is this on a device? Chances are you would either have to devise a different way of loading your asset, or be satisfied with a loading animation.
If the main K size is coming from a large image, you could consider loading it in segments, starting with the part that is initially visible.

JTextPane liveness

My Swing application prints lines of text to a JTextPane inside of a JScrollPane when a JButton is pressed. For quick operations there is no issue. However, some JButtons invoke operations that may take a few minutes. The button remains greyed out during this time.
What currently happens is that the text is "batched up" and then I get hundreds of lines all at once at the end of the operation at the same moment the button becomes un-greyed. The problem is that I would like the text being appended to the document displayed in the JTextPane to appear sooner (at the moment it is appended) rather than at the time the entire operation completes. This would create a better user experience.
What am I doing wrong?
Use a SwingWorker for performing your background operation.
// Your button handler
public void actionPerformed(ActionEvent e) {
(new SwingWorker<Void, String>() {
public Void doInBackground() {
// perform your operation
// invoke publish("your string");
}
protected void process(List<String> chunks) {
// append your string to the scroll pane
}
}).execute();
}
You are invoking code directly from within the AWT-Thread which blocks every event. The solution is to put your long-running code in a separate Thread. As your code is executed and obtains results, you notifiy your view (using the observer/observable pattern).As your view is notified, you update the scrollpane content.
You must also verify if you are running in the AWT-Thread or not (SwingUtilities.isEventDispatchThread()). If you are not, then you need to dispatch the update of the view in the AWT-Thread using SwingUtilities.invokeLater() because Swing is not Thread-safe.

Setting the application focus to a java-program in Ubuntu/LTSP

We are using LTSP with Thin-Clients. We are using it, to run a Java-Swing-Application. The users should not be able to do anything else, so instead of a Gnome-Session we use a shell-script to start our application.
Nearly everything works perfect but one thing: When the Thin-Client starts, the application starts too but doesn't receive the focus. We have to click once with the mouse inside the application, which is not that good, because the application is designed to be used without a mouse.
I didn't found anything useful, a toFront() on my Main Frame wasn't successful.
Has anyone any better suggestions??
You can use method java.awt.Window#setAlwaysOnTop(boolean) to grab the focus and after the first user interaction reset the alwayOnTop property.
You could try to call requestFocus on your JFrame as soon as it becomes visible:
JFrame frame = new JFrame();
frame.addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent e) {
((JFrame) e.getSource()).requestFocus();
}
});
frame.setVisible(true);

i integer does not +1 the 1st time

I have a gallery where it will load an image after a previous image is loaded, so every time 'i' will +1 so that it could move to the next image. This code works fine on my other files, but I dunno why it doesn't work for the current file.
Normally if I trace 'i' the correct will be
0,1,2,3,4,5,6... etc
adding on till the limit, but this files its 'i' repeat the 1st number twice, only it continues to add
0,0,1,2,3,4,5,6...etc
The code is completely the same with the other file I'm using, but I don't know why it just doesn't work here. The code does not seems to have any problem. Anyway i can work around this situation?
private var i:uint=0;
private function loadItem():void {
if (i<myXMLList.length()) {
loadedPic=myXMLList[i].thumbnails;
galleryLoader = new Loader();
galleryLoader.load(new URLRequest(loadedPic));
galleryLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,picLoaded);
} else {
adjustImage();
}
}
private function picLoaded(event:Event):void {
var bmp=new Bitmap(event.target.content.bitmapData);
bmp.smoothing=true;
bmpArray.push(bmp);
imagesArray[i].addChild(bmp);
i++;
loadItem();
}
That code looks fine, it's really very difficult to tell what might be causing that. The best advice I can give you would be to set some break points; for example set one at the point where you add the event listener to the galleryLoader object, and then run Flash's debugger. You run it by going to Debug > Debug Movie.
The debugger will stop at that line, and you will be able to look in the Variables window to see your i variable as you step through the code line-by-line. You step through by pressing the step in button, inside the Debug Console window. I've put in an image below showing the debugger's specific windows (that you won't see at any other time in Flash):
I think that by doing that (if you haven't already tried, that is) you should pretty quickly see what's going wrong. Hope it helps anyway.
debu
I've finally found out whats the problem.
public function grid():void {
addEventListener(Event.ADDED_TO_STAGE, add2Stage);
}
private function add2Stage(event:Event):void {
myLoader=new URLLoader();
myLoader.load(new URLRequest(galleryXML));
myLoader.addEventListener(Event.COMPLETE,processXML);
}
Its because I'm using adding the functions to stage. After I remove the add2stage function then everything's fine. But why will it affect and run the function twice at 1st? I'm just adding it to the stage to get the stage width.