From 1bfac67b87942a3eb703c02ebf23f0016e1c2671 Mon Sep 17 00:00:00 2001 From: Franklin Date: Sat, 23 Mar 2024 11:44:34 +0100 Subject: [PATCH] Setup --- src/clone_entity_tree.rs | 62 ++++++++++++++++++++++++++++++ src/lib.rs | 9 ++++- src/markers.rs | 21 +++++++++++ src/markers/mod.rs | 3 -- src/needs_icon_marker.rs | 31 +++++++++++++++ src/plugin.rs | 54 +++++++++++++++++---------- src/queue.rs | 7 ---- src/setup.rs | 81 ++++++++++++++++++++++++++++++++++++++++ src/state.rs | 15 ++++++++ src/update.rs | 0 10 files changed, 251 insertions(+), 32 deletions(-) create mode 100644 src/clone_entity_tree.rs create mode 100644 src/markers.rs delete mode 100644 src/markers/mod.rs create mode 100644 src/needs_icon_marker.rs delete mode 100644 src/queue.rs create mode 100644 src/setup.rs create mode 100644 src/state.rs create mode 100644 src/update.rs diff --git a/src/clone_entity_tree.rs b/src/clone_entity_tree.rs new file mode 100644 index 0000000..286c1e7 --- /dev/null +++ b/src/clone_entity_tree.rs @@ -0,0 +1,62 @@ +use bevy::{ecs::{query::QueryEntityError, system::Command}, prelude::*}; +use std::sync::Arc; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EntityTreeNode { + pub source: Entity, + pub destination: Entity, + pub children: Vec, +} + +impl EntityTreeNode { + pub fn from_entity_recursive( + commands: &mut Commands, + from_entity: Entity, + q_children: &Query<&Children>, + ) -> EntityTreeNode { + let children = match q_children.get(from_entity) { + Ok(children) => children + .iter() + .map(|&child| { + EntityTreeNode::from_entity_recursive( + commands, child, q_children, + ) + }) + .collect::>(), + Err(QueryEntityError::QueryDoesNotMatch(_)) => vec![], + Err(e) => panic!("{}", e), + }; + EntityTreeNode { + source: from_entity, + destination: commands.spawn_empty().id(), + children, + } + } + + pub fn iter(&self) -> impl Iterator { + self.children.iter() + } +} + +pub fn clone_entity_tree( + world: &mut World, + EntityTreeNode { + source, + destination, + children, + }: &EntityTreeNode, +) { + //clone_entity_components(world, *source, *destination); + for node in children { + clone_entity_tree(world, node); + let mut destination = world.get_entity_mut(*destination).unwrap(); + destination.add_child(node.destination); + } +} +// uses arc to prevent cloning the whole tree. +pub struct CloneEntityTree(Arc); +impl Command for CloneEntityTree { + fn apply(self, world: &mut World) { + clone_entity_tree(world, &self.0); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 8f4b197..fae8dd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,8 @@ mod markers; -mod plugin; -mod queue; \ No newline at end of file +mod update; +mod setup; +mod state; +mod clone_entity_tree; + +pub mod plugin; +pub mod needs_icon_marker; \ No newline at end of file diff --git a/src/markers.rs b/src/markers.rs new file mode 100644 index 0000000..38a28f5 --- /dev/null +++ b/src/markers.rs @@ -0,0 +1,21 @@ +use bevy::ecs::component::Component; + +/// The root of all the scenes that will be generated from this plugin. +#[derive(Component, Debug)] +pub struct IconCreatorRootMarker; + +#[derive(Component, Debug)] +pub struct IconCreatorSceneRootMarker; + +#[derive(Component, Debug)] +pub struct IconCreatorCameraMarker; + +#[derive(Component, Debug)] +pub struct IconCreatorLightMarker; + +#[derive(Component, Debug)] +pub struct IconCreatorEntityParentMarker; + +/// Everything inside a scene should contain this marker with the scene's id. +#[derive(Component, Debug)] +pub struct InIconCreatorSceneMarker(pub u8); \ No newline at end of file diff --git a/src/markers/mod.rs b/src/markers/mod.rs deleted file mode 100644 index afe2f5c..0000000 --- a/src/markers/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ - -/// The root of all the scenes that will be generated from this plugin. -pub struct IconCreatorRootMarker; \ No newline at end of file diff --git a/src/needs_icon_marker.rs b/src/needs_icon_marker.rs new file mode 100644 index 0000000..258b56c --- /dev/null +++ b/src/needs_icon_marker.rs @@ -0,0 +1,31 @@ +use bevy::{ecs::component::Component, reflect::Reflect, transform::components::Transform, utils::Uuid}; + +/// Put this marker on any entity. This crate will then find this marker and copy all the entities underneath this entity, +/// then it will spawn them in the icon creator scene and once N number of frames have passed then render it to a texture. +#[derive(Debug, Component, Reflect, Default)] +pub struct NeedsIconMarker { + /// The transform to be applied to the parent entity when it gets spawned in the icon creator scene. + /// + /// If this is None then the transform will just be a Transform::default() + pub(crate) transform: Option, + /// The amount of frames that will be waited for the final image to be rendered once spawned. + /// + /// This crate already waits 3 frames for the entity to be spawned. + pub(crate) extra_frames: Option, + /// With this identifier you will be able to look up the icon once it's created. + pub(crate) id: Uuid, +} + +impl NeedsIconMarker { + pub fn new(id: Uuid) -> Self { + Self { transform: None, extra_frames: None, id } + } + pub fn with_transform(mut self, transform: Transform) -> Self { + self.transform = Some(transform); + self + } + pub fn with_extra_frames(mut self, extra_frames: u8) -> Self { + self.extra_frames = Some(extra_frames); + self + } +} \ No newline at end of file diff --git a/src/plugin.rs b/src/plugin.rs index 51aed77..a323b12 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,6 +1,11 @@ -use bevy::{app::Plugin, math::Vec3}; +use bevy::{app::{Plugin, Startup}, math::Vec3}; -const DEFAULT_WORLD_POSITION_FOR_ROOT: Vec3 = Vec3 { x: 4000.0, y: -300.0, z: 4000.0 }; +use crate::{setup::setup_icon_creation_scenes, state::IconCreatorState}; + +const DEFAULT_SCENES_AMOUNT: u8 = 1; +const DEFAULT_WORLD_POSITION_FOR_ROOT: Vec3 = Vec3 { x: 0.0, y: -300.0, z: 0.0 }; +const DEFAULT_RENDER_LAYER: u8 = 21; +const DEFAULT_LIGHT_INTENSITY: f32 = 14_000.0; /// Either use `IconCreatorPlugin::default()` or `IconCreatorPlugin::with_config(scenes)` pub struct IconCreatorPlugin { @@ -12,28 +17,37 @@ pub struct IconCreatorPlugin { scenes: u8, /// The global coordinates of the Root of the scenes. /// - /// Default is Vec3 { x: 4000.0, y: -300.0, z: 4000.0 } + /// Default is Vec3 { x: 0.0, y: -300.0, z: 0.0 } world_pos: Vec3, -} - - -impl Default for IconCreatorPlugin { - fn default() -> Self { - Self { scenes: 1, world_pos: DEFAULT_WORLD_POSITION_FOR_ROOT } - } -} - -impl IconCreatorPlugin { - pub fn with_config(scenes: u8, world_pos: Vec3) -> Self { - Self { - scenes, - world_pos, - } - } + /// The render layer everything inside this is going to be placed in + /// + /// Default is 21 + render_layer: u8, + /// Default is 14,000 + light_intensity: f32, } impl Plugin for IconCreatorPlugin { fn build(&self, app: &mut bevy::prelude::App) { - + app.insert_resource(IconCreatorState::new(self.scenes, self.world_pos, self.render_layer, self.light_intensity)); + + app.add_systems(Startup, setup_icon_creation_scenes); + } +} + +impl Default for IconCreatorPlugin { + fn default() -> Self { + Self { scenes: DEFAULT_SCENES_AMOUNT, world_pos: DEFAULT_WORLD_POSITION_FOR_ROOT, render_layer: DEFAULT_RENDER_LAYER, light_intensity: DEFAULT_LIGHT_INTENSITY } + } +} + +impl IconCreatorPlugin { + pub fn with_config(scenes: u8, world_pos: Vec3, render_layer: u8, light_intensity: f32) -> Self { + Self { + scenes, + world_pos, + render_layer, + light_intensity, + } } } \ No newline at end of file diff --git a/src/queue.rs b/src/queue.rs deleted file mode 100644 index 331713a..0000000 --- a/src/queue.rs +++ /dev/null @@ -1,7 +0,0 @@ -use bevy::ecs::system::Resource; - - -#[derive(Resource, Default, Debug, Clone)] -pub struct IconCreatorQueue { - -} \ No newline at end of file diff --git a/src/setup.rs b/src/setup.rs new file mode 100644 index 0000000..3447a06 --- /dev/null +++ b/src/setup.rs @@ -0,0 +1,81 @@ +use bevy::{prelude::*, render::{camera::ScalingMode, view::RenderLayers}}; + +use crate::{markers::{IconCreatorEntityParentMarker, IconCreatorRootMarker, IconCreatorSceneRootMarker, InIconCreatorSceneMarker}, state::IconCreatorState}; + +pub fn setup_icon_creation_scenes( + mut commands: Commands, + icon_creator_state: Res, +) { + let icon_creator_root_entity = commands.spawn(( + IconCreatorRootMarker, + TransformBundle::from_transform(Transform::from_translation(icon_creator_state.world_pos)), + VisibilityBundle::default(), + RenderLayers::layer(icon_creator_state.render_layer), + Name::new("Icon Creator Root Marker") + )).id(); + for scene_id in 0..icon_creator_state.scenes { + // Scene Root + let scene_root_entity = commands + .spawn(( + IconCreatorSceneRootMarker, + InIconCreatorSceneMarker(scene_id), + TransformBundle::default(), + VisibilityBundle::default(), + RenderLayers::layer(icon_creator_state.render_layer), + Name::new(format!("Scene Root with id: {scene_id}")), + )) + .set_parent(icon_creator_root_entity) + .id(); + // Camera + commands + .spawn(( + InIconCreatorSceneMarker(scene_id), + Camera3dBundle { + camera: Camera { + order: -1, + clear_color: ClearColorConfig::Custom(Color::NONE), + is_active: false, + hdr: true, + ..Default::default() + }, + projection: Projection::Orthographic(OrthographicProjection { + scaling_mode: ScalingMode::Fixed { width: 1.0, height: 1.0 }, + scale: 0.5, + ..Default::default() + }), + transform: Transform::from_xyz(0.0, 0.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ..Default::default() + }, + RenderLayers::layer(icon_creator_state.render_layer), + Name::new("Scene camera"), + )) + .set_parent(scene_root_entity); + // Light + commands + .spawn(( + PointLightBundle { + point_light: PointLight { + intensity: icon_creator_state.light_intensity, + ..Default::default() + }, + transform: Transform::from_xyz(0.0, 0.0, 2.5), + ..Default::default() + }, + InIconCreatorSceneMarker(scene_id), + RenderLayers::layer(icon_creator_state.render_layer), + Name::new("Scene Point Light"), + )) + .set_parent(scene_root_entity); + // Parent of the entities that will be spawned. + commands + .spawn(( + IconCreatorEntityParentMarker, + InIconCreatorSceneMarker(scene_id), + TransformBundle::default(), + VisibilityBundle::default(), + RenderLayers::layer(icon_creator_state.render_layer), + Name::new("Scene Entity Parent"), + )) + .set_parent(scene_root_entity); + } +} \ No newline at end of file diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..3966317 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,15 @@ +use bevy::{ecs::system::Resource, math::Vec3}; + +#[derive(Resource, Debug)] +pub struct IconCreatorState { + pub(crate) scenes: u8, + pub(crate) world_pos: Vec3, + pub(crate) render_layer: u8, + pub(crate) light_intensity: f32, +} + +impl IconCreatorState { + pub fn new(scenes: u8, world_pos: Vec3, render_layer: u8, light_intensity: f32) -> Self { + Self { scenes, world_pos, render_layer, light_intensity } + } +} \ No newline at end of file diff --git a/src/update.rs b/src/update.rs new file mode 100644 index 0000000..e69de29