I\'ve been reading Koen Witters detailed article about different game loop solutions but I\'m having some problems implementing the last one with GLUT, which is the recommended
Have, as an example, a mouse-driven rotation matrix that updates at a fixed frame-rate, independently of the rendering frame-rate. In my program, space-bar toggles benchmarking mode, and determines the Boolean fxFPS.
Let go of the mouse button while dragging, and you can 'throw' an object transformed by this matrix.
If fxFPS is true then the rendering frame-rate is throttled to the animation frame-rate; otherwise identical frames are drawn repeatedly for benchmarking, even though not enough milliseconds will have passed to trigger any animation.
If you're thinking about slowing down AND speeding up frames, you have to think carefully about whether you mean rendering or animation frames in each case. In this example, render throttling for simple animations is combined with animation acceleration, for any cases when frames might be dropped in a potentially slow animation.
To accelerate the animation, rotations are performed repeatedly in a loop. Such a loop is not too slow compared with the option of doing trig with an adaptive rotation angle; just be careful what you put inside any loop that actually takes longer to execute, the lower the FPS. This loop takes far less than an extra frame to complete, for each frame-drop that it accounts for, so it's reasonably safe.
int xSt, ySt, xCr, yCr, msM = 0, msOld = 0;
bool dragging = false, spin = false, moving = false;
glm::mat4 mouseRot(1.0f), continRot(1.0f);
float twoOvHght; // Set in reshape()
glm::mat4 mouseRotate(bool slow) {
glm::vec3 axis(twoOvHght * (yCr - ySt), twoOvHght * (xCr - xSt), 0); // Perpendicular to mouse motion
float len = glm::length(axis);
if (slow) { // Slow rotation; divide angle by mouse-delay in milliseconds; it is multiplied by frame delay to speed it up later
int msP = msM - msOld;
len /= (msP != 0 ? msP : 1);
}
if (len != 0) axis = glm::normalize(axis); else axis = glm::vec3(0.0f, 0.0f, 1.0f);
return rotate(axis, cosf(len), sinf(len));
}
void mouseMotion(int x, int y) {
moving = (xCr != x) | (yCr != y);
if (dragging & moving) {
xSt = xCr; xCr = x; ySt = yCr; yCr = y; msOld = msM; msM = glutGet(GLUT_ELAPSED_TIME);
mouseRot = mouseRotate(false) * mouseRot;
}
}
void mouseButton(int button, int state, int x, int y) {
if (button == 0) {
if (state == 0) {
dragging = true; moving = false; spin = false;
xCr = x; yCr = y; msM = glutGet(GLUT_ELAPSED_TIME);
glutPostRedisplay();
} else {
dragging = false; spin = moving;
if (spin) continRot = mouseRotate(true);
}
}
}
And then later...
bool fxFPS = false;
int T = 0, ms = 0;
const int fDel = 20;
void display() {
ms = glutGet(GLUT_ELAPSED_TIME);
if (T <= ms) { T = ms + fDel;
for (int lp = 0; lp < fDel; lp++) {
orient = rotY * orient; orientCu = rotX * rotY * orientCu; // Auto-rotate two orientation quaternions
if (spin) mouseRot = continRot * mouseRot; // Track rotation from thowing action by mouse
}
orient1 = glm::mat4_cast(orient); orient2 = glm::mat4_cast(orientCu);
}
// Top secret animation code that will make me rich goes here
glutSwapBuffers();
if (spin | dragging) { if (fxFPS) while (glutGet(GLUT_ELAPSED_TIME) < T); glutPostRedisplay(); } // Fast, repeated updates of the screen
}
Enjoy throwing things around an axis; I find that most people do. Notice that the fps affects nothing whatsoever, in the interface or the rendering. I've minimised the use of divisions, so comparisons should be nice and accurate, and any inaccuracy in the clock does not accumulate unnecessarily.
Syncing of multiplayer games is another 18 conversations, I would judge.