257 lines
7.5 KiB
C++
257 lines
7.5 KiB
C++
|
|
/* Author: Josh Holtrop
|
|
* DornerWorks screensaver
|
|
*/
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include "LightBounce.h"
|
|
|
|
#include "math.h"
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
using namespace std;
|
|
|
|
#define SIZE 5
|
|
#define STRIDE_MULTIPLIER 1.0;
|
|
#define ZOOM 12.0
|
|
#define ORB_RADIUS 1.5
|
|
#define ORB_SPEED 6.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
|
|
}
|
|
|
|
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()
|
|
{
|
|
static Uint32 last_elapsed = 0;
|
|
SSMode::update();
|
|
if (last_elapsed == 0)
|
|
last_elapsed = m_elapsed;
|
|
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 - 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];
|
|
if (m_orb_pos[0] < -m_half_size)
|
|
{
|
|
m_orb_dir[0] = -m_orb_dir[0];
|
|
m_orb_pos[0] = -2 * m_half_size - m_orb_pos[0];
|
|
}
|
|
else if (m_orb_pos[0] > m_half_size)
|
|
{
|
|
m_orb_dir[0] = -m_orb_dir[0];
|
|
m_orb_pos[0] = 2 * m_half_size - m_orb_pos[0];
|
|
}
|
|
if (m_orb_pos[1] < -m_half_size)
|
|
{
|
|
m_orb_dir[1] = -m_orb_dir[1];
|
|
m_orb_pos[1] = -2 * m_half_size - m_orb_pos[1];
|
|
}
|
|
else if (m_orb_pos[1] > m_half_size)
|
|
{
|
|
m_orb_dir[1] = -m_orb_dir[1];
|
|
m_orb_pos[1] = 2 * m_half_size - m_orb_pos[1];
|
|
}
|
|
if (m_orb_pos[2] < -m_half_size)
|
|
{
|
|
m_orb_dir[2] = -m_orb_dir[2];
|
|
m_orb_pos[2] = -2 * m_half_size - m_orb_pos[2];
|
|
}
|
|
else if (m_orb_pos[2] > m_half_size)
|
|
{
|
|
m_orb_dir[2] = -m_orb_dir[2];
|
|
m_orb_pos[2] = 2 * m_half_size - 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();
|
|
last_elapsed = m_elapsed;
|
|
}
|