use log::LevelFilter;
use crate::features::{ExampleRenderFeature, ExampleRenderFeaturePlugin};
use crate::phases::OpaqueRenderPhase;
use glam::Vec3;
use legion::{Resources, World};
use rafx::api::*;
use rafx::assets::AssetManager;
use rafx::assets::AssetResource;
use rafx::framework::render_features::{
ExtractResources, RenderFeatureFlagMask, RenderFeatureMaskBuilder, RenderPhaseMaskBuilder,
RenderRegistry, RenderViewDepthRange,
};
use rafx::framework::visibility::VisibilityResource;
use rafx::rafx_visibility::{DepthRange, OrthographicParameters, Projection};
use rafx::renderer::{
AssetSource, RenderViewMeta, Renderer, RendererBuilder, RendererConfigResource,
SwapchainHandler, ViewportsResource,
};
use std::sync::Arc;
use std::time;
use std::time::Duration;
mod example_plugin;
use example_plugin::ExampleRendererPipelinePlugin;
mod features;
mod phases;
const WINDOW_WIDTH: u32 = 900;
const WINDOW_HEIGHT: u32 = 600;
#[derive(Clone)]
pub struct TimeState {
app_start_instant: time::Instant,
now_instant: time::Instant,
}
impl TimeState {
pub fn new() -> TimeState {
let now_instant = time::Instant::now();
TimeState {
app_start_instant: now_instant,
now_instant,
}
}
pub fn update(&mut self) {
self.now_instant = time::Instant::now();
}
pub fn total_time(&self) -> time::Duration {
self.now_instant.duration_since(self.app_start_instant)
}
pub fn current_instant(&self) -> time::Instant {
self.now_instant
}
}
fn main() {
env_logger::Builder::from_default_env()
.default_format_timestamp_nanos(true)
.filter_level(LevelFilter::Info)
.init();
run().unwrap();
}
fn run() -> RafxResult<()> {
let sdl2_systems = sdl2_init();
let api = unsafe {
RafxApi::new(
&sdl2_systems.window,
&sdl2_systems.window,
&Default::default(),
)?
};
let mut resources = Resources::default();
resources.insert(TimeState::new());
{
let sdl2_window = &sdl2_systems.window;
resources.insert(VisibilityResource::new());
resources.insert(ViewportsResource::default());
let demo_render_feature_plugin = Arc::new(ExampleRenderFeaturePlugin::default());
demo_render_feature_plugin.legion_init(&mut resources);
let mut renderer_builder = RendererBuilder::default();
renderer_builder = renderer_builder.add_render_feature_plugin(demo_render_feature_plugin);
let mut renderer_builder_result = {
let extract_resources = ExtractResources::default();
let pipeline_plugin = Arc::new(ExampleRendererPipelinePlugin);
let assets_build_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../demo-editor/data/build_data");
renderer_builder.build(
extract_resources,
&api,
AssetSource::BuildDir(assets_build_dir),
pipeline_plugin,
|| None,
)
}?;
let (width, height) = sdl2_window.vulkan_drawable_size();
let swapchain_def = RafxSwapchainDef {
width,
height,
enable_vsync: true,
color_space_priority: vec![RafxSwapchainColorSpace::Srgb],
};
let swapchain_helper = SwapchainHandler::create_swapchain(
&mut renderer_builder_result.asset_manager,
&mut renderer_builder_result.renderer,
sdl2_window,
sdl2_window,
&swapchain_def,
)?;
resources.insert(api.device_context());
resources.insert(api);
resources.insert(swapchain_helper);
resources.insert(renderer_builder_result.asset_resource);
resources.insert(
renderer_builder_result
.asset_manager
.resource_manager()
.render_registry()
.clone(),
);
resources.insert(renderer_builder_result.asset_manager);
resources.insert(renderer_builder_result.renderer);
resources.insert(RendererConfigResource::default());
let mut world = World::default();
let main_view_frustum = {
let mut visibility_resource = resources.get_mut::<VisibilityResource>().unwrap();
visibility_resource.register_view_frustum()
};
log::info!("Starting window event loop");
let mut event_pump = sdl2_systems
.context
.event_pump()
.expect("Could not create sdl event pump");
'running: loop {
if !process_input(&mut event_pump) {
break 'running;
}
{
let mut viewports_resource = resources.get_mut::<ViewportsResource>().unwrap();
let (width, height) = sdl2_systems.window.vulkan_drawable_size();
viewports_resource.main_window_size = RafxExtents2D { width, height };
let main_camera_phase_mask = RenderPhaseMaskBuilder::default()
.add_render_phase::<OpaqueRenderPhase>()
.build();
let main_camera_feature_mask = RenderFeatureMaskBuilder::default()
.add_render_feature::<ExampleRenderFeature>()
.build();
const CAMERA_Z: f32 = 1000.0;
let eye = Vec3::new(0., 0., CAMERA_Z);
let half_width = viewports_resource.main_window_size.width as f32 / 2.0;
let half_height = viewports_resource.main_window_size.height as f32 / 2.0;
let look_at = Vec3::ZERO;
let up = Vec3::Y;
let view = glam::Mat4::look_at_rh(eye, look_at, up);
let near = 0.01;
let far = 2000.0;
let projection = Projection::Orthographic(OrthographicParameters::new(
-half_width,
half_width,
-half_height,
half_height,
near,
far,
DepthRange::InfiniteReverse,
));
main_view_frustum
.set_projection(&projection)
.set_transform(eye, look_at, up);
viewports_resource.main_view_meta = Some(RenderViewMeta {
view_frustum: main_view_frustum.clone(),
eye_position: eye,
view,
proj: projection.as_rh_mat4(),
depth_range: RenderViewDepthRange::from_projection(&projection),
render_phase_mask: main_camera_phase_mask,
render_feature_mask: main_camera_feature_mask,
render_feature_flag_mask: RenderFeatureFlagMask::empty(),
debug_name: "main".to_string(),
})
}
{
let mut time_state = resources.get_mut::<TimeState>().unwrap();
time_state.update();
}
{
let mut asset_resource = resources.get_mut::<AssetResource>().unwrap();
asset_resource.update();
}
{
let mut asset_manager = resources.get_mut::<AssetManager>().unwrap();
asset_manager.update_asset_loaders().unwrap();
}
{
let renderer = resources.get::<Renderer>().unwrap();
let mut extract_resources = ExtractResources::default();
macro_rules! add_to_extract_resources {
($ty: ident) => {
#[allow(non_snake_case)]
let mut $ty = resources.get_mut::<$ty>().unwrap();
extract_resources.insert(&mut *$ty);
};
($ty: path, $name: ident) => {
let mut $name = resources.get_mut::<$ty>().unwrap();
extract_resources.insert(&mut *$name);
};
}
add_to_extract_resources!(VisibilityResource);
add_to_extract_resources!(RafxSwapchainHelper);
add_to_extract_resources!(ViewportsResource);
add_to_extract_resources!(AssetManager);
add_to_extract_resources!(AssetResource);
add_to_extract_resources!(TimeState);
add_to_extract_resources!(RendererConfigResource);
extract_resources.insert(&mut world);
renderer.start_rendering_next_frame(
&mut extract_resources,
Duration::from_secs_f32(1.0 / 60.0),
)?;
}
}
}
{
{
let swapchain_helper = resources.remove::<RafxSwapchainHelper>().unwrap();
let mut asset_manager = resources.get_mut::<AssetManager>().unwrap();
let renderer = resources.get::<Renderer>().unwrap();
SwapchainHandler::destroy_swapchain(swapchain_helper, &mut *asset_manager, &*renderer)?;
}
resources.remove::<Renderer>();
ExampleRenderFeaturePlugin::legion_destroy(&mut resources);
resources.remove::<RenderRegistry>();
resources.remove::<AssetResource>();
resources.remove::<AssetManager>();
resources.remove::<RafxDeviceContext>();
}
let mut api = resources.remove::<RafxApi>().unwrap();
std::mem::drop(resources);
api.destroy()?;
Ok(())
}
pub struct Sdl2Systems {
pub context: sdl2::Sdl,
pub video_subsystem: sdl2::VideoSubsystem,
pub window: sdl2::video::Window,
}
pub fn sdl2_init() -> Sdl2Systems {
let context = sdl2::init().expect("Failed to initialize sdl2");
let video_subsystem = context
.video()
.expect("Failed to create sdl video subsystem");
let mut window_binding = video_subsystem.window("Rafx Example", WINDOW_WIDTH, WINDOW_HEIGHT);
let window_builder = window_binding
.position_centered()
.allow_highdpi()
.resizable();
#[cfg(target_os = "macos")]
let window_builder = window_builder.metal_view();
let window = window_builder.build().expect("Failed to create window");
Sdl2Systems {
context,
video_subsystem,
window,
}
}
fn process_input(event_pump: &mut sdl2::EventPump) -> bool {
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } => return false,
Event::KeyDown {
keycode: Some(keycode),
keymod: _modifiers,
..
} => {
if keycode == Keycode::Escape {
return false;
}
}
_ => {}
}
}
true
}