diff --git a/doc/snippets/CMakeLists.txt b/doc/snippets/CMakeLists.txt index c63e2d1d0..84a485333 100644 --- a/doc/snippets/CMakeLists.txt +++ b/doc/snippets/CMakeLists.txt @@ -192,6 +192,7 @@ if(MAGNUM_WITH_SDL2APPLICATION AND MAGNUM_TARGET_GL) target_link_libraries(getting-started-blue PRIVATE MagnumSdl2Application) add_library(snippets-MagnumPlatform STATIC + Magnum-application.cpp MagnumPlatform.cpp MagnumGL-application.cpp) target_link_libraries(snippets-MagnumPlatform PRIVATE MagnumSdl2Application) diff --git a/doc/snippets/Magnum-application.cpp b/doc/snippets/Magnum-application.cpp new file mode 100644 index 000000000..a954338df --- /dev/null +++ b/doc/snippets/Magnum-application.cpp @@ -0,0 +1,72 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/Platform/Sdl2Application.h" +#include "Magnum/Timeline.h" + +using namespace Magnum; + +#define DOXYGEN_ELLIPSIS(...) __VA_ARGS__ +#define DOXYGEN_IGNORE(...) __VA_ARGS__ + +class MyApplication: public Platform::Application { + public: + explicit MyApplication(const Arguments& arguments); + + void drawEvent(); + + private: + Timeline _timeline; +}; + +/* [Timeline-usage] */ +MyApplication::MyApplication(const Arguments& arguments): + Platform::Application{arguments, NoCreate} +{ + DOXYGEN_ELLIPSIS() + + // Enable VSync or set minimal loop period for the application, if + // needed/applicable ... + + _timeline.start(); +} + +void MyApplication::drawEvent() { + DOXYGEN_ELLIPSIS() + + // Distance of object traveling at speed of 15 units per second + Float distance = 15.0f*_timeline.previousFrameDuration(); DOXYGEN_IGNORE(static_cast(distance);) + + // Move an object, draw it ... + + swapBuffers(); + redraw(); + _timeline.nextFrame(); +} +/* [Timeline-usage] */ + +int main() { + return 0; /* on iOS SDL redefines main to SDL_main and then return is needed */ +} diff --git a/src/Magnum/Animation/Player.h b/src/Magnum/Animation/Player.h index 927ab9e7a..083293da3 100644 --- a/src/Magnum/Animation/Player.h +++ b/src/Magnum/Animation/Player.h @@ -175,8 +175,10 @@ never from @ref pause(), @ref stop() or any other API. For managing global application you can use @ref Timeline, @ref std::chrono APIs or any other type that supports basic arithmetic. The time doesn't have to be monotonic or have constant speed, but note that non-continuous and backward -time jumps may have worse performance than going monotonically forward. See -@ref Animation-Player-time-type "below" for more information about using +time jumps may have worse performance than going monotonically forward. With +the @ref Timeline in particular, it's recommended to never call +@ref Timeline::stop() but control the player start/pause/stop state instead. +See @ref Animation-Player-time-type "below" for more information about using different time types. @snippet MagnumAnimation.cpp Player-usage-playback diff --git a/src/Magnum/Timeline.cpp b/src/Magnum/Timeline.cpp index e8c674135..06f3c8ed6 100644 --- a/src/Magnum/Timeline.cpp +++ b/src/Magnum/Timeline.cpp @@ -35,21 +35,21 @@ using namespace std::chrono; namespace Magnum { void Timeline::start() { - running = true; + _running = true; _startTime = high_resolution_clock::now(); _previousFrameTime = _startTime; _previousFrameDuration = 0; } void Timeline::stop() { - running = false; + _running = false; _startTime = high_resolution_clock::time_point(); _previousFrameTime = _startTime; _previousFrameDuration = 0; } void Timeline::nextFrame() { - if(!running) return; + if(!_running) return; auto now = high_resolution_clock::now(); auto duration = UnsignedInt(duration_cast(now-_previousFrameTime).count()); diff --git a/src/Magnum/Timeline.h b/src/Magnum/Timeline.h index 2ad16b816..6c0fbbdd5 100644 --- a/src/Magnum/Timeline.h +++ b/src/Magnum/Timeline.h @@ -39,20 +39,20 @@ namespace Magnum { /** @brief Timeline -Keeps track of time delta between frames. Can be used as source for animation -speed computations. +Keeps track of time delta between frames. Can be used for advancing animation +playback. @section Timeline-usage Basic usage -Construct the timeline on initialization so the instance is available for -whole lifetime of the application. Call @ref start() before first draw event is -performed, after everything is properly initialized. +Construct the timeline on initialization so the instance is available for the +whole lifetime of the application. Call @ref start() after the application +state is fully initialized and before the first draw event is performed. -@note When timeline is started, it immediately starts measuring frame time. - Be prepared that time of first frame will be much longer than time of - following frames. It mainly depends on where you called @ref start() in - your initialization routine, but can be also affected by driver- and - GPU-specific lazy texture binding, shader recompilations etc. +@note When the timeline is started, it immediately starts measuring frame time. + Be prepared that time of the first frame may be much longer than time of + the following frames. It mainly depends on where you called @ref start() in + your initialization routine, but can be also affected by various + driver-specific operations that are done lazily during the first frame. In your draw event implementation don't forget to call @ref nextFrame() after buffer swap. You can use @ref previousFrameDuration() to compute animation @@ -60,52 +60,38 @@ speed. To limit application framerate you can use @ref Platform::Sdl2Application::setSwapInterval() "Platform::*Application::setSwapInterval()" or @ref Platform::Sdl2Application::setMinimalLoopPeriod() "Platform::*Application::setMinimalLoopPeriod()". Note that on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten" the framerate is -governed by browser and you can't do anything about it. +governed by the browser and you can't do anything about it. Example usage: -@code{.cpp} -MyApplication::MyApplication(const Arguments& arguments): Platform::Application{arguments} { - // Initialization ... +@snippet Magnum-application.cpp Timeline-usage - // Enable VSync or set minimal loop period for the application, if - // needed/applicable ... - - timeline.start(); -} - -void MyApplication::drawEvent() { - // Distance of object travelling at speed of 15 units per second - Float distance = 15.0f*timeline.previousFrameDuration(); - - // Move object, draw ... - - swapBuffers(); - redraw(); - timeline.nextFrame(); -} -@endcode +Apart from directly using the returned time values, the @ref Timeline can also +be used together with @ref Animation::Player for a more controlled behavior. In +that case, it's recommended to never call @ref Timeline::stop() but control the +player start/pause/stop state instead. See @ref Animation::Player documentation +for more information. */ class MAGNUM_EXPORT Timeline { public: /** * @brief Constructor * - * Creates stopped timeline. + * Creates a stopped timeline. * @see @ref start() */ - explicit Timeline(): _previousFrameDuration(0), running(false) {} + explicit Timeline() = default; /** - * @brief Start timeline + * @brief Start the timeline * - * Sets previous frame time and duration to @cpp 0 @ce. + * Sets previous frame time and duration to @cpp 0.0f @ce. * @see @ref stop(), @ref previousFrameDuration() */ void start(); /** - * @brief Stop timeline + * @brief Stop the timeline * * @see @ref start(), @ref nextFrame() */ @@ -114,32 +100,32 @@ class MAGNUM_EXPORT Timeline { /** * @brief Advance to next frame * - * @note This function does nothing if the timeline is stopped. + * Does nothing if the timeline is stopped. * @see @ref stop() */ void nextFrame(); /** - * @brief Time at previous frame (in seconds) + * @brief Time at previous frame in seconds * - * Returns time elapsed since start() was called. If the timeline is - * stopped, the function returns @cpp 0.0f @ce. + * Returns time elapsed since @ref start() was called. If the timeline + * is stopped, the function returns @cpp 0.0f @ce. */ Float previousFrameTime() const; /** - * @brief Duration of previous frame (in seconds) + * @brief Duration of previous frame in seconds * * If the timeline is stopped, the function returns @cpp 0.0f @ce. */ Float previousFrameDuration() const { return _previousFrameDuration; } private: - std::chrono::high_resolution_clock::time_point _startTime; - std::chrono::high_resolution_clock::time_point _previousFrameTime; - Float _previousFrameDuration; + std::chrono::high_resolution_clock::time_point _startTime{}; + std::chrono::high_resolution_clock::time_point _previousFrameTime{}; + Float _previousFrameDuration{}; - bool running; + bool _running = false; }; }