/* Author: Josh Holtrop * DornerWorks screensaver */ #include #include #include "LightBounce.h" #include "math.h" #include #include #include using namespace std; #define SIZE 5 #define STRIDE_MULTIPLIER 1.0; #define ZOOM 12.0 #define ORB_RADIUS 1.5 #define ORB_SPEED 12.0 LightBounceBox::LightBounceBox(LogoBox * lb, float x, float y, float z, float xr, float yr, float zr) { this->x = x; this->y = y; this->z = z; this->xr = xr; this->yr = yr; this->zr = zr; this->dist = 0.0; m_dl = glGenLists(1); glNewList(m_dl, GL_COMPILE); glPushMatrix(); glTranslatef(x, y, z); glRotatef(xr, 1, 0, 0); glRotatef(yr, 0, 1, 0); glRotatef(zr, 0, 0, 1); lb->draw(); glPopMatrix(); glEndList(); } LightBounceBox::~LightBounceBox() { glDeleteLists(m_dl, 1); } void LightBounceBox::updateDist(float x, float y, float z) { float dx = x - this->x; float dy = y - this->y; float dz = z - this->z; this->dist = (dx*dx) + (dy*dy) + (dz*dz); } bool LightBounceBoxComparator::operator()(LightBounceBox * l1, LightBounceBox * l2) { return l1->getDist() > l2->getDist(); } /* construct screensaver mode and do some basic OpenGL setup */ LightBounce::LightBounce(SSMain * _SSMain) : SSMode(_SSMain) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (double)m_SSMain->getWidth() / (double)m_SSMain->getHeight() / (double)m_SSMain->getNumMonitors(), 0.01, 1000.01); glMatrixMode(GL_MODELVIEW); float box_stride = m_logoBox.getWidth() * STRIDE_MULTIPLIER; m_half_size = SIZE * box_stride / 2.0; float y = -m_half_size + box_stride / 2.0; int rot = false; for (int i = 0; i < SIZE; i++) { float x = -m_half_size + box_stride / 2.0; for (int j = 0; j < SIZE; j++) { // front LightBounceBox * box = new LightBounceBox( &m_logoBox, x, y, -m_half_size, 0, 180.0, rot ? 90.0 : 0 ); m_boxes.push_back(box); // right box = new LightBounceBox( &m_logoBox, m_half_size, y, x, 0, 90.0, rot ? 0 : 90.0 ); m_boxes.push_back(box); // back box = new LightBounceBox( &m_logoBox, x, y, m_half_size, 0, 0, rot ? 90.0 : 0 ); m_boxes.push_back(box); // left box = new LightBounceBox( &m_logoBox, -m_half_size, y, x, 0, 270.0, rot ? 0 : 90.0 ); m_boxes.push_back(box); // top box = new LightBounceBox( &m_logoBox, x, m_half_size, y, 270, 0, rot ? 0 : 90.0 ); m_boxes.push_back(box); // bottom box = new LightBounceBox( &m_logoBox, x, -m_half_size, y, 90, 0, rot ? 0 : 90.0 ); m_boxes.push_back(box); rot = !rot; x += box_stride; } y += box_stride; } /* Set up the orb */ m_orb_pos[0] = m_orb_pos[1] = m_orb_pos[2] = 0.0f; double theta = M_2_PI * ((double)rand() / (double)RAND_MAX); double gamma = M_PI * ((double)rand() / (double)RAND_MAX); m_orb_dir[0] = cos(theta) * sin(gamma); m_orb_dir[1] = sin(theta) * sin(gamma); m_orb_dir[2] = cos(gamma); m_orb_dl = glGenLists(1); glNewList(m_orb_dl, GL_COMPILE); GLfloat mat[] = {1, 1, 0.2, 0.8}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat); GLUquadric * quad = gluNewQuadric(); gluQuadricNormals(quad, GL_TRUE); gluSphere(quad, ORB_RADIUS, 16, 8); glEndList(); glPushAttrib(GL_POLYGON_BIT); /* store CULL_FACE settings */ glPushAttrib(GL_ENABLE_BIT); /* store current GL_BLEND setting */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLuint tex; glGenTextures(1, &tex); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); GLfloat pixels[] = {1, 1, 1, 0.5}; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_FLOAT, pixels); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #if 0 glEnable(GL_COLOR_MATERIAL); glColor4f(1, 1, 1, 0.3); #endif m_last_elapsed = m_elapsed; } LightBounce::~LightBounce() { glPopAttrib(); /* restore old GL_BLEND setting */ glPopAttrib(); /* restore old CULL_FACE settings */ int sz = m_boxes.size(); for (int i = 0; i < sz; i++) delete m_boxes[i]; } /* called every time this screensaver mode should redraw the screen */ void LightBounce::update() { SSMode::update(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int numMonitors = m_SSMain->getNumMonitors(); int width = m_SSMain->getWidth(); int height = m_SSMain->getHeight(); /* update the viewer position */ double angle = m_elapsed/3700.0f; double viewer_dist = SIZE * ZOOM; float viewer_x = viewer_dist * cos(angle); float viewer_z = viewer_dist * sin(angle); float viewer_y = SIZE * ZOOM * 2.0 / 3.0; /* update the orb position */ float multiplier = ORB_SPEED * (m_elapsed - m_last_elapsed) / 1000.0; m_orb_pos[0] += multiplier * m_orb_dir[0]; m_orb_pos[1] += multiplier * m_orb_dir[1]; m_orb_pos[2] += multiplier * m_orb_dir[2]; float orb_limit = m_half_size - ORB_RADIUS; if (m_orb_pos[0] < -orb_limit) { m_orb_dir[0] = -m_orb_dir[0]; m_orb_pos[0] = -2 * orb_limit - m_orb_pos[0]; } else if (m_orb_pos[0] > orb_limit) { m_orb_dir[0] = -m_orb_dir[0]; m_orb_pos[0] = 2 * orb_limit - m_orb_pos[0]; } if (m_orb_pos[1] < -orb_limit) { m_orb_dir[1] = -m_orb_dir[1]; m_orb_pos[1] = -2 * orb_limit - m_orb_pos[1]; } else if (m_orb_pos[1] > orb_limit) { m_orb_dir[1] = -m_orb_dir[1]; m_orb_pos[1] = 2 * orb_limit - m_orb_pos[1]; } if (m_orb_pos[2] < -orb_limit) { m_orb_dir[2] = -m_orb_dir[2]; m_orb_pos[2] = -2 * orb_limit - m_orb_pos[2]; } else if (m_orb_pos[2] > orb_limit) { m_orb_dir[2] = -m_orb_dir[2]; m_orb_pos[2] = 2 * orb_limit - m_orb_pos[2]; } for (int i = 0, sz = m_boxes.size(); i < sz; i++) { m_boxes[i]->updateDist(viewer_x, viewer_y, viewer_z); } sort(m_boxes.begin(), m_boxes.end(), m_comparator); for (int i = 0; i < numMonitors; i++) { bool drewOrb = false; float orbDx = viewer_x - m_orb_pos[0]; float orbDy = viewer_y - m_orb_pos[1]; float orbDz = viewer_z - m_orb_pos[2]; float orbDist = (orbDx * orbDx) + (orbDy * orbDy) + (orbDz * orbDz); glViewport(i*width/numMonitors, 0, width/numMonitors, height); glLoadIdentity(); gluLookAt(viewer_x, viewer_y, viewer_z, 0, 0, 0, 0, 1, 0); for (int i = 0, sz = m_boxes.size(); i < sz; i++) { if (m_boxes[i]->getDist() < orbDist && !drewOrb) { glPushMatrix(); glTranslatef(m_orb_pos[0], m_orb_pos[1], m_orb_pos[2]); glCallList(m_orb_dl); glPopMatrix(); drewOrb = true; } m_boxes[i]->draw(); } } SDL_GL_SwapBuffers(); m_last_elapsed = m_elapsed; }