/* 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 /* srand() */ #include /* time() */ #include #include #include #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), m_switchmode(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 (m_switchmode || (elapsed_msec - lastChanged_msec > SSMODE_TIMEOUT_MSEC)) { delete m_mode; m_mode = startMode(); lastChanged_msec = elapsed_msec; m_switchmode = false; } switch (event.type) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_n) { m_switchmode = true; /* switch to next mode on 'N' key */ } else { goto RET; /* terminate on other key */ } break; case SDL_QUIT: /* terminate on 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; }