diff --git a/modes/Tunnel.cc b/modes/Tunnel.cc new file mode 100644 index 0000000..638a852 --- /dev/null +++ b/modes/Tunnel.cc @@ -0,0 +1,165 @@ + +#include +#include +#include +#include +#include + +#include +#include + +#include "Tunnel.h" + +using namespace std; + +#define N_INITIAL_LAYERS 5 +#define N_LOGOS_PER_RING 12 +#define RING_RADIUS 18 +#define BREAKOFF_DIST 80 +#define RING_LAYER_DIST 10 +#define XLATE_RATE 0.02 +#define REVOLUTION_TIME 15000 +#define DESTROY_DIST 200 +#define BREAK_RATE 0.03 + +Tunnel::Tunnel() +{ + m_last_ticks = 0; + srand(time(NULL) + getpid()); +} + +Tunnel::~Tunnel() +{ +} + +void Tunnel::getRandomBreakAxis(float (*axis)[3]) +{ + double alpha = rand() / (double)RAND_MAX * 2.0 * M_PI; + double beta = rand() / (double)RAND_MAX * M_PI_2; + (*axis)[0] = cos(alpha) * sin(beta); + (*axis)[2] = sin(alpha) * sin(beta); + (*axis)[1] = 0.5 + cos(beta); +} + +float Tunnel::getRandomBreakSpinSpeed() +{ + return 0.01 + rand() / (double)RAND_MAX * 0.01; +} + +bool Tunnel::expose (GnomeScreensaver & gs) +{ + if (m_last_ticks == 0) + { + m_last_ticks = gs.getTicks(); + m_start_ticks = m_last_ticks; + } + uint64_t ticks = gs.getTicks(); + int elapsed = ticks - m_last_ticks; + m_offset += XLATE_RATE * elapsed; + while (m_offset - m_last_ring_offset > RING_LAYER_DIST) + { + m_last_ring_offset += RING_LAYER_DIST; + addRing(m_last_ring_offset); + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(360.0 * + ((ticks - m_start_ticks) % REVOLUTION_TIME) / REVOLUTION_TIME, + 0, 1, 0); + for (list::iterator it = m_logos.begin(); + it != m_logos.end(); + it++) + { + double diff_offset = m_offset - it->offset; + if (diff_offset > DESTROY_DIST) + { + m_logos.erase(it++); + continue; + } + + if (it->break_ticks == 0 && diff_offset > BREAKOFF_DIST) + { + it->break_ticks = ticks; + getRandomAxis(&it->spin_axis); + getRandomBreakAxis(&it->break_axis); + it->spin_rate = getRandomBreakSpinSpeed(); + } + glPushMatrix(); + if (it->break_ticks) + { + int break_ticks = ticks - it->break_ticks; + glTranslatef(BREAK_RATE * break_ticks * it->break_axis[0], + BREAK_RATE * break_ticks * it->break_axis[1], + BREAK_RATE * break_ticks * it->break_axis[2]); + } + glTranslatef(0, diff_offset, 0); + glRotatef(it->trot, 0, 1, 0); + glTranslatef(RING_RADIUS, 0, 0); + glRotatef(-90.0, 0, 0, 1); + glRotatef(90.0, 1, 0, 0); + glRotatef(it->zrot, 0, 0, 1); + if (it->break_ticks) + { + glRotatef(it->spin_rate * (ticks - it->break_ticks), + it->spin_axis[0], + it->spin_axis[1], + it->spin_axis[2]); + } + m_logobox.draw(); + glPopMatrix(); + } + glPopMatrix(); + + m_last_ticks = ticks; + + return true; +} + +void Tunnel::addRing(double offset) +{ + for (int j = 0; j < N_LOGOS_PER_RING; j++) + { + float zrot = ((j + m_ring_rot_idx) & 0x3) * 90.0; + float trot = j * 360.0 / N_LOGOS_PER_RING; + LBStruct lbs = { + offset, + zrot, + trot, + 0 + }; + m_logos.push_back(lbs); + } + m_ring_rot_idx++; +} + +bool Tunnel::configure (GnomeScreensaver & gs) +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, gs.getAspectRatio() / gs.getNumMonitors(), + 0.01, 1000.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0, 0, 0, 0, 1, 0, 0, 0, 1); + + glViewport(0, 0, gs.getWidth(), gs.getHeight()); + + m_logos.clear(); + for (int i = 0; i <= N_INITIAL_LAYERS; i++) + { + addRing((i - N_INITIAL_LAYERS) * RING_LAYER_DIST); + } + + m_offset = 0.0; + m_last_ring_offset = 0.0; + + return true; +} + +bool Tunnel::update (GnomeScreensaver & gs) +{ + return true; +} diff --git a/modes/Tunnel.h b/modes/Tunnel.h new file mode 100644 index 0000000..8f5a585 --- /dev/null +++ b/modes/Tunnel.h @@ -0,0 +1,42 @@ + +#ifndef TUNNEL_H +#define TUNNEL_H + +#include + +#include "LogoBox.h" +#include "Mode.h" +#include "GnomeScreensaver.h" + +class Tunnel : public Mode +{ + public: + Tunnel(); + ~Tunnel(); + bool expose (GnomeScreensaver & gs); + bool configure (GnomeScreensaver & gs); + bool update (GnomeScreensaver & gs); + typedef struct { + double offset; + float zrot; + float trot; + uint64_t break_ticks; + float spin_axis[3]; + float break_axis[3]; + float spin_rate; + } LBStruct; + protected: + void addRing(double offset); + void getRandomBreakAxis(float (*axis)[3]); + float getRandomBreakSpinSpeed(); + LogoBox m_logobox; + uint64_t m_last_ticks; + uint64_t m_start_ticks; + std::list m_logos; + double m_offset; + double m_last_ring_offset; + unsigned int m_ring_rot_idx; +}; + +#endif /* TUNNEL_H */ + diff --git a/src/dwss.cc b/src/dwss.cc index 96ea7b1..f515de7 100644 --- a/src/dwss.cc +++ b/src/dwss.cc @@ -34,8 +34,9 @@ static Mode *getMode(GnomeScreensaver & gs) { #if 0 return new Starfield(gs); -#endif return new Spin(); +#endif + return new Tunnel(); } int main (int argc, char *argv[])