1pub mod material;
2mod pass;
3mod prgs;
4mod read_buffer;
5pub mod texture_internal;
6
7use super::{
8 glmanager::{
9 shader::{self, Shader},
10 GlManager,
11 },
12 render_unit::RenderUnit,
13};
14use crate::graphics::glmanager::light::*;
15use crate::graphics::resources::Meshes;
16use fere_common::*;
17use fere_resources::*;
18use gl::types::GLuint;
19use serde::{Deserialize, Serialize};
20use texture_internal::{FrameBuffer, TextureInternal3D};
21
22pub fn deferred_mode(color: bool, depth: bool, index: bool) {
23 unsafe {
24 gl::DepthMask(depth as u8);
25 if !color && index {
26 gl::ColorMask(0, 0, 0, 0);
27 gl::ColorMaski(6, 1, 0, 0, 0);
28 } else if color && !index {
29 gl::ColorMask(1, 1, 1, 1);
30 gl::ColorMaski(6, 0, 0, 0, 0);
31 } else if color && index {
32 gl::ColorMask(1, 1, 1, 1);
33 } else {
34 gl::ColorMask(0, 0, 0, 0);
35 }
36 }
37}
38
39#[derive(Debug)]
40pub struct TextureFetcher {
41 _framebuffer: GLuint,
42 _color_attachment: GLuint,
43}
44
45impl TextureFetcher {
46 pub fn fetch(&self) -> u64 {
47 0
48 }
49
50 pub fn noop() -> Self {
51 Self {
52 _framebuffer: 0,
53 _color_attachment: 0,
54 }
55 }
56}
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct GraphicsConfig {
60 pub resolution: IVec2,
61 pub shadow_resolution: usize,
62 pub probe_resolution: usize,
63 pub max_major_lights: usize,
64
65 pub video_record: bool,
66}
67
68pub struct Graphics {
69 gl_manager: GlManager,
70
71 screen_size: IVec2,
72
73 pass_deferred1: FrameBuffer,
75 pass_final: FrameBuffer,
76 pass_shadow: Vec<FrameBuffer>,
77 pass_probe: FrameBuffer,
78
79 pass_yuv: Option<FrameBuffer>,
80
81 meshes: Meshes,
83
84 pub prgs: prgs::Programs,
85}
86
87impl Graphics {
88 pub fn new(config: GraphicsConfig) -> Self {
89 let gl_manager = GlManager::new("".to_string());
90 let screen_size = config.resolution;
91 let max_major_lights = config.max_major_lights;
92
93 let pass_deferred1 = pass::create_deferred(screen_size);
94 let pass_final = pass::create_final(screen_size);
95
96 let pass_shadow = (0..max_major_lights)
97 .map(|_| pass::create_shadow(config.shadow_resolution as u32))
98 .collect::<Vec<_>>();
99 let pass_probe = pass::create_probe(config.probe_resolution as u32);
100 let pass_yuv = if config.video_record {
101 Some(pass::create_yuv(screen_size))
102 } else {
103 None
104 };
105
106 let meshes = Meshes::default();
107
108 let prgs = prgs::Programs::new(&gl_manager);
109
110 Graphics {
111 gl_manager,
112 screen_size,
113 pass_deferred1,
114 pass_final,
115 pass_shadow,
116 pass_probe,
117 pass_yuv,
118 meshes,
119 prgs,
120 }
121 }
122
123 pub fn meshes(&self) -> &Meshes {
124 &self.meshes
125 }
126
127 pub fn get_object_index_fetcher(&self) -> TextureFetcher {
131 TextureFetcher {
132 _framebuffer: self.pass_deferred1.raw_get(),
133 _color_attachment: 6,
134 }
135 }
136
137 pub fn screen_size(&self) -> IVec2 {
138 self.screen_size
139 }
140
141 pub fn ru_set(&self, program: &shader::Shader, unit: &RenderUnit) {
142 deferred_mode(unit.color, unit.depth, unit.id.is_some());
143 unsafe {
144 if unit.depth_test {
145 gl::Enable(gl::DEPTH_TEST);
146 } else {
147 gl::Disable(gl::DEPTH_TEST);
148 }
149 if let Some(id) = unit.id {
150 let u = program.uloc_get(shader::Uniform::ObjectIndex);
151 gl::Uniform1ui(u, id);
152 }
153 if let Some(lighting) = unit.lighting.as_ref() {
154 let u = program.uloc_get(shader::Uniform::Lighting);
155 gl::Uniform1i(u, *lighting as i32);
156 }
157 }
158 }
159
160 pub fn get_gl(&self) -> &GlManager {
161 &self.gl_manager
162 }
163
164 fn draw_lighvolume_common(&self, mesh: &Mesh) {
170 mesh.bind();
171 deferred_mode(false, false, false);
172 unsafe {
173 gl::CullFace(gl::BACK);
174 gl::DepthFunc(gl::LEQUAL);
175 gl::Disable(gl::STENCIL_TEST);
176
177 gl::StencilFunc(gl::ALWAYS, 0, 0);
178 gl::StencilOp(gl::KEEP, gl::KEEP, gl::INCR);
179
180 gl::Disable(gl::BLEND);
181 }
182 mesh.draw();
183
184 deferred_mode(true, false, false);
185 unsafe {
186 gl::CullFace(gl::FRONT);
187 gl::DepthFunc(gl::GEQUAL);
188 gl::Disable(gl::STENCIL_TEST);
189
190 gl::StencilFunc(gl::NOTEQUAL, 0, 0xFF);
191 gl::StencilOp(gl::ZERO, gl::ZERO, gl::ZERO);
192
193 gl::Enable(gl::BLEND);
194 gl::BlendEquation(gl::FUNC_ADD);
195 gl::BlendFunc(gl::ONE, gl::ONE);
196 }
197 mesh.draw();
198 }
199
200 pub fn draw_lightvolume_uni(
201 &self,
202 program: &Shader,
203 light: &LightUni,
204 cpos: Vec3,
205 _range: bool,
206 ) {
207 program.uniform_light(&light.light, 0);
208 program.uniform_camera(&cpos);
209
210 let radius = light.radius;
211
212 program.uniform_model_s(
213 &glm::vec4_to_vec3(&light.light.pos),
214 &glm::identity(),
215 &Vec3::from_element(radius),
216 false,
217 );
218 self.draw_lighvolume_common(&self.meshes.sphere);
219 }
220
221 pub fn get_transform_for_lightvolume_dir(light: &LightDir) -> Mat4 {
222 let mut trans = glm::translate(&Mat4::identity(), &glm::vec4_to_vec3(&light.light.pos));
223
224 trans *= fere_common::geo::rotation_between(
225 &Vec3::new(1.0, 0.0, 0.0),
226 &Vec3::new(0.0, -1.0, 0.0),
227 &light.xdir,
228 &light.ydir,
229 );
230 trans = glm::scale(&trans, &Vec3::from_element(light.radius));
231 trans = glm::scale(
232 &trans,
233 &Vec3::new((light.angle / 2.0).tan(), (light.angle / 2.0).tan(), 1.0),
234 );
235 trans = glm::translate(&trans, &Vec3::new(0.0, 0.0, 1.0));
236 trans = glm::rotate(&trans, (180.0_f32).to_radians(), &Vec3::new(1.0, 0.0, 0.0));
237 trans
238 }
239
240 pub fn draw_lightvolume_dir(&self, program: &Shader, light: &LightDir, cpos: Vec3) {
241 program.uniform_light_dir(&light, 0);
242 program.uniform_camera(&cpos);
243
244 let trans = Self::get_transform_for_lightvolume_dir(light);
245 program.uniform_model(&trans, false);
246 self.draw_lighvolume_common(&self.meshes.pyramid);
247 }
248
249 pub fn draw_lightvolume_ambient(
250 &self,
251 program: &Shader,
252 cbpos: &Vec3,
253 cpos: &Vec3,
254 size: &Vec3,
255 ) {
256 self.meshes.cube.bind();
257
258 let trans = glm::translate(&glm::identity(), cbpos);
259 let trans = glm::scale(&trans, size);
260 let trans = glm::translate(&trans, &Vec3::new(0.0, 0.0, 0.5));
261 program.uniform_model(&trans, false);
262 program.uniform_camera(&cpos);
263 self.draw_lighvolume_common(&self.meshes.cube);
264 }
265
266 pub fn fill_screen(&self, prg: &Shader) {
267 prg.uniform_transformations(&Mat4::new_scaling(2.0), &Mat4::identity());
268 self.meshes.square.bind();
269 prg.uniform_model(&Mat4::identity(), false);
270 self.meshes.square.draw();
271 }
272
273 pub fn bind_deferred_pass1(&self) {
274 pass::bind_deferred_pass1(self)
275 }
276
277 pub fn bind_deferred_pass2(&self, clear: bool) {
278 pass::bind_deferred_pass2(self, clear)
279 }
280
281 pub fn bind_shadow(&self, index: usize) {
282 pass::bind_shadow(self, index);
283 }
284
285 pub fn bind_probe(&self) {
286 pass::bind_probe(self)
287 }
288
289 pub fn bind_shadow_map(&self, program: &Shader, index: usize) {
290 unsafe {
291 gl::ActiveTexture(gl::TEXTURE6);
292 gl::BindTexture(
293 gl::TEXTURE_2D,
294 self.pass_shadow[index].depth_get().tex_get().raw_get(),
295 );
296 gl::Uniform1i(program.uloc_get_tex()[6], 6)
297 }
298 }
299
300 pub fn bind_gbuffer(&self, program: &Shader, offset: usize) {
301 pass::bind_gbuffer(self, program, offset)
302 }
303
304 pub fn bind_probe_volume(
305 &self,
306 program: &Shader,
307 offset: usize,
308 illumination: &TextureInternal3D,
309 depth: &TextureInternal3D,
310 ) {
311 pass::bind_probe_volume(self, program, offset, illumination, depth)
312 }
313
314 pub fn render_final(&self) {
315 pass::render_final(self)
316 }
317
318 pub fn render_yuv(&self) {
319 pass::render_yuv(self)
320 }
321
322 pub fn bind_forward(&self) {
323 pass::bind_forward(self);
324 }
325
326 pub fn bind_2d(&self) {
327 pass::bind_2d(self)
328 }
329}
330
331impl Graphics {
333 pub fn get_irradiance_volume_tex(&self) -> (u32, IVec2) {
334 (
335 self.pass_probe.outputs_get()[1].tex_get().raw_get(),
336 self.pass_probe.outputs_get()[1].size_get(),
337 )
338 }
339
340 pub fn get_gbuffer_normal(&self) -> (u32, IVec2) {
341 (
342 self.pass_deferred1.outputs_get()[1].tex_get().raw_get(),
343 self.pass_deferred1.outputs_get()[1].size_get(),
344 )
345 }
346}