|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
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 "GlfwApplication.h"
|
|
|
|
|
|
|
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
|
|
#include "Magnum/Version.h"
|
|
|
|
|
#include "Magnum/Platform/Context.h"
|
|
|
|
|
#include "Magnum/Platform/ScreenedApplication.hpp"
|
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace Platform {
|
|
|
|
|
|
|
|
|
|
GlfwApplication* GlfwApplication::_instance = nullptr;
|
|
|
|
|
|
|
|
|
|
#ifdef GLFW_TRUE
|
|
|
|
|
/* The docs say that it's the same, verify that just in case */
|
|
|
|
|
static_assert(GLFW_TRUE == true && GLFW_FALSE == false, "GLFW does not have sane bool values");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT
|
|
|
|
|
GlfwApplication::GlfwApplication(const Arguments& arguments): GlfwApplication{arguments, Configuration{}} {}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
GlfwApplication::GlfwApplication(const Arguments& arguments, const Configuration& configuration): GlfwApplication{arguments, nullptr} {
|
|
|
|
|
createContext(configuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GlfwApplication::GlfwApplication(const Arguments& arguments, std::nullptr_t):
|
|
|
|
|
_context{new Context{NoCreate, arguments.argc, arguments.argv}},
|
|
|
|
|
_needsRedraw(true)
|
|
|
|
|
{
|
|
|
|
|
/* Save global instance */
|
|
|
|
|
_instance = this;
|
|
|
|
|
|
|
|
|
|
/* Init GLFW */
|
|
|
|
|
glfwSetErrorCallback(staticErrorCallback);
|
|
|
|
|
|
|
|
|
|
if(!glfwInit()) {
|
|
|
|
|
Error() << "Could not initialize GLFW";
|
|
|
|
|
std::exit(8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::createContext() { createContext({}); }
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::createContext(const Configuration& configuration) {
|
|
|
|
|
if(!tryCreateContext(configuration)) std::exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GlfwApplication::tryCreateContext(const Configuration& configuration) {
|
|
|
|
|
CORRADE_ASSERT(_context->version() == Version::None, "Platform::GlfwApplication::tryCreateContext(): context already created", false);
|
|
|
|
|
|
|
|
|
|
/* Window flags */
|
|
|
|
|
GLFWmonitor* monitor = nullptr; /* Needed for setting fullscreen */
|
|
|
|
|
if (configuration.windowFlags() >= Configuration::WindowFlag::Fullscreen) {
|
|
|
|
|
monitor = glfwGetPrimaryMonitor();
|
|
|
|
|
glfwWindowHint(GLFW_AUTO_ICONIFY, configuration.windowFlags() >= Configuration::WindowFlag::AutoIconify);
|
|
|
|
|
} else {
|
|
|
|
|
const Configuration::WindowFlags& flags = configuration.windowFlags();
|
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, flags >= Configuration::WindowFlag::Resizeable);
|
|
|
|
|
glfwWindowHint(GLFW_VISIBLE, !(flags >= Configuration::WindowFlag::Hidden));
|
|
|
|
|
#ifdef GLFW_MAXIMIZED
|
|
|
|
|
glfwWindowHint(GLFW_MAXIMIZED, flags >= Configuration::WindowFlag::Maximized);
|
|
|
|
|
#endif
|
|
|
|
|
glfwWindowHint(GLFW_ICONIFIED, flags >= Configuration::WindowFlag::Minimized);
|
|
|
|
|
glfwWindowHint(GLFW_FLOATING, flags >= Configuration::WindowFlag::Floating);
|
|
|
|
|
}
|
|
|
|
|
glfwWindowHint(GLFW_FLOATING, configuration.windowFlags() >= Configuration::WindowFlag::Focused);
|
|
|
|
|
|
|
|
|
|
/* Context window hints */
|
|
|
|
|
glfwWindowHint(GLFW_SAMPLES, configuration.sampleCount());
|
|
|
|
|
glfwWindowHint(GLFW_SRGB_CAPABLE, configuration.isSRGBCapable());
|
|
|
|
|
|
|
|
|
|
const Configuration::Flags& flags = configuration.flags();
|
|
|
|
|
#ifdef GLFW_CONTEXT_NO_ERROR
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_NO_ERROR, flags >= Configuration::Flag::NoError);
|
|
|
|
|
#endif
|
|
|
|
|
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, flags >= Configuration::Flag::Debug);
|
|
|
|
|
glfwWindowHint(GLFW_STEREO, flags >= Configuration::Flag::Stereo);
|
|
|
|
|
|
|
|
|
|
/* Cursor flags */
|
|
|
|
|
glfwWindowHint(GLFW_CURSOR, Int(configuration.cursorMode()));
|
|
|
|
|
|
|
|
|
|
/* Set context version, if requested */
|
|
|
|
|
if(configuration.version() != Version::None) {
|
|
|
|
|
Int major, minor;
|
|
|
|
|
std::tie(major, minor) = version(configuration.version());
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor);
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES
|
|
|
|
|
if(configuration.version() >= Version::GL310) {
|
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
|
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set context flags */
|
|
|
|
|
_window = glfwCreateWindow(configuration.size().x(), configuration.size().y(), configuration.title().c_str(), monitor, nullptr);
|
|
|
|
|
if(!_window) {
|
|
|
|
|
Error() << "Platform::GlfwApplication::tryCreateContext(): cannot create context";
|
|
|
|
|
glfwTerminate();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set callbacks */
|
|
|
|
|
glfwSetFramebufferSizeCallback(_window, staticViewportEvent);
|
|
|
|
|
glfwSetKeyCallback(_window, staticKeyEvent);
|
|
|
|
|
glfwSetCursorPosCallback(_window, staticMouseMoveEvent);
|
|
|
|
|
glfwSetMouseButtonCallback(_window, staticMouseEvent);
|
|
|
|
|
glfwSetScrollCallback(_window, staticMouseScrollEvent);
|
|
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(_window);
|
|
|
|
|
|
|
|
|
|
/* Return true if the initialization succeeds */
|
|
|
|
|
return _context->tryCreate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GlfwApplication::~GlfwApplication() {
|
|
|
|
|
glfwDestroyWindow(_window);
|
|
|
|
|
glfwTerminate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::setSwapInterval(const Int interval) {
|
|
|
|
|
glfwSwapInterval(interval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GlfwApplication::exec() {
|
|
|
|
|
while(!glfwWindowShouldClose(_window)) {
|
|
|
|
|
if(_needsRedraw) {
|
|
|
|
|
drawEvent();
|
|
|
|
|
}
|
|
|
|
|
glfwPollEvents();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::staticKeyEvent(GLFWwindow*, int key, int, int action, int mods) {
|
|
|
|
|
KeyEvent e(static_cast<KeyEvent::Key>(key), {static_cast<InputEvent::Modifier>(mods)});
|
|
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
_instance->keyPressEvent(e);
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
_instance->keyReleaseEvent(e);
|
|
|
|
|
} /* we don't handle GLFW_REPEAT */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::staticMouseMoveEvent(GLFWwindow* window, double x, double y) {
|
|
|
|
|
MouseMoveEvent e{Vector2i{Int(x), Int(y)}, KeyEvent::getCurrentGlfwModifiers(window)};
|
|
|
|
|
_instance->mouseMoveEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::staticMouseEvent(GLFWwindow*, int button, int action, int mods) {
|
|
|
|
|
MouseEvent e(static_cast<MouseEvent::Button>(button), {static_cast<InputEvent::Modifier>(mods)});
|
|
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
_instance->mousePressEvent(e);
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
_instance->mouseReleaseEvent(e);
|
|
|
|
|
} /* we don't handle GLFW_REPEAT */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::staticMouseScrollEvent(GLFWwindow* window, double xoffset, double yoffset) {
|
|
|
|
|
MouseScrollEvent e(Vector2d{xoffset, yoffset}, KeyEvent::getCurrentGlfwModifiers(window));
|
|
|
|
|
_instance->mouseScrollEvent(e);
|
|
|
|
|
|
|
|
|
|
if(yoffset != 0.0) {
|
|
|
|
|
MouseEvent e1((yoffset > 0.0) ? MouseEvent::Button::WheelUp : MouseEvent::Button::WheelDown, KeyEvent::getCurrentGlfwModifiers(window));
|
|
|
|
|
_instance->mousePressEvent(e1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::staticErrorCallback(int, const char* description) {
|
|
|
|
|
Error() << description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto GlfwApplication::KeyEvent::getCurrentGlfwModifiers(GLFWwindow* window) -> Modifiers {
|
|
|
|
|
static_assert(GLFW_PRESS == true && GLFW_RELEASE == false,
|
|
|
|
|
"GLFW press and release constants do not correspond to bool values");
|
|
|
|
|
|
|
|
|
|
Modifiers mods;
|
|
|
|
|
if(glfwGetKey(window, Int(Key::LeftShift)) || glfwGetKey(window, Int(Key::RightShift)))
|
|
|
|
|
mods |= Modifier::Shift;
|
|
|
|
|
if(glfwGetKey(window, Int(Key::LeftAlt)) || glfwGetKey(window, Int(Key::RightAlt)))
|
|
|
|
|
mods |= Modifier::Alt;
|
|
|
|
|
if(glfwGetKey(window, Int(Key::LeftCtrl)) || glfwGetKey(window, Int(Key::RightCtrl)))
|
|
|
|
|
mods |= Modifier::Ctrl;
|
|
|
|
|
if(glfwGetKey(window, Int(Key::RightSuper)))
|
|
|
|
|
mods |= Modifier::AltGr;
|
|
|
|
|
|
|
|
|
|
return mods;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlfwApplication::viewportEvent(const Vector2i&) {}
|
|
|
|
|
void GlfwApplication::keyPressEvent(KeyEvent&) {}
|
|
|
|
|
void GlfwApplication::keyReleaseEvent(KeyEvent&) {}
|
|
|
|
|
void GlfwApplication::mousePressEvent(MouseEvent&) {}
|
|
|
|
|
void GlfwApplication::mouseReleaseEvent(MouseEvent&) {}
|
|
|
|
|
void GlfwApplication::mouseMoveEvent(MouseMoveEvent&) {}
|
|
|
|
|
void GlfwApplication::mouseScrollEvent(MouseScrollEvent&) {}
|
|
|
|
|
|
|
|
|
|
GlfwApplication::Configuration::Configuration():
|
|
|
|
|
_title{"Magnum GLFW Application"},
|
|
|
|
|
_size{800, 600}, _sampleCount{0},
|
|
|
|
|
_version{Version::None},
|
|
|
|
|
_windowFlags{WindowFlag::Focused},
|
|
|
|
|
_cursorMode{CursorMode::Normal} {}
|
|
|
|
|
|
|
|
|
|
GlfwApplication::Configuration::~Configuration() = default;
|
|
|
|
|
|
|
|
|
|
template class BasicScreen<GlfwApplication>;
|
|
|
|
|
template class BasicScreenedApplication<GlfwApplication>;
|
|
|
|
|
|
|
|
|
|
}}
|