dwscr/ss/LightBounce.cc
josh 912b0a7117 Made orb look more "light"-like
git-svn-id: svn://anubis/dwscr/trunk@114 5bef9df8-b654-44bb-925b-0ff18baa8f8c
2008-12-18 15:19:50 +00:00

291 lines
9.2 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 2.5
#define ORB_SPEED 20.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);
/* Create the orb display list */
m_orb_dl = glGenLists(1);
glNewList(m_orb_dl, GL_COMPILE);
/* save lights, materials, and blending information */
glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
GLfloat mat[] = {0.7, 0.7, 0.14, 0.6};
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat);
GLfloat specular[] = {0.15, 0.15, 0.03, 1.0};
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
GLUquadric * quad = gluNewQuadric();
gluQuadricNormals(quad, GL_TRUE);
glPushMatrix();
glLoadIdentity();
GLfloat light_pos[] = {0, 0, 0, 1};
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glPopMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
gluSphere(quad, ORB_RADIUS, 20, 12);
glPopAttrib();
glEndList();
glPushAttrib(GL_POLYGON_BIT); /* store CULL_FACE settings */
glPushAttrib(GL_ENABLE_BIT); /* store current GL_BLEND setting */
glPushAttrib(GL_LIGHTING_BIT); /* store current LIGHTING settings */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(1, &m_alpha_texture);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_alpha_texture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
m_last_elapsed = 0;
}
LightBounce::~LightBounce()
{
glPopAttrib(); /* restore old LIGHTING settings */
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];
glDeleteTextures(1, &m_alpha_texture);
glDeleteLists(m_orb_dl, 1);
}
/* called every time this screensaver mode should redraw the screen */
void LightBounce::update()
{
SSMode::update();
if (m_last_elapsed == 0)
m_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 * 0.2;
/* 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);
GLfloat light_pos[4];
light_pos[0] = m_orb_pos[0];
light_pos[1] = m_orb_pos[1];
light_pos[2] = m_orb_pos[2];
light_pos[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
for (int i = 0, sz = m_boxes.size(); i < sz; i++)
{
if (m_boxes[i]->getDist() < orbDist && !drewOrb)
{
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_TEXTURE_2D);
glPushMatrix();
glTranslatef(m_orb_pos[0], m_orb_pos[1], m_orb_pos[2]);
glCallList(m_orb_dl);
glPopMatrix();
glPopAttrib();
drewOrb = true;
}
float dx = m_orb_pos[0] - m_boxes[i]->getX();
float dy = m_orb_pos[1] - m_boxes[i]->getY();
float dz = m_orb_pos[2] - m_boxes[i]->getZ();
// float orb_box_dist = sqrtf((dx * dx) + (dy * dy) + (dz * dz));
float orb_box_dist = (dx * dx) + (dy * dy) + (dz * dz);
orb_box_dist /= m_half_size * m_half_size * 1.5;
// orb_box_dist *= M_PI;
if (orb_box_dist > 1)
orb_box_dist = 1;
float alpha = 1 - orb_box_dist;
// alpha = (alpha + 1.0) / 2.0;
GLfloat pixels[] = {1, 1, 1, alpha};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_FLOAT, pixels);
m_boxes[i]->draw();
}
}
SDL_GL_SwapBuffers();
m_last_elapsed = m_elapsed;
}