Browse code

WIP: Add GLBackendSDL

Robert Cranston authored on 12/10/2021 04:12:23
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,304 @@
1
+/// Guards
2
+
3
+
4
+#ifdef GLBACKEND_SDL
5
+
6
+
7
+/// Includes
8
+
9
+
10
+#include <glbackend_sdl.hpp>
11
+
12
+#include <functional>
13
+#include <sstream>
14
+#include <string>
15
+#include <type_traits>
16
+#include <utility>
17
+
18
+#include <glbase.hpp>
19
+#include <glbackend.hpp>
20
+
21
+#include <SDL2/SDL.h>
22
+#include <SDL2/SDL_error.h>
23
+#include <SDL2/SDL_events.h>
24
+#include <SDL2/SDL_keycode.h>
25
+#include <SDL2/SDL_version.h>
26
+
27
+// NOLINTNEXTLINE
28
+#define STR_EXCEPTION GLBase::Exception
29
+#include <str.hpp>
30
+
31
+
32
+/// Constants
33
+
34
+
35
+auto static constexpr sdl_subsystems_ =
36
+    SDL_INIT_VIDEO  |
37
+    SDL_INIT_EVENTS |
38
+    SDL_INIT_TIMER;
39
+
40
+
41
+/// Special member functions
42
+
43
+
44
+GLBackendSDL::GLBackendSDL(
45
+    std::string const & title,
46
+    std::array<int, 2>  size,
47
+    std::array<int, 2>  version,
48
+    int                 samples,
49
+    bool                fullscreen,
50
+    bool                transparent
51
+)
52
+:
53
+    GLBackend(),
54
+    window_ {nullptr},
55
+    context_{nullptr},
56
+    running_{true},
57
+    time_   {0.0F}
58
+{
59
+    // Backend init
60
+    if (SDL_InitSubSystem(sdl_subsystems_) != 0)
61
+        STR_THROW(
62
+            "Failed to initialize SDL" << ":\n" <<
63
+            SDL_GetError()
64
+        );
65
+
66
+    // Window options
67
+    SDL_GL_ResetAttributes();
68
+    auto window_flags = Uint32{0};
69
+    window_flags |= SDL_WINDOW_OPENGL;
70
+    if (fullscreen)
71
+        window_flags |= SDL_WINDOW_FULLSCREEN;
72
+    if (transparent)
73
+    {
74
+        window_flags |= SDL_WINDOW_BORDERLESS;
75
+        window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
76
+    }
77
+    if (size[0] == 0 || size[1] == 0)
78
+    {
79
+        auto mode = SDL_DisplayMode{};
80
+        SDL_GetCurrentDisplayMode(0, &mode);
81
+        size[0] = mode.w;
82
+        size[1] = mode.h;
83
+    }
84
+    size_ = size;
85
+
86
+    // Context options
87
+    auto context_flags = int{0};
88
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, SDL_TRUE);
89
+    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,      8); // NOLINT
90
+    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,    8); // NOLINT
91
+    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,     8); // NOLINT
92
+    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,    8); // NOLINT
93
+    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,   24); // NOLINT
94
+    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,  8); // NOLINT
95
+    if (samples)
96
+    {
97
+        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
98
+        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
99
+    }
100
+    if (version[0])
101
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, version[0]);
102
+    if (version[1])
103
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, version[1]);
104
+    if ((version[0] == 3 && version[1] >= 2) || version[0] >= 4) // NOLINT
105
+    {
106
+        SDL_GL_SetAttribute(
107
+            SDL_GL_CONTEXT_PROFILE_MASK,
108
+            SDL_GL_CONTEXT_PROFILE_CORE
109
+        );
110
+        context_flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; // NOLINT
111
+    }
112
+    if (debug() >= 1)
113
+        context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; // NOLINT
114
+    else if ((version[0] == 4 && version[1] >= 6) || version[0] >= 5) // NOLINT
115
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_NO_ERROR, SDL_TRUE);
116
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags);
117
+
118
+    try
119
+    {
120
+        // Window
121
+        window_ = SDL_CreateWindow(
122
+            title.c_str(),
123
+            SDL_WINDOWPOS_UNDEFINED, // NOLINT
124
+            SDL_WINDOWPOS_UNDEFINED, // NOLINT
125
+            size[0],
126
+            size[1],
127
+            window_flags
128
+        );
129
+        if (!window_)
130
+            STR_THROW(
131
+                "Failed to create SDL window" << ":\n" <<
132
+                SDL_GetError()
133
+            );
134
+
135
+        // Context
136
+        context_ = SDL_GL_CreateContext(window_);
137
+        if (!context_)
138
+            STR_THROW(
139
+                "Failed to create SDL context" << ":\n" <<
140
+                SDL_GetError()
141
+            );
142
+        SDL_GL_MakeCurrent(window_, context_);
143
+        if (debug() == 0)
144
+            SDL_GL_SetSwapInterval(1);
145
+        init_();
146
+
147
+        // Lock
148
+        if (fullscreen)
149
+            GLBackendSDL::lock(true);
150
+    }
151
+    catch (...)
152
+    {
153
+        destroy_();
154
+        throw;
155
+    }
156
+}
157
+
158
+
159
+GLBackendSDL::~GLBackendSDL()
160
+{
161
+    destroy_();
162
+}
163
+
164
+
165
+GLBackendSDL::GLBackendSDL(GLBackendSDL && other) noexcept
166
+:
167
+    GLBackend(std::move(other)),
168
+    window_ {other.window_},
169
+    context_{other.context_},
170
+    running_{other.running_},
171
+    time_   {other.time_}
172
+{
173
+    other.window_  = nullptr;
174
+    other.context_ = nullptr;
175
+}
176
+
177
+
178
+void GLBackendSDL::destroy_()
179
+{
180
+    GLBackendSDL::lock(false);
181
+    if (context_)
182
+        SDL_GL_DeleteContext(context_);
183
+    if (window_)
184
+        SDL_DestroyWindow(window_);
185
+    SDL_QuitSubSystem(sdl_subsystems_);
186
+}
187
+
188
+
189
+/// Render loop
190
+
191
+
192
+inline void GLBackendSDL::events()
193
+{
194
+    auto event = SDL_Event{};
195
+    while (SDL_PollEvent(&event))
196
+    {
197
+        switch (event.type)
198
+        {
199
+            case SDL_KEYDOWN:
200
+                if (event.key.repeat)
201
+                    break;
202
+                if (callback_key_)
203
+                {
204
+                    auto key = event.key.keysym.sym;
205
+                    if (key == SDLK_RETURN)
206
+                        callback_key_("Enter");
207
+                    else if (key == SDLK_LCTRL  || key == SDLK_RCTRL)
208
+                        callback_key_("Control");
209
+                    else if (key == SDLK_LSHIFT || key == SDLK_RSHIFT)
210
+                        callback_key_("Shift");
211
+                    else if (key == SDLK_LALT   || key == SDLK_RALT)
212
+                        callback_key_("Alt");
213
+                    else
214
+                        callback_key_(SDL_GetKeyName(key));
215
+                }
216
+                break;
217
+            case SDL_MOUSEBUTTONDOWN:
218
+                if (callback_button_)
219
+                    callback_button_(event.button.button);
220
+                break;
221
+            case SDL_MOUSEWHEEL:
222
+                scroll_ = {
223
+                    (float)event.wheel.x,
224
+                    (float)event.wheel.y,
225
+                };
226
+                if (callback_scroll_)
227
+                    callback_scroll_(scroll_);
228
+                break;
229
+            case SDL_MOUSEMOTION:
230
+                position_ = {
231
+                    (float)event.motion.x,
232
+                    (float)event.motion.y,
233
+                };
234
+                move_ = {
235
+                    (float)event.motion.xrel,
236
+                    (float)event.motion.yrel,
237
+                };
238
+                if (callback_position_)
239
+                    callback_position_(position_);
240
+                if (callback_move_)
241
+                    callback_move_(move_);
242
+                break;
243
+            case SDL_WINDOWEVENT:
244
+                switch (event.window.event)
245
+                {
246
+                    case SDL_WINDOWEVENT_SIZE_CHANGED:
247
+                        // size_ = {
248
+                        //     event.window.data1,
249
+                        //     event.window.data2,
250
+                        // };
251
+                        SDL_GL_GetDrawableSize(
252
+                            window_,
253
+                            &size_[0],
254
+                            &size_[1]
255
+                        );
256
+                        if (callback_size_)
257
+                            callback_size_(size_);
258
+                        break;
259
+                    case SDL_WINDOWEVENT_CLOSE:
260
+                            running_ = false;
261
+                        break;
262
+                }
263
+                break;
264
+        }
265
+    }
266
+}
267
+
268
+
269
+/// Debug
270
+
271
+
272
+std::string GLBackendSDL::debug_info() const
273
+{
274
+    auto ostream = std::ostringstream{};
275
+
276
+    auto version_compiled = SDL_version{};
277
+    auto version_linked   = SDL_version{};
278
+    SDL_VERSION(&version_compiled);
279
+    SDL_GetVersion(&version_linked);
280
+    debug_info_(ostream, "SDL", {
281
+        {
282
+            "VERSION_COMPILED",
283
+                std::to_string(version_compiled.major) + "." +
284
+                std::to_string(version_compiled.minor) + "." +
285
+                std::to_string(version_compiled.patch),
286
+        },
287
+        {
288
+            "VERSION_LINKED",
289
+                std::to_string(version_linked.major) + "." +
290
+                std::to_string(version_linked.minor) + "." +
291
+                std::to_string(version_linked.patch),
292
+        },
293
+    });
294
+
295
+    ostream << GLBackend::debug_info();
296
+
297
+    return ostream.str();
298
+}
299
+
300
+
301
+/// Guards
302
+
303
+
304
+#endif