From 63b49c70c79f8b6666efefb5b7d6fa12a45bcf43 Mon Sep 17 00:00:00 2001 From: Lillian Vixe Date: Thu, 6 Jun 2024 14:56:15 -0700 Subject: [PATCH] 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. --- src/vvedit/mod.rs | 46 +------ src/vvedit/s_editor_ui.rs | 79 +++++++++--- src/vvedit/s_orbit_camera.rs | 4 +- src/vvlib/s_structure_asset.rs | 211 +++++++++++++++++++++++++++++++-- 4 files changed, 265 insertions(+), 75 deletions(-) diff --git a/src/vvedit/mod.rs b/src/vvedit/mod.rs index 7c2a487..6375abd 100644 --- a/src/vvedit/mod.rs +++ b/src/vvedit/mod.rs @@ -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, - asset_server: Res, - mesh_assets: ResMut>, - mut oct_assets: ResMut>, - mut commands: Commands, - mut materials: ResMut>, -) { - 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() {} diff --git a/src/vvedit/s_editor_ui.rs b/src/vvedit/s_editor_ui.rs index 884cddf..c7d849a 100644 --- a/src/vvedit/s_editor_ui.rs +++ b/src/vvedit/s_editor_ui.rs @@ -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, @@ -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, asset_server: ResMut, + //mut pairs: ResMut, + //mesh_assets: ResMut>, + mut event_writer: EventWriter, ) { - spawn_camera(commands); + spawn_camera(&mut commands); let str = "test.vvs"; let handle = asset_server.load::(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, diff --git a/src/vvedit/s_orbit_camera.rs b/src/vvedit/s_orbit_camera.rs index fd5dbae..1caf242 100644 --- a/src/vvedit/s_orbit_camera.rs +++ b/src/vvedit/s_orbit_camera.rs @@ -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(( diff --git a/src/vvlib/s_structure_asset.rs b/src/vvlib/s_structure_asset.rs index b5fc371..ef412bb 100644 --- a/src/vvlib/s_structure_asset.rs +++ b/src/vvlib/s_structure_asset.rs @@ -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, pub element_data: HashMap, } + +#[derive(Component)] +pub struct StructureComponent { + pub asset: Handle, + pub nodes: HashMap, +} + +#[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, + materials: &mut ResMut>, + meshes: &mut ResMut>, + pairs: &mut ResMut, + 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, + mut tracker: Query<(Entity, &mut StructureComponent)>, + mut shaper: Query<(Entity, &mut Transform)>, + mut structure_assets: ResMut>, + mut asset_server: ResMut, + mut materials: ResMut>, + mut meshes: ResMut>, + mut pairs: ResMut, + 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, 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 { + pub fn process_from_save_format(&mut self, server: &mut ResMut) -> Option { 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::(); app.init_asset::(); + app.add_systems(Update, structure_update); + app.add_event::(); } } #[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())