You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
For some applications (e.g. simulators) it's useful to be able to specify the next frame's world time, so you can control what time eventually gets fed to the ISceneAnimators' animateNode() function. I suspect it'd be useful for games as well, such as when you want to slow down or speed up the world.
Niko, in the next version of irrlicht, could you change ISceneManager::drawAll() to take a time parameter, as in:
I should've mentioned that this change would also help splitscreen/multi-window rendering as presented in the split-screen tutorial. In that tutorial, one renders to each of four screens by calling drawAll() four times. This means that each drawAll will show a world that has advanced a few milliseconds ahead of the last. This may not sound like much, but you never know. (My particular esoteric example is that using stereo vision on a virtual world would get screwed up if the right eye sees a time-delayed version of what the left eye sees).
PS: would there be any reason to give the gui manager's drawAll a time parameter? I suspect not.
PPS: maybe the Right Thing is to separate scene rendering and animator updating, but that'd probably break backward compatibility all over the place.
Symptom:
After implementing the above changes, RotationAnimators stop rotating their nodes.
Cause:
RotationAnimators keep track of the time at which the last call to AnimateNode() took place. This is so that in the next AnimateNode(), the animator knows how much time has passed, and knows how much to rotate the node by. The problem is that this "last AnimateNode() call time" is initialized in the constructor, as ITimer::getTime().
Under the changes described above, The user can provide arbitrary times to drawAll, which then get passed to AnimateNode. In my case, my user-specified world time started at 0, but the RotationAnimator had a stored "last call to AnimateNode() time" of several million (milliseconds). This set the rotation to somehing huge, so huge that subsequent incremental rotations were off the floating point scale and didn't do anything.
A solution:
Instead of initializing the "last call to AnimateNode() time" in the RotationAnimator constructor, I now have it initialized in the first call to AnimateNode(). I think this makes more sense anyway, even aside from user-specified world times. The delay between the construction of the animator and the first call to AnimateNode can be unpredictable, and what if a user wants a node to start at a specific orientation at that first frame?
Other issues this brings up:
Use quaternions in RotationAnimator?
Maybe instead of using euler angles as the differential rotation, one should use a quaternion. For one, since it's a cyclic representation, it would never get so huge that additional small rotations get discarded as floating point noise. But that probably won't happen too often anyway. The real value is that adding two euler angle sets is a messy approximation to rotation concatenation that only "works" when the added euler angle set is very small. Multiplying quaternions, however, performs rotation concatenation exactly for any two rotations.
I think I just add some features to the timer with the next release: Like stopping it, making it run slower, set a new time, etc. This would fix all problems.
I have been meaning to ask about the timers in Irrlicht, are they robust enough to not need your own soloution. Delta timing seems pointless with most if not all of the internal irrlicht update functions (because, I assume, it is using it behind the scenes already?).
The thing I am stumped with atm is scenenodeanimators not being able to run a splineanimator just once (no loop) or be able to intercept the point and stop it. I did notice the timing on this (over varying framerates) was near perfect, and I had 3 PCs all running in sync with massive framerate differences which was good.
I would prefer that the draw function be kept parameter free if possible...
Simply because its a draw function it needs to be as tight as possible, updateing world objects should be done in separate function and should be keep out of the beginScene() and endScene() calls.
If every object repositioned itself while being drawn it would be a nightmare.