summaryrefslogtreecommitdiff
path: root/keyframes.cpp
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-07-22 20:45:08 -0400
committerFox Caminiti <fox@foxcam.net>2022-07-22 20:45:08 -0400
commitfc8040d695644aaca4596adebeca4ea1369ef630 (patch)
treeaea6979da97c43df8f03f3a2d7b421ee71bef370 /keyframes.cpp
first
Diffstat (limited to 'keyframes.cpp')
-rw-r--r--keyframes.cpp383
1 files changed, 383 insertions, 0 deletions
diff --git a/keyframes.cpp b/keyframes.cpp
new file mode 100644
index 0000000..a7ff37a
--- /dev/null
+++ b/keyframes.cpp
@@ -0,0 +1,383 @@
+internal keyframe*
+KeyframeLookupMemory(property_channel *Property, int16 i) {
+ int16 b = i / MAX_KEYFRAMES_PER_BLOCK;
+ int16 k = i - b*MAX_KEYFRAMES_PER_BLOCK;
+ return &Property->KeyframeBlock[b]->Keyframe[k];
+}
+
+internal keyframe*
+KeyframeLookupIndex(property_channel *Property, int16 a) {
+ int16 i = Property->SortedIndex[a];
+ int16 b = i / MAX_KEYFRAMES_PER_BLOCK;
+ int16 k = i - b*MAX_KEYFRAMES_PER_BLOCK;
+ return &Property->KeyframeBlock[b]->Keyframe[k];
+}
+
+internal keyframe*
+PushKeyframe(property_channel *Property) {
+ int16 i = Property->NumberOfTotalKeyframes;
+ int16 b = i / MAX_KEYFRAMES_PER_BLOCK;
+ int16 k = i - b*MAX_KEYFRAMES_PER_BLOCK;
+ return &Property->KeyframeBlock[b]->Keyframe[k];
+}
+
+// (extremely bad)
+internal temp_keyframe_list
+GetSelectedKeyframes(project_data *File)
+{
+ temp_keyframe_list KeyframeList;
+ int z = 0;
+ for (int i = 0; i < File->NumberOfLayers; i++) {
+ for (int a = 0; a < AmountOf(File->Layer[i]->Property); a++) {
+ for (int l = 0; l < File->Layer[i]->Property[a].NumberOfTotalKeyframes; l++) {
+ keyframe *Keyframe = KeyframeLookupMemory(&File->Layer[i]->Property[a], l);
+ if (Keyframe->IsSelected) {
+ KeyframeList.SelectedKeyframe[z] = Keyframe;
+ z++;
+ }
+ }
+ }
+ }
+ KeyframeList.Amount = z;
+ return KeyframeList;
+}
+
+internal int32
+KeyframeMemoryToIndex(property_channel *Property, int32 a)
+{
+ int32 Result = -1;
+ for (int l = 0; l < Property->NumberOfTotalKeyframes; l++) {
+ if (Property->SortedIndex[l] == a) {
+ Result = l;
+ break;
+ }
+ }
+ Assert(Result > -1);
+ return Result;
+}
+
+internal void
+SelectKeyframe(project_data *File, project_layer *Layer, property_channel *Property, keyframe *Keyframe)
+{
+ Layer->IsSelected = true;
+ File->NumberOfSelectedLayers++;
+ Property->NumberOfSelectedKeyframes++;
+ Keyframe->IsSelected = true;
+}
+
+internal void
+DeselectKeyframe(project_data *File, project_layer *Layer, property_channel *Property, keyframe *Keyframe)
+{
+ Layer->IsSelected = true;
+ File->NumberOfSelectedLayers++;
+ Property->NumberOfSelectedKeyframes++;
+ Keyframe->IsSelected = true;
+}
+
+internal void
+CheckKeyframeSort(property_channel *Property, int32 Increment, int32 b)
+{
+ int32 i = KeyframeMemoryToIndex(Property, b);
+ if (Increment > 0) {
+ if (i+1 != Property->NumberOfTotalKeyframes) {
+ keyframe *CurrentKeyframe = KeyframeLookupIndex(Property, i);
+ keyframe *NextKeyframe = KeyframeLookupIndex(Property, i + 1);
+ if (NextKeyframe->FrameNumber < CurrentKeyframe->FrameNumber) {
+ uint16 Temp = Property->SortedIndex[i];
+ Property->SortedIndex[i] = Property->SortedIndex[i + 1];
+ Property->SortedIndex[i + 1] = Temp;
+ }
+ }
+ } else {
+ if (i != 0) {
+ keyframe *CurrentKeyframe = KeyframeLookupIndex(Property, i);
+ keyframe *LastKeyframe = KeyframeLookupIndex(Property, i - 1);
+ if (CurrentKeyframe->FrameNumber < LastKeyframe->FrameNumber) {
+ uint16 Temp = Property->SortedIndex[i];
+ Property->SortedIndex[i] = Property->SortedIndex[i - 1];
+ Property->SortedIndex[i - 1] = Temp;
+ }
+ }
+ }
+}
+
+internal void
+ShiftKeyframeIndex(property_channel *Property, int16 Increment, int16 StopAt) {
+ if (Increment > 0) {
+ int16 i = Property->NumberOfTotalKeyframes - 1;
+ while (i > StopAt) {
+ Property->SortedIndex[i + Increment] = Property->SortedIndex[i];
+ i--;
+ }
+ } else {
+ int16 i = StopAt;
+ while (i < Property->NumberOfTotalKeyframes - 1) {
+ Property->SortedIndex[i] = Property->SortedIndex[i + Increment];
+ i++;
+ }
+ }
+}
+
+internal void
+DeleteKeyframeFromMemory(property_channel *Property, int16 Increment, int16 StopAt) {
+ if (Increment > 0) {
+ int16 i = Property->NumberOfTotalKeyframes - 1;
+ while (i > StopAt) {
+ keyframe *CurrentKeyframe = KeyframeLookupMemory(Property, i);
+ keyframe *NextKeyframe = KeyframeLookupMemory(Property, i + Increment);
+ *NextKeyframe = *CurrentKeyframe;
+ i--;
+ }
+ Property->NumberOfTotalKeyframes += Increment;
+ } else {
+ int16 i = StopAt;
+ while (i < Property->NumberOfTotalKeyframes - 1) {
+ keyframe *CurrentKeyframe = KeyframeLookupMemory(Property, i);
+ keyframe *NextKeyframe = KeyframeLookupMemory(Property, i - Increment);
+ *CurrentKeyframe = *NextKeyframe;
+ i++;
+ }
+ Property->NumberOfTotalKeyframes += Increment;
+ }
+}
+
+internal void
+ResortPropertyChannel(property_channel *Property) {
+ for (int16 i = 0; i < Property->NumberOfTotalKeyframes; i++)
+ {
+ Property->SortedIndex[i] = i;
+ }
+ for (;;) {
+ int16 Swaps = 0;
+ for (int16 i = 0; i < Property->NumberOfTotalKeyframes - 1; i++)
+ {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, i);
+ keyframe *NextKeyframe = KeyframeLookupIndex(Property, i + 1);
+ if (Keyframe->FrameNumber > NextKeyframe->FrameNumber) {
+ uint16 Temp = Property->SortedIndex[i];
+ Property->SortedIndex[i] = Property->SortedIndex[i + 1];
+ Property->SortedIndex[i + 1] = Temp;
+ Swaps++;
+ }
+ }
+ if (Swaps == 0)
+ break;
+ }
+}
+
+internal void
+DeleteSelectedKeyframes(project_data *File, memory *Memory)
+{
+ for (int i = 0; i < File->NumberOfLayers; i++) {
+ for (int a = 0; a < AmountOf(File->Layer[i]->Property); a++) {
+ property_channel *Property = &File->Layer[i]->Property[a];
+ for (int l = 0; l < Property->NumberOfTotalKeyframes; l++) {
+ keyframe *Keyframe = KeyframeLookupMemory(Property, l);
+ if (Keyframe->IsSelected) {
+ int16 ToShift = 1;
+ bool32 Until = true;
+ while (Until) {
+ keyframe *KeyframeN = KeyframeLookupMemory(Property, l + ToShift);
+ if (KeyframeN->IsSelected) {
+ ToShift += 1;
+ } else {
+ Until = false;
+ }
+ }
+ DeleteKeyframeFromMemory(Property, -ToShift, l);
+ }
+ }
+ ResortPropertyChannel(Property);
+ }
+ }
+}
+
+internal void
+CalculatePropertyMinMax(property_channel *Property) {
+ Property->LocalMaxVal = Property->MinVal;
+ Property->LocalMinVal = Property->MaxVal;
+ for (int16 i = 0; i < Property->NumberOfTotalKeyframes; i++) {
+ keyframe *Keyframe = KeyframeLookupMemory(Property, i);
+ Property->LocalMinVal.f = Ceil(Property->LocalMinVal.f, Keyframe->Value.f);
+ Property->LocalMaxVal.f = Floor(Property->LocalMaxVal.f, Keyframe->Value.f);
+ }
+ if (Property->LocalMinVal.f == Property->LocalMaxVal.f)
+ {
+ Property->LocalMaxVal.f += 1;
+ }
+}
+
+
+internal void
+IncrementKeyframes(property_channel *Property, int16 Increment)
+{
+ for (int i = 0; i < Property->NumberOfTotalKeyframes; i++) {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, i);
+ Keyframe->FrameNumber += Increment;
+ }
+}
+
+internal void
+IncrementKeyframesInLayer(project_layer *Layer, int16 Increment)
+{
+ for (int a = 0; a < AmountOf(Layer->Property); a++)
+ IncrementKeyframes(&Layer->Property[a], Increment);
+ for (int e = 0; e < Layer->NumberOfEffects; e++)
+ for (int a = 0; a < Layer->Effect[e]->NumberOfProperties; a++)
+ IncrementKeyframes(&Layer->Effect[e]->Property[a], Increment);
+}
+
+internal void
+CreateKeyframeBlock(property_channel *, memory *);
+
+// dir 0 left, 1 right
+internal void
+ClampKeyframeHandles(property_channel *Property, int16 b, int16 dir) {
+ if (dir == 0) {
+ if (b > 0) {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, b - 1);
+ keyframe *NextKeyframe = KeyframeLookupIndex(Property, b);
+ real32 XSpan = NextKeyframe->FrameNumber - Keyframe->FrameNumber;
+ if (abs(NextKeyframe->TangentLeft.x) > XSpan)
+ NextKeyframe->TangentLeft.x = -XSpan;
+ if (NextKeyframe->TangentLeft.x > 0)
+ NextKeyframe->TangentLeft.x = 0;
+ }
+ }
+ if (dir == 1) {
+ if (b < Property->NumberOfTotalKeyframes - 1) {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, b);
+ keyframe *NextKeyframe = KeyframeLookupIndex(Property, b + 1);
+ real32 XSpan = NextKeyframe->FrameNumber - Keyframe->FrameNumber;
+ if (Keyframe->TangentRight.x > XSpan)
+ Keyframe->TangentRight.x = XSpan;
+ if (Keyframe->TangentRight.x < 0)
+ Keyframe->TangentRight.x = 0;
+ }
+ }
+}
+
+internal void
+ClampSurroundingKeyframeHandles(property_channel *Property, int16 b) {
+ ClampKeyframeHandles(Property, b, 0);
+ ClampKeyframeHandles(Property, b, 1);
+ if (b > 0) {
+ ClampKeyframeHandles(Property, b-1, 0);
+ ClampKeyframeHandles(Property, b-1, 1);
+ }
+ if (b < Property->NumberOfTotalKeyframes - 1) {
+ ClampKeyframeHandles(Property, b+1, 0);
+ ClampKeyframeHandles(Property, b+1, 1);
+ }
+}
+
+
+
+internal void
+ManualKeyframeInsertF(property_channel *Property, memory *Memory, int32 CurrentFrame, real32 Val)
+{
+ if (!(Property->NumberOfTotalKeyframes % MAX_KEYFRAMES_PER_BLOCK)) {
+ CreateKeyframeBlock(Property, Memory);
+ }
+ keyframe *Keyframe = NULL;
+ if (Property->NumberOfTotalKeyframes == 0) {
+ Keyframe = &Property->KeyframeBlock[0]->Keyframe[0];
+ Property->NumberOfTotalKeyframes++;
+ } else if (Property->NumberOfTotalKeyframes == 1) {
+ Keyframe = &Property->KeyframeBlock[0]->Keyframe[0];
+ if (CurrentFrame != Keyframe->FrameNumber) {
+ if (CurrentFrame > Keyframe->FrameNumber) {
+ Property->SortedIndex[1] = 1;
+ } else {
+ Property->SortedIndex[0] = 1;
+ }
+ Property->NumberOfTotalKeyframes++;
+ }
+ Keyframe = &Property->KeyframeBlock[0]->Keyframe[1];
+ } else {
+ keyframe *LastKeyframe = KeyframeLookupIndex(Property, Property->NumberOfTotalKeyframes-1);
+ if (LastKeyframe->FrameNumber < CurrentFrame) {
+ Property->SortedIndex[Property->NumberOfTotalKeyframes] = Property->NumberOfTotalKeyframes;
+ } else {
+ for (int16 i = 0; i < Property->NumberOfTotalKeyframes; i++) {
+ keyframe *CurrentKeyframe = KeyframeLookupIndex(Property, i);
+ if (CurrentKeyframe->FrameNumber > CurrentFrame) {
+ ShiftKeyframeIndex(Property, 1, i - 1);
+ Property->SortedIndex[i] = Property->NumberOfTotalKeyframes;
+ break;
+ }
+ }
+ }
+ Keyframe = PushKeyframe(Property);
+ Property->NumberOfTotalKeyframes++;
+ }
+ Assert(!(Keyframe == NULL))
+ Keyframe->FrameNumber = CurrentFrame;
+ Keyframe->Value.f = Val;
+ Keyframe->Type = bezier;
+ Keyframe->TangentLeft = V2(-1, 0);
+ Keyframe->TangentRight = V2(1, 0);
+ CalculatePropertyMinMax(Property);
+}
+
+
+internal void
+CalculateKeyframesLinearly(uint16 CurrentFrame, struct property_channel *Property)
+{
+
+ keyframe *FirstKeyframe = KeyframeLookupIndex(Property, 0);
+
+ keyframe *LastKeyframe = KeyframeLookupIndex(Property, Property->NumberOfTotalKeyframes - 1);
+ if (Property->NumberOfTotalKeyframes == 0) {
+ // do nothing
+ }
+ // check if current frame is before first keyframe or after last
+ else if (Property->NumberOfTotalKeyframes == 1 ||
+ CurrentFrame < FirstKeyframe->FrameNumber) {
+ Property->CurrentValue = FirstKeyframe->Value;
+ }
+ else if (CurrentFrame > LastKeyframe->FrameNumber) {
+ Property->CurrentValue = LastKeyframe->Value;
+ }
+ else if (Property->NumberOfTotalKeyframes > 1) {
+ for (int i = 0; i < (Property->NumberOfTotalKeyframes - 1); i++) {
+ keyframe *Keyframe = KeyframeLookupIndex(Property, i);
+ keyframe *NextKeyframe = KeyframeLookupIndex(Property, i+1);
+ if (CurrentFrame >= Keyframe->FrameNumber &&
+ CurrentFrame <= NextKeyframe->FrameNumber)
+ {
+ real32 FakeVelocity = ((CurrentFrame - Keyframe->FrameNumber) /
+ (NextKeyframe->FrameNumber -
+ (real32)Keyframe->FrameNumber));
+ real32 t = FakeVelocity;
+ // real32 u = 1.0f - t;
+ // real32 w1 = u * u * u;
+ // real32 w2 = 3 * u * u * t;
+ // real32 w3 = 3 * u * t * t;
+ // real32 w4 = t * t * t;
+ real32 t2 = t * t;
+ real32 t3 = t2 * t;
+ real32 mt = 1-t;
+ real32 mt2 = mt * mt;
+ real32 mt3 = mt2 * mt;
+ if (Property->VarType == type_real ) {
+ real32 OldValue = Property->CurrentValue.f;
+ real32 CurrentVal = Keyframe->Value.f;
+ real32 CurrentTan = CurrentVal + Keyframe->TangentRight.y;
+ real32 NextVal = NextKeyframe->Value.f;
+ real32 NextTan = NextVal + NextKeyframe->TangentLeft.y;
+ // Property->CurrentValue.f = w1 * CurrentVal + w2 * CurrentTan + w3 * NextTan + w4 * NextVal;
+ Property->CurrentValue.f = CurrentVal*mt3 + 3*CurrentTan*mt2*t + 3*NextTan*mt*t2 + NextVal*t3;
+ //Property->CurrentValue.f = CurrentVal + ((NextVal - CurrentVal) * FakeVelocity);
+ }
+ else if (Property->VarType == type_color) {
+ v4 OldValue = Property->CurrentValue.col;
+ v4 CurrentVal = Keyframe->Value.col;
+ v4 NextVal = NextKeyframe->Value.col;
+ Property->CurrentValue.col = CurrentVal + ((NextVal - CurrentVal) * FakeVelocity);
+ }
+ break;
+ }
+ }
+ }
+}