mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-25 14:29:03 -06:00
Fix viewport & window issues (#2630)
* Add support for multiple windows & viewports With correct rendering of both Scene and Overlays/GUI. GUI is restricted to either the first window or any other windows tagged with "GUI", overlays are drawn on all windows/viewports. Closes #2542 and #1645
This commit is contained in:
@@ -264,12 +264,12 @@ void checkJoystickStatus() {
|
||||
}
|
||||
|
||||
bool isGuiWindow(sgct::Window* window) {
|
||||
if (Engine::instance().windows().size() == 1) {
|
||||
// If we only have one window, assume it's also the GUI window.
|
||||
// It might not have been given the 'GUI' tag
|
||||
return true;
|
||||
if (global::windowDelegate->hasGuiWindow()) {
|
||||
return window->hasTag("GUI");
|
||||
}
|
||||
return window->hasTag("GUI");
|
||||
|
||||
const sgct::Window* first = Engine::instance().windows().front().get();
|
||||
return window->id() == first->id();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -742,13 +742,6 @@ void setSgctDelegateFunctions() {
|
||||
sgctDelegate.currentSubwindowSize = []() {
|
||||
ZoneScoped;
|
||||
|
||||
if (currentWindow->viewports().size() > 1) {
|
||||
const Viewport& viewport = *currentWindow->viewports().front();
|
||||
return glm::ivec2(
|
||||
currentWindow->resolution().x * viewport.size().x,
|
||||
currentWindow->resolution().y * viewport.size().y
|
||||
);
|
||||
}
|
||||
switch (currentWindow->stereoMode()) {
|
||||
case Window::StereoMode::SideBySide:
|
||||
case Window::StereoMode::SideBySideInverted:
|
||||
@@ -764,26 +757,20 @@ void setSgctDelegateFunctions() {
|
||||
);
|
||||
default:
|
||||
return glm::ivec2(
|
||||
currentWindow->resolution().x,
|
||||
currentWindow->resolution().y
|
||||
currentWindow->resolution().x * currentViewport->size().x,
|
||||
currentWindow->resolution().y * currentViewport->size().y
|
||||
);
|
||||
}
|
||||
};
|
||||
sgctDelegate.currentDrawBufferResolution = []() {
|
||||
ZoneScoped;
|
||||
|
||||
Viewport* viewport = currentWindow->viewports().front().get();
|
||||
const Viewport* viewport = dynamic_cast<const Viewport*>(currentViewport);
|
||||
if (viewport != nullptr) {
|
||||
if (viewport->hasSubViewports() && viewport->nonLinearProjection()) {
|
||||
ivec2 dim = viewport->nonLinearProjection()->cubemapResolution();
|
||||
return glm::ivec2(dim.x, dim.y);
|
||||
}
|
||||
else if (currentWindow->viewports().size() > 1) {
|
||||
// @TODO (abock, 2020-04-09) This should probably be based on the current
|
||||
// viewport?
|
||||
ivec2 dim = currentWindow->finalFBODimensions();
|
||||
return glm::ivec2(dim.x * viewport->size().x, dim.y * viewport->size().y);
|
||||
}
|
||||
else {
|
||||
ivec2 dim = currentWindow->finalFBODimensions();
|
||||
return glm::ivec2(dim.x, dim.y);
|
||||
@@ -800,12 +787,43 @@ void setSgctDelegateFunctions() {
|
||||
}
|
||||
return glm::ivec2(-1, -1);
|
||||
};
|
||||
sgctDelegate.currentViewportResolution = []() {
|
||||
ZoneScoped;
|
||||
|
||||
if (currentViewport != nullptr) {
|
||||
ivec2 res = currentWindow->resolution();
|
||||
vec2 size = currentViewport->size();
|
||||
return glm::ivec2(size.x * res.x, size.y * res.y);
|
||||
}
|
||||
return glm::ivec2(-1, -1);
|
||||
};
|
||||
sgctDelegate.dpiScaling = []() {
|
||||
ZoneScoped;
|
||||
|
||||
vec2 scale = currentWindow->scale();
|
||||
return glm::vec2(scale.x, scale.y);
|
||||
};
|
||||
sgctDelegate.firstWindowResolution = []() {
|
||||
ZoneScoped;
|
||||
sgct::Window* window = Engine::instance().windows().front().get();
|
||||
return glm::ivec2(window->resolution().x, window->resolution().y);
|
||||
};
|
||||
sgctDelegate.guiWindowResolution = []() {
|
||||
ZoneScoped;
|
||||
const Window* guiWindow = nullptr;
|
||||
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
|
||||
if (window->hasTag("GUI")) {
|
||||
guiWindow = window.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!guiWindow) {
|
||||
guiWindow = Engine::instance().windows().front().get();
|
||||
}
|
||||
|
||||
return glm::ivec2(guiWindow->resolution().x, guiWindow->resolution().y);
|
||||
};
|
||||
sgctDelegate.osDpiScaling = []() {
|
||||
ZoneScoped;
|
||||
|
||||
@@ -901,6 +919,11 @@ void setSgctDelegateFunctions() {
|
||||
|
||||
return currentWindow->id();
|
||||
};
|
||||
sgctDelegate.firstWindowId = []() {
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().windows().front()->id();
|
||||
};
|
||||
sgctDelegate.openGLProcedureAddress = [](const char* func) {
|
||||
ZoneScoped;
|
||||
|
||||
@@ -959,6 +982,35 @@ void setSgctDelegateFunctions() {
|
||||
sgctDelegate.currentNode = []() {
|
||||
return ClusterManager::instance().thisNodeId();
|
||||
};
|
||||
sgctDelegate.mousePositionViewportRelative = [](glm::vec2 mousePosition) {
|
||||
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
|
||||
if (isGuiWindow(window.get())) {
|
||||
sgct::ivec2 res = window->resolution();
|
||||
for (const std::unique_ptr<Viewport>& viewport : window->viewports()) {
|
||||
sgct::vec2 pos = viewport->position();
|
||||
sgct::vec2 size = viewport->size();
|
||||
glm::vec4 bounds = glm::vec4(
|
||||
pos.x * res.x,
|
||||
(1.0 - pos.y - size.y) * res.y,
|
||||
(pos.x + size.x) * res.x,
|
||||
(1.0 - pos.y) * res.y
|
||||
);
|
||||
|
||||
if (
|
||||
(mousePosition.x >= bounds.x && mousePosition.x <= bounds.z) &&
|
||||
(mousePosition.y >= bounds.y && mousePosition.y <= bounds.w)
|
||||
) {
|
||||
return glm::vec2(
|
||||
res.x * (mousePosition.x - bounds.x) / (bounds.z - bounds.x),
|
||||
res.y * (mousePosition.y - bounds.y) / (bounds.w - bounds.y)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mousePosition;
|
||||
};
|
||||
}
|
||||
|
||||
void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& hasProfile,
|
||||
|
||||
@@ -89,6 +89,7 @@ public:
|
||||
void deinitializeGL();
|
||||
void preSynchronization();
|
||||
void postSynchronizationPreDraw();
|
||||
void viewportChanged();
|
||||
void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
|
||||
const glm::mat4& projectionMatrix);
|
||||
void drawOverlays();
|
||||
|
||||
@@ -62,8 +62,14 @@ struct WindowDelegate {
|
||||
|
||||
glm::ivec2 (*currentViewportSize)() = []() { return glm::ivec2(0); };
|
||||
|
||||
glm::ivec2(*currentViewportResolution)() = []() { return glm::ivec2(0); };
|
||||
|
||||
glm::vec2 (*dpiScaling)() = []() { return glm::vec2(1.f); };
|
||||
|
||||
glm::ivec2(*firstWindowResolution)() = []() { return glm::ivec2(0); };
|
||||
|
||||
glm::ivec2(*guiWindowResolution)() = []() { return glm::ivec2(0); };
|
||||
|
||||
float (*osDpiScaling)() = []() { return 1.f; };
|
||||
|
||||
bool (*hasGuiWindow)() = []() { return false; };
|
||||
@@ -89,6 +95,8 @@ struct WindowDelegate {
|
||||
|
||||
int (*currentWindowId)() = []() { return 0; };
|
||||
|
||||
int (*firstWindowId)() = []() { return 0; };
|
||||
|
||||
double (*getHorizFieldOfView)() = []() { return 0.0; };
|
||||
|
||||
void (*setHorizFieldOfView)(float hFovDeg) = [](float) { };
|
||||
@@ -113,6 +121,9 @@ struct WindowDelegate {
|
||||
int (*numberOfNodes)() = []() { return 0; };
|
||||
|
||||
int (*currentNode)() = []() { return 0; };
|
||||
|
||||
glm::vec2 (*mousePositionViewportRelative)(glm::vec2 mousePosition) =
|
||||
[](glm::vec2) { return glm::vec2(0); };
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -111,7 +111,7 @@ void CefWebGuiModule::startOrStopGui() {
|
||||
);
|
||||
_instance->initialize();
|
||||
_instance->reshape(static_cast<glm::ivec2>(
|
||||
static_cast<glm::vec2>(global::windowDelegate->currentSubwindowSize()) *
|
||||
static_cast<glm::vec2>(global::windowDelegate->guiWindowResolution()) *
|
||||
global::windowDelegate->dpiScaling()
|
||||
));
|
||||
if (!_url.value().empty()) {
|
||||
@@ -226,12 +226,13 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration)
|
||||
const bool isGuiWindow =
|
||||
global::windowDelegate->hasGuiWindow() ?
|
||||
global::windowDelegate->isGuiWindow() :
|
||||
true;
|
||||
global::windowDelegate->currentWindowId()
|
||||
== global::windowDelegate->firstWindowId();
|
||||
const bool isMaster = global::windowDelegate->isMaster();
|
||||
|
||||
if (isGuiWindow && isMaster && _instance) {
|
||||
if (global::windowDelegate->windowHasResized() || _instance->_shouldReshape) {
|
||||
glm::ivec2 csws = global::windowDelegate->currentSubwindowSize();
|
||||
glm::ivec2 csws = global::windowDelegate->guiWindowResolution();
|
||||
_instance->reshape(static_cast<glm::ivec2>(
|
||||
static_cast<glm::vec2>(csws) * global::windowDelegate->dpiScaling()
|
||||
));
|
||||
|
||||
@@ -79,7 +79,7 @@ BrowserInstance::~BrowserInstance() {
|
||||
|
||||
void BrowserInstance::initialize() {
|
||||
reshape(static_cast<glm::ivec2>(
|
||||
static_cast<glm::vec2>(global::windowDelegate->currentSubwindowSize()) *
|
||||
static_cast<glm::vec2>(global::windowDelegate->guiWindowResolution()) *
|
||||
global::windowDelegate->dpiScaling()
|
||||
));
|
||||
_isInitialized = true;
|
||||
|
||||
@@ -383,6 +383,8 @@ bool EventHandler::mousePositionCallback(double x, double y) {
|
||||
const glm::vec2 dpiScaling = global::windowDelegate->dpiScaling();
|
||||
_mousePosition.x = floor(static_cast<float>(x) * dpiScaling.x);
|
||||
_mousePosition.y = floor(static_cast<float>(y) * dpiScaling.y);
|
||||
_mousePosition =
|
||||
global::windowDelegate->mousePositionViewportRelative(_mousePosition);
|
||||
_browserInstance->sendMouseMoveEvent(mouseEvent());
|
||||
global::interactionMonitor->markInteraction();
|
||||
|
||||
|
||||
@@ -938,6 +938,8 @@ void OpenSpaceEngine::deinitializeGL() {
|
||||
|
||||
LTRACE("OpenSpaceEngine::deinitializeGL(begin)");
|
||||
|
||||
viewportChanged();
|
||||
|
||||
// We want to render an image informing the user that we are shutting down
|
||||
global::renderEngine->renderEndscreen();
|
||||
global::windowDelegate->swapBuffer();
|
||||
@@ -1171,15 +1173,6 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
|
||||
bool master = global::windowDelegate->isMaster();
|
||||
global::syncEngine->postSynchronization(SyncEngine::IsMaster(master));
|
||||
|
||||
// This probably doesn't have to be done here every frame, but doing it earlier gives
|
||||
// weird results when using side_by_side stereo --- abock
|
||||
using FR = ghoul::fontrendering::FontRenderer;
|
||||
FR::defaultRenderer().setFramebufferSize(global::renderEngine->fontResolution());
|
||||
|
||||
FR::defaultProjectionRenderer().setFramebufferSize(
|
||||
global::renderEngine->renderingResolution()
|
||||
);
|
||||
|
||||
if (_shutdown.inShutdown) {
|
||||
if (_shutdown.timer <= 0.f) {
|
||||
global::eventEngine->publishEvent<events::EventApplicationShutdown>(
|
||||
@@ -1231,6 +1224,17 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
|
||||
LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(end)");
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::viewportChanged() {
|
||||
// Needs to be updated since each render call potentially targets a different
|
||||
// window and/or viewport
|
||||
using FR = ghoul::fontrendering::FontRenderer;
|
||||
FR::defaultRenderer().setFramebufferSize(global::renderEngine->fontResolution());
|
||||
|
||||
FR::defaultProjectionRenderer().setFramebufferSize(
|
||||
global::renderEngine->renderingResolution()
|
||||
);
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
|
||||
const glm::mat4& projectionMatrix)
|
||||
{
|
||||
@@ -1238,6 +1242,8 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& view
|
||||
TracyGpuZone("Render");
|
||||
LTRACE("OpenSpaceEngine::render(begin)");
|
||||
|
||||
viewportChanged();
|
||||
|
||||
global::renderEngine->render(sceneMatrix, viewMatrix, projectionMatrix);
|
||||
|
||||
for (const std::function<void()>& func : *global::callback::render) {
|
||||
@@ -1254,6 +1260,8 @@ void OpenSpaceEngine::drawOverlays() {
|
||||
TracyGpuZone("Draw2D");
|
||||
LTRACE("OpenSpaceEngine::drawOverlays(begin)");
|
||||
|
||||
viewportChanged();
|
||||
|
||||
const bool isGuiWindow =
|
||||
global::windowDelegate->hasGuiWindow() ?
|
||||
global::windowDelegate->isGuiWindow() :
|
||||
|
||||
@@ -165,7 +165,7 @@ void LoadingScreen::render() {
|
||||
|
||||
const glm::vec2 dpiScaling = global::windowDelegate->dpiScaling();
|
||||
const glm::ivec2 res =
|
||||
glm::vec2(global::windowDelegate->currentSubwindowSize()) * dpiScaling;
|
||||
glm::vec2(global::windowDelegate->firstWindowResolution()) * dpiScaling;
|
||||
|
||||
float screenAspectRatio = static_cast<float>(res.x) / static_cast<float>(res.y);
|
||||
|
||||
|
||||
@@ -615,7 +615,7 @@ glm::ivec2 RenderEngine::fontResolution() const {
|
||||
return global::windowDelegate->currentViewportSize();
|
||||
}
|
||||
else {
|
||||
return global::windowDelegate->currentSubwindowSize();
|
||||
return global::windowDelegate->currentViewportResolution();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,7 +835,7 @@ void RenderEngine::renderEndscreen() {
|
||||
|
||||
const glm::vec2 dpiScaling = global::windowDelegate->dpiScaling();
|
||||
const glm::ivec2 res =
|
||||
glm::vec2(global::windowDelegate->currentSubwindowSize()) / dpiScaling;
|
||||
glm::vec2(global::windowDelegate->firstWindowResolution()) / dpiScaling;
|
||||
glViewport(0, 0, res.x, res.y);
|
||||
|
||||
constexpr std::string_view Text = "Shutting down";
|
||||
|
||||
Reference in New Issue
Block a user