reorganized everything
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 4 Oct 2018 13:56:48 +0000 (16:56 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 4 Oct 2018 13:56:48 +0000 (16:56 +0300)
new animation system with keyframes

src/geom.cc [new file with mode: 0644]
src/geom.h [new file with mode: 0644]
src/main.cc
src/seq.cc [new file with mode: 0644]
src/seq.h [new file with mode: 0644]
src/track.cc [new file with mode: 0644]
src/track.h [new file with mode: 0644]

diff --git a/src/geom.cc b/src/geom.cc
new file mode 100644 (file)
index 0000000..804c18f
--- /dev/null
@@ -0,0 +1,117 @@
+#include <GL/glew.h>
+#include <GL/freeglut.h>
+#include "geom.h"
+#include "sdr.h"
+
+static unsigned int sdr_curve_top;
+
+bool init_geom()
+{
+       if(!(sdr_curve_top = create_program_load("sdr/curve_top.v.glsl", "sdr/curve_top.f.glsl"))) {
+               return false;
+       }
+       return true;
+}
+
+void destroy_geom()
+{
+       free_program(sdr_curve_top);
+}
+
+void faros()
+{
+       // kormos
+       glPushMatrix();
+       glScalef(1.1, 3, 1.1);
+       glTranslatef(0, 0.5, 0);
+       glutSolidCube(1.0);
+       glPopMatrix();
+
+       glShadeModel(GL_FLAT);
+
+       // base
+       glPushMatrix();
+       glRotatef(90, 1, 0, 0);
+       glTranslatef(0, -0.15, 0);
+       glutSolidCylinder(2, 0.3, 16, 1);
+       glPopMatrix();
+
+       // middle cylinder
+       glPushMatrix();
+       glTranslatef(0, 3, 0);
+       glRotatef(22.5, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glutSolidCylinder(0.5, 1.0, 8, 1);
+       glPopMatrix();
+
+       // trim middle cylinder (mporntoura)
+       glPushMatrix();
+       glTranslatef(0, 3.9, 0);
+       glRotatef(22.5, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glutSolidCylinder(0.55, 0.02, 8, 1);
+       glPopMatrix();
+
+       // top smaller cylinder
+       glPushMatrix();
+       glTranslatef(0, 4, 0);
+       glRotatef(22.5, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glutSolidCylinder(0.28, 0.5, 8, 1);
+       glPopMatrix();
+
+       // top wire even smaller cylinder
+       glPushMatrix();
+       glTranslatef(0, 4.5, 0);
+       glRotatef(22.5, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glutWireCylinder(0.18, 0.3, 9, 3);
+       glPopMatrix();
+
+       glShadeModel(GL_SMOOTH);
+
+       // top troulos
+       glPushMatrix();
+       glTranslatef(0, 4.8, 0);
+       glRotatef(22.5, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glutSolidCone(0.18, 0.2, 9, 1);
+       glPopMatrix();
+
+       // tsamploukano
+       glPushMatrix();
+       glTranslatef(-0.28, 4, 0);
+       glScalef(1, 13, 1);
+       glutSolidSphere(0.1, 16, 16);
+       glPopMatrix();
+
+       //pyramid on top of kormos
+       bind_program(sdr_curve_top);
+
+       glPushMatrix();
+       glTranslatef(0, 3, 0);
+       glRotatef(45, 0, 1, 0);
+       glRotatef(-90, 1, 0, 0);
+       glScalef(1, 1, 0.45);
+       glutSolidCylinder(1, 1, 4, 16);
+       glPopMatrix();
+
+       bind_program(0);
+}
+
+
+void ground()
+{
+       glPushMatrix();
+
+       glTranslatef(0, -1.25, 0);
+       glScalef(1, 0.1, 1);
+
+       glutSolidSphere(10, 32, 32);
+
+       glPopMatrix();
+}
+
+void xlogo()
+{
+}
diff --git a/src/geom.h b/src/geom.h
new file mode 100644 (file)
index 0000000..14ba125
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef GEOM_H_
+#define GEOM_H_
+
+bool init_geom();
+void destroy_geom();
+
+void faros();
+void ground();
+void xlogo();
+
+#endif /* GEOM_H_ */
index a2164a4..245c87f 100644 (file)
@@ -3,30 +3,26 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <assert.h>
 
 #include "sdr.h"
-
-#define CURVE_VS "sdr/curve_top.v.glsl"
-#define CURVE_FS "sdr/curve_top.f.glsl"
-#define BEAM_VS "sdr/beam.v.glsl"
-#define BEAM_FS "sdr/beam.f.glsl"
+#include "geom.h"
+#include "seq.h"
 
 #define BEAM_SHELLS 40
 #define BEAM_RMIN 0.01
 #define BEAM_RMAX 0.125
 #define BEAM_ENERGY 0.02
 #define BEAM_LEN 16.0
+#define BEAM_DEF_SPEED 0.1
 
 static bool init();
 static void cleanup();
 
-static void faros();
+static void display();
 static void light();
-static void ground();
 static void backdrop();
-static void xlogo();
 
-static void display();
 static void idle();
 static void reshape(int x, int y);
 static void keyboard(unsigned char c, int x, int y);
@@ -34,15 +30,16 @@ static void mbutton(int bn, int state, int x, int y);
 static void mmotion(int x, int y);
 
 static float cam_theta = 45, cam_phi, cam_dist = 10;
-static unsigned int sdr_curve_top, sdr_beam, sdr_sky;
+static unsigned int sdr_beam, sdr_sky;
 static long start_time;
-static float anim_speed = 1.0;
 static long anim_stop_time;
-static long tmsec;
+static long tmsec, prev_tmsec;
 
 static const float sil_color[] = {0.05, 0.02, 0.1, 1.0};
 static const float beam_color[] = {0.5, 0.4, 0.2, 1.0};
 
+static float beam_angle, beam_speed;
+
 int main(int argc, char **argv)
 {
        glutInit(&argc, argv);
@@ -81,105 +78,67 @@ static bool init()
 
        glEnable(GL_NORMALIZE);
 
-       if(!(sdr_curve_top = create_program_load(CURVE_VS, CURVE_FS)))
+       if(!init_geom()) {
                return false;
-
-       if(!(sdr_beam = create_program_load(BEAM_VS, BEAM_FS)))
+       }
+       if(!(sdr_beam = create_program_load("sdr/beam.v.glsl", "sdr/beam.f.glsl")))
                return false;
 
        if(!(sdr_sky = create_program_load("sdr/sky.v.glsl", "sdr/sky.f.glsl"))) {
                return false;
        }
 
+       if(!init_seq()) {
+               return false;
+       }
+       add_seq_track("beam-speed", INTERP_SIGMOID, EXTRAP_CLAMP, BEAM_DEF_SPEED);
+       load_seq("seq");
+
        start_time = glutGet(GLUT_ELAPSED_TIME);
+       prev_tmsec = start_time;
        return true;
 }
 
 static void cleanup()
 {
+       destroy_seq();
+       destroy_geom();
+       free_program(sdr_beam);
+       free_program(sdr_sky);
 }
 
-static void faros()
+static void display()
 {
-       glColor3fv(sil_color);
+       tmsec = (long)glutGet(GLUT_ELAPSED_TIME) - start_time;
+       float dt = (tmsec - prev_tmsec) / 1000.0f;
+       prev_tmsec = tmsec;
 
-       // kormos
-       glPushMatrix();
-       glScalef(1.1, 3, 1.1);
-       glTranslatef(0, 0.5, 0);
-       glutSolidCube(1.0);
-       glPopMatrix();
-
-       glShadeModel(GL_FLAT);
-
-       // base
-       glPushMatrix();
-       glRotatef(90, 1, 0, 0);
-       glTranslatef(0, -0.15, 0);
-       glutSolidCylinder(2, 0.3, 16, 1);
-       glPopMatrix();
-
-       // middle cylinder
-       glPushMatrix();
-       glTranslatef(0, 3, 0);
-       glRotatef(22.5, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glutSolidCylinder(0.5, 1.0, 8, 1);
-       glPopMatrix();
-
-       // trim middle cylinder (mporntoura)
-       glPushMatrix();
-       glTranslatef(0, 3.9, 0);
-       glRotatef(22.5, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glutSolidCylinder(0.55, 0.02, 8, 1);
-       glPopMatrix();
+       if(anim_stop_time) dt = 0.0f;
 
-       // top smaller cylinder
-       glPushMatrix();
-       glTranslatef(0, 4, 0);
-       glRotatef(22.5, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glutSolidCylinder(0.28, 0.5, 8, 1);
-       glPopMatrix();
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       backdrop();
 
-       // top wire even smaller cylinder
-       glPushMatrix();
-       glTranslatef(0, 4.5, 0);
-       glRotatef(22.5, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glutWireCylinder(0.18, 0.3, 9, 3);
-       glPopMatrix();
+       glMatrixMode(GL_MODELVIEW);
+       glLoadIdentity();
 
-       glShadeModel(GL_SMOOTH);
+       glTranslatef(0, -2, -cam_dist);
+       glRotatef(cam_phi, 1, 0, 0);
+       glRotatef(cam_theta, 0, 1, 0);
 
-       // top troulos
-       glPushMatrix();
-       glTranslatef(0, 4.8, 0);
-       glRotatef(22.5, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glutSolidCone(0.18, 0.2, 9, 1);
-       glPopMatrix();
+       glColor3fv(sil_color);
+       ground();
+       faros();
 
-       // tsamploukano
        glPushMatrix();
-       glTranslatef(-0.28, 4, 0);
-       glScalef(1, 13, 1);
-       glutSolidSphere(0.1, 16, 16);
-       glPopMatrix();
 
-       //pyramid on top of kormos
-       bind_program(sdr_curve_top);
+       beam_speed = get_seq_value("beam-speed", tmsec);
+       beam_angle += beam_speed * 360.0f * dt;
+       glRotatef(beam_angle, 0, 1, 0);
+       light();
 
-       glPushMatrix();
-       glTranslatef(0, 3, 0);
-       glRotatef(45, 0, 1, 0);
-       glRotatef(-90, 1, 0, 0);
-       glScalef(1, 1, 0.45);
-       glutSolidCylinder(1, 1, 4, 16);
        glPopMatrix();
 
-       bind_program(0);
+       glutSwapBuffers();
 }
 
 static void light()
@@ -213,19 +172,6 @@ static void light()
        glPopAttrib();
 }
 
-static void ground()
-{
-       glPushMatrix();
-
-       glTranslatef(0, -1.25, 0);
-       glScalef(1, 0.1, 1);
-
-       glColor3fv(sil_color);
-       glutSolidSphere(10, 32, 32);
-
-       glPopMatrix();
-}
-
 static void backdrop()
 {
        glFrontFace(GL_CW);
@@ -235,40 +181,7 @@ static void backdrop()
        glFrontFace(GL_CCW);
 }
 
-static void display()
-{
-       if(anim_stop_time > 0) {
-               tmsec = anim_stop_time - start_time;
-       } else {
-               tmsec = (long)glutGet(GLUT_ELAPSED_TIME) - start_time;
-       }
 
-       float tsec = (float)tmsec / 1000.0;
-       float tanim = tsec * anim_speed;
-
-       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-       backdrop();
-
-       glMatrixMode(GL_MODELVIEW);
-       glLoadIdentity();
-
-       glTranslatef(0, -2, -cam_dist);
-       glRotatef(cam_phi, 1, 0, 0);
-       glRotatef(cam_theta, 0, 1, 0);
-
-       ground();
-       faros();
-
-       glPushMatrix();
-
-       float beam_angle = tanim * 0.1 * 360;
-       glRotatef(beam_angle, 0, 1, 0);
-       light();
-
-       glPopMatrix();
-
-       glutSwapBuffers();
-}
 
 static void idle()
 {
@@ -285,25 +198,29 @@ static void reshape(int x, int y)
        gluPerspective(50, (float)x / (float)y, 0.5, 500);
 }
 
-static long calc_timeshift(float prev_speed, float speed)
-{
-       long delta = tmsec * speed - tmsec * prev_speed;
-       return delta / speed;
-}
-
 #define ANIM_DELTA     0.5
 
 static void keyboard(unsigned char c, int x, int y)
 {
-       float prev_anim_speed;
+       int idx;
+       static float orig_beam_speed;
 
        switch(c) {
        case 27:
                exit(0);
 
+       case '\b':
+               start_time = glutGet(GLUT_ELAPSED_TIME);
+               prev_tmsec = 0;
+               anim_stop_time = 0;
+               beam_angle = 0;
+               break;
+
        case ' ':
                if(anim_stop_time > 0) {
-                       start_time += glutGet(GLUT_ELAPSED_TIME) - anim_stop_time;
+                       long msec = glutGet(GLUT_ELAPSED_TIME);
+                       start_time += msec - anim_stop_time;
+                       prev_tmsec = msec - start_time;
                        anim_stop_time = 0;
                } else {
                        anim_stop_time = glutGet(GLUT_ELAPSED_TIME);
@@ -311,17 +228,35 @@ static void keyboard(unsigned char c, int x, int y)
                break;
 
        case '=':
-               start_time += calc_timeshift(anim_speed, anim_speed + ANIM_DELTA);
-               anim_speed += ANIM_DELTA;
+               beam_speed = get_seq_value("beam-speed", tmsec);
+               clear_seq_track("beam-speed");
+               set_seq_value("beam-speed", tmsec, beam_speed + ANIM_DELTA);
                break;
 
        case '-':
-               prev_anim_speed = anim_speed;
-               anim_speed -= ANIM_DELTA;
-               if(anim_speed < 0)
-                       anim_speed = 0;
-               start_time += calc_timeshift(prev_anim_speed, anim_speed);
+               beam_speed = get_seq_value("beam-speed", tmsec) - ANIM_DELTA;
+               if(beam_speed < 0)
+                       beam_speed = 0;
+               clear_seq_track("beam-speed");
+               set_seq_value("beam-speed", tmsec, beam_speed);
                break;
+
+       case '\r':
+       case '\n':
+               idx = find_seq_track("beam-speed");
+               assert(idx >= 0);
+               if(get_seq_value(idx, tmsec) > 0.0) {
+                       clear_seq_track(idx);
+                       set_seq_value(idx, tmsec, beam_speed);
+                       set_seq_value(idx, tmsec + 3000, 0);
+                       orig_beam_speed = beam_speed;
+               } else {
+                       clear_seq_track(idx);
+                       set_seq_value(idx, tmsec, 0);
+                       set_seq_value(idx, tmsec + 3000, orig_beam_speed);
+               }
+               break;
+
        default:
                break;
        }
diff --git a/src/seq.cc b/src/seq.cc
new file mode 100644 (file)
index 0000000..29036a5
--- /dev/null
@@ -0,0 +1,103 @@
+#include <string.h>
+#include <vector>
+#include "seq.h"
+#include "track.h"
+
+struct SeqTrack {
+       char *name;
+       Track *track;
+};
+
+static std::vector<SeqTrack> tracks;
+
+bool init_seq()
+{
+       return true;
+}
+
+void destroy_seq()
+{
+       int ntrk = tracks.size();
+       for(int i=0; i<ntrk; i++) {
+               delete tracks[i].track;
+               delete [] tracks[i].name;
+       }
+       tracks.clear();
+}
+
+int add_seq_track(const char *name, InterpMode inmode, ExtrapMode exmode, float defval)
+{
+       int idx = find_seq_track(name);
+       if(idx >= 0) return idx;
+
+       SeqTrack st;
+       st.name = new char[strlen(name) + 1];
+       strcpy(st.name, name);
+       st.track = new Track;
+       st.track->defval = defval;
+       st.track->interp = inmode;
+       st.track->extrap = exmode;
+       tracks.push_back(st);
+       return tracks.size() - 1;
+}
+
+int find_seq_track(const char *name)
+{
+       int ntrk = tracks.size();
+       for(int i=0; i<ntrk; i++) {
+               if(strcmp(tracks[i].name, name) == 0) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+Track *get_seq_track(int idx)
+{
+       return tracks[idx].track;
+}
+
+void clear_seq_track(int idx)
+{
+       tracks[idx].track->clear();
+}
+
+void clear_seq_track(const char *name)
+{
+       int idx = find_seq_track(name);
+       if(idx >= 0) {
+               tracks[idx].track->clear();
+       }
+}
+
+void set_seq_value(int idx, long tm, float val)
+{
+       tracks[idx].track->set_key(tm, val);
+}
+
+void set_seq_value(const char *name, long tm, float val)
+{
+       int idx = find_seq_track(name);
+       if(idx >= 0) {
+               tracks[idx].track->set_key(tm, val);
+       }
+}
+
+float get_seq_value(int idx, long tm)
+{
+       return (*tracks[idx].track)(tm);
+}
+
+float get_seq_value(const char *name, long tm)
+{
+       int idx = find_seq_track(name);
+       if(idx < 0) {
+               return 0.0f;
+       }
+       return (*tracks[idx].track)(tm);
+}
+
+bool load_seq(const char *fname)
+{
+       return false;   /* TODO */
+}
diff --git a/src/seq.h b/src/seq.h
new file mode 100644 (file)
index 0000000..aebd836
--- /dev/null
+++ b/src/seq.h
@@ -0,0 +1,23 @@
+#ifndef ANIM_H_
+#define ANIM_H_
+
+#include "track.h"
+
+bool init_seq();
+void destroy_seq();
+
+int add_seq_track(const char *name, InterpMode inmode, ExtrapMode exmode, float defval);
+int find_seq_track(const char *name);
+Track *get_seq_track(int idx);
+
+void clear_seq_track(int idx);
+void clear_seq_track(const char *name);
+
+void set_seq_value(int idx, long tm, float val);
+void set_seq_value(const char *name, long tm, float val);
+float get_seq_value(int idx, long tm);
+float get_seq_value(const char *name, long tm);
+
+bool load_seq(const char *fname);
+
+#endif /* ANIM_H_ */
diff --git a/src/track.cc b/src/track.cc
new file mode 100644 (file)
index 0000000..bc775ba
--- /dev/null
@@ -0,0 +1,146 @@
+#include <assert.h>
+#include <algorithm>
+#include "track.h"
+
+static long remap_time(ExtrapMode mode, long t, long t0, long t1);
+static float smoothstep(float a, float b, float x);
+
+Track::Track()
+{
+       interp = INTERP_SIGMOID;
+       extrap = EXTRAP_CLAMP;
+       keys_sorted = true;
+       defval = 0.0f;
+}
+
+void Track::clear()
+{
+       keys.clear();
+}
+
+void Track::set_key(long tm, float val)
+{
+       int idx = find_key(tm);
+       if(idx >= 0) {
+               keys[idx].value = val;
+               return;
+       }
+
+       TrackKey key = {tm, val};
+       keys.push_back(key);
+       keys_sorted = false;
+}
+
+float Track::get_key(long tm) const
+{
+       int idx = find_key(tm);
+       if(idx == -1) return 0.0f;
+       return keys[idx].value;
+}
+
+int Track::find_key(long tm) const
+{
+       int sz = (int)keys.size();
+       for(int i=0; i<sz; i++) {
+               if(keys[i].time == tm) return i;
+       }
+       return -1;
+}
+
+static bool keycmp(const TrackKey &a, const TrackKey &b)
+{
+       return a.time < b.time;
+}
+
+float Track::operator ()(long tm) const
+{
+       if(keys.empty()) {
+               return defval;
+       }
+
+       int nkeys = keys.size();
+       if(nkeys == 1) {
+               return keys[0].value;
+       }
+       if(!keys_sorted) {
+               Track *track = (Track*)this;
+               std::sort(track->keys.begin(), track->keys.end(), keycmp);
+               keys_sorted = true;
+       }
+
+       long tstart = keys[0].time;
+       long tend = keys[nkeys - 1].time;
+
+       tm = remap_time(extrap, tm, tstart, tend);
+
+       int idx0 = get_interval(tm);
+       assert(idx0 >= 0 && idx0 < nkeys);
+       int idx1 = idx0 + 1;
+
+       if(idx0 == nkeys - 1) {
+               return keys[idx0].value;
+       }
+
+       float dt = (float)(keys[idx1].time - keys[idx0].time);
+       float t = (float)(tm - keys[idx0].time) / dt;
+
+       switch(interp) {
+       case INTERP_STEP:
+               return keys[idx0].value;
+
+       case INTERP_SIGMOID:
+               t = smoothstep(0, 1, t);
+       case INTERP_LINEAR:
+               return keys[idx0].value + (keys[idx1].value - keys[idx0].value) * t;
+
+       default:
+               break;
+       }
+       return 0.0f;
+}
+
+int Track::get_interval(long tm) const
+{
+       int nkeys = (int)keys.size();
+
+       for(int i=0; i<nkeys-1; i++) {
+               if(tm < keys[i + 1].time) {
+                       return i;
+               }
+       }
+       return nkeys - 1;
+}
+
+static long remap_time(ExtrapMode mode, long t, long t0, long t1)
+{
+       long interval = t1 - t0;
+
+       switch(mode) {
+       case EXTRAP_CLAMP:
+               if(interval <= 0) return t0;
+               return t < t0 ? t0 : (t >= t1 ? t1 : t);
+
+       case EXTRAP_REPEAT:
+               if(interval > 0) {
+                       long x = (t - t0) % interval;
+                       if(x < 0) x += interval;
+                       return x + t0;
+               }
+               return t0;
+
+       default:
+               break;
+       }
+
+       assert(!"unreachable");
+       return t;
+}
+
+static float smoothstep(float a, float b, float x)
+{
+       if(x < a) return 0.0f;
+       if(x >= b) return 1.0f;
+
+       x = (x - a) / (b - a);
+       return x * x * (3.0f - 2.0f * x);
+}
diff --git a/src/track.h b/src/track.h
new file mode 100644 (file)
index 0000000..b80562e
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef TRACK_H_
+#define TRACK_H_
+
+#include <vector>
+
+enum InterpMode {
+       INTERP_STEP,
+       INTERP_LINEAR,
+       INTERP_SIGMOID
+};
+
+enum ExtrapMode {
+       EXTRAP_CLAMP,
+       EXTRAP_REPEAT
+};
+
+struct TrackKey {
+       long time;
+       float value;
+};
+
+class Track {
+private:
+       std::vector<TrackKey> keys;
+       mutable bool keys_sorted;
+
+       int get_interval(long tm) const;
+
+public:
+       InterpMode interp;
+       ExtrapMode extrap;
+       float defval;
+
+       Track();
+
+       void clear();
+
+       void set_key(long tm, float val);
+       float get_key(long tm) const;
+       int find_key(long tm) const;
+
+       float operator ()(long tm) const;
+};
+
+#endif /* TRACK_H_ */