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