Skip to content

Commit 687c8b4

Browse files
feat: timeline loop
1 parent 6055621 commit 687c8b4

1 file changed

Lines changed: 170 additions & 76 deletions

File tree

FreeFrame/Window.cs

Lines changed: 170 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ enum CreateMode
4040
int _ioHeight;
4141
System.Numerics.Vector4 _ioColor;
4242
int _ioTimeline;
43+
bool _ioIsLoop;
44+
bool _ioIsReverse;
4345
bool _dialogFilePicker = false;
4446
bool _dialogCompatibility = false;
4547

@@ -83,6 +85,11 @@ protected override void OnLoad()
8385
_timeline = new SortedDictionary<int, List<Shape>>();
8486

8587
_ImGuiController = new ImGuiController(ClientSize.X, ClientSize.Y);
88+
89+
_ioIsLoop = false;
90+
_ioIsReverse = false;
91+
92+
// TODO: default values for io
8693
}
8794
protected override void OnResize(ResizeEventArgs e)
8895
{
@@ -554,43 +561,36 @@ public void ShowUIDebug()
554561
}
555562
ImGui.End();
556563
}
557-
public int Interpolate(int x, int x1, int x2, int y1, int y2)
564+
public int LinearInterpolate(int x, int x1, int x2, int y1, int y2)
558565
{
559566
float y;
560-
if (x1 < x2)
561-
{
562-
if (y1 < y2)
563-
y = y1 + (x - x1) * ((y2 - y1) / (x2 - x1));
564-
else
565-
y = y2 + (x - x1) * ((y1 - y2) / (x2 - x1));
566-
}
567-
else
568-
{
569-
if (y1 < y2)
570-
y = y1 + (x - x2) * ((y2 - y1) / (x1 - x2));
571-
else
572-
y = y2 + (x - x2) * ((y1 - y2) / (x1 - x2));
573-
}
567+
y = y1 + (x - x1) * ((y2 - y1) / ((x2 - x1) == 0 ? 1 : (x2 - x1)));
568+
//if (y1 < y2)
569+
// y = y1 + (x - x1) * ((y2 - y1) / (x2 - x1));
570+
//else
571+
// y = y2 + (x - x1) * ((y1 - y2) / (x2 - x1));
574572

575573

576-
if (y1 < y2)
574+
if (y1 <= y2)
577575
{
578-
Console.WriteLine("input({0}) min({1}) max({2}) === {3}", y, y1, y2, Math.Clamp(y, y1, y2));
576+
//Console.Write("Logicc");
577+
//Console.WriteLine("input({0}) min({1}) max({2}) === {3}", y, y1, y2, Math.Clamp(y, y1, y2));
579578
return (int)Math.Clamp(y, y1, y2);
580579

581580
}
582581
else
583582
{
584-
Console.WriteLine("input({0}) min({1}) max({2}) === {3}", y, y2, y1, Math.Clamp(y, y2, y1));
583+
//Console.Write("Not loooooooooooooooogic");
584+
//Console.WriteLine("input({0}) min({1}) max({2}) === {3}", y, y2, y1, Math.Clamp(y, y2, y1));
585585
return (int)Math.Clamp(y, y2, y1);
586586
}
587587
}
588-
public Color4 InterpolateColor(int x, int x1, int x2, Color4 y1, Color4 y2)
588+
public Color4 LinearInterpolate(int x, int x1, int x2, Color4 y1, Color4 y2)
589589
{
590-
int r = Interpolate(x, x1, x2, (int)(y1.R * 255), (int)(y2.R * 255));
591-
int g = Interpolate(x, x1, x2, (int)(y1.G * 255), (int)(y2.G * 255));
592-
int b = Interpolate(x, x1, x2, (int)(y1.B * 255), (int)(y2.B * 255));
593-
int a = Interpolate(x, x1, x2, (int)(y1.A * 255), (int)(y2.A * 255));
590+
int r = LinearInterpolate(x, x1, x2, (int)(y1.R * 255), (int)(y2.R * 255));
591+
int g = LinearInterpolate(x, x1, x2, (int)(y1.G * 255), (int)(y2.G * 255));
592+
int b = LinearInterpolate(x, x1, x2, (int)(y1.B * 255), (int)(y2.B * 255));
593+
int a = LinearInterpolate(x, x1, x2, (int)(y1.A * 255), (int)(y2.A * 255));
594594
return new Color4(r / 255f, g / 255f, b / 255f, a / 255f);
595595
}
596596
public void ShowUI()
@@ -940,60 +940,133 @@ public void ShowUI()
940940
{
941941
if (_timeline.Any(i => i.Value.Any(j => j.Id == shape.Id))) // If exist somewhere else but not here
942942
{
943-
List<int> keys = _timeline.Where(pair => pair.Value.Any(x => x.Id == shape.Id)).Select(pair => pair.Key).ToList(); // Key key everywhere it exist
943+
int[] keys = _timeline.Where(pair => pair.Value.Any(x => x.Id == shape.Id)).Select(pair => pair.Key).ToArray(); // Key key everywhere it exist
944944

945945
// Find two nearest
946946
(int first, int second) nearest = (int.MaxValue, int.MaxValue);
947-
foreach (int key in keys)
947+
//(int first, int second) deltas = (int.MaxValue, int.MaxValue);
948+
nearest.first = 0;
949+
nearest.second = 0; //Math.Min(keys[keys.Length - 1], _ioTimeline);
950+
951+
int timelineIndex = _ioTimeline;
952+
953+
if (_ioIsLoop)
948954
{
949-
int delta = Math.Abs(key - _ioTimeline);
950-
if (delta < nearest.first) // First nearest
951-
nearest.first = key;
952-
else if (delta < nearest.second) // Second nearest
953-
nearest.second = key;
955+
int delta = keys[keys.Length - 1] - keys[0];
956+
timelineIndex = timelineIndex - (delta * (int)Math.Floor((double)timelineIndex / delta));
954957
}
955-
if (nearest.second != int.MaxValue && nearest.first < _ioTimeline && _ioTimeline < nearest.second) // If need to interpolate
958+
959+
if (timelineIndex >= keys[keys.Length - 1])
956960
{
957-
Shape first = _timeline[nearest.first].Find(x => x.Id == shape.Id)!; // can't be null
958-
Shape second = _timeline[nearest.second].Find(x => x.Id == shape.Id)!; // can't be null
959-
960-
Console.WriteLine("X vv");
961-
// Interpolate every properties
962-
shape.X = Interpolate(_ioTimeline, nearest.first, nearest.second, first.X, second.X);
963-
Console.WriteLine(Environment.NewLine);
964-
Console.WriteLine("Y vv");
965-
shape.Y = Interpolate(_ioTimeline, nearest.first, nearest.second, first.Y, second.Y);
966-
Console.WriteLine(Environment.NewLine);
967-
Console.WriteLine("Width vv");
968-
shape.Width = Interpolate(_ioTimeline, nearest.first, nearest.second, first.Width, second.Width);
969-
Console.WriteLine(Environment.NewLine);
970-
Console.WriteLine("Height vv");
971-
shape.Height = Interpolate(_ioTimeline, nearest.first, nearest.second, first.Height, second.Height);
972-
Console.WriteLine(Environment.NewLine);
973-
Console.WriteLine("Angle vv");
974-
shape.Angle = Interpolate(_ioTimeline, nearest.first, nearest.second, first.Angle, second.Angle);
975-
Console.WriteLine(Environment.NewLine);
976-
Console.WriteLine("CornerRadius vv");
977-
shape.CornerRadius = Interpolate(_ioTimeline, nearest.first, nearest.second, first.CornerRadius, second.CornerRadius);
978-
Console.WriteLine(Environment.NewLine);
979-
Console.WriteLine("Color vv");
980-
shape.Color = InterpolateColor(_ioTimeline, nearest.first, nearest.second, first.Color, second.Color);
981-
982-
shape.ImplementObject();
961+
nearest.first = keys[keys.Length - 1];
962+
nearest.second = keys[keys.Length - 1];
963+
//if (_ioIsLoop)
964+
// nearest.first = keys[0];
965+
}
966+
else if (timelineIndex <= keys[0])
967+
{
968+
nearest.first = keys[0];
969+
nearest.second = keys[0];
970+
//if (_ioIsLoop)
971+
// nearest.second = keys[keys.Length - 1];
972+
}
973+
else
974+
{
975+
for (int i = 0; i < keys.Length; i++)
976+
{
977+
Console.WriteLine("key[{0}] = {1}", i, keys[i]);
978+
if (keys[i] >= timelineIndex)
979+
{
980+
nearest.second = keys[i];
981+
if (i - 1 >= 0) // If second possible
982+
nearest.first = keys[i - 1];
983+
break;
984+
}
985+
}
983986
}
984-
else // Just draw the first nearest
987+
988+
989+
990+
Console.WriteLine("HHHHHHHHHHHHHHHHHHHHHHHHHHHHH first: {0} second: {1}", nearest.first, nearest.second);
991+
//foreach (int key in keys)
992+
//{
993+
// int delta = Math.Abs(key - _ioTimeline);
994+
// if (delta < deltas.first) // First nearest
995+
// {
996+
// nearest.second = nearest.first;
997+
// deltas.second = deltas.first;
998+
// deltas.first = delta;
999+
// nearest.first = key;
1000+
// }
1001+
// else if (delta < deltas.second) // Second nearest
1002+
// {
1003+
// deltas.second = delta;
1004+
// nearest.second = key;
1005+
// }
1006+
//}
1007+
//if (nearest.second != int.MaxValue && ((nearest.second <= _ioTimeline && _ioTimeline <= nearest.first) || (nearest.first <= _ioTimeline && _ioTimeline <= nearest.second))) // If need to interpolate
1008+
// if (nearest.first != nearest.second)
9851009
{
9861010
Shape first = _timeline[nearest.first].Find(x => x.Id == shape.Id)!; // can't be null
1011+
Shape second = _timeline[nearest.second].Find(x => x.Id == shape.Id)!; // can't be null;
1012+
// If reverse and loop invert the two shape every odd
1013+
if (_ioIsLoop && _ioIsReverse)
1014+
{
1015+
if (keys.Length > 1)
1016+
{
1017+
int delta = keys[keys.Length - 1] - keys[0];
1018+
Console.WriteLine("(timelineIndex:{0} / delta:{1}) {2} % 2 == 1 =>>>> {3}", _ioTimeline, delta, _ioTimeline / delta, (int)Math.Floor((double)_ioTimeline / delta) % 2 == 1);
1019+
if ((int)Math.Floor((double)_ioTimeline / delta) % 2 == 1) // if odd
1020+
{
1021+
Console.WriteLine("Invertttttttttttttt");
1022+
second = _timeline[nearest.first].Find(x => x.Id == shape.Id)!; // can't be null
1023+
first = _timeline[nearest.second].Find(x => x.Id == shape.Id)!; // can't be null
1024+
}
1025+
}
1026+
}
1027+
1028+
//if (first != null && second != null)
1029+
{
1030+
//Console.WriteLine("X vv");
1031+
// Interpolate every properties
1032+
shape.X = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.X, second.X);
1033+
//Console.WriteLine(Environment.NewLine);
1034+
//Console.WriteLine("Y vv");
1035+
shape.Y = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.Y, second.Y);
1036+
//Console.WriteLine(Environment.NewLine);
1037+
//Console.WriteLine("Width vv");
1038+
shape.Width = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.Width, second.Width);
1039+
//Console.WriteLine(Environment.NewLine);
1040+
//Console.WriteLine("Height vv");
1041+
shape.Height = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.Height, second.Height);
1042+
//Console.WriteLine(Environment.NewLine);
1043+
//Console.WriteLine("Angle vv");
1044+
shape.Angle = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.Angle, second.Angle);
1045+
//Console.WriteLine(Environment.NewLine);
1046+
//Console.WriteLine("CornerRadius vv");
1047+
shape.CornerRadius = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.CornerRadius, second.CornerRadius);
1048+
//Console.WriteLine(Environment.NewLine);
1049+
//Console.WriteLine("Color vv");
1050+
shape.Color = LinearInterpolate(timelineIndex, nearest.first, nearest.second, first.Color, second.Color);
1051+
1052+
shape.ImplementObject();
1053+
1054+
}
9871055

988-
shape.X = first.X;
989-
shape.Y = first.Y;
990-
shape.Width = first.Width;
991-
shape.Height = first.Height;
992-
shape.Angle = first.Angle;
993-
shape.CornerRadius = first.CornerRadius;
994-
shape.Color = first.Color;
995-
shape.ImplementObject();
9961056
}
1057+
//else // Just draw the first nearest
1058+
//{
1059+
// Shape first = _timeline[nearest.first].Find(x => x.Id == shape.Id)!; // can't be null
1060+
1061+
// shape.X = first.X;
1062+
// shape.Y = first.Y;
1063+
// shape.Width = first.Width;
1064+
// shape.Height = first.Height;
1065+
// shape.Angle = first.Angle;
1066+
// shape.CornerRadius = first.CornerRadius;
1067+
// shape.Color = first.Color;
1068+
// shape.ImplementObject();
1069+
//}
9971070
}
9981071
else
9991072
{
@@ -1004,23 +1077,44 @@ public void ShowUI()
10041077
}
10051078
ResetSelection();
10061079
}
1080+
if (ImGui.Checkbox("Loop", ref _ioIsLoop))
1081+
_ioIsReverse = _ioIsLoop;
1082+
ImGui.Indent();
1083+
if (ImGui.Checkbox("Reverse", ref _ioIsReverse))
1084+
if (_ioIsLoop == false)
1085+
_ioIsLoop = _ioIsReverse;
1086+
ImGui.Unindent();
1087+
10071088
if (_selectedShape != null)
10081089
{
1009-
if (ImGui.Button(String.Format("Create keyframe for {0}", _selectedShape.GetType().Name)))
1090+
if (_timeline.ContainsKey(_ioTimeline) && _timeline[_ioTimeline] != null && _timeline[_ioTimeline].Any(x => x.Id == _selectedShape.Id))
10101091
{
1011-
if (_timeline.ContainsKey(_ioTimeline) == false || _timeline[_ioTimeline] == null)
1012-
_timeline[_ioTimeline] = new List<Shape>();
1013-
1014-
foreach (Shape shape in _timeline[_ioTimeline])
1092+
if (ImGui.Button(String.Format("Remove keyframe {0} for {1}", _ioTimeline, _selectedShape.GetType().Name)))
10151093
{
1016-
if (shape.Id == _selectedShape.Id)
1094+
_timeline[_ioTimeline].Remove(_timeline[_ioTimeline].Find(x => x.Id == _selectedShape.Id)!); // Can't be null
1095+
if (_timeline[_ioTimeline].Count == 0)
1096+
_timeline.Remove(_ioTimeline);
1097+
// If list _timeline[_ioTimeline] empty then null it
1098+
}
1099+
}
1100+
else
1101+
{
1102+
if (ImGui.Button(String.Format("Create keyframe for {0}", _selectedShape.GetType().Name)))
1103+
{
1104+
if (_timeline.ContainsKey(_ioTimeline) == false || _timeline[_ioTimeline] == null)
1105+
_timeline[_ioTimeline] = new List<Shape>();
1106+
1107+
foreach (Shape shape in _timeline[_ioTimeline])
10171108
{
1018-
Console.WriteLine("Already exist");
1019-
_timeline[_ioTimeline].Remove(shape);
1020-
break;
1109+
if (shape.Id == _selectedShape.Id)
1110+
{
1111+
Console.WriteLine("Already exist");
1112+
_timeline[_ioTimeline].Remove(shape);
1113+
break;
1114+
}
10211115
}
1116+
_timeline[_ioTimeline].Add(_selectedShape.Clone());
10221117
}
1023-
_timeline[_ioTimeline].Add(_selectedShape.Clone());
10241118
}
10251119
}
10261120
ImGui.End();

0 commit comments

Comments
 (0)