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:
parent
20f554b8d5
commit
41b673753e
|
@ -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
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(¤t_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(¤t_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 => {
|
||||
|
|
|
@ -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?))
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue