single-build structure view on-load.

TODO: swapping between grid view and structure view. multiple of each being loaded, selecting bringing it to view. creating new structure and grid assets from UI.
This commit is contained in:
Lillian Vixe 2024-06-06 14:56:15 -07:00
parent 0e19a10325
commit 63b49c70c7
4 changed files with 265 additions and 75 deletions

View file

@ -3,7 +3,7 @@
use bevy::{diagnostic::FrameTimeDiagnosticsPlugin, prelude::*, window::WindowResolution};
use crate::vvlib::{
s_oct_asset::{self, OctAssetMarker, OctTreeAsset},
s_oct_asset::{self},
s_structure_asset::StructureAssetPlugin,
};
@ -17,7 +17,7 @@ pub fn setup(app: &mut App) -> &mut App {
app.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
resolution: WindowResolution::new(1152., 864.).with_scale_factor_override(1.0),
title: "testbed".to_string(),
title: "VixeVoxe".to_string(),
..default()
}),
..default()
@ -37,44 +37,4 @@ pub fn setup(app: &mut App) -> &mut App {
s_editor_ui::register_edit_ui(app)
}
pub fn startup(
mut pairs: ResMut<s_oct_asset::MeshingOctTreePairs>,
asset_server: Res<AssetServer>,
mesh_assets: ResMut<Assets<Mesh>>,
mut oct_assets: ResMut<Assets<OctTreeAsset>>,
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let id = OctTreeAsset::load(&mut pairs, asset_server, mesh_assets, "test.vvg".into());
let parent = commands
.spawn(TransformBundle {
local: Transform::from_scale(Vec3::splat(0.25)),
..Default::default()
})
.id();
let child = commands
.spawn((
PbrBundle {
mesh: id.clone(),
material: materials.add(Color::rgb(1., 1., 1.)),
..default()
},
OctAssetMarker {
oct_handle: pairs.oct_handle_for(id, &mut oct_assets),
},
))
.id();
commands.entity(parent).add_child(child);
let light_transform = Transform::from_xyz(1.8, 1.8, 1.8).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 100000.0,
range: 1000.0,
..default()
},
transform: light_transform,
..default()
});
}
pub fn startup() {}

View file

@ -1,16 +1,7 @@
use bevy::{
app::{Startup, Update},
asset::{AssetServer, Assets, Handle},
ecs::{
entity::Entity,
query::With,
system::{Commands, Query, Res, ResMut, Resource},
},
math::Vec3,
prelude::default,
render::{camera::Camera, color::Color},
transform::components::{GlobalTransform, Transform},
window::{PrimaryWindow, Window, WindowResolution},
app::{Startup, Update}, asset::{AssetServer, Assets, Handle}, ecs::{
entity::Entity, event::EventWriter, query::With, system::{Commands, Query, Res, ResMut, Resource}
}, hierarchy::BuildChildren, math::Vec3, pbr::{PointLight, PointLightBundle}, prelude::{default, SpatialBundle}, render::{camera::Camera, color::Color}, transform::{components::{GlobalTransform, Transform}, TransformBundle}, window::{PrimaryWindow, Window, WindowResolution}
};
use bevy_egui::{
egui::{self, color_picker, epaint::Hsva, Id, Pos2, Rect, ScrollArea},
@ -21,7 +12,7 @@ use crate::{
vvedit::s_editor_bevy_input_shim::keybind_codes::REMOVE_VOXEL,
vvlib::{
s_inputs::InputRegister, s_intersections::octtree_ray_overlap, s_obb::OBB,
s_oct_asset::OctAssetMarker, s_structure_asset::StructureAsset,
s_oct_asset::OctAssetMarker, s_structure_asset::{StructureAsset, StructureComponent, StructureUpdateMessage, StructureUpdateType},
},
};
use crate::{
@ -59,6 +50,7 @@ pub struct EditWindowUIState {
pub selected_structure_element: String,
pub selected_structure: String,
pub selected_grid: String,
pub display_state: DisplayState,
}
impl Default for EditWindowUIState {
fn default() -> Self {
@ -71,6 +63,7 @@ impl Default for EditWindowUIState {
selected_structure_element: "".into(),
selected_structure: "".into(),
selected_grid: "".into(),
display_state: Default::default()
}
}
}
@ -91,6 +84,14 @@ impl PopupWindowMode {
}
}
#[derive(Default, Clone)]
pub enum DisplayState {
#[default]
None, //nothing loaded yet
GridView(String),
StructureView(String),
}
#[derive(Clone)]
pub struct EditWindowEguiState {
pub popup_identifier: Option<Id>,
@ -184,7 +185,6 @@ pub fn register_edit_ui(
) -> &mut bevy::prelude::App {
app.insert_resource(EditWindowUIState {
brush_color: egui_color_from(Color::RED),
grids: Vec::new(),
..default()
});
app.add_plugins(EguiPlugin);
@ -199,19 +199,64 @@ pub fn register_edit_ui(
pub fn startup_system_edit_ui(
// formatting comment
commands: Commands,
mut commands: Commands,
mut shared_ui_state: ResMut<EditWindowUIState>,
asset_server: ResMut<AssetServer>,
//mut pairs: ResMut<MeshingOctTreePairs>,
//mesh_assets: ResMut<Assets<Mesh>>,
mut event_writer: EventWriter<StructureUpdateMessage>,
) {
spawn_camera(commands);
spawn_camera(&mut commands);
let str = "test.vvs";
let handle = asset_server.load::<StructureAsset>(str);
let data = StructureEditData {
path: str.into(),
id: handle,
id: handle.clone(),
has_changed_since_last_save: false,
};
shared_ui_state.structures.push(data);
//let id = OctTreeAsset::load(&mut pairs, asset_server.into(), mesh_assets, "test.vvg".into());
let parent = commands
.spawn(TransformBundle {
local: Transform::from_scale(Vec3::splat(1f32)),
..Default::default()
})
.id();
/*let child = commands
.spawn((
PbrBundle {
mesh: id.clone(),
material: materials.add(Color::rgb(1., 1., 1.)),
..default()
},
OctAssetMarker {
oct_handle: pairs.oct_handle_for(id, &mut oct_assets),
},
))
.id();
commands.entity(parent).add_child(child);*/
let id = commands.spawn((SpatialBundle::INHERITED_IDENTITY, StructureComponent {
asset: handle,
nodes: Default::default(),
})).id();
commands.entity(parent).add_child(id.clone());
event_writer.send(StructureUpdateMessage {
update_type: StructureUpdateType::Build,
entity: id,
});
let light_transform = Transform::from_xyz(7f32, 7f32, 7f32).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 100000.0,
range: 10000.0,
..default()
},
transform: light_transform,
..default()
});
}
fn update_ui_scale_factor(
mut egui_settings: ResMut<EguiSettings>,

View file

@ -127,8 +127,8 @@ pub mod orbit_camera {
}
/// Spawn a camera like this
pub fn spawn_camera(mut commands: Commands) {
let translation = Vec3::new(-2.0, 2.5, 5.0);
pub fn spawn_camera(commands: &mut Commands) {
let translation = Vec3::new(-5.0, 5f32, 10.0);
let radius = translation.length();
commands.spawn((

View file

@ -1,7 +1,20 @@
use std::cmp::Ordering;
use bevy::{
app::{App, Plugin},
asset::{Asset, AssetApp, AssetLoader, AssetServer, AsyncReadExt, Handle},
app::{App, Plugin, Update},
asset::{Asset, AssetApp, AssetLoader, AssetServer, Assets, AsyncReadExt, Handle},
ecs::{
component::Component,
entity::Entity,
event::{Event, EventReader},
system::{Commands, Query, ResMut},
world::Mut,
},
hierarchy::{BuildChildren, DespawnRecursiveExt},
pbr::{PbrBundle, StandardMaterial},
prelude::{default, SpatialBundle},
reflect::TypePath,
render::{color::Color, mesh::Mesh, view::Visibility},
transform::components::Transform,
utils::{hashbrown::HashMap, thiserror},
};
@ -10,7 +23,7 @@ use s_string_tree::StringTree;
use crate::vvedit::s_string_tree;
use thiserror::Error;
use super::s_oct_asset::OctTreeAsset;
use super::s_oct_asset::{MeshingOctTreePairs, OctAssetMarker, OctTreeAsset};
#[derive(Asset, TypePath)]
pub struct StructureAsset {
@ -18,6 +31,169 @@ pub struct StructureAsset {
pub default_pose_positions: HashMap<String, Transform>,
pub element_data: HashMap<String, ElementData>,
}
#[derive(Component)]
pub struct StructureComponent {
pub asset: Handle<StructureAsset>,
pub nodes: HashMap<String, Entity>,
}
#[derive(Event)]
pub struct StructureUpdateMessage {
pub update_type: StructureUpdateType,
pub entity: Entity,
}
pub enum StructureUpdateType {
Build, // just builds.
Rebuild, // deletes old nodes and rebuilds
Reshape, //moves transforms and that's it
}
pub fn build_tree(
root_entity: &Entity,
asset: &StructureAsset,
structure_component: Mut<StructureComponent>,
materials: &mut ResMut<Assets<StandardMaterial>>,
meshes: &mut ResMut<Assets<Mesh>>,
pairs: &mut ResMut<MeshingOctTreePairs>,
commands: &mut Commands,
) {
let mut sorted_construction_order = asset.layout.list_of_elements();
sorted_construction_order.sort_by(|left, right| {
if let Some(left) = asset.layout.depth_of(left) {
if let Some(right) = asset.layout.depth_of(right) {
return left.cmp(&right);
}
}
return Ordering::Equal;
});
for each in sorted_construction_order {
if let Some(element_data) = asset.element_data.get(&each) {
let trans = {
if let Some(transform) = asset.default_pose_positions.get(&each) {
transform
} else {
&Transform::IDENTITY
}
};
let p_entity = {
if let Some(parent) = asset.layout.parent_of(&each) {
if let Some(result) = structure_component.nodes.get(parent) {
result
} else {
&root_entity
}
} else {
&root_entity
}
};
let child = {
match element_data {
ElementData::None => {
let mut spat_bundle = SpatialBundle::from_transform(trans.clone());
spat_bundle.visibility = Visibility::Inherited;
commands.spawn(spat_bundle).id()
}
ElementData::Unprocessed(_) => {
println!("somehow not processed in build");
let mut spat_bundle = SpatialBundle::from_transform(trans.clone());
spat_bundle.visibility = Visibility::Inherited;
commands.spawn(spat_bundle).id()
}
ElementData::MeshAsset(handle, _) => {
let mut spat_bundle = SpatialBundle::from_transform(trans.clone());
spat_bundle.visibility = Visibility::Inherited;
commands
.spawn(spat_bundle)
.with_children(|parent| {
parent.spawn((
PbrBundle {
mesh: pairs.mesh_handle_for(handle.clone(), meshes),
material: materials.add(Color::rgb(1., 1., 1.)),
..default()
},
OctAssetMarker {
oct_handle: handle.clone(),
},
));
})
.id()
}
}
};
commands.entity(p_entity.clone()).add_child(child.clone());
println!("{}", child.clone().to_bits());
}
}
}
pub fn structure_update(
mut events: EventReader<StructureUpdateMessage>,
mut tracker: Query<(Entity, &mut StructureComponent)>,
mut shaper: Query<(Entity, &mut Transform)>,
mut structure_assets: ResMut<Assets<StructureAsset>>,
mut asset_server: ResMut<AssetServer>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut pairs: ResMut<MeshingOctTreePairs>,
mut commands: Commands,
) {
for event in events.read() {
if let Ok((root_entity, mut structure_component)) = tracker.get_mut(event.entity) {
let handle = structure_component.asset.clone();
if let Some(asset) = structure_assets.get_mut(handle.clone()) {
for (_, element) in &mut asset.element_data {
if element.needs_processing() {
if let Some(processed_value) =
element.process_from_save_format(&mut asset_server)
{
*element = processed_value;
}
}
}
}
if let Some(asset) = structure_assets.get_mut(handle.clone()) {
match event.update_type {
StructureUpdateType::Build => build_tree(
&root_entity,
asset,
structure_component,
&mut materials,
&mut meshes,
&mut pairs,
&mut commands,
),
StructureUpdateType::Rebuild => {
for (_, each) in &structure_component.nodes {
commands.entity(each.clone()).despawn_recursive();
}
structure_component.nodes.clear();
build_tree(
&root_entity,
asset,
structure_component,
&mut materials,
&mut meshes,
&mut pairs,
&mut commands,
)
}
StructureUpdateType::Reshape => {
for (name, ent) in &structure_component.nodes {
if let Ok((_, mut trans)) = shaper.get_mut(ent.clone()) {
if let Some(value) = asset.default_pose_positions.get(name) {
trans.clone_from(value);
}
}
}
}
}
}
}
}
}
#[derive(Clone)]
pub enum ElementData {
None,
@ -25,6 +201,12 @@ pub enum ElementData {
MeshAsset(Handle<OctTreeAsset>, String), //store path
}
impl ElementData {
pub fn needs_processing(&self) -> bool {
match self {
Self::Unprocessed(_) => true,
_ => false,
}
}
pub fn is_none(&self) -> bool {
match self {
ElementData::None => true,
@ -38,11 +220,13 @@ impl ElementData {
ElementData::MeshAsset(_, path) => Some(format!("grid|{path}")),
}
}
pub fn process_from_save_format(&mut self, server: &mut AssetServer) -> Option<Self> {
pub fn process_from_save_format(&mut self, server: &mut ResMut<AssetServer>) -> Option<Self> {
let mut result_change = ElementData::None;
match self {
ElementData::Unprocessed(contents) => {
println!("{}", contents.clone());
let mut sides = contents.split("|");
sides.next();
let left = sides.next();
if left.is_none() {
return None;
@ -82,6 +266,8 @@ impl Plugin for StructureAssetPlugin {
fn build(&self, app: &mut App) {
app.init_asset_loader::<StructureLoader>();
app.init_asset::<StructureAsset>();
app.add_systems(Update, structure_update);
app.add_event::<StructureUpdateMessage>();
}
}
#[derive(Default)]
@ -494,11 +680,6 @@ pub mod serialization {
} else {
return None;
}*/
if let Some(children) = each.children() {
for each in children {
to_process.push(each);
}
}
}
// v HELPER FUNCTION
fn save_child(element: &String, tree: &StringTree, data: &mut String) {
@ -556,14 +737,18 @@ pub mod serialization {
data += "||";
// v NODE DATA SUCH AS RELIANT GRIDS
for (name, element_data) in &asset.element_data {
data += NEWLINE;
data += name.as_str();
data += "|";
let save_formatted = element_data.to_save_format();
if save_formatted.is_none() {
println!("Couldn't save element data to save format");
return None;
}
data += save_formatted.unwrap().as_str();
let formatted = save_formatted.unwrap();
if formatted.trim() != "" {
data += NEWLINE;
data += name.as_str();
data += "|";
data += formatted.as_str();
}
}
// ^ NODE DATA SUCH AS RELIANT GRIDS
Some(data.as_bytes().to_vec())