dwscr/ss/SSMain.cc
josh e87905c268 added u's
git-svn-id: svn://anubis/dwscr/trunk@118 5bef9df8-b654-44bb-925b-0ff18baa8f8c
2009-10-08 15:15:45 +00:00

166 lines
4.1 KiB
C++

/* Author: Josh Holtrop
* DornerWorks screensaver
* This module implements the main functionality of the DW screensaver.
* It is responsible for handling input and timer events, as well
* as instantiating and rotating through the various screensaver modes
* that have been implemented.
*/
#include <stdlib.h> /* srand() */
#include <time.h> /* time() */
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL.h>
#include "SSMain.h"
#include "PlainSpin.h"
#include "LightBounce.h"
#ifndef WITHOUT_ODE
#include "TumblingLogos.h"
#include "Towers.h"
#endif
/* switch to the next screensaver mode after this many milliseconds */
#define SSMODE_TIMEOUT_MSEC (1000*45)
#define SCREENSAVER_MAX_RUNTIME (30u*60u*1000u)
static SDL_Event event;
/* create the main screensaver object */
SSMain::SSMain(int width, int height, int numMonitors, SDL_Surface * sdlSurface)
: m_width (width), m_height (height),
m_numMonitors (numMonitors), m_sdlSurface (sdlSurface),
m_mode(NULL), m_drawing(false)
{
/* set up some common OpenGL defaults */
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_CULL_FACE);
GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
/* setup redraw SDL event structure */
event.type = SDL_USEREVENT;
event.user.code = 0;
srand(time(NULL));
}
/* called by SDL when the update timer expires */
Uint32 SSMain::updateCallback(Uint32 interval, void * param)
{
SSMain * ssmain = (SSMain *) param;
return ssmain->updateCallback(interval);
}
/* member update function to be called by our registered
* SDL callback non-member function */
Uint32 SSMain::updateCallback(Uint32 interval)
{
if (!m_drawing)
{
SDL_PushEvent(&event);
}
return interval;
}
/* called to begin the screensaver,
* exits when the screensaver should terminate */
void SSMain::run()
{
Uint32 elapsed_msec;
Uint32 lastChanged_msec = 0;
SDL_Event event;
/* initially set the screensaver mode */
m_mode = startMode();
/* register a screen redrawing SDL event */
SDL_AddTimer(12, &updateCallback, this);
/* draw the screen */
update();
/* main event loop */
while (SDL_WaitEvent(&event))
{
elapsed_msec = SDL_GetTicks(); /* get the time the event occurred at */
#if SCREENSAVER_MAX_RUNTIME > 0
if (elapsed_msec >= SCREENSAVER_MAX_RUNTIME)
goto RET;
#endif
if (elapsed_msec - lastChanged_msec > SSMODE_TIMEOUT_MSEC)
{
delete m_mode;
m_mode = startMode();
lastChanged_msec = elapsed_msec;
}
switch (event.type)
{
case SDL_KEYDOWN: /* terminate screensaver upon */
case SDL_QUIT: /* key press or quit event */
goto RET;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == 1)
{
delete m_mode;
m_mode = startMode();
lastChanged_msec = elapsed_msec;
}
break;
case SDL_USEREVENT:
if (event.user.code == 0)
{
update();
}
break;
}
}
RET:
;
}
/* return a new screensaver mode object to start displaying */
SSMode * SSMain::startMode()
{
static int mode = 0;
#ifndef WITHOUT_ODE
const int numModes = 4;
#else
const int numModes = 2;
#endif
mode++;
if (mode >= numModes)
mode = 0;
switch (mode)
{
case 0:
return new PlainSpin(this);
case 1:
return new LightBounce(this);
#ifndef WITHOUT_ODE
case 2:
return new Towers(this);
default:
return new TumblingLogos(this);
#endif
}
}
/* call the update function to redraw the screen from the
* currently active screensaver mode.
* Uses a pseudo-semaphore to block new redraw requests
* from coming in while current ones are being serviced.
*/
void SSMain::update()
{
m_drawing = true;
m_mode->update();
m_drawing = false;
}