Reputation: 14865
I had it working with QGLWidget
(following this page) in older version of Qt, but I am stuck attempting to update to Qt6.
Additionally, I would like a good integration, to move to QQuickFramebufferObject and QtQuick2.
Attempt 1:
This attempt to create a WNT_Window
(on Windows) by using QWidget
handle. It "seems" to work when I set Qt::WA_PaintOnScreen
, however the standard output shows many messages:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
Removing Qt::WA_PaintOnScreen
, the image blinks like if OCCT was drawing directly on the screen and Qt swapping buffers after.
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
// OCC Viewer
m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_view = m_viewer->CreateView();
// Make this QOpenGLWindow to be the surface for the view
WId windowHandle = (WId)winId();
Handle(Aspect_Window) wind;
#ifdef WIN32
wind = new WNT_Window((Aspect_Handle)windowHandle);
#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
wind = new Cocoa_Window((NSView *)windowHandle);
#else
wind = new Xw_Window(aDisplayConnection, (Window)windowHandle);
#endif
m_view->SetWindow(wind);
if (!wind->IsMapped()) wind->Map();
// OCC Context
m_context = new AIS_InteractiveContext(m_viewer);
Attempt 2:
This strategy creates an Aspect_NeutralWindow
initialized from the QWidget
handle and the current GL context.
This solution is unable to show any OCCT content.
// Create OpenGL graphic driver
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
// OCC Viewer
m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_view = m_viewer->CreateView();
// Aspect rendering context should use the OpenGL context of QOpenGLWidget
Aspect_RenderingContext renderContext = (Aspect_RenderingContext)QOpenGLContext::currentContext()->handle();
Handle(Aspect_Window) wind = new Aspect_NeutralWindow();
m_view->SetWindow(wind, renderContext);
if (!wind->IsMapped()) wind->Map();
// OCC Context
m_context = new AIS_InteractiveContext(m_viewer);
Attempt 3:
This strategy, following this page, attempt to use GL context and build OCCT to use it.
// Create OpenGL graphic driver
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
Handle(OpenGl_Context) oglContext = new OpenGl_Context();
oglContext->Init(QOpenGLContext::currentContext()); //Initialize from currently bound OpenGL context
Handle(OpenGl_FrameBuffer) fbo = new OpenGl_FrameBuffer();
fbo->InitWrapper(oglContext);
oglContext->SetDefaultFrameBuffer(fbo);
// OCC Viewer
m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_view = m_internal->m_viewer->CreateView();
m_view->SetImmediateUpdate(false);
graphicDriver->ChangeOptions().buffersNoSwap = false;
// OCC Context
m_context = new AIS_InteractiveContext(m_viewer);
Again, OCCT is unable to show any content.
Full example:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(VisiTouchPSL LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
find_package(OpenCASCADE REQUIRED)
set(EXEC_NAME TestOcctQt6)
# Find Qt packages
find_package(Qt6 COMPONENTS Widgets OpenGLWidgets REQUIRED)
# Add your source and headers files here
set(HEADERS
occView.h
)
set(SOURCES
occView.cpp
main.cpp
)
# Create executable
add_executable(${EXEC_NAME} ${HEADERS} ${SOURCES})
# Link Qt libraries
target_link_libraries(${EXEC_NAME} PRIVATE Qt6::Widgets Qt6::OpenGLWidgets ${OpenCASCADE_LIBRARIES})
# Include OpenCASCADE headers
target_include_directories(${EXEC_NAME} PRIVATE ${OpenCASCADE_INCLUDE_DIRS})
// main.cpp
// Author ADRIAN MAIRE
// MIT license
#include "occView.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
OcctViewer w;
w.resize(800, 600);
w.show();
return a.exec();
}
//occView.h
// Author ADRIAN MAIRE
// MIT license
#ifndef OCCTVIEWER_H
#define OCCTVIEWER_H
#include <memory>
#include <QOpenGLWidget>
#include <AIS_InteractiveContext.hxx>
#include <Standard_Handle.hxx>
//! Adapted a QWidget for OpenCASCADE viewer.
class OcctViewer : public QOpenGLWidget
{
Q_OBJECT
// Pimpl to not expose OCCL stuff used internally
struct Internal;
public:
explicit OcctViewer(QWidget* parent=nullptr);
~OcctViewer() override;
// Provide access to OCCT context, for building the scene
const Handle(AIS_InteractiveContext)& getContext() const;
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
// Some default content for this example.
void makeTorus();
std::unique_ptr<Internal> m_internal;
public slots:
void rotateScene();
};
#endif
// occView.cpp
// Author ADRIAN MAIRE
// MIT license
#include "occView.h"
#include <QOpenGLContext>
#include <QTimer>
#include <OpenGl_GraphicDriver.hxx>
#include <V3d_View.hxx>
#include <Aspect_Handle.hxx>
#include <Aspect_NeutralWindow.hxx>
#include <Aspect_DisplayConnection.hxx>
#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_Context.hxx>
#include <WNT_Window.hxx>
#include <BRepPrimAPI_MakeTorus.hxx>
#include <AIS_Shape.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <QOpenGLFunctions>
struct OcctViewer::Internal
{
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(AIS_InteractiveContext) m_context;
//For texting/example
Handle(AIS_Shape) m_torusShape;
double m_rotationAngle = 0.0;
QTimer timer;
};
OcctViewer::OcctViewer(QWidget* parent )
: QOpenGLWidget(parent)
, m_internal(std::make_unique<Internal>())
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground); // Avoid many QPainter prints/errors
setAutoFillBackground(false);
setUpdateBehavior(QOpenGLWidget::NoPartialUpdate);
// Setup the rotation of the scene
connect(&m_internal->timer, &QTimer::timeout, this, &OcctViewer::rotateScene);
m_internal->timer.setInterval(500);
m_internal->timer.start();
}
OcctViewer::~OcctViewer() = default;
void OcctViewer::initializeGL()
{
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
//ATTEMPT 3
/*// Create OpenGL graphic driver
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
Handle(OpenGl_Context) oglContext = new OpenGl_Context();
oglContext->Init(QOpenGLContext::currentContext()); //Initialize from currently bound OpenGL context
Handle(OpenGl_FrameBuffer) fbo = new OpenGl_FrameBuffer();
fbo->InitWrapper(oglContext);
oglContext->SetDefaultFrameBuffer(fbo);
// OCC Viewer
m_internal->m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_internal->m_view = m_internal->m_viewer->CreateView();
m_internal->m_view->SetImmediateUpdate(false);
graphicDriver->ChangeOptions().buffersNoSwap = false;*/
// ATTEMPT 2
/*
// Create OpenGL graphic driver
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
// OCC Viewer
m_internal->m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_internal->m_view = m_internal->m_viewer->CreateView();
// Aspect rendering context should use the OpenGL context of QOpenGLWidget
Aspect_RenderingContext renderContext = (Aspect_RenderingContext)QOpenGLContext::currentContext()->handle();
Handle(Aspect_Window) wind = new Aspect_NeutralWindow();
m_internal->m_view->SetWindow(wind, renderContext);
if (!wind->IsMapped()) wind->Map();*/
//ATTEMPT 1
// Create OpenGL graphic driver
/*Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection);
// OCC Viewer
m_internal->m_viewer = new V3d_Viewer(graphicDriver);
// OCC View
m_internal->m_view = m_internal->m_viewer->CreateView();
// Make this QOpenGLWindow to be the surface for the view
WId windowHandle = (WId)winId();
Handle(Aspect_Window) wind;
#ifdef _WIN32
wind = new WNT_Window((Aspect_Handle)windowHandle);
#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
wind = new Cocoa_Window((NSView *)windowHandle);
#else
wind = new Xw_Window(aDisplayConnection, (Window)windowHandle);
#endif
m_internal->m_view->SetWindow(wind);
if (!wind->IsMapped()) wind->Map();*/
// OCC Context
m_internal->m_context = new AIS_InteractiveContext(m_internal->m_viewer);
// Setup the scene
m_internal->m_viewer->SetDefaultLights();
m_internal->m_viewer->SetLightOn();
m_internal->m_context->SetDisplayMode(AIS_Shaded, Standard_True);
// Setup the rendering
m_internal->m_view->SetBackgroundColor(Quantity_NOC_WHITE);
m_internal->m_view->MustBeResized();
m_internal->m_view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_ZBUFFER);
// Create initial content (for the example)
makeTorus();
}
const Handle(AIS_InteractiveContext)& OcctViewer::getContext() const
{
return m_internal->m_context;
}
void OcctViewer::paintGL()
{
if (QOpenGLContext::currentContext() != context()) // avoid QPaint errors.
{
makeCurrent();
}
static bool color = true;
color = ! color;
QOpenGLFunctions *f = context()->functions();
f->glClearColor(0.0f, color?1.0f:0.5f, 0.0f, 0.1f);
if (!m_internal->m_view.IsNull())
{
m_internal->m_view->Redraw();
}
}
void OcctViewer::resizeGL( int w, int h )
{
if( !m_internal->m_view.IsNull() )
{
m_internal->m_view->MustBeResized();
}
}
void OcctViewer::makeTorus()
{
// Create a Torus
gp_Ax2 axis;
axis.SetLocation(gp_Pnt(0.0, 0.0, 0.0));
TopoDS_Shape torus = BRepPrimAPI_MakeTorus(axis, 90.0, 30.0).Shape();
m_internal->m_torusShape = new AIS_Shape(torus);
m_internal->m_torusShape->SetColor(Quantity_NOC_BLUE);
m_internal->m_context->Display(m_internal->m_torusShape, Standard_True);
// Align the view to fit the full window with the torus
m_internal->m_view->FitAll();
m_internal->m_view->ZFitAll();
}
void OcctViewer::rotateScene()
{
if (m_internal->m_torusShape.IsNull())
{
return;
}
m_internal->m_rotationAngle += 0.01; // Adjust this value to change rotation speed
if (m_internal->m_rotationAngle >= 2 * M_PI)
{
m_internal->m_rotationAngle -= 2 * M_PI;
}
gp_Trsf rotation;
rotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), m_internal->m_rotationAngle);
m_internal->m_context->SetLocation(m_internal->m_torusShape, rotation);
// Request a redraw
update();
}
Upvotes: 1
Views: 280