diff --git a/GLTFViewer/.idea/.idea.GLTFViewer/.idea/vcs.xml b/GLTFViewer/.idea/.idea.GLTFViewer/.idea/vcs.xml index d843f34..6c0b863 100644 --- a/GLTFViewer/.idea/.idea.GLTFViewer/.idea/vcs.xml +++ b/GLTFViewer/.idea/.idea.GLTFViewer/.idea/vcs.xml @@ -1,4 +1,6 @@ - + + + \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer.sln.DotSettings.user b/GLTFViewer/GLTFViewer.sln.DotSettings.user index 3b1f3d9..48d22c8 100644 --- a/GLTFViewer/GLTFViewer.sln.DotSettings.user +++ b/GLTFViewer/GLTFViewer.sln.DotSettings.user @@ -1,2 +1,3 @@  - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer/App.axaml.cs b/GLTFViewer/GLTFViewer/App.axaml.cs index 128b7a0..e62a891 100644 --- a/GLTFViewer/GLTFViewer/App.axaml.cs +++ b/GLTFViewer/GLTFViewer/App.axaml.cs @@ -9,8 +9,6 @@ public partial class App : Application public override void Initialize() { AvaloniaXamlLoader.Load(this); - - } public override void OnFrameworkInitializationCompleted() diff --git a/GLTFViewer/GLTFViewer/Engine.cs b/GLTFViewer/GLTFViewer/Engine.cs deleted file mode 100644 index 82be0b7..0000000 --- a/GLTFViewer/GLTFViewer/Engine.cs +++ /dev/null @@ -1,8 +0,0 @@ -using GLTFViewer.Rendering; - -namespace GLTFViewer; - -public static class Engine -{ - -} \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer/Engine/Node.cs b/GLTFViewer/GLTFViewer/Engine/Node.cs new file mode 100644 index 0000000..a186ca8 --- /dev/null +++ b/GLTFViewer/GLTFViewer/Engine/Node.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; + +namespace GLTFViewer.Engine; + +public class Node +{ + public string Name { get; } + public ObservableCollection Children { get; } + public ObservableCollection Properties { get; } + + public Node(string name) + { + Name = name; + Children = new ObservableCollection(); + Properties = new ObservableCollection(); + } + + public Node(string name, ObservableCollection children) + { + Name = name; + Children = children; + Properties = new ObservableCollection(); + } + + public void AddChild(Node child) + { + Children.Add(child); + } + + public void RemoveChild(Node child) + { + Children.Remove(child); + } + + public void AddProperty(NodeProperty property) + { + if (Properties.Any(p => p.Name == property.Name)) + { + throw new InvalidOperationException($"A property with the name {property.Name} already exists in node {Name}."); + } + + Properties.Add(property); + } + + public void RemoveProperty(NodeProperty property) + { + if (!Properties.Remove(property)) + { + Console.WriteLine($"Could not remove property {property.Name} from node {Name}: Property not found."); + } + } + + public void SetProperty(string name, T value) + { + var property = Properties.OfType>().FirstOrDefault(p => p.Name == name); + if (property == null) + { + property = new NodeProperty(name, value); + Properties.Add(property); + } + else + { + property.Value = value; + } + } +} \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer/Engine/NodeProperty.cs b/GLTFViewer/GLTFViewer/Engine/NodeProperty.cs new file mode 100644 index 0000000..a6ad824 --- /dev/null +++ b/GLTFViewer/GLTFViewer/Engine/NodeProperty.cs @@ -0,0 +1,21 @@ +namespace GLTFViewer.Engine; + +public abstract class NodeProperty +{ + public string Name { get; } + + protected NodeProperty(string name) + { + Name = name; + } +} + +public class NodeProperty : NodeProperty +{ + public T Value { get; set; } + + public NodeProperty(string name, T value) : base(name) + { + Value = value; + } +} \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer/Rendering/Renderer.cs b/GLTFViewer/GLTFViewer/Engine/Rendering/Renderer.cs similarity index 96% rename from GLTFViewer/GLTFViewer/Rendering/Renderer.cs rename to GLTFViewer/GLTFViewer/Engine/Rendering/Renderer.cs index d8d422e..c0b1aff 100644 --- a/GLTFViewer/GLTFViewer/Rendering/Renderer.cs +++ b/GLTFViewer/GLTFViewer/Engine/Rendering/Renderer.cs @@ -11,7 +11,7 @@ public class Renderer public void Initialize(GlInterface gl) { GLLoader.LoadBindings(new AvaloniaBindingsContext(gl)); - GL.ClearColor(0,0,1,1); + GL.ClearColor(1,1,1,1); } public void Render(GlInterface gl, int width, int height, int fbo) diff --git a/GLTFViewer/GLTFViewer/Engine/Ui/SceneTree.cs b/GLTFViewer/GLTFViewer/Engine/Ui/SceneTree.cs new file mode 100644 index 0000000..ef4587f --- /dev/null +++ b/GLTFViewer/GLTFViewer/Engine/Ui/SceneTree.cs @@ -0,0 +1,42 @@ +using System.Collections.ObjectModel; +using Avalonia.Controls; +using Avalonia.Controls.Templates; + +namespace GLTFViewer.Engine.Ui; + +public class SceneTree +{ + public Node Root { get; } = new Node("root"); + + private TreeView _sceneTreeView; + private ObservableCollection _nodes; + + public SceneTree(TreeView sceneTreeView) + { + _sceneTreeView = sceneTreeView; + + Initialize(); + } + + public void Initialize() + { + Root.AddProperty(new NodeProperty("TestPropertyString", "TestValue")); + Root.AddProperty(new NodeProperty("TestPropertyInt", 42)); + + + _nodes = new ObservableCollection() + { + Root + }; + + _sceneTreeView.ItemsSource = _nodes; + _sceneTreeView.ItemTemplate = new FuncTreeDataTemplate( + (node, _) => + { + var textBlock = new TextBlock { Text = node.Name }; + return textBlock; + }, + node => node.Children + ); + } +} \ No newline at end of file diff --git a/GLTFViewer/GLTFViewer/MainUI.axaml b/GLTFViewer/GLTFViewer/MainUI.axaml index b375fd1..4b72bb4 100644 --- a/GLTFViewer/GLTFViewer/MainUI.axaml +++ b/GLTFViewer/GLTFViewer/MainUI.axaml @@ -5,17 +5,51 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="GLTFViewer.MainUI"> - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + diff --git a/GLTFViewer/GLTFViewer/MainUI.axaml.cs b/GLTFViewer/GLTFViewer/MainUI.axaml.cs index d6a5af1..ecfb30d 100644 --- a/GLTFViewer/GLTFViewer/MainUI.axaml.cs +++ b/GLTFViewer/GLTFViewer/MainUI.axaml.cs @@ -1,13 +1,65 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Markup.Xaml; +using GLTFViewer.Engine; +using GLTFViewer.Engine.Ui; namespace GLTFViewer; public partial class MainUI : UserControl { + + private SceneTree _sceneTree; + + private TreeView _sceneTreeView; + private TreeView _propertyTreeView; + + + + public MainUI() { InitializeComponent(); + + _sceneTreeView = SceneTreeView; + _propertyTreeView = PropertyTreeView; + _sceneTree = new SceneTree(_sceneTreeView); + + _sceneTreeView.SelectionChanged += PropertyTreeViewOnSelectionChanged; + + var random = new Random(); + Node previousNode = _sceneTree.Root; + + for (int i = 0; i < 20; i++) + { + var newNode = new Node($"child{i}"); + if (random.Next(2) == 0) + { + previousNode.AddChild(newNode); + } + else + { + _sceneTree.Root.AddChild(newNode); + } + previousNode = newNode; + } + } + + private void PropertyTreeViewOnSelectionChanged(object? sender, SelectionChangedEventArgs e) + { + _propertyTreeView.ItemsSource = _sceneTreeView.SelectedItem is Node node ? node.Properties : null; + _propertyTreeView.ItemTemplate = new FuncTreeDataTemplate( + (property, _) => + { + var textBlock = new TextBlock { Text = property.Name }; + return textBlock; + }, + property => null + ); } } \ No newline at end of file