working add-new-assets-at-runtime

NOT WORKING: selection swapper / seeing loaded asset in editor after creating or after loading.
This commit is contained in:
Lillian Vixe 2024-06-16 13:21:38 -07:00
parent 20f554b8d5
commit 41b673753e
5 changed files with 174 additions and 64 deletions

View file

@ -1,8 +1,5 @@
version 1
torso|head|waist|frontleftpaw|frontrightpaw
head|leftear|rightear
waist|tail|backleftpaw|backrightpaw
test
||
element|torso
position|0|0|0
@ -12,5 +9,13 @@ element|head
position|0|0|0
scale|1|1|1
rotation|0|0|0|1
element|test
position|0|0|0
scale|1|1|1
rotation|0|0|0|1
element|
position|30|0|0
scale|1|1|1
rotation|0|0|0|1
||
head|grid|test.vvg

View file

@ -246,16 +246,19 @@ pub fn startup_system_edit_ui(
mut event_writer: EventWriter<StructureUpdateMessage>,
) {
spawn_camera(&mut commands);
/*
let str = "test.vvs";
let handle = asset_server.load::<StructureAsset>(str);
//let id = OctTreeAsset::load(&mut pairs, asset_server.into(), mesh_assets, "test.vvg".into());
*/
let display_parent = commands
.spawn(TransformBundle {
local: Transform::from_scale(Vec3::splat(1f32)),
.spawn(SpatialBundle {
visibility: Visibility::Visible,
transform: Transform::from_scale(Vec3::splat(0.25f32)),
..Default::default()
})
.id();
shared_ui_state.display_root = display_parent;
/*
let id = commands.spawn((SpatialBundle {
visibility: Visibility::Visible,
..Default::default()
@ -263,7 +266,6 @@ pub fn startup_system_edit_ui(
asset: handle.clone(),
nodes: Default::default(),
})).id();
shared_ui_state.display_root = display_parent;
let data = StructureEditData {
path: str.into(),
id: handle.clone(),
@ -276,6 +278,7 @@ pub fn startup_system_edit_ui(
update_type: StructureUpdateType::Rebuild,
entity: id,
});
*/
let light_transform = Transform::from_xyz(4f32, 4f32, 4f32).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(PointLightBundle {
@ -448,7 +451,7 @@ pub fn edit_window_ui(
window: Query<&Window>,
mut asset_server: ResMut<AssetServer>,
mut event_writer: EventWriter<StructureUpdateMessage>,
//commands: Commands,
mut commands: Commands,
) {
shared_ui_state.egui.windows.clear();
let title = String::from("VVEdit");
@ -601,17 +604,19 @@ pub fn edit_window_ui(
shared_ui_state.selection = Selection::None;
}
}
let mut selection: Selection = shared_ui_state.selection.clone();
ui.collapsing("grid assets", |ui| {
if !shared_ui_state.selection.is_none() {
if ui.button("Deselect Asset").clicked() {
shared_ui_state.selection = Selection::None;
}
}
for (id, _asset) in (&grid_assets).iter() {
let path = asset_server.get_path(id.untyped());
if let Some(path) = path {
ui.label(path.to_string().as_str());
}
for grid in &shared_ui_state.grids {
ui.radio_value(
&mut selection,
Selection::Grid(grid.path.to_string()),
grid.path.to_string().as_str(),
);
}
});
ui.collapsing("structure assets", |ui| {
@ -620,19 +625,17 @@ pub fn edit_window_ui(
shared_ui_state.selection = Selection::None;
}
}
for (id, _asset) in (&structure_assets).iter() {
let path = asset_server.get_path(id.untyped());
if let Some(path) = path {
//ui.label(path.to_string().as_str());
ui.radio_value(
&mut shared_ui_state.selection,
Selection::Structure(path.to_string()),
path.to_string().as_str(),
);
}
for structure in &shared_ui_state.structures {
ui.radio_value(
&mut selection,
Selection::Grid(structure.path.to_string()),
structure.path.to_string().as_str(),
);
}
});
if selection != shared_ui_state.selection {
shared_ui_state.selection = selection;
}
let mut selected_structure = false;
let mut selection = Option::<StringTree>::None;
if let Selection::Structure(select) = &shared_ui_state.selection {
@ -812,6 +815,6 @@ pub fn edit_window_ui(
&mut asset_server,
&mut structure_assets,
&mut event_writer,
//&mut commands
&mut commands
);
}

View file

@ -1,10 +1,16 @@
use std::{fs, io, path::Path};
use std::{
fs, io,
path::{Path, PathBuf},
sync::RwLock,
};
use bevy::{
asset::{AssetServer, Assets},
ecs::{entity::Entity, event::EventWriter, system::ResMut},
hierarchy::BuildChildren,
math::{Quat, Vec3},
render::color::Color,
prelude::{Commands, SpatialBundle},
render::{color::Color, view::Visibility},
utils::hashbrown::hash_map::Entry,
};
use bevy_egui::{
@ -22,7 +28,10 @@ use crate::{
vvlib::{
s_identifier_validation::{self, is_valid},
s_oct_asset::OctTreeAsset,
s_structure_asset::{StructureAsset, StructureUpdateMessage, StructureUpdateType},
s_octtree::OctTree,
s_structure_asset::{
StructureAsset, StructureComponent, StructureUpdateMessage, StructureUpdateType,
},
},
};
@ -81,7 +90,7 @@ pub fn show_popup(
asset_server: &mut ResMut<AssetServer>,
structure_assets: &mut ResMut<Assets<StructureAsset>>,
event_writer: &mut EventWriter<StructureUpdateMessage>,
//commands: &mut Commands,
commands: &mut Commands,
) {
enum PopupStateChange {
None,
@ -89,7 +98,7 @@ pub fn show_popup(
RenameComplete,
Reparent(String, String, String), //structure subject, name of element to reparent, new parent
Addition(String, String, String), //structure subject, new element name, new parent
Cancel,
Close,
}
let mut state_change = PopupStateChange::None;
//let mut added_valid_name = false;
@ -184,7 +193,7 @@ pub fn show_popup(
});
// todo: rename action. edit subject action (mesh, light), remove action (with, without reparenting)
if ui.button("Cancel").clicked() {
state_change = PopupStateChange::Cancel;
state_change = PopupStateChange::Close;
}
});
}
@ -302,21 +311,40 @@ pub fn show_popup(
Extension::Invalid => {}
Extension::Structure => {
let handle = asset_server.load::<StructureAsset>(path_pre.clone());
let data = StructureEditData {
path: path_pre,
id: handle,
has_changed_since_last_save: false,
edit_entity: Entity::PLACEHOLDER, //BAD BAD BAD
};
let handleclone = handle.clone();
let mut loaded_already = false;
for each in &state.structures {
if each.id == data.id {
if each.id == handleclone {
loaded_already = true;
}
}
if !loaded_already {
let id = commands
.spawn((
SpatialBundle {
visibility: Visibility::Visible,
..Default::default()
},
StructureComponent {
asset: handleclone,
nodes: Default::default(),
},
))
.id();
let data = StructureEditData {
path: path_pre,
id: handle,
has_changed_since_last_save: false,
edit_entity: id.clone(),
};
state.structures.push(data);
commands.entity(state.display_root).add_child(id);
event_writer.send(StructureUpdateMessage {
update_type: StructureUpdateType::Rebuild,
entity: id,
});
}
state_change = PopupStateChange::Close;
}
Extension::Grid => {
let handle = asset_server.load::<OctTreeAsset>(path_pre.clone());
@ -334,15 +362,16 @@ pub fn show_popup(
if !loaded_already {
state.grids.push(data);
}
state_change = PopupStateChange::Close;
}
}
}
ui.label("");
} else {
ui.label("");
ui.label("X");
}
if ui.button("close").clicked() {
state_change = PopupStateChange::Cancel;
state_change = PopupStateChange::Close;
}
ui.separator();
for each in files {
@ -358,33 +387,115 @@ pub fn show_popup(
// selector for type of asset
// name (selector ensures its unique before allowing creation)
// upon adding, in V state_change, submit to the selective visibility tech the entities spawned
let mut can_commit = false;
let mut valid_identifier = false;
let ui =
egui::Window::new("new asset".to_owned()).id(state.egui.popup_identifier.unwrap());
ui.show(contexts.ctx_mut(), |ui| {
ui.vertical(|ui| {
ui.text_edit_singleline(current_name);
// ENSURING UNIQUENESS: Must not already exist in assets folder or loaded assets.
fn as_final_path(input: &String, is_structure_or_grid: &bool) -> String {
let extension = if *is_structure_or_grid {
".vvs"
} else {
".vvg"
};
"assets/".to_string() + input.as_str() + extension
}
if is_valid(current_name.clone()) {
let as_asset_path = as_final_path(&current_name, is_structure_or_grid);
valid_identifier = !Path::new(&as_asset_path).exists();
}
// MUST BE A VALID IDENTIFIER
ui.label(
"identifiers cannot contain the pipe character \"|\", \
whitespace (spaces, newlines, tabs), or the comma character \",\". \
slashes \"/\" will create folders automatically if needed.",
use of slashes \"/\" will create folders automatically if needed.",
);
ui.horizontal(|ui| {
ui.radio_value(is_structure_or_grid, true, "Structure");
ui.radio_value(is_structure_or_grid, false, "Grid");
});
ui.horizontal(|ui| {
if can_commit {
if valid_identifier {
ui.label("");
} else {
ui.label("");
ui.label("X");
}
if ui.button("Cancel").clicked() {
state_change = PopupStateChange::Cancel;
state_change = PopupStateChange::Close;
}
if ui.add_enabled(can_commit, Button::new("create")).clicked() {
if ui
.add_enabled(valid_identifier, Button::new("create"))
.clicked()
{
//commit changes
//first check if we need to make the directory
// TODO: move to when you click Save All Changes so directory doesnt exist if they scrap the idea/close the app immediately after creating
let mut final_path = as_final_path(&current_name, is_structure_or_grid);
let full_path = PathBuf::from(final_path.clone());
let dir_path = full_path.parent();
if let Some(dir_path) = dir_path {
if !dir_path.is_dir() {
let result = fs::create_dir_all(dir_path);
if result.is_err() {
println!("ah shit");
} else {
println!("success!");
}
}
}
final_path = final_path.replace("assets/", "");
if *is_structure_or_grid {
// add structure
let handle = asset_server.add::<StructureAsset>(Default::default());
let handleclone = handle.clone();
let data = StructureEditData {
path: final_path,
id: handle,
has_changed_since_last_save: false,
edit_entity: Entity::PLACEHOLDER, //BAD BAD BAD
};
state.structures.push(data);
state_change = PopupStateChange::Close;
let id = commands
.spawn((
SpatialBundle {
visibility: Visibility::Visible,
..Default::default()
},
StructureComponent {
asset: handleclone,
nodes: Default::default(),
},
))
.id();
commands.entity(state.display_root).add_child(id);
event_writer.send(StructureUpdateMessage {
update_type: StructureUpdateType::Rebuild,
entity: id,
});
} else {
// add grid
let handle = asset_server.add::<OctTreeAsset>(OctTreeAsset {
model: RwLock::new(OctTree::<Color>::new(
Vec3::ZERO,
Color::RED,
)),
handle: None,
task: None,
});
let data = GridEditData {
path: final_path,
id: handle,
has_changed_since_last_save: true,
};
state.grids.push(data);
state_change = PopupStateChange::Close;
// SPAWN ENTITY?
}
}
});
});
@ -423,7 +534,7 @@ pub fn show_popup(
state.popup = PopupWindowMode::None;
}
}
PopupStateChange::Cancel => {
PopupStateChange::Close => {
state.popup = PopupWindowMode::None;
}
PopupStateChange::RenameComplete => {

View file

@ -4,5 +4,6 @@ no meshes loaded
load a structure: display structure is updated. load all meshes in the structure.
load a mesh: add a mesh node in the structure at root with name of mesh
~~BONUS: want a discovery-list-display of all known assets - scan assets folder~~
~~BONUS: Keep track of if structure or meshes have changed, when they changed offer to save if loading a new structure or closing program (meshes will stay loaded unchanged until close, loading a new structure erases current structure (temp?))~~
DONE:
want a discovery-list-display of all known assets - scan assets folder
Keep track of if structure or meshes have changed, when they changed offer to save if loading a new structure or closing program (meshes will stay loaded unchanged until close, loading a new structure erases current structure (temp?))

View file

@ -25,7 +25,7 @@ use thiserror::Error;
use super::s_oct_asset::{MeshingOctTreePairs, OctAssetMarker, OctTreeAsset};
#[derive(Asset, TypePath, Debug)]
#[derive(Asset, TypePath, Debug, Default)]
pub struct StructureAsset {
pub layout: StringTree,
pub default_pose_positions: HashMap<String, Transform>,
@ -675,26 +675,16 @@ pub mod serialization {
// v STRING TREE (tree that defines shape/structure of it)
{
//let mut is_first = true;
data += NEWLINE;
let mut to_process = Vec::<String>::new();
for each in &asset.layout.root {
to_process.push(each.name_of().unwrap().clone());
/*if let Some(name) = each.name_of() {
//
if !is_first {
data += "|";
} else {
is_first = false;
}
data += name.clone().as_str();
} else {
return None;
}*/
}
// v HELPER FUNCTION
fn save_child(element: &String, tree: &StringTree, data: &mut String) {
if let Some(children) = tree.children_of(element) {
if children.is_empty() {
*data += NEWLINE;
*data += element.as_str();
return;
}
*data += NEWLINE;