[Not Solved] Cinematics stop after the window comes back into focus after focus is lost

I am developing a 3D panel inside of a Swing application to show models in. I am having an issue with Cinematics not showing properly when the Window becomes inactive or out of focus.



I have listed a test case below to repeat the issue.



Run this and then press P to start the cinematic. Then click on any other window this will stop the cinematic.



I am looking for a way for this not to happen because I need to run cinematics while making a different window the focus and then coming back to the JME window.



I have run this against the Beta release from 10/22/2011 as well as the nightly build from 12/31/2011.



Thank you for your time.



[java]package helloJME;





import java.awt.event.ActionEvent;



import com.jme3.app.SimpleApplication;

import com.jme3.cinematic.Cinematic;

import com.jme3.cinematic.events.AbstractCinematicEvent;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;





/** Sample 1 - how to get started with the most simple JME 3 application.

  • Display a blue 3D cube and view from all sides by
  • moving the mouse and pressing the WASD keys. /

    public class helloJME extends SimpleApplication {

    protected Geometry player;

    Camera cam;

    Cinematic cinematic = null;

    int lastArrivalTime = 0;



    class MovePlayerEvent extends AbstractCinematicEvent {

    private Vector3f startPosition;

    private Vector3f endPosition;

    private float value = 0;

    private float duration = 0;

    private Spatial spatial;



    public MovePlayerEvent() {}



    public MovePlayerEvent(Vector3f endPosition, float duration) {

    super();

    this.duration = duration;

    if (duration>0)

    setSpeed(1f/duration);

    this.endPosition = endPosition;

    this.spatial = player;

    }



    @Override

    public void onPlay() {

    // if (playState != playState.Paused)

    startPosition = player.getWorldTranslation().clone();

    spatial.setLocalTranslation(endPosition);

    }



    @Override

    public void onUpdate(float tpf) {

    if (duration==0)

    value = 0;

    else

    value += Math.min(tpf * speed, 1.0f);

    Vector3f pos = FastMath.interpolateLinear(value, startPosition, endPosition);

    spatial.setLocalTranslation(pos);

    }



    @Override

    public void onStop() {

    value = 0;

    }



    @Override

    public void onPause() {

    }

    }



    public static void main(String[] args){

    helloJME app = new helloJME();

    app.start();

    }





    @Override

    public void simpleInitApp() {

    setPauseOnLostFocus(false);

    cam = this.getCamera();

    cam.setLocation(new Vector3f(1.65292f, 102.5887f, 122.99368f));

    cam.setRotation(new Quaternion(-0.003028753f, 0.94518274f, -0.32641003f, -0.008770208f));

    cam.getDirection(new Vector3f(-0.014601667f, -0.61708736f, -0.78675914f));

    Vector3f location1 = new Vector3f (0,0,0);

    Vector3f location2 = new Vector3f (0,2f,0);

    Box b = new Box(location2, 1f, 2f, 1f);

    Box c = new Box(location1,120f,1f,52.5f);

    player = new Geometry("Player", b);

    Geometry geom1 = new Geometry("Box 1", c);

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    mat.setColor("Color", ColorRGBA.Blue);

    mat1.setColor("Color", ColorRGBA.Green);

    mat2.setColor("Color", ColorRGBA.White);

    geom1.setMaterial(mat1);

    player.setMaterial(mat);

    rootNode.attachChild(geom1);

    rootNode.attachChild(player);

    flyCam.setDragToRotate(true);

    flyCam.setMoveSpeed(10f);

    inputManager.deleteMapping("SIMPLEAPP_Exit");

    initKeys(); // load my custom keybinding

    }



    /
    * Custom Keybinding: Map named actions to inputs. */

    private void initKeys() {

    inputManager.addMapping("Play", new KeyTrigger(KeyInput.KEY_P));

    inputManager.addListener(actionListener, new String[]{"Play"});

    }



    private ActionListener actionListener = new ActionListener() {

    public void onAction(String name, boolean keyPressed, float tpf) {

    if (name.equals("Play") && !keyPressed) {

    doCreateCinematic();

    }

    }

    };



    private class PlayWhenInitialized {

    private javax.swing.Timer timer = new javax.swing.Timer(2, new java.awt.event.ActionListener() {

    public void actionPerformed(ActionEvent e) {

    if (!cinematic.isInitialized())

    return;

    cinematic.stop();

    cinematic.play();

    timer.stop();

    }

    });

    public PlayWhenInitialized() {

    timer.setRepeats(true);

    timer.start();

    }

    }



    private void addMovePlayerEvent(int arrivalTime, Vector3f location) {

    if (arrivalTime<lastArrivalTime)

    lastArrivalTime = 0;

    cinematic.addCinematicEvent(arrivalTime, new MovePlayerEvent(location, arrivalTime-lastArrivalTime));

    lastArrivalTime = arrivalTime;

    }



    private void doCreateCinematic() {

    // create new cinematic

    if (cinematic!=null)

    getStateManager().detach(cinematic);

    cinematic = new Cinematic(rootNode,200);



    addMovePlayerEvent(1, new Vector3f(-60,0,0));

    addMovePlayerEvent(2, new Vector3f(60,0,0));

    addMovePlayerEvent(3, new Vector3f(-60,0,0));

    addMovePlayerEvent(4, new Vector3f(60,0,0));

    addMovePlayerEvent(5, new Vector3f(-60,0,0));

    addMovePlayerEvent(6, new Vector3f(60,0,0));

    addMovePlayerEvent(7, new Vector3f(-60,0,0));

    addMovePlayerEvent(8, new Vector3f(0,0,0));



    // attach and play

    getStateManager().attach(cinematic);



    new PlayWhenInitialized();

    }

    }[/java]

Try this:

[java]

@Override

public void simpleInitApp()

{

setPauseOnLostFocus(false);



// …

}

[/java]

I have set that to false and when the window loses focus and I click back on the window and adjust the camera angle the Cinematic Stops.

I have tested the code listed above on the alpha release of JME3 and there is no issue with cinematics pausing when the window looses or gains focus. This issue exhists in the Beta release download as well as the nightly build from 1/9/2011.



Setting setPauseOnLostFocus(false); does note resolve the issue. What happens is when the window gains focus the cinematic stops for a number a seconds and the resumes.



This issue causes problems for any software that has a second window such as a control panel or tool palette.

It will break any time there is a WindowStateChange event that occurs when a user moves between applications, or when the OS pushes an action that creates a window state change in the program.



Thank you for your time.

I have posted video examples of the issue I am encountering.



The Cinematic correctly works on the Alpha Release of JME 3 when the window loses and gains focus. http://youtu.be/X-LPQBZR2Bs



The Cinematic does not work properly on Beta or Nightly Releases. When the window regains focus the cinematic stops for a number of seconds and then continues. http://youtu.be/XMDZxzogg58

I know what’s going on here…

@Momoko_Fan, @normen,@pspeed. So we kept asking what feature had the old “smoothed” timer over the NanoTimer…well one feature was that it was paused when the app was paused…

NanoTimer just keep fetching System.nanoTime();



@dm1056 i’ll fix it

2 Likes

@nehon Thank you very much.

@nehon



Do you know when this correction might be added in the nightly builds?



Thank you for your time

I’m on it, it’s harder than it looks. I found several solutions but i need to brainstorm with the others to chose the best solution

@nehon Thank you very much for your time and hard work.

In discussion, it’s becoming clearer that “pause on lost focus” is not really the same as “pause the game”. You may want one, the other, or both in various combinations depending on your usage.



For example, when the game pauses you may want to pop-up a menu until the user clicks “go” again… but you’d still want the update() loop to run (which is currently what “pause on lost focus” pauses).



Complicated.

@nehon and @pspeed



Just wanted to see how this issue was progressing.



Thank you for this wonderful tool y’all have created.

@nehon said:
I know what's going on here....
@Momoko_Fan, @normen,@pspeed. So we kept asking what feature had the old "smoothed" timer over the NanoTimer....well one feature was that it was paused when the app was paused....
NanoTimer just keep fetching System.nanoTime();

@dm1056 i'll fix it


Rereading the thread this time.

the issue is that NOT pausing is causing issues, ie: setPauseOnFocusLost() is false. I suspect somewhere a heavy-handed timer reset was added that should not have been. Because otherwise, gain and loss of focus should not cause issues.

The fact that pausing does not pause the timer is another issue that cannot be fixed by simply resetting the timer... and if that was done then it should be reverted.
1 Like

@Paul, the problem is the same if i don’t use a timer and if i just stack tfp to compute time.



When you resume, the first tpf you get is equal to the time you spent in pause. So if you spend like 30 minutes in pause…the cinematic ends anyway.



As we said, we need a proper way to pause the timer, it’s better sending a 0 tpf instead of a big tpf.

1 Like

But as it is now… not pausing is also broken. That’s bad. So now there is no way to avoid issues, apparently. You can’t even just turn off pausing.

1 Like

well…i can implement pausing for the nanoTimer…and just make sure it doesn’t account pause time in the tpf sent…

I thought I remembered in conversation that you added a timer.reset() somewhere. Since JME doesn’t implement game pause yet that should be removed.



…then we can focus on making pause actually pause time. But first I think we should go back to having NOT pausing work right.

Remember… the original posted is trying NOT to pause the cinematics.

@pspeed said:
I thought I remembered in conversation that you added a timer.reset() somewhere. Since JME doesn't implement game pause yet that should be removed.

...then we can focus on making pause actually pause time. But first I think we should go back to having NOT pausing work right.

i did not commit this because we agreed it shouldn't be reset :p

@pspeed said:
Remember... the original posted is trying NOT to pause the cinematics.

erf....i understood the other way around.

I am trying to have the cinematics continue playing while the window is going in and out of focus.



Thank you very much for the updates.