Start reordering code to fit into new ecs concept

This commit is contained in:
Michael Hübner 2025-02-26 14:51:44 +01:00
parent d6469c9181
commit a7bbf4c7d3
18 changed files with 262 additions and 481 deletions

View file

@ -11,6 +11,7 @@ assetpath = { workspace = true }
anyhow = { workspace = true }
presentation = { path = "../presentation" }
ecs = { path = "../ecs" }
[target.'cfg(target_os = "linux")'.dependencies]
shared_library = { workspace = true }

View file

@ -6,6 +6,7 @@ use super::vulkancore::VulkanCore;
#[cfg(feature = "sound")]
use audio::SoundHandler;
use ecs::World;
use crate::prelude::*;
use anyhow::Result;
@ -39,16 +40,7 @@ pub struct Context {
os_specific: OsSpecific,
application_start_time: Instant,
context_object: Arc<RwLock<Option<Box<dyn ContextObject + Send + Sync>>>>,
fallback: Mutex<Option<Box<dyn Fn(anyhow::Error) -> Result<()> + Send + Sync>>>,
push_events: Mutex<Vec<Box<dyn FnOnce() -> Result<()> + Send + Sync>>>,
// queue timer
last_check: Mutex<Duration>,
fallback: Option<Box<dyn Fn(anyhow::Error) -> Result<()> + Send + Sync>>,
}
impl Context {
@ -56,20 +48,6 @@ impl Context {
ContextBuilder::default()
}
pub fn set_context_object<C>(&self, context_object: Option<C>)
where
C: ContextObject + Send + Sync + 'static,
{
let tmp = self.context_object.clone();
self.push_event(move || {
*tmp.write().unwrap() =
context_object.map(|c| Box::new(c) as Box<dyn ContextObject + Send + Sync>);
Ok(())
})
}
pub fn window_config(&self) -> WindowConfig<'_> {
match self.presentation.backend() {
PresentationBackend::Window(wsi) => WindowConfig::new(wsi),
@ -82,30 +60,25 @@ impl Context {
}
}
pub fn push_event(&self, event: impl FnOnce() -> Result<()> + 'static + Send + Sync) {
self.push_events.lock().unwrap().push(Box::new(event));
}
#[cfg(feature = "sound")]
pub fn sound(&self) -> MutexGuard<'_, SoundHandler> {
self.sound_handler.lock().unwrap()
}
pub fn run(&self) -> Result<()> {
pub fn run<C>(&self, world: &mut World) -> Result<()> {
'running: loop {
let render_core = self.render_core.clone();
match self.presentation.poll_events(
|event| {
if let Some(ctx_obj) = &mut *self.context_object.write().unwrap() {
ctx_obj.event(event)?;
}
// TODO
// if let Some(ctx_obj) = world.resources.get_mut_opt::<C>() {
// ctx_obj.event(event)?;
// }
Ok(())
},
{
let render_core = self.render_core.clone();
move |w, h| render_core.write().unwrap().resize(w, h)
},
|w, h| render_core.write().unwrap().resize(world, w, h),
) {
Ok(res) => {
if !res {
@ -113,24 +86,17 @@ impl Context {
}
}
Err(err) => {
if let Some(fallback) = self.fallback.lock().unwrap().as_ref() {
if let Some(fallback) = &self.fallback {
(fallback)(err)?;
}
}
}
if let Err(err) = self.update() {
if let Some(fallback) = &self.fallback.lock().unwrap().as_ref() {
(fallback)(err)?;
}
}
if !self.render_core_mut().next_frame()? {
if !self.render_core_mut().next_frame(world)? {
break 'running;
}
}
*self.context_object.write().unwrap() = None;
self.render_core_mut().clear_post_processing_routines();
Ok(())
@ -144,11 +110,11 @@ impl Context {
self.render_core.write().unwrap()
}
pub fn set_fallback<F>(&self, fallback: F)
pub fn set_fallback<F>(&mut self, fallback: F)
where
F: Fn(anyhow::Error) -> Result<()> + 'static + Send + Sync,
{
*self.fallback.lock().unwrap() = Some(Box::new(fallback));
self.fallback = Some(Box::new(fallback));
}
pub fn close(&self) -> Result<()> {
@ -163,10 +129,6 @@ impl Context {
self.core.queue()
}
pub fn time(&self) -> Duration {
self.application_start_time.elapsed()
}
pub fn controllers(&self) -> RwLockReadGuard<'_, Vec<Arc<RwLock<Controller>>>> {
self.presentation.event_system().controllers()
}
@ -188,42 +150,6 @@ impl std::fmt::Debug for Context {
}
}
impl Context {
#[inline]
fn update(&self) -> Result<()> {
if let Some(ctx_obj) = &mut *self.context_object.write().unwrap() {
if let Err(err) = ctx_obj.update() {
return Err(err);
}
}
let mut events = Vec::new();
{
let mut push_events_lock = self.push_events.lock().unwrap();
mem::swap(&mut events, &mut push_events_lock);
}
for event in events {
event()?;
}
let one_second = Duration::from_secs(1);
let mut last_check = self.last_check.lock().unwrap();
if (self.time() - *last_check) > one_second {
*last_check += one_second;
#[cfg(feature = "sound")]
{
self.sound().check_clear_queue()?;
}
}
Ok(())
}
}
impl ContextInterface for Context {
fn device(&self) -> &Arc<Device> {
self.device()
@ -465,19 +391,10 @@ impl ContextBuilder {
self
}
pub fn build<F, SCENE>(self, create_scene: F) -> Result<Arc<Context>>
where
SCENE: TScene + 'static,
F: FnOnce(
&Arc<Device>,
&Arc<Mutex<Queue>>,
(f32, f32),
&TargetMode<Vec<Arc<Image>>>,
) -> Result<SCENE>,
{
pub fn build<S: TScene + 'static>(self) -> Result<Context> {
if self.enable_backtrace {
// set environment variable for Rust-debug-trace
set_var("RUST_BACKTRACE", "1");
unsafe { set_var("RUST_BACKTRACE", "1") };
}
#[cfg(feature = "openxr")]
@ -515,12 +432,11 @@ impl ContextBuilder {
let os_specific = OsSpecific::new(&self.os_specific_config);
let (render_core, _target_mode) = create_render_core(
let (render_core, _target_mode) = create_render_core::<S>(
&presentation,
core.device(),
core.queue(),
self.render_core_create_info,
create_scene,
)?;
if self.enable_mouse {
@ -535,7 +451,7 @@ impl ContextBuilder {
presentation.event_system().enable_controller();
}
Ok(Arc::new(Context {
Ok(Context {
core,
presentation,
render_core: Arc::new(RwLock::new(render_core)),
@ -545,16 +461,8 @@ impl ContextBuilder {
os_specific,
application_start_time: Instant::now(),
context_object: Arc::new(RwLock::new(None)),
fallback: Mutex::new(None),
push_events: Mutex::new(Vec::new()),
last_check: Mutex::new(Duration::from_secs(0)),
}))
fallback: None,
})
}
#[cfg(feature = "openxr")]
@ -568,13 +476,14 @@ impl ContextBuilder {
fn get_vr_mode(&self) -> Option<VRMode> {
#[cfg(any(feature = "openvr", feature = "openxr"))]
// if we requested a VR mode, check if it is available
match self.vr_mode {
Some(vr_mode) => {
return self
.vr_mode
.map(|vr_mode| {
let available_vr_modes = PresentationCore::enabled_vr_modes();
// if requested VR mode is enabled, use it
if available_vr_modes.contains(&vr_mode) {
return Some(vr_mode);
Some(vr_mode)
}
// fallback to the first available
else if !available_vr_modes.is_empty() {
@ -585,19 +494,16 @@ impl ContextBuilder {
vr_mode, mode
);
return Some(mode);
Some(mode)
}
// use default desktop, as last resort
else {
println!("No VRMode present, fallback to Window");
return None;
None
}
}
None => {
return None;
}
}
})
.flatten();
#[cfg(not(any(feature = "openvr", feature = "openxr")))]
None

View file

@ -29,17 +29,23 @@ impl Resources {
}
pub fn get<T: Any + Send + Sync>(&self) -> &T {
self.get_opt::<T>().unwrap()
}
pub fn get_opt<T: Any + Send + Sync>(&self) -> Option<&T> {
self.map
.get(&TypeId::of::<T>())
.map(|any| Self::downcast_ref_unchecked(any))
.unwrap()
}
pub fn get_mut<T: Any + Send + Sync>(&mut self) -> &mut T {
self.get_mut_opt::<T>().unwrap()
}
pub fn get_mut_opt<T: Any + Send + Sync>(&mut self) -> Option<&mut T> {
self.map
.get_mut(&TypeId::of::<T>())
.map(|any| Self::downcast_mut_unchecked(any))
.unwrap()
}
pub fn multi_mut(&mut self) -> ResourceMultiMut<'_> {

View file

@ -14,6 +14,16 @@ pub struct WorldBuilder {
pub(crate) updates: Updates,
pub events: Events,
pub resources: Resources,
systems: Vec<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync + 'static>>,
}
impl WorldBuilder {
pub fn add_system<F>(&mut self, f: F)
where
F: Fn(&mut World) -> Result<()> + Send + Sync + 'static,
{
self.systems.push(Box::new(f));
}
}
impl WorldBuilder {
@ -31,6 +41,8 @@ impl WorldBuilder {
entity_object_manager: Default::default(),
start_time: Instant::now(),
systems: self.systems,
}
}
}
@ -53,6 +65,8 @@ pub struct World {
entity_object_manager: EntityObjectManager,
start_time: Instant,
systems: Vec<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync + 'static>>,
}
impl World {
@ -61,6 +75,7 @@ impl World {
updates: Default::default(),
events: Default::default(),
resources: Default::default(),
systems: Default::default(),
}
}
@ -311,7 +326,10 @@ impl World {
impl World {
pub fn run(&mut self) -> Result<()> {
let systems = std::mem::take(&mut self.systems);
loop {
// we need to take all events because of borrowing rules
let mut events = self.events.take_events();
events.fire_events(self)?;
@ -325,6 +343,10 @@ impl World {
}
self.commit_entity_changes()?;
for system in systems.iter() {
system(self)?;
}
}
}
}

View file

@ -72,8 +72,9 @@ impl context::prelude::PostProcess for GuiPostProcess {
}
}
struct GraphicsObjects {
context: Arc<Context>,
pub struct Engine {
engine_settings: Arc<EngineSettings>,
gui_handler: Arc<GuiHandler>,
gui_post_process: Arc<GuiPostProcess>,
input: Arc<RwLock<Input>>,
@ -84,24 +85,8 @@ struct GraphicsObjects {
resource_base_path: String,
}
impl Drop for GraphicsObjects {
fn drop(&mut self) {
self.context
.render_core()
.remove_post_processing_routine(self.gui_post_process.clone());
}
}
pub struct Engine {
engine_settings: Arc<EngineSettings>,
graphical: GraphicsObjects,
entity_object_manager: EntityObjectManager,
}
impl Engine {
pub fn new(#[allow(unused)] mut create_info: EngineCreateInfo<'_>) -> Result<Arc<Self>> {
pub fn new(#[allow(unused)] mut create_info: EngineCreateInfo<'_>) -> Result<Self> {
if let Font::Path(path) = &mut create_info.gui_info.font {
path.set_prefix(&create_info.resource_base_path);
}
@ -193,17 +178,7 @@ impl Engine {
context_builder = context_builder.enable_backtrace();
}
context_builder.build(|device, queue, window_extents, images| {
Scene::new(
device,
queue,
window_extents,
images,
create_info.rasterizer_info,
create_info.raytracing_info,
create_info.graphics_info,
)
})?
context_builder.build::<Scene>()?
};
// update sound handler center
@ -234,97 +209,41 @@ impl Engine {
create_info.resource_base_path.clone(),
)?);
let engine = Arc::new(Engine {
graphical: {
let asset_manager = AssetManager::new(engine_settings.clone())?;
let asset_manager = AssetManager::new(engine_settings.clone())?;
let gui_handler = GuiHandler::new(
create_info.gui_info,
&(context.clone() as Arc<dyn ContextInterface>),
)?;
let gui_handler = GuiHandler::new(
create_info.gui_info,
&(context.clone() as Arc<dyn ContextInterface>),
)?;
// default keyboard navigation
let mut direction_mapping = HashMap::new();
// direction_mapping.insert(Keycode::A, GuiDirection::Left);
// direction_mapping.insert(Keycode::D, GuiDirection::Right);
// direction_mapping.insert(Keycode::W, GuiDirection::Up);
// direction_mapping.insert(Keycode::S, GuiDirection::Down);
direction_mapping.insert(Keycode::Left, GuiDirection::Left);
direction_mapping.insert(Keycode::Right, GuiDirection::Right);
direction_mapping.insert(Keycode::Up, GuiDirection::Up);
direction_mapping.insert(Keycode::Down, GuiDirection::Down);
// default keyboard navigation
let mut direction_mapping = HashMap::new();
// direction_mapping.insert(Keycode::A, GuiDirection::Left);
// direction_mapping.insert(Keycode::D, GuiDirection::Right);
// direction_mapping.insert(Keycode::W, GuiDirection::Up);
// direction_mapping.insert(Keycode::S, GuiDirection::Down);
direction_mapping.insert(Keycode::Left, GuiDirection::Left);
direction_mapping.insert(Keycode::Right, GuiDirection::Right);
direction_mapping.insert(Keycode::Up, GuiDirection::Up);
direction_mapping.insert(Keycode::Down, GuiDirection::Down);
let input = Input { direction_mapping };
let input = Input { direction_mapping };
let gui_post_process = Arc::new(GuiPostProcess(gui_handler.clone()));
context
.render_core()
.add_post_processing_routine(gui_post_process.clone());
let gui_post_process = Arc::new(GuiPostProcess(gui_handler.clone()));
context
.render_core()
.add_post_processing_routine(gui_post_process.clone());
GraphicsObjects {
context,
gui_post_process,
gui_handler,
input: Arc::new(RwLock::new(input)),
Ok(Engine {
gui_post_process,
gui_handler,
input: Arc::new(RwLock::new(input)),
asset_manager: RwLock::new(asset_manager),
asset_manager: RwLock::new(asset_manager),
resource_base_path: create_info.resource_base_path,
}
},
entity_object_manager: EntityObjectManager::default(),
resource_base_path: create_info.resource_base_path,
engine_settings,
});
Ok(engine)
}
fn convert_scene_ref(tscene: &Box<dyn TScene>) -> Option<NonNull<Scene>> {
unsafe {
let ptr_to_ptr: *const *mut Scene =
std::mem::transmute(destructure_traitobject::data(tscene as *const _));
NonNull::new(*ptr_to_ptr)
}
}
pub fn scene(&self) -> &Scene {
unsafe {
Self::convert_scene_ref(self.graphical.context.render_core_mut().scene_mut())
.unwrap()
.as_ref()
}
}
pub fn on_scene<'a, F>(&'a self, f: F) -> Result<()>
where
F: FnOnce(&Scene) -> Result<()> + 'a,
{
f(unsafe {
Self::convert_scene_ref(self.graphical.context.render_core().scene())
.unwrap()
.as_ref()
})
}
pub fn scene_mut(&self) -> &mut Scene {
unsafe {
Self::convert_scene_ref(self.graphical.context.render_core_mut().scene_mut())
.unwrap()
.as_mut()
}
}
pub fn on_scene_mut<'a, F>(&'a self, f: F) -> Result<()>
where
F: FnOnce(&mut Scene) -> Result<()> + 'a,
{
f(unsafe {
Self::convert_scene_ref(self.graphical.context.render_core_mut().scene_mut())
.unwrap()
.as_mut()
})
}
@ -360,17 +279,6 @@ impl Engine {
LoadingScreen::load(self.context(), gui, loader, on_ready)
}
pub fn set_fallback<F>(&self, fallback: F)
where
F: Fn(anyhow::Error) -> anyhow::Result<()> + 'static + Send + Sync,
{
self.context().set_fallback(fallback);
}
pub fn run(self: &Arc<Engine>) -> Result<()> {
self.graphical.context.run()
}
pub fn new_point_light(&self) -> Result<Light> {
Light::point_light(self.context().device())
}
@ -383,42 +291,6 @@ impl Engine {
Light::spot_light(self.context().device())
}
pub fn window_config(&self) -> WindowConfig<'_> {
self.context().window_config()
}
pub fn quit(&self) -> Result<()> {
self.context().close()
}
pub fn gui_handler(&self) -> &Arc<GuiHandler> {
&self.graphical.gui_handler
}
pub fn device(&self) -> &Arc<Device> {
self.context().device()
}
pub fn queue(&self) -> &Arc<Mutex<Queue>> {
self.context().queue()
}
pub fn sound(&self) -> MutexGuard<'_, SoundHandler> {
self.context().sound()
}
pub fn controllers(&self) -> RwLockReadGuard<'_, Vec<Arc<RwLock<Controller>>>> {
self.context().controllers()
}
pub fn active_controller(&self) -> Result<Option<Arc<RwLock<Controller>>>> {
self.context().active_controller()
}
pub fn set_active_controller(&self, controller: &Arc<RwLock<Controller>>) {
self.context().set_active_controller(controller);
}
pub fn controller_icon(&self, button: ControllerButton) -> Result<Arc<Image>> {
Ok(self.settings().controller_icon(self, button)?.unwrap_or(
self.settings()
@ -426,12 +298,8 @@ impl Engine {
))
}
pub fn context(&self) -> &Arc<Context> {
&self.graphical.context
}
pub fn build_path(&self, path: &str) -> AssetPath {
(self.graphical.resource_base_path.as_str(), path).into()
(self.resource_base_path.as_str(), path).into()
}
pub fn assets(&self) -> AssetHandler<'_> {
@ -455,3 +323,11 @@ impl Engine {
&self.engine_settings
}
}
impl Drop for Engine {
fn drop(&mut self) {
self.context
.render_core()
.remove_post_processing_routine(self.gui_post_process.clone());
}
}

View file

@ -341,16 +341,71 @@ impl Scene {
(((v + 1.0) / 2.0) * max) as i32
}
pub fn world_to_screen_space(&self, world_space: Vector3<f32>) -> Result<(i32, i32)> {
Self::_world_to_screen_space(
(self.screen_width, self.screen_height),
world_space,
self.view(),
)
}
pub fn screen_space_to_world(&self, x: u32, y: u32) -> Result<Option<Vector3<f32>>> {
let scale = self.renderer.render_scale();
self.renderer
.screen_to_world((x as f32 * scale) as u32, (y as f32 * scale) as u32)
}
pub fn particle_system_vulkan_objects_mut(&mut self) -> &mut ParticleSystemVulkanObjects {
&mut self.particle_system_vulkan_objects
}
pub fn particle_system_vulkan_objects(&self) -> &ParticleSystemVulkanObjects {
&self.particle_system_vulkan_objects
}
pub fn add_light(&mut self, light: Light) -> Result<()> {
self.renderer.add_light(light)?;
Ok(())
}
pub fn remove_light(&mut self, light: Light) -> Result<()> {
self.renderer.remove_light(light)?;
Ok(())
}
pub fn clear_lights(&mut self) -> Result<()> {
self.renderer.clear_lights()?;
Ok(())
}
pub fn view(&self) -> &View {
self.renderer.view()
}
fn _process(
pub fn view_mut(&mut self) -> &mut View {
self.renderer.view_mut()
}
pub fn render_type(&self) -> SceneType {
self.render_type
}
pub fn frame_time(&self) -> Duration {
self.frame_time
}
}
impl TScene for Scene {
fn process(
&mut self,
buffer_recorder: &mut CommandBufferRecorder<'_>,
images: &TargetMode<Vec<Arc<Image>>>,
indices: &TargetMode<usize>,
) -> Result<()> {
) -> anyhow::Result<()> {
self.frame_time = {
let now = self.now();
@ -402,7 +457,7 @@ impl Scene {
let frustum = view.frustum();
let planes = frustum.planes();
let content: Vec<Option<&EntityObject<Self>>> = self
let content: Vec<Option<&EntityObject>> = self
.entities
.par_values()
.map(|entity_object| {
@ -439,70 +494,6 @@ impl Scene {
Ok(())
}
pub fn world_to_screen_space(&self, world_space: Vector3<f32>) -> Result<(i32, i32)> {
Self::_world_to_screen_space(
(self.screen_width, self.screen_height),
world_space,
self.view(),
)
}
pub fn screen_space_to_world(&self, x: u32, y: u32) -> Result<Option<Vector3<f32>>> {
let scale = self.renderer.render_scale();
self.renderer
.screen_to_world((x as f32 * scale) as u32, (y as f32 * scale) as u32)
}
pub fn particle_system_vulkan_objects_mut(&mut self) -> &mut ParticleSystemVulkanObjects {
&mut self.particle_system_vulkan_objects
}
pub fn particle_system_vulkan_objects(&self) -> &ParticleSystemVulkanObjects {
&self.particle_system_vulkan_objects
}
pub fn add_light(&mut self, light: Light) -> Result<()> {
self.renderer.add_light(light)?;
Ok(())
}
pub fn remove_light(&mut self, light: Light) -> Result<()> {
self.renderer.remove_light(light)?;
Ok(())
}
pub fn clear_lights(&mut self) -> Result<()> {
self.renderer.clear_lights()?;
Ok(())
}
pub fn view_mut(&mut self) -> &mut View {
self.renderer.view_mut()
}
pub fn render_type(&self) -> SceneType {
self.render_type
}
pub fn frame_time(&self) -> Duration {
self.frame_time
}
}
impl TScene for Scene {
fn process(
&mut self,
buffer_recorder: &mut CommandBufferRecorder<'_>,
images: &TargetMode<Vec<Arc<Image>>>,
indices: &TargetMode<usize>,
) -> anyhow::Result<()> {
self._process(buffer_recorder, images, indices)
}
fn resize(
&mut self,
window_width: f32,

View file

@ -7,3 +7,4 @@ edition = "2024"
anyhow.workspace = true
ecs = { path = "../../ecs" }
engine = { path = "../../engine" }

View file

@ -1,9 +1,35 @@
use anyhow::Result;
use ecs::*;
use engine::prelude::*;
fn main() -> Result<()> {
let mut world_builder = World::builder();
// world_builder.
let (context, engine, scene) = Engine::new(EngineCreateInfo {
app_info: todo!(),
window_info: todo!(),
os_specific_config: todo!(),
vulkan_debug_info: todo!(),
volume_info: todo!(),
gui_info: todo!(),
enable_backtrace: todo!(),
enable_mouse: todo!(),
enable_keyboard: todo!(),
enable_controller: todo!(),
controller_deadzones: todo!(),
resource_base_path: todo!(),
controller_directories: todo!(),
asset_directories: todo!(),
graphics_info: todo!(),
raytracing_info: todo!(),
rasterizer_info: todo!(),
key_backgrounds: todo!(),
})?;
world_builder.resources.insert(context);
world_builder.resources.insert(engine);
world_builder.resources.insert(scene);
world_builder.build().run()
}

View file

@ -16,7 +16,6 @@ impl LoadingScreen {
where
R: Fn(T) -> Result<()> + Send + Sync + 'static,
T: Send + Sync + 'static,
L: FnOnce() -> T + Send + Sync + 'static,
G: TopLevelGui + TopGui + Send + Sync + 'static,
{
@ -32,7 +31,8 @@ impl LoadingScreen {
gui.disable().unwrap();
}
context.push_event(move || (on_ready)(result));
todo!();
// context.push_event(move || (on_ready)(result));
});
Ok(())

View file

@ -13,6 +13,8 @@ anyhow = { workspace = true }
openxr = { workspace = true, optional = true }
openvr = { workspace = true, optional = true }
ecs = { path = "../ecs" }
[features]
OpenXR = ["openxr"]
OpenVR = ["openvr"]

View file

@ -16,6 +16,7 @@ use anyhow::Result;
use traits::RenderCore;
use ui::prelude::*;
use vulkan_rs::prelude::*;
use wsi::vulkanwindowrendercore::VulkanWindowRenderCore;
use crate::prelude::*;
@ -28,32 +29,16 @@ pub struct RenderCoreCreateInfo {
pub vsync: bool,
}
pub fn create_render_core<SCENE, F>(
pub fn create_render_core<S: TScene + 'static>(
presentation_core: &PresentationCore,
device: &Arc<Device>,
queue: &Arc<Mutex<Queue>>,
create_info: RenderCoreCreateInfo,
create_scene: F,
) -> Result<(Box<dyn RenderCore>, TargetMode<()>)>
where
SCENE: TScene + 'static,
F: FnOnce(
&Arc<Device>,
&Arc<Mutex<Queue>>,
(f32, f32),
&TargetMode<Vec<Arc<Image>>>,
) -> Result<SCENE>,
{
) -> Result<(Box<dyn RenderCore>, TargetMode<()>)> {
match presentation_core.backend() {
PresentationBackend::Window(wsi) => {
let (render_core, target_mode) =
wsi::vulkanwindowrendercore::VulkanWindowRenderCore::new(
wsi.clone(),
device,
queue,
create_info,
create_scene,
)?;
VulkanWindowRenderCore::<S>::new(wsi.clone(), device, queue, create_info)?;
Ok((Box::new(render_core), target_mode))
}

View file

@ -114,7 +114,7 @@ impl PresentationCore {
pub fn poll_events<F, R>(&self, event_callback: F, resize_event: R) -> Result<bool>
where
F: Fn(Event) -> Result<()>,
R: Fn(u32, u32) -> Result<()>,
R: FnMut(u32, u32) -> Result<()>,
{
self.event_system.poll_events(event_callback, resize_event)
}
@ -169,7 +169,11 @@ impl PresentationCore {
impl std::fmt::Debug for PresentationCore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "WindowSystemIntegration {{ sdl_context: SDL2, eventsystem: EventSystem, backend: {:#?} }}", self.backend)
write!(
f,
"WindowSystemIntegration {{ sdl_context: SDL2, eventsystem: EventSystem, backend: {:#?} }}",
self.backend
)
}
}

View file

@ -1,14 +1,16 @@
use crate::prelude::*;
use crate::Result;
use crate::prelude::*;
use cgmath::{Matrix4, SquareMatrix};
use ecs::World;
use ui::prelude::*;
use vulkan_rs::prelude::*;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc, Mutex, RwLock,
atomic::{AtomicUsize, Ordering::SeqCst},
};
#[derive(Debug, Clone, Copy, PartialEq)]
@ -47,7 +49,7 @@ impl Default for VRTransformations {
}
}
pub struct RenderBackend {
pub struct RenderBackend<S: TScene + 'static> {
device: Arc<Device>,
queue: Arc<Mutex<Queue>>,
@ -59,16 +61,16 @@ pub struct RenderBackend {
command_buffer: Arc<CommandBuffer>,
scene: Box<dyn TScene>,
post_processes: Mutex<Vec<Arc<dyn PostProcess>>>,
s: PhantomData<S>,
}
impl RenderBackend {
pub fn new<SCENE: TScene + 'static>(
impl<S: TScene + 'static> RenderBackend<S> {
pub fn new(
device: &Arc<Device>,
queue: &Arc<Mutex<Queue>>,
images: TargetMode<Vec<Arc<Image>>>,
scene: SCENE,
) -> Result<Self> {
let image_count = match &images {
TargetMode::Mono(images) => images.len(),
@ -92,8 +94,9 @@ impl RenderBackend {
command_buffer,
scene: Box::new(scene),
post_processes: Mutex::new(Vec::new()),
s: PhantomData,
})
}
@ -102,7 +105,7 @@ impl RenderBackend {
}
}
impl RenderBackend {
impl<S: TScene + 'static> RenderBackend<S> {
pub fn device(&self) -> &Arc<Device> {
&self.device
}
@ -115,7 +118,11 @@ impl RenderBackend {
*self.clear_color.write().unwrap() = VkClearColorValue::float32(clear_color);
}
pub fn render(&mut self, image_indices: TargetMode<usize>) -> Result<&Arc<CommandBuffer>> {
pub fn render(
&mut self,
world: &mut World,
image_indices: TargetMode<usize>,
) -> Result<&Arc<CommandBuffer>> {
// begin main command buffer
let mut buffer_recorder = self.command_buffer.begin(VkCommandBufferBeginInfo::new(
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
@ -164,7 +171,7 @@ impl RenderBackend {
}
// make a call to the connected scene
self.scene.process(
world.resources.get_mut::<S>().process(
&mut buffer_recorder,
&*self.swapchain_images.lock().unwrap(),
&image_indices,
@ -180,6 +187,7 @@ impl RenderBackend {
pub fn resize(
&mut self,
world: &mut World,
images: TargetMode<Vec<Arc<Image>>>,
width: u32,
height: u32,
@ -195,7 +203,10 @@ impl RenderBackend {
SeqCst,
);
self.scene.resize(width as f32, height as f32, &images)?;
world
.resources
.get_mut::<S>()
.resize(width as f32, height as f32, &images)?;
*self.swapchain_images.lock().unwrap() = images;
for post_process in self.post_processes.lock().unwrap().iter() {
@ -205,15 +216,6 @@ impl RenderBackend {
Ok(())
}
// scene handling
pub fn scene(&self) -> &Box<dyn TScene> {
&self.scene
}
pub fn scene_mut(&mut self) -> &mut Box<dyn TScene> {
&mut self.scene
}
pub fn add_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
let mut post_processes = self.post_processes.lock().unwrap();
@ -254,7 +256,7 @@ impl RenderBackend {
}
}
impl RenderBackend {
impl<S: TScene + 'static> RenderBackend<S> {
#[inline]
fn clear_image(
buffer_recorder: &mut CommandBufferRecorder<'_>,

View file

@ -1,3 +1,4 @@
use ecs::World;
use ui::prelude::*;
use vulkan_rs::prelude::*;
@ -36,9 +37,9 @@ pub trait PostProcess: Send + Sync {
}
pub trait RenderCore: std::fmt::Debug + Send + Sync {
fn next_frame(&mut self) -> Result<bool>;
fn next_frame(&mut self, world: &mut World) -> Result<bool>;
fn resize(&mut self, w: u32, h: u32) -> Result<()>;
fn resize(&mut self, world: &mut World, w: u32, h: u32) -> Result<()>;
fn format(&self) -> VkFormat;
fn image_layout(&self) -> VkImageLayout {
@ -47,10 +48,6 @@ pub trait RenderCore: std::fmt::Debug + Send + Sync {
fn set_clear_color(&self, color: [f32; 4]);
// scene handling
fn scene(&self) -> &Box<dyn TScene>;
fn scene_mut(&mut self) -> &mut Box<dyn TScene>;
// post process handling
fn add_post_processing_routine(&self, post_process: Arc<dyn PostProcess>);
fn remove_post_processing_routine(&self, post_process: Arc<dyn PostProcess>);

View file

@ -48,6 +48,7 @@ pub mod openvrrendercore;
#[cfg(not(feature = "OpenVR"))]
pub mod openvrrendercore {
use crate::Result;
use ecs::World;
use ui::prelude::*;
use vulkan_rs::prelude::*;
@ -55,8 +56,8 @@ pub mod openvrrendercore {
use super::openvrintegration::OpenVRIntegration;
use crate::prelude::*;
use crate::RenderCoreCreateInfo;
use crate::prelude::*;
pub struct OpenVRRenderCore {
_dummy: u32,
@ -78,11 +79,11 @@ pub mod openvrrendercore {
unimplemented!()
}
fn resize(&mut self, _: u32, _: u32) -> Result<()> {
fn resize(&mut self, _: &mut World, _: u32, _: u32) -> Result<()> {
unimplemented!()
}
fn next_frame(&mut self) -> Result<bool> {
fn next_frame(&mut self, _: &mut World) -> Result<bool> {
unimplemented!()
}
@ -90,15 +91,6 @@ pub mod openvrrendercore {
unimplemented!()
}
// scene handling
fn scene(&self) -> &Box<dyn TScene> {
unimplemented!()
}
fn scene_mut(&mut self) -> &mut Box<dyn TScene> {
unimplemented!()
}
// post process handling
fn add_post_processing_routine(&self, _post_process: Arc<dyn PostProcess>) {
unimplemented!()

View file

@ -1,19 +1,20 @@
use crate::{prelude::*, renderbackend::RenderBackend, RenderCoreCreateInfo};
use crate::{RenderCoreCreateInfo, prelude::*, renderbackend::RenderBackend};
use super::windowsystemintegration::WindowSystemIntegration;
use crate::Result;
use ecs::World;
// use ui::prelude::*;
use vulkan_rs::prelude::*;
use std::sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc, Mutex, RwLock,
atomic::{AtomicUsize, Ordering::SeqCst},
};
use std::time::Duration;
use std::u64;
pub struct VulkanWindowRenderCore {
pub struct VulkanWindowRenderCore<S: TScene + 'static> {
device: Arc<Device>,
// driver provided images
@ -26,30 +27,20 @@ pub struct VulkanWindowRenderCore {
render_finished_sem: Arc<Semaphore>,
render_fence: Arc<Fence>,
render_backend: RenderBackend,
render_backend: RenderBackend<S>,
current_image_index: AtomicUsize,
wsi: Arc<WindowSystemIntegration>,
}
impl VulkanWindowRenderCore {
pub fn new<SCENE, F>(
impl<S: TScene + 'static> VulkanWindowRenderCore<S> {
pub fn new(
wsi: Arc<WindowSystemIntegration>,
device: &Arc<Device>,
queue: &Arc<Mutex<Queue>>,
create_info: RenderCoreCreateInfo,
create_scene: F,
) -> Result<(Self, TargetMode<()>)>
where
SCENE: TScene + 'static,
F: FnOnce(
&Arc<Device>,
&Arc<Mutex<Queue>>,
(f32, f32),
&TargetMode<Vec<Arc<Image>>>,
) -> Result<SCENE>,
{
) -> Result<(Self, TargetMode<()>)> {
// check swapchain extension
if !device.enabled_extensions().swapchain {
return Err(anyhow::Error::msg("Swapchain Extension must be enabled"));
@ -66,7 +57,7 @@ impl VulkanWindowRenderCore {
)));
}
let usage = create_info.usage | RenderBackend::required_image_usage();
let usage = create_info.usage | RenderBackend::<S>::required_image_usage();
// create swapchain
let swapchain = Swapchain::new(
@ -87,14 +78,8 @@ impl VulkanWindowRenderCore {
let fence = Fence::builder().build(device.clone())?;
let images = TargetMode::Mono(swapchain_images);
let scene = create_scene(
device,
queue,
(swapchain.width() as f32, swapchain.height() as f32),
&images,
)?;
let render_backend = RenderBackend::new(device, queue, images, scene)?;
let render_backend = RenderBackend::new(device, queue, images)?;
let window_render_core = VulkanWindowRenderCore {
device: device.clone(),
@ -118,7 +103,7 @@ impl VulkanWindowRenderCore {
Ok((window_render_core, TargetMode::Mono(())))
}
fn aquire_next_image_index(&mut self) -> Result<()> {
fn aquire_next_image_index(&mut self, world: &mut World) -> Result<()> {
// there was a bug that a windows never reacted after it was minimized
// with this timeout, the window has 250ms delay
#[cfg(target_os = "windows")]
@ -141,7 +126,7 @@ impl VulkanWindowRenderCore {
}
OutOfDate::OutOfDate => {
let (w, h) = self.wsi.window_size();
resize_mut.resize(w, h)?;
resize_mut.resize(world, w, h)?;
*semaphore = Semaphore::new(self.device.clone())?;
}
@ -155,12 +140,12 @@ impl VulkanWindowRenderCore {
}
}
impl RenderCore for VulkanWindowRenderCore {
impl<S: TScene + 'static> RenderCore for VulkanWindowRenderCore<S> {
fn format(&self) -> VkFormat {
self.format
}
fn resize(&mut self, w: u32, h: u32) -> Result<()> {
fn resize(&mut self, world: &mut World, w: u32, h: u32) -> Result<()> {
self.swapchain.recreate((w, h))?;
let swapchain_images = self.swapchain.wrap_images(
@ -170,6 +155,7 @@ impl RenderCore for VulkanWindowRenderCore {
)?;
self.render_backend.resize(
world,
TargetMode::Mono(swapchain_images),
self.swapchain.width(),
self.swapchain.height(),
@ -178,12 +164,13 @@ impl RenderCore for VulkanWindowRenderCore {
Ok(())
}
fn next_frame(&mut self) -> Result<bool> {
self.aquire_next_image_index()?;
fn next_frame(&mut self, world: &mut World) -> Result<bool> {
self.aquire_next_image_index(world)?;
let command_buffer = self
.render_backend
.render(TargetMode::Mono(self.current_image_index.load(SeqCst)))?;
let command_buffer = self.render_backend.render(
world,
TargetMode::Mono(self.current_image_index.load(SeqCst)),
)?;
let submits = &[SubmitInfo::default()
.add_wait_semaphore(
@ -205,7 +192,7 @@ impl RenderCore for VulkanWindowRenderCore {
)?
} {
let (w, h) = self.wsi.window_size();
self.resize(w, h)?;
self.resize(world, w, h)?;
self.render_fence.reset();
return Ok(true);
}
@ -225,15 +212,6 @@ impl RenderCore for VulkanWindowRenderCore {
self.render_backend.set_clear_color(color);
}
// scene handling
fn scene(&self) -> &Box<dyn TScene> {
self.render_backend.scene()
}
fn scene_mut(&mut self) -> &mut Box<dyn TScene> {
self.render_backend.scene_mut()
}
// post process handling
fn add_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
self.render_backend
@ -271,7 +249,7 @@ impl RenderCore for VulkanWindowRenderCore {
}
}
impl std::fmt::Debug for VulkanWindowRenderCore {
impl<S: TScene + 'static> std::fmt::Debug for VulkanWindowRenderCore<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "VulkanWindowRenderCore {{ }}")
}

View file

@ -3,13 +3,13 @@
use anyhow::Error;
use sdl2;
use sdl2::Sdl;
use sdl2::clipboard::ClipboardUtil;
use sdl2::messagebox::{show_simple_message_box, MessageBoxFlag};
use sdl2::messagebox::{MessageBoxFlag, show_simple_message_box};
use sdl2::mouse::Cursor;
use sdl2::surface::Surface as SDL_Surface;
use sdl2::sys::SDL_Window;
use sdl2::video::{FullscreenType, WindowPos};
use sdl2::Sdl;
use crate::Result;
use vulkan_rs::prelude::*;
@ -18,8 +18,8 @@ use std::mem::MaybeUninit;
use std::ops::Deref;
use std::path::Path;
use std::sync::{
atomic::{AtomicI32, AtomicU32, Ordering::SeqCst},
Arc, Mutex,
atomic::{AtomicI32, AtomicU32, Ordering::SeqCst},
};
const SDL_SYSWM_WINDOWS: u32 = 0x1;
@ -35,7 +35,7 @@ struct SdlSysWmInfo {
info: [u64; 32],
}
extern "C" {
unsafe extern "C" {
fn SDL_GetWindowWMInfo(window: *const sdl2::sys::SDL_Window, info: *mut SdlSysWmInfo) -> bool;
}
@ -421,7 +421,7 @@ impl WindowSystemIntegration {
return Err(anyhow::Error::msg(format!(
"Unsupported window subsystem flag {}",
sys_wm_info.subsystem
)))
)));
}
}

View file

@ -46,6 +46,7 @@ pub mod openxrrendercore;
#[cfg(not(feature = "OpenXR"))]
pub mod openxrrendercore {
use crate::Result;
use ecs::World;
use ui::prelude::*;
use vulkan_rs::prelude::*;
@ -53,8 +54,8 @@ pub mod openxrrendercore {
use super::openxrintegration::OpenXRIntegration;
use crate::prelude::*;
use crate::RenderCoreCreateInfo;
use crate::prelude::*;
pub struct OpenXRRenderCore {
_dummy: u32,
@ -76,11 +77,11 @@ pub mod openxrrendercore {
unimplemented!()
}
fn resize(&mut self, _: u32, _: u32) -> Result<()> {
fn resize(&mut self, _: &mut World, _: u32, _: u32) -> Result<()> {
unimplemented!()
}
fn next_frame(&mut self) -> Result<bool> {
fn next_frame(&mut self, _: &mut World) -> Result<bool> {
unimplemented!()
}
@ -88,15 +89,6 @@ pub mod openxrrendercore {
unimplemented!()
}
// scene handling
fn scene(&self) -> &Box<dyn TScene> {
unimplemented!()
}
fn scene_mut(&mut self) -> &mut Box<dyn TScene> {
unimplemented!()
}
// post process handling
fn add_post_processing_routine(&self, _post_process: Arc<dyn PostProcess>) {
unimplemented!()