testing
This commit is contained in:
parent
7e91f93fe0
commit
2f8afb8403
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -8,6 +8,7 @@
|
||||||
"./Cargo.toml",
|
"./Cargo.toml",
|
||||||
"./Cargo.toml",
|
"./Cargo.toml",
|
||||||
"./Cargo.toml",
|
"./Cargo.toml",
|
||||||
|
"./Cargo.toml",
|
||||||
"./Cargo.toml"
|
"./Cargo.toml"
|
||||||
],
|
],
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ mod s_orbit_camera;
|
||||||
pub mod s_string_tree;
|
pub mod s_string_tree;
|
||||||
pub mod s_ui_details;
|
pub mod s_ui_details;
|
||||||
|
|
||||||
|
|
||||||
pub fn setup(app: &mut App) -> &mut App {
|
pub fn setup(app: &mut App) -> &mut App {
|
||||||
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||||
primary_window: Some(Window {
|
primary_window: Some(Window {
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Default for EditWindowUIState {
|
||||||
pub enum PopupWindowMode {
|
pub enum PopupWindowMode {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
StructureElement(String),
|
EditStructureElement(String, String), //rename from and to, otherwise second string is unused
|
||||||
}
|
}
|
||||||
impl PopupWindowMode {
|
impl PopupWindowMode {
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
|
@ -394,7 +394,7 @@ pub fn edit_window_ui(
|
||||||
for window_entity in &windows {
|
for window_entity in &windows {
|
||||||
let ctx = contexts.ctx_for_window_mut(window_entity);
|
let ctx = contexts.ctx_for_window_mut(window_entity);
|
||||||
let pos = ctx.memory(|memory| {
|
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())
|
memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -46,6 +46,33 @@ impl StringTree {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
StringTree { root: Vec::new() }
|
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 {
|
pub fn add_root_level(&mut self, element: &String) -> bool {
|
||||||
for each in &self.root {
|
for each in &self.root {
|
||||||
if Self::check_present(each, element) {
|
if Self::check_present(each, element) {
|
||||||
|
|
|
@ -8,6 +8,8 @@ use bevy_egui::{
|
||||||
EguiContexts,
|
EguiContexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::vvlib::s_identifier_validation;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
s_editor_ui::{EditWindowUIState, PopupWindowMode},
|
s_editor_ui::{EditWindowUIState, PopupWindowMode},
|
||||||
s_string_tree::StringTreeElement,
|
s_string_tree::StringTreeElement,
|
||||||
|
@ -60,9 +62,10 @@ pub fn round_trip_color() {
|
||||||
pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
|
pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
|
||||||
let mut change_state = None;
|
let mut change_state = None;
|
||||||
let mut reparent = None;
|
let mut reparent = None;
|
||||||
match &state.popup {
|
let mut rename_complete = false;
|
||||||
|
match &mut state.popup {
|
||||||
PopupWindowMode::None => return,
|
PopupWindowMode::None => return,
|
||||||
PopupWindowMode::StructureElement(name) => {
|
PopupWindowMode::EditStructureElement(name, rename) => {
|
||||||
//formatting comment
|
//formatting comment
|
||||||
let response = egui::Window::new("edit structure element ".to_owned() + &name.clone())
|
let response = egui::Window::new("edit structure element ".to_owned() + &name.clone())
|
||||||
.id(state.egui.popup_identifier.unwrap());
|
.id(state.egui.popup_identifier.unwrap());
|
||||||
|
@ -70,6 +73,19 @@ pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
|
||||||
//formatting comment
|
//formatting comment
|
||||||
let cur = name.clone();
|
let cur = name.clone();
|
||||||
ui.label("what do you want to do with ".to_owned() + &name + "?");
|
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 {
|
enum Tasks {
|
||||||
MoveElement,
|
MoveElement,
|
||||||
RemoveElement,
|
RemoveElement,
|
||||||
|
@ -113,6 +129,16 @@ pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
|
||||||
} else {
|
} else {
|
||||||
state.structure.deparent(&cur);
|
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();
|
let mut string_selected = state.selected_structure_element.clone();
|
||||||
ui.collapsing("Model Structure", |ui| {
|
ui.collapsing("Model Structure", |ui| {
|
||||||
ui.vertical(|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 {
|
for each in &state.structure.root {
|
||||||
match each {
|
match each {
|
||||||
super::s_string_tree::StringTreeElement::None => {}
|
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() {
|
if ui.add_enabled(true, but).clicked() {
|
||||||
let mut should_close = false;
|
let mut should_close = false;
|
||||||
if let PopupWindowMode::StructureElement(val) = &state.popup {
|
if let PopupWindowMode::EditStructureElement(val, _) = &state.popup
|
||||||
|
{
|
||||||
if val == name {
|
if val == name {
|
||||||
should_close = true;
|
should_close = true;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +174,10 @@ pub fn show_editable_stringtree(ui: &mut egui::Ui, state: &mut EditWindowUIState
|
||||||
if should_close {
|
if should_close {
|
||||||
state.popup = PopupWindowMode::None;
|
state.popup = PopupWindowMode::None;
|
||||||
} else {
|
} 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());
|
ui.radio_value(selection, name.clone(), name.clone());
|
||||||
if ui.button("...").clicked() {
|
if ui.button("...").clicked() {
|
||||||
let mut should_close = false;
|
let mut should_close = false;
|
||||||
if let PopupWindowMode::StructureElement(val) = state {
|
if let PopupWindowMode::EditStructureElement(val, _) = state {
|
||||||
if val == name {
|
if val == name {
|
||||||
should_close = true;
|
should_close = true;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +224,7 @@ pub fn show_child(
|
||||||
if should_close {
|
if should_close {
|
||||||
*state = PopupWindowMode::None;
|
*state = PopupWindowMode::None;
|
||||||
} else {
|
} else {
|
||||||
*state = PopupWindowMode::StructureElement(name.clone())
|
*state = PopupWindowMode::EditStructureElement(name.clone(), name.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub mod s_oct_asset;
|
||||||
pub mod s_octtree;
|
pub mod s_octtree;
|
||||||
pub mod s_structure_asset;
|
pub mod s_structure_asset;
|
||||||
pub mod s_true_generic_octtree;
|
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 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
|
pub const INTERVAL: f32 = 0.3; // how often to add ^ that many and remove ^ that many random locations
|
||||||
|
|
|
@ -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 {
|
pub struct StructureAsset {
|
||||||
shape: StringTree,
|
layout: StringTree,
|
||||||
base_pose: Pose,
|
positions: HashMap<String, Transform>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pose {
|
#[derive(Default)]
|
||||||
elements: HashMap<String, ChildElPose>,
|
pub struct StructureLoader {
|
||||||
|
//can anything even be put in here?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[non_exhaustive]
|
||||||
fn test_quaternion_euler_convs() {
|
#[derive(Debug, Error)]
|
||||||
let start = Vec3::new(0., f32::to_radians(90.), f32::to_radians(45.));
|
pub enum StructureLoadError {
|
||||||
let quat = dbg!(Quat::from_euler(
|
#[error("Invalid File Data: {0}")]
|
||||||
bevy::math::EulerRot::XYZ,
|
FileDataInvalid(String),
|
||||||
start.x,
|
#[error("FileNotFound: {0}")]
|
||||||
start.y,
|
FileNotFound(String),
|
||||||
start.z
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
));
|
));
|
||||||
let int = quat.normalize().to_euler(bevy::math::EulerRot::XYZ);
|
}
|
||||||
let out = [int.0.to_degrees(), int.1.to_degrees(), int.2.to_degrees()];
|
return serialization::meshes::load_detect_version(bytes);
|
||||||
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)
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue