This commit is contained in:
Franklin 2024-03-23 11:44:34 +01:00
parent 20f333c931
commit 1bfac67b87
10 changed files with 251 additions and 32 deletions

62
src/clone_entity_tree.rs Normal file
View File

@ -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<EntityTreeNode>,
}
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::<Vec<_>>(),
Err(QueryEntityError::QueryDoesNotMatch(_)) => vec![],
Err(e) => panic!("{}", e),
};
EntityTreeNode {
source: from_entity,
destination: commands.spawn_empty().id(),
children,
}
}
pub fn iter(&self) -> impl Iterator<Item = &EntityTreeNode> {
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<EntityTreeNode>);
impl Command for CloneEntityTree {
fn apply(self, world: &mut World) {
clone_entity_tree(world, &self.0);
}
}

View File

@ -1,3 +1,8 @@
mod markers;
mod plugin;
mod queue;
mod update;
mod setup;
mod state;
mod clone_entity_tree;
pub mod plugin;
pub mod needs_icon_marker;

21
src/markers.rs Normal file
View File

@ -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);

View File

@ -1,3 +0,0 @@
/// The root of all the scenes that will be generated from this plugin.
pub struct IconCreatorRootMarker;

31
src/needs_icon_marker.rs Normal file
View File

@ -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<Transform>,
/// 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<u8>,
/// 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
}
}

View File

@ -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,
}
}
}

View File

@ -1,7 +0,0 @@
use bevy::ecs::system::Resource;
#[derive(Resource, Default, Debug, Clone)]
pub struct IconCreatorQueue {
}

81
src/setup.rs Normal file
View File

@ -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<IconCreatorState>,
) {
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);
}
}

15
src/state.rs Normal file
View File

@ -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 }
}
}

0
src/update.rs Normal file
View File