diff --git a/src/framework/AbstractGraphicsEngine.cpp b/src/framework/AbstractGraphicsEngine.cpp index 6567f739e8bf06ed795e6e11b15f25c55dab4cc8..1f4577e4a2de67115917f17a5e25ef6d721a21ce 100644 --- a/src/framework/AbstractGraphicsEngine.cpp +++ b/src/framework/AbstractGraphicsEngine.cpp @@ -20,45 +20,14 @@ #include "AbstractGraphicsEngine.h" -AbstractGraphicsEngine::AbstractGraphicsEngine() : m_BoincAdapter() +AbstractGraphicsEngine::AbstractGraphicsEngine() : m_BoincAdapter() { - m_InitialBOINCRefreshDone = false; } AbstractGraphicsEngine::~AbstractGraphicsEngine() { } -int AbstractGraphicsEngine::initialWindowWidth() -{ - if(!m_InitialBOINCRefreshDone) { - m_BoincAdapter.refresh(); - m_InitialBOINCRefreshDone = true; - } - - return m_BoincAdapter.graphicsWindowWidth(); -} - -int AbstractGraphicsEngine::initialWindowHeight() -{ - if(!m_InitialBOINCRefreshDone) { - m_BoincAdapter.refresh(); - m_InitialBOINCRefreshDone = true; - } - - return m_BoincAdapter.graphicsWindowHeight(); -} - -int AbstractGraphicsEngine::frameRate() -{ - if(!m_InitialBOINCRefreshDone) { - m_BoincAdapter.refresh(); - m_InitialBOINCRefreshDone = true; - } - - return m_BoincAdapter.graphicsFrameRate(); -} - void AbstractGraphicsEngine::refreshLocalBOINCInformation() { m_BoincAdapter.refresh(); diff --git a/src/framework/AbstractGraphicsEngine.h b/src/framework/AbstractGraphicsEngine.h index a5f7cde73d139b8d99bd86764dd513aaa668913c..8765efdb4dbe9f3ec4b8429f4412bab4a1053e53 100644 --- a/src/framework/AbstractGraphicsEngine.h +++ b/src/framework/AbstractGraphicsEngine.h @@ -31,12 +31,12 @@ /** * \brief This abstract class provides common features for all graphics engines - * + * * All graphics engines (Open GL visualisation code) have to be derived from this class. * First of all it defines the common interface which the rest of the graphics framework * expects any implementing classes to support. Apart from that, this class also defines * common properties like event idetifiers and basic access to BOINC client information. - * + * * \author Oliver Bock\n * Max-Planck-Institute for Gravitational Physics\n * Hannover, Germany @@ -46,72 +46,72 @@ class AbstractGraphicsEngine public: /// Destructor virtual ~AbstractGraphicsEngine(); - + /** * \brief This method is called when an implementing graphics engine should initialize itself - * + * * \param width The current width of the display surface * \param height The current height of the display surface - * \param font A pointer to a Resource object containing TTF font faces for text rendering + * \param font A pointer to a Resource object containing TTF font faces for text rendering * \param recycle This flag indicates whether we initialize (FALSE) or reinitialize (TRUE) the context */ virtual void initialize(const int width, const int height, const Resource *font, const bool recycle = false) = 0; - + /** * \brief This method is called when the windowing system encounters a window resize event - * + * * \param width The new width of the display surface * \param height The new height of the display surface */ virtual void resize(const int width, const int height) = 0; - + /** * \brief This method is called when an implementing graphics engine should render one frame - * + * * \param timeOfDay The current time in "seconds since the Epoch" (with microsecond precision) - */ + */ virtual void render(const double timeOfDay) = 0; - + /** * \brief Defined mouse button identifiers - * + * * \see mouseButtonEvent * \see mouseMoveEvent - */ + */ enum MouseButton { MouseButtonLeft = 1, MouseButtonRight = 2 }; - + /** * \brief This method is called when the windowing system encounters a mouse button event - * + * * \param positionX The mouse position on the x-axis when the event occurred (range: 0-width) * \param positionY The mouse position on the y-axis when the event occurred (range: 0-height) * \param buttonPressed The mouse button pressed (if any) when the event occurred. * It can be identified using the elements of \ref MouseButton. - * + * * \see MouseButton - */ + */ virtual void mouseButtonEvent(const int positionX, const int positionY, const MouseButton buttonPressed) = 0; - + /** * \brief This method is called when the windowing system encounters a mouse move event - * + * * \param deltaX The relative mouse position change with respect to the x-axis when the event occurred * \param deltaY The relative mouse position change with respect to the y-axis when the event occurred * \param buttonPressed The mouse button pressed (if any) when the event occurred. * It can be identified using the elements of \ref MouseButton. * * \see MouseButton - */ + */ virtual void mouseMoveEvent(const int deltaX, const int deltaY, const MouseButton buttonPressed) = 0; - + /** * \brief Defined keyboard identifiers - * + * * \see keyboardPressEvent - */ + */ enum KeyBoardKey { KeyA = 0x1, KeyB = 0x2, @@ -142,81 +142,50 @@ public: KeyEnter = 0x4000000, KeyEscape = 0x8000000 }; - + /** * \brief This method is called when the windowing system encounters a key press event - * + * * \attention Please note that not all key events are currently forwarded (this should be change * as soon as the need arises). Please see WindowManager::eventLoop for details. - * + * * \param keyPressed The keyboard key pressed. It can be identified using the elements of \ref KeyBoardKey. - * + * * \see KeyBoardKey * \see WindowManager::eventLoop */ virtual void keyboardPressEvent(const KeyBoardKey keyPressed) = 0; - + /** * \brief This method is called when the BOINC client information should be updated - * + * * When you inherit from this class and implement this method, please make sure you call * \ref refreshLocalBOINCInformation() to invoke the generic default implementation which * refreshes \ref m_BoincAdapter. - * + * * \see refreshLocalBOINCInformation() */ virtual void refreshBOINCInformation() = 0; - /** - * \brief Retrieves the initial window width (horizontal resolution) when running in windowed mode - * - * \return The initial window width to be used - * - * \see BOINCClientAdapter::graphicsWindowWidth() - */ - int initialWindowWidth(); - - /** - * \brief Retrieves the initial window width (vertical resolution) when running in windowed mode - * - * \return The initial window height to be used - * - * \see BOINCClientAdapter::graphicsWindowHeight() - */ - int initialWindowHeight(); - - /** - * \brief Retrieves the frame rate at which the graphics engine should be invoked for rendering - * - * \return The frame rate to be used for rendering - * - * \see BOINCClientAdapter::graphicsFrameRate() - */ - int frameRate(); - protected: /** * \brief Default constructor - * + * * The constructor is protected since this is an abstract class. */ AbstractGraphicsEngine(); /** * \brief This method has to be called in order to update the BOINC client information - * + * * This is the local/generic implementation which refreshes \ref m_BoincAdapter. - * + * * \see refreshBOINCInformation() */ virtual void refreshLocalBOINCInformation(); - + /// BOINC client adapter instance for information retrieval BOINCClientAdapter m_BoincAdapter; - -private: - /// Indicator showing the initial BOINC adapter refresh status - bool m_InitialBOINCRefreshDone; }; /** diff --git a/src/framework/WindowManager.cpp b/src/framework/WindowManager.cpp index 5c948655660bad377d5f3124eae27fbbef7764fa..9a3492edd026d8f5c763a5df78b33e6cefffaaeb 100644 --- a/src/framework/WindowManager.cpp +++ b/src/framework/WindowManager.cpp @@ -23,10 +23,12 @@ WindowManager::WindowManager() { m_ScreensaverMode = false; + m_BoincAdapter = new BOINCClientAdapter(); } WindowManager::~WindowManager() { + delete m_BoincAdapter; } bool WindowManager::initialize(const int width, const int height, const int frameRate) @@ -52,11 +54,17 @@ bool WindowManager::initialize(const int width, const int height, const int fram if (videoInfo->vfmt->BitsPerPixel != 0) { m_DesktopBitsPerPixel = videoInfo->vfmt->BitsPerPixel; } - - // set initial non-fullscreen resolution as well as the render interval - m_WindowedWidth = width; - m_WindowedHeight = height; - m_RenderEventInterval = 1000.0f / frameRate; + + // get initial non-fullscreen resolution and frame rate from project preferences + m_BoincAdapter->initialize(""); + int preferredWidth = m_BoincAdapter->graphicsWindowWidth(); + int preferredHeight = m_BoincAdapter->graphicsWindowHeight(); + int preferredFrameRate = m_BoincAdapter->graphicsFrameRate(); + + // override optional default values if preferred values are set + m_WindowedWidth = preferredWidth != 0 ? preferredWidth : width; + m_WindowedHeight = preferredHeight != 0 ? preferredHeight : height; + m_RenderEventInterval = 1000.0f / (preferredFrameRate != 0 ? preferredFrameRate : frameRate); /* * SDL_ASYNCBLIT - Surface benutzt asynchrone Blits, wenn möglich @@ -74,7 +82,7 @@ bool WindowManager::initialize(const int width, const int height, const int fram // set common video flags // (for OpenGL nothing more than SDL_OPENGL and SDL_FULLSCREEN should be used) m_VideoModeFlags = SDL_OPENGL; - + // check fullscreen video mode m_FullscreenModeAvailable = true; Uint32 bitPerPixel = SDL_VideoModeOK( @@ -87,7 +95,7 @@ bool WindowManager::initialize(const int width, const int height, const int fram cerr << "Fullscreen video mode not supported: " << SDL_GetError() << endl; m_FullscreenModeAvailable = false; } - + // check initial windowed video mode m_WindowedModeAvailable = true; bitPerPixel = SDL_VideoModeOK( @@ -100,7 +108,7 @@ bool WindowManager::initialize(const int width, const int height, const int fram cerr << "Windowed video mode not supported: " << SDL_GetError() << endl; m_WindowedModeAvailable = false; } - + // both checks failed if(!(m_FullscreenModeAvailable || m_WindowedModeAvailable)) { cerr << "No suitable video mode available!"<< endl; @@ -113,7 +121,7 @@ bool WindowManager::initialize(const int width, const int height, const int fram SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); - + // unused requirements //SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); //SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); @@ -127,14 +135,14 @@ bool WindowManager::initialize(const int width, const int height, const int fram m_CurrentWidth = m_WindowedWidth; m_CurrentHeight = m_WindowedHeight; m_VideoModeFlags |= SDL_RESIZABLE; - + // finally, get surface m_DisplaySurface = SDL_SetVideoMode( m_CurrentWidth, m_CurrentHeight, m_DesktopBitsPerPixel, m_VideoModeFlags); - + if (m_DisplaySurface == NULL) { cerr << "Could not acquire rendering surface: " << SDL_GetError() << endl; return false; @@ -147,8 +155,8 @@ void WindowManager::eventLoop() { // be sure there's at least one observer! assert(eventObservers.size() > 0); - - // set two main timers (interval in ms) + + // set two main timers (interval in ms) SDL_AddTimer(m_RenderEventInterval, &timerCallbackRenderEvent, NULL); SDL_AddTimer(1000, &timerCallbackBOINCUpdateEvent, NULL); @@ -159,7 +167,7 @@ void WindowManager::eventLoop() //SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE); //SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE); //SDL_EventState(SDL_USEREVENT, SDL_IGNORE); - + // events we ignore SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE); SDL_EventState(SDL_KEYUP, SDL_IGNORE); @@ -176,7 +184,7 @@ void WindowManager::eventLoop() while (SDL_WaitEvent(&event) ) { if (event.type == SDL_USEREVENT && event.user.code == RenderEvent) { - + #ifdef DEBUG_VALGRIND // stop after i iterations when running valgrinded static int i = 0; @@ -191,35 +199,35 @@ void WindowManager::eventLoop() if (m_DisplaySurface) SDL_FreeSurface(m_DisplaySurface); break; } -#endif +#endif } else if (event.type == SDL_USEREVENT && event.user.code == BOINCUpdateEvent) { - + // notify observers (currently exactly one, hence front()) to fetch a BOINC update eventObservers.front()->refreshBOINCInformation(); } else if (m_ScreensaverMode && (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_KEYDOWN)) { - + // we're in screensaver mode so exit on user input SDL_Quit(); } else if (event.motion.state & (SDL_BUTTON(1) | SDL_BUTTON(3)) && event.type == SDL_MOUSEMOTION) { - + if (event.motion.state & SDL_BUTTON(1)) { // notify our observers (currently exactly one, hence front()) eventObservers.front()->mouseMoveEvent( - event.motion.xrel, + event.motion.xrel, event.motion.yrel, AbstractGraphicsEngine::MouseButtonLeft); } else if (event.motion.state & SDL_BUTTON(3)) { // notify our observers (currently exactly one, hence front()) eventObservers.front()->mouseMoveEvent( - event.motion.xrel, + event.motion.xrel, event.motion.yrel, AbstractGraphicsEngine::MouseButtonRight); } @@ -227,14 +235,14 @@ void WindowManager::eventLoop() else if (event.type == SDL_VIDEORESIZE) { m_CurrentWidth = m_WindowedWidth = event.resize.w; m_CurrentHeight = m_WindowedHeight = event.resize.h; - + // update video mode m_DisplaySurface = SDL_SetVideoMode( m_CurrentWidth, m_CurrentHeight, m_DesktopBitsPerPixel, m_VideoModeFlags); - + // notify our observers (currently exactly one, hence front()) // (windoze needs to be reinitialized instead of just resized, oh well) /// \todo Can we determine the host OS? On X11 a resize() is sufficient! @@ -242,7 +250,7 @@ void WindowManager::eventLoop() } else if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { - + // just exit (SDL_FreeSurface is called automatically) SDL_Quit(); @@ -370,11 +378,11 @@ void WindowManager::toggleFullscreen() // set new dimensions m_CurrentWidth = m_WindowedWidth; m_CurrentHeight = m_WindowedHeight; - + // (un)set video mode flags m_VideoModeFlags &= ~SDL_FULLSCREEN; m_VideoModeFlags |= SDL_RESIZABLE; - + // show cursor in fullscreen mode SDL_ShowCursor(SDL_ENABLE); } @@ -382,22 +390,22 @@ void WindowManager::toggleFullscreen() // set new dimensions m_CurrentWidth = m_DesktopWidth; m_CurrentHeight = m_DesktopHeight; - + // (un)set video mode flags m_VideoModeFlags |= SDL_FULLSCREEN; m_VideoModeFlags &= ~SDL_RESIZABLE; - + // hide cursor SDL_ShowCursor(SDL_DISABLE); } - + // reset video mode m_DisplaySurface = SDL_SetVideoMode( m_CurrentWidth, m_CurrentHeight, m_DesktopBitsPerPixel, m_VideoModeFlags); - + // notify our observers (currently exactly one, hence front()) // (windoze needs to be reinitialized instead of just resized, oh well) /// \todo Can we determine the host OS? On X11 a resize() is sufficient! diff --git a/src/framework/WindowManager.h b/src/framework/WindowManager.h index 2047d9f3fe07c80f3be81792e5a7cea9779972af..87bb8c50b4a6142ba54273497c68d6b242c35d1f 100644 --- a/src/framework/WindowManager.h +++ b/src/framework/WindowManager.h @@ -31,6 +31,7 @@ #include <util.h> #include "AbstractGraphicsEngine.h" +#include "BOINCClientAdapter.h" using namespace std; @@ -41,13 +42,13 @@ using namespace std; /** * \brief This class is responsible for the application's window and event management. - * + * * %WindowManager provides an initialized OpenGL context needed by any given * \ref AbstractGraphicsEngine. In addition to that it serves as the main event * controller. That means it handles all window and user input events and propagates * them to all registered observers (of type \ref AbstractGraphicsEngine). This also * includes all timer events required for rendering and information retrieval control. - * + * * \author Oliver Bock\n * Max-Planck-Institute for Gravitational Physics\n * Hannover, Germany @@ -55,190 +56,196 @@ using namespace std; class WindowManager { public: - + /// Default constructor WindowManager(); - + /// Destructor virtual ~WindowManager(); - + /** * \brief Initializes the %WindowManager - * + * * Call this method first (after instantiation) to prepare the - * main application window as well as the OpenGL context. - * + * main application window as well as the OpenGL context. Please + * note that the optional parameters \c width, \c height and \c + * frameRate are overridden by the values set by the user in the + * project preferences! + * * \param width The optional initial width of the main window * \param height The optional initial height of the main window * \param frameRate The optional initial frame rate to be used - * + * * \return TRUE if successfull, otherwise FALSE */ bool initialize(const int width = 800, const int height = 600, const int frameRate = 20); - + /** * \brief Registeres a new event observer - * + * * All registered observers are notified in case one of the events * specified in \ref EventCodes occurrs. - * + * * \param engine The pointer to the \ref AbstractGraphicsEngine instance to register - * + * * \see AbstractGraphicsEngine::mouseButtonEvent() * \see AbstractGraphicsEngine::mouseMoveEvent() * \see AbstractGraphicsEngine::keyboardPressEvent() */ void registerEventObserver(AbstractGraphicsEngine *engine); - + /** * \brief Unregisteres a new event observer - * + * * \param engine The pointer to the \ref AbstractGraphicsEngine instance to unregister */ void unregisterEventObserver(AbstractGraphicsEngine *engine); - + /** * \brief The main event loop - * + * * Call this method to enter the main window's event loop. All subsequent application * control is defined here. The method returns when the window is closed or destroyed. */ void eventLoop(); - + /** * \brief Retrieve the current main window's width - * + * * \return The current window width */ int windowWidth() const; - + /** * \brief Retrieve the current main window's height - * + * * \return The current window height */ int windowHeight() const; - + /** * \brief Set the main window's caption - * + * * \param caption The new caption of the main window */ void setWindowCaption(const string caption) const; - + /** * \brief Set the main window's icon - * + * * \param filename The new icon's filename - */ + */ void setWindowIcon(const string filename) const; - + /** * \brief Toggles the fullscreen state of the main window - * + * * Note: the initial state is windowed (not fullscreen). - * + * */ void toggleFullscreen(); - + /** * \brief Set the screensaver mode indicator - * + * * \param enabled The new value for the screensaver mode indicator - */ + */ void setScreensaverMode(const bool enabled); private: /** * \brief Timer callback to trigger render events - * + * * This callback is used by a SDL timer registered in \ref eventLoop(). * It creates a \ref RenderEvent which is handled by eventLoop(). * In order to use a constant timer interval, \c interval is * returned as it was passed. - * + * * \param interval The current timer interval * \param param The user supplied parameter of the timer event - * + * * \return The timer interval to be used for the following events - * + * * \see eventLoop() * \see EventCodes - * + * * \todo Work around static callback, otherwise we might get event conflicts * when more than one instance. Maybe we should use a singleton here anyway... */ static Uint32 timerCallbackRenderEvent(Uint32 interval, void *param); - + /** * \brief Timer callback to trigger BOINC update events - * + * * This callback is used by a SDL timer registered in \ref eventLoop(). * It creates a \ref BOINCUpdateEvent which is handled by eventLoop(). * In order to use a constant timer interval, \c interval is * returned as it was passed. - * + * * Note: it might seem a bit strange to trigger the BOINC updates here but it's * here where \b all event controlling and propagation takes place. BOINCClientAdapter * for example is meant to be used \b by an instance receiving this event, not * actually handling it itself. Thus AbstractGraphicsEngine handles this event * and \b uses its BOINC adapter accordingly. - * + * * \param interval The current timer interval * \param param The user supplied parameter of the timer event - * + * * \return The timer interval to be used for the following events - * + * * \see eventLoop() * \see EventCodes - * + * * \todo Work around static callback, otherwise we might get event conflicts * when more than one instance. Maybe we should use a singleton here anyway... */ static Uint32 timerCallbackBOINCUpdateEvent(Uint32 interval, void *param); - + + /// Local BOINC adapter instance to read project preferences + BOINCClientAdapter *m_BoincAdapter; + /// The render event interval (in ms) for invoking the render event observer float m_RenderEventInterval; - + /// The current width of the host's desktop int m_DesktopWidth; - + /// The current height of the host's desktop int m_DesktopHeight; - + /// The current bits per pixel value of the host's desktop int m_DesktopBitsPerPixel; - + /// The current width of the application window (windowed and/or fullscreen) int m_CurrentWidth; - + /// The current height of the application window (windowed and/or fullscreen) int m_CurrentHeight; - + /// The width of the application window (windowed mode only) int m_WindowedWidth; - + /// The height of the application window (windowed mode only) int m_WindowedHeight; - + /// The current video mode flags Uint32 m_VideoModeFlags; - + /// Indicator for fullscreen mode availability bool m_FullscreenModeAvailable; - + /// Indicator for desired window mode availability (resolution, color depth, features) bool m_WindowedModeAvailable; - + /// The SDL display surface handle SDL_Surface *m_DisplaySurface; - + /// The screensaver mode indicator bool m_ScreensaverMode; - + /** * \brief The known event codes handled by %eventLoop() - * + * * \see eventLoop() * \see timerCallbackRenderEvent() * \see timerCallbackBOINCUpdateEvent() @@ -247,7 +254,7 @@ private: RenderEvent, BOINCUpdateEvent }; - + /// The event observer registry list<AbstractGraphicsEngine *> eventObservers; }; diff --git a/src/starsphere/main.cpp b/src/starsphere/main.cpp index 1a78f0025aac9a15883710a917ebab564f5f8a1c..c49eefd783b8ee7ee961e87ebadfa62a75100728 100644 --- a/src/starsphere/main.cpp +++ b/src/starsphere/main.cpp @@ -35,31 +35,28 @@ int main(int argc, char **argv) AbstractGraphicsEngine *graphics = GraphicsEngineFactory::createInstance( GraphicsEngineFactory::Starsphere, GraphicsEngineFactory::EinsteinS5R3); - + if(!graphics) { cerr << "Requested graphics engine could not be found/instantiated!" << endl; exit(1); } - - // initialize window manager - if(!window.initialize(graphics->initialWindowWidth(), - graphics->initialWindowHeight(), - graphics->frameRate())) { - + + // initialize window manager + if(!window.initialize()) { cerr << "Window manager could not be initialized!" << endl; delete graphics; exit(1); } - + // create font resource instance const Resource *fontResource = factory.createInstance("FontSansSerif"); - + if(fontResource == NULL) { cerr << "Font resource could not be loaded!" << endl; delete graphics; exit(1); } - + if(fontResource->data()->size() <= 0) { cerr << "Font resource could not be loaded!" << endl; delete graphics; @@ -68,14 +65,14 @@ int main(int argc, char **argv) } window.setWindowCaption("Einstein@Home"); - + // register starsphere as event observer window.registerEventObserver(graphics); // pepare rendering graphics->initialize(window.windowWidth(), window.windowHeight(), fontResource); graphics->refreshBOINCInformation(); - + // check optional command line parameter if(argc == 2) { string param(argv[1]); @@ -88,11 +85,11 @@ int main(int argc, char **argv) // enter main event loop window.eventLoop(); - + // clean up end exit window.unregisterEventObserver(graphics); delete graphics; delete fontResource; - + exit(0); }