1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
mod hook;
pub(super) mod systems;
use bevy::{
asset::{Asset, Handle},
ecs::{bundle::Bundle, component::Component},
math::Mat4,
reflect::TypePath,
render::view::Visibility,
transform::components::Transform,
};
use crate::VoxelModelCollection;
pub use hook::VoxelSceneHook;
/// A component bundle for spawning Voxel Scenes.
///
/// The root of the spawned scene will be the entity that has this bundle.
/// In addition to the standard components bevy uses to organise and render pbr meshes,
/// spawned entities will also have [`VoxelLayer`] and [`VoxelModelInstance`] components added.
/// ```
/// # use bevy::prelude::*;
/// # use bevy_vox_scene::VoxelSceneBundle;
///
/// fn setup(
/// mut commands: Commands,
/// assets: Res<AssetServer>,
/// ) {
/// commands.spawn(VoxelSceneBundle {
/// scene: assets.load("study.vox"),
/// ..default()
/// });
///
/// commands.spawn(VoxelSceneBundle {
/// // Load a single model using the name assigned to it in MagicaVoxel.
/// // If a model is nested in a named group, than the group will form part of the path
/// // Path components are separated with a slash
/// scene: assets.load("study.vox#workstation/desk"),
/// ..default()
/// });
/// }
/// ```
#[derive(Bundle, Default)]
pub struct VoxelSceneBundle {
/// A handle to a [`VoxelScene`], typically loaded from a ".vox" file via the [`bevy::asset::AssetServer`].
/// This Entity will become the root of the spawned Voxel Scene.
pub scene: Handle<VoxelScene>,
/// The transform of the scene root. This will override whatever the root transform is in the Magica Voxel scene.
pub transform: Transform,
/// The visibility of the scene root. This will override whatever the root visibility is in the Magical Voxel scene.
pub visibility: Visibility,
}
/// A component bundle for spawning Voxel Scenes, with a [`VoxelSceneHook`].
///
/// The root of the spawned scene will be the entity that has this bundle.
/// In addition to the standard components bevy uses to organise and render pbr meshes,
/// spawned entities will also have [`VoxelLayer`] and [`VoxelModelInstance`] components added.
/// The [`VoxelSceneHook`] allows you to modify entities spawned within the hierarchy.
/// A typical use-case would be adding additional components based on an entity's [`bevy::core::Name`]
/// or [`VoxelLayer`].
/// ```
/// # use bevy::{prelude::*, app::AppExit, utils::HashSet};
/// # use bevy_vox_scene::{VoxelSceneHook, VoxelSceneHookBundle};
/// #
/// # #[derive(Component)]
/// # struct Fish;
/// #
/// # fn setup(
/// # mut commands: Commands,
/// # assets: Res<AssetServer>,
/// # ) {
/// VoxelSceneHookBundle {
/// scene: assets.load("study.vox#tank"),
/// hook: VoxelSceneHook::new(move |entity, commands| {
/// let Some(name) = entity.get::<Name>() else { return };
/// match name.as_str() {
/// "tank/goldfish" | "tank/tetra" => {
/// commands.insert(Fish);
/// }
/// _ => {},
/// }
/// }),
/// ..default()
/// };
/// # }
/// ```
#[derive(Bundle, Default)]
pub struct VoxelSceneHookBundle {
/// A handle to a [`VoxelScene`], typically loaded from a ".vox" file via the [`bevy::asset::AssetServer`].
/// This Entity will become the root of the spawned Voxel Scene.
pub scene: Handle<VoxelScene>,
/// A [`VoxelSceneHook`] allows you to specify a closure that will be run for each Entity spawned in the scene graph.
pub hook: VoxelSceneHook,
/// The transform of the scene root. This will override whatever the root transform is in the Magica Voxel scene.
pub transform: Transform,
/// The visibility of the scene root. This will override whatever the root visibility is in the Magical Voxel scene.
pub visibility: Visibility,
}
/// A representation of the Voxel Scene Graph.
///
/// To spawn a voxel scene, add a [`Handle<VoxelScene>`](VoxelScene), [`VoxelSceneBundle`], or [`VoxelSceneHookBundle`] to an Entity.
/// Voxel Scenes can be loaded from Magica Voxel .vox files.
#[derive(Asset, TypePath, Debug)]
pub struct VoxelScene {
pub(crate) root: VoxelNode,
pub(crate) layers: Vec<LayerInfo>,
pub(crate) model_collection: Handle<VoxelModelCollection>,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct VoxelNode {
pub name: Option<String>,
pub transform: Mat4,
pub children: Vec<VoxelNode>,
pub model_id: Option<usize>,
pub is_hidden: bool,
pub layer_id: u32,
}
#[derive(Debug, Clone)]
pub(crate) struct LayerInfo {
pub name: Option<String>,
pub is_hidden: bool,
}
/// Component wrapping the handle to the [`VoxelModel`]
///
/// When the scene is spawned this component gets added to entities with a voxel mesh.
#[derive(Component, Clone)]
pub struct VoxelModelInstance {
/// Handle to the collection that this model is instanced from
pub collection: Handle<VoxelModelCollection>,
/// The name of the model within the collection
pub model_name: String,
}
/// A component specifying which layer the Entity belongs to, with an optional name.
///
/// This can be configured in the Magica Voxel world editor.
#[derive(Component, Clone)]
pub struct VoxelLayer {
/// The identifier for the layer. Magic Voxel 0.99.6 allows you to assign nodes to one of 8 layers,
/// so this value will be an index in the range 0 through 7.
pub id: u32,
/// An optional name for the Layer, assignable in Magica Voxel layer editor.
pub name: Option<String>,
}