From 5824ecfe39d946ec98a71bfd8fca761d70aece53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 23 May 2012 17:43:00 +0200 Subject: [PATCH] New library for OpenGL context creation using various toolkits. Currently there is only GLUT context, pulled from magnum-examples repository. --- CMakeLists.txt | 3 +- doc/namespaces.dox | 9 ++ modules/FindMagnum.cmake | 15 +++ src/CMakeLists.txt | 1 + src/Contexts/AbstractContext.h | 52 ++++++++ src/Contexts/CMakeLists.txt | 11 ++ src/Contexts/GlutContext.cpp | 48 +++++++ src/Contexts/GlutContext.h | 226 +++++++++++++++++++++++++++++++++ 8 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 src/Contexts/AbstractContext.h create mode 100644 src/Contexts/CMakeLists.txt create mode 100644 src/Contexts/GlutContext.cpp create mode 100644 src/Contexts/GlutContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 356a2cc51..88253e669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,4 +27,5 @@ add_subdirectory(src) install(DIRECTORY src/ DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" - PATTERN "*/Test" EXCLUDE) + PATTERN "*/Test" EXCLUDE + PATTERN "src/Contexts" EXCLUDE) diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 42355a40f..b340a199e 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -11,6 +11,15 @@ Contains classes needed for building meshes, setting up and rendering the scene. */ +/** @dir Contexts + * @brief Namespace Magnum::Contexts + */ +/** @namespace Magnum::Contexts +@brief Context creation + +Base classes for creating OpenGL contexts with various toolkits. +*/ + /** @dir Math * @brief Namespace Magnum::Math */ diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index d7967b2d4..fbe8edb2e 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -16,6 +16,7 @@ # Additional dependencies are specified by the components. The optional # components are: # +# GlutContext - GLUT context (depends on GLUT package) # MeshTools - MeshTools library # Physics - Physics library # Primitives - Library with stock geometric primitives (static) @@ -63,6 +64,20 @@ foreach(component ${Magnum_FIND_COMPONENTS}) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX ${component}) + # Contexts + if(${component} MATCHES .+Context) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Contexts) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${component}.h) + + # GLUT context dependencies + if(${component} STREQUAL GlutContext) + find_package(GLUT) + if(NOT GLUT_FOUND) + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + endif() + endif() + # Mesh tools library if(${component} STREQUAL MeshTools) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b926a47c..a6ceea13b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ add_library(Magnum SHARED target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY} ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY}) install(TARGETS Magnum DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +add_subdirectory(Contexts) add_subdirectory(Math) add_subdirectory(MeshTools) add_subdirectory(Physics) diff --git a/src/Contexts/AbstractContext.h b/src/Contexts/AbstractContext.h new file mode 100644 index 000000000..74d42e530 --- /dev/null +++ b/src/Contexts/AbstractContext.h @@ -0,0 +1,52 @@ +#ifndef Magnum_Contexts_AbstractContext_h +#define Magnum_Contexts_AbstractContext_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Contexts::GlutContext + */ + +namespace Magnum { namespace Contexts { + +/** +@brief Base class for context creation + +See subclasses documentation for more information. Context classes subclasses +are meant to be used directly in `main()`, for example: +@code +class MyContext: public Magnum::Contexts::GlutContext { + // implement required methods... +}; +int main(int argc, char** argv) { + MyContext c(argc, argv); + return c.exec(); +} +@endcode +*/ +class AbstractContext { + public: + virtual inline ~AbstractContext() {} + + /** + * @brief Execute main loop + * @return Value for returning from `main()`. + */ + virtual int exec() = 0; +}; + +}} + +#endif diff --git a/src/Contexts/CMakeLists.txt b/src/Contexts/CMakeLists.txt new file mode 100644 index 000000000..a7519d44d --- /dev/null +++ b/src/Contexts/CMakeLists.txt @@ -0,0 +1,11 @@ +install(FILES AbstractContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) + +# GLUT context +find_package(GLUT) +if(GLUT_FOUND) + add_library(MagnumGlutContext STATIC GlutContext.cpp) + install(FILES GlutContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) + install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +else() + message(STATUS "GLUT library was not found. GLUT context library will not be generated.") +endif() diff --git a/src/Contexts/GlutContext.cpp b/src/Contexts/GlutContext.cpp new file mode 100644 index 000000000..ed08016bb --- /dev/null +++ b/src/Contexts/GlutContext.cpp @@ -0,0 +1,48 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "GlutContext.h" + +using namespace Corrade::Utility; + +namespace Magnum { namespace Contexts { + +GlutContext* GlutContext::instance = nullptr; + +GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const Math::Vector2& size): argc(argc), argv(argv) { + /* Save global instance */ + instance = this; + + /* Init GLUT */ + glutInit(&argc, argv); + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); + glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL); + glutInitWindowSize(size.x(), size.y()); + glutCreateWindow(title.c_str()); + glutReshapeFunc(staticViewportEvent); + glutSpecialFunc(staticKeyEvent); + glutMouseFunc(staticMouseEvent); + glutMotionFunc(staticMouseMoveEvent); + glutDisplayFunc(staticDrawEvent); + + /* Init GLEW */ + GLenum err = glewInit(); + if(err != GLEW_OK) { + Error() << "GlutContext: cannot initialize GLEW:" << glewGetErrorString(err); + exit(1); + } +} + +}} diff --git a/src/Contexts/GlutContext.h b/src/Contexts/GlutContext.h new file mode 100644 index 000000000..86ca69e96 --- /dev/null +++ b/src/Contexts/GlutContext.h @@ -0,0 +1,226 @@ +#ifndef Magnum_Contexts_GlutContext_h +#define Magnum_Contexts_GlutContext_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Contexts::GlutContext + */ + +#include "Magnum.h" +#include + +#include "AbstractContext.h" + +namespace Magnum { namespace Contexts { + +/** @nosubgrouping +@brief GLUT context + +Supports keyboard handling for limited subset of keys, mouse handling with +support for changing cursor and mouse tracking and warping. + +You need to implement at least drawEvent() and viewportEvent() to be able to +draw on the screen. +*/ +class GlutContext: public AbstractContext { + public: + /** + * @brief Constructor + * @param argc Count of arguments of main() function + * @param argv Arguments of main() function + * @param title Window title + * @param size Window size + */ + GlutContext(int& argc, char** argv, const std::string& title = "Magnum GLUT context", const Math::Vector2& size = Math::Vector2(800, 600)); + + inline int exec() { + glutMainLoop(); + return 0; + } + + /** @{ @name Drawing functions */ + + protected: + /** + * @brief Viewport event + * + * Called when viewport size changes. You should pass the new size to + * Camera::viewport() function of your camera. + */ + virtual void viewportEvent(const Math::Vector2& size) = 0; + + /** + * @brief Draw event + * + * Here implement your drawing functions, such as calling + * Camera::draw(). After drawing is finished, call swapBuffers(). If + * you want to draw immediately again, call also redraw(). + */ + virtual void drawEvent() = 0; + + /** + * @brief Swap buffers + * + * Paints currently rendered framebuffer on screen. + */ + inline void swapBuffers() { + glutSwapBuffers(); + } + + /** + * @brief Redraw immediately + * + * Marks the window for redrawing, resulting in call of drawEvent() + * in the next iteration. + */ + virtual inline void redraw() { + glutPostRedisplay(); + } + + /*@}*/ + + /** @{ @name Keyboard handling */ + + public: + /** @brief Key */ + enum class Key: int { + Up = GLUT_KEY_UP, /**< Up arrow */ + Down = GLUT_KEY_DOWN, /**< Down arrow */ + Left = GLUT_KEY_LEFT, /**< Left arrow */ + Right = GLUT_KEY_RIGHT, /**< Right arrow */ + F1 = GLUT_KEY_F1, /**< F1 */ + F2 = GLUT_KEY_F2, /**< F2 */ + F3 = GLUT_KEY_F3, /**< F3 */ + F4 = GLUT_KEY_F4, /**< F4 */ + F5 = GLUT_KEY_F5, /**< F5 */ + F6 = GLUT_KEY_F6, /**< F6 */ + F7 = GLUT_KEY_F7, /**< F7 */ + F8 = GLUT_KEY_F8, /**< F8 */ + F9 = GLUT_KEY_F9, /**< F9 */ + F10 = GLUT_KEY_F10, /**< F10 */ + F11 = GLUT_KEY_F11, /**< F11 */ + F12 = GLUT_KEY_F12, /**< F12 */ + Home = GLUT_KEY_HOME, /**< Home */ + End = GLUT_KEY_END, /**< End */ + PageUp = GLUT_KEY_PAGE_UP, /**< Page up */ + PageDown = GLUT_KEY_PAGE_DOWN /**< Page down */ + }; + + protected: + /** + * @brief Key event + * + * Called when an key is pressed. Default implementation does nothing. + */ + virtual inline void keyEvent(Key key, const Math::Vector2& position) {} + + /*@}*/ + + /** @{ @name Mouse handling */ + + public: + /** @brief Mouse button */ + enum class MouseButton: int { + Left = GLUT_LEFT_BUTTON, /**< Left button */ + Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */ + Right = GLUT_RIGHT_BUTTON, /**< Right button */ + WheelUp = 3, /**< Wheel up */ + WheelDown = 4 /**< Wheel down */ + }; + + /** @brief Mouse state */ + enum class MouseState: int { + Up = GLUT_UP, /**< No button pressed */ + Down = GLUT_DOWN /**< Button pressed */ + }; + + /** @brief Mouse cursor */ + enum class MouseCursor: int { + Default = GLUT_CURSOR_INHERIT, /**< Default cursor provided by parent window */ + None = GLUT_CURSOR_NONE /**< No cursor */ + }; + + /** + * @brief Enable or disable mouse tracking + * + * When mouse tracking is enabled, mouseMoveEvent() is called even + * when no button is pressed. Mouse tracking is disabled by default. + */ + inline void setMouseTracking(bool enabled) { + glutPassiveMotionFunc(enabled ? staticMouseMoveEvent : nullptr); + } + + /** @brief Set mouse cursor */ + inline void setMouseCursor(MouseCursor cursor) { + glutSetCursor(static_cast(cursor)); + } + + /** @brief Warp mouse cursor to given coordinates */ + inline void warpMouseCursor(const Math::Vector2& position) { + glutWarpPointer(position.x(), position.y()); + } + + protected: + /** + * @brief Mouse event + * + * Called when mouse button is pressed or released. Default + * implementation does nothing. + */ + virtual inline void mouseEvent(MouseButton button, MouseState state, const Math::Vector2& position) {} + + /** + * @brief Mouse move event + * + * Called when any mouse button is pressed and mouse is moved. Default + * implementation does nothing. + * + * @see setMouseTracking() + */ + virtual inline void mouseMoveEvent(const Math::Vector2& position) {} + + /*@}*/ + + private: + inline static void staticViewportEvent(int x, int y) { + instance->viewportEvent({x, y}); + } + + inline static void staticKeyEvent(int key, int x, int y) { + instance->keyEvent(static_cast(key), {x, y}); + } + + inline static void staticMouseEvent(int button, int state, int x, int y) { + instance->mouseEvent(static_cast(button), static_cast(state), {x, y}); + } + + inline static void staticMouseMoveEvent(int x, int y) { + instance->mouseMoveEvent({x, y}); + } + + inline static void staticDrawEvent() { + instance->drawEvent(); + } + + static GlutContext* instance; + + int& argc; + char** argv; +}; + +}} + +#endif