[solved] input is delayed by 1 frame (when using setFrameRate(x) ie. x=1) ? jme3 r7361

EDIT: ignore all posts up until this post:

http://hub.jmonkeyengine.org/groups/general-2/forum/topic/input-is-delayed-by-1-frame-jme3-r7361/?topic_page=2&num=15#post-126497

(because, I wrongly thought that the input is delayed by 1 frame all the time, but instead it only does this when used setFrameRate and you press the key while Display.sync() is sleeping )


Heylo :)
I was trying to track my issue and it seems that this is the cause (vague enough? ok self-slap xD)
I put a simple code, to test this, press Esc key once when you see the message:
"before update begins, press a key now ie. Esc"
and what you notice is, that, although you pressed the key before update() [not simpleUpdate()!] began, the effect of this happens only the next call to update. And this works the same for mouse inputs.
This affects me in my case, when I click on an object and then it moved from that position(in the very next frame) such that now the click is in mid air(not on the object, in this frame, because it moved that much), and thus it's not detected by the input handler(my onAction) that I clicked on the object (although I did so in that frame)
EDIT: in this screenie, I pressed Esc only once (that is press&release) when the first message appeared then I waited until it exited (that is, on the next call to update and after the second msg)
http://i.imgur.com/6S1By.png
[java]package org.jme3.forum2;
import com.jme3.app.SimpleApplication;
public class Input1FrameLag extends SimpleApplication {
public static void main(String[] args) {
Input1FrameLag i = new Input1FrameLag();
i.start();
}
@Override
public void simpleInitApp() {
//
}
@Override
public void update() {
try {
// works for mouse inputs also
System.out.println("before update begins, press a key now ie. Esc");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
super.update();
}
}
[/java]

I think you are creating a totally artificial case here ^^ The input is in fact the first thing that is worked off in the update loop. So when you press the key later (in update()) of course it will only be delivered the next time the update loop starts again. Everything else would mess up the update order. Normally you would want to get the input, then update your spatials with that info (in update/simpleupdate/control update etc) and then render the result. So the order is fine and the input is not “late” as you suggest.

1 Like

I dig what you’re saying, but if I put the delay in simpleUpdate, thus allowing me to press the key while in simpleUpdate, it does only deliver this key on the second call to update() , that is, not the next call to update() but the next after the next (just as in my first example)



I know, I was “O_o” when I found out too (unless I am wrong as you said and I need help to realize it lol, really tho)



here’s updated code with same effect:

http://i.imgur.com/5BOlC.png

[java]package org.jme3.forum2;



import com.jme3.app.SimpleApplication;



public class Input1FrameLag extends SimpleApplication {

public static void main(String[] args) {

Input1FrameLag i = new Input1FrameLag();

i.start();

}



@Override

public void simpleInitApp() {

//

}



@Override

public void simpleUpdate(float tpf) {

try {

// works for mouse inputs also

System.out

.println(“before simpleUpdate begins, press a key now ie. Esc”);

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}



}

[/java]



I DO thank you for your reply, I was eagerly waiting, like a child-monkey :slight_smile:

I don’t understand, there is only one moment where you get the key input and that is at the beginning of the loop, before simpleUpdate or any update you can override.

I don’t actually know how to explain this, sorry…

here’s 3 consecutive frames (1. 2. and 3.)

  1. update()
  • process inputs
  • call simpleUpdate
  • user pressed then released Esc key while in here
  • after like 5 seconds of Thread.sleep() exit simpleUpdate
  • do something else update() related like render
  1. update()
  • process inputs (Esc key is not senses yet)
  • call simpleUpdate
  • user does nothing here
  • 5 seconds delay
  • do other update stuff again, like render
  1. update()
  • process inputs

    the Esc key is sensed and it’s actionListener is executed which calls this.stop()


But normally you’d expect this:
  1. update()
  • process inputs
  • call simpleUpdate
  • user pressed then released Esc key while in here
  • after like 5 seconds of Thread.sleep() exit simpleUpdate
  • do something else update() related like render
  1. update()
  • process inputs

    the Esc key is sensed and it’s actionListener is executed which calls this.stop()



    The difference being the one extra frame in between… which allows the logic&render even to progress by 1 frame before the key is actually sensed (the key which was pressed 1 frame before) or something - again, unless I’m missing something which seems to be mostly the case (sorry in advance xD)

    EDIT: spaces got eaten - hopefully blockquote will fix

    EDIT2: nope that didn’t work, trying list

I removed the embedded ul li :stuck_out_tongue:

We need to fix this space/return vanishing problem :frowning:

1 Like

oh dear god, I cannot even edit my previous post after trying list/listitem … oops - go away from meh bugs! it’s not like I smell or anything! or is it? xD

The Edit button is nowhere to be seen :slight_smile:

In all honesty, I did nest lists - was that unexpected?

Closing the app with ESC might take some time because it sets a flag on the context. Try creating an ActionListener and then printing out stuff when you get the event. The input is NOT delayed.

1 Like

I stand corrected, indeed the input is not delayed:

[java]package org.jme3.forum2;



import org.w3c.dom.events.MouseEvent;



import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.input.controls.MouseButtonTrigger;



public class Input1FrameLag extends SimpleApplication {

public static void main(String[] args) {

Input1FrameLag i = new Input1FrameLag();

i.start();

}



@Override

public void simpleInitApp() {

ActionListener al = new ActionListener() {



@Override

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

if ((name == “boom”) && (isPressed)) {

System.out.println(“sensed!”);

}

}

};

inputManager.addMapping(“boom”, new KeyTrigger(KeyInput.KEY_SPACE),

new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));



inputManager.addListener(al, “boom”);

}



@Override

public void simpleUpdate(float tpf) {

try {

// works for mouse inputs also

System.out

.println(“before simpleUpdate begins, press SPACE or LMB now not Esc”);

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}



}

[/java]



it might just be then, a particularity in my program (a different one) which I will now track down… what is happening there is, I click LMB on a Box in this frame, and on the next frame (the input is indeed sensed) but the Box moved (as it does every frame) such that the actionListener for this next frame doesn’t see the Box as it was in the previous frame (ie. the click missed the Box) - somehow the Box’s motion is updated before entering the input’s actionListener such that on whatever I think I clicked on the previous frame, is not there when sensed on the next frame (it seems to me it should be though, because input’s actionListener is executed indeed before simpleUpdate)



I’ll post anew when I have a simple testcase, I am sorry for being rather wrong about the input delayed thingy, I was too quick to generalize(and I even thought I triple checked huh!), I am sorry for believing it too blindly that I somehow subconsciously made it true - (only) for me ie. 1. first I believed it is so, 2. then I made sure it is so (for me anyway). I apologize for all parties involved. That being said, pretend I never said this (ie. ignore it in your following posts, if any)

ok, it seems that the Thread.sleep() is causing me the frame delay

because I am pausing(sleep) right after simpleUpdate, I don’t see the updated/rendered frame of the current state of the Spatials (I see the current frame which has now become the previous frame due to me changing the Spatials’ ie. translations) so that is why when I am in this frame freeze (due to sleep) when I LMB on the Box, actually the box is already moved but the rendering was delayed by my sleep - I just need to move my sleep to the beginning of simpleUpdate (it seems, EDIT: nope) EDIT2: actually I can’t fix this, anywhere I put my sleep of 2 seconds per frame it will cause 1 frame delay



this is latest testcase, no need to run it but if you do you’ll notice that if you press SPACE while Thread.sleep is in effect and before update() [or rather inputManager.update() ] is actually called, that is: if you press it when you see the message “frame:1 before update begins press SPACE now” , then you’ll see it’s not sensed by this update (even though this update or inputManager.update() was not yet called) - just pointing out how easy it was for this to fool me that input is delayed 1 frame heh - probably all inputs are dequeued from a lower level before calling update() and before inputManager fiddles with its own queue(which is higher level)

[java]package org.jme3.forum2;

import java.util.prefs.BackingStoreException;

import org.w3c.dom.events.MouseEvent;

import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;

public class Input1FrameLag extends SimpleApplication {

public static void main(String[] args) throws BackingStoreException {

Input1FrameLag i = new Input1FrameLag();

AppSettings aps = new AppSettings(true);

aps.load(aps.getTitle());

aps.setVSync(false);

i.setSettings(aps);

i.setShowSettings(false);

i.start();

}

private Geometry boxGeo;

private int frame = 1;

@Override

public void simpleInitApp() {

ActionListener al = new ActionListener() {

@Override

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

if ((name == “boom”) && (isPressed)) {

boxGeo.move(0, 0, -10);

boxGeo.getWorldTransform();// causes checkDoTransformUpdate

System.out.println(“Box moved!”);

}

}

};

inputManager.addMapping(“boom”, new KeyTrigger(KeyInput.KEY_SPACE),

new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));

inputManager.addListener(al, “boom”);

Box boxMesh = new Box(2, 2, 2);

boxGeo = new Geometry(“box”, boxMesh);

Material boxMat = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”);

boxMat.getAdditionalRenderState().setWireframe(true);

boxMat.setColor(“Color”, ColorRGBA.Green);

boxGeo.setMaterial(boxMat);

rootNode.attachChild(boxGeo);

}

@Override

public void simpleUpdate(float tpf) {

try {

System.out.println(“frame:” + frame + " in simpleUpdate");

Thread.sleep(2000);

Thread.yield();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

@Override

public void update() {

try {

System.out.print(“frame:” + frame + " before update begins");

if (1 == frame) {

System.out.println(" press SPACE now");

} else {

System.out.println();

}

Thread.sleep(2000);

Thread.yield();

} catch (InterruptedException e) {

e.printStackTrace();

}

super.update();

try {

System.out.println(“frame:” + frame + " after update is done");

Thread.sleep(2000);

Thread.yield();

// Note: rendering only happens after this delay

} catch (InterruptedException e) {

e.printStackTrace();

}

frame++;

}

}

[/java]

Phew, its kinda hard reading your reports when you just put out your headspace content like this here ^^

1 Like

Perhaps the reason you’re seeing this result is because the input is handled before the box is moved, making it appear as if the input is delayed.

1 Like

I’m somewhat aware of that in a fearful way,… I don’t actually know how else to do it

By that you mean, I don’t put enough spaces to delimit paragraphs OR/AND I put too much detailed info at the beginning when instead I should eventually put the details later but first just a small sentence saying the general thing ? I guess I can’t stop myself from trying (not necessarily succeeding) to be thorough; that being said, don’t you wish to see whatever jme3 program I will ever make ? (lol? that is, if I somehow manage to make any, ‘cause whatever I just described here(not the frame delay) seems to be preventing me to do anything “real”)

Let me see if I can redo the prev. post:

=======

I realized that Thread.sleep is causing the delay in my program

___ I see {the current frame}, then I change {the Spatials’ state, ie. their translations}, then I do the Thread.sleep, which means this sleep happens before {the rendering of the current state of Spatials} (anywhere I’d put this sleep, even in overridden update(),will happen either 1. before the rendering (because rendering happens after .update() ), OR 2. before sensing the input that I do while in sleep(due to low level inputs being pulled before calling .update() and I sleep while in update() thus pressing any keys while in this sleep won’t transfer them to be available for inputManager.processQueue() [btw, I slept(.sleep()) before this being called] because (I guess) the inputs are transferred to be accessible by inputManager by something else prior to calling .update() OR ok, right after .update() was called)

[ok,I’m failing to do it lol, it’s already way too much text, in fact it’s probably more than before… - asking myself: do I actually need to be this thorough?]

but looking at the bright side: I’m real good at failing :smiley:

Respectfully,

signing off





EDIT: fixed gt and lt signs obscured text within them, replaced with “{” and “}”

Momoko_Fan said:
Perhaps the reason you're seeing this result is because the input is handled before the box is moved, making it appear as if the input is delayed.

exactly :) see, why couldn't I just say that, instead of all that garbage ?!
I mean, the box is moved, but not rendered yet, EDIT: because my Thread.sleep is preventing the rendering to occur, until next frame
EDIT2: the bad thing is, I cannot put any Thread.sleep anywhere and NOT get a delay, either in rendering OR in input, basically can't sync input and rendering when doing a Thread.sleep

EDIT3: (lol?)
1. if i put the delay(sleep) at the beginning, it will miss my input for this frame, meaning while I do see and click on the Box, the box will update in this frame and then I will have missed it by the next frame when the input is sensed
2. if I put the delay after I update the Box, then the rendered will be delayed, the input too, basically when I click on the Box, it's already updated but I see the previous frame
oh well, same thing I said in prev post (but more detailed)

regarding this,

is there any way to add my own callback right after the rendering ? EDIT: Thread.sleep would rule there

simpleUpdate() is pre-rendering

Okay let me ask this in a different way … Why are you using Thread.sleep()?

Halting the render thread for a prolonged period of time is not a good thing to do, as it won’t be able to process window messages for the OpenGL window, causing it to lock up.

1 Like

I’m trying to emulate low fps of sorts :slight_smile: for learning purposes really

If there’s another way to emulate a kind of poor graphics card that takes a while to render, I’d be happy to consider it - obviously my way is not working as it is :slight_smile:

I guess you mean, the window messages which contain the inputs that I press when I sleep right before calling update() are not processed(from SWT to inputManager) in due time to make them available to inputManager.processQueue() (due to maybe too low delay between {after sleep() is done and inputManager.processQueue()} ) and thus that will cause my input to be delayed til the next frame (I mean, in my case only - with sleep before update() )



EDIT: fixed gt and lt signs obscured text within them, replaced with “{” and “}”

oh nelly, I just realized that in this post and in the previous one, whenever I used the less than and greater than chars, that part between them got cut out and it’s not shown - I understand why it happened but for some reason I decide(now) not to fix it :confused: (and it looked so good in the former post)

EDIT: by the time you see this I will have edited those posts (though I don’t remember if they were the only ones) so they don’t use greater than and less than signs, instead I’ll replace them with “}” and “{”

No, the window messages are OS related. If you halt the thread that handles them, the window will freeze.

For emulating low fps, did you try using AppSettings.setFrameRate?

1 Like

indeed the window freezes, windows is also detecting it as hung , depending on how long the sleep lasts,

I didn’t try setFrameRate, I’ll try now… though it is limited to minimum 1 fps, I was hoping for 0.5 fps , really :slight_smile:

ok I tried it but almost the same thing happens as with Thread.sleep

I say “almost” because with sleep, the input is sensed the very next frame (if it happened during the {sleep of {the previous frame’s simpleUpdate}}), but with setFrameRate, the input is sensed in the frame right after the next one… hmm, I’ll recheck, i don’t know: it seems so.; so this way I get that 1 frame delay for input

[java]package org.jme3.forum2;

import java.util.prefs.BackingStoreException;

import org.w3c.dom.events.MouseEvent;

import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;

public class Input1FrameLag extends SimpleApplication {

public static void main(String[] args) throws BackingStoreException {

Input1FrameLag i = new Input1FrameLag();

AppSettings aps = new AppSettings(true);

aps.load(aps.getTitle());

aps.setVSync(false);

i.setSettings(aps);

i.setShowSettings(false);

aps.setFrameRate(1);

i.start();

}

private Geometry boxGeo;

private int frame = 1;

@Override

public void simpleInitApp() {

ActionListener al = new ActionListener() {

@Override

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

if ((name == “boom”) && (isPressed)) {

boxGeo.move(0, 0, -10);

boxGeo.getWorldTransform();// causes checkDoTransformUpdate

System.out.println(“Box moved!”);

}

}

};

inputManager.addMapping(“boom”, new KeyTrigger(KeyInput.KEY_SPACE),

new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));

inputManager.addListener(al, “boom”);

Box boxMesh = new Box(2, 2, 2);

boxGeo = new Geometry(“box”, boxMesh);

Material boxMat = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”);

boxMat.getAdditionalRenderState().setWireframe(true);

boxMat.setColor(“Color”, ColorRGBA.Green);

boxGeo.setMaterial(boxMat);

rootNode.attachChild(boxGeo);

}

@Override

public void simpleUpdate(float tpf) {

// try {

// System.out.println(“frame:” + frame + " in simpleUpdate");

// Thread.sleep(2000);

// Thread.yield();

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

}

@Override

public void update() {

// try {

System.out.print(“frame:” + frame + " before update begins");

// if (1 == frame) {

// System.out.println(" press SPACE now");

// } else {

System.out.println();

// }

// Thread.sleep(2000);

// Thread.yield();

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

super.update();

// try {

System.out.println(“frame:” + frame + " after update is done");

// Thread.sleep(2000);

// Thread.yield();

// // Note: rendering only happens after this delay

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

frame++;

}

}

[/java]

EDIT2: moved to next post xD