GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 112, 0 excluded
0.0%
Functions:
0 of 17, 0 excluded
0.0%
Branches:
0 of 160, 0 excluded
0.0%

libs/render/src/eu/render/material.cc
Line Branch Exec Source
1 #include "eu/render/material.h"
2
3 #include "eu/assert/assert.h"
4 #include "eu/base/cint.h"
5
6 #include "eu/render/renderer.h"
7 // #include "eu/render/assets.h"
8 #include "eu/render/camera.h"
9 #include "eu/render/render_settings.h"
10 #include "eu/render/shader.h"
11 #include "eu/render/shader_resource.h"
12 #include "eu/render/world.h"
13 #include "eu/render/state.h"
14 #include "eu/render/constants.h"
15
16
17 namespace eu::render
18 {
19
20 UnlitMaterial::UnlitMaterial(const ShaderResource& resource)
21 : shader_container(&resource.unlit_shader_container)
22 {
23 }
24
25 void UnlitMaterial::use_shader(const RenderContext& rc)
26 {
27 shader_from_container(*shader_container, rc).program->use();
28 }
29
30 void set_optional_mat(
31 ShaderProgram* program, const std::optional<Uniform>& uniform, const std::optional<m4>& transform
32 )
33 {
34 if (uniform && transform)
35 {
36 program->set_mat(*uniform, *transform);
37 }
38 else
39 {
40 ASSERT(uniform.has_value() == false);
41 ASSERT(transform.has_value() == false);
42 }
43 }
44
45 v3 vec_from_lin(const Lin_rgb& lin)
46 {
47 return { lin.r, lin.g, lin.b };
48 }
49
50 void UnlitMaterial::set_uniforms(
51 const RenderContext& rc, const CompiledCamera&, const std::optional<m4>& world_from_local
52 )
53 {
54 const auto& shader = shader_from_container(*shader_container, rc);
55 shader.program->set_vec4(shader.tint_color_uni, { vec_from_lin(linear_from_srgb(color, rc.gamma)), alpha });
56 set_optional_mat(shader.program.get(), shader.world_from_local_uni, world_from_local);
57 }
58
59 void UnlitMaterial::bind_textures(const RenderContext& rc, State* states, Assets* assets)
60 {
61 std::shared_ptr<Texture2d> t = texture;
62 if (t == nullptr)
63 {
64 t = assets->white;
65 }
66
67 bind_texture_2d(states, shader_from_container(*shader_container, rc).tex_diffuse_uniform, *t);
68 }
69
70 void UnlitMaterial::apply_lights(const RenderContext&, const Lights&, const RenderSettings&, State*, Assets*)
71 {
72 // no lights for unlit material
73 }
74
75 bool UnlitMaterial::is_transparent() const
76 {
77 // todo(Gustav): improve transparency
78 return alpha < ALPHA_TRANSPARENCY_LIMIT;
79 }
80
81 DefaultMaterial::DefaultMaterial(const ShaderResource& resource)
82 : shader_container(&resource.default_shader_container)
83 {
84 }
85
86 void DefaultMaterial::use_shader(const RenderContext& rc)
87 {
88 shader_from_container(*shader_container, rc).program->use();
89 }
90
91 void DefaultMaterial::set_uniforms(
92 const RenderContext& rc, const CompiledCamera& cc, const std::optional<m4>& world_from_local
93 )
94 {
95 const auto& shader = shader_from_container(*shader_container, rc);
96
97 shader.program->set_vec4(shader.tint_color_uni, {vec_from_lin(linear_from_srgb(color, rc.gamma)), alpha});
98 shader.program->set_vec3(shader.ambient_tint_uni, vec_from_lin(linear_from_srgb(ambient_tint, rc.gamma)));
99 shader.program->set_vec3(shader.specular_color_uni, vec_from_lin(linear_from_srgb(specular_color, rc.gamma)));
100 shader.program->set_float(shader.shininess_uni, shininess);
101 shader.program->set_float(shader.emissive_factor_uni, emissive_factor);
102
103 set_optional_mat(shader.program.get(), shader.world_from_local_uni, world_from_local);
104 shader.program->set_vec3(shader.view_position_uni, cc.position);
105 }
106
107 std::shared_ptr<Texture2d> get_or_white(Assets* assets, std::shared_ptr<Texture2d> t)
108 {
109 if (t == nullptr)
110 {
111 return assets->white;
112 }
113 else
114 {
115 return t;
116 }
117 };
118
119 std::shared_ptr<Texture2d> get_or_black(Assets* assets, std::shared_ptr<Texture2d> t)
120 {
121 if (t == nullptr)
122 {
123 return assets->black;
124 }
125 else
126 {
127 return t;
128 }
129 };
130
131 void DefaultMaterial::bind_textures(const RenderContext& rc, State* states, Assets* assets)
132 {
133 const auto& shader = shader_from_container(*shader_container, rc);
134 bind_texture_2d(states, shader.tex_diffuse_uniform, *get_or_white(assets, diffuse));
135 bind_texture_2d(states, shader.tex_specular_uniform, *get_or_white(assets, specular));
136 bind_texture_2d(states, shader.tex_emissive_uniform, *get_or_black(assets, emissive));
137 }
138
139 void DefaultMaterial::apply_lights(
140 const RenderContext& rc, const Lights& lights, const RenderSettings& settings, State* states, Assets* assets
141 )
142 {
143 const auto& shader = shader_from_container(*shader_container, rc);
144 shader.program->set_vec3(shader.light_ambient_color_uni, vec_from_lin(linear_from_srgb(lights.ambient_color, rc.gamma)) * lights.ambient_strength);
145
146 constexpr auto no_directional_light = ([]() {
147 DirectionalLight p;
148 p.color = colors::black;
149 p.diffuse_strength = 0.0f;
150 p.specular_strength = 0.0f;
151 return p;
152 })();
153 constexpr auto no_point_light = ([]() {
154 PointLight p;
155 p.color = colors::black;
156 p.diffuse_strength = 0.0f;
157 p.specular_strength = 0.0f;
158 return p;
159 })();
160 auto no_frustum_light = ([]() {
161 FrustumLight p;
162 p.color = colors::black;
163 p.diffuse_strength = 0.0f;
164 p.specular_strength = 0.0f;
165 return p;
166 })();
167
168 // todo(Gustav): graph the most influential lights instead of the first N lights
169 for (int index = 0; index < settings.number_of_directional_lights; index += 1)
170 {
171 const auto& p = sizet_from_int(index) < lights.directional_lights.size()
172 ? lights.directional_lights[sizet_from_int(index)]
173 : no_directional_light;
174 const auto& u = shader.directional_lights[sizet_from_int(index)];
175 shader.program->set_vec3(u.light_diffuse_color_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.diffuse_strength);
176 shader.program->set_vec3(u.light_specular_color_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.specular_strength);
177 const auto vectors = create_vectors(p);
178 shader.program->set_vec3(u.dir_uni, vectors.front);
179 }
180
181 for (int index = 0; index < settings.number_of_point_lights; index += 1)
182 {
183 const auto& p = sizet_from_int(index) < lights.point_lights.size()
184 ? lights.point_lights[sizet_from_int(index)]
185 : no_point_light
186 ;
187 const auto& u = shader.point_lights[sizet_from_int(index)];
188 shader.program->set_vec3(u.light_diffuse_color_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.diffuse_strength);
189 shader.program->set_vec3(u.light_specular_color_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.specular_strength);
190 shader.program->set_vec3(u.light_world_uni, p.position);
191 shader.program->set_vec4(u.light_attenuation_uni, {p.min_range, p.max_range, p.curve.slope, p.curve.threshold});
192 }
193
194 for (int index = 0; index < settings.number_of_frustum_lights; index += 1)
195 {
196 const auto& p = sizet_from_int(index) < lights.frustum_lights.size() ? lights.frustum_lights[sizet_from_int(index)]
197 : no_frustum_light;
198 const auto& u = shader.frustum_lights[sizet_from_int(index)];
199 shader.program->set_vec3(u.diffuse_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.diffuse_strength);
200 shader.program->set_vec3(u.specular_uni, vec_from_lin(linear_from_srgb(p.color, settings.gamma)) * p.specular_strength);
201 shader.program->set_vec3(u.world_pos_uni, p.position);
202 shader.program->set_vec4(u.attenuation_uni, {p.min_range, p.max_range, p.curve.slope, p.curve.threshold});
203
204 const auto view_from_world = create_view_from_world_mat(p.position, create_vectors(p.rotation));
205 const auto clip_from_view = m4::create_perspective(p.fov, p.aspect, 0.1f, p.max_range);
206 shader.program->set_mat(u.clip_from_world_uni, clip_from_view * view_from_world);
207
208 bind_texture_2d(states, u.tex_cookie_uniform, *get_or_white(assets, p.cookie));
209 }
210
211 // directional light shadows
212 ASSERT(rc.shadow_context);
213 auto* shadow_map = rc.shadow_context != nullptr ? rc.shadow_context->directional_shadow_map : nullptr;
214 if (shadow_map != nullptr)
215 {
216 bind_texture_2d(states, shader.tex_directional_light_depth_uni, *shadow_map);
217 }
218 else
219 {
220 bind_texture_2d(states, shader.tex_directional_light_depth_uni, *assets->white);
221 }
222
223 const auto directional_shadow_clip_from_world
224 = rc.shadow_context != nullptr ? rc.shadow_context->directional_shadow_clip_from_world : m4_identity;
225 shader.program->set_mat(shader.directional_shadow_clip_from_world_uni, directional_shadow_clip_from_world);
226 }
227
228 bool DefaultMaterial::is_transparent() const
229 {
230 // todo(Gustav): improve transparency
231 return alpha < ALPHA_TRANSPARENCY_LIMIT;
232 }
233
234 } // namespace eu::render
235