./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 / 250
0.0%
Branches:
0 / 410
0.0%
Functions:
0 / 33
0.0%

libs/render/src/eu/render/canvas.cc
Line Branch Exec Source
1 #include "eu/render/canvas.h"
2
3 #include "dependency_glad.h"
4
5 #include "eu/assert/assert.h"
6 #include "eu/base/rect.h"
7 #include "eu/base/cint.h"
8 #include "eu/base/mat4.h"
9
10 #include "eu/render/shader.h"
11 #include "eu/render/texture.h"
12 #include "eu/render/opengl_utils.h"
13 #include "eu/render/state.h"
14
15
16 using namespace std::literals;
17
18
19 namespace internal
20 {
21 namespace
22 {
23 using namespace eu;
24 using namespace eu::render;
25
26
27 ✗ void add_vertex(SpriteBatch* batch, const Vertex2& v)
28 {
29 ✗ batch->data.push_back(v.position.x);
30 ✗ batch->data.push_back(v.position.y);
31 ✗ batch->data.push_back(v.position.z);
32
33 ✗ batch->data.push_back(v.color.rgb.r);
34 ✗ batch->data.push_back(v.color.rgb.g);
35 ✗ batch->data.push_back(v.color.rgb.b);
36 ✗ batch->data.push_back(v.color.alpha);
37
38 ✗ batch->data.push_back(v.texturecoord.x);
39 ✗ batch->data.push_back(v.texturecoord.y);
40 ✗ }
41
42
43
44 struct ViewportDef
45 {
46 Rect screen_rect;
47
48 float virtual_width;
49 float virtual_height;
50 };
51
52
53 ViewportDef
54 ✗ fit_with_black_bars
55 (
56 float width,
57 float height,
58 int window_width,
59 int window_height
60 )
61 {
62
0/12
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 16 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 168 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 87 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 85 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 93 not taken.
✗ ASSERTX(width > 0, width);
63
0/12
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 30 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 168 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 103 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 101 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
✗ ASSERTX(height > 0, height);
64
0/12
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 44 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 168 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 119 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 117 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 125 not taken.
✗ ASSERTX(window_width >= 0, window_width);
65
0/12
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 58 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 168 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 135 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 133 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 57 not taken.
✗ Branch 139 → 140 not taken.
✗ Branch 139 → 141 not taken.
✗ ASSERTX(window_height >= 0, window_height);
66 ✗ const float w = float_from_int(window_width) / width;
67 ✗ const float h = float_from_int(window_height) / height;
68 ✗ const float s = std::min(w, h);
69
0/12
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 77 not taken.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 168 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 151 not taken.
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 149 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 76 not taken.
✗ Branch 155 → 156 not taken.
✗ Branch 155 → 157 not taken.
✗ ASSERTX(s > 0, s, w, h);
70 ✗ const float new_width = width * s;
71 ✗ const float new_height = height * s;
72
73 return ViewportDef
74 {
75
0/2
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 166 not taken.
✗ .screen_rect = Rect::from_size({new_width, new_height}).with_bottom_left_at
76
0/2
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 165 not taken.
✗ ({
77 ✗ (float_from_int(window_width) - new_width) / 2.0f,
78 ✗ (float_from_int(window_height) - new_height) / 2.0f
79 }),
80 .virtual_width = width,
81 .virtual_height = height
82 ✗ };
83
0/34
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 94 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 110 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 126 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 142 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 158 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 158 not taken.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 158 not taken.
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 98 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
✗ Branch 110 → 111 not taken.
✗ Branch 110 → 114 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 130 not taken.
✗ Branch 128 → 129 not taken.
✗ Branch 128 → 130 not taken.
✗ Branch 142 → 143 not taken.
✗ Branch 142 → 146 not taken.
✗ Branch 144 → 145 not taken.
✗ Branch 144 → 146 not taken.
✗ Branch 158 → 159 not taken.
✗ Branch 158 → 162 not taken.
✗ Branch 160 → 161 not taken.
✗ Branch 160 → 162 not taken.
✗ }
84
85
86 float
87 ✗ determine_extend_scale(float scale, float height, int window_height)
88 {
89 ✗ const auto scaled_height = height * scale;
90 ✗ const auto s = static_cast<float>(window_height) / scaled_height;
91 ✗ return s;
92 }
93
94
95 ViewportDef
96 ✗ extended_viewport
97 (
98 float width,
99 float height,
100 int window_width,
101 int window_height
102 )
103 {
104
0/12
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 16 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 140 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 75 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 73 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 81 not taken.
✗ ASSERTX(width >= 0, width);
105
0/12
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 30 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 140 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 91 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 89 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
✗ ASSERTX(height >= 0, height);
106
0/12
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 44 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 140 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 107 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 105 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 113 not taken.
✗ ASSERTX(window_width >= 0, window_width);
107
0/12
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 58 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 140 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 123 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 121 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 57 not taken.
✗ Branch 127 → 128 not taken.
✗ Branch 127 → 129 not taken.
✗ ASSERTX(window_height >= 0, window_height);
108 ✗ const auto w = float_from_int(window_width) / width;
109 ✗ const auto h = float_from_int(window_height) / height;
110
0/4
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 138 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 137 not taken.
✗ const auto r = Rect::from_size({ float_from_int(window_width), float_from_int(window_height) }).with_bottom_left_at({ 0, 0 });
111
0/2
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 69 not taken.
✗ if (w < h)
112 {
113 ✗ const auto s = determine_extend_scale(w, height, window_height);
114 ✗ return ViewportDef{ .screen_rect = r, .virtual_width = width, .virtual_height = height * s };
115 }
116 else
117 {
118 ✗ const auto s = determine_extend_scale(h, width, window_width);
119 ✗ return ViewportDef{ .screen_rect = r, .virtual_width = width * s, .virtual_height = height };
120 }
121
0/24
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 82 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 98 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 114 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 130 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 86 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 86 not taken.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 102 not taken.
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ Branch 114 → 115 not taken.
✗ Branch 114 → 118 not taken.
✗ Branch 116 → 117 not taken.
✗ Branch 116 → 118 not taken.
✗ Branch 130 → 131 not taken.
✗ Branch 130 → 134 not taken.
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 134 not taken.
✗ }
122
123
124 ✗ float lerp(float lhs, float t, float rhs)
125 {
126 ✗ return lhs + t * (rhs - lhs);
127 }
128
129 ✗ Rect lerp(const Rect& lhs, float t, const Rect& rhs)
130 {
131 #define V(x) lerp(lhs.x, t, rhs.x)
132 return Rect::from_left_right_top_bottom
133 ✗ (
134 ✗ V(left),
135 ✗ V(right),
136 ✗ V(top),
137 ✗ V(bottom)
138 ✗ );
139 #undef V
140 }
141
142
143 [[nodiscard]]
144 ViewportDef
145 ✗ lerp
146 (
147 const ViewportDef& lhs,
148 float t,
149 const ViewportDef& rhs
150 )
151 {
152 #define V(x) lerp(lhs.x, t, rhs.x)
153 return
154 {
155 ✗ .screen_rect = V(screen_rect),
156 ✗ .virtual_width = V(virtual_width),
157 ✗ .virtual_height = V(virtual_height)
158 ✗ };
159 #undef V
160 }
161
162
163 ✗ Layer create_layer(const ViewportDef& vp)
164 {
165
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return { .viewport_aabb_in_worldspace = Rect::from_size({vp.virtual_width, vp.virtual_height}), .screen = vp.screen_rect };
166 }
167
168
169 ✗ RenderLayer2 create_layer2(const RenderCommand& rc, const ViewportDef& vp)
170 {
171
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 17 not taken.
✗ set_gl_viewport(vp.screen_rect);
172
173 // prepare for 2d rendering
174
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 15 not taken.
✗ StateChanger{ rc.states }
175
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 15 not taken.
✗ .depth_test(false)
176
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 15 not taken.
✗ .blend_mode(Blend::src_alpha, Blend::one_minus_src_alpha)
177
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 15 not taken.
✗ .blending(true);
178
179 ✗ const auto camera = m4_identity;
180
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 17 not taken.
✗ const auto projection = m4::create_ortho_lrud(0.0f, vp.virtual_width, vp.virtual_height, 0.0f, -1.0f, 1.0f);
181
182
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 17 not taken.
✗ rc.render->quad_shader.use();
183
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 17 not taken.
✗ rc.render->quad_shader.set_mat(rc.render->view_projection_uniform, projection);
184
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 17 not taken.
✗ rc.render->quad_shader.set_mat(rc.render->transform_uniform, camera);
185
186 // todo(Gustav): transform viewport according to the camera
187
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 16 not taken.
✗ return RenderLayer2{ create_layer(vp), &rc.render->batch };
188 }
189
190 ✗ RenderLayer3 create_layer3(const RenderCommand&, const ViewportDef& vp)
191 {
192 // set_gl_viewport(vp.screen_rect);
193
194 // todo(Gustav): prepare states for 3d rendering
195 // StateChanger{rc.states}.depth_test(true).blending(false);
196
197
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 6 not taken.
✗ return RenderLayer3{ create_layer(vp) };
198 }
199
200
201 ✗ ViewportDef create_viewport(const LayoutData& ld, const Size& size)
202 {
203
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (ld.style == ViewportStyle::black_bars)
204 {
205 ✗ return fit_with_black_bars(ld.requested_width, ld.requested_height, size.width, size.height);
206 }
207 else
208 {
209 ✗ return extended_viewport(ld.requested_width, ld.requested_height, size.width, size.height);
210 }
211 }
212
213
214 ✗ ViewportDef create_viewport(const LerpData& ld, const Size& size)
215 {
216 return lerp
217
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
✗ (
218 ✗ create_viewport(ld.lhs, size),
219
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 8 not taken.
✗ ld.t,
220
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 9 not taken.
✗ create_viewport(ld.rhs, size)
221 ✗ );
222 }
223
224
225 bool
226 ✗ is_fullscreen(const LerpData& ld)
227 {
228
0/6
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 9 not taken.
✗ if (ld.lhs.style == ld.rhs.style || (ld.t <= 0.0f || ld.t >= 1.0f))
229 {
230
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ const auto style = ld.t >= 1.0f ? ld.rhs.style : ld.lhs.style;
231 ✗ return style == ViewportStyle::extended;
232 }
233
234 ✗ return false;
235 }
236 }
237 }
238
239
240
241
242 namespace eu::render
243 {
244
245 ✗ SpriteBatch::SpriteBatch(State* the_states, ShaderProgram* quad_shader, Render2* r)
246 ✗ : states(the_states)
247 ✗ , render(r)
248
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 49 not taken.
✗ , white_texture
249 (
250 load_image_from_color
251 (
252
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 51 not taken.
✗ SEND_DEBUG_LABEL_MANY("white_texture")
253 core::color_from_rgba(255, 255, 255, 255),
254 TextureEdge::clamp,
255 TextureRenderStyle::pixel,
256 Transparency::include,
257 ColorData::dont_care
258 )
259 ✗ )
260 {
261
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 66 not taken.
✗ quad_shader->use();
262
263
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 66 not taken.
✗ glGenVertexArrays(1, &va);
264
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 66 not taken.
✗ glBindVertexArray(va);
265
266 ✗ constexpr auto vertex_size = 9 * sizeof(float);
267 ✗ constexpr auto max_vertices = 4 * max_quads;
268 ✗ constexpr auto max_indices = 6 * max_quads;
269
270
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 66 not taken.
✗ glGenBuffers(1, &vb);
271
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 66 not taken.
✗ glBindBuffer(GL_ARRAY_BUFFER, vb);
272
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 66 not taken.
✗ glBufferData(GL_ARRAY_BUFFER, vertex_size * max_vertices, nullptr, GL_DYNAMIC_DRAW);
273
274 ✗ auto relative_offset = [](unsigned int i)
275 {
276 ✗ return reinterpret_cast<void*>(i * sizeof(float));
277 };
278
279 ✗ unsigned int offset = 0;
280
281
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 66 not taken.
✗ glEnableVertexAttribArray(0);
282
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 66 not taken.
✗ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_size, relative_offset(offset));
283 ✗ offset += 3;
284
285
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 66 not taken.
✗ glEnableVertexAttribArray(1);
286
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 66 not taken.
✗ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, vertex_size, relative_offset(offset));
287 ✗ offset += 4;
288
289
0/2
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 66 not taken.
✗ glEnableVertexAttribArray(2);
290
0/2
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 66 not taken.
✗ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertex_size, relative_offset(offset));
291 ✗ offset += 2;
292
293
294 ✗ std::vector<u32> indices;
295
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 64 not taken.
✗ indices.reserve(max_indices);
296
297
0/2
✗ Branch 34 → 27 not taken.
✗ Branch 34 → 35 not taken.
✗ for(auto quad_index=0; quad_index<max_quads; quad_index+=1)
298 {
299 ✗ const auto base = quad_index * 4;
300
0/2
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 55 not taken.
✗ indices.emplace_back(base + 0);
301
0/2
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 56 not taken.
✗ indices.emplace_back(base + 1);
302
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 57 not taken.
✗ indices.emplace_back(base + 2);
303
304
0/2
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 58 not taken.
✗ indices.emplace_back(base + 2);
305
0/2
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 59 not taken.
✗ indices.emplace_back(base + 3);
306
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 60 not taken.
✗ indices.emplace_back(base + 0);
307 }
308
309
0/8
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 43 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 64 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 43 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 61 not taken.
✗ ASSERT(max_indices == indices.size());
310
311
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 64 not taken.
✗ glGenBuffers(1, &ib);
312
0/2
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 64 not taken.
✗ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib);
313
0/2
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 64 not taken.
✗ glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_indices * sizeof(u32), indices.data(), GL_STATIC_DRAW);
314 ✗ }
315
316
317 ✗ SpriteBatch::~SpriteBatch()
318 {
319 ✗ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
320 ✗ glDeleteBuffers(1, &ib);
321
322 ✗ glBindBuffer(GL_ARRAY_BUFFER, 0);
323 ✗ glDeleteBuffers(1, &vb);
324
325 ✗ glBindVertexArray(0);
326 ✗ glDeleteVertexArrays(1, &va);
327 ✗ }
328
329
330 ✗ void SpriteBatch::quad(std::optional<const Texture2d*> texture_argument, const Vertex2& v0, const Vertex2& v1, const Vertex2& v2, const Vertex2& v3)
331 {
332 ✗ const Texture2d* texture = texture_argument.value_or(&white_texture);
333
334
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if(quads == max_quads)
335 {
336 ✗ submit();
337 }
338
339
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ if(current_texture == nullptr)
340 {
341 ✗ current_texture = texture;
342 }
343
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 10 not taken.
✗ else if (current_texture != texture)
344 {
345 ✗ submit();
346 ✗ current_texture = texture;
347 }
348
349 ✗ quads += 1;
350
351 ✗ internal::add_vertex(this, v0);
352 ✗ internal::add_vertex(this, v1);
353 ✗ internal::add_vertex(this, v2);
354 ✗ internal::add_vertex(this, v3);
355 ✗ }
356
357 ✗ void Quad::draw(SpriteBatch* batch, const Rect& scr)
358 {
359
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 28 not taken.
✗ const auto tc = texturecoord.value_or(Rect::from_size({1.0f, 1.0f}));
360
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 40 not taken.
✗ const auto size = scr.get_size();
361
0/4
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 10 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 30 not taken.
✗ const auto local_offset = size * (rotation ? rotation->center : v2{0.5f, 0.5f});
362
0/4
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 31 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 31 not taken.
✗ const auto offset = scr.get_bottom_left() + local_offset;
363
364 ✗ const auto rotate = [&](const v2& p)
365 {
366
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ if (rotation.has_value() == false)
367 {
368 ✗ return v3{ p.x, p.y, 0.0f };
369 }
370
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 16 not taken.
✗ const auto local = p - offset;
371
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 16 not taken.
✗ const auto trans = local.get_rotated(rotation->angle);
372
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 16 not taken.
✗ const auto rotated = trans + offset;
373 ✗ return v3{ rotated.x, rotated.y, 0.0f };
374 ✗ };
375
376 batch->quad
377
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 32 not taken.
✗ (
378 texture,
379
0/2
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 32 not taken.
✗ {.position = rotate({scr.left, scr.bottom}), .color = tint, .texturecoord = {tc.left, tc.bottom}},
380
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 34 not taken.
✗ {.position = rotate({scr.right, scr.bottom}), .color = tint, .texturecoord = {tc.right, tc.bottom}},
381
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 36 not taken.
✗ {.position = rotate({scr.right, scr.top}), .color = tint, .texturecoord = {tc.right, tc.top}},
382
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 38 not taken.
✗ {.position = rotate({scr.left, scr.top}), .color = tint, .texturecoord = {tc.left, tc.top}}
383 );
384 ✗ }
385
386 ✗ void SpriteBatch::submit()
387 {
388
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if(quads == 0)
389 {
390 ✗ return;
391 }
392
393 ✗ bind_texture_2d(states, render->texture_uniform, *current_texture);
394 ✗ glBindVertexArray(va);
395
396 ✗ glBindBuffer(GL_ARRAY_BUFFER, vb);
397 glBufferSubData
398 ✗ (
399 GL_ARRAY_BUFFER,
400 0,
401 ✗ static_cast<GLsizeiptr>(sizeof(float) * data.size()),
402 ✗ static_cast<const void*>(data.data())
403 );
404 ✗ glDrawElements(GL_TRIANGLES, 6 * quads, GL_UNSIGNED_INT, nullptr);
405
406 ✗ data.resize(0);
407 ✗ quads = 0;
408 ✗ current_texture = nullptr;
409 }
410
411
412 ✗ Render2::Render2(State* states)
413 // todo(Gustav): move quad_description and quad_layout to a separate setup
414
0/4
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 75 not taken.
✗ : quad_description
415 (
416 {
417 ✗ {.type = core::VertexType::position2xy, .name = "position"},
418 {.type = core::VertexType::color4, .name = "color"},
419 {.type = core::VertexType::texture2, .name = "uv"}
420 }
421 )
422
0/2
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 88 not taken.
✗ , quad_layout
423 (
424
0/8
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 92 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 90 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
✗ compile_shader_layout(core::compile_attribute_layouts({quad_description}), quad_description, std::nullopt, std::nullopt)
425 )
426
0/2
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 111 not taken.
✗ , quad_shader
427 (
428
0/2
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 113 not taken.
✗ SEND_DEBUG_LABEL_MANY("QUAD SHADER")
429
0/2
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 119 not taken.
✗ R"glsl(
430 #version 450 core
431 in vec3 position;
432 in vec4 color;
433 in vec2 uv;
434
435 uniform mat4 view_projection;
436 uniform mat4 transform;
437
438 out vec4 varying_color;
439 out vec2 varying_uv;
440
441 void main()
442 {
443 varying_color = color;
444 varying_uv = uv;
445 gl_Position = view_projection * transform * vec4(position, 1.0);
446 }
447 )glsl",
448
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 125 not taken.
✗ R"glsl(
449 #version 450 core
450
451 in vec4 varying_color;
452 in vec2 varying_uv;
453
454 uniform sampler2D uniform_texture;
455
456 out vec4 color;
457
458 void main()
459 {
460 color = texture(uniform_texture, varying_uv) * varying_color;
461 }
462 )glsl",
463 ✗ quad_layout
464 )
465
0/4
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 131 not taken.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 129 not taken.
✗ , view_projection_uniform(quad_shader.get_uniform("view_projection"))
466
0/4
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 137 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 135 not taken.
✗ , transform_uniform(quad_shader.get_uniform("transform"))
467
0/4
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 143 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 141 not taken.
✗ , texture_uniform(quad_shader.get_uniform("uniform_texture"))
468
0/2
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 156 not taken.
✗ , batch(states, &quad_shader, this)
469 {
470
0/4
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 149 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 147 not taken.
✗ setup_textures(&quad_shader, {&texture_uniform});
471
472 // todo(Gustav): verify mesh layout with SpriteBatch
473
0/18
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 76 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 76 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 76 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 72 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 99 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 83 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 83 not taken.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 103 not taken.
✗ Branch 101 → 102 not taken.
✗ Branch 101 → 103 not taken.
✗ }
474
475
476 ✗ RenderLayer2::~RenderLayer2()
477 {
478 ✗ batch->submit();
479 ✗ }
480
481
482 ✗ RenderLayer2::RenderLayer2(const Layer& l, SpriteBatch* b)
483 : Layer(l)
484 ✗ , batch(b)
485 {
486 ✗ }
487
488 ✗ RenderLayer3::RenderLayer3(const Layer& l)
489 ✗ : Layer(l)
490 {
491 ✗ }
492
493 ✗ v2 Layer::mouse_to_world(const v2& p) const
494 {
495 // transform from mouse pixels to window 0-1
496
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto n = to_01(screen, p);
497
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return from_01(viewport_aabb_in_worldspace, n);
498 }
499
500 void
501 ✗ RenderCommand::clear(const Rgb& color, const LayoutData& ld) const
502 {
503
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 5 not taken.
✗ if(ld.style == ViewportStyle::extended)
504 {
505 ✗ glClearColor(color.r, color.g, color.b, 1.0f);
506 ✗ glClear(GL_COLOR_BUFFER_BIT);
507 }
508 else
509 {
510
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 17 not taken.
✗ auto l = with_layer2(*this, ld);
511
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
✗ Quad{ .tint = color }.draw(l.batch, l.viewport_aabb_in_worldspace);
512 ✗ }
513 ✗ }
514
515
516
517
518 void
519 ✗ RenderCommand::clear(const Rgb& color, const LerpData& ld) const
520 {
521
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 6 not taken.
✗ if(internal::is_fullscreen(ld))
522 {
523 ✗ glClearColor(color.r, color.g, color.b, 1.0f);
524 ✗ glClear(GL_COLOR_BUFFER_BIT);
525 }
526 else
527 {
528
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 18 not taken.
✗ auto l = with_layer2(*this, ld);
529
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 15 not taken.
✗ Quad{ .tint = color }.draw(l.batch, l.viewport_aabb_in_worldspace);
530 ✗ }
531 ✗ }
532
533
534 ✗ RenderLayer2 with_layer2(const RenderCommand& rc, const LayoutData& ld)
535 {
536
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
537
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer2(rc, vp);
538 }
539
540
541 ✗ RenderLayer3 with_layer3(const RenderCommand& rc, const LayoutData& ld)
542 {
543
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
544
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer3(rc, vp);
545 }
546
547
548 ✗ Layer with_layer(const InputCommand& rc, const LayoutData& ld)
549 {
550
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
551
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer(vp);
552 }
553
554
555
556
557
558 ✗ RenderLayer2 with_layer2(const RenderCommand& rc, const LerpData& ld)
559 {
560
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
561
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer2(rc, vp);
562 }
563
564
565 ✗ RenderLayer3 with_layer3(const RenderCommand& rc, const LerpData& ld)
566 {
567
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
568
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer3(rc, vp);
569 }
570
571
572 ✗ Layer with_layer(const InputCommand& rc, const LerpData& ld)
573 {
574
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ const auto vp = internal::create_viewport(ld, rc.size);
575
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return internal::create_layer(vp);
576 }
577
578 }
579