Controls with bitmaps - c

How can I make a control using bitmaps which changes when I drag with the mouse (e.g. a rotating knob)? And this using the Win32 API?

Write code to recognize the WM_MOUSEWHEEL message in your control's window procedure.

The following is a typical loop you'll see in simple games. It's not good practice but a good basis to build upon:
while(!quit) {
while(evt = events_left_for_processing) {
react_to_event(evt);
}
draw_frame();
}
Pay special attention to the second "while", it is better to do it like this than to do an "if", you'll be able to process combined events more accurately.
After a while you may need time-based physics and it becomes more complicated (using accumulators).. A sample from a rather simple game I was writing:
/* Time-based animation loop.
* Accumulator idea picked from an article by Glenn Fiedler on gafferongames.com */
while(!done) {
/* Input */
while(SDL_PollEvent(&evt)) {
window_event(evt, &done);
}
/* Physics */
newTime = time();
deltaTime = newTime - currentTime;
if(deltaTime > 0.0f) {
currentTime = newTime;
accumulator += deltaTime;
while(accumulator >= dt) {
window_update(t, dt);
accumulator -= dt;
t += dt;
}
}
#ifdef FPS_CAPPED
drawTime = newTime - currentDrawTime;
/* Draw */
if(drawTime >= FPS_CAPPED) {
currentDrawTime = newTime;
#endif
window_draw();
SDL_GL_SwapBuffers();
#ifdef FPS_CAPPED
}
#endif
}
window_update etc are generalized functions (they execute a function in the game state, using function pointers).
In your case, the transformation of the square would be changed in the event handler, which catches mouse_move events and has a state for catching mouse_press/release events. In the update you would change the square's position/etc data. In the draw routine you would blit the square. (unless you use other frameworks like OpenGL which use matrix transforms in the render pipeline)

Related

Glut Idle Function with FrameRate Limit

My current OpenGL and Glut code uses this function to set a framerate limit
static int redisplay_interval;
void timer() {
glutPostRedisplay();
glutTimerFunc(redisplay_interval, timer, 0);
}
void SetFPS(int fps) {
redisplay_interval = 1000 / fps;
glutTimerFunc(redisplay_interval, timer, 0);
}
void Render() {
for
// iterate array of 3d objects movement 1 step
loop
glutSwapBuffers();
}
in Main:
glutDisplayFunc(Render);
SetFPS(60);
glutMainLoop();
...
However, I'm trying to update an array of 3D objects one step at a time and now I don't know where I would place it and make sure it iterates through the movement for loop once and then do a PostRedisplay with a frame rate limiter still in place.
A very similar topic and answer was also posted here:
https://stackoverflow.com/a/35612434/15578244
not sure on how to go about in my use case.

Reuse texture SDL

I'm making my first SDL2 game, I have a texture where I draw my game but after each rendering the texture is blanked, I need to have my original texture unmodified.
I have easily made this with surface but it was too slow.
I draw random artefacts on this texture that disappears with the time, I use SDL_RenderFill to shade the texture.
Anyone know how to do this ?
EDIT: Here's the code of the texture rendering
int gv_render(void) // This is called every 10ms
{
gv_lock;
int nexttimeout;
// Clear the screen
SDL_SetRenderTarget(renderer,NULL);
SDL_SetRenderDrawColor(renderer,0,0,0,255);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_NONE);
SDL_RenderClear(renderer);
// Render view specific stuff
SDL_SetRenderTarget(renderer,gv_screen); // gv_screen is my screen texture
switch (player_view) { // I have multiple views
case pvsound:nexttimeout=wave_render();break; // <- THE 2ND FUNCTION \/
};
SDL_RenderPresent(renderer);
// Final screen rendering
SDL_SetRenderTarget(renderer,NULL);
SDL_RenderCopy(renderer,gv_screen,NULL,NULL);
gv_unlock;
return nexttimeout;
};
int wave_render(void) // I (will) have multiple view modes
{
game_wave *currwave = firstwave; // First wave is the first element of a linked list
game_wave *prevwave = firstwave;
map_block* block;
map_block* oldblock;
gv_lock;
// Load the old texture
SDL_RenderCopy(renderer,gv_screen,NULL,NULL);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
// Dark the screen
SDL_SetRenderDrawColor(renderer,0,0,0,8);
SDL_RenderFillRect(renderer,NULL);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_NONE);
// Now I travel my list
while (currwave) {
// Apply block info
/* skipped non graphics */
// Draw the wave point
uint8_t light; // Wave have a strong that decrease with time
if (currwave->strong>=1.0)
light = 255; // Over 1 it don't decrease
else light = currwave->strong*255; // Now they aren't fully white
SDL_SetRenderDrawColor(renderer,light,light,light,255);
SDL_RenderDrawPoint(renderer, currwave->xpos,currwave->ypos);
// Switch to next wave
prevwave = currwave; // There also code is the skipped part
currwave = currwave->next;
};
SDL_RenderPresent(renderer);
gv_unlock;
return 10;
};
```
This seem to be complicated, as say #david C. Rankin the SDL renderer is faster than surface but more or less write-only (SDL_RenderReadPixels and SDL_UpdateTexture could do the job in non realtime case).
I have changed my method, I use a linked list of pixels coordinates with entry points in a 256 items array.
My source code is now :
struct game_wave_point {
struct game_wave_point *next;
int x;
int y;
};typedef struct game_wave_point game_wave_point;
game_wave_point* graph_waves[256] = {NULL,NULL,...};
wave_render(void)
{
game_wave *currwave = firstwave;
// Perform the darkening
int i;
uint8_t light;
for (i=1;i<=255;i++)
graph_waves[i-1] = graph_waves[i];
graph_waves[255] = NULL;
// Remove unvisible point
game_wave_point* newpoint;
while (graph_waves[0]) {
newpoint = graph_waves[0];
graph_waves[0] = newpoint->next;
free(newpoint);
};
// Wave heartbeat...
while (currwave) {
/* blablabla */
// Add the drawing point
newpoint = malloc(sizeof(game_wave_point));
newpoint->next = graph_waves[light];
newpoint->x = currwave->xpos*pixelsperblock;
newpoint->y = currwave->ypos*pixelsperblock;
if ((newpoint->x<0)|(newpoint->y<0))
free(newpoint);
else graph_waves[light] = newpoint;
/* blablabla */
};
// Now perform the drawing
for (i=1;i<=255;i++) {
newpoint = graph_waves[i];
SDL_SetRenderDrawColor(renderer,i,i,i,255);
SDL_GetRenderDrawColor(renderer,&light,NULL,NULL,NULL);
while (newpoint) {
SDL_RenderDrawPoint(renderer,newpoint->x,newpoint->y);
newpoint = newpoint->next;
};
};
return 10;
};
This work well on my computer (progressive slow appear in a case that I will never reach).
Next optimization maybe performed with Linux mremap(2) and similar, this will allow creating a simple array that work with SDL_RenderDrawPoints without slowness of realloc() on big array.

why is GlutPostRedisplay and sleep function is not working in this code?

i have tried to implement the data transfer between usb and cpu in this project. The data transfer is being shown as a small rectangle moving from one component of the computer to another.
In the code below, the GlutPostRedisplay does not work.
Also, can someone tell me if sleep() used is correct because the functions called in display do not work in sync. casing() is never executed. After fisrtscreen(), it directly jumps to opened() and operate() does not work.
what is the error with this code ??
void operate()
{
URLTEXTX = 200;
URLTEXTY = 950;
displayString(READUSB,1);
//southbrigde to northbrigde
bottom(488.0,425.0,380.0);
back(488.0,188.0,380.0);
top(188.0,380.0,550.0);
//northbridge to cpu
front(230.0,350.0,595.0);
top(345.0,600.0,650.0);
//read from usb
back(700.0,625.0,465.0);
bottom(625.0,460.0,385.0);
back(620.0,525.0,390.0);
sleep(1);
URLTEXTX = 200;
URLTEXTY = 950;
displayString(WRITEUSB,1);
//cpu to northbridge
bottom(350.0,650.0,595.0);
back(350.0,230.0,600.0);
//northbridge to southbridge
bottom(188.0,550.0,380.0);
front(188.0,488.0,380.0);
top(483.0,380.0,425.0);
//write to usb
front(525.0,625.0,385.0);
top(625.0,385.0,460.0);
front(620.0,700.0,460.0);
sleep(1);
URLTEXTX = 200;
URLTEXTY = 950;
displayString(READDVD,1);
//read from dvd
back(600.0,560.0,810.0);
bottom(570.0,810.0,600.0);
back(560.0,525.0,610.0);
//ram to northbridge
back(450.0,230.0,580.0);
//northbridge to cpu
front(230.0,350.0,595.0);
top(345.0,600.0,650.0);
sleep(1);
URLTEXTX = 200;
URLTEXTY = 950;
displayString(WRITEDVD,1);
//cpu to northbridge
bottom(350.0,650.0,595.0);
back(350.0,230.0,600.0);
//northbridge to ram
front(230.0,450.0,580.0);
//write to dvd
front(525.0,570.0,600.0);
top(570.0,600.0,800.0);
front(560.0,600.0,800.0);
sleep(1);
URLTEXTX = 200;
URLTEXTY = 950;
displayString(READHD,1);
//read from hard disc
back(640.0,560.0,300.0);
top(560.0,300.0,530.0);
back(560.0,525.0,530.0);
//ram to northbridge
back(450.0,230.0,580.0);
//northbridge to cpu
front(230.0,350.0,595.0);
top(345.0,600.0,650.0);
sleep(1);
URLTEXTX = 200;
URLTEXTY = 950;
displayString(WRITEHD,1);
//cpu to northbridge
bottom(350.0,650.0,595.0);
back(350.0,230.0,600.0);
//northbridge to ram
front(230.0,450.0,580.0);
//write to hard disc
front(525.0,560.0,530.0);
bottom(560.0,530.0,300.0);
front(560.0,640.0,300.0);
sleep(1);
}
void front(GLfloat x1,GLfloat x2,GLfloat y1)//to move in forward direction
{
GLfloat i;
for(i=x1;i<=x2;i++)
{
drawbit(i,x1+5,y1,y1-5);
glutPostRedisplay();
}
}
void back(GLfloat x1,GLfloat x2,GLfloat y1)//to move in backward direction
{
GLfloat i;
for(i=x1;i>=x2;i--)
{
drawbit(i,i-5,y1,y1-5);
glutPostRedisplay();
}
}
void top(GLfloat x1,GLfloat y1,GLfloat y2)//to move in upward direction
{
GLfloat i;
for(i=y1;i<=y2;i++)
{
drawbit(x1,x1+5,i,i+5);
glutPostRedisplay();
}
}
void bottom(GLfloat x1,GLfloat y1,GLfloat y2)//to move in downward direction
{
GLfloat i;
for(i=y1;i>=y2;i--)
{
drawbit(x1,x1-5,i,i-5);
glutPostRedisplay();
}
}
void drawbit(GLfloat x1,GLfloat x2,GLfloat y1,GLfloat y2)
{
glBegin(GL_POLYGON);
glColor3f(1.0,1.0,1.0);
glVertex2f(x1,y1);
glVertex2f(x2,y1);
glVertex2f(x2,y2);
glVertex2f(x1,y2);
glEnd();
glFlush();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
firstscreen(); //introduction to the project
sleep(3);
glClear(GL_COLOR_BUFFER_BIT);
casing(); //cpu case
sleep(2);
glClear(GL_COLOR_BUFFER_BIT);
opened(); //when cpu case is opened shows internal components
sleep(1);
operate(); //data transfer between various components
}
The problem is similar to this: Pausing in OpenGL successively
glutPostRedisplay simply sets a flag in glut to call your display callback on the next loop. It doesn't actually draw anything.
The function I suspect you're after is glutSwapBuffers. Without double buffering, geometry is drawn directly to the screen (although "draw" commands to the GPU are buffered for which you'd want glFlush). This commonly causes flickering because you see things that later get covered by closer geometry (because of the depth buffer). Double buffering solves this by rendering to an off-screen buffer and then displaying the result all at once. Make sure GLUT_DOUBLE is passed to glutInit so that you have a back buffer.
While you're sleep()ing, your application won't be able to capture and process events. Lets say you want to close the window. Until sleep returns the whole thing will be unresponsive. A sleep can still be important so you don't hog your CPU. I'd separate these concepts.
Loop/poll with an idle function until your delay time has elapsed. Then call glutPostRedisplay. Add glutSwapBuffers to display if you're double buffering.
Write a framerate limiter that calls sleep so you don't hog cycles.
A simple method to draw different things after set delays is to write a small state machine...
int state = STATE_INIT;
float timer = 0.0f;
void idle()
{
//insert framerate limiter here
//calculate time since last frame, perhaps using glutGet(GLUT_ELAPSED_TIME)
float deltaTime = ...
timer -= deltaTime;
if (timer < 0.0f)
{
switch (state)
{
case STATE_INIT:
state = STATE_DRAW_FIRST_THING;
timer = 123.0f;
...
}
glutPostRedisplay();
}
}
void display()
{
...
if (state == STATE_DRAW_FIRST_THING)
{
...
}
...
glutSwapBuffers();
}
As your app becomes bigger this I doubt this will be maintainable and you'll want something more robust, but until then this is a good start.
Simply changing a void (*currentView)(void); callback function in idle would save some hard coding in display. You might want to create an object orientated state machine. Beyond boolean states you might want to look into animation and keyframe interpolation. Rather than hard code everything, storing geometry, keyframes and state sequences in a file is a nice way to separate code and data. XML is very nice to work with for this provided you use a library.

How To Slow Down glutIdleFunc Animation Speed

Dear all I am trying to create animation using OpenGL through glutIdleFunc(). Below is my code:
float t = 0.0;
void idle (void)
{
t += 0.1;
if (t > 2*pi)
{
t = 0.0;
}
glutPostRedisplay();
}
//in main function
glutIdleFunc(idle);
I have been trying to adjust the increment of t in order to slow down my animation. But somehow my animation keeps moving on too fast, until I can't catch it with my eye. Does anyone know how to slow down this kind of animation? Thank's
You need to use the time since the last function call rather than a straight value as your metric, since that time may vary.
For more information, read valkea's answer on GameDev, which suggests that you use glutGet(GLUT_ELAPSED_TIME) to calculate that value.
Rather than trying to find an artificial t value to use in your idle function, you'll probably be better off using a real timer such as C's time(). Then, simply advance your animation by the appropriate amount given the elapsed time since the last frame was drawn.
Here's how it might look:
time_t lastTime;
void draw() {
const time_t now = time();
const double dt_s = difftime(now, lastTime);
// Update your frame based on the elapsed time. For example, update an angle
// based on a specified rotation rate (omega_deg_s):
const double omega_deg_s = 10.0;
angle += dt_s * omega_deg_s;
angle = fmod(angle, 360.0);
// Now draw something based on the new angle info:
draw_my_scene(angle);
// Record current time for next time:
lastTime = now;
}

Constant game speed independent of variable FPS in OpenGL with GLUT?

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 one.
After reading a couple of articles, tutorials and code from other people on how to achieve a constant game speed, I think that what I currently have implemented (I'll post the code below) is what Koen Witters called Game Speed dependent on Variable FPS, the second on his article.
First, through my searching experience, there's a couple of people that probably have the knowledge to help out on this but don't know what GLUT is and I'm going to try and explain (feel free to correct me) the relevant functions for my problem of this OpenGL toolkit. Skip this section if you know what GLUT is and how to play with it.
GLUT Toolkit:
GLUT is an OpenGL toolkit and helps with common tasks in OpenGL.
The glutDisplayFunc(renderScene) takes a pointer to a renderScene() function callback, which will be responsible for rendering everything. The renderScene() function will only be called once after the callback registration.
The glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0) takes the number of milliseconds to pass before calling the callback processAnimationTimer(). The last argument is just a value to pass to the timer callback. The processAnimationTimer() will not be called each TIMER_MILLISECONDS but just once.
The glutPostRedisplay() function requests GLUT to render a new frame so we need call this every time we change something in the scene.
The glutIdleFunc(renderScene) could be used to register a callback to renderScene() (this does not make glutDisplayFunc() irrelevant) but this function should be avoided because the idle callback is continuously called when events are not being received, increasing the CPU load.
The glutGet(GLUT_ELAPSED_TIME) function returns the number of milliseconds since glutInit was called (or first call to glutGet(GLUT_ELAPSED_TIME)). That's the timer we have with GLUT. I know there are better alternatives for high resolution timers, but let's keep with this one for now.
I think this is enough information on how GLUT renders frames so people that didn't know about it could also pitch in this question to try and help if they fell like it.
Current Implementation:
Now, I'm not sure I have correctly implemented the second solution proposed by Koen, Game Speed dependent on Variable FPS. The relevant code for that goes like this:
#define TICKS_PER_SECOND 30
#define MOVEMENT_SPEED 2.0f
const int TIMER_MILLISECONDS = 1000 / TICKS_PER_SECOND;
int previousTime;
int currentTime;
int elapsedTime;
void renderScene(void) {
(...)
// Setup the camera position and looking point
SceneCamera.LookAt();
// Do all drawing below...
(...)
}
void processAnimationTimer(int value) {
// setups the timer to be called again
glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0);
// Get the time when the previous frame was rendered
previousTime = currentTime;
// Get the current time (in milliseconds) and calculate the elapsed time
currentTime = glutGet(GLUT_ELAPSED_TIME);
elapsedTime = currentTime - previousTime;
/* Multiply the camera direction vector by constant speed then by the
elapsed time (in seconds) and then move the camera */
SceneCamera.Move(cameraDirection * MOVEMENT_SPEED * (elapsedTime / 1000.0f));
// Requests to render a new frame (this will call my renderScene() once)
glutPostRedisplay();
}
void main(int argc, char **argv) {
glutInit(&argc, argv);
(...)
glutDisplayFunc(renderScene);
(...)
// Setup the timer to be called one first time
glutTimerFunc(TIMER_MILLISECONDS, processAnimationTimer, 0);
// Read the current time since glutInit was called
currentTime = glutGet(GLUT_ELAPSED_TIME);
glutMainLoop();
}
This implementation doesn't fell right. It works in the sense that helps the game speed to be constant dependent on the FPS. So that moving from point A to point B takes the same time no matter the high/low framerate. However, I believe I'm limiting the game framerate with this approach. [EDIT: Each frame will only be rendered when the time callback is called, that means the framerate will be roughly around TICKS_PER_SECOND frames per second. This doesn't feel right, you shouldn't limit your powerful hardware, it's wrong. It's my understanding though, that I still need to calculate the elapsedTime. Just because I'm telling GLUT to call the timer callback every TIMER_MILLISECONDS, it doesn't mean it will always do that on time.]
I'm not sure how can I fix this and to be completely honest, I have no idea what is the game loop in GLUT, you know, the while( game_is_running ) loop in Koen's article. [EDIT: It's my understanding that GLUT is event-driven and that game loop starts when I call glutMainLoop() (which never returns), yes?]
I thought I could register an idle callback with glutIdleFunc() and use that as replacement of glutTimerFunc(), only rendering when necessary (instead of all the time as usual) but when I tested this with an empty callback (like void gameLoop() {}) and it was basically doing nothing, only a black screen, the CPU spiked to 25% and remained there until I killed the game and it went back to normal. So I don't think that's the path to follow.
Using glutTimerFunc() is definitely not a good approach to perform all movements/animations based on that, as I'm limiting my game to a constant FPS, not cool. Or maybe I'm using it wrong and my implementation is not right?
How exactly can I have a constant game speed with variable FPS? More exactly, how do I correctly implement Koen's Constant Game Speed with Maximum FPS solution (the fourth one on his article) with GLUT? Maybe this is not possible at all with GLUT? If not, what are my alternatives? What is the best approach to this problem (constant game speed) with GLUT?
[EDIT] Another Approach:
I've been experimenting and here's what I was able to achieve now. Instead of calculating the elapsed time on a timed function (which limits my game's framerate) I'm now doing it in renderScene(). Whenever changes to the scene happen I call glutPostRedisplay() (ie: camera moving, some object animation, etc...) which will make a call to renderScene(). I can use the elapsed time in this function to move my camera for instance.
My code has now turned into this:
int previousTime;
int currentTime;
int elapsedTime;
void renderScene(void) {
(...)
// Setup the camera position and looking point
SceneCamera.LookAt();
// Do all drawing below...
(...)
}
void renderScene(void) {
(...)
// Get the time when the previous frame was rendered
previousTime = currentTime;
// Get the current time (in milliseconds) and calculate the elapsed time
currentTime = glutGet(GLUT_ELAPSED_TIME);
elapsedTime = currentTime - previousTime;
/* Multiply the camera direction vector by constant speed then by the
elapsed time (in seconds) and then move the camera */
SceneCamera.Move(cameraDirection * MOVEMENT_SPEED * (elapsedTime / 1000.0f));
// Setup the camera position and looking point
SceneCamera.LookAt();
// All drawing code goes inside this function
drawCompleteScene();
glutSwapBuffers();
/* Redraw the frame ONLY if the user is moving the camera
(similar code will be needed to redraw the frame for other events) */
if(!IsTupleEmpty(cameraDirection)) {
glutPostRedisplay();
}
}
void main(int argc, char **argv) {
glutInit(&argc, argv);
(...)
glutDisplayFunc(renderScene);
(...)
currentTime = glutGet(GLUT_ELAPSED_TIME);
glutMainLoop();
}
Conclusion, it's working, or so it seems. If I don't move the camera, the CPU usage is low, nothing is being rendered (for testing purposes I only have a grid extending for 4000.0f, while zFar is set to 1000.0f). When I start moving the camera the scene starts redrawing itself. If I keep pressing the move keys, the CPU usage will increase; this is normal behavior. It drops back when I stop moving.
Unless I'm missing something, it seems like a good approach for now. I did find this interesting article on iDevGames and this implementation is probably affected by the problem described on that article. What's your thoughts on that?
Please note that I'm just doing this for fun, I have no intentions of creating some game to distribute or something like that, not in the near future at least. If I did, I would probably go with something else besides GLUT. But since I'm using GLUT, and other than the problem described on iDevGames, do you think this latest implementation is sufficient for GLUT? The only real issue I can think of right now is that I'll need to keep calling glutPostRedisplay() every time the scene changes something and keep calling it until there's nothing new to redraw. A little complexity added to the code for a better cause, I think.
What do you think?
glut is designed to be the game loop. When you call glutMainLoop(), it executes a 'for loop' with no termination condition except the exit() signal. You can implement your program kind of like you're doing now, but you need some minor changes. First, if you want to know what the FPS is, you should put that tracking into the renderScene() function, not in your update function. Naturally, your update function is being called as fast as specified by the timer and you're treating elapsedTime as a measure of time between frames. In general, that will be true because you're calling glutPostRedisplay rather slowly and glut won't try to update the screen if it doesn't need to (there's no need to redraw if the scene hasn't changed). However, there are other times that renderScene will be called. For example, if you drag something across the window. If you did that, you'd see a higher FPS (if you were properly tracking the FPS in the render function).
You could use glutIdleFunc, which is called continuously whenever possible--similar to the while(game_is_running) loop. That is, whatever logic you would otherwise put into that while loop, you could put into the callback for glutIdleFunc. You can avoid using glutTimerFunc by keeping track of the ticks on your own, as in the article you linked (using glutGet(GLUT_ELAPSED_TIME)).
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.

Resources