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