use crate::{
fyrox::{
core::{color::Color, pool::Handle, sstorage::ImmutableString},
fxhash::FxHashSet,
graph::SceneGraph,
graphics::{
error::FrameworkError,
framebuffer::{Attachment, GpuFrameBuffer},
gpu_texture::PixelKind,
server::GraphicsServer,
},
renderer::{
bundle::{BundleRenderContext, RenderContext, RenderDataBundleStorage},
cache::shader::{
binding, property, PropertyGroup, RenderMaterial, RenderPassContainer,
},
make_viewport_matrix, RenderPassStatistics, SceneRenderPass, SceneRenderPassContext,
},
scene::{node::Node, Scene},
},
Editor,
};
use std::{any::TypeId, cell::RefCell, rc::Rc};
pub struct HighlightRenderPass {
framebuffer: GpuFrameBuffer,
edge_detect_shader: RenderPassContainer,
pub scene_handle: Handle<Scene>,
pub nodes_to_highlight: FxHashSet<Handle<Node>>,
}
impl HighlightRenderPass {
fn create_frame_buffer(
server: &dyn GraphicsServer,
mut width: usize,
mut height: usize,
) -> GpuFrameBuffer {
width = width.max(1);
height = height.max(1);
let depth_stencil = server
.create_2d_render_target("HighlightDepthStencil", PixelKind::D24S8, width, height)
.unwrap();
let frame_texture = server
.create_2d_render_target("HighlightFrameTexture", PixelKind::RGBA8, width, height)
.unwrap();
server
.create_frame_buffer(
Some(Attachment::depth_stencil(depth_stencil)),
vec![Attachment::color(frame_texture)],
)
.unwrap()
}
pub fn new_raw(server: &dyn GraphicsServer, width: usize, height: usize) -> Self {
Self {
framebuffer: Self::create_frame_buffer(server, width, height),
edge_detect_shader: RenderPassContainer::from_str(
server,
include_str!("../resources/shaders/highlight.shader"),
)
.unwrap(),
scene_handle: Default::default(),
nodes_to_highlight: Default::default(),
}
}
pub fn new(server: &dyn GraphicsServer, width: usize, height: usize) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self::new_raw(server, width, height)))
}
pub fn resize(&mut self, server: &dyn GraphicsServer, width: usize, height: usize) {
self.framebuffer = Self::create_frame_buffer(server, width, height);
}
}
impl SceneRenderPass for HighlightRenderPass {
fn on_ldr_render(
&mut self,
ctx: SceneRenderPassContext,
) -> Result<RenderPassStatistics, FrameworkError> {
let mut stats = RenderPassStatistics::default();
if self.scene_handle != ctx.scene_handle {
return Ok(Default::default());
}
{
let render_pass_name = ImmutableString::new("Forward");
let mut render_bundle_storage =
RenderDataBundleStorage::new_empty(ctx.observer.position.clone());
let mut render_context = RenderContext {
render_mask: ctx.observer.render_mask,
elapsed_time: ctx.elapsed_time,
observer_position: &ctx.observer.position,
frustum: Some(&ctx.observer.frustum),
storage: &mut render_bundle_storage,
graph: &ctx.scene.graph,
render_pass_name: &render_pass_name,
dynamic_surface_cache: ctx.dynamic_surface_cache,
};
for &root_node_handle in self.nodes_to_highlight.iter() {
if ctx.scene.graph.is_valid_handle(root_node_handle) {
for (_, node) in ctx.scene.graph.traverse_iter(root_node_handle) {
node.collect_render_data(&mut render_context);
}
}
}
render_bundle_storage.sort();
self.framebuffer.clear(
ctx.observer.viewport,
Some(Color::TRANSPARENT),
Some(1.0),
None,
);
stats += render_bundle_storage.render_to_frame_buffer(
ctx.server,
ctx.geometry_cache,
ctx.shader_cache,
|_| true,
|_| true,
BundleRenderContext {
texture_cache: ctx.texture_cache,
render_pass_name: &render_pass_name,
frame_buffer: &self.framebuffer,
use_pom: false,
light_position: &Default::default(),
renderer_resources: ctx.renderer_resources,
ambient_light: Default::default(),
scene_depth: Some(ctx.depth_texture),
viewport: ctx.observer.viewport,
uniform_memory_allocator: ctx.uniform_memory_allocator,
resource_manager: ctx.resource_manager,
},
)?;
}
{
let frame_matrix = make_viewport_matrix(ctx.observer.viewport);
let frame_texture = &self.framebuffer.color_attachments()[0].texture;
let color = Color::ORANGE.as_frgba();
let properties = PropertyGroup::from([
property("worldViewProjection", &frame_matrix),
property("color", &color),
]);
let material = RenderMaterial::from([
binding(
"frameTexture",
(frame_texture, &ctx.renderer_resources.nearest_clamp_sampler),
),
binding("properties", &properties),
]);
stats += self.edge_detect_shader.run_pass(
1,
&ImmutableString::new("Primary"),
ctx.framebuffer,
&ctx.renderer_resources.quad,
ctx.observer.viewport,
&material,
ctx.uniform_buffer_cache,
Default::default(),
None,
)?;
}
Ok(Default::default())
}
fn source_type_id(&self) -> TypeId {
TypeId::of::<Editor>()
}
}