This commit is contained in:
Lillian Vixe 2024-05-17 02:55:31 -07:00
parent 7e91f93fe0
commit 2f8afb8403
7 changed files with 211 additions and 91 deletions

View file

@ -8,6 +8,7 @@
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml"
],
}

View file

@ -10,6 +10,7 @@ mod s_orbit_camera;
pub mod s_string_tree;
pub mod s_ui_details;
pub fn setup(app: &mut App) -> &mut App {
app.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {

View file

@ -69,7 +69,7 @@ impl Default for EditWindowUIState {
pub enum PopupWindowMode {
#[default]
None,
StructureElement(String),
EditStructureElement(String, String), //rename from and to, otherwise second string is unused
}
impl PopupWindowMode {
pub fn is_none(&self) -> bool {
@ -394,7 +394,7 @@ pub fn edit_window_ui(
for window_entity in &windows {
let ctx = contexts.ctx_for_window_mut(window_entity);
let pos = ctx.memory(|memory| {
if let PopupWindowMode::StructureElement(_) = shared_ui_state.popup {
if let PopupWindowMode::EditStructureElement(_, _) = shared_ui_state.popup {
memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap())
} else {
None

View file

@ -46,6 +46,33 @@ impl StringTree {
pub fn new() -> Self {
StringTree { root: Vec::new() }
}
pub fn rename(&mut self, subject: &String, new_name: &String) -> bool {
for each in &mut self.root {
if Self::recursive_search_rename(each, subject, new_name) {
return true;
}
}
false
}
fn recursive_search_rename(
element: &mut StringTreeElement,
subject: &String,
new_name: &String,
) -> bool {
if let StringTreeElement::Element(title, children) = element {
if title == subject {
*title = new_name.clone();
return true;
} else {
for each in children.as_mut() {
if Self::recursive_search_rename(each, subject, new_name) {
return true;
}
}
}
}
false
}
pub fn add_root_level(&mut self, element: &String) -> bool {
for each in &self.root {
if Self::check_present(each, element) {

View file

@ -8,6 +8,8 @@ use bevy_egui::{
EguiContexts,
};
use crate::vvlib::s_identifier_validation;
use super::{
s_editor_ui::{EditWindowUIState, PopupWindowMode},
s_string_tree::StringTreeElement,
@ -60,9 +62,10 @@ pub fn round_trip_color() {
pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
let mut change_state = None;
let mut reparent = None;
match &state.popup {
let mut rename_complete = false;
match &mut state.popup {
PopupWindowMode::None => return,
PopupWindowMode::StructureElement(name) => {
PopupWindowMode::EditStructureElement(name, rename) => {
//formatting comment
let response = egui::Window::new("edit structure element ".to_owned() + &name.clone())
.id(state.egui.popup_identifier.unwrap());
@ -70,6 +73,19 @@ pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
//formatting comment
let cur = name.clone();
ui.label("what do you want to do with ".to_owned() + &name + "?");
ui.horizontal(|ui| {
//.
ui.label("rename element: ");
let mut rename_string = rename.clone();
ui.text_edit_singleline(&mut rename_string);
if s_identifier_validation::is_valid(rename_string.clone()) {
*rename = rename_string;
}
if ui.button("Confirm and change name").clicked() {
//.
rename_complete = true;
}
});
enum Tasks {
MoveElement,
RemoveElement,
@ -113,6 +129,16 @@ pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
} else {
state.structure.deparent(&cur);
}
return;
}
if rename_complete {
if let PopupWindowMode::EditStructureElement(old, new) = &state.popup {
state.structure.rename(old, new);
if &state.selected_structure_element == old {
state.selected_structure_element = new.clone();
}
}
state.popup = PopupWindowMode::None;
}
}
@ -120,6 +146,13 @@ pub fn show_editable_stringtree(ui: &mut egui::Ui, state: &mut EditWindowUIState
let mut string_selected = state.selected_structure_element.clone();
ui.collapsing("Model Structure", |ui| {
ui.vertical(|ui| {
if state.selected_structure_element != "" {
ui.label("Tree Element Selection: ".to_owned() + &state.selected_structure_element);
if ui.button("deselect").clicked() {
state.selected_structure_element = "".into();
}
ui.separator();
}
for each in &state.structure.root {
match each {
super::s_string_tree::StringTreeElement::None => {}
@ -132,7 +165,8 @@ pub fn show_editable_stringtree(ui: &mut egui::Ui, state: &mut EditWindowUIState
if ui.add_enabled(true, but).clicked() {
let mut should_close = false;
if let PopupWindowMode::StructureElement(val) = &state.popup {
if let PopupWindowMode::EditStructureElement(val, _) = &state.popup
{
if val == name {
should_close = true;
}
@ -140,7 +174,10 @@ pub fn show_editable_stringtree(ui: &mut egui::Ui, state: &mut EditWindowUIState
if should_close {
state.popup = PopupWindowMode::None;
} else {
state.popup = PopupWindowMode::StructureElement(name.clone())
state.popup = PopupWindowMode::EditStructureElement(
name.clone(),
name.clone(),
)
}
}
});
@ -179,7 +216,7 @@ pub fn show_child(
ui.radio_value(selection, name.clone(), name.clone());
if ui.button("...").clicked() {
let mut should_close = false;
if let PopupWindowMode::StructureElement(val) = state {
if let PopupWindowMode::EditStructureElement(val, _) = state {
if val == name {
should_close = true;
}
@ -187,7 +224,7 @@ pub fn show_child(
if should_close {
*state = PopupWindowMode::None;
} else {
*state = PopupWindowMode::StructureElement(name.clone())
*state = PopupWindowMode::EditStructureElement(name.clone(), name.clone())
}
}
});

View file

@ -8,6 +8,7 @@ pub mod s_oct_asset;
pub mod s_octtree;
pub mod s_structure_asset;
pub mod s_true_generic_octtree;
pub mod s_identifier_validation;
pub const RANDOM_SPACE: f32 = 5.; // size of the random possibility space.
pub const INTERVAL: f32 = 0.3; // how often to add ^ that many and remove ^ that many random locations

View file

@ -1,92 +1,145 @@
use bevy::{
math::{Quat, Vec3},
transform::components::Transform,
utils::hashbrown::HashMap,
};
use crate::vvedit::s_string_tree::StringTree;
use s_string_tree::StringTree;
use bevy::{asset::{Asset, AssetLoader, AsyncReadExt}, reflect::TypePath, transform::components::Transform, utils::{hashbrown::HashMap, thiserror}};
pub struct ChildElPose {
euler: Vec3,
translation: Vec3,
scale: Vec3,
}
pub enum StructureOptions {
None,
}
impl ChildElPose {
fn quat_from(&self) -> Quat {
Quat::from_rotation_x(self.euler.x)
+ Quat::from_rotation_y(self.euler.y)
+ Quat::from_rotation_z(self.euler.z)
}
pub fn into_transform(&self) -> Transform {
Transform::from_rotation(self.quat_from())
* Transform::from_scale(self.scale)
* Transform::from_translation(self.translation)
}
pub fn interpolate_toward(&self, other: &ChildElPose, t: f32) -> ChildElPose {
let t = t.clamp(0., 1.);
let rot = self.quat_from().slerp(other.quat_from(), t);
let translation = self.translation.lerp(other.translation, t);
let scale = self.scale.lerp(other.scale, t);
Self::new_quat(rot, translation, scale)
}
pub fn interpolate(lhs: &ChildElPose, rhs: &ChildElPose, t: f32) -> ChildElPose {
lhs.interpolate_toward(rhs, t)
}
pub fn combine_with(&self, other: &ChildElPose) -> ChildElPose {
let rot = self.quat_from() + other.quat_from();
let translation = self.translation + other.translation;
let scale = self.scale * other.scale;
Self::new_quat(rot, translation, scale)
}
pub fn combine(lhs: &ChildElPose, rhs: &ChildElPose) -> ChildElPose {
lhs.combine_with(rhs)
}
pub fn new_euler(euler: Vec3, translation: Vec3, scale: Vec3) -> ChildElPose {
ChildElPose {
euler,
translation,
scale,
}
}
pub fn new_quat(rot: Quat, translation: Vec3, scale: Vec3) -> ChildElPose {
let int = rot.to_euler(bevy::math::EulerRot::XYZ);
ChildElPose {
euler: Vec3::new(int.0.to_degrees(), int.1.to_degrees(), int.2.to_degrees()),
translation,
scale,
}
}
}
use thiserror::Error;
use crate::vvedit::s_string_tree;
#[derive(Asset, TypePath)]
pub struct StructureAsset {
shape: StringTree,
base_pose: Pose,
layout: StringTree,
positions: HashMap<String, Transform>,
}
pub struct Pose {
elements: HashMap<String, ChildElPose>,
#[derive(Default)]
pub struct StructureLoader {
//can anything even be put in here?
}
#[test]
fn test_quaternion_euler_convs() {
let start = Vec3::new(0., f32::to_radians(90.), f32::to_radians(45.));
let quat = dbg!(Quat::from_euler(
bevy::math::EulerRot::XYZ,
start.x,
start.y,
start.z
));
let int = quat.normalize().to_euler(bevy::math::EulerRot::XYZ);
let out = [int.0.to_degrees(), int.1.to_degrees(), int.2.to_degrees()];
dbg!(&out);
let quat2 = Quat::from_euler(
bevy::math::EulerRot::XYZ,
out[0].to_radians(),
out[1].to_radians(),
out[2].to_radians(),
);
assert!(quat2.normalize() == quat)
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum StructureLoadError {
#[error("Invalid File Data: {0}")]
FileDataInvalid(String),
#[error("FileNotFound: {0}")]
FileNotFound(String),
}
pub mod serialization {
pub mod meshes {
use std::path::Path;
use bevy::{
asset::io::{AssetSource, AssetWriter},
tasks::block_on,
};
use super::super::{StructureLoadError, StructureAsset};
pub fn load_detect_version(bytes: Vec<u8>) -> Result<StructureAsset, StructureLoadError> {
return Err(StructureLoadError::FileDataInvalid("".to_string()));
}
pub fn write_latest_version(path: &String, asset: &StructureAsset) -> bool {
write_any_version(path, asset, Default::default())
}
pub fn write_any_version(
path: &String,
asset: &StructureAsset,
version: StructureVersions,
) -> bool {
if let Some(writer) = get_writer() {
let mut bytes: Vec<u8> = Vec::new();
if let Some(mut header) = version_header(version) {
bytes.append(&mut header);
} else {
return false;
}
match version {
StructureVersions::Error => return false,
StructureVersions::Version1 => {
if let Some(mut contents) = versions::version_1::save(&asset) {
bytes.append(&mut contents);
} else {
return false;
}
}
}
let res =
block_on(async { writer.write_bytes(Path::new(path), bytes.as_slice()).await });
return res.is_ok();
}
false
}
pub fn get_writer() -> Option<Box<dyn AssetWriter>> {
AssetSource::get_default_writer("assets".into())(true)
}
#[derive(Copy, Clone, Default)]
pub enum StructureVersions {
#[default]
Version1,
Error,
}
mod versions {
pub mod version_1 {
use super::super::super::super::{StructureLoadError, StructureAsset};
pub fn load(data: std::str::Lines<'_>) -> Result<StructureAsset, StructureLoadError> {
Err(StructureLoadError::FileDataInvalid("".to_string()))
}
pub fn save(asset: &StructureAsset) -> Option<Vec<u8>> {
None
}
}
}
const VERSION1: &str = "version 1";
pub fn determine_version(line: Option<&str>) -> StructureVersions {
if line.is_some() {
let line: String = line.unwrap().into();
if line.to_lowercase() == String::from(VERSION1) {
return StructureVersions::Version1;
}
}
StructureVersions::Error
}
pub fn version_header(version: StructureVersions) -> Option<Vec<u8>> {
match version {
StructureVersions::Error => None,
StructureVersions::Version1 => Some((VERSION1.to_string()).as_bytes().to_vec()),
}
}
}
}
impl AssetLoader for StructureLoader {
type Asset = StructureAsset;
type Settings = ();
type Error = StructureLoadError;
fn load<'a>(
&'a self,
reader: &'a mut bevy::asset::io::Reader,
_settings: &'a Self::Settings,
_load_context: &'a mut bevy::asset::LoadContext,
) -> bevy::utils::BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
Box::pin(async move {
let mut bytes: Vec<u8> = Vec::<u8>::new();
let result = reader.read_to_end(&mut bytes).await;
if result.is_err() {
return Err(StructureLoadError::FileNotFound(
"could not read_to_end the bytes".to_string(),
));
}
return serialization::meshes::load_detect_version(bytes);
})
}
}