#include #include #include #include #include #include #include #include "Tunnel.h" using namespace std; #define N_INITIAL_LAYERS 8 #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 260 #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; }