use std::any::TypeId;
use color::rgba;
use rin_events::{Property, Stream, StreamExt};
#[cfg(gui)]
use rin_gui::ControlGeometry;
use rin_math::{Pnt2, Rect};
use rin_window::{self as window, Window, WindowExt, Events, WindowEvents};
use rin_gl as gl;
use rinecs::{EntitiesThreadLocal, Read, ResourcesThreadLocal, StorageRegistry, SystemConditionThreadLocal, SystemId, SystemThreadLocal, entity::EntityStoragesThreadLocal};
use crate::{
DeferredScene, RenderStage, RendersTo, render_stage,
bundle::UpdateRenderBarrier,
transformation::{RenderPlane, Viewport},
components::Visible
};
#[cfg(feature="gl_forward_renderer")]
use crate::renderer::{
ScreenRenderBuffer,
components::RenderPlane as GpuRenderPlane,
resources::RenderStage as GlRenderStage
};
pub struct ImmediateRenderer<R>{
pub renderer: gl::Renderer<'static>,
pub window: Window,
pub system: R,
}
impl<R: RenderSystem + 'static> crate::RendererBundle for ImmediateRenderer<R>{
type Parameters = ();
fn setup(self, world: &mut DeferredScene){
let viewport = self.window.viewport();
world.add_resource(crate::transformation::Viewport::new(viewport));
world.add_resource_thread_local(self.renderer);
let window = self.window;
world.add_resource_as_trait_thread_local(rinecs::cast!(window as dyn WindowExt));
world.add_render_system(self.system);
}
fn viewport(&mut self) -> Property<'static, Rect<i32>>{
self.window.event_stream().window().resized().map(|size| Rect{
pos: Pnt2::origin(),
width: size.x,
height: size.y,
}).to_property(self.window.viewport())
}
fn window(&self) -> Option<&Window>{
Some(&self.window)
}
fn window_mut(&mut self) -> Option<&mut Window>{
Some(&mut self.window)
}
fn event_stream(&mut self) -> Stream<'static, window::Event>{
self.window.event_stream()
}
}
pub trait RenderSystem{
fn render_to_screen(
&mut self,
gl: &gl::Renderer,
viewport: Rect<i32>,
entities: EntitiesThreadLocal,
resources: ResourcesThreadLocal)
{
self.render(gl, viewport, entities, resources)
}
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal,
resources: ResourcesThreadLocal);
fn render_stage() -> RenderStage{
RenderStage::AfterPostprocessing
}
fn renders_to(&self) -> Vec<RendersTo>{
vec![RendersTo::MainRenderSurface]
}
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionThreadLocal> where Self: Sized {
None
}
fn name() -> Option<&'static str> where Self: Sized { None }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized {
match Self::render_stage(){
RenderStage::RenderSurfaceOpaque => vec![TypeId::of::<render_stage::AfterRenderSurfaceOpaque>()],
RenderStage::AfterPostprocessingOpaque => vec![TypeId::of::<render_stage::AfterPostprocessingOpaque>()],
RenderStage::RenderSurfaceTranslucent => vec![TypeId::of::<render_stage::AfterRenderSurfaceTranslucent>()],
RenderStage::AfterPostprocessing => vec![TypeId::of::<render_stage::AfterPostprocessing>()],
RenderStage::Window => vec![TypeId::of::<render_stage::Window>()],
}
}
fn needs() -> Vec<TypeId> where Self: Sized {
match Self::render_stage(){
RenderStage::RenderSurfaceOpaque => vec![TypeId::of::<render_stage::RenderSurfaceOpaque>()],
RenderStage::AfterPostprocessingOpaque => vec![
TypeId::of::<render_stage::RenderSurfaceOpaque>(),
TypeId::of::<render_stage::AfterRenderSurfaceOpaque>(),
TypeId::of::<render_stage::PostprocessingOpaque>()
],
RenderStage::RenderSurfaceTranslucent => vec![
TypeId::of::<render_stage::RenderSurfaceOpaque>(),
TypeId::of::<render_stage::AfterRenderSurfaceOpaque>(),
TypeId::of::<render_stage::PostprocessingOpaque>(),
TypeId::of::<render_stage::RenderSurfaceTranslucent>(),
TypeId::of::<render_stage::AfterRenderSurfaceTranslucent>(),
],
RenderStage::AfterPostprocessing => vec![
TypeId::of::<render_stage::RenderSurfaceOpaque>(),
TypeId::of::<render_stage::AfterRenderSurfaceOpaque>(),
TypeId::of::<render_stage::PostprocessingOpaque>(),
TypeId::of::<render_stage::RenderSurfaceTranslucent>(),
TypeId::of::<render_stage::AfterRenderSurfaceTranslucent>(),
TypeId::of::<render_stage::Postprocessing>(),
],
RenderStage::Window => vec![
TypeId::of::<render_stage::RenderSurfaceOpaque>(),
TypeId::of::<render_stage::AfterRenderSurfaceOpaque>(),
TypeId::of::<render_stage::PostprocessingOpaque>(),
TypeId::of::<render_stage::RenderSurfaceTranslucent>(),
TypeId::of::<render_stage::AfterRenderSurfaceTranslucent>(),
TypeId::of::<render_stage::Postprocessing>(),
TypeId::of::<render_stage::AfterPostprocessing>(),
TypeId::of::<render_stage::FinalSurface>(),
TypeId::of::<render_stage::FinalSurfaceBlit>(),
],
}
}
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn runs_on_gpu() -> bool { true }
fn file_line_info(&self) -> &'static str { "" }
}
impl<F> RenderSystem for F
where F: Fn(
&gl::Renderer,
Rect<i32>,
EntitiesThreadLocal,
ResourcesThreadLocal)
{
fn render_to_screen(
&mut self,
gl: &gl::Renderer,
viewport: Rect<i32>,
entities: EntitiesThreadLocal,
resources: ResourcesThreadLocal)
{
(*self)(&gl, viewport, entities, resources)
}
fn render<S: glin::RenderSurface>(
&mut self,
_gl: &gl::Renderer<S>,
_viewport: Rect<i32>,
_entities: EntitiesThreadLocal,
_resources: ResourcesThreadLocal)
{
}
}
#[cfg(feature = "dynamic_systems")]
pub(crate) struct DynamicRenderSystem<S, R>{
render_fn_path: String,
_marker_s: PhantomData<S>,
_marker_r: PhantomData<R>,
}
#[cfg(feature = "dynamic_systems")]
impl<S,R> DynamicRenderSystem<S,R>{
pub(crate) unsafe fn new(render_fn_path: &str) -> DynamicRenderSystem<S, R>{
DynamicRenderSystem{
render_fn_path: render_fn_path.to_owned(),
_marker_r: PhantomData,
_marker_s: PhantomData,
}
}
}
#[cfg(feature = "dynamic_systems")]
impl<'a, SS: glin::RenderSurface> RenderSystem<'a> for DynamicRenderSystem<SS, render_stage::RenderSurfaceOpaque>{
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal<'a>,
resources: ResourcesThreadLocal<'a>)
{
let render_fn = unsafe {
resources.get_dynamic_symbol::<fn(_,_,_,_)>(&self.render_fn_path).unwrap()
};
render_fn(gl, viewport, entities, resources)
}
fn render_stage() -> RenderStage{
RenderStage::RenderSurfaceOpaque
}
}
#[cfg(feature = "dynamic_systems")]
impl<'a, SS: glin::RenderSurface> RenderSystem<'a> for DynamicRenderSystem<SS, render_stage::AfterPostprocessingOpaque>{
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal<'a>,
resources: ResourcesThreadLocal<'a>)
{
let render_fn = unsafe {
resources.get_dynamic_symbol::<fn(_,_,_,_)>(&self.render_fn_path).unwrap()
};
render_fn(gl, viewport, entities, resources)
}
fn render_stage() -> RenderStage{
RenderStage::AfterPostprocessingOpaque
}
}
#[cfg(feature = "dynamic_systems")]
impl<'a, SS: glin::RenderSurface> RenderSystem<'a> for DynamicRenderSystem<SS, render_stage::RenderSurfaceTranslucent>{
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal<'a>,
resources: ResourcesThreadLocal<'a>)
{
let render_fn = unsafe {
resources.get_dynamic_symbol::<fn(_,_,_,_)>(&self.render_fn_path).unwrap()
};
render_fn(gl, viewport, entities, resources)
}
fn render_stage() -> RenderStage{
RenderStage::RenderSurfaceTranslucent
}
}
#[cfg(feature = "dynamic_systems")]
impl<'a, SS: glin::RenderSurface> RenderSystem<'a> for DynamicRenderSystem<SS, render_stage::AfterPostprocessing>{
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal<'a>,
resources: ResourcesThreadLocal<'a>)
{
let render_fn = unsafe {
resources.get_dynamic_symbol::<fn(_,_,_,_)>(&self.render_fn_path).unwrap()
};
render_fn(gl, viewport, entities, resources)
}
fn render_stage() -> RenderStage{
RenderStage::AfterPostprocessing
}
}
#[cfg(feature = "dynamic_systems")]
impl<'a> RenderSystem<'a> for DynamicRenderSystem<glin::Screen, render_stage::Window>{
fn render<S: gl::RenderSurface>(
&mut self,
gl: &gl::Renderer<S>,
viewport: Rect<i32>,
entities: EntitiesThreadLocal<'a>,
resources: ResourcesThreadLocal<'a>)
{
let render_fn = unsafe {
resources.get_dynamic_symbol::<fn(_,_,_,_)>(&self.render_fn_path).unwrap()
};
render_fn(gl, viewport, entities, resources)
}
fn render_stage() -> RenderStage{
RenderStage::Window
}
}
pub struct RenderWrapper<R>(pub(crate) R);
impl<U: RenderSystem> SystemThreadLocal for RenderWrapper<U> {
fn run(&mut self, mut entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let gl = resources.get::<gl::Renderer>().unwrap();
let window = resources.as_trait::<dyn WindowExt>().unwrap();
let mut renders_to = self.0.renders_to();
if let Some(main_surface_pos) = renders_to.iter()
.position(|renders_to| *renders_to == RendersTo::MainRenderSurface)
{
renders_to.remove(main_surface_pos);
let viewport = ||{
let mut viewport = resources.get::<Viewport>().unwrap().clone();
viewport.pos.y = window.height() - viewport.height;
#[cfg(gui)]
let viewport_x = {
if let Some(gui) = resources.get::<crate::gui::Gui>(){
if *gui.visible().get(){
let pos = *gui.position().get();
let width = *gui.width().get();
(pos.x + width) as i32
}else{
0
}
}else{
0
}
};
#[cfg(not(gui))]
let viewport_x = 0;
viewport.pos.x = viewport_x;
viewport
};
macro_rules! render_to_screen{
() => {
{
let viewport = viewport();
let gl = gl.with_properties(&[gl::Property::Viewport(viewport.into())]);
self.0.render_to_screen(&gl, viewport, entities.clone(), resources.clone())
}
}
};
macro_rules! render_to_surface{
($surface: expr) => {
{
let surface = &$surface;
let gl = gl.with_fbo(surface);
self.0.render(&gl, surface.viewport().into(), entities.clone(), resources.clone())
}
}
};
match U::render_stage(){
RenderStage::RenderSurfaceOpaque => {
#[cfg(feature = "gl_forward_renderer")]
{
if let Some(mut render_surface) = resources.get_mut::<ScreenRenderBuffer>(){
render_to_surface!(**render_surface.render_buffer(GlRenderStage::AfterOpaque));
}else{
render_to_screen!();
}
}
#[cfg(not(feature = "gl_forward_renderer"))]
render_to_screen!();
},
RenderStage::AfterPostprocessingOpaque => {
#[cfg(feature = "gl_forward_renderer")]
{
if let Some(mut render_surface) = resources.get_mut::<ScreenRenderBuffer>(){
let needs_clear = render_surface.last_stage() != GlRenderStage::AfterOpaquePostprocess;
let surface = render_surface.color_depth_only_fbo(GlRenderStage::AfterOpaquePostprocess);
let gl = gl.with_fbo(&surface);
if needs_clear {
gl.clear_color(&rgba!(0.0, 0.0, 0.0, 0.0));
}
self.0.render(&gl, surface.viewport().into(), entities.clone(), resources.clone())
}else{
render_to_screen!();
}
}
#[cfg(not(feature = "gl_forward_renderer"))]
render_to_screen!();
},
RenderStage::RenderSurfaceTranslucent => {
#[cfg(feature = "gl_forward_renderer")]
{
if let Some(mut render_surface) = resources.get_mut::<ScreenRenderBuffer>(){
render_to_surface!(render_surface.color_depth_only_fbo(GlRenderStage::AfterTranslucent));
}else{
render_to_screen!();
}
}
#[cfg(not(feature = "gl_forward_renderer"))]
render_to_screen!();
},
RenderStage::AfterPostprocessing => {
#[cfg(feature = "gl_forward_renderer")]
{
if let Some(mut render_surface) = resources.get_mut::<ScreenRenderBuffer>(){
let needs_clear = render_surface.last_stage() != GlRenderStage::AfterFinalPostprocess;
let surface = render_surface.color_depth_only_fbo(GlRenderStage::AfterFinalPostprocess);
let gl = gl.with_fbo(&surface);
if needs_clear {
gl.clear_color(&rgba!(0.0, 0.0, 0.0, 0.0));
}
self.0.render(&gl, surface.viewport().into(), entities.clone(), resources.clone())
}else{
render_to_screen!();
}
}
#[cfg(not(feature = "gl_forward_renderer"))]
render_to_screen!();
},
RenderStage::Window => render_to_screen!(),
}
}
#[cfg(feature = "gl_forward_renderer")]
{
let storage = entities.storage_for::<(
Read<RenderPlane>,
Read<GpuRenderPlane>,
Read<Visible>)>();
for (renderplanes, gpu_renderplanes, visible) in storage.iter_for_entities(renders_to.iter().map(|p| p.entity().unwrap()))
{
if !visible.is_visible(){
continue
}
for (renderplane, gpu) in renderplanes.iter().zip(gpu_renderplanes){
let gl = gl.with_fbo(&gpu.fbo);
let gl = gl.with_mvp(renderplane.camera_matrices().clone());
let entities = &entities as *const EntitiesThreadLocal as *mut EntitiesThreadLocal;
self.0.render(
&gl,
gpu.fbo.viewport().into(),
unsafe{ (*entities).clone() },
resources.clone()
)
}
}
}
}
fn checks(e: &mut StorageRegistry) -> Option<SystemConditionThreadLocal> where Self: Sized {
U::checks(e)
}
fn name() -> Option<&'static str> where Self: Sized { U::name() }
fn before() -> Vec<SystemId> where Self: Sized { U::before() }
fn after() -> Vec<SystemId> where Self: Sized {
let mut after = U::after();
after.push(SystemId::barrier::<UpdateRenderBarrier>());
after
}
fn updates() -> Vec<TypeId> where Self: Sized {
let mut updates = U::updates();
#[cfg(any(feature="web", feature="desktop", feature="desktop_gles"))]
updates.push(TypeId::of::<Window>());
updates
}
fn needs() -> Vec<TypeId> where Self: Sized { U::needs() }
fn reads() -> Vec<TypeId> where Self: Sized {
let mut reads = U::reads();
reads.extend_from_slice(&[
TypeId::of::<RenderPlane>(),
#[cfg(feature="gl_forward_renderer")]
TypeId::of::<GpuRenderPlane>(),
TypeId::of::<Visible>(),
TypeId::of::<Viewport>(),
TypeId::of::<gl::Renderer>(),
TypeId::of::<dyn WindowExt>(),
#[cfg(gui)]
TypeId::of::<crate::gui::Gui>(),
]);
reads
}
fn writes() -> Vec<TypeId> where Self: Sized {
let mut writes = U::writes();
#[cfg(feature="gl_forward_renderer")]
writes.extend_from_slice(&[
TypeId::of::<ScreenRenderBuffer>()
]);
writes
}
fn runs_on_gpu() -> bool { U::runs_on_gpu() }
fn file_line_info(&self) -> &'static str { self.0.file_line_info() }
}