Browse code

WIP: Add GLBackendWxWidgets

Robert Cranston authored on 20/10/2021 21:11:33
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,284 @@
1
+/// Guards
2
+
3
+
4
+#ifdef GLBACKEND_WXWIDGETS
5
+
6
+
7
+/// Includes
8
+
9
+
10
+#include <glbackend_wxwidgets.hpp>
11
+
12
+#include <array>
13
+#include <sstream>
14
+#include <string>
15
+#include <utility>
16
+#include <vector>
17
+
18
+#include <glbase.hpp>
19
+#include <glbackend.hpp>
20
+
21
+// #include <wx/wx.h>
22
+#include <wx/app.h>
23
+#include <wx/defs.h>
24
+#include <wx/display.h>
25
+#include <wx/event.h>
26
+#include <wx/frame.h>
27
+#include <wx/glcanvas.h>
28
+#include <wx/init.h>
29
+#include <wx/platinfo.h>
30
+#include <wx/string.h>
31
+#include <wx/tbarbase.h>
32
+#include <wx/toplevel.h>
33
+#include <wx/utils.h>
34
+#include <wx/version.h>
35
+#include <wx/versioninfo.h>
36
+#include <wx/vidmode.h>
37
+#include <wx/window.h>
38
+#include <wx/windowid.h>
39
+
40
+// NOLINTNEXTLINE
41
+#define STR_EXCEPTION GLBase::Exception
42
+#include <str.hpp>
43
+
44
+
45
+
46
+namespace
47
+{
48
+class Canvas : public wxGLCanvas
49
+{
50
+
51
+public:
52
+
53
+    Canvas(
54
+        wxWindow      * parent,
55
+        wxWindowID      id,
56
+        int     const * attribs,
57
+        wxPoint const & pos,
58
+        wxSize  const & size
59
+    )
60
+    :
61
+        wxGLCanvas(parent, id, attribs, pos, size)
62
+    {}
63
+
64
+protected:
65
+
66
+    // TODO(rcrnstn): Implement wxWidgets event handling.
67
+    // void paint_(wxPaintEvent& event);
68
+    // void size_(wxSizeEvent& event);
69
+    // void char_(wxKeyEvent& event);
70
+    // void mouse_event_(wxMouseEvent& event);
71
+    // void exit_(wxCommandEvent& event);
72
+    wxDECLARE_EVENT_TABLE(); // NOLINT
73
+
74
+};
75
+}
76
+
77
+
78
+// TODO(rcrnstn): Implement wxWidgets event handling.
79
+#pragma GCC diagnostic push
80
+#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
81
+wxBEGIN_EVENT_TABLE(Canvas, wxGLCanvas) // NOLINT
82
+//     EVT_PAINT(Canvas::paint_)
83
+wxEND_EVENT_TABLE() // NOLINT
84
+#pragma GCC diagnostic pop
85
+
86
+
87
+GLBackendWxWidgets::GLBackendWxWidgets(
88
+    std::string const & title,
89
+    std::array<int, 2>  size,
90
+    std::array<int, 2>  version,
91
+    int                 samples,
92
+    bool                fullscreen,
93
+    bool                transparent
94
+)
95
+:
96
+    GLBackend(),
97
+    app_       {nullptr},
98
+    frame_     {nullptr},
99
+    canvas_    {nullptr},
100
+    context_   {nullptr},
101
+    event_loop_{},
102
+    time_      {0.0F},
103
+    locked_    {false}
104
+{
105
+    // Backend init
106
+    if (!wxApp::GetInstance())
107
+    {
108
+        wxDISABLE_DEBUG_SUPPORT();
109
+
110
+        wxApp::SetInitializerFunction([]()
111
+        {
112
+            // cppcheck-suppress cstyleCast
113
+            return (wxAppConsole *)new wxApp;
114
+        });
115
+
116
+        auto argc = int{0};
117
+        auto argv = std::array<char *, 1>{{nullptr}};
118
+        if (!wxEntryStart(argc, &argv[0]))
119
+            STR_THROW("Failed to initialize wxWidgets.");
120
+
121
+        app_ = wxApp::GetInstance();
122
+        app_->OnInit();
123
+    }
124
+
125
+    // Window options
126
+    auto frame_style = long{0}; // NOLINT
127
+    frame_style |= wxDEFAULT_FRAME_STYLE; // NOLINT
128
+    frame_style &= ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX); // NOLINT
129
+    frame_style |= wxWANTS_CHARS; // NOLINT
130
+    if (transparent)
131
+    {
132
+        frame_style &= ~wxDEFAULT_FRAME_STYLE; // NOLINT
133
+        frame_style |= wxSTAY_ON_TOP; // NOLINT
134
+    }
135
+    if (size[0] == 0 || size[1] == 0)
136
+    {
137
+        auto const mode = wxDisplay(0).GetCurrentMode();
138
+        size[0] = mode.GetWidth();
139
+        size[1] = mode.GetHeight();
140
+    }
141
+    size_ = size;
142
+
143
+    // Context options
144
+    auto canvas_attribs = std::vector<int>{};
145
+    //NOLINTNEXTLINE
146
+    #define GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_(...) \
147
+        canvas_attribs.insert(canvas_attribs.end(), __VA_ARGS__);
148
+    GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
149
+        WX_GL_RGBA,
150
+        WX_GL_DOUBLEBUFFER,
151
+        WX_GL_MIN_RED, 8,
152
+        WX_GL_MIN_GREEN, 8,
153
+        WX_GL_MIN_BLUE, 8,
154
+        WX_GL_MIN_ALPHA, 8,
155
+        WX_GL_DEPTH_SIZE, 24,
156
+        WX_GL_STENCIL_SIZE, 8,
157
+    })
158
+    if (samples)
159
+        GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
160
+            WX_GL_SAMPLE_BUFFERS, 1,
161
+            WX_GL_SAMPLES, samples,
162
+        })
163
+    if (version[0])
164
+        GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
165
+            WX_GL_MAJOR_VERSION, version[0],
166
+        })
167
+    if (version[1])
168
+        GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
169
+            WX_GL_MINOR_VERSION, version[1],
170
+        })
171
+    if ((version[0] == 3 && version[1] >= 2) || version[0] >= 4) // NOLINT
172
+        GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
173
+            WX_GL_CORE_PROFILE,
174
+        })
175
+    GLBACKEND_WXWIDGETS_CANVAS_ATTRIBS_INSERT_({
176
+        0
177
+    });
178
+
179
+    try
180
+    {
181
+        // Frame
182
+        frame_ = new wxFrame(); // NOLINT
183
+        if (transparent)
184
+            frame_->SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
185
+        frame_->Create(
186
+            nullptr,
187
+            wxID_ANY,
188
+            title,
189
+            wxDefaultPosition,
190
+            wxDefaultSize,
191
+            frame_style
192
+        );
193
+        frame_->SetClientSize(size[0], size[1]);
194
+        if (fullscreen)
195
+            frame_->ShowFullScreen(true);
196
+        else
197
+            frame_->Show(true);
198
+
199
+        // Canvas
200
+        canvas_ = new Canvas{ // NOLINT
201
+            frame_,
202
+            wxID_ANY,
203
+            &canvas_attribs[0],
204
+            wxDefaultPosition,
205
+            {size[0], size[1]},
206
+        };
207
+
208
+        // Context
209
+        context_ = new wxGLContext(canvas_); // NOLINT
210
+        events(); // NOLINT
211
+        context_->SetCurrent(*canvas_);
212
+        init_();
213
+
214
+        // Lock
215
+        if (fullscreen)
216
+            lock(true);
217
+    }
218
+    catch (...)
219
+    {
220
+        destroy_();
221
+        throw;
222
+    }
223
+}
224
+
225
+
226
+GLBackendWxWidgets::~GLBackendWxWidgets()
227
+{
228
+    destroy_();
229
+}
230
+
231
+
232
+std::string GLBackendWxWidgets::debug_info() const
233
+{
234
+    auto ostream = std::ostringstream{};
235
+
236
+    auto version_compiled = wxGetLibraryVersionInfo().GetVersionString();
237
+    auto version_linked   = wxString(wxVERSION_STRING);
238
+    auto os               = wxGetOsDescription();
239
+    auto port             = wxPlatformInfo::Get().GetPortIdName();
240
+    debug_info_(ostream, "wxWidgets", {
241
+        {"VERSION_COMPILED", version_compiled.ToStdString()},
242
+        {"VERSION_LINKED",   version_linked  .ToStdString()},
243
+        {"OS",               os              .ToStdString()},
244
+        {"PORT",             port            .ToStdString()},
245
+    });
246
+
247
+    ostream << GLBackend::debug_info();
248
+
249
+    return ostream.str();
250
+}
251
+
252
+
253
+// TODO(rcrnstn): Implement wxWidgets event handling.
254
+// void GLBackendWxWidgets::paint_(wxPaintEvent& WXUNUSED(event))
255
+// {
256
+//     wxPaintDC paint_dc(this);
257
+//     if (render_)
258
+//         render_();
259
+// }
260
+
261
+
262
+void GLBackendWxWidgets::destroy_()
263
+{
264
+    delete context_;
265
+    if (canvas_)
266
+    {
267
+        lock(false);
268
+        canvas_->Destroy();
269
+    }
270
+    if (frame_)
271
+        frame_->Destroy();
272
+    events(); // NOLINT
273
+    if (app_)
274
+    {
275
+        app_->OnExit();
276
+        wxEntryCleanup();
277
+    }
278
+}
279
+
280
+
281
+/// Guards
282
+
283
+
284
+#endif