fixed animation speed
[faros-demo] / src / main.cc
1 #include <GL/glew.h>
2 #include <GL/freeglut.h>
3
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 #include "sdr.h"
8
9 #define CURVE_VS "sdr/curve_top.v.glsl"
10 #define CURVE_FS "sdr/curve_top.f.glsl"
11 #define BEAM_VS "sdr/beam.v.glsl"
12 #define BEAM_FS "sdr/beam.f.glsl"
13
14 #define BEAM_SHELLS 40
15 #define BEAM_RMIN 0.01
16 #define BEAM_RMAX 0.125
17 #define BEAM_ENERGY 0.02
18 #define BEAM_LEN 16.0
19
20 static bool init();
21 static void cleanup();
22
23 static void faros();
24 static void light();
25 static void ground();
26 static void backdrop();
27 static void xlogo();
28
29 static void display();
30 static void idle();
31 static void reshape(int x, int y);
32 static void keyboard(unsigned char c, int x, int y);
33 static void mbutton(int bn, int state, int x, int y);
34 static void mmotion(int x, int y);
35
36 static float cam_theta = 45, cam_phi, cam_dist = 10;
37 static unsigned int sdr_curve_top, sdr_beam, sdr_sky;
38 static long start_time;
39 static float anim_speed = 1.0;
40 static long anim_stop_time;
41 static long tmsec;
42
43 static const float sil_color[] = {0.05, 0.02, 0.1, 1.0};
44 static const float beam_color[] = {0.5, 0.4, 0.2, 1.0};
45
46 int main(int argc, char **argv)
47 {
48         glutInit(&argc, argv);
49         glutInitWindowSize(800, 600);
50         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
51
52         glutCreateWindow("Faros");
53
54         glutDisplayFunc(display);
55         glutIdleFunc(idle);
56         glutReshapeFunc(reshape);
57         glutKeyboardFunc(keyboard);
58         glutMouseFunc(mbutton);
59         glutMotionFunc(mmotion);
60
61         if(!init()) {
62                 return 1;
63         }
64
65         atexit(cleanup);
66         glutMainLoop();
67
68         return 0;
69 }
70
71 static bool init()
72 {
73         glewInit();
74
75         glEnable(GL_CULL_FACE);
76         glEnable(GL_DEPTH_TEST);
77         glEnable(GL_MULTISAMPLE);
78
79 //      glEnable(GL_LIGHTING);
80         glEnable(GL_LIGHT0);
81
82         glEnable(GL_NORMALIZE);
83
84         if(!(sdr_curve_top = create_program_load(CURVE_VS, CURVE_FS)))
85                 return false;
86
87         if(!(sdr_beam = create_program_load(BEAM_VS, BEAM_FS)))
88                 return false;
89
90         if(!(sdr_sky = create_program_load("sdr/sky.v.glsl", "sdr/sky.f.glsl"))) {
91                 return false;
92         }
93
94         start_time = glutGet(GLUT_ELAPSED_TIME);
95         return true;
96 }
97
98 static void cleanup()
99 {
100 }
101
102 static void faros()
103 {
104         glColor3fv(sil_color);
105
106         // kormos
107         glPushMatrix();
108         glScalef(1.1, 3, 1.1);
109         glTranslatef(0, 0.5, 0);
110         glutSolidCube(1.0);
111         glPopMatrix();
112
113         glShadeModel(GL_FLAT);
114
115         // base
116         glPushMatrix();
117         glRotatef(90, 1, 0, 0);
118         glTranslatef(0, -0.15, 0);
119         glutSolidCylinder(2, 0.3, 16, 1);
120         glPopMatrix();
121
122         // middle cylinder
123         glPushMatrix();
124         glTranslatef(0, 3, 0);
125         glRotatef(22.5, 0, 1, 0);
126         glRotatef(-90, 1, 0, 0);
127         glutSolidCylinder(0.5, 1.0, 8, 1);
128         glPopMatrix();
129
130         // trim middle cylinder (mporntoura)
131         glPushMatrix();
132         glTranslatef(0, 3.9, 0);
133         glRotatef(22.5, 0, 1, 0);
134         glRotatef(-90, 1, 0, 0);
135         glutSolidCylinder(0.55, 0.02, 8, 1);
136         glPopMatrix();
137
138         // top smaller cylinder
139         glPushMatrix();
140         glTranslatef(0, 4, 0);
141         glRotatef(22.5, 0, 1, 0);
142         glRotatef(-90, 1, 0, 0);
143         glutSolidCylinder(0.28, 0.5, 8, 1);
144         glPopMatrix();
145
146         // top wire even smaller cylinder
147         glPushMatrix();
148         glTranslatef(0, 4.5, 0);
149         glRotatef(22.5, 0, 1, 0);
150         glRotatef(-90, 1, 0, 0);
151         glutWireCylinder(0.18, 0.3, 9, 3);
152         glPopMatrix();
153
154         glShadeModel(GL_SMOOTH);
155
156         // top troulos
157         glPushMatrix();
158         glTranslatef(0, 4.8, 0);
159         glRotatef(22.5, 0, 1, 0);
160         glRotatef(-90, 1, 0, 0);
161         glutSolidCone(0.18, 0.2, 9, 1);
162         glPopMatrix();
163
164         // tsamploukano
165         glPushMatrix();
166         glTranslatef(-0.28, 4, 0);
167         glScalef(1, 13, 1);
168         glutSolidSphere(0.1, 16, 16);
169         glPopMatrix();
170
171         //pyramid on top of kormos
172         bind_program(sdr_curve_top);
173
174         glPushMatrix();
175         glTranslatef(0, 3, 0);
176         glRotatef(45, 0, 1, 0);
177         glRotatef(-90, 1, 0, 0);
178         glScalef(1, 1, 0.45);
179         glutSolidCylinder(1, 1, 4, 16);
180         glPopMatrix();
181
182         bind_program(0);
183 }
184
185 static void light()
186 {
187         glPushAttrib(GL_ENABLE_BIT);
188         glDisable(GL_CULL_FACE);
189
190         glPushMatrix();
191
192         glTranslatef(0, 4.65, 0.2);
193         bind_program(sdr_beam);
194         set_uniform_float(sdr_beam, "beam_len", BEAM_LEN);
195
196         glEnable(GL_BLEND);
197         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
198
199         for(int i=0; i<BEAM_SHELLS; i++) {
200                 float t = (float)i / (float)(BEAM_SHELLS - 1);
201                 float rad = BEAM_RMIN + (BEAM_RMAX - BEAM_RMIN) * t;
202                 float alpha = BEAM_ENERGY / (t * t);
203
204                 glColor4f(beam_color[0], beam_color[1], beam_color[2], alpha);
205
206                 glutSolidCylinder(rad, BEAM_LEN, 12, 1);
207         }
208
209         bind_program(0);
210
211         glPopMatrix();
212
213         glPopAttrib();
214 }
215
216 static void ground()
217 {
218         glPushMatrix();
219
220         glTranslatef(0, -1.25, 0);
221         glScalef(1, 0.1, 1);
222
223         glColor3fv(sil_color);
224         glutSolidSphere(10, 32, 32);
225
226         glPopMatrix();
227 }
228
229 static void backdrop()
230 {
231         glFrontFace(GL_CW);
232         bind_program(sdr_sky);
233         glutSolidSphere(200, 16, 32);
234         bind_program(0);
235         glFrontFace(GL_CCW);
236 }
237
238 static void display()
239 {
240         if(anim_stop_time > 0) {
241                 tmsec = anim_stop_time - start_time;
242         } else {
243                 tmsec = (long)glutGet(GLUT_ELAPSED_TIME) - start_time;
244         }
245
246         float tsec = (float)tmsec / 1000.0;
247         float tanim = tsec * anim_speed;
248
249         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
250         backdrop();
251
252         glMatrixMode(GL_MODELVIEW);
253         glLoadIdentity();
254
255         glTranslatef(0, -2, -cam_dist);
256         glRotatef(cam_phi, 1, 0, 0);
257         glRotatef(cam_theta, 0, 1, 0);
258
259         ground();
260         faros();
261
262         glPushMatrix();
263
264         float beam_angle = tanim * 0.1 * 360;
265         glRotatef(beam_angle, 0, 1, 0);
266         light();
267
268         glPopMatrix();
269
270         glutSwapBuffers();
271 }
272
273 static void idle()
274 {
275         glutPostRedisplay();
276 }
277
278 static void reshape(int x, int y)
279 {
280         glViewport(0, 0, x, y);
281
282         glMatrixMode(GL_PROJECTION);
283         glLoadIdentity();
284
285         gluPerspective(50, (float)x / (float)y, 0.5, 500);
286 }
287
288 static long calc_timeshift(float prev_speed, float speed)
289 {
290         long delta = tmsec * speed - tmsec * prev_speed;
291         return delta / speed;
292 }
293
294 #define ANIM_DELTA      0.5
295
296 static void keyboard(unsigned char c, int x, int y)
297 {
298         float prev_anim_speed;
299
300         switch(c) {
301         case 27:
302                 exit(0);
303
304         case ' ':
305                 if(anim_stop_time > 0) {
306                         start_time += glutGet(GLUT_ELAPSED_TIME) - anim_stop_time;
307                         anim_stop_time = 0;
308                 } else {
309                         anim_stop_time = glutGet(GLUT_ELAPSED_TIME);
310                 }
311                 break;
312
313         case '=':
314                 start_time += calc_timeshift(anim_speed, anim_speed + ANIM_DELTA);
315                 anim_speed += ANIM_DELTA;
316                 break;
317
318         case '-':
319                 prev_anim_speed = anim_speed;
320                 anim_speed -= ANIM_DELTA;
321                 if(anim_speed < 0)
322                         anim_speed = 0;
323                 start_time += calc_timeshift(prev_anim_speed, anim_speed);
324                 break;
325         default:
326                 break;
327         }
328 }
329
330 static int prev_x, prev_y;
331 static bool bst[8];
332 static void mbutton(int bn, int state, int x, int y)
333 {
334         int button = bn - GLUT_LEFT_BUTTON;
335         bst[button] = state == GLUT_DOWN;
336
337         prev_x = x;
338         prev_y = y;
339 }
340
341 static void mmotion(int x, int y)
342 {
343         int dx = x - prev_x;
344         int dy = y - prev_y;
345
346         prev_x = x;
347         prev_y = y;
348
349         if (dx == 0 && dy == 0)
350                 return;
351
352         if (bst[0]) {
353                 cam_theta += dx * 0.5;
354                 cam_phi += dy * 0.5;
355
356                 if (cam_phi < -90)
357                         cam_phi = -90;
358
359                 if (cam_phi > 90)
360                         cam_phi = 90;
361         }
362
363         if (bst[2]) {
364                 cam_dist += dy * 0.1;
365
366                 if (cam_dist < 0)
367                         cam_dist = 0;
368         }
369 }