Browse code

Add GLBackend, GLBackendDefault

Robert Cranston authored on 12/10/2021 00:02:06
Showing 1 changed files
... ...
@@ -0,0 +1,308 @@
1
+/// Includes
2
+
3
+
4
+#include <glbackend.hpp>
5
+
6
+#include <algorithm>
7
+#include <cstddef>
8
+#include <exception>
9
+#include <iomanip>
10
+#include <regex>
11
+#include <sstream>
12
+#include <string>
13
+
14
+#include <glbase.hpp>
15
+
16
+// NOLINTNEXTLINE
17
+#define STR_EXCEPTION GLBase::Exception
18
+#include <str.hpp>
19
+
20
+
21
+/// Special member functions
22
+
23
+
24
+GLBackend::GLBackend()
25
+:
26
+    callback_update_{},
27
+    callback_render_{},
28
+    scroll_{},
29
+    position_{},
30
+    move_{},
31
+    size_{},
32
+    callback_key_{},
33
+    callback_button_{},
34
+    callback_scroll_{},
35
+    callback_position_{},
36
+    callback_move_{},
37
+    callback_size_{}
38
+{
39
+}
40
+
41
+
42
+void GLBackend::init_()
43
+{
44
+    #ifdef __GLEW_H__
45
+    if (auto error = glewInit())
46
+        STR_THROW(
47
+            "Failed to initialize GLEW:" << "\n" <<
48
+            glewGetErrorString(error)
49
+        );
50
+    #endif
51
+
52
+    if (debug() >= 1)
53
+    {
54
+        if (supported({4, 3}, "GL_KHR_debug"))
55
+        {
56
+            glEnable(GL_DEBUG_OUTPUT);
57
+            glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
58
+            glDebugMessageControl(
59
+                GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE,
60
+                0, nullptr,
61
+                GL_TRUE
62
+            );
63
+            glDebugMessageControl(
64
+                GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
65
+                0, nullptr,
66
+                GL_FALSE
67
+            );
68
+            glDebugMessageCallback(debug_gl_message_callback_, nullptr);
69
+        }
70
+    }
71
+}
72
+
73
+
74
+/// Render loop
75
+
76
+
77
+void GLBackend::run(float dt_fixed)
78
+{
79
+    auto t = time(0);
80
+    running(true);
81
+    while (events(), running())
82
+    {
83
+        if (callback_update_)
84
+        {
85
+            auto t_next = time();
86
+            auto dt = t_next - t;
87
+            if (dt_fixed != 0.0F)
88
+                dt = dt_fixed;
89
+            while (t + dt <= t_next)
90
+            {
91
+                callback_update_(t, dt, !(t + 2 * dt <= t_next));
92
+                t += dt;
93
+            }
94
+        }
95
+        if (callback_render_)
96
+            callback_render_();
97
+        swap();
98
+    }
99
+}
100
+
101
+
102
+/// Path
103
+
104
+
105
+GLBASE_GLOBAL(GLBackend::prefix_, {})
106
+
107
+
108
+/// TGA
109
+
110
+
111
+void GLBackend::tga_write(
112
+    Path const & path
113
+) const
114
+{
115
+    tga_().write(path_prefix_(path, prefix()));
116
+}
117
+
118
+
119
+bool GLBackend::tga_compare(
120
+    Path const & path,
121
+    bool         write_on_failed_read
122
+) const
123
+{
124
+    auto path_prefix = path_prefix_(path, prefix());
125
+    auto tga = tga_();
126
+    try
127
+    {
128
+        auto tga_read = TGA_::read(path_prefix);
129
+        return tga_read.data() == tga.data();
130
+    }
131
+    catch (std::exception const & exception)
132
+    {
133
+        if (!write_on_failed_read)
134
+            throw;
135
+        if (debug() >= 1)
136
+            debug_callback()(exception.what());
137
+        debug_callback()(STR("Writing TGA \"" << path_prefix << "\"."));
138
+        tga.write(path_prefix);
139
+        return false;
140
+    }
141
+}
142
+
143
+
144
+GLBackend::TGA_ GLBackend::tga_() const
145
+{
146
+    glFlush();
147
+    auto size = this->size();
148
+    auto data = std::vector<GLubyte>((4 * (size_t)size[0] * (size_t)size[1]));
149
+    glPixelStorei(GL_PACK_ALIGNMENT, 4);
150
+    glReadPixels(
151
+        0, 0,
152
+        size[0], size[1],
153
+        GL_BGRA, GL_UNSIGNED_BYTE,
154
+        data.data()
155
+    );
156
+    return TGA_(size, std::move(data));
157
+}
158
+
159
+
160
+/// Debug
161
+
162
+
163
+std::string GLBackend::debug_info() const
164
+{
165
+    auto ostream = std::ostringstream{};
166
+
167
+    #ifdef __GLEW_H__
168
+    // NOLINTNEXTLINE
169
+    #define GLBACKEND_INFO_GLEW_(NAME) \
170
+        {#NAME, (char const *)glewGetString(GLEW_##NAME)}
171
+    debug_info_(ostream, "GLEW", {
172
+        GLBACKEND_INFO_GLEW_(VERSION),
173
+    });
174
+    #endif
175
+
176
+    // NOLINTNEXTLINE
177
+    #define GLBACKEND_INFO_GL_(NAME) \
178
+        {#NAME, (char const *)glGetString(GL_##NAME)}
179
+    // NOLINTNEXTLINE
180
+    #define GLBACKEND_INFO_GL_FLAG_(NAME) \
181
+        { \
182
+            #NAME, \
183
+            (flags & (GLuint)GL_CONTEXT_FLAG_##NAME##_BIT) \
184
+                ? "TRUE" \
185
+                : "FALSE" \
186
+        }
187
+    // NOLINTNEXTLINE
188
+    #define GLBACKEND_INFO_GL_INTEGER_(NAME) \
189
+        {#NAME, std::to_string(integer(GL_##NAME)) }
190
+    auto const flags = (GLuint)integer(GL_CONTEXT_FLAGS);
191
+    debug_info_(ostream, "OpenGL", {
192
+        GLBACKEND_INFO_GL_(VENDOR),
193
+        GLBACKEND_INFO_GL_(RENDERER),
194
+        GLBACKEND_INFO_GL_(VERSION),
195
+        GLBACKEND_INFO_GL_(SHADING_LANGUAGE_VERSION),
196
+        GLBACKEND_INFO_GL_FLAG_(FORWARD_COMPATIBLE),
197
+        GLBACKEND_INFO_GL_FLAG_(DEBUG),
198
+        GLBACKEND_INFO_GL_FLAG_(ROBUST_ACCESS),
199
+        GLBACKEND_INFO_GL_FLAG_(NO_ERROR),
200
+        GLBACKEND_INFO_GL_INTEGER_(SAMPLE_BUFFERS),
201
+        GLBACKEND_INFO_GL_INTEGER_(SAMPLES),
202
+    });
203
+
204
+    return ostream.str();
205
+}
206
+
207
+
208
+void GLBackend::debug_info_(
209
+    std::ostream                                           & ostream,
210
+    std::string                                      const & category,
211
+    std::vector<std::pair<std::string, std::string>> const & values,
212
+    char                                                     fill
213
+)
214
+{
215
+    auto length_max = int{0};
216
+    for (auto const & value : values)
217
+        length_max = std::max(length_max, (int)value.first.length());
218
+    ostream << category << "\n";
219
+    for (auto const & value : values)
220
+        ostream
221
+            << "  "
222
+            << std::left << std::setw(length_max + 1 + 2) << std::setfill(fill)
223
+            << (value.first + " ")
224
+            << (" " + value.second)
225
+            << "\n";
226
+}
227
+
228
+
229
+void GLAPIENTRY GLBackend::debug_gl_message_callback_(
230
+    GLenum          source,
231
+    GLenum          type,
232
+    GLuint          id,
233
+    GLenum          severity,
234
+    GLsizei         length,
235
+    GLchar  const * message,
236
+    void    const * user_param
237
+)
238
+{
239
+    (void)length;
240
+    (void)user_param;
241
+
242
+    auto ostream = std::ostringstream{};
243
+    ostream << std::hex << std::showbase;
244
+
245
+    // https://www.khronos.org/opengl/wiki/Debug_Output#Message_Components
246
+    ostream << "GL debug message ";
247
+    // NOLINTNEXTLINE
248
+    #define GLBACKEND_CALLBACK_CASE_(CATEGORY, VALUE) \
249
+        case GL_DEBUG_##CATEGORY##_##VALUE: \
250
+            ostream << #VALUE; \
251
+            break;
252
+    switch(source)
253
+    {
254
+        GLBACKEND_CALLBACK_CASE_(SOURCE, API)
255
+        GLBACKEND_CALLBACK_CASE_(SOURCE, WINDOW_SYSTEM)
256
+        GLBACKEND_CALLBACK_CASE_(SOURCE, SHADER_COMPILER)
257
+        GLBACKEND_CALLBACK_CASE_(SOURCE, THIRD_PARTY)
258
+        GLBACKEND_CALLBACK_CASE_(SOURCE, APPLICATION)
259
+        GLBACKEND_CALLBACK_CASE_(SOURCE, OTHER)
260
+        default:
261
+            ostream << source;
262
+    }
263
+    ostream << " ";
264
+    switch(type)
265
+    {
266
+        GLBACKEND_CALLBACK_CASE_(TYPE, ERROR)
267
+        GLBACKEND_CALLBACK_CASE_(TYPE, DEPRECATED_BEHAVIOR)
268
+        GLBACKEND_CALLBACK_CASE_(TYPE, UNDEFINED_BEHAVIOR)
269
+        GLBACKEND_CALLBACK_CASE_(TYPE, PORTABILITY)
270
+        GLBACKEND_CALLBACK_CASE_(TYPE, PERFORMANCE)
271
+        GLBACKEND_CALLBACK_CASE_(TYPE, MARKER)
272
+        GLBACKEND_CALLBACK_CASE_(TYPE, PUSH_GROUP)
273
+        GLBACKEND_CALLBACK_CASE_(TYPE, POP_GROUP)
274
+        GLBACKEND_CALLBACK_CASE_(TYPE, OTHER)
275
+        default:
276
+            ostream << type;
277
+    }
278
+    ostream << " ";
279
+    switch(severity)
280
+    {
281
+        GLBACKEND_CALLBACK_CASE_(SEVERITY, HIGH)
282
+        GLBACKEND_CALLBACK_CASE_(SEVERITY, MEDIUM)
283
+        GLBACKEND_CALLBACK_CASE_(SEVERITY, LOW)
284
+        GLBACKEND_CALLBACK_CASE_(SEVERITY, NOTIFICATION)
285
+        default:
286
+            ostream << severity;
287
+    }
288
+    ostream << " ";
289
+    ostream << id;
290
+    ostream << ":\n";
291
+
292
+    ostream << debug_gl_message_(message);
293
+
294
+    debug_callback()(ostream.str());
295
+}
296
+
297
+
298
+std::string GLBackend::debug_gl_message_(std::string message)
299
+{
300
+    message.erase(message.find_last_not_of(" \n") + 1);
301
+
302
+    auto static const file_line = std::regex{R""(^"([^"]+)"(:[0-9]+.*))""};
303
+    auto match = std::smatch{};
304
+    if (std::regex_match(message, match, file_line))
305
+        message = match.str(1) + match.str(2);
306
+
307
+    return message;
308
+}
Browse code

Add project

Robert Cranston authored on 04/06/2021 19:51:44
Showing 1 changed files
1 1
new file mode 100644