160 lines
3.8 KiB
C++
160 lines
3.8 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/SDL.h>
|
|
#include "SSMain.h"
|
|
#include "PlainSpin.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)
|
|
|
|
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 (elapsed_msec - lastChanged_msec > SSMODE_TIMEOUT_MSEC)
|
|
{
|
|
delete m_mode;
|
|
m_mode = startMode();
|
|
lastChanged_msec = elapsed_msec;
|
|
}
|
|
|
|
switch (event.type)
|
|
{
|
|
#ifndef WINDOW_MODE
|
|
case SDL_KEYDOWN: /* terminate screensaver upon */
|
|
#endif
|
|
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 = 3;
|
|
#else
|
|
const int numModes = 1;
|
|
#endif
|
|
|
|
mode++;
|
|
if (mode >= numModes)
|
|
mode = 0;
|
|
|
|
switch (mode)
|
|
{
|
|
case 0:
|
|
return new PlainSpin(this);
|
|
#ifndef WITHOUT_ODE
|
|
case 1:
|
|
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;
|
|
}
|