Are you suggesting that maybe we should sense the input after the wait instead of before?
the way I see it, setFrameRate uses some kind of delay (ie. sleep?) which happens after update() and during which if I do press some keys, they are not sensed on the next call to update(), they are sensed instead on the next after next call to update(), that is, the one after the next one
thus I would expect the following code to act the same way, but it doesnât, in other words: this code does sense the key right on the next update, even though it sleeps right after update() is called
[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]
upon further scooping around:
I guess itâs all obvious in here com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop():
[java]/**
- execute one iteration of the render loop in the OpenGL thread
*/
protected void runLoop(){
if (!created.get())
throw new IllegalStateException();
listener.update();//XXX: this is our update()
if (renderable.get()){
assert checkGLError();
// calls swap buffers, etc.
try {
if (autoFlush){
Display.update();
}else{
Display.processMessages();
Thread.sleep(50);
// add a small wait
// to reduce CPU usage
}
} catch (Throwable ex){
listener.handleError(âError while swapping buffersâ, ex);
}
}
if (frameRate > 0)
Display.sync(frameRate);//XXX: this is the setFrameRate sleeper
if (renderable.get() && autoFlush)
renderer.onFrame();
}[/java]
that Display.update or that processMessages, both eventually call org.lwjgl.opengl.Display.pollDevices() which kinda sense the input (all that you pressed before reaching that call) - at least how I see it
therefore since the setFrameRate delay happens in the Display.sync() call below that, then itâs only natural that the inputs are not sensed in the next frame (at least not before calling Application.update() ) , so only on the frame after the next frame update() can touch them
EDIT: I also updated the topic title , added âwhen setFrameRate(1)â, because it apparently does delay input by 1 frame only in this case(when using setFrameRate with a low value?), although I was wrong for the initial case when I thought it was delayed all the timeâŚ
I donât know, Iâm kinda just saying or stating how it is nowâŚ
Wasnât actually thinking of a solution, ⌠let me see now,
the way it is now, we sense the input before the wait but also itâs after the update, which means, if we press a key while the wait happens, the next update wonât sense that, because the input is sensed after the update⌠erm ok iâm starting to not make sense (i sense :))
I guess I would try to Display.pollDevices() at right before inputManager is processing its own queue ? that is, before the update, which means as you said, after the âwaitâ (aka after Display.sync)
Iâm not exactly sure what Display.update(); does, but assuming it refreshes the display (ie. shows the current state of Spatials on screen, aka renders), then I would maybe pull out the Display.processMessages(); from inside it, and the one in the âif elseâ part, and put them right before the update() aka before listener.update();
- though I am not exactly sure how would this affect other things (like the display.update)
also donât know what renderer.onFrame(); is supposed to do (yet), but Iâd probably do as I said instead of putting processMessages() right after the Display.sync()
Okay in the latest SVN I moved the input polling to after the wait, can you try again now?
Thanks!, tried it and it works as expected (on my other program also) with setFrameRate that is; (jme3 7382)
also, what file stores preferences like resolution selected in the settings dialog, because i realized itâs been storing my setFrameRate of 1 fps somewhere, and it keeps loading it if I app.setShowSettings(false); and donât setFrameRate myself
trying to use process monitor to find out the file but itâs a lot of noise Iâve to filter thru
EDIT: oh itâs in registry ⌠I couldâve almost miss it
HKEY_CURRENT_USERSoftwareJavaSoftPrefsj/Monkey /Engine 3.0
HKEY_CURRENT_USERSoftwareJavaSoftPrefsj/Monkey /Engine 3.0/Frame/Rate
I wonder when does it get unsetâŚ
EDIT2: I mean, once I set that (if I do it before showing the settings dialog) it gets saved and in effect forever, unless I use a different setFrameRate value, but just in case I want to unset it, like for maximum fps, Iâd have to hack set it to ie. 20000 maybe ?
Its not a file, its stored in the registry:
HKCU/Software/JavaSoft/Prefs
great
any idea how to unset it? from my java program I mean ie. delete it
Set some settings on the AppSettings and then call save() on it
Summary: I have to use setFrameRate(0); to disable any frame rate limitations, if I previously used setFrameRate and my settings got saved
======
I could use setFrameRate(0) to avoid any limitations but it seems hacky
I tried this:
[java] public static void main(String[] args) throws BackingStoreException {
Input1FrameLag i = new Input1FrameLag();
AppSettings aps = new AppSettings(true);
aps.load(aps.getTitle());
aps.setVSync(false);
aps.setFrameRate(2);
aps.remove(âFrameRateâ);
aps.save(aps.getTitle());
i.setSettings(aps);
i.setShowSettings(false);
i.start();
}[/java]
but it doesnât remove FrameRate from registry, though it does remove it from the current game session ie. i.start() will behave as if no frame rate was set, good but not really portable this way
I guess the problem is, that {once you called setFrameRate in your program} and {you also allowed the settings dialog to be shown (ie. setShowSettings(true)) OR called AppSettings.save()} the value FrameRate is set in the registry, so it you later want it to not be in effect youâd have to call setFrameRate(0) either every time (if you never show the dialog but you do load the settings manually and you donât save them) OR call it once and then gets saved as 0 and while it is 0
[java]if (frameRate > 0)
Display.sync(frameRate);[/java]
this wonât get executed, which is fine, I guess, now that I think about it, I mean removing it from registry will cause it to be 0 anyway or less than 0 whatever
Though if you just do this:
[java]setFrameRate(1);[/java]
and then on the next run you comment it out, it will still be in effect (well unless {you never showed the settings dialog which auto saves it})