/// Guards #ifdef GLBACKEND_WXWIDGETS /// Includes #include <glbackend_wxwidgets.hpp> #include <array> #include <sstream> #include <string> #include <utility> #include <vector> #include <glbase.hpp> #include <glbackend.hpp> // #include <wx/wx.h> #include <wx/app.h> #include <wx/defs.h> #include <wx/display.h> #include <wx/event.h> #include <wx/frame.h> #include <wx/glcanvas.h> #include <wx/init.h> #include <wx/platinfo.h> #include <wx/string.h> #include <wx/tbarbase.h> #include <wx/toplevel.h> #include <wx/utils.h> #include <wx/version.h> #include <wx/versioninfo.h> #include <wx/vidmode.h> #include <wx/window.h> #include <wx/windowid.h> // NOLINTNEXTLINE #define STR_EXCEPTION GLBase::Exception #include <str.hpp> namespace { class Canvas : public wxGLCanvas { public: Canvas( wxWindow * parent, wxWindowID id, int const * attribs, wxPoint const & pos, wxSize const & size ) : wxGLCanvas(parent, id, attribs, pos, size) {} protected: // TODO(rcrnstn): Implement wxWidgets event handling. // void paint_(wxPaintEvent& event); // void size_(wxSizeEvent& event); // void char_(wxKeyEvent& event); // void mouse_event_(wxMouseEvent& event); // void exit_(wxCommandEvent& event); wxDECLARE_EVENT_TABLE(); // NOLINT }; } // TODO(rcrnstn): Implement wxWidgets event handling. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" wxBEGIN_EVENT_TABLE(Canvas, wxGLCanvas) // NOLINT // EVT_PAINT(Canvas::paint_) wxEND_EVENT_TABLE() // NOLINT #pragma GCC diagnostic pop GLBackendWxWidgets::GLBackendWxWidgets( std::string const & title, std::array<int, 2> size, std::array<int, 2> version, int samples, bool fullscreen, bool transparent ) : GLBackend(), app_ {nullptr}, frame_ {nullptr}, canvas_ {nullptr}, context_ {nullptr}, event_loop_{}, time_ {0.0F}, locked_ {false} { // Backend init if (!wxApp::GetInstance()) { wxDISABLE_DEBUG_SUPPORT(); wxApp::SetInitializerFunction([]() { // cppcheck-suppress cstyleCast return (wxAppConsole *)new wxApp; }); auto argc = int{0}; auto argv = std::array<char *, 1>{{nullptr}}; if (!wxEntryStart(argc, &argv[0])) STR_THROW("Failed to initialize wxWidgets."); app_ = wxApp::GetInstance(); app_->OnInit(); } // Window options auto frame_style = long{0}; // NOLINT frame_style |= wxDEFAULT_FRAME_STYLE; // NOLINT frame_style &= ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX); // NOLINT frame_style |= wxWANTS_CHARS; // NOLINT if (transparent) { frame_style &= ~wxDEFAULT_FRAME_STYLE; // NOLINT frame_style |= wxSTAY_ON_TOP; // NOLINT } if (size[0] == 0 || size[1] == 0) { auto const mode = wxDisplay(0).GetCurrentMode(); size[0] = mode.GetWidth(); size[1] = mode.GetHeight(); } size_ = size; // Context options auto canvas_attribs = std::vector<int>{}; //NOLINTNEXTLINE #define GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_(...) \ canvas_attribs.insert(canvas_attribs.end(), __VA_ARGS__); GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_MIN_RED, 8, WX_GL_MIN_GREEN, 8, WX_GL_MIN_BLUE, 8, WX_GL_MIN_ALPHA, 8, WX_GL_DEPTH_SIZE, 24, WX_GL_STENCIL_SIZE, 8, }) if (samples) GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ WX_GL_SAMPLE_BUFFERS, 1, WX_GL_SAMPLES, samples, }) if (version[0]) GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ WX_GL_MAJOR_VERSION, version[0], }) if (version[1]) GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ WX_GL_MINOR_VERSION, version[1], }) if ((version[0] == 3 && version[1] >= 2) || version[0] >= 4) // NOLINT GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ WX_GL_CORE_PROFILE, }) GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({ 0 }); try { // Frame frame_ = new wxFrame(); // NOLINT if (transparent) frame_->SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); frame_->Create( nullptr, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, frame_style ); frame_->SetClientSize(size[0], size[1]); if (fullscreen) frame_->ShowFullScreen(true); else frame_->Show(true); // Canvas canvas_ = new Canvas{ // NOLINT frame_, wxID_ANY, &canvas_attribs[0], wxDefaultPosition, {size[0], size[1]}, }; // Context context_ = new wxGLContext(canvas_); // NOLINT events(); // NOLINT context_->SetCurrent(*canvas_); init_(); // Lock if (fullscreen) lock(true); } catch (...) { destroy_(); throw; } } GLBackendWxWidgets::~GLBackendWxWidgets() { destroy_(); } std::string GLBackendWxWidgets::debug_info() const { auto ostream = std::ostringstream{}; auto version_compiled = wxGetLibraryVersionInfo().GetVersionString(); auto version_linked = wxString(wxVERSION_STRING); auto os = wxGetOsDescription(); auto port = wxPlatformInfo::Get().GetPortIdName(); debug_info_(ostream, "wxWidgets", { {"VERSION_COMPILED", version_compiled.ToStdString()}, {"VERSION_LINKED", version_linked .ToStdString()}, {"OS", os .ToStdString()}, {"PORT", port .ToStdString()}, }); ostream << GLBackend::debug_info(); return ostream.str(); } // TODO(rcrnstn): Implement wxWidgets event handling. // void GLBackendWxWidgets::paint_(wxPaintEvent& WXUNUSED(event)) // { // wxPaintDC paint_dc(this); // if (render_) // render_(); // } void GLBackendWxWidgets::destroy_() { delete context_; if (canvas_) { lock(false); canvas_->Destroy(); } if (frame_) frame_->Destroy(); events(); // NOLINT if (app_) { app_->OnExit(); wxEntryCleanup(); } } /// Guards #endif