--- /dev/null
+#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()
+{
+}
--- /dev/null
+#ifndef GEOM_H_
+#define GEOM_H_
+
+bool init_geom();
+void destroy_geom();
+
+void faros();
+void ground();
+void xlogo();
+
+#endif /* GEOM_H_ */
#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);
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);
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()
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);
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()
{
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);
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;
}
--- /dev/null
+#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 */
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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);
+}
--- /dev/null
+#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_ */