diff --git a/CMakeLists.txt b/CMakeLists.txt index 3007cc69c6..7799627034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1018,9 +1018,9 @@ endif() OCCT_MODULES_AND_TOOLKITS (SAMPLES "SAMPLES_TOOLKITS" OCCT_SAMPLES) if (BUILD_MODULE_QtSamples) - if (NOT Qt5_FOUND OR NOT USE_GLES2) + if (NOT Qt5_FOUND OR NOT WIN32) list (REMOVE_ITEM qt_SAMPLES_TOOLKITS AndroidQt) - message (STATUS "Info: AndroidQt sample excluded due to Qt5 or GLES2 usage are disabled") + message (STATUS "Info: AndroidQt sample excluded due to Qt5 usage is disabled or OS is not Windows") endif() if (NOT BUILD_Inspector) diff --git a/adm/cmake/qt.cmake b/adm/cmake/qt.cmake index 922177b8b6..2eacf8f093 100644 --- a/adm/cmake/qt.cmake +++ b/adm/cmake/qt.cmake @@ -18,3 +18,19 @@ UNSET (${3RDPARTY_QT_LIBRARY_DIR} CACHE) set (USED_3RDPARTY_QT_DIR "${3RDPARTY_QT_DIR}") message (STATUS "Info: Qt is used from folder: ${3RDPARTY_QT_DIR}") + +# Now set CMAKE_PREFIX_PATH to point to local Qt installation. +# Without this setting find_package() will not work +set(CMAKE_PREFIX_PATH ${3RDPARTY_QT_DIR}) + +# Now we can apply standard CMake finder for Qt5. We do this mostly +# to have qt5_wrap_cpp() function available and Qt5_FOUND variable filled +find_package(Qt5 QUIET COMPONENTS Widgets Quick PATHS ${3RDPARTY_QT_DIR} NO_DEFAULT_PATH) +if (NOT ${Qt5_FOUND}) + # Now we can apply standard CMake finder for Qt. We do this mostly + # to have qt4_wrap_cpp() function available + find_package(Qt4) + #message (STATUS "Qt4 cmake configuration") +else() + #message (STATUS "Qt5 cmake configuration") +endif() diff --git a/adm/cmake/qt_macro.cmake b/adm/cmake/qt_macro.cmake index c535772c2e..7870d60e7c 100644 --- a/adm/cmake/qt_macro.cmake +++ b/adm/cmake/qt_macro.cmake @@ -6,13 +6,6 @@ macro (FIND_QT_PACKAGE PROJECT_LIBRARIES_DEBUG PROJECT_LIBRARIES_RELEASE PROJECT message (FATAL_ERROR "Empty Qt dir") endif() - # Now set CMAKE_PREFIX_PATH to point to local Qt installation. - # Without this setting find_package() will not work - set(CMAKE_PREFIX_PATH ${3RDPARTY_QT_DIR}) - - # Now we can apply standard CMake finder for Qt5. We do this mostly - # to have qt5_wrap_cpp() function available - find_package(Qt5 QUIET COMPONENTS Widgets Quick PATHS ${3RDPARTY_QT_DIR} NO_DEFAULT_PATH) if (${Qt5_FOUND}) #message (STATUS "Qt5 cmake configuration") @@ -28,10 +21,6 @@ macro (FIND_QT_PACKAGE PROJECT_LIBRARIES_DEBUG PROJECT_LIBRARIES_RELEASE PROJECT GET_FILENAME_COMPONENT(QT_BINARY_DIR ${QT_LRELEASE_EXECUTABLE} DIRECTORY) MARK_AS_ADVANCED(QT_BINARY_DIR) else() - # Now we can apply standard CMake finder for Qt. We do this mostly - # to have qt4_wrap_cpp() function available - find_package(Qt4) - #message (STATUS "Qt4 cmake configuration") set(PROJECT_INCLUDES ${QT_INCLUDES}) if (WIN32) diff --git a/adm/templates/sample.bat b/adm/templates/sample.bat index 023346648d..e7446dda3f 100644 --- a/adm/templates/sample.bat +++ b/adm/templates/sample.bat @@ -25,6 +25,7 @@ if ["%1"] == [""] ( ) call "%~dp0env.bat" %2 %3 %4 +if not ["%QTDIR%"] == [""] if exist "%QTDIR%\qml" if ["%QML2_IMPORT_PATH%"] == [""] set "QML2_IMPORT_PATH=%QTDIR%/qml" set "EXE_PATH=%CSF_OCCTBinPath%/%1.exe" if not exist "%EXE_PATH%" ( diff --git a/samples/qt/AndroidQt/res/qml/main.qml b/samples/qt/AndroidQt/res/qml/main.qml index 2566fb29cd..f933cccdac 100644 --- a/samples/qt/AndroidQt/res/qml/main.qml +++ b/samples/qt/AndroidQt/res/qml/main.qml @@ -28,6 +28,9 @@ Window { id: root_window visible: true + width: (Qt.platform.os == "android" || Qt.platform.os == "ios") ? Screen.width : 600 + height: (Qt.platform.os == "android" || Qt.platform.os == "ios") ? Screen.height : 400 + Item { id: root_item anchors.fill: parent @@ -52,8 +55,8 @@ Window { anchors.left: parent.left // size - width: 200 - height: 200 + width: (Qt.platform.os == "android" || Qt.platform.os == "ios") ? 200 : 150 + height: (Qt.platform.os == "android" || Qt.platform.os == "ios") ? 200 : 150 color: "white" diff --git a/samples/qt/AndroidQt/src/AndroidQt.cxx b/samples/qt/AndroidQt/src/AndroidQt.cxx index 70026c13ca..54a339c37b 100644 --- a/samples/qt/AndroidQt/src/AndroidQt.cxx +++ b/samples/qt/AndroidQt/src/AndroidQt.cxx @@ -11,13 +11,19 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#include -#include -#include +#if defined(_WIN32) + #include +#endif + +#include "AndroidQt.h" +#include "AndroidQt_UserInteractionParameters.h" +#include "AndroidQt_Window.h" #include #include #include +#include +#include #include #include #include @@ -25,6 +31,7 @@ #include #include #include +#include #include #include @@ -36,7 +43,7 @@ AndroidQt::AndroidQt() : myFitAllAction (false) { - connect (this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*))); + connect (this, SIGNAL (windowChanged (QQuickWindow*)), this, SLOT (handleWindowChanged (QQuickWindow*))); // set shaders location variable QByteArray aDataRoot = "/data/data/org.qtproject.example.AndroidQt/files/opencascade/shared"; @@ -138,7 +145,7 @@ void AndroidQt::handleWindowChanged (QQuickWindow* theWin) return; } - connect(theWin, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection); + connect (theWin, SIGNAL (beforeSynchronizing()), this, SLOT (sync()), Qt::DirectConnection); theWin->setClearBeforeRendering (false); } @@ -151,28 +158,54 @@ void AndroidQt::sync() { myViewportSize = window()->size() * window()->devicePixelRatio(); + Graphic3d_Vec2i aWinTopLeft (window()->x(), window()->y()); + Graphic3d_Vec2i aWinSize (myViewportSize.width(), myViewportSize.height()); + const bool isChangedLeft = (myWinTopLeft.x() != aWinTopLeft.x()); + const bool isChangedTop = (myWinTopLeft.y() != aWinTopLeft.y()); + myWinTopLeft = aWinTopLeft; + if (myViewer.IsNull()) { - initViewer(); - connect (window(), SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection); + initViewer (Aspect_Drawable (window()->winId())); + connect (window(), SIGNAL (beforeRendering()), this, SLOT (paint()), Qt::DirectConnection); } else { Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver()); + #ifdef __ANDROID__ if (aDriver->getRawGlContext() != eglGetCurrentContext()) { - initViewer(); + initViewer (Aspect_Drawable (window()->winId())); } else + #endif { - Handle(AndroidQt_Window) aWindow = Handle(AndroidQt_Window)::DownCast (myView->Window()); + #ifdef __ANDROID__ + Handle(AndroidQt_Window) aWindow = Handle(AndroidQt_Window)::DownCast(myView->Window()); aWindow->SetSize (myViewportSize.width(), myViewportSize.height()); //myView->MustBeResized(); // can be used instead of SetWindow() when EGLsurface has not been changed EGLContext anEglContext = eglGetCurrentContext(); myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext); + #else + if (aWinSize.x() != myWinSize.x() + || aWinSize.y() != myWinSize.y()) + { + myView->MustBeResized(); + myView->Invalidate(); + } + else if (isChangedTop) + { + myView->MustBeResized(); + } + else if (isChangedLeft) + { + myView->MustBeResized(); + } + #endif } } + myWinSize = aWinSize; } // ======================================================================= @@ -183,7 +216,7 @@ void AndroidQt::paint() { myMutex.lock(); - if (Abs(myTouchPoint.DevX()) + Abs(myTouchPoint.DevY()) > 1) + if (Abs (myTouchPoint.DevX()) + Abs (myTouchPoint.DevY()) > 1) { myView->StartRotation (myTouchPoint.X().first, myTouchPoint.Y().first); myView->Rotation (myTouchPoint.X().second, myTouchPoint.Y().second); @@ -206,10 +239,12 @@ void AndroidQt::paint() // function : initViewer // purpose : // ======================================================================= -bool AndroidQt::initViewer() +bool AndroidQt::initViewer (Aspect_Drawable theWin) { - EGLint aCfgId = 0; int aWidth = 0, aHeight = 0; + Handle(Aspect_DisplayConnection) aDisplayConnection; +#ifdef __ANDROID__ + EGLint aCfgId = 0; EGLDisplay anEglDisplay = eglGetCurrentDisplay(); EGLContext anEglContext = eglGetCurrentContext(); EGLSurface anEglSurf = eglGetCurrentSurface (EGL_DRAW); @@ -232,6 +267,7 @@ bool AndroidQt::initViewer() if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE) { + Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations", Message_Fail); release(); return false; } @@ -242,6 +278,7 @@ bool AndroidQt::initViewer() Handle(AndroidQt_Window) aWindow = Handle(AndroidQt_Window)::DownCast (myView->Window()); if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig)) { + Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized", Message_Fail); release(); return false; } @@ -251,15 +288,46 @@ bool AndroidQt::initViewer() } Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (NULL, Standard_False); - aDriver->ChangeOptions().buffersNoSwap = Standard_True; - //aDriver->ChangeOptions().glslWarnings = Standard_True; // for GLSL shaders debug - - if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig)) +#elif defined(_WIN32) + HWND aWinHandle = (HWND)theWin; + HDC aWindowDC = wglGetCurrentDC(); + HGLRC aRendCtx = wglGetCurrentContext(); + if (aWinHandle == NULL + || aWindowDC == NULL + || aRendCtx == NULL) { + Message::DefaultMessenger()->Send ("Error: No active WGL context!", Message_Fail); release(); return false; } + RECT aRect; + ::GetClientRect (aWinHandle, &aRect); + aWidth = aRect.right - aRect.left; + aHeight = aRect.bottom - aRect.top; + myWinSize.x() = aWidth; + myWinSize.y() = aHeight; + if (!myViewer.IsNull()) + { + Handle(WNT_Window) aWindow = new WNT_Window (aWinHandle); + myView->SetWindow (aWindow, (Aspect_RenderingContext)aRendCtx); + return true; + } + Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisplayConnection, Standard_False); +#endif + + aDriver->ChangeOptions().buffersNoSwap = Standard_True; + //aDriver->ChangeOptions().glslWarnings = Standard_True; // for GLSL shaders debug + +#ifdef __ANDROID__ + if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig)) + { + Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized", Message_Fail); + release(); + return false; + } +#endif + // create viewer myViewer = new V3d_Viewer (aDriver); myViewer->SetDefaultBackgroundColor (AndroidQt_UserInteractionParameters::BgColor.Name()); @@ -270,10 +338,20 @@ bool AndroidQt::initViewer() myContext = new AIS_InteractiveContext (myViewer); myContext->SetDisplayMode (AIS_Shaded, false); +#ifdef __ANDROID__ Handle(AndroidQt_Window) aWindow = new AndroidQt_Window (aWidth, aHeight); - myView = myViewer->CreateView(); +#elif defined(_WIN32) + Handle(WNT_Window) aWindow = new WNT_Window (aWinHandle); +#endif + myView = myViewer->CreateView(); + myView->SetImmediateUpdate (Standard_False); + +#ifdef __ANDROID__ myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext); +#else + myView->SetWindow (aWindow, (Aspect_RenderingContext )aRendCtx); +#endif myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08, V3d_ZBUFFER); return true; diff --git a/samples/qt/AndroidQt/src/AndroidQt.h b/samples/qt/AndroidQt/src/AndroidQt.h index 9bc0e57b78..0e5462e0c8 100644 --- a/samples/qt/AndroidQt/src/AndroidQt.h +++ b/samples/qt/AndroidQt/src/AndroidQt.h @@ -29,7 +29,7 @@ #include -#include +#include "AndroidQt_TouchParameters.h" //! QML item with embedded OCCT viewer. class AndroidQt : public QQuickItem @@ -67,7 +67,8 @@ private slots: private: //! (Re-)initialize viewer on OpenGL context change. - bool initViewer(); + //! \param theWin handle to GUI window + bool initViewer (Aspect_Drawable theWin); //! Close viewer void release(); @@ -77,6 +78,8 @@ private: Handle(V3d_Viewer) myViewer; //!< 3D viewer Handle(V3d_View) myView; //!< 3D view Handle(AIS_InteractiveContext) myContext; //!< interactive context + Graphic3d_Vec2i myWinTopLeft; //!< cached window position (top-left) + Graphic3d_Vec2i myWinSize; //!< cached window width-height QMutex myMutex; //!< mutex for interconnection with rendering thread QSize myViewportSize; //!< QML item size diff --git a/samples/qt/AndroidQt/src/AndroidQt_TouchParameters.cxx b/samples/qt/AndroidQt/src/AndroidQt_TouchParameters.cxx index c844e26175..4e8cd0e4af 100644 --- a/samples/qt/AndroidQt/src/AndroidQt_TouchParameters.cxx +++ b/samples/qt/AndroidQt/src/AndroidQt_TouchParameters.cxx @@ -11,7 +11,7 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#include +#include "AndroidQt_TouchParameters.h" // ======================================================================= // function : AndroidQt_TouchParameters diff --git a/samples/qt/AndroidQt/src/AndroidQt_Window.cxx b/samples/qt/AndroidQt/src/AndroidQt_Window.cxx index 024b74dc75..9dc603a552 100644 --- a/samples/qt/AndroidQt/src/AndroidQt_Window.cxx +++ b/samples/qt/AndroidQt/src/AndroidQt_Window.cxx @@ -11,7 +11,7 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#include +#include "AndroidQt_Window.h" IMPLEMENT_STANDARD_RTTIEXT(AndroidQt_Window, Aspect_Window) diff --git a/samples/qt/AndroidQt/src/Main.cxx b/samples/qt/AndroidQt/src/Main.cxx index dca2797359..51ae7c1a06 100644 --- a/samples/qt/AndroidQt/src/Main.cxx +++ b/samples/qt/AndroidQt/src/Main.cxx @@ -14,10 +14,18 @@ #include #include -#include +#include "AndroidQt.h" + +#include int main(int argc, char *argv[]) { +#if defined(_WIN32) && (QT_VERSION > 0x050000) + TCollection_AsciiString aPlugindsDirName = OSD_Environment ("QTDIR").Value(); + if (!aPlugindsDirName.IsEmpty()) + QApplication::addLibraryPath (QString (aPlugindsDirName.ToCString()) + "/plugins"); +#endif + QApplication app(argc, argv); qmlRegisterType("AndroidQt", 1, 0, "AndroidQt");