Browse Source

Add tick event in Glfw applications

Linked: #577
pull/580/head
Andreas Leroux 4 years ago
parent
commit
7f045b5d7d
  1. 51
      src/Magnum/Platform/GlfwApplication.cpp
  2. 33
      src/Magnum/Platform/GlfwApplication.h

51
src/Magnum/Platform/GlfwApplication.cpp

@ -33,6 +33,7 @@
#include <Corrade/Containers/StridedArrayView.h> #include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Utility/Arguments.h> #include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/Unicode.h> #include <Corrade/Utility/Unicode.h>
#include <Corrade/Utility/System.h>
#include "Magnum/ImageView.h" #include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
@ -56,9 +57,10 @@ static_assert(GLFW_TRUE == true && GLFW_FALSE == false, "GLFW does not have sane
enum class GlfwApplication::Flag: UnsignedByte { enum class GlfwApplication::Flag: UnsignedByte {
Redraw = 1 << 0, Redraw = 1 << 0,
TextInputActive = 1 << 1, TextInputActive = 1 << 1,
Exit = 1 << 2, NoTickEvent = 1 << 2,
Exit = 1 << 3,
#ifdef CORRADE_TARGET_APPLE #ifdef CORRADE_TARGET_APPLE
HiDpiWarningPrinted = 1 << 3 HiDpiWarningPrinted = 1 << 4
#endif #endif
}; };
@ -75,7 +77,7 @@ GlfwApplication::GlfwApplication(const Arguments& arguments, const Configuration
#endif #endif
GlfwApplication::GlfwApplication(const Arguments& arguments, NoCreateT): GlfwApplication::GlfwApplication(const Arguments& arguments, NoCreateT):
_flags{Flag::Redraw} _minimalLoopPeriod{0}, _flags{Flag::Redraw}
{ {
Utility::Arguments args{Implementation::windowScalingArguments()}; Utility::Arguments args{Implementation::windowScalingArguments()};
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
@ -762,15 +764,36 @@ bool GlfwApplication::mainLoopIteration() {
*/ */
if(glfwGetWindowUserPointer(_window) != this) setupCallbacks(); if(glfwGetWindowUserPointer(_window) != this) setupCallbacks();
/* If redrawing, poll for events immediately after drawEvent() (which could const UnsignedInt timeBefore = _minimalLoopPeriod ? glfwGetTime() : 0;
be setting the Redraw flag again, thus doing constant redraw). If not,
avoid spinning the CPU by waiting for the next input event. */ glfwPollEvents();
if (mainLoopDrawEventIteration())
glfwPollEvents(); /* Tick event */
else if(!(_flags & Flag::NoTickEvent)) tickEvent();
glfwWaitEvents();
/* drawEvent() was called */
if (mainLoopDrawEventIteration()) {
/* delay to prevent CPU hogging (if set) */
if(!(_minimalLoopPeriod) {
const UnsignedInt loopTime = glfwGetTime() - timeBefore;
if(loopTime < _minimalLoopPeriod)
Utility::System::sleep(_minimalLoopPeriod - loopTime);
}
return !glfwWindowShouldClose(_window);
}
return !glfwWindowShouldClose(_window); /* If not drawing anything, delay to prevent CPU hogging (if set) */
if(_minimalLoopPeriod) {
const UnsignedInt loopTime = glfwGetTime() - timeBefore;
if(loopTime < _minimalLoopPeriod)
Utility::System::sleep(_minimalLoopPeriod - loopTime);
}
/* Then, if the tick event doesn't need to be called periodically, wait
indefinitely for next input event */
if(_flags & Flag::NoTickEvent) glfwWaitEvents();
return !(flags & Flag::Exit || glfwWindowShouldClose(_window));
} }
void GlfwApplication::exit(int exitCode) { void GlfwApplication::exit(int exitCode) {
@ -871,6 +894,12 @@ void GlfwApplication::exitEvent(ExitEvent& event) {
event.setAccepted(); event.setAccepted();
} }
void GlfwApplication::tickEvent() {
/* If this got called, the tick event is not implemented by user and thus
we don't need to call it ever again */
_flags |= Flag::NoTickEvent;
}
void GlfwApplication::viewportEvent(ViewportEvent&) {} void GlfwApplication::viewportEvent(ViewportEvent&) {}
void GlfwApplication::keyPressEvent(KeyEvent&) {} void GlfwApplication::keyPressEvent(KeyEvent&) {}
void GlfwApplication::keyReleaseEvent(KeyEvent&) {} void GlfwApplication::keyReleaseEvent(KeyEvent&) {}

33
src/Magnum/Platform/GlfwApplication.h

@ -543,6 +543,21 @@ class GlfwApplication {
*/ */
void setSwapInterval(Int interval); void setSwapInterval(Int interval);
/**
* @brief Set minimal loop period
*
* This setting reduces the main loop frequency in case VSync is
* not/cannot be enabled or no drawing is done. Default is @cpp 0 @ce
* (i.e. looping at maximum frequency). If the application is drawing
* on the screen and VSync is enabled, this setting is ignored.
* @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten",
* the browser is managing the frequency instead.
* @see @ref setSwapInterval()
*/
void setMinimalLoopPeriod(UnsignedInt milliseconds) {
_minimalLoopPeriod = milliseconds;
}
/** @copydoc Sdl2Application::redraw() */ /** @copydoc Sdl2Application::redraw() */
void redraw(); void redraw();
@ -753,6 +768,23 @@ class GlfwApplication {
* @} * @}
*/ */
protected:
/**
* @brief Tick event
*
* If implemented, this function is called periodically after
* processing all input events and before draw event even though there
* might be no input events and redraw is not requested. Useful e.g.
* for asynchronous task polling. Use @ref setMinimalLoopPeriod()/
* @ref setSwapInterval() to control main loop frequency.
*
* If this implementation gets called from its @cpp override @ce, it
* will effectively stop the tick event from being fired and the app
* returns back to waiting for input events. This can be used to
* disable the tick event when not needed.
*/
virtual void tickEvent();
private: private:
enum class Flag: UnsignedByte; enum class Flag: UnsignedByte;
typedef Containers::EnumSet<Flag> Flags; typedef Containers::EnumSet<Flag> Flags;
@ -778,6 +810,7 @@ class GlfwApplication {
Vector2 _dpiScaling; Vector2 _dpiScaling;
GLFWwindow* _window{nullptr}; GLFWwindow* _window{nullptr};
UnsignedInt _minimalLoopPeriod;
Flags _flags; Flags _flags;
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
/* Has to be in an Optional because we delay-create it in a constructor /* Has to be in an Optional because we delay-create it in a constructor

Loading…
Cancel
Save