スポンサーリンク

Windows 11 + wxWidgets 3.3.1 + VTK 9.5.1

VTK 9.5.1を使おうとしたところ、今までのwxWidgets+VTKのコードで動かなくなっていた。

なんとかWindows+wxWidgetsでVTK9.5.1での表示ができるようになった。

#include <wx/wxprec.h>
#include <wx/glcanvas.h>
#include <wx/frame.h>

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include <GL/gl.h>

#pragma comment(lib, "opengl32.lib")

#include <iostream>

//VTK_MODULE_INITに必要
#include <vtkAutoInit.h>

#include <vtkOutputWindow.h>
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

#include <vtkActor.h>

#include <vtkPolyDataMapper.h>
#include <vtkCylinderSource.h>
#include <vtkInteractorStyleTrackballCamera.h>


#include <vtkWin32OpenGLRenderWindow.h>
#include <vtkWin32RenderWindowInteractor.h>

#include <vtkConeSource.h>


VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);


vtkSmartPointer<vtkActor> CreateCone() {
    vtkSmartPointer<vtkConeSource> coneSource;
    coneSource = vtkSmartPointer<vtkConeSource>::New();
    vtkSmartPointer<vtkPolyDataMapper> mapper;
    mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(coneSource->GetOutputPort());
    vtkSmartPointer<vtkActor> actor;
    actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    return actor;
}

class MyGLCanvas : public wxGLCanvas
{
public:
    MyGLCanvas(wxFrame* parent,int* attribList = NULL);

private:

    wxGLContext* m_context; // OpenGL context
    //////////////////////////////////////////
    vtkNew<vtkWin32OpenGLRenderWindow> _renderWindow;
    vtkNew<vtkWin32RenderWindowInteractor> _interactor;
    vtkNew<vtkRenderer> _renderer;
    //////////////////////////////////////////
    bool vtk_inited = false;
    //////////////////////////////////////////
    // OpenGLコンテキストの作成をしてVTKに貸与する関数
    void InitVTKFromCurrentContext();
    //////////////////////////////////////////
    // マウスイベントを処理
    int last_x_ = 0, last_y_ = 0;
    void OnLeftDown(wxMouseEvent& e);
    void OnLeftUp(wxMouseEvent& e);
    void OnRightDown(wxMouseEvent& e);
    void OnRightUp(wxMouseEvent& e);
    void OnMiddleDown(wxMouseEvent& e);
    void OnMiddleUp(wxMouseEvent& e);
    void OnMotion(wxMouseEvent& e);
    void OnMouseWheel(wxMouseEvent& e);
    //////////////////////////////////////////
    void OnPaint(wxPaintEvent& evt);
};

MyGLCanvas::MyGLCanvas(wxFrame* parent, int* attribList)
    : wxGLCanvas(parent, wxID_ANY, attribList)
{
    Bind(wxEVT_PAINT, &MyGLCanvas::OnPaint, this);

    m_context = new wxGLContext(this);

    SetBackgroundStyle(wxBG_STYLE_CUSTOM);

    Bind(wxEVT_LEFT_DOWN, &MyGLCanvas::OnLeftDown, this);
    Bind(wxEVT_LEFT_UP, &MyGLCanvas::OnLeftUp, this);
    Bind(wxEVT_RIGHT_DOWN, &MyGLCanvas::OnRightDown, this);
    Bind(wxEVT_RIGHT_UP, &MyGLCanvas::OnRightUp, this);
    Bind(wxEVT_MIDDLE_DOWN, &MyGLCanvas::OnMiddleDown, this);
    Bind(wxEVT_MIDDLE_UP, &MyGLCanvas::OnMiddleUp, this);
    Bind(wxEVT_MOTION, &MyGLCanvas::OnMotion, this);
    Bind(wxEVT_MOUSEWHEEL, &MyGLCanvas::OnMouseWheel, this);
}


void MyGLCanvas::OnLeftDown(wxMouseEvent& e) {
    SetFocus();
    CaptureMouse();
    last_x_ = e.GetX(); last_y_ = e.GetY();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::LeftButtonPressEvent);
}

void MyGLCanvas::OnLeftUp(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    ReleaseMouse();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::LeftButtonReleaseEvent);
}

void MyGLCanvas::OnRightDown(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    CaptureMouse();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::RightButtonPressEvent);
}

void MyGLCanvas::OnRightUp(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    ReleaseMouse();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::RightButtonReleaseEvent);
}

void MyGLCanvas::OnMiddleDown(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    CaptureMouse();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::MiddleButtonPressEvent);
}

void MyGLCanvas::OnMiddleUp(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    ReleaseMouse();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent);
}

void MyGLCanvas::OnMotion(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    _interactor->InvokeEvent(vtkCommand::MouseMoveEvent);
}

void MyGLCanvas::OnMouseWheel(wxMouseEvent& e) {
    last_x_ = e.GetX(); last_y_ = e.GetY();
    _interactor->SetEventInformationFlipY(last_x_, last_y_, e.ControlDown(), e.ShiftDown());
    if (e.GetWheelRotation() > 0) _interactor->InvokeEvent(vtkCommand::MouseWheelForwardEvent);
    else                          _interactor->InvokeEvent(vtkCommand::MouseWheelBackwardEvent);
}


void MyGLCanvas::InitVTKFromCurrentContext() {
    // wxのGLを現在化
    wxPaintDC dc(this);

    SetCurrent(*m_context);
    
    // Win32ハンドル取得
    HWND hwnd = this->GetHandle();
    HDC  hdc = dc.GetHDC();
    HGLRC hrc = m_context->GetGLRC();

    // wxWidgetsが作ったコンテキストをVTKへ貸与
    _renderWindow->SetWindowId(hwnd);
    _renderWindow->SetDeviceContext(hdc);
    _renderWindow->SetContextId(hrc);
    _renderWindow->InitializeFromCurrentContext();

    // レンダラの設定
    _renderWindow->AddRenderer(_renderer);
    _interactor->SetRenderWindow(_renderWindow);
    _interactor->Initialize();
    _interactor->Enable();

    // マウスイベントを設定.
    auto style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
    style->SetDefaultRenderer(_renderer);
    _interactor->SetInteractorStyle(style);

    // レンダリング
    _renderer->SetBackground(1.1, 0.2, 0.3);
    _renderer->AddActor(CreateCone());

    vtk_inited = true;
}



void MyGLCanvas::OnPaint(wxPaintEvent& evt)
{
    if (!IsShown()) return;

    if (!vtk_inited) 
        InitVTKFromCurrentContext();

    SetCurrent(*m_context);

    _renderWindow->Render();

}




class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title, int xpos, int ypos, int width, int height);
    ~MyFrame();

    void OnSize(wxSizeEvent& event);

    MyGLCanvas* m_canvas = NULL;
};


MyFrame::MyFrame(const wxString& title, int xpos, int ypos, int width, int height)
    : wxFrame((wxFrame*)NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
    int args[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 };


    m_canvas = new MyGLCanvas(this, args);

    Bind(wxEVT_SIZE, &MyFrame::OnSize, this);

}
void MyFrame::OnSize(wxSizeEvent& event) {
    m_canvas->SetSize(event.GetSize());
}

MyFrame::~MyFrame()
{
    delete m_canvas;
}


class MyApp : public wxApp
{
public:
    bool OnInit();
};


bool MyApp::OnInit()
{
    // VTKのデバッグ出力ウィンドウを表示しない
    vtkOutputWindow::SetGlobalWarningDisplay(0);


    MyFrame* frame = new MyFrame(wxT("wxWidgets OpenGL"), 50, 50, 400, 400);
    frame->Show();

    return true;
}

IMPLEMENT_APP(MyApp)

追記

OnSizeを以下のように記述。

void MyGLCanvas::OnSize(wxSizeEvent& e)
{
    if (!vtk_inited || !IsShownOnScreen())
        return;

    int w = 0, h = 0;
    GetClientSize(&w, &h);

    // HiDPI 対応(MSW の例)
    int pw = w, ph = h;
#ifdef __WXMSW__
    double scale = GetContentScaleFactor();
    pw = static_cast<int>(std::lround(w * scale));
    ph = static_cast<int>(std::lround(h * scale));
#endif


    // 次のペイントで描画
    Refresh(false);

    e.Skip(); // 既定処理も通す

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: