GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 187, 0 excluded
0.0%
Functions:
0 of 34, 0 excluded
0.0%
Branches:
0 of 196, 0 excluded
0.0%

libs/render/src/render/statechanger.cc
Line Branch Exec Source
1 #include "render/statechanger.h"
2
3 #include "assert/assert.h"
4
5 #include "base/cint.h"
6
7 #include "render/texture.h"
8 #include "render/uniform.h"
9 #include "render/opengl_states.h"
10 #include "render/opengl_utils.h"
11
12 namespace eu::render
13 {
14
15 template<typename T>
16 bool should_change(std::optional<T>* current_state, T new_state)
17 {
18 // if there is a value, and that is the same... then don't update opengl
19 if (*current_state && *current_state == new_state)
20 {
21 return false;
22 }
23
24 *current_state = new_state;
25 return true;
26 }
27
28 void apply(std::optional<bool>* current_state, bool new_state, GLenum gl_type)
29 {
30 if (should_change(current_state, new_state))
31 {
32 if (new_state)
33 {
34 glEnable(gl_type);
35 }
36 else
37 {
38 glDisable(gl_type);
39 }
40 }
41 }
42
43 GLenum enum_from_c(Compare new_state)
44 {
45 switch (new_state)
46 {
47 case Compare::always: return GL_ALWAYS;
48 case Compare::never: return GL_NEVER;
49 case Compare::less: return GL_LESS;
50 case Compare::equal: return GL_EQUAL;
51 case Compare::less_equal: return GL_LEQUAL;
52 case Compare::greater: return GL_GREATER;
53 case Compare::not_equal: return GL_NOTEQUAL;
54 case Compare::greater_equal: return GL_GEQUAL;
55 default: DIE("Invalid depth func"); return GL_LESS;
56 }
57 }
58
59 GLenum enum_from_sa (StencilAction sa)
60 {
61 switch (sa)
62 {
63 case StencilAction::keep: return GL_KEEP;
64 case StencilAction::zero: return GL_ZERO;
65 case StencilAction::replace: return GL_REPLACE;
66 case StencilAction::increase: return GL_INCR;
67 case StencilAction::increase_wrap: return GL_INCR_WRAP;
68 case StencilAction::decrease: return GL_DECR;
69 case StencilAction::decrease_wrap: return GL_DECR_WRAP;
70 case StencilAction::invert: return GL_INVERT;
71 default: DIE("Invalid stencil action"); return GL_KEEP;
72 }
73 };
74
75 StateChanger::StateChanger(OpenglStates* s)
76 : states(s)
77 {
78 }
79
80 StateChanger& StateChanger::cull_face(bool new_state)
81 {
82 apply(&states->cull_face, new_state, GL_CULL_FACE);
83 return *this;
84 }
85
86 StateChanger& StateChanger::blending(bool new_state)
87 {
88 apply(&states->blending, new_state, GL_BLEND);
89 return *this;
90 }
91
92 StateChanger& StateChanger::depth_test(bool new_state)
93 {
94 apply(&states->depth_test, new_state, GL_DEPTH_TEST);
95 return *this;
96 }
97
98 StateChanger& StateChanger::depth_mask(bool new_state)
99 {
100 if (should_change(&states->depth_mask, new_state))
101 {
102 glDepthMask(new_state ? GL_TRUE : GL_FALSE);
103 }
104 return *this;
105 }
106
107 StateChanger& StateChanger::depth_func(Compare new_state)
108 {
109 if (should_change(&states->depth_func, new_state))
110 {
111 const auto mode = enum_from_c(new_state);
112 glDepthFunc(mode);
113 }
114
115 return *this;
116 }
117
118 StateChanger& StateChanger::stencil_test(bool new_state)
119 {
120 apply(&states->stencil_test, new_state, GL_STENCIL_TEST);
121 return *this;
122 }
123
124 /// Set a bitmask that is ANDed with the stencil value about to be written to the buffer.
125 StateChanger& StateChanger::stencil_mask(u32 new_state)
126 {
127 if (should_change(&states->stencil_mask, new_state))
128 {
129 glStencilMask(new_state);
130 }
131
132 return *this;
133 }
134
135 StateChanger& StateChanger::stencil_func(Compare func, i32 ref, u32 mask)
136 {
137 if (should_change(&states->stencil_func, {func, ref, mask}))
138 {
139 glStencilFunc(enum_from_c(func), ref, mask);
140 }
141
142 return *this;
143 }
144
145 StateChanger& StateChanger::render_mode(RenderMode new_state)
146 {
147 if (should_change(&states->render_mode, new_state))
148 {
149 const auto mode = ([new_state]() -> GLenum
150 {
151 switch (new_state)
152 {
153 case RenderMode::fill: return GL_FILL;
154 case RenderMode::line: return GL_LINE;
155 case RenderMode::point: return GL_POINT;
156 default: DIE("Invalid render mode"); return GL_FILL;
157 }
158 })();
159 glPolygonMode(GL_FRONT_AND_BACK, mode);
160 }
161 return *this;
162 }
163
164 StateChanger& StateChanger::stencil_op(StencilAction stencil_fail, StencilAction depth_fail, StencilAction pass)
165 {
166 if (should_change(&states->stencil_op, {stencil_fail, depth_fail, pass}))
167 {
168 // todo(Gustav): look into using glStencilOpSeparate instead to specify front and back faces
169 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glStencilOpSeparate.xhtml
170 glStencilOp(enum_from_sa(stencil_fail), enum_from_sa(depth_fail), enum_from_sa(pass));
171 }
172
173 return *this;
174 }
175
176 StateChanger& StateChanger::cull_face_mode(CullFace new_state)
177 {
178 if (should_change(&states->cull_face_mode, new_state))
179 {
180 const auto mode = ([new_state]() -> GLenum
181 {
182 switch (new_state)
183 {
184 case CullFace::front: return GL_FRONT;
185 case CullFace::back: return GL_BACK;
186 case CullFace::front_and_back: return GL_FRONT_AND_BACK;
187 default: DIE("Invalid cull face mode"); return GL_BACK;
188 }
189 })();
190 glCullFace(mode);
191 }
192 return *this;
193 }
194
195 StateChanger& StateChanger::blend_mode(Blend src, Blend dst)
196 {
197 if (should_change(&states->blend_mode, {src, dst}))
198 {
199 const auto convert = [](Blend b) -> GLenum
200 {
201 switch (b)
202 {
203 case Blend::zero: return GL_ZERO;
204 case Blend::one: return GL_ONE;
205 case Blend::src_color: return GL_SRC_COLOR;
206 case Blend::one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
207 case Blend::dst_color: return GL_DST_COLOR;
208 case Blend::one_minus_dst_color: return GL_ONE_MINUS_DST_COLOR;
209 case Blend::src_alpha: return GL_SRC_ALPHA;
210 case Blend::one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
211 case Blend::dst_alpha: return GL_DST_ALPHA;
212 case Blend::one_minus_dst_alpha: return GL_ONE_MINUS_DST_ALPHA;
213 case Blend::constant_color: return GL_CONSTANT_COLOR;
214 case Blend::one_minus_constant_color: return GL_ONE_MINUS_CONSTANT_COLOR;
215 case Blend::constant_alpha: return GL_CONSTANT_ALPHA;
216 case Blend::one_minus_constant_alpha: return GL_ONE_MINUS_CONSTANT_ALPHA;
217 case Blend::src_alpha_saturate: return GL_SRC_ALPHA_SATURATE;
218 case Blend::src1_color: return GL_SRC1_COLOR;
219 case Blend::one_minus_src1_color: return GL_ONE_MINUS_SRC1_COLOR;
220 case Blend::src1_alpha: return GL_SRC1_ALPHA;
221 case Blend::one_minus_src1_alpha: return GL_ONE_MINUS_SRC1_ALPHA;
222 default: DIE("Invalid blend mode"); return GL_ZERO;
223 }
224 };
225 glBlendFunc(convert(src), convert(dst));
226 }
227 return *this;
228 }
229
230 StateChanger& StateChanger::activate_texture(int new_texture)
231 {
232 if (should_change(&states->active_texture, new_texture))
233 {
234 glActiveTexture(glenum_from_int(GL_TEXTURE0 + new_texture));
235 }
236 return *this;
237 }
238
239 StateChanger& StateChanger::bind_texture_2d(int slot, unsigned int texture)
240 {
241 ASSERT(slot == states->active_texture);
242 if (should_change(&states->texture_bound[sizet_from_int(slot)], texture))
243 {
244 glBindTexture(GL_TEXTURE_2D, texture);
245 }
246 return *this;
247 }
248
249 StateChanger& StateChanger::bind_texture_cubemap(int slot, unsigned int texture)
250 {
251 ASSERT(slot == states->active_texture);
252 if (should_change(&states->texture_bound[sizet_from_int(slot)], texture))
253 {
254 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
255 }
256 return *this;
257 }
258
259 void bind_texture_2d(OpenglStates* states, const Uniform& uniform, const Texture2d& texture)
260 {
261 if (uniform.is_valid() == false)
262 {
263 return;
264 }
265 ASSERT(uniform.texture >= 0);
266
267 StateChanger{states}.activate_texture(uniform.texture).bind_texture_2d(uniform.texture, texture.id);
268 }
269
270 void bind_texture_2d(OpenglStates* states, const Uniform& uniform, const FrameBuffer& texture)
271 {
272 if (uniform.is_valid() == false)
273 {
274 return;
275 }
276 ASSERT(uniform.texture >= 0);
277 ASSERT(texture.debug_is_msaa == false);
278
279 StateChanger{states}.activate_texture(uniform.texture).bind_texture_2d(uniform.texture, texture.id);
280 }
281
282 void bind_texture_cubemap(OpenglStates* states, const Uniform& uniform, const TextureCubemap& texture)
283 {
284 if (uniform.is_valid() == false)
285 {
286 return;
287 }
288 ASSERT(uniform.texture >= 0);
289
290 StateChanger{states}.activate_texture(uniform.texture).bind_texture_cubemap(uniform.texture, texture.id);
291 }
292
293 } // namespace klotter
294