fere 0.0.0

A 3D rendering engine focused on simple use and realtime global illumination.
Documentation
use super::*;
use chamber::*;

impl RenderContext {
    pub fn process_op(&mut self, op: RenderOp) -> Result<Option<RenderOp>, OpError> {
        match op {
            RenderOp::Multiple(_) => {
                panic!("`RenderOp::Multiple` on `process_op()`")
            }
            RenderOp::StartFrame(_) => {
                self.graphics.bind_deferred_pass1();
                Ok(None)
            }
            RenderOp::SetCamera(camera_info_) => {
                let programs = vec![
                    self.graphics.prgs.basic.as_ref(),
                    self.graphics.prgs.standard.as_ref(),
                    self.graphics.prgs.sh_visualize.as_ref(),
                    self.graphics.prgs.sh_visualize_single.as_ref(),
                    self.graphics.prgs.geo_visualize.as_ref(),
                    self.graphics.prgs.dr_2.as_ref(),
                    self.graphics.prgs.dr_2_irradiance.as_ref(),
                    self.graphics.prgs.dr_2_ambient.as_ref(),
                    self.graphics.prgs.dr_2_omni.as_ref(),
                ];
                for program in programs {
                    program.bind();
                    program.uniform_transformations(
                        camera_info_.projection_get(),
                        camera_info_.view_get(),
                    );
                }
                self.camera_info = Some(camera_info_);
                Ok(None)
            }
            RenderOp::DrawLine(DrawLine {
                pos1,
                pos2,
                color,
                width,
            }) => {
                let prg = self.graphics.prgs.standard.as_ref();
                prg.bind();
                let runit = RenderUnit {
                    color: true,
                    depth: true,
                    depth_test: true,
                    id: None,
                    lighting: Some(Lighting::DefFixed),
                };
                self.graphics.ru_set(prg, &runit);
                let arr = &self.graphics.meshes().line;
                arr.bind();
                bind_fixed_color(&prg, &color);
                prg.uniform_line(&pos1, &pos2, width);
                arr.draw_line();
                Ok(None)
            }
            RenderOp::DrawGeneral(DrawGeneral { object, surface }) => {
                self.get_chamber_ctx(object.chamber_index)?;

                let prg = self.graphics.prgs.standard.as_ref();
                prg.bind();
                let runit = RenderUnit {
                    color: true,
                    depth: true,
                    depth_test: true,
                    id: None,
                    lighting: Some(Lighting::DefFull),
                };
                self.graphics.ru_set(prg, &runit);

                prg.uniform_model(&object.trans, false);
                object.mesh.bind();
                bind_general(&prg, &surface);
                object.mesh.draw();

                if object.shadow {
                    self.get_mut_chamber_ctx(object.chamber_index)?
                        .shadow_objects
                        .push(ChamberShadowObject {
                            mesh: object.mesh,
                            trans: object.trans,
                        })
                }
                Ok(None)
            }
            RenderOp::DrawEmissiveStatic(DrawEmissiveStatic {
                object,
                surface,
                point_light,
            }) => {
                self.get_chamber_ctx(object.chamber_index)?;

                let prg = self.graphics.prgs.standard.as_ref();
                prg.bind();
                let runit = RenderUnit {
                    color: true,
                    depth: true,
                    depth_test: true,
                    id: None,
                    lighting: Some(Lighting::DefFull),
                };
                self.graphics.ru_set(prg, &runit);

                prg.uniform_model(&object.trans, false);
                object.mesh.bind();
                bind_emissive_static(&prg, &surface, 0.0);
                object.mesh.draw();

                if object.shadow {
                    self.get_mut_chamber_ctx(object.chamber_index)?
                        .shadow_objects
                        .push(ChamberShadowObject {
                            mesh: Arc::clone(&object.mesh),
                            trans: object.trans,
                        })
                }
                self.get_mut_chamber_ctx(object.chamber_index)?
                    .emissive_static_objects
                    .push(ChamberEmissiveStaticObject {
                        mesh: Arc::clone(&object.mesh),
                        trans: object.trans,
                        surface: surface.clone(),
                    });

                if let Some(point_light) = point_light {
                    let emission = match surface.timepoints[0].emission {
                            fere_resources::surface::TexVar::T(_) => return Err(OpError::Other("`point_light` in `DrawEmissiveStatic` is not implemented for a textured surface.".to_owned())),
                            fere_resources::surface::TexVar::U(x) => x,
                        };
                    let emission_intensity = match &surface.timepoints[0].emission_intensity {
                            fere_resources::surface::TexVar::T(_) => return Err(OpError::Other("`point_light` in `DrawEmissiveStatic` is not implemented for a textured surface.".to_owned())),
                            fere_resources::surface::TexVar::U(x) => x,
                        };

                    Ok(Some(RenderOp::AddPointLight(AddPointLight {
                        pos: object.mesh.description().mean_pos,
                        color: nalgebra::convert::<IVec3, Vec3>(emission) / 255.0
                            * fere_common::light::intensity_to_weight(*emission_intensity)
                            * point_light,
                        chamber_index: object.chamber_index,
                    })))
                } else {
                    Ok(None)
                }
            }
            RenderOp::DrawWireFrame(DrawWireFrame {
                mesh,
                trans,
                color,
                width,
            }) => {
                let prg = self.graphics.prgs.standard.as_ref();
                prg.bind();
                let runit = RenderUnit {
                    color: true,
                    depth: true,
                    depth_test: true,
                    id: None,
                    lighting: Some(Lighting::DefFixed),
                };
                self.graphics.ru_set(prg, &runit);
                mesh.bind();
                prg.uniform_wireframe(&trans, &color, width);
                mesh.draw_wireframe();
                Ok(None)
            }
            RenderOp::AddMajorLight(x) => {
                self.get_chamber_ctx(x.chamber_index)?;

                let result =
                    if self.params.debug_lightvolume_outline {
                        let (light, _) = common::prepare_major_light(&x);
                        Some(RenderOp::DrawWireFrame(DrawWireFrame {
						mesh: Arc::clone(&self.graphics.meshes().pyramid),
						trans: crate::graphics::graphics::Graphics::get_transform_for_lightvolume_dir(&light),
						color: IVec4::new(0, 255, 255 ,255),
						width: 1.0,
					}))
                    } else {
                        None
                    };
                self.get_mut_chamber_ctx(x.chamber_index)?
                    .major_lights
                    .push(x);
                Ok(result)
            }
            RenderOp::AddAmbientLight(x) => {
                self.get_mut_chamber_ctx(x.chamber_index)?
                    .ambient_lights
                    .push(x);
                Ok(None)
            }
            RenderOp::AddPointLight(x) => {
                self.get_mut_chamber_ctx(x.chamber_index)?
                    .point_lights
                    .push(x);
                Ok(None)
            }
            RenderOp::ShadeWithIv(x) => {
                let chamber_index = x.chamber_index;
                if self
                    .get_mut_chamber_ctx(x.chamber_index)?
                    .shade_with_iv
                    .replace(x)
                    .is_some()
                {
                    Err(OpError::InvalidShade(format!(
                        "ShadeWithIv on chamber #{}",
                        chamber_index
                    )))
                } else {
                    Ok(None)
                }
            }
            RenderOp::VisualizeProbes(c) => {
                let chamber = self.get_chamber_ctx(c.chamber_index)?;
                let probes = chamber
                    .chamber
                    .state
                    .probe_volume_suite
                    .probe_volume()
                    .probes();

                let prg = self.graphics.prgs.sh_visualize_single.as_ref();
                prg.bind();
                let mesh = &self.graphics.meshes().sphere;
                mesh.bind();

                for probe in probes {
                    let sh: Vec<Vec3> = probe.sh.iter().map(|x| x.1).collect();
                    prg.uniform_sh(&sh);
                    prg.uniform_model_s(
                        &probe.pos,
                        &Mat4::identity(),
                        &Vec3::new(4.0, 4.0, 4.0),
                        false,
                    );
                    mesh.draw()
                }
                Ok(None)
            }
            RenderOp::DrawImage(x) => {
                self.draw_images.push(x);
                Ok(None)
            }
            RenderOp::DrawBillboard(x) => {
                self.draw_billboarsd.push(x);
                Ok(None)
            }
            RenderOp::ShowInternalTexture(x) => {
                self.show_internal_textures.push(x);
                Ok(None)
            }
            _ => unimplemented!(),
        }
    }
}