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:
Joakim Kilby
2023-05-17 22:02:47 +02:00
committed by GitHub
parent f613b6651d
commit ca4b6d2ce2
9 changed files with 112 additions and 37 deletions

View File

@@ -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,

View File

@@ -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();

View File

@@ -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

View File

@@ -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()
));

View File

@@ -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;

View File

@@ -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();

View File

@@ -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() :

View File

@@ -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);

View File

@@ -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";