Added timer_callback sample for user callbacks
[freeglut] / progs / demos / timer_callback / timer.c
1 /* Timer (callback) demo
2  *
3  * Written by John Tsiombikas <nuclear@member.fsf.org>
4  * Modified by Vincent Simonetti
5  *
6  * A modification of the timer sample, but with this
7  * offering a use of the user-data callback.
8  */
9 #include <stdio.h>
10 #include <GL/freeglut.h>
11
12 struct display_index_s
13 {
14         /* color index will be advanced every time the timer expires */
15         int surround_color_index;
16         int center_color_index;
17 };
18 typedef struct display_index_s display_index_t;
19
20 struct timer_state_s
21 {
22         int* color_index_ptr;
23         int* timer_time_ptr;
24 };
25 typedef struct timer_state_s timer_state_t;
26
27 struct menu_state_s
28 {
29         int* timer_time_ptr;
30         int menu_id;
31 };
32 typedef struct menu_state_s menu_state_t;
33
34 void disp(void* uptr);
35 void timer_func(int which, void* uptr);
36
37 const float color[][3] = {
38         {1, 0, 0},
39         {0, 1, 0},
40         {0, 0, 1},
41         {1, 1, 0},
42         {0, 1, 1},
43         {1, 0, 1}
44 };
45 const int timerInts[] = {
46     250,
47     500,
48     1000
49 };
50
51 void createMenuEntries(menu_state_t* menuState)
52 {
53         int i;
54     for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
55     {
56         char temp[10] = {'\0'};
57         /* flag current value */
58         if ((*menuState->timer_time_ptr) == timerInts[i])
59             temp[0] = '+';
60         else
61             temp[0] = '-';
62
63         sprintf(temp + 1, " %4d ms", timerInts[i]);
64
65         glutAddMenuEntry(temp, timerInts[i]);
66     }
67 }
68
69 void updateMenuEntries(menu_state_t* menuState)
70 {
71         int i;
72     for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
73     {
74         char temp[10] = { '\0' };
75         /* flag current value */
76         if ((*menuState->timer_time_ptr) == timerInts[i])
77             temp[0] = '+';
78         else
79             temp[0] = '-';
80
81         sprintf(temp + 1, " %4d ms", timerInts[i]);
82
83         glutChangeToMenuEntry(i+1, temp, timerInts[i]);
84     }
85 }
86
87 void MenuHandler(int timerInt, void* user_ptr)
88 {
89         menu_state_t* menuState;
90         
91         if (!user_ptr)
92         {
93                 /* In case main menu is selected somehow */
94                 return;
95         }
96
97         menuState = (menu_state_t*)user_ptr;
98
99         *menuState->timer_time_ptr = timerInt;
100         glutSetMenu(menuState->menu_id);
101         updateMenuEntries(menuState);
102 }
103
104 int main(int argc, char **argv)
105 {
106         int timerSurroundInt = 1000, timerCenterInt = 500;
107         display_index_t displayIndex = { 0, 2 };
108         timer_state_t surroundTimerState = { &displayIndex.surround_color_index, &timerSurroundInt };
109         timer_state_t centerTimerState = { &displayIndex.center_color_index, &timerCenterInt };
110         menu_state_t surroundMenuState = { &timerSurroundInt, 0 };
111         menu_state_t centerMenuState = { &timerCenterInt, 0 };
112
113         glutInit(&argc, argv);
114         glutInitWindowSize(128, 128);
115         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
116         glutCreateWindow("timer test");
117
118         glutDisplayFuncUcall(disp, &displayIndex);
119
120     /* get timer started, its reset in the timer function itself */
121     glutTimerFuncUcall(timerSurroundInt, timer_func, 1, &surroundTimerState);
122         glutTimerFuncUcall(timerCenterInt, timer_func, 2, &centerTimerState);
123
124     /* menus for setting timing */
125         surroundMenuState.menu_id = glutCreateMenuUcall(MenuHandler, &surroundMenuState);
126     createMenuEntries(&surroundMenuState);
127
128         centerMenuState.menu_id = glutCreateMenuUcall(MenuHandler, &centerMenuState);
129     createMenuEntries(&centerMenuState);
130
131     glutCreateMenuUcall(MenuHandler, NULL); /* doesn't matter, no clickable entries in this menu */
132     glutAddSubMenu("Center", centerMenuState.menu_id);
133     glutAddSubMenu("Surround", surroundMenuState.menu_id);
134     glutAttachMenu(GLUT_RIGHT_BUTTON);
135
136         glutMainLoop();
137         return 0;
138 }
139
140 void disp(void* user_ptr)
141 {
142         const display_index_t* displayIndex;
143         int cidx, pcidx;
144
145         displayIndex = (display_index_t*)user_ptr;
146         
147         cidx = displayIndex->surround_color_index;
148         glClearColor(color[cidx][0], color[cidx][1], color[cidx][2], 1);
149         glClear(GL_COLOR_BUFFER_BIT);
150
151         pcidx = displayIndex->center_color_index;
152     glPointSize(10.f);
153     glColor3f(color[pcidx][0], color[pcidx][1], color[pcidx][2]);
154     glBegin(GL_POINTS);
155         glVertex2i(0,0);
156     glEnd();
157
158         glutSwapBuffers();
159 }
160
161 void timer_func(int which, void* user_ptr)
162 {
163         const timer_state_t* timerState;
164         
165         timerState = (timer_state_t*)user_ptr;
166
167         /* advance the color index and trigger a redisplay */
168         *timerState->color_index_ptr = (*timerState->color_index_ptr + 1) % (sizeof color / sizeof *color);
169     
170         glutPostRedisplay();
171
172         /* (re)set the timer callback and ask glut to call it in x ms */
173     glutTimerFuncUcall(*timerState->timer_time_ptr, timer_func, which, user_ptr);
174 }