Skip to content

Instantly share code, notes, and snippets.

@smoogipoo
Created April 14, 2023 11:07
Show Gist options
  • Save smoogipoo/1dc881ed4deca7c6cee9d39c8dd806d1 to your computer and use it in GitHub Desktop.
Save smoogipoo/1dc881ed4deca7c6cee9d39c8dd806d1 to your computer and use it in GitHub Desktop.
Topological DrawNode Test
DrawFrame();
void DrawFrame()
{
DrawNode root = new CompositeDrawNode(0)
{
Children =
{
new DrawNode(1),
new BufferedDrawNode(2, new CompositeDrawNode(3)
{
Children =
{
new DrawNode(4),
new DrawNode(5),
new CompositeDrawNode(6)
{
Children =
{
new BufferedDrawNode(7, new DrawNode(8))
}
}
}
}),
new DrawNode(9)
}
};
// Gather events from all DrawNodes. This is a topologically sorted list.
List<IDrawNodeEvent> events = new List<IDrawNodeEvent>();
root.CreateVisitor().Visit(root, events);
// And then... draw!
// -- First the framebuffers.
Console.WriteLine("-- FrameBuffer pass");
foreach (var e in events.OfType<FrameBufferDrawEvent>().Reverse())
{
Console.WriteLine($"FrameBuffer({e.DrawNode.Index})");
e.Action(e.DrawNode);
}
// -- Then the render passes.
// We only need the first DrawNode in this case, because we're still using the tree traversal.
DrawEvent? firstEvent = events.OfType<DrawEvent>().FirstOrDefault();
if (firstEvent is DrawEvent first)
{
Console.WriteLine("-- FtB pass");
first.FrontToBackAction.Invoke(first.DrawNode);
Console.WriteLine("-- BtF pass");
first.BackToFrontAction.Invoke(first.DrawNode);
}
}
public interface IDrawNodeEvent
{
public DrawNode DrawNode { get; }
}
public record struct FrameBufferDrawEvent(DrawNode DrawNode, Action<DrawNode> Action) : IDrawNodeEvent;
public record struct DrawEvent(DrawNode DrawNode, Action<DrawNode> BackToFrontAction, Action<DrawNode> FrontToBackAction) : IDrawNodeEvent;
public class DrawNode
{
public readonly int Index; // DEBUG ONLY.
public DrawNode(int index)
{
Index = index;
}
public virtual DrawNodeVisitor CreateVisitor() => new DrawNodeVisitor();
public virtual void Draw()
{
Console.WriteLine($"Draw({Index})");
}
public virtual void DrawOpaqueInterior()
{
Console.WriteLine($"Draw({Index})");
}
}
public class DrawNodeVisitor
{
public void Visit(DrawNode drawNode, List<IDrawNodeEvent> events)
{
VisitDrawNode(drawNode, events);
}
protected virtual void VisitDrawNode(DrawNode drawNode, List<IDrawNodeEvent> events)
{
events.Add(new DrawEvent(drawNode, d => d.Draw(), d => d.DrawOpaqueInterior()));
}
}
public class CompositeDrawNode : DrawNode
{
public readonly List<DrawNode> Children = new List<DrawNode>();
public CompositeDrawNode(int index)
: base(index)
{
}
public override void Draw()
{
base.Draw();
for (int i = 0; i < Children.Count; i++)
Children[i].Draw();
}
public override void DrawOpaqueInterior()
{
for (int i = Children.Count - 1; i >= 0; i--)
Children[i].DrawOpaqueInterior();
base.DrawOpaqueInterior();
}
public override DrawNodeVisitor CreateVisitor() => new CompositeDrawNodeVisitor();
}
public class CompositeDrawNodeVisitor : DrawNodeVisitor
{
protected override void VisitDrawNode(DrawNode drawNode, List<IDrawNodeEvent> events)
{
base.VisitDrawNode(drawNode, events);
CompositeDrawNode composite = (CompositeDrawNode)drawNode;
foreach (var child in composite.Children)
child.CreateVisitor().Visit(child, events);
}
}
public class BufferedDrawNode : DrawNode
{
public readonly DrawNode Child;
public BufferedDrawNode(int index, DrawNode child)
: base(index)
{
Child = child;
}
public void PopulateContents()
{
Child.Draw();
}
public override DrawNodeVisitor CreateVisitor() => new BufferedDrawNodeVisitor();
}
public class BufferedDrawNodeVisitor : DrawNodeVisitor
{
protected override void VisitDrawNode(DrawNode drawNode, List<IDrawNodeEvent> events)
{
BufferedDrawNode buffered = (BufferedDrawNode)drawNode;
events.Add(new FrameBufferDrawEvent(buffered, n => ((BufferedDrawNode)n).PopulateContents()));
buffered.Child.CreateVisitor().Visit(buffered.Child, events);
base.VisitDrawNode(drawNode, events);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment