-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTerminalDisplay.cs
More file actions
173 lines (139 loc) · 5.27 KB
/
TerminalDisplay.cs
File metadata and controls
173 lines (139 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using System.Diagnostics;
using System.Drawing;
using Pastel;
namespace TerminalRenderer;
public class TerminalDisplay
{
private Dictionary<Point, TerminalPixel> _pixelDrawList = new();
public Point CameraPosition = DefaultCameraPosition;
public int Width = DefaultWidth;
public int Height = DefaultHeight;
public static int DefaultWidth = Console.WindowWidth / 2 - 1;
public static int DefaultHeight = Console.WindowHeight - 1;
public static Point DefaultCameraPosition = new(-(DefaultWidth / 2), -(DefaultHeight / 2));
private int _writeRowIndex = 0;
private int _writeColumnIndex = 0;
private TerminalPixel[][] _previousFrame;
private bool _firstFrameRendered = false;
private Rectangle _renderRegion => new (CameraPosition.X, CameraPosition.Y, Width, Height);
public TerminalDisplay()
{
_previousFrame = new TerminalPixel[Height][];
for (int y = 0; y < _previousFrame.Length; y++)
{
_previousFrame[y] = new TerminalPixel[Width];
}
}
public T Draw<T>(T terminalRenderable) where T : ITerminalRenderable
{
foreach (TerminalPixel pixel in terminalRenderable.Render())
{
if (_renderRegion.Contains(pixel.Position))
_pixelDrawList[pixel.Position] = pixel;
// else
// {
// Console.Clear();
// Console.WriteLine($"CULLED PIXEL: {pixel.Position} {pixel.BackgroundColor}");
// Console.ReadLine();
// }
}
return terminalRenderable;
}
/// <summary>
/// Draws over the terminal and renders the draw list
/// </summary>
public void Render()
{
Console.SetCursorPosition(0, 0);
if (!_firstFrameRendered)
{
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
// gets the current point with the camera offset
var currentPoint = FramePositionToWorldPosition(new Point(x, y));
// checks if any point draws on the current pixel and uses it
// if none are found, uses default
if (_pixelDrawList.TryGetValue(currentPoint, out var pixel)) ;
else pixel = new TerminalPixel(currentPoint);
Write(pixel, _writeColumnIndex++, _writeRowIndex);
}
DescendRow();
}
}
else
{
IEnumerable<TerminalPixel> pointDifference = Diff(_previousFrame, _pixelDrawList);
foreach (var pixel in pointDifference)
{
Point pos = pixel.GetFramePosition(this);
Write(pixel, pos.X, pos.Y, true);
}
}
EndRender();
}
private static IEnumerable<TerminalPixel> Diff(TerminalPixel[][] previous, Dictionary<Point, TerminalPixel> latest)
{
for (int y = 0; y < previous.Length; y++)
{
TerminalPixel[] row = previous[y];
for (int x = 0; x < row.Length; x++)
{
TerminalPixel prevPixel = row[x];
TerminalPixel? newPixel = null;
if (latest.TryGetValue(prevPixel.Position, out TerminalPixel latestPixel))
newPixel = latestPixel;
// __ => EXPLICIT EMPTY
// .. => NULL / DOESNT EXIST
// diff logic:
// - | P N D R
// 1 | __ + .. = .. > __
// 2 | XX + .. = __ > __
// 3 | XX + YY = YY > YY
// 4 | XX + XX = .. > XX
if (newPixel is null) // 1 or 2
{
if (!prevPixel.EquivalentTo(TerminalPixel.Default)) // 2
yield return TerminalPixel.Default with { Position = prevPixel.Position };
continue; // 1
}
else if (!prevPixel.EquivalentTo(newPixel.Value)) // 3
yield return newPixel.Value;
continue; // 4
}
}
}
private void Write(TerminalPixel pixel, int x, int y, bool modifyPos = false)
{
if (modifyPos)
Console.SetCursorPosition(x * TerminalPixel.PixelContentLength, y);
string colorizedContent = pixel.PixelContent
.PastelBg(pixel.BackgroundColor)
.Pastel(pixel.ForegroundColor);
Console.Write(colorizedContent);
_previousFrame[y][x] = pixel;
}
private void DescendRow()
{
Console.WriteLine();
_writeRowIndex++;
_writeColumnIndex = 0;
}
private void EndRender()
{
Console.ResetColor();
Console.SetCursorPosition(0, Height);
_writeRowIndex = 0;
_writeColumnIndex = 0;
_pixelDrawList.Clear();
_firstFrameRendered = true;
}
public void MoveCamera(Point offset)
{
CameraPosition.X += offset.X;
CameraPosition.Y += offset.Y;
}
public Point FramePositionToWorldPosition(Point pos) => new(pos.X + CameraPosition.X, pos.Y + CameraPosition.Y);
public void MoveCamera(int xOffset, int yOffset) => MoveCamera(new Point(xOffset, yOffset));
}