Start sky box example

This commit is contained in:
hodasemi 2025-02-28 15:13:19 +01:00
parent 8205b91ec9
commit 0a93da3b5b
19 changed files with 535 additions and 469 deletions

View file

@ -19,6 +19,7 @@ members = [
"promise",
"ring_buffer",
"scene_update_macros",
"skybox",
"transaction_derive",
]

View file

@ -21,7 +21,8 @@ impl ImageFormatChecker {
self.image_data.height,
)
.format(initial_format)
.attach_sampler(Sampler::pretty_sampler().build(device)?);
.max_mip_map_levels()
.attach_pretty_sampler(device)?;
let mut format = initial_format;
@ -35,7 +36,7 @@ impl ImageFormatChecker {
return Err(anyhow::Error::msg(format!(
"Image format {:?} for asset does not work",
format
)))
)));
}
};

View file

@ -22,14 +22,6 @@ use std::rc::Rc;
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::time::{Duration, Instant};
pub trait ContextObject {
fn name(&self) -> &str;
fn update(&mut self) -> Result<()>;
fn event(&mut self, event: Event) -> Result<()>;
}
pub struct Context {
core: VulkanCore,
pub(crate) presentation: PresentationCore,
@ -65,18 +57,17 @@ impl Context {
&mut self.sound_handler
}
pub fn next_frame<C>(&mut self, world: &mut World) -> Result<bool> {
pub fn next_frame<C, F>(&mut self, world: &mut World, mut f: F) -> Result<bool>
where
C: Send + Sync + 'static,
F: FnMut(&mut World, &mut C, Event) -> Result<()> + Send + Sync + 'static,
{
let render_core = self.render_core.clone();
let consumer = world.resources.get_mut_unchecked::<C>();
let w = unsafe { remove_life_time_mut(world) };
match self.presentation.poll_events(
|event| {
// TODO
// if let Some(ctx_obj) = world.resources.get_mut_opt::<C>() {
// ctx_obj.event(event)?;
// }
Ok(())
},
|event| f(w, consumer, event),
|w, h| render_core.write().unwrap().resize(world, w, h),
) {
Ok(res) => {

View file

@ -2,5 +2,3 @@
pub mod core;
pub mod prelude;
pub use crate::core::context::ContextObject;

View file

@ -1,6 +1,6 @@
#![allow(clippy::type_complexity)]
use super::engine_object::*;
use super::engine_event_handling::*;
use super::engine_settings::EngineSettings;
use anyhow::Result;
@ -11,7 +11,7 @@ use crate::assets::asset_manager::AssetManager;
use crate::prelude::*;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::sync::Arc;
struct GuiPostProcess(Arc<GuiHandler>);
@ -34,8 +34,6 @@ impl context::prelude::PostProcess for GuiPostProcess {
}
pub struct Engine {
input: Arc<RwLock<Input>>,
// loads and keeps track of raw data
asset_manager: AssetManager,
@ -43,7 +41,7 @@ pub struct Engine {
}
impl Engine {
pub fn new(
pub fn new<T: EventConsumer>(
#[allow(unused)] mut create_info: EngineCreateInfo<'_>,
world: &mut WorldBuilder,
) -> Result<()> {
@ -188,13 +186,12 @@ impl Engine {
direction_mapping.insert(Keycode::Down, GuiDirection::Down);
let engine = Engine {
input: Arc::new(RwLock::new(Input { direction_mapping })),
asset_manager,
resource_base_path: create_info.resource_base_path,
};
world.resources.insert(InputMap { direction_mapping });
world.resources.insert(context);
world.resources.insert(engine);
world.resources.insert(engine_settings);
@ -208,7 +205,7 @@ impl Engine {
world.resources.insert(scene);
world.add_system(Self::main_system);
world.add_system(Self::main_system::<T>);
Ok(())
}
@ -251,10 +248,25 @@ impl Engine {
}
impl Engine {
fn main_system(world: &mut World) -> Result<bool> {
fn main_system<T: EventConsumer>(world: &mut World) -> Result<bool> {
world
.resources
.get_mut_unchecked::<Context>()
.next_frame::<()>(world)
.get::<Arc<GuiHandler>>()
.process_callbacks()?;
let gui_handler = world.resources.get_unchecked::<Arc<GuiHandler>>();
let input_map = world.resources.get_unchecked::<InputMap>();
let context = world.resources.get_unchecked::<Context>();
let res = world.resources.get_mut_unchecked::<Context>().next_frame(
world,
|world, consumer: &mut T, event| {
Self::event(world, context, gui_handler, input_map, consumer, event)
},
)?;
gui_handler.process_callbacks()?;
Ok(res)
}
}

View file

@ -0,0 +1,332 @@
use crate::prelude::*;
use anyhow::Result;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
// use super::engine_object_data::{EngineObjectAccess, EngineObjectDataHandle};
#[derive(Debug)]
pub enum EngineEvent {
MouseMotion(u32, u32),
MouseButtonDown(MouseButton),
MouseButtonUp(MouseButton),
MouseWheel(i32, i32, MouseWheelDirection),
KeyDown(Keycode),
KeyUp(Keycode),
ButtonDown(ControllerButton),
ButtonUp(ControllerButton),
ControllerAxis(ControllerAxis),
ControllerAdded(Arc<RwLock<Controller>>),
ControllerRemoved(Arc<RwLock<Controller>>),
FileDrop(String),
}
pub trait EventConsumer: Send + Sync + 'static {
fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()>;
}
pub struct InputMap {
pub direction_mapping: HashMap<Keycode, GuiDirection>,
}
impl Engine {
pub(crate) fn event<T: EventConsumer>(
world: &mut World,
context: &Context,
gui_handler: &GuiHandler,
input: &InputMap,
consumer: &mut T,
event: Event,
) -> anyhow::Result<()> {
match event {
Event::MouseMotion(x, y) => {
gui_handler.set_mouse_pos(x, y)?;
consumer.event(world, EngineEvent::MouseMotion(x, y))?;
}
Event::MouseButtonDown(mouse_button) => {
if !gui_handler.mouse_down(mouse_button)? {
consumer.event(world, EngineEvent::MouseButtonDown(mouse_button))?;
}
}
Event::MouseButtonUp(mouse_button) => {
if !gui_handler.mouse_up(mouse_button)? {
consumer.event(world, EngineEvent::MouseButtonUp(mouse_button))?;
}
}
Event::MouseWheel(x, y, direction) => {
consumer.event(world, EngineEvent::MouseWheel(x, y, direction))?
}
Event::KeyDown(keycode) => {
Self::key_down_event(world, context, gui_handler, input, consumer, keycode)?;
}
Event::KeyUp(keycode) => {
Self::key_up_event(world, gui_handler, input, consumer, keycode)?;
}
Event::TextInput(text) => {
Self::text_input(gui_handler, text)?;
}
Event::ControllerButtonDown(button) => {
Self::button_down_event(world, gui_handler, consumer, button)?;
}
Event::ControllerButtonUp(button) => {
Self::button_up_event(world, consumer, button)?;
}
Event::ControllerAxis(controller) => {
let controller = controller.read().unwrap();
if !gui_handler.check_navigatable()? {
Self::axis_event(world, consumer, &controller)?
} else {
gui_handler.update_selection(controller.direction())?;
}
}
Event::ControllerAdded(controller) => {
Self::controller_added(world, consumer, controller)?
}
Event::ControllerRemoved(controller) => {
Self::controller_removed(world, consumer, controller)?
}
Event::FileDrop(filename) => consumer.event(world, EngineEvent::FileDrop(filename))?,
}
Ok(())
}
}
impl Engine {
#[inline]
fn controller_added<T: EventConsumer>(
world: &mut World,
consumer: &mut T,
controller: Arc<RwLock<Controller>>,
) -> Result<()> {
consumer.event(world, EngineEvent::ControllerAdded(controller))?;
Ok(())
}
#[inline]
fn controller_removed<T: EventConsumer>(
world: &mut World,
consumer: &mut T,
controller: Arc<RwLock<Controller>>,
) -> Result<()> {
consumer.event(world, EngineEvent::ControllerRemoved(controller))?;
Ok(())
}
#[inline]
fn key_up_event<T: EventConsumer>(
world: &mut World,
gui_handler: &GuiHandler,
input: &InputMap,
consumer: &mut T,
keycode: Keycode,
) -> Result<()> {
if input.direction_mapping.get(&keycode).is_some()
&& gui_handler.update_selection(GuiDirection::None)?
{
return Ok(());
}
consumer.event(world, EngineEvent::KeyUp(keycode))?;
Ok(())
}
#[inline]
fn key_down_event<T: EventConsumer>(
world: &mut World,
context: &Context,
gui_handler: &GuiHandler,
input: &InputMap,
consumer: &mut T,
keycode: Keycode,
) -> Result<()> {
if let Some(direction) = input.direction_mapping.get(&keycode) {
if gui_handler.update_selection(*direction)? {
return Ok(());
}
}
match keycode {
Keycode::Backspace => {
if gui_handler.remove_char()? {
return Ok(());
}
}
Keycode::Return => {
if gui_handler.accept_selection()? {
return Ok(());
}
}
Keycode::Escape => {
if gui_handler.decline_topgui()? {
return Ok(());
}
}
Keycode::V => {
if let Some(writeable) = gui_handler.writeable()? {
if let Some(content) = context.window_config().clipboard_content()? {
writeable.set_text(content)?;
}
}
}
_ => (),
}
consumer.event(world, EngineEvent::KeyDown(keycode))?;
Ok(())
}
#[inline]
fn button_up_event<T: EventConsumer>(
world: &mut World,
consumer: &mut T,
button: ControllerButton,
) -> Result<()> {
consumer.event(world, EngineEvent::ButtonUp(button))?;
Ok(())
}
#[inline]
fn button_down_event<T: EventConsumer>(
world: &mut World,
gui_handler: &GuiHandler,
consumer: &mut T,
button: ControllerButton,
) -> Result<()> {
if gui_handler.check_navigatable()? {
Self::check_button_down(world, gui_handler, consumer, button)?;
} else {
consumer.event(world, EngineEvent::ButtonDown(button))?;
}
Ok(())
}
#[inline]
fn axis_event<T: EventConsumer>(
world: &mut World,
consumer: &mut T,
controller: &Controller,
) -> Result<()> {
consumer.event(
world,
EngineEvent::ControllerAxis(controller.controller_axis()),
)?;
Ok(())
}
#[inline]
fn check_button_down<T: EventConsumer>(
world: &mut World,
gui_handler: &GuiHandler,
consumer: &mut T,
button: ControllerButton,
) -> Result<()> {
match button {
ControllerButton::A => {
if gui_handler.accept_selection()? {
return Ok(());
}
}
ControllerButton::B => {
if gui_handler.decline_topgui()? {
return Ok(());
}
}
ControllerButton::RightButton => {
if gui_handler.next_tab_topgui(false)? {
return Ok(());
}
}
ControllerButton::LeftButton => {
if gui_handler.previous_tab_topgui(false)? {
return Ok(());
}
}
ControllerButton::RightTrigger => {
if gui_handler.next_tab_topgui(true)? {
return Ok(());
}
}
ControllerButton::LeftTrigger => {
if gui_handler.previous_tab_topgui(true)? {
return Ok(());
}
}
ControllerButton::DPadDown => {
let selection_res = gui_handler.update_selection(GuiDirection::Down)?;
gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadUp => {
let selection_res = gui_handler.update_selection(GuiDirection::Up)?;
gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadRight => {
let selection_res = gui_handler.update_selection(GuiDirection::Right)?;
gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadLeft => {
let selection_res = gui_handler.update_selection(GuiDirection::Left)?;
gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
_ => (),
}
if !gui_handler.accept_custom_selection(button)? {
consumer.event(world, EngineEvent::ButtonDown(button))?;
}
Ok(())
}
#[inline]
fn text_input(gui_handler: &GuiHandler, text: String) -> Result<()> {
if let Some(writeable) = gui_handler.writeable()? {
for c in text.chars() {
writeable.add_letter(c)?;
}
}
Ok(())
}
}

View file

@ -1,420 +0,0 @@
use crate::prelude::*;
use anyhow::Result;
use context::ContextObject;
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
// use super::engine_object_data::{EngineObjectAccess, EngineObjectDataHandle};
#[derive(Debug)]
pub enum EngineEvent {
MouseMotion(u32, u32),
MouseButtonDown(MouseButton),
MouseButtonUp(MouseButton),
MouseWheel(i32, i32, MouseWheelDirection),
KeyDown(Keycode),
KeyUp(Keycode),
ButtonDown(ControllerButton),
ButtonUp(ControllerButton),
ControllerAxis(ControllerAxis),
ControllerAdded(Arc<RwLock<Controller>>),
ControllerRemoved(Arc<RwLock<Controller>>),
FileDrop(String),
}
// pub trait EngineObjectHelper: Any {
// type Payload: Send + Sync;
// fn access(&self) -> EngineObjectAccess<'_, Self::Payload>;
// fn payload(&self) -> EngineObjectDataHandle<Self::Payload>;
// fn ui(&self) -> &States;
// fn ui_mut(&mut self) -> &mut States;
// fn access_callback_mut<'a, F>(
// &'a self,
// f: F,
// ) -> impl FnMut() -> Result<()> + Send + Sync + 'static
// where
// F: FnMut(EngineObjectAccess<'a, Self::Payload>) -> Result<()> + Send + Sync + 'static,
// {
// self.payload().access_callback_mut(f)
// }
// fn access_callback<F>(&self, f: F) -> impl Fn() -> Result<()> + Send + Sync + 'static
// where
// F: Fn(EngineObjectAccess<'_, Self::Payload>) -> Result<()> + Send + Sync + 'static,
// {
// self.payload().access_callback(f)
// }
// fn handle_callback_mut<F>(&self, mut f: F) -> impl FnMut() -> Result<()> + Send + Sync + 'static
// where
// F: FnMut(
// EngineObjectDataHandle<Self::Payload>,
// EngineObjectAccess<'_, Self::Payload>,
// ) -> Result<()>
// + Send
// + Sync
// + 'static,
// {
// let handle = self.payload();
// move || {
// let data = handle.as_data();
// let access = data.access();
// f(handle.copy(), access)
// }
// }
// fn handle_callback<F>(&self, f: F) -> impl Fn() -> Result<()> + Send + Sync + 'static
// where
// F: Fn(
// EngineObjectDataHandle<Self::Payload>,
// EngineObjectAccess<'_, Self::Payload>,
// ) -> Result<()>
// + Send
// + Sync
// + 'static,
// {
// let handle = self.payload();
// move || {
// let data = handle.as_data();
// let access = data.access();
// f(handle.copy(), access)
// }
// }
// }
pub trait EngineObject: Any {
fn name(&self) -> &str;
fn update(&mut self) -> Result<()>;
fn event(&mut self, event: EngineEvent) -> Result<()>;
}
pub struct Input {
pub direction_mapping: HashMap<Keycode, GuiDirection>,
}
pub struct ContextObjectImpl<E>
where
E: EngineObject + Send + Sync,
{
engine_object: E,
context: Arc<Context>,
input: Arc<RwLock<Input>>,
gui_handler: Arc<GuiHandler>,
ctrl_pressed: bool,
}
impl<E> ContextObjectImpl<E>
where
E: EngineObject + Send + Sync,
{
pub fn new(
context: Arc<Context>,
engine_object: E,
input: Arc<RwLock<Input>>,
gui_handler: Arc<GuiHandler>,
) -> Result<Self> {
Ok(ContextObjectImpl {
context,
engine_object,
input,
gui_handler,
ctrl_pressed: false,
})
}
}
impl<E> ContextObject for ContextObjectImpl<E>
where
E: EngineObject + Send + Sync,
{
fn name(&self) -> &str {
self.engine_object.name()
}
fn update(&mut self) -> anyhow::Result<()> {
self.gui_handler.process_callbacks()?;
self.engine_object.update()
}
fn event(&mut self, event: Event) -> anyhow::Result<()> {
match event {
Event::MouseMotion(x, y) => {
self.gui_handler.set_mouse_pos(x, y)?;
self.engine_object.event(EngineEvent::MouseMotion(x, y))?;
}
Event::MouseButtonDown(mouse_button) => {
if !self.gui_handler.mouse_down(mouse_button)? {
self.engine_object
.event(EngineEvent::MouseButtonDown(mouse_button))?;
}
}
Event::MouseButtonUp(mouse_button) => {
if !self.gui_handler.mouse_up(mouse_button)? {
self.engine_object
.event(EngineEvent::MouseButtonUp(mouse_button))?;
}
}
Event::MouseWheel(x, y, direction) => self
.engine_object
.event(EngineEvent::MouseWheel(x, y, direction))?,
Event::KeyDown(keycode) => {
self.key_down_event(keycode)?;
}
Event::KeyUp(keycode) => {
self.key_up_event(keycode)?;
}
Event::TextInput(text) => {
self.text_input(text)?;
}
Event::ControllerButtonDown(button) => {
self.button_down_event(button)?;
}
Event::ControllerButtonUp(button) => {
self.button_up_event(button)?;
}
Event::ControllerAxis(controller) => {
let controller = controller.read().unwrap();
if !self.gui_handler.check_navigatable()? {
self.axis_event(&controller)?
} else {
self.gui_handler.update_selection(controller.direction())?;
}
}
Event::ControllerAdded(controller) => self.controller_added(controller)?,
Event::ControllerRemoved(controller) => self.controller_removed(controller)?,
Event::FileDrop(filename) => {
self.engine_object.event(EngineEvent::FileDrop(filename))?
}
}
Ok(())
}
}
impl<E> ContextObjectImpl<E>
where
E: EngineObject + Send + Sync,
{
#[inline]
fn controller_added(&mut self, controller: Arc<RwLock<Controller>>) -> Result<()> {
self.engine_object
.event(EngineEvent::ControllerAdded(controller))?;
Ok(())
}
#[inline]
fn controller_removed(&mut self, controller: Arc<RwLock<Controller>>) -> Result<()> {
self.engine_object
.event(EngineEvent::ControllerRemoved(controller))?;
Ok(())
}
#[inline]
fn key_up_event(&mut self, keycode: Keycode) -> Result<()> {
let input = self.input.read().unwrap();
if input.direction_mapping.get(&keycode).is_some()
&& self.gui_handler.update_selection(GuiDirection::None)?
{
return Ok(());
}
match keycode {
Keycode::RCtrl | Keycode::LCtrl => {
self.ctrl_pressed = false;
}
_ => (),
}
self.engine_object.event(EngineEvent::KeyUp(keycode))?;
Ok(())
}
#[inline]
fn key_down_event(&mut self, keycode: Keycode) -> Result<()> {
let input = self.input.read().unwrap();
if let Some(direction) = input.direction_mapping.get(&keycode) {
if self.gui_handler.update_selection(*direction)? {
return Ok(());
}
}
match keycode {
Keycode::Backspace => {
if self.gui_handler.remove_char()? {
return Ok(());
}
}
Keycode::Return => {
if self.gui_handler.accept_selection()? {
return Ok(());
}
}
Keycode::Escape => {
if self.gui_handler.decline_topgui()? {
return Ok(());
}
}
Keycode::RCtrl | Keycode::LCtrl => {
self.ctrl_pressed = true;
}
Keycode::V => {
if let Some(writeable) = self.gui_handler.writeable()? {
if let Some(content) = self.context.window_config().clipboard_content()? {
writeable.set_text(content)?;
}
}
}
_ => (),
}
self.engine_object.event(EngineEvent::KeyDown(keycode))?;
Ok(())
}
#[inline]
fn button_up_event(&mut self, button: ControllerButton) -> Result<()> {
self.engine_object.event(EngineEvent::ButtonUp(button))?;
Ok(())
}
#[inline]
fn button_down_event(&mut self, button: ControllerButton) -> Result<()> {
if self.gui_handler.check_navigatable()? {
self.check_button_down(button)?;
} else {
self.engine_object.event(EngineEvent::ButtonDown(button))?;
}
Ok(())
}
#[inline]
fn axis_event(&mut self, controller: &Controller) -> Result<()> {
self.engine_object
.event(EngineEvent::ControllerAxis(controller.controller_axis()))?;
Ok(())
}
#[inline]
fn check_button_down(&mut self, button: ControllerButton) -> Result<()> {
match button {
ControllerButton::A => {
if self.gui_handler.accept_selection()? {
return Ok(());
}
}
ControllerButton::B => {
if self.gui_handler.decline_topgui()? {
return Ok(());
}
}
ControllerButton::RightButton => {
if self.gui_handler.next_tab_topgui(false)? {
return Ok(());
}
}
ControllerButton::LeftButton => {
if self.gui_handler.previous_tab_topgui(false)? {
return Ok(());
}
}
ControllerButton::RightTrigger => {
if self.gui_handler.next_tab_topgui(true)? {
return Ok(());
}
}
ControllerButton::LeftTrigger => {
if self.gui_handler.previous_tab_topgui(true)? {
return Ok(());
}
}
ControllerButton::DPadDown => {
let selection_res = self.gui_handler.update_selection(GuiDirection::Down)?;
self.gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadUp => {
let selection_res = self.gui_handler.update_selection(GuiDirection::Up)?;
self.gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadRight => {
let selection_res = self.gui_handler.update_selection(GuiDirection::Right)?;
self.gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
ControllerButton::DPadLeft => {
let selection_res = self.gui_handler.update_selection(GuiDirection::Left)?;
self.gui_handler.update_selection(GuiDirection::None)?;
if selection_res {
return Ok(());
}
}
_ => (),
}
if !self.gui_handler.accept_custom_selection(button)? {
self.engine_object.event(EngineEvent::ButtonDown(button))?;
}
Ok(())
}
#[inline]
fn text_input(&self, text: String) -> Result<()> {
if let Some(writeable) = self.gui_handler.writeable()? {
for c in text.chars() {
writeable.add_letter(c)?;
}
}
Ok(())
}
}

View file

@ -1,7 +1,7 @@
pub mod engine;
pub mod engine_settings;
pub mod engine_object;
pub mod engine_event_handling;
pub mod asset_handler;
pub mod engine_create_info;

View file

@ -10,7 +10,7 @@ pub use crate::engine::{
asset_handler::{AssetHandler, AssetLoader},
engine::*,
engine_create_info::EngineCreateInfo,
engine_object::{EngineEvent, EngineObject},
engine_event_handling::{EngineEvent, EventConsumer},
engine_settings::*,
};

View file

@ -0,0 +1,36 @@
use crate::prelude::*;
use anyhow::Result;
pub struct FreeCameraControl {}
impl Default for FreeCameraControl {
fn default() -> Self {
Self {}
}
}
impl FreeCameraControl {
pub fn roll(&mut self, view: &View) -> Result<()> {
Ok(())
}
pub fn pitch(&mut self, view: &View) -> Result<()> {
Ok(())
}
pub fn yaw(&mut self, view: &View) -> Result<()> {
Ok(())
}
pub fn forward_back(&mut self, view: &View) -> Result<()> {
Ok(())
}
pub fn left_right(&mut self, view: &View) -> Result<()> {
Ok(())
}
pub fn up_down(&mut self, view: &View) -> Result<()> {
Ok(())
}
}

View file

@ -6,8 +6,9 @@ pub mod validcommandbuffer;
pub mod view;
pub mod camera_control;
pub mod top_down_camera_control;
pub mod view_frustum;
pub mod free_camera_control;
pub mod prelude;

View file

@ -6,6 +6,6 @@ pub use super::validcommandbuffer::*;
pub use super::view::*;
pub use super::camera_control::*;
pub use super::top_down_camera_control::*;
pub use super::view_frustum::*;

View file

@ -1,8 +1,8 @@
use crate::prelude::*;
use anyhow::Result;
use cgmath::{num_traits::clamp, vec3, Deg, Matrix4, Vector2, Vector3};
use cgmath::{Deg, Matrix4, Vector2, Vector3, num_traits::clamp, vec3};
pub struct CameraControl {
pub struct TopDownCameraControl {
zoom_levels: Vec<f32>,
current_zoom_level: usize,
@ -17,7 +17,7 @@ pub struct CameraControl {
mouse_position_start: Option<(u32, u32)>,
}
impl CameraControl {
impl TopDownCameraControl {
const SCALE: f32 = 0.3;
const MIN_PITCH: f32 = 10.0;
const MAX_PITCH: f32 = 80.0;
@ -91,8 +91,8 @@ impl CameraControl {
self.rotation = Deg((self.rotation.0 + (self.stick_direction.x * factors.x)) % 360.0);
self.arc = Deg(clamp(
self.arc.0 - (self.stick_direction.y * factors.y),
CameraControl::MIN_PITCH,
CameraControl::MAX_PITCH,
TopDownCameraControl::MIN_PITCH,
TopDownCameraControl::MAX_PITCH,
));
self.set_camera_offset(view)
@ -102,14 +102,14 @@ impl CameraControl {
self.mouse_position = (x, y);
if let Some((start_x, start_y)) = self.mouse_position_start {
let x_diff = (start_x as i32 - x as i32) as f32 * CameraControl::SCALE;
let y_diff = (start_y as i32 - y as i32) as f32 * CameraControl::SCALE;
let x_diff = (start_x as i32 - x as i32) as f32 * TopDownCameraControl::SCALE;
let y_diff = (start_y as i32 - y as i32) as f32 * TopDownCameraControl::SCALE;
self.rotation = Deg((self.rotation_start.0 + x_diff) % 360.0);
self.arc = Deg(clamp(
self.arc_start.0 - y_diff,
CameraControl::MIN_PITCH,
CameraControl::MAX_PITCH,
TopDownCameraControl::MIN_PITCH,
TopDownCameraControl::MAX_PITCH,
));
self.set_camera_offset(view)?;

View file

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
plexus = "0.0.11"
anyhow.workspace = true
ecs = { path = "../../ecs" }

View file

@ -6,7 +6,55 @@ use engine::prelude::*;
fn main() -> Result<()> {
let mut world_builder = World::builder();
Engine::new(EngineCreateInfo::default(), &mut world_builder)?;
Engine::new::<GameState>(EngineCreateInfo::default(), &mut world_builder)?;
world_builder.add_system(GameState::update);
world_builder.resources.insert(GameState::Startup);
world_builder.build().run()
}
enum GameState {
Startup,
Loading,
Menu,
Game(Game),
}
impl GameState {
fn update(world: &mut World) -> Result<bool> {
match world.resources.get_mut_unchecked::<Self>() {
GameState::Startup => (),
GameState::Loading => (),
GameState::Menu => (),
GameState::Game(game) => game.update(world)?,
}
Ok(true)
}
}
impl EventConsumer for GameState {
fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()> {
match self {
GameState::Startup => (),
GameState::Loading => (),
GameState::Menu => (),
GameState::Game(game) => game.event(world, event)?,
}
Ok(())
}
}
struct Game {}
impl Game {
fn update(&mut self, world: &mut World) -> Result<()> {
Ok(())
}
fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()> {
Ok(())
}
}

View file

@ -178,9 +178,9 @@ impl EventSystem {
.map_err(|s| anyhow::Error::msg(s))?)
}
pub fn poll_events<F, R>(&mut self, event_callback: F, mut resize: R) -> Result<bool>
pub fn poll_events<F, R>(&mut self, mut event_callback: F, mut resize: R) -> Result<bool>
where
F: Fn(Event) -> Result<()>,
F: FnMut(Event) -> Result<()>,
R: FnMut(u32, u32) -> Result<()>,
{
let mut controller_axis_changed = false;

View file

@ -113,7 +113,7 @@ impl PresentationCore {
pub fn poll_events<F, R>(&mut self, event_callback: F, resize_event: R) -> Result<bool>
where
F: Fn(Event) -> Result<()>,
F: FnMut(Event) -> Result<()>,
R: FnMut(u32, u32) -> Result<()>,
{
self.event_system.poll_events(event_callback, resize_event)

11
skybox/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "skybox"
version = "0.1.0"
authors = ["hodasemi <michaelh.95@t-online.de>"]
edition = "2024"
[dependencies]
anyhow.workspace = true
ecs = { path = "../ecs" }
context = { path = "../context" }

54
skybox/src/lib.rs Normal file
View file

@ -0,0 +1,54 @@
use std::{path::PathBuf, sync::Arc};
use anyhow::Result;
use context::prelude::*;
use ecs::*;
pub struct SkyBoxImages {
left: PathBuf,
right: PathBuf,
front: PathBuf,
back: PathBuf,
top: PathBuf,
bottom: PathBuf,
}
impl<T: ExactSizeIterator<Item = PathBuf>> From<T> for SkyBoxImages {
fn from(mut paths: T) -> Self {
debug_assert_eq!(paths.len(), 6);
Self {
left: paths.next().unwrap(),
right: paths.next().unwrap(),
front: paths.next().unwrap(),
back: paths.next().unwrap(),
top: paths.next().unwrap(),
bottom: paths.next().unwrap(),
}
}
}
pub struct SkyBox {
cube_map: Arc<Image>,
}
impl SkyBox {
pub fn new(world: &mut WorldBuilder, images: impl Into<SkyBoxImages>) -> Result<Self> {
let images = images.into();
let context = world.resources.get::<Context>();
let cube_map = Image::cube_map([
images.left.try_into()?,
images.right.try_into()?,
images.front.try_into()?,
images.back.try_into()?,
images.top.try_into()?,
images.bottom.try_into()?,
])?
.max_mip_map_levels()
.attach_pretty_sampler(context.device())?
.build(context.device(), context.queue())?;
Ok(Self { cube_map })
}
}