From 75f62e52f22c99e462b520f2c7af84b79dc087c0 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Sun, 20 Mar 2016 20:43:37 +0100 Subject: [PATCH] Make Qt editor work with the SDL engine Viewport rendering doesn't quite work yet, though. --- CMakeLists.txt | 21 +++++++ src/editor/C4Console.cpp | 2 +- src/editor/C4ConsoleQt.cpp | 2 +- src/editor/C4ConsoleQtState.cpp | 16 +++++ src/editor/C4ConsoleQtViewport.cpp | 31 ++++++---- src/editor/C4ConsoleQtViewport.h | 8 ++- src/editor/C4ViewportWindow.cpp | 6 ++ src/game/C4Viewport.cpp | 3 + src/graphics/C4DrawGL.cpp | 11 +++- src/graphics/C4DrawGL.h | 35 +++++++++-- src/graphics/C4DrawGLCtx.cpp | 94 ++++++++++++++++++++++++++++++ src/platform/C4Window.h | 3 + src/platform/C4WindowSDL.cpp | 10 ++++ 13 files changed, 219 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8d5a9e71..8ca75b738 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -919,6 +919,27 @@ elseif(USE_SDL_MAINLOOP) src/platform/C4AppSDL.cpp src/platform/C4WindowSDL.cpp ) + # TODO: Remove duplication + if(WITH_QT_EDITOR) + qt5_add_resources(qt_editor_resources "src/editor/resource.qrc") + list(APPEND OC_GUI_SOURCES + src/editor/C4ConsoleQt.cpp + src/editor/C4ConsoleQt.h + src/editor/C4ConsoleQtState.cpp + src/editor/C4ConsoleQtState.h + src/editor/C4ConsoleQtPropListViewer.cpp + src/editor/C4ConsoleQtPropListViewer.h + src/editor/C4ConsoleQtObjectListViewer.cpp + src/editor/C4ConsoleQtObjectListViewer.h + src/editor/C4ConsoleQtDefinitionListViewer.cpp + src/editor/C4ConsoleQtDefinitionListViewer.h + src/editor/C4ConsoleQtViewport.cpp + src/editor/C4ConsoleQtViewport.h + src/editor/C4ConsoleQtMainWindow.ui + src/editor/resource.qrc + ${qt_editor_resources} + ) + endif() elseif(USE_WIN32_WINDOWS) if(WITH_QT_EDITOR) qt5_add_resources(qt_editor_resources "src/editor/resource.qrc") diff --git a/src/editor/C4Console.cpp b/src/editor/C4Console.cpp index a2d68938f..e8a984eb3 100644 --- a/src/editor/C4Console.cpp +++ b/src/editor/C4Console.cpp @@ -561,7 +561,7 @@ void C4Console::RegisterRecentInput(const char *input, RecentScriptInputLists se mru.erase(mru.begin()); } -#if !(defined(USE_WIN32_WINDOWS) || defined(USE_COCOA) || defined(USE_GTK)) +#if !(defined(USE_WIN32_WINDOWS) || defined(USE_COCOA) || defined(USE_GTK) || defined(WITH_QT_EDITOR)) class C4ConsoleGUI::State: public C4ConsoleGUI::InternalState { public: State(C4ConsoleGUI *console): Super(console) {} diff --git a/src/editor/C4ConsoleQt.cpp b/src/editor/C4ConsoleQt.cpp index d898c05bb..a5c615207 100644 --- a/src/editor/C4ConsoleQt.cpp +++ b/src/editor/C4ConsoleQt.cpp @@ -95,7 +95,7 @@ C4Window* C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application) hWindow = reinterpret_cast(state->window->winId()); renderwnd = hWindow; #else - TODO + // nothing to do #endif Active = true; EnableControls(fGameOpen); diff --git a/src/editor/C4ConsoleQtState.cpp b/src/editor/C4ConsoleQtState.cpp index a9bb1d03f..f5dc03d86 100644 --- a/src/editor/C4ConsoleQtState.cpp +++ b/src/editor/C4ConsoleQtState.cpp @@ -391,6 +391,22 @@ bool C4ConsoleGUIState::CreateConsoleWindow(C4AbstractApp *app) { // No Qt main loop execution during console creation ExecRecursionCheck no_qt_recursion; + + // Initialize OpenGL. + QSurfaceFormat format; + format.setMajorVersion(/*REQUESTED_GL_CTX_MAJOR*/ 3); + format.setMinorVersion(/*REQUESTED_GL_CTX_MINOR*/ 2); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setDepthBufferSize(8); + format.setProfile(QSurfaceFormat::CoreProfile); + if (Config.Graphics.DebugOpenGL) + format.setOption(QSurfaceFormat::DebugContext); + QSurfaceFormat::setDefaultFormat(format); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + + // Basic Qt+Main window setup from .ui file int fake_argc = 0; application.reset(new QApplication(fake_argc, NULL)); diff --git a/src/editor/C4ConsoleQtViewport.cpp b/src/editor/C4ConsoleQtViewport.cpp index 512d338ab..4a7759e76 100644 --- a/src/editor/C4ConsoleQtViewport.cpp +++ b/src/editor/C4ConsoleQtViewport.cpp @@ -28,21 +28,23 @@ /* Console viewports */ C4ConsoleQtViewportView::C4ConsoleQtViewportView(class C4ConsoleQtViewportDockWidget *dock) - : QWidget(dock), dock(dock), cvp(dock->cvp ? dock->cvp->cvp : NULL) + : QOpenGLWidget(dock), dock(dock), cvp(dock->cvp ? dock->cvp->cvp : NULL) { setAutoFillBackground(false); setAttribute(Qt::WA_NoSystemBackground, true); - setAttribute(Qt::WA_PaintOnScreen, true); +#ifdef USE_WIN32_WINDOWS setAttribute(Qt::WA_NativeWindow, true); +#endif setAttribute(Qt::WA_ShowWithoutActivating, true); setWindowFlags(Qt::FramelessWindowHint); setFocusPolicy(Qt::WheelFocus); setMouseTracking(true); // Register for viewport + C4ViewportWindow *window = dock->cvp; #ifdef USE_WIN32_WINDOWS - dock->cvp->hWindow = reinterpret_cast(this->winId()); + window->hWindow = reinterpret_cast(this->winId()); #else - TODO + window->glwidget = this; #endif } @@ -52,12 +54,6 @@ bool C4ConsoleQtViewportView::IsPlayViewport() const && (::Console.EditCursor.GetMode() == C4CNS_ModePlay)); } -void C4ConsoleQtViewportView::resizeEvent(QResizeEvent *resize_event) -{ - QWidget::resizeEvent(resize_event); - if (cvp) dock->cvp->cvp->UpdateOutputSize(resize_event->size().width(), resize_event->size().height()); -} - bool C4ConsoleQtViewportView::nativeEvent(const QByteArray &eventType, void *message, long *result) { // Handle native Windows messages @@ -234,7 +230,7 @@ static C4KeyCode QtKeyToUnixScancode(const QKeyEvent &event) case Qt::Key_Down: return K_DOWN; case Qt::Key_Left: return K_LEFT; case Qt::Key_Right: return K_RIGHT; - case Qt::Key_Clear: return K_CENTER; + /* case Qt::Key_Clear: return K_CENTER; */ case Qt::Key_Insert: return K_INSERT; case Qt::Key_Delete: return K_DELETE; case Qt::Key_Menu: return K_MENU; @@ -311,6 +307,19 @@ void C4ConsoleQtViewportView::leaveEvent(QEvent *) ::Console.EditCursor.SetMouseHover(false); } +void C4ConsoleQtViewportView::initializeGL() { } + +void C4ConsoleQtViewportView::resizeGL(int w, int h) +{ + cvp->UpdateOutputSize(w, h); +} + +void C4ConsoleQtViewportView::paintGL() +{ + // Painting is done regularily elsewhere anyways. + /* cvp->Execute(); */ +} + C4ConsoleQtViewportLabel::C4ConsoleQtViewportLabel(const QString &title, C4ConsoleQtViewportDockWidget *dock) : QLabel(dock), dock(dock) diff --git a/src/editor/C4ConsoleQtViewport.h b/src/editor/C4ConsoleQtViewport.h index 278868184..422e853fb 100644 --- a/src/editor/C4ConsoleQtViewport.h +++ b/src/editor/C4ConsoleQtViewport.h @@ -24,7 +24,7 @@ #include // for glew.h #include -class C4ConsoleQtViewportView : public QWidget +class C4ConsoleQtViewportView : public QOpenGLWidget { Q_OBJECT @@ -37,7 +37,6 @@ private: protected: void focusInEvent(QFocusEvent * event) override; void focusOutEvent(QFocusEvent * event) override; - void resizeEvent(QResizeEvent *resize_event) override; bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; void mouseMoveEvent(QMouseEvent *eventMove) override; void mousePressEvent(QMouseEvent *eventPress) override; @@ -51,6 +50,11 @@ protected: public: C4ConsoleQtViewportView(class C4ConsoleQtViewportDockWidget *dock); + + // QOpenGLWidget functions + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; }; class C4ConsoleQtViewportLabel : public QLabel diff --git a/src/editor/C4ViewportWindow.cpp b/src/editor/C4ViewportWindow.cpp index 10d356d8b..7ef38201e 100644 --- a/src/editor/C4ViewportWindow.cpp +++ b/src/editor/C4ViewportWindow.cpp @@ -162,6 +162,12 @@ bool C4Viewport::ViewPositionByScrollBars() #endif // USE_GTK +#if (defined(USE_SDL_MAINLOOP) && defined(WITH_QT_EDITOR)) +// TODO +bool C4Viewport::ScrollBarsByViewPosition() {return 0;} +bool C4Viewport::TogglePlayerLock() {return 0;} +#endif + void C4ViewportWindow::PerformUpdate() { if (cvp) diff --git a/src/game/C4Viewport.cpp b/src/game/C4Viewport.cpp index d5a7b3b2c..191b479a8 100644 --- a/src/game/C4Viewport.cpp +++ b/src/game/C4Viewport.cpp @@ -66,6 +66,9 @@ bool C4Viewport::UpdateOutputSize(int32_t new_width, int32_t new_height) rect.y = allocation.y; rect.Wdt = allocation.width; rect.Hgt = allocation.height; +#elif defined(WITH_QT_EDITOR) + // Never query the window - size is always passed from Qt. + return false; #else if (!pWindow->GetSize(&rect)) return false; #endif diff --git a/src/graphics/C4DrawGL.cpp b/src/graphics/C4DrawGL.cpp index a75bea8b8..71db13f7f 100644 --- a/src/graphics/C4DrawGL.cpp +++ b/src/graphics/C4DrawGL.cpp @@ -24,7 +24,7 @@ #include #include "C4Rect.h" #include "C4Config.h" -#include +#include #ifndef USE_CONSOLE @@ -288,7 +288,14 @@ CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp) if (!pWindow) return NULL; // create it - CStdGLCtx *pCtx = new CStdGLCtx(); + CStdGLCtx *pCtx; +#ifdef WITH_QT_EDITOR + auto app = dynamic_cast(pApp); + if (app->isEditor) + pCtx = new CStdGLCtxQt(); + else +#endif + pCtx = new CStdGLCtx(); bool first_ctx = !pMainCtx; if (first_ctx) { diff --git a/src/graphics/C4DrawGL.h b/src/graphics/C4DrawGL.h index 26bfd2cac..3d3fffa5d 100644 --- a/src/graphics/C4DrawGL.h +++ b/src/graphics/C4DrawGL.h @@ -105,19 +105,19 @@ class CStdGLCtx { public: CStdGLCtx(); // ctor - ~CStdGLCtx() { Clear(); } // dtor + virtual ~CStdGLCtx() { Clear(); } // dtor - void Clear(bool multisample_change = false); // clear objects + virtual void Clear(bool multisample_change = false); // clear objects #ifdef USE_WGL std::vector EnumerateMultiSamples() const; #endif - bool Init(C4Window * pWindow, C4AbstractApp *pApp); + virtual bool Init(C4Window * pWindow, C4AbstractApp *pApp); - bool Select(bool verbose = false); // select this context - void Deselect(); // select this context + virtual bool Select(bool verbose = false); // select this context + virtual void Deselect(); // select this context - bool PageFlip(); // present scene + virtual bool PageFlip(); // present scene protected: void SelectCommon(); @@ -144,6 +144,26 @@ protected: friend class C4Surface; }; +#ifdef WITH_QT_EDITOR +// OpenGL context with Qt as backend. Implemented as subclass to allow co-existance with a different backend for fullscreen. +class CStdGLCtxQt : public CStdGLCtx +{ +public: + CStdGLCtxQt(); + //~CStdGLCtxQt(); + + void Clear(bool multisample_change = false) override; // clear objects + bool Init(C4Window * pWindow, C4AbstractApp *pApp) override; + bool Select(bool verbose = false) override; // select this context + void Deselect() override; // select this context + bool PageFlip() override; // present scene + +private: + class QOpenGLContext *context = nullptr; + class QOffscreenSurface *surface = nullptr; +}; +#endif + // OpenGL encapsulation class CStdGL : public C4Draw { @@ -272,6 +292,9 @@ protected: friend class C4Window; friend class C4ShaderCall; friend class C4FoWRegion; +#ifdef WITH_QT_EDITOR + friend class CStdGLCtxQt; +#endif }; // Global access pointer diff --git a/src/graphics/C4DrawGLCtx.cpp b/src/graphics/C4DrawGLCtx.cpp index c64711865..4b113d9ec 100644 --- a/src/graphics/C4DrawGLCtx.cpp +++ b/src/graphics/C4DrawGLCtx.cpp @@ -653,4 +653,98 @@ bool CStdGLCtx::PageFlip() #endif //USE_GTK/USE_SDL_MAINLOOP +#ifdef WITH_QT_EDITOR +#undef LineFeed // conflicts with Qt +#include +#include +#include + +CStdGLCtxQt::CStdGLCtxQt() { } + +void CStdGLCtxQt::Clear(bool multisample_change) +{ + pWindow = nullptr; + if (context) + { + delete context; + delete surface; + } +} + +bool CStdGLCtxQt::Init(C4Window *window, C4AbstractApp *app) +{ + if (!pGL) return false; + pWindow = window; + + if (!pWindow->glwidget) + { + surface = new QOffscreenSurface(); + surface->create(); + context = new QOpenGLContext(); + if (!context->create()) + return false; + } + + if (!Select(true)) return false; + + // init extensions + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (GLEW_OK != err) + { + // Problem: glewInit failed, something is seriously wrong. + return pGL->Error(reinterpret_cast(glewGetErrorString(err))); + } + + this_context = contexts.insert(contexts.end(), this); + return true; +} + +bool CStdGLCtxQt::Select(bool verbose) +{ + if (context) + { + if (!context->makeCurrent(surface)) + return false; + } + else + pWindow->glwidget->makeCurrent(); + SelectCommon(); + // update clipper - might have been done by UpdateSize + // however, the wrong size might have been assumed + if (!pGL->UpdateClipper()) + { + if (verbose) pGL->Error(" gl: UpdateClipper failed"); + return false; + } + // success + return true; +} + +void CStdGLCtxQt::Deselect() +{ + if (context) + context->doneCurrent(); + else + pWindow->glwidget->doneCurrent(); + if (pGL && pGL->pCurrCtx == this) + { + pGL->pCurrCtx = 0; + pGL->RenderTarget = 0; + } +} + +bool CStdGLCtxQt::PageFlip() +{ + // flush GL buffer + glFlush(); + if (!pWindow) return false; + if (context) + return false; + pWindow->glwidget->update(); + return true; +} + +#endif + #endif // USE_CONSOLE diff --git a/src/platform/C4Window.h b/src/platform/C4Window.h index 4e58ef54a..7b2ade75d 100644 --- a/src/platform/C4Window.h +++ b/src/platform/C4Window.h @@ -403,6 +403,9 @@ public: #elif defined(USE_GTK) unsigned long renderwnd; #endif +#ifdef WITH_QT_EDITOR + class QOpenGLWidget *glwidget; +#endif protected: #if defined(USE_GTK) bool FindFBConfig(int samples, GLXFBConfig *info); diff --git a/src/platform/C4WindowSDL.cpp b/src/platform/C4WindowSDL.cpp index 66b9cba87..284145029 100644 --- a/src/platform/C4WindowSDL.cpp +++ b/src/platform/C4WindowSDL.cpp @@ -20,7 +20,9 @@ #include #include +#include #include +#include #include #include @@ -42,6 +44,14 @@ C4Window::~C4Window () C4Window * C4Window::Init(WindowKind windowKind, C4AbstractApp * pApp, const char * Title, const C4Rect * size) { +#ifdef WITH_QT_EDITOR + if (windowKind == W_Viewport) + { + // embed into editor: Viewport widget creation handled by C4ConsoleQt + ::Console.AddViewport(static_cast(this)); + return this; + } +#endif /* SDL_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLESAMPLES,*/ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);