/* 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 "TumblingLogos.h" #include "Towers.h" /* 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; const int numModes = 3; mode++; if (mode >= numModes) mode = 0; switch (mode) { case 0: return new PlainSpin(this); case 1: return new Towers(this); default: return new TumblingLogos(this); } } /* 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; }