~tagglink/solar-system

cbbb2aac7bcc344bf892c55d1fad2bfa0675308a — Tomas Granlund 1 year, 16 days ago 1651a4d
custom render plugin renders to custom render target
6 files changed, 116 insertions(+), 33 deletions(-)

M Cargo.lock
M Cargo.toml
M rustfmt.toml
M src/main.rs
M src/render/mod.rs
A src/render/plugin.rs
M Cargo.lock => Cargo.lock +1 -0
@@ 3427,6 3427,7 @@ version = "0.1.0"
dependencies = [
 "amethyst",
 "amethyst_gltf",
 "derivative 2.2.0",
 "lazy_static",
 "serde",
]

M Cargo.toml => Cargo.toml +1 -0
@@ 11,3 11,4 @@ amethyst_gltf = { path = "amethyst/amethyst_gltf", version = "0.15.3" }
amethyst = { path = "amethyst", version = "0.15.3", features = ["vulkan"]}
serde = { version = "1.0.104", features = ["derive"] }
lazy_static = { version = "1.4" }
derivative = { version = "2.1.1" }

M rustfmt.toml => rustfmt.toml +1 -1
@@ 1,4 1,4 @@
max_width = 60
max_width = 100
hard_tabs = false
tab_spaces = 2
newline_style = "Auto"

M src/main.rs => src/main.rs +16 -29
@@ 4,36 4,31 @@ use amethyst::{
  core::transform::TransformBundle,
  input::{InputBundle, StringBindings},
  prelude::*,
  renderer::{
    plugins::RenderToWindow,
    types::DefaultBackend,
    RenderingBundle,
  },
  renderer::{bundle::Target, plugins::RenderToWindow, types::DefaultBackend, RenderingBundle},
  ui::{RenderUi, UiBundle},
  utils::{application_root_dir, auto_fov::AutoFovSystem}
  utils::{application_root_dir, auto_fov::AutoFovSystem},
};

use amethyst_gltf::GltfSceneLoaderSystemDesc;

mod body;
mod prefab;
mod render;
mod systems;
mod universe;
mod ui;
mod render;
mod universe;

use crate::{
  prefab::{GLTFPrefab, PlanetPrefab, UiPrefab},
  systems::{BodySystem, GravitySystem, ui::IndicatorSystem},
  universe::Universe,
  render::RenderCustom3D,
  systems::{ui::IndicatorSystem, BodySystem, GravitySystem},
  universe::Universe,
};

fn main() -> amethyst::Result<()> {
  amethyst::start_logger(Default::default());
  let app_root = application_root_dir()?;
  let display_config_path =
    app_root.join("config/display.ron");
  let display_config_path = app_root.join("config/display.ron");
  let key_bindings_path = app_root.join("config/keys.ron");
  let assets_dir = app_root.join("assets");



@@ 71,34 66,26 @@ fn main() -> amethyst::Result<()> {
      .with_sensitivity(0.1, 0.1)
      .with_speed(5000f32),
    )?
    .with_bundle(
      TransformBundle::new().with_dep(&["fly_movement"]),
    )?
    .with_bundle(
      InputBundle::<StringBindings>::new()
        .with_bindings_from_file(&key_bindings_path)?,
    )?
    .with_bundle(TransformBundle::new().with_dep(&["fly_movement"]))?
    .with_bundle(InputBundle::<StringBindings>::new().with_bindings_from_file(&key_bindings_path)?)?
    .with_bundle(UiBundle::<StringBindings>::new())?
    .with_bundle(
      RenderingBundle::<DefaultBackend>::new()
        .with_plugin(
          RenderToWindow::from_config_path(
            display_config_path,
          )?
          .with_clear([0.0, 0.0, 0.0, 1.0]),
          RenderToWindow::from_config_path(display_config_path)?.with_clear([0.0, 0.0, 0.0, 1.0]),
        )
        .with_plugin(RenderCustom3D::default())
        .with_plugin(RenderUi::default()),
    )?
    .with(AutoFovSystem::default(), "auto_fov", &[])
    .with(GravitySystem::new(time_scale, length_scale, mass_scale), "gravity_system", &[])
    .with(
      GravitySystem::new(time_scale, length_scale, mass_scale),
      "gravity_system",
      &[],
    )
    .with(BodySystem, "body_system", &[])
    .with(IndicatorSystem::default(), "indicator_system", &[]);
  let mut game = Application::new(
    assets_dir,
    Universe::new(),
    game_data,
  )?;
  let mut game = Application::new(assets_dir, Universe::new(), game_data)?;
  game.run();
  Ok(())
}

M src/render/mod.rs => src/render/mod.rs +4 -3
@@ 8,13 8,14 @@ use amethyst::renderer::{
    },
    shader::SpirvShader,
  },
  skinning::JointCombined,
  RenderBase3D,
  skinning::JointCombined
};

mod plugin;

use lazy_static::lazy_static;

pub type RenderCustom3D = RenderBase3D<CustomPassDef>;
pub type RenderCustom3D = plugin::CustomRenderPlugin3D<CustomPassDef>;

lazy_static! {
  static ref CUSTOM_VERTEX: SpirvShader =

A src/render/plugin.rs => src/render/plugin.rs +93 -0
@@ 0,0 1,93 @@
use amethyst::{
  core::ecs::{DispatcherBuilder, World},
  error::Error,
  renderer::{
    bundle::{
      ImageOptions, OutputColor, RenderOrder, RenderPlan, RenderPlugin, Target, TargetPlanOutputs,
    },
    mtl::StaticTextureSet,
    pass::{Base3DPassDef, DrawBase3DDesc, DrawBase3DTransparentDesc},
    rendy::{mesh::VertexFormat, shader::SpirvShader},
    visibility::VisibilitySortingSystem,
    Backend, Factory, Format, Kind, RenderGroupDesc,
  },
  window::ScreenDimensions,
};

pub trait Custom3DPassDef: 'static + std::fmt::Debug + Send + Sync {
  const NAME: &'static str;
  type TextureSet: for<'a> StaticTextureSet<'a>;
  fn vertex_shader() -> &'static SpirvShader;
  fn fragment_shader() -> &'static SpirvShader;
  fn base_format() -> Vec<VertexFormat>;
  fn skinned_format() -> Vec<VertexFormat>;
}

#[derive(derivative::Derivative)]
#[derivative(Default(bound = ""), Debug(bound = ""))]
pub struct CustomRenderPlugin3D<D: Base3DPassDef> {
  dimensions: Option<ScreenDimensions>,
  dirty: bool,
  _phantomdata: std::marker::PhantomData<D>,
}

impl<B: Backend, D: Base3DPassDef> RenderPlugin<B> for CustomRenderPlugin3D<D> {
  fn on_build<'a, 'b>(
    &mut self,
    _world: &mut World,
    builder: &mut DispatcherBuilder<'a, 'b>,
  ) -> Result<(), Error> {
    builder.add(VisibilitySortingSystem::new(), "visibility_system", &[]);
    Ok(())
  }

  #[allow(clippy::map_clone)]
  fn should_rebuild(&mut self, world: &World) -> bool {
    let new_dimensions = world.try_fetch::<ScreenDimensions>();
    if self.dimensions.as_ref() != new_dimensions.as_deref() {
      self.dirty = true;
      self.dimensions = new_dimensions.map(|d| (*d).clone());
      return false;
    }
    self.dirty
  }

  fn on_plan(
    &mut self,
    plan: &mut RenderPlan<B>,
    _factory: &mut Factory<B>,
    _world: &World,
  ) -> Result<(), Error> {
    use amethyst::renderer::rendy::hal::command::{ClearColor, ClearDepthStencil, ClearValue};

    let dimensions = self.dimensions.as_ref().unwrap();
    let image_options = ImageOptions {
      kind: Kind::D2(dimensions.width() as u32, dimensions.height() as u32, 1, 1),
      levels: 1,
      format: Format::D32Sfloat,
      clear: None,
    };
    plan.define_pass(
      Target::Custom("3D"),
      TargetPlanOutputs {
        colors: vec![OutputColor::Image(ImageOptions {
          clear: Some(ClearValue::Color(ClearColor::Sfloat([0., 0., 0., 1.]))),
          ..image_options
        })],
        depth: Some(ImageOptions {
          clear: Some(ClearValue::DepthStencil(ClearDepthStencil(0.0, 0))),
          ..image_options
        }),
      },
    )?;
    plan.extend_target(Target::Custom("3D"), move |ctx| {
      ctx.add(RenderOrder::Opaque, DrawBase3DDesc::<B, D>::new().builder())?;
      ctx.add(
        RenderOrder::Transparent,
        DrawBase3DTransparentDesc::<B, D>::new().builder(),
      )?;
      Ok(())
    });
    Ok(())
  }
}