Skip to content

Commit

Permalink
flatten mod hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
Utsira committed Jan 15, 2024
1 parent fc69d07 commit 5adc5ca
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 36 deletions.
File renamed without changes.
17 changes: 12 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ use bevy::{

mod loader;
mod scene;
mod hook;
mod systems;
mod parse;
mod mesh;
mod voxel;

#[cfg(test)]
mod tests;

pub use scene::{VoxelLayer, VoxelScene, VoxelSceneBundle, VoxelSceneHookBundle, VoxelModelInstance, VoxelModel};
pub use hook::VoxelSceneHook;
pub use loader::VoxLoaderSettings;
#[doc(inline)]
use loader::VoxSceneLoader;
use scene::VoxelModel;
pub use scene::{VoxelLayer, VoxelScene, VoxelSceneBundle, VoxelSceneHook, VoxelSceneHookBundle};
mod mesh;
mod voxel;

/// The core plugin adding functionality for loading `.vox` files.
///
Expand All @@ -73,7 +80,7 @@ impl Plugin for VoxScenePlugin {
.register_asset_loader(VoxSceneLoader)
.add_systems(
SpawnScene,
(scene::systems::spawn_vox_scenes, scene::systems::run_hooks).chain(),
(systems::spawn_vox_scenes, systems::run_hooks).chain(),
);
}
}
8 changes: 4 additions & 4 deletions src/loader.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::voxel::VoxelData;
use crate::{voxel::VoxelData, parse::{parse_xform_node, find_subasset_names}};
use anyhow::anyhow;
use bevy::{
asset::{io::Reader, AssetLoader, AsyncReadExt, Handle, LoadContext},
Expand All @@ -13,7 +13,7 @@ use bevy::{
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::scene::{self, LayerInfo, VoxelModel, VoxelNode, VoxelScene};
use crate::scene::{LayerInfo, VoxelModel, VoxelNode, VoxelScene};

/// An asset loader capable of loading models in `.vox` files as usable [`bevy::render::mesh::Mesh`]es.
///
Expand Down Expand Up @@ -392,7 +392,7 @@ impl VoxSceneLoader {
// Scene graph

let root =
scene::parse::parse_xform_node(&file.scenes, &file.scenes[0], None, load_context);
parse_xform_node(&file.scenes, &file.scenes[0], None, load_context);
let layers: Vec<LayerInfo> = file
.layers
.iter()
Expand All @@ -402,7 +402,7 @@ impl VoxSceneLoader {
})
.collect();
let mut subasset_by_name: HashMap<String, VoxelNode> = HashMap::new();
scene::parse::find_subasset_names(&mut subasset_by_name, &root);
find_subasset_names(&mut subasset_by_name, &root);

for (subscene_name, node) in subasset_by_name {
load_context.labeled_asset_scope(subscene_name.clone(), |_| VoxelScene {
Expand Down
2 changes: 1 addition & 1 deletion src/scene/parse.rs → src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy::{
};
use dot_vox::{Frame, SceneNode};

use super::VoxelNode;
use crate::scene::VoxelNode;

pub(crate) fn parse_xform_node(
graph: &Vec<SceneNode>,
Expand Down
65 changes: 49 additions & 16 deletions src/scene/mod.rs → src/scene.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
mod hook;
pub(crate) mod parse;
pub(super) mod systems;
#[cfg(test)]
mod tests;
use bevy::{
asset::{Asset, Handle},
ecs::{bundle::Bundle, component::Component},
Expand All @@ -12,13 +7,14 @@ use bevy::{
render::{mesh::Mesh, view::Visibility},
transform::components::Transform,
};
pub use hook::VoxelSceneHook;

use crate::voxel::VoxelData;
use crate::{voxel::VoxelData, 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.
/// ```no_run
/// # use bevy::prelude::*;
/// # use bevy_vox_scene::VoxelSceneBundle;
Expand Down Expand Up @@ -55,7 +51,37 @@ pub struct VoxelSceneBundle {
/// A component bundle for spawning Voxel Scenes, with a [`VoxelSceneHook`].
///
/// The root of the spawned scene will be the entity that has this bundle.
/// The [`VoxelSceneHook`] allows you to easily modify Entities deep within the scene hierarchy.
/// 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`].
Expand All @@ -81,18 +107,22 @@ pub struct VoxelScene {

#[derive(Debug, Clone, Default)]
pub(crate) struct VoxelNode {
name: Option<String>,
transform: Mat4,
children: Vec<VoxelNode>,
model: Option<Handle<VoxelModel>>,
is_hidden: bool,
layer_id: u32,
pub name: Option<String>,
pub transform: Mat4,
pub children: Vec<VoxelNode>,
pub model: Option<Handle<VoxelModel>>,
pub is_hidden: bool,
pub layer_id: u32,
}

/// Asset containing the voxel data for a model, as well as handles to the mesh derived from that data and the material
#[derive(Asset, TypePath)]
pub(crate) struct VoxelModel {
pub struct VoxelModel {
/// The voxel data used to generate the mesh
pub data: VoxelData,
/// Handle to the model's mesh
pub mesh: Handle<Mesh>,
/// Handle to the model's material
pub material: Handle<StandardMaterial>,
}

Expand All @@ -102,8 +132,11 @@ pub(crate) struct LayerInfo {
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)]
pub struct VoxelModelInstance(Handle<VoxelModel>);
pub struct VoxelModelInstance(pub Handle<VoxelModel>);

/// A component specifying which layer the Entity belongs to, with an optional name.
///
Expand Down
2 changes: 1 addition & 1 deletion src/scene/systems.rs → src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use bevy::{
transform::components::Transform,
};

use super::{VoxelLayer, VoxelModel, VoxelModelInstance, VoxelNode, VoxelScene};
use crate::scene::{VoxelLayer, VoxelModel, VoxelModelInstance, VoxelNode, VoxelScene};

pub(crate) fn spawn_vox_scenes(
mut commands: Commands,
Expand Down
16 changes: 12 additions & 4 deletions src/scene/tests.rs → src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::*;
use crate::VoxScenePlugin;
use crate::{VoxScenePlugin, scene::VoxelModelInstance};
use bevy::{
app::App,
asset::{AssetApp, AssetPlugin, AssetServer, Assets, LoadState},
asset::{AssetApp, AssetPlugin, AssetServer, Assets, LoadState, Handle},
core::Name,
hierarchy::Children,
render::texture::ImagePlugin,
MinimalPlugins,
render::{texture::ImagePlugin, mesh::Mesh},
MinimalPlugins, pbr::StandardMaterial, utils::hashbrown::HashSet,
};

#[async_std::test]
Expand Down Expand Up @@ -191,6 +191,14 @@ async fn test_spawn_system() {
3,
"But only 3 of the voxel nodes are named"
);
let mut instance_query = app.world.query::<&VoxelModelInstance>();
assert_eq!(
instance_query.iter(&app.world).len(),
4,
"4 model instances spawned in this scene slice"
);
let models: HashSet<Handle<VoxelModel>> = instance_query.iter(&app.world).map(|c| c.0.clone()).collect();
assert_eq!(models.len(), 2, "Instances point to 2 unique models");
assert_eq!(
app.world
.get::<Name>(entity)
Expand Down
10 changes: 5 additions & 5 deletions src/voxel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use ndshape::Shape;

// trait implementation rules requires the use of a newtype to allow meshing.
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) struct Voxel {
pub(crate) index: u8,
pub(crate) is_translucent: bool,
pub struct Voxel {
pub index: u8,
pub is_translucent: bool,
}

pub(crate) const EMPTY_VOXEL: Voxel = Voxel {
pub const EMPTY_VOXEL: Voxel = Voxel {
index: 255,
is_translucent: false,
};
Expand All @@ -34,7 +34,7 @@ impl MergeVoxel for Voxel {
}
}

pub(crate) struct VoxelData {
pub struct VoxelData {
pub shape: RuntimeShape<u32, 3>,
pub voxels: Vec<Voxel>,
}
Expand Down

0 comments on commit 5adc5ca

Please sign in to comment.