dwscr/ss/Towers.cc
josh 68d41e9c63 moved files to trunk directory
git-svn-id: svn://anubis/dwscr/trunk@83 5bef9df8-b654-44bb-925b-0ff18baa8f8c
2008-09-22 17:27:40 +00:00

303 lines
9.1 KiB
C++

/* Author: Josh Holtrop
* DornerWorks screensaver
* A slightly more interesting screensaver mode involving
* towers of DW logos with randomly disappearing ones
*/
#include <math.h> /* fmax(), sin() */
#include <stdlib.h> /* rand() */
#include <GL/gl.h>
#include <GL/glu.h>
#include "Towers.h"
#include <ode/ode.h>
#include <iostream>
using namespace std;
#define WORLD_STEP 0.001
/* time at beginning of mode to not remove any logos (msec) */
#define WAIT_TIME 6000
/* amount of time to wait before removing another logo (msec) */
#define REMOVE_TIME 3000
#define GROUND_ALPHA 0.5
Towers::Towers(SSMain * _SSMain) : SSMode(_SSMain)
{
/* set up our specific openGL settings */
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);
/* create the ground texture */
float tex[] = {1.0, 0.0, 0.0, GROUND_ALPHA,
1.0, 1.0, 1.0, GROUND_ALPHA,
1.0, 1.0, 1.0, GROUND_ALPHA,
1.0, 0.0, 0.0, GROUND_ALPHA};
glGenTextures(1, &m_groundTexture);
glBindTexture(GL_TEXTURE_2D, m_groundTexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, 2, 2, 0, GL_RGBA, GL_FLOAT, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* create the ODE world */
createWorld();
m_lastElapsed = 0;
m_logoToRemove = -1;
m_logosList = glGenLists(1);
}
Towers::~Towers()
{
int sz = m_logos.size();
for (int i = 0; i < sz; i++)
{
delete m_logos[i];
}
dJointGroupDestroy(m_contactJointGroup);
dWorldDestroy(m_world);
dSpaceDestroy(m_space);
glDeleteTextures(1, &m_groundTexture);
glDeleteLists(m_logosList, 1);
}
void Towers::createWorld()
{
/* set up the ODE world and collision space */
m_world = dWorldCreate();
// dWorldSetCFM(m_world, 1e-5);
dWorldSetGravity(m_world, 0, -9.81, 0);
dWorldSetERP(m_world, 0.8);
m_space = dHashSpaceCreate(0);
// dVector3 center = {0, 10, 0};
// dVector3 extents = {100, 40, 100};
// m_space = dQuadTreeSpaceCreate(0, center, extents, 5);
m_contactJointGroup = dJointGroupCreate(0);
double lHeight = 0.0;
const double towerBaseOffset = 0.0;
const int towerHeight = 6;
const double towerSpacing = 10.0;
const double logoTierSpacing = 3.75;
bool turn = false;
for (double xoffset = -towerSpacing;
xoffset < towerSpacing*1.1;
xoffset += towerSpacing*2.0)
{
for (double zoffset = -towerSpacing;
zoffset < towerSpacing*1.1;
zoffset += towerSpacing*2.0)
{
double towerOffset = 0.0;
for (int i = 0;
i < towerHeight;
i++, towerOffset += lHeight, turn = !turn)
{
double localXOffset = 0.0;
double localZOffset = 0.0;
if (turn)
localXOffset = -logoTierSpacing;
else
localZOffset = -logoTierSpacing;
for (int i = 0; i < 2; i++)
{
LogoBox * lb = new LogoBox(m_world, m_space);
if (lHeight == 0.0)
lHeight = lb->getDepth();
dMatrix3 rotation;
dRFromEulerAngles(rotation,
0,
turn ? M_PI_2 : 0,
0);
dBodySetRotation(lb->getBody(), rotation);
dBodySetPosition(lb->getBody(),
xoffset + localXOffset,
towerBaseOffset + towerOffset + lb->getDepth()/2.0,
zoffset + localZOffset);
m_logos.push_back(lb);
if (turn)
localXOffset += logoTierSpacing * 2;
else
localZOffset += logoTierSpacing * 2;
}
}
turn = !turn;
}
}
/* create ground plane */
dCreatePlane(m_space, 0, 1, 0, 0);
}
void Towers::update()
{
SSMode::update();
if (m_lastElapsed == 0)
m_lastElapsed = m_elapsed;
if (m_logoToRemove == -1 && m_elapsed > WAIT_TIME)
{
if (m_logos.size() > 0)
{
m_lastRemoveTime = m_elapsed;
m_logoToRemove = rand() % m_logos.size();
}
}
else if (m_elapsed - m_lastRemoveTime > REMOVE_TIME)
{
if (m_logoToRemove >= 0)
{
std::vector<LogoBox *>::iterator it = m_logos.begin();
for (int i = 0; i < m_logoToRemove; i++)
it++;
delete *it;
m_logos.erase(it);
m_logoToRemove = (m_logos.size() > 0) ? rand() % m_logos.size() : -1;
m_lastRemoveTime = m_elapsed;
}
}
Uint32 delta = m_elapsed - m_lastElapsed;
for (unsigned int i = 0; i < delta / 2; i++)
worldStep();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int numMonitors = m_SSMain->getNumMonitors();
int width = m_SSMain->getWidth();
int height = m_SSMain->getHeight();
bool drewLogos = false;
for (int i = 0; i < numMonitors; i++)
{
glViewport(i*width/numMonitors, 0, width/numMonitors, height);
glLoadIdentity();
gluLookAt(0, 30, 55, /* eye position */
0, 12, 0, /* focal point */
0, 1, 0); /* up vector */
glRotatef(m_elapsed/60.0f, 0, 1, 0); /* rotate view over time */
/* draw logo reflection */
glPushAttrib(GL_POLYGON_BIT);
glFrontFace(GL_CW); /* polygon vertex order reversed when
reflecting across a plane */
glPushMatrix();
glScalef(1.0, -1.0, 1.0);
if (drewLogos)
glCallList(m_logosList);
else
{
glNewList(m_logosList, GL_COMPILE_AND_EXECUTE);
drawLogos();
glEndList();
drewLogos = true;
}
glPopMatrix();
glPopAttrib();
drawGround();
/* draw logos normally */
// drawLogos();
glCallList(m_logosList);
}
SDL_GL_SwapBuffers();
m_lastElapsed = m_elapsed;
}
void Towers::drawLogos()
{
/* draw the logos */
int sz = m_logos.size();
for (int i = 0; i < sz; i++)
{
dBodyID body = m_logos[i]->getBody();
pushTransform(dBodyGetPosition(body),
dBodyGetRotation(body));
if (i == m_logoToRemove)
{
float amt = fabsf(sin(1.9*M_PI*
(m_elapsed-m_lastRemoveTime)/REMOVE_TIME));
GLfloat emission[] = {0.0, 0.0, amt, 1.0};
glPushAttrib(GL_LIGHTING_BIT);
glMaterialfv(GL_FRONT, GL_EMISSION, emission);
}
m_logos[i]->draw();
if (i == m_logoToRemove)
{
glPopAttrib();
}
glPopMatrix();
}
}
void Towers::drawGround()
{
const float gs = 120; /* ground size */
const float tt = 20; /* texture tiles */
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBegin(GL_QUADS);
glNormal3f(0, 1, 0);
glTexCoord2f(0, 0);
glVertex3f(-gs, 0, gs);
glTexCoord2f(tt, 0);
glVertex3f(gs, 0, gs);
glTexCoord2f(tt, tt);
glVertex3f(gs, 0, -gs);
glTexCoord2f(0, tt);
glVertex3f(-gs, 0, -gs);
glEnd();
glPopAttrib();
}
/* used by ODE to perform collision detection */
void Towers_collide_callback(void * data, dGeomID o1, dGeomID o2)
{
const int maxNumContacts = 2;
Towers * t = (Towers *) data;
static dContact contact[maxNumContacts];
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnected(b1, b2))
return;
int num = dCollide(o1, o2, maxNumContacts,
&contact[0].geom, sizeof(dContact));
int i;
for (i = 0; i < num; i++)
{
contact[i].surface.mode =
dContactSlip1 | dContactSlip2 | dContactBounce |
dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = 0.5;
contact[i].surface.slip1 = 0.0;
contact[i].surface.slip2 = 0.0;
contact[i].surface.soft_erp = 0.8;
contact[i].surface.soft_cfm = 0.01;
contact[i].surface.bounce = 0.0;
dJointID joint = dJointCreateContact(t->m_world,
t->m_contactJointGroup, contact + i);
dJointAttach(joint, b1, b2);
}
}
/* invokes ODE to do physics on our world */
void Towers::worldStep()
{
dSpaceCollide(m_space, this, Towers_collide_callback);
dWorldQuickStep(m_world, WORLD_STEP);
dJointGroupEmpty(m_contactJointGroup);
}