use crate::camera::*;
use crate::core::*;
use crate::definition::*;
use crate::effect::*;
use crate::light::*;
use crate::math::*;
use crate::phong::*;
use std::collections::HashMap;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DebugType {
POSITION,
NORMAL,
COLOR,
DEPTH,
DIFFUSE,
SPECULAR,
POWER,
NONE,
}
pub struct PhongDeferredPipeline {
context: Context,
program_map: HashMap<String, ImageEffect>,
debug_effect: Option<ImageEffect>,
pub debug_type: DebugType,
geometry_pass_texture: Option<ColorTargetTexture2DArray<u8>>,
geometry_pass_depth_texture: Option<DepthTargetTexture2DArray>,
}
impl PhongDeferredPipeline {
pub fn new(context: &Context) -> Result<Self, Error> {
let renderer = Self {
context: context.clone(),
program_map: HashMap::new(),
debug_effect: None,
debug_type: DebugType::NONE,
geometry_pass_texture: Some(ColorTargetTexture2DArray::new(
context,
1,
1,
2,
Interpolation::Nearest,
Interpolation::Nearest,
None,
Wrapping::ClampToEdge,
Wrapping::ClampToEdge,
Format::RGBA,
)?),
geometry_pass_depth_texture: Some(DepthTargetTexture2DArray::new(
context,
1,
1,
1,
Wrapping::ClampToEdge,
Wrapping::ClampToEdge,
DepthFormat::Depth32F,
)?),
};
Ok(renderer)
}
pub fn geometry_pass(
&mut self,
width: usize,
height: usize,
camera: &Camera,
geometries: &[&dyn PhongGeometry],
) -> Result<(), Error> {
self.geometry_pass_texture = Some(ColorTargetTexture2DArray::<u8>::new(
&self.context,
width,
height,
2,
Interpolation::Nearest,
Interpolation::Nearest,
None,
Wrapping::ClampToEdge,
Wrapping::ClampToEdge,
Format::RGBA,
)?);
self.geometry_pass_depth_texture = Some(DepthTargetTexture2DArray::new(
&self.context,
width,
height,
1,
Wrapping::ClampToEdge,
Wrapping::ClampToEdge,
DepthFormat::Depth32F,
)?);
RenderTargetArray::new(
&self.context,
self.geometry_pass_texture.as_ref().unwrap(),
self.geometry_pass_depth_texture.as_ref().unwrap(),
)?
.write(&[0, 1], 0, ClearState::default(), || {
for geometry in geometries {
if geometry
.aabb()
.map(|aabb| camera.in_frustum(&aabb))
.unwrap_or(true)
{
geometry.geometry_pass(
RenderStates::default(),
Viewport::new_at_origo(width, height),
camera,
)?;
}
}
Ok(())
})?;
Ok(())
}
pub fn light_pass(
&mut self,
viewport: Viewport,
camera: &Camera,
ambient_light: Option<&AmbientLight>,
directional_lights: &[&DirectionalLight],
spot_lights: &[&SpotLight],
point_lights: &[&PointLight],
) -> Result<(), Error> {
let render_states = RenderStates {
depth_test: DepthTestType::LessOrEqual,
..Default::default()
};
if self.debug_type != DebugType::NONE {
if self.debug_effect.is_none() {
self.debug_effect = Some(
ImageEffect::new(&self.context, include_str!("shaders/debug.frag")).unwrap(),
);
}
self.debug_effect.as_ref().unwrap().use_uniform_mat4(
"viewProjectionInverse",
&(camera.projection() * camera.view()).invert().unwrap(),
)?;
self.debug_effect
.as_ref()
.unwrap()
.use_texture_array(self.geometry_pass_texture(), "gbuffer")?;
self.debug_effect
.as_ref()
.unwrap()
.use_texture_array(self.geometry_pass_depth_texture_array(), "depthMap")?;
self.debug_effect
.as_ref()
.unwrap()
.use_uniform_int("type", &(self.debug_type as i32))?;
self.debug_effect
.as_ref()
.unwrap()
.apply(render_states, viewport)?;
return Ok(());
}
let key = format!(
"{},{},{},{}",
ambient_light.is_some(),
directional_lights.len(),
spot_lights.len(),
point_lights.len()
);
if !self.program_map.contains_key(&key) {
self.program_map.insert(
key.clone(),
ImageEffect::new(
&self.context,
&crate::phong::phong_fragment_shader(
&include_str!("shaders/deferred_surface.frag"),
directional_lights.len(),
spot_lights.len(),
point_lights.len(),
),
)?,
);
};
let effect = self.program_map.get(&key).unwrap();
crate::phong::bind_lights(
effect,
ambient_light,
directional_lights,
spot_lights,
point_lights,
)?;
effect.use_texture_array(self.geometry_pass_texture(), "gbuffer")?;
effect.use_texture_array(self.geometry_pass_depth_texture_array(), "depthMap")?;
if !directional_lights.is_empty() || !spot_lights.is_empty() || !point_lights.is_empty() {
effect.use_uniform_vec3("eyePosition", &camera.position())?;
effect.use_uniform_mat4(
"viewProjectionInverse",
&(camera.projection() * camera.view()).invert().unwrap(),
)?;
}
effect.apply(render_states, viewport)?;
Ok(())
}
pub fn geometry_pass_texture(&self) -> &ColorTargetTexture2DArray<u8> {
self.geometry_pass_texture.as_ref().unwrap()
}
pub fn geometry_pass_depth_texture_array(&self) -> &DepthTargetTexture2DArray {
self.geometry_pass_depth_texture.as_ref().unwrap()
}
pub fn geometry_pass_depth_texture(&self) -> DepthTargetTexture2D {
let depth_array = self.geometry_pass_depth_texture.as_ref().unwrap();
let depth_texture = DepthTargetTexture2D::new(
&self.context,
depth_array.width(),
depth_array.height(),
Wrapping::ClampToEdge,
Wrapping::ClampToEdge,
DepthFormat::Depth32F,
)
.unwrap();
depth_array
.copy_to(
0,
CopyDestination::<u8>::DepthTexture(&depth_texture),
Viewport::new_at_origo(depth_array.width(), depth_array.height()),
)
.unwrap();
depth_texture
}
}