summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-08-16 15:06:45 -0400
committerFox Caminiti <fox@foxcam.net>2022-08-16 15:06:45 -0400
commite89dc91182a94e48ca9220a2fe075db680ddff04 (patch)
treea277c1e38293f92e635c981ad2f6b0d84d103e09
parent04b7ccfd87d802e6b9a22b86c8d098979164b8ba (diff)
undo functional
-rw-r--r--createcalls.cpp130
-rw-r--r--ffmpeg_backend.cpp16
-rw-r--r--functions.h5
-rw-r--r--layer.cpp26
-rw-r--r--main.cpp5
-rw-r--r--main.h22
-rw-r--r--my_imgui_widgets.cpp62
-rw-r--r--undo.cpp159
8 files changed, 341 insertions, 84 deletions
diff --git a/createcalls.cpp b/createcalls.cpp
index 4564d59..f2a173f 100644
--- a/createcalls.cpp
+++ b/createcalls.cpp
@@ -31,9 +31,11 @@ Source_Generate(project_data *File, memory *Memory, void *Path)
}
if (Found) {
- Action_Change_Commit(Memory, &Source->Path, &Path, action_change_ptr);
+ Action_Entry_Begin(Memory, action_entry_default, "Add source");
+ Action_Change_Commit(Memory, &Source->Path, &Source->Path, &Path, action_change_ptr);
uint32 i = File->NumberOfSources + 1;
- Action_Change_Commit(Memory, &File->NumberOfSources, &i, action_change_u16);
+ Action_Change_Commit(Memory, &File->NumberOfSources, &File->NumberOfSources, &i, action_change_u16);
+ Action_Entry_End(Memory);
return 1;
} else {
// PostMsg(State, "File open fail...");
@@ -132,29 +134,44 @@ void * Layer_AllocateBitmap(memory *Memory, uint16 Width, uint16 Height, uint16
project_layer * Layer_Init(project_data *File, memory *Memory)
{
- int16 a = File->NumberOfLayers++;
- Assert(a < MAX_LAYERS);
-
- File->Layer[a] = (project_layer *)AllocateMemory(Memory, sizeof(project_layer), F_Layers);
-
- File->Layer[a]->Name = (char *)AllocateMemory(Memory, STRING_SIZE, F_Strings);
- sprintf(File->Layer[a]->Name, "Layer %i", a);
- File->Layer[a]->x = InitFloatProperty("X Position", 0.0f, 1.0f);
- File->Layer[a]->y = InitFloatProperty("Y Position", 0.0f, 1.0f);
- File->Layer[a]->ax = InitFloatProperty("Anchor X", 0.5f, 0.005f);
- File->Layer[a]->ay = InitFloatProperty("Anchor Y", 0.5f, 0.005f);
- File->Layer[a]->scale = InitFloatProperty("Scale", 1.0f, 0.005f);
- File->Layer[a]->rotation = InitFloatProperty("Rotation", 0.0f, 1.0f);
- File->Layer[a]->opacity = InitFloatProperty("Opacity", 1.0f, 0.005f, 0.0f, 1.0f);
- File->Layer[a]->time = InitFloatProperty("Frame Number", 0.0f, 1.0f, 0, 100000);
- File->Layer[a]->EndFrame = File->NumberOfFrames;
-
- return File->Layer[a];
+ int16 Index = File->NumberOfLayers;
+ int16 NextIndex = File->NumberOfLayers + 1;
+
+ // NOTE(fox): We don't have to record any values that get set here aside
+ // from this index in the Action tree since all we need to do to "delete"
+ // the layer is to unset this. The layer that gets made here is always at
+ // the top of the index.
+ Action_Entry_Begin(Memory, action_entry_layerinit, "Create layer");
+ Action_Change_Commit(Memory, &File->NumberOfLayers, &Index, &NextIndex, action_change_u16);
+
+ File->Layer[Index] = (project_layer *)AllocateMemory(Memory, sizeof(project_layer), F_Layers);
+
+ project_layer *Layer = File->Layer[Index];
+
+ Action_Entry_SetPointer(Memory, &Layer->BitmapInfo.AVInfo);
+
+ Action_Entry_End(Memory);
+
+ Layer->Name = (char *)AllocateMemory(Memory, STRING_SIZE, F_Strings);
+ sprintf(Layer->Name, "Layer %i", NextIndex); // CSbros...
+ Layer->x = InitFloatProperty("X Position", 0.0f, 1.0f);
+ Layer->y = InitFloatProperty("Y Position", 0.0f, 1.0f);
+ Layer->ax = InitFloatProperty("Anchor X", 0.5f, 0.005f);
+ Layer->ay = InitFloatProperty("Anchor Y", 0.5f, 0.005f);
+ Layer->scale = InitFloatProperty("Scale", 1.0f, 0.005f);
+ Layer->rotation = InitFloatProperty("Rotation", 0.0f, 1.0f);
+ Layer->opacity = InitFloatProperty("Opacity", 1.0f, 0.005f, 0.0f, 1.0f);
+ Layer->time = InitFloatProperty("Frame Number", 0.0f, 1.0f, 0, 100000);
+ Layer->EndFrame = File->NumberOfFrames;
+
+ return Layer;
}
static cached_bitmap *
Cache_CheckBitmap(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame)
{
+ if (!Source || !BitmapInfo)
+ return 0;
memory_table *Table = &Memory->Slot[B_LoadedBitmaps];
int32 FrameToSeek = TimelineFrame - BitmapInfo->FrameOffset;
// Stills have a frame index of zero.
@@ -293,11 +310,47 @@ Mask_TriangulateAndRasterize(memory *Memory, project_layer *Layer, mask *Mask)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
+static void
+Layer_InitSource(project_layer *Layer, source *Source, memory *Memory)
+{
+ uint16 Width = Source->Info.Width;
+ uint16 Height = Source->Info.Height;
+ uint16 BytesPerPixel = Source->Info.BytesPerPixel;
+ Layer->BitmapInfo.BitmapBuffer = Layer_AllocateBitmap(Memory, Width, Height, BytesPerPixel);
+}
+
+static void
+Layer_PositionCenter(project_layer *Layer, uint16 Width, uint16 Height) {
+ Layer->x.CurrentValue.f = Width/2;
+ Layer->y.CurrentValue.f = Height/2;
+}
+
+static void
+Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, source *Source)
+{
+ if (File->NumberOfLayers + 1 > MAX_LAYERS) {
+ // TODO(fox): Output!
+ }
+ project_layer *Layer = Layer_Init(File, Memory);
+ Layer->Source = Source;
+ State->UpdateFrame = true;
+}
+
static void
-Layer_UpdateBitmap(project_layer *Layer, memory *Memory, int32 CurrentFrame) {
+Layer_UpdateBitmap(project_data *File, project_layer *Layer, memory *Memory, int32 CurrentFrame) {
source *Source = Layer->Source;
layer_bitmap_info *BitmapInfo = &Layer->BitmapInfo;
+
+ // AVInfo is created here instead of on layer creation so we can save
+ // having to keep some state in the undo/delete commands.
+ if (!BitmapInfo->AVInfo) {
+ BitmapInfo->AVInfo = AllocateMemory(Memory, sizeof(av_info), P_AVInfo);
+ AV_Init(Source, (av_info *)BitmapInfo->AVInfo, Memory);
+ Layer_InitSource(Layer, Source, Memory);
+ Layer_PositionCenter(Layer, File->Width, File->Height);
+ }
+
cached_bitmap *Bitmap = Cache_CheckBitmap(Source, BitmapInfo, Memory, CurrentFrame);
if (!Bitmap) {
if (Source->SourceType == source_type_image) {
@@ -332,32 +385,6 @@ Layer_UpdateBitmap(project_layer *Layer, memory *Memory, int32 CurrentFrame) {
Bitmap_CopyToPointer(Memory->Scratch, DestBuffer, BytesPerPixel, PackedSize);
}
-static void
-Layer_InitSource(project_layer *Layer, source *Source, memory *Memory)
-{
- Layer->Source = Source;
- uint16 Width = Source->Info.Width;
- uint16 Height = Source->Info.Height;
- uint16 BytesPerPixel = Source->Info.BytesPerPixel;
- Layer->BitmapInfo.BitmapBuffer = Layer_AllocateBitmap(Memory, Width, Height, BytesPerPixel);
-}
-
-static void
-Layer_PositionCenter(project_layer *Layer, uint16 Width, uint16 Height) {
- Layer->x.CurrentValue.f = Width/2;
- Layer->y.CurrentValue.f = Height/2;
-}
-
-static void
-Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, source *Source)
-{
- project_layer *Layer = Layer_Init(File, Memory);
- AV_Init(Source, &Layer->BitmapInfo, Memory);
- Layer_InitSource(Layer, Source, Memory);
- Layer_PositionCenter(Layer, File->Width, File->Height);
- State->UpdateFrame = true;
-}
-
static ImVec2
Layer_LocalToScreenSpace(project_layer *Layer, ui *UI, comp_buffer CompBuffer, v2 Point)
{
@@ -392,13 +419,10 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory)
{
void *SourceString = String_GenerateFromChar(Memory, "../asset/24.mp4");
Source_Generate(File, Memory, SourceString);
- Layer_CreateFromSource(File, State, Memory, Source);
- Action_Undo(Memory);
- Action_Undo(Memory);
- Action_Redo(Memory);
- Action_Redo(Memory);
- Assert(0);
source *Source = &File->Source[0];
+ Layer_CreateFromSource(File, State, Memory, Source);
+ // Action_Undo(Memory);
+ // Action_Redo(Memory);
SelectLayer(File->Layer[0], State, 0);
// AddEffect(File->Layer[0], Memory, 3);
diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp
index f437285..6f0aeb5 100644
--- a/ffmpeg_backend.cpp
+++ b/ffmpeg_backend.cpp
@@ -86,10 +86,20 @@ bool32 AV_IsFileSupported(char *filename)
return 1;
}
-void AV_Init(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory)
+// Note that we can't get away with not having to keep track of the AV pointer
+// for undos by clearing/reallocing these contexts every frame since the state
+// of the PTS value is stored inside FileFormatContext.
+void AV_Dealloc(av_info *AV)
+{
+ Assert(AV);
+ avformat_free_context(AV->FileFormatContext);
+ avcodec_free_context(&AV->VideoCodecContext);
+ av_packet_free(&AV->VideoPacket);
+ av_frame_free(&AV->VideoFrame);
+};
+
+void AV_Init(source *Source, av_info *AV, memory *Memory)
{
- BitmapInfo->AVInfo = AllocateMemory(Memory, sizeof(av_info), P_AVInfo);
- av_info *AV = (av_info *)BitmapInfo->AVInfo;
*AV = {};
int32 err = 0;
diff --git a/functions.h b/functions.h
index 7f8f5d3..6cecb76 100644
--- a/functions.h
+++ b/functions.h
@@ -32,7 +32,10 @@ static v2 ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 C
void Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 *Increment);
-static void Action_Change_Commit(memory *Memory, void *DataLocation, void *NewData, action_change_type ActionChange);
+static void Action_Change_Commit(memory *Memory, void *DataLocation, void *OriginalData, void *NewData, action_change_type ActionChange);
+static void Action_Entry_SetPointer(memory *Memory, void *Data);
+static void Action_Entry_Begin(memory *Memory, action_entry_type Type, char *Name);
+static void Action_Entry_End(memory *Memory);
static void Action_Undo(memory *Memory);
static void Action_Redo(memory *Memor);
diff --git a/layer.cpp b/layer.cpp
index 8983076..b289976 100644
--- a/layer.cpp
+++ b/layer.cpp
@@ -56,6 +56,16 @@ InteractProperty(int16 a, project_data *File, project_state *State, bool32 Ended
// Cache->InteractIndex = State->SelectedLayerIndex[0];
if (Ended)
{
+ project_layer *Layer = File->Layer[State->MostRecentlySelectedLayer];
+ // We can't end for pos/anchor point until we commit both channels. Should think of something better.
+ if ((a == 1) || (a == 3)) {
+ Action_Change_Commit(Memory, &Layer->Property[a].CurrentValue.f, &State->InteractCache[1], &Layer->Property[a].CurrentValue.f, action_change_r32);
+ } else {
+ Action_Change_Commit(Memory, &Layer->Property[a].CurrentValue.f, &State->InteractCache[0], &Layer->Property[a].CurrentValue.f, action_change_r32);
+ }
+ if (!(a == 0) && !(a == 2)) {
+ Action_Entry_End(Memory);
+ }
State->IsInteracting = false;
// Cache->Interact = Clear;
}
@@ -64,7 +74,7 @@ InteractProperty(int16 a, project_data *File, project_state *State, bool32 Ended
}
static void
-TransformsInteract(project_data *File, project_state *State, ui *UI, transforms_hotkey_interact Mode)
+TransformsInteract(project_data *File, project_state *State, memory *Memory, ui *UI, transforms_hotkey_interact Mode)
{
if (UI->FocusedWindow == focus_timeline) {
temp_layer_list List = FindSelectedLayerIndex(File, State->NumberOfSelectedLayers);
@@ -83,6 +93,20 @@ TransformsInteract(project_data *File, project_state *State, ui *UI, transforms_
}
}
} else if (UI->FocusedWindow == focus_viewport) {
+ // TODO(fox): Make multi-select possible!
+ project_layer *Layer = File->Layer[State->MostRecentlySelectedLayer];
+ Action_Entry_Begin(Memory, action_entry_default, "Tranforms interact");
+ if (Mode == sliding_position) {
+ State->InteractCache[0] = Layer->x.CurrentValue.f;
+ State->InteractCache[1] = Layer->y.CurrentValue.f;
+ } else if (Mode == sliding_anchorpoint) {
+ State->InteractCache[0] = Layer->ax.CurrentValue.f;
+ State->InteractCache[1] = Layer->ay.CurrentValue.f;
+ } else if (Mode == sliding_rotation) {
+ State->InteractCache[0] = Layer->rotation.CurrentValue.f;
+ } else if (Mode == sliding_scale) {
+ State->InteractCache[0] = Layer->scale.CurrentValue.f;
+ }
State->IsInteracting = true;
State->TransformsHotkeyInteract = Mode;
}
diff --git a/main.cpp b/main.cpp
index ac4ddd1..74aaec6 100644
--- a/main.cpp
+++ b/main.cpp
@@ -99,7 +99,7 @@ MainFunction(main_sdl *Main, memory *Memory,
CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Property[r]);
}
}
- Layer_UpdateBitmap(Layer, Memory, File->CurrentFrame);
+ Layer_UpdateBitmap(File, Layer, Memory, File->CurrentFrame);
}
}
State->UpdateKeyframes = false;
@@ -262,7 +262,6 @@ int main(int argc, char *argv[]) {
LoadTestFootage(&File, &State, &Memory);
- Assert(0);
#if DEBUG
// GDB and LLDB say this plain struct that's literally under 30 bytes is
@@ -462,7 +461,9 @@ int main(int argc, char *argv[]) {
ImGui_PropertiesPanel(&File, &State, &UI, &Memory);
ImGui_Timeline(&File, &State, &Memory, &UI, io);
+
#if DEBUG
+ ImGui_DebugUndoTree(&File, &Memory);
if (Debug.ToggleWindow) {
ImGui::ShowDemoWindow();
ImGui_DebugMemoryViewer(&File, &Memory);
diff --git a/main.h b/main.h
index 4e48fc5..a31bc64 100644
--- a/main.h
+++ b/main.h
@@ -67,10 +67,31 @@ struct cached_bitmap {
uint32 Frame; // What frame it is.
};
+// Some actions may require a higher-level function to undo to a satisfactory
+// standard, so actions are allowed to do more than just set/swap single values.
+enum action_entry_type {
+ action_entry_layerinit,
+ action_entry_default
+};
+
+struct action_entry {
+ char *Name;
+ action_entry_type Type;
+ void *ExtraPointer;
+ uint16 NumberOfActions;
+};
+
+struct action_entries {
+ action_entry Entry[1024];
+ uint16 Index;
+ uint16 NumberOfEntries;
+};
+
struct memory {
memory_table Slot[16];
cached_bitmap Bitmap[4096];
void *Scratch; // 64 MB of data
+ action_entries Action;
};
struct property_channel;
@@ -486,6 +507,7 @@ struct project_state
selection_type RecentSelectionType = selection_none;
bool32 IsInteracting;
+ real32 InteractCache[4]; // we need to store the initial position in order to record it in the undo tree
transforms_hotkey_interact TransformsHotkeyInteract;
int32 MsgTime; // currently in "frames"
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
index d1d8d83..b924d55 100644
--- a/my_imgui_widgets.cpp
+++ b/my_imgui_widgets.cpp
@@ -70,6 +70,26 @@ ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, propert
}
}
+static void
+ImGui_InteractSliderProperty(project_state *State, memory *Memory, property_channel *Property)
+{
+ ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f,
+ Property->ScrubVal.f, &Property->MinVal.f, &Property->MaxVal.f, "%f");
+ if (ImGui::IsItemActivated()) {
+ Action_Entry_Begin(Memory, action_entry_default, "Tranforms interact");
+ State->InteractCache[0] = Property->CurrentValue.f;
+ }
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsItemDeactivated()) {
+ Action_Change_Commit(Memory, &Property->CurrentValue.f, &State->InteractCache[0],
+ &Property->CurrentValue.f, action_change_r32);
+ Action_Entry_End(Memory);
+ State->UpdateFrame = true;
+ }
+}
+
// Returns a normalized UV position of the composition
static v2
ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 MousePos)
@@ -82,6 +102,19 @@ ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, I
}
static void
+ImGui_DebugUndoTree(project_data *File, memory *Memory)
+{
+ ImGui::SetNextWindowSize(ImVec2(200, 800));
+ ImGui::Begin("undotree");
+ for (int i = 0; i < Memory->Action.NumberOfEntries; i++) {
+ action_entry Entry = Memory->Action.Entry[i];
+ bool32 CurrentPos = (i < Memory->Action.Index);
+ ImGui::MenuItem(Entry.Name, NULL, CurrentPos);
+ }
+ ImGui::End();
+}
+
+static void
ImGui_DebugMemoryViewer(project_data *File, memory *Memory)
{
ImGui::SetNextWindowSize(ImVec2(800, 200));
@@ -194,11 +227,7 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
if (ImGui::Button("K"))
ManualKeyframeInsertF(Property, Memory, File->CurrentFrame, Property->CurrentValue.f);
ImGui::SameLine();
- if (ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f,
- Property->ScrubVal.f, &Property->MinVal.f, &Property->MaxVal.f, "%f"))
- {
- State->UpdateFrame = true;
- }
+ ImGui_InteractSliderProperty(State, Memory, Property);
ImGui::PopID();
}
for (int h = 0; h < Layer->NumberOfEffects; h++) {
@@ -221,9 +250,9 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
for (int i = 0; i < Effect->NumberOfProperties; i++) {
property_channel *Property = &Effect->Property[i];
ImGui::PushID(Property);
- if (Property->VarType == type_real)
- if (ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f"))
- State->UpdateFrame = true;
+ if (Property->VarType == type_real) {
+ ImGui_InteractSliderProperty(State, Memory, Property);
+ }
if (Property->VarType == type_color)
if (ImGui::ColorEdit4("color 1", &Property->CurrentValue.f, ImGuiColorEditFlags_Float))
State->UpdateFrame = true;
@@ -1493,6 +1522,15 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB
State->UpdateKeyframes = true;
}
+ if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
+ if (io.KeyCtrl && io.KeyShift) {
+ Action_Redo(Memory);
+ } else if (io.KeyCtrl) {
+ Action_Undo(Memory);
+ }
+ State->UpdateFrame = true;
+ State->UpdateKeyframes = true;
+ }
if (ImGui::IsKeyPressed(ImGuiKey_Space)) {
if (io.KeyShift) {
@@ -1510,13 +1548,13 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB
}
if (ImGui::IsKeyPressed(ImGuiKey_R) && State->NumberOfSelectedLayers)
- TransformsInteract(File, State, UI, sliding_rotation);
+ TransformsInteract(File, State, Memory, UI, sliding_rotation);
if (ImGui::IsKeyPressed(ImGuiKey_S) && State->NumberOfSelectedLayers)
- TransformsInteract(File, State, UI, sliding_scale);
+ TransformsInteract(File, State, Memory, UI, sliding_scale);
if (ImGui::IsKeyPressed(ImGuiKey_G) && State->NumberOfSelectedLayers)
- TransformsInteract(File, State, UI, sliding_position);
+ TransformsInteract(File, State, Memory, UI, sliding_position);
if (ImGui::IsKeyPressed(ImGuiKey_A) && State->NumberOfSelectedLayers)
- TransformsInteract(File, State, UI, sliding_anchorpoint);
+ TransformsInteract(File, State, Memory, UI, sliding_anchorpoint);
if (ImGui::IsKeyPressed(ImGuiKey_1))
LoadTestFootage(File, State, Memory);
diff --git a/undo.cpp b/undo.cpp
index 7858f8d..3d70d49 100644
--- a/undo.cpp
+++ b/undo.cpp
@@ -7,10 +7,11 @@
// We need to encode data that's able to go from A -> B as well as B -> A. Thus
// for the ints I encode the difference instead of just whatever the last value
// was. Strings currently just stores both.
-void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, action_change_type ActionChange)
+void Action_Change_Commit(memory *Memory, void *DataAddress, void *OriginalData, void *NewData, action_change_type ActionChange)
{
+ Memory->Action.Entry[Memory->Action.Index].NumberOfActions++;
void *UndoEntry = AllocateMemory(Memory, sizeof(void *), P_UndoBuffer);
- *(ptrsize *)UndoEntry = (ptrsize)OriginalData;
+ *(ptrsize *)UndoEntry = (ptrsize)DataAddress;
void *Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer);
*(action_change_type *)Data = ActionChange;
switch (ActionChange)
@@ -22,7 +23,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
uint16 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(uint16), P_UndoBuffer);
*(uint16 *)Data = Difference;
- *(uint16 *)OriginalData = *(uint16 *)NewData;
+ *(uint16 *)DataAddress = *(uint16 *)NewData;
} break;
case action_change_i16:
{
@@ -31,7 +32,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
int16 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(int16), P_UndoBuffer);
*(int16 *)Data = Difference;
- *(int16 *)OriginalData = *(int16 *)NewData;
+ *(int16 *)DataAddress = *(int16 *)NewData;
} break;
case action_change_u32:
{
@@ -40,7 +41,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
uint32 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(uint32), P_UndoBuffer);
*(uint32 *)Data = Difference;
- *(uint32 *)OriginalData = *(uint32 *)NewData;
+ *(uint32 *)DataAddress = *(uint32 *)NewData;
} break;
case action_change_i32:
{
@@ -49,7 +50,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
int32 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(int32), P_UndoBuffer);
*(int32 *)Data = Difference;
- *(int32 *)OriginalData = *(int32 *)NewData;
+ *(int32 *)DataAddress = *(int32 *)NewData;
} break;
case action_change_r32:
{
@@ -58,7 +59,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
real32 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(real32), P_UndoBuffer);
*(real32 *)Data = Difference;
- *(real32 *)OriginalData = *(real32 *)NewData;
+ *(real32 *)DataAddress = *(real32 *)NewData;
} break;
case action_change_u64:
{
@@ -67,7 +68,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
uint64 Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(uint64), P_UndoBuffer);
*(uint64 *)Data = Difference;
- *(uint64 *)OriginalData = *(uint64 *)NewData;
+ *(uint64 *)DataAddress = *(uint64 *)NewData;
} break;
case action_change_ptr:
{
@@ -76,7 +77,7 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
ptrsize Difference = NewValue - OriginalValue;
void *Data = AllocateMemory(Memory, sizeof(ptrsize), P_UndoBuffer);
*(ptrsize *)Data = Difference;
- *(ptrsize *)OriginalData = *(ptrsize *)NewData;
+ *(ptrsize *)DataAddress = *(ptrsize *)NewData;
} break;
case action_change_string:
{
@@ -84,18 +85,43 @@ void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, act
CopyStrings(Data, OriginalData);
Data = AllocateMemory(Memory, STRING_SIZE, P_UndoBuffer);
CopyStrings(Data, NewData);
- CopyStrings(OriginalData, NewData);
+ CopyStrings(DataAddress, NewData);
} break;
}
Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer);
*(action_change_type *)Data = ActionChange;
}
+void Action_Entry_Begin(memory *Memory, action_entry_type Type, char *Name)
+{
+ Memory->Action.Entry[Memory->Action.Index].Name = Name;
+ Memory->Action.Entry[Memory->Action.Index].Type = Type;
+}
+
+void Action_Entry_Begin2(memory *Memory, action_entry_type Type, char *Name, char *Name2)
+{
+ Memory->Action.Entry[Memory->Action.Index].Name = Name;
+ Memory->Action.Entry[Memory->Action.Index].Type = Type;
+ Memory->Action.Entry[Memory->Action.Index + 1].Name = Name2;
+ Memory->Action.Entry[Memory->Action.Index + 1].Type = Type;
+}
+
+void Action_Entry_SetPointer(memory *Memory, void *Data)
+{
+ Memory->Action.Entry[Memory->Action.Index].ExtraPointer = Data;
+}
+
+void Action_Entry_End(memory *Memory)
+{
+ Memory->Action.Index++;
+ Memory->Action.NumberOfEntries++;
+}
+
// TODO(fox): Maybe take the extra lines to separate the incrementing of the
// address from the variable assignment to improve legibility.
// The pointer is unwinded.
-void Action_Undo(memory *Memory) {
+void Action_Change_Undo(memory *Memory) {
memory_table *Table = &Memory->Slot[P_UndoBuffer];
uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition;
action_change_type *ActionType = (action_change_type *)LastPos - 1;
@@ -109,6 +135,41 @@ void Action_Undo(memory *Memory) {
void *Address = (void *)*(ptrsize *)TableAddress;
*(uint16 *)Address -= *Difference;
} break;
+ case action_change_i16:
+ {
+ int16 *Difference = (int16 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(int16 *)Address -= *Difference;
+ } break;
+ case action_change_u32:
+ {
+ uint32 *Difference = (uint32 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(uint32 *)Address -= *Difference;
+ } break;
+ case action_change_i32:
+ {
+ int32 *Difference = (int32 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(int32 *)Address -= *Difference;
+ } break;
+ case action_change_r32:
+ {
+ real32 *Difference = (real32 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(real32 *)Address -= *Difference;
+ } break;
+ case action_change_u64:
+ {
+ uint64 *Difference = (uint64 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(uint64 *)Address -= *Difference;
+ } break;
case action_change_ptr:
{
ptrsize *Difference = (ptrsize *)ActionType - 1;
@@ -116,12 +177,17 @@ void Action_Undo(memory *Memory) {
void *Address = (void *)*(ptrsize *)TableAddress;
*(ptrsize *)Address -= *Difference;
} break;
+ case action_change_string:
+ {
+ TableAddress = 0x0;
+ Assert(0);
+ } break;
}
Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address);
}
// The pointer is rewinded.
-void Action_Redo(memory *Memory) {
+void Action_Change_Redo(memory *Memory) {
memory_table *Table = &Memory->Slot[P_UndoBuffer];
uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition;
void *Address = (void *)*(ptrsize *)LastPos;
@@ -135,12 +201,81 @@ void Action_Redo(memory *Memory) {
TableAddress = (uint8 *)Difference + sizeof(uint16) + sizeof(action_change_type);
*(uint16 *)Address += *Difference;
} break;
+ case action_change_i16:
+ {
+ int16 *Difference = (int16 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(int16) + sizeof(action_change_type);
+ *(int16 *)Address += *Difference;
+ } break;
+ case action_change_u32:
+ {
+ uint32 *Difference = (uint32 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(uint32) + sizeof(action_change_type);
+ *(uint32 *)Address += *Difference;
+ } break;
+ case action_change_i32:
+ {
+ int32 *Difference = (int32 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(int32) + sizeof(action_change_type);
+ *(int32 *)Address += *Difference;
+ } break;
+ case action_change_r32:
+ {
+ real32 *Difference = (real32 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(real32) + sizeof(action_change_type);
+ *(real32 *)Address += *Difference;
+ } break;
+ case action_change_u64:
+ {
+ uint64 *Difference = (uint64 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(uint64) + sizeof(action_change_type);
+ *(uint64 *)Address += *Difference;
+ } break;
case action_change_ptr:
{
ptrsize *Difference = (ptrsize *)(ActionType + 1);
TableAddress = (uint8 *)Difference + sizeof(ptrsize) + sizeof(action_change_type);
*(ptrsize *)Address += *Difference;
} break;
+ case action_change_string:
+ {
+ TableAddress = 0x0;
+ Assert(0);
+ } break;
}
Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address);
}
+
+void Action_Undo(memory *Memory) {
+ Memory->Action.Index--;
+ action_entry Entry = Memory->Action.Entry[Memory->Action.Index];
+ switch (Entry.Type)
+ {
+ case action_entry_layerinit:
+ {
+ AV_Dealloc((av_info *)*(ptrsize *)Entry.ExtraPointer);
+ *(ptrsize *)Entry.ExtraPointer = 0x0; // what actually dereferences the pointer
+ } break;
+ case action_entry_default:
+ {
+ } break;
+ }
+ for (int i = 0; i < Entry.NumberOfActions; i++)
+ Action_Change_Undo(Memory);
+}
+
+void Action_Redo(memory *Memory) {
+ action_entry Entry = Memory->Action.Entry[Memory->Action.Index];
+ switch (Entry.Type)
+ {
+ case action_entry_layerinit:
+ {
+ } break;
+ case action_entry_default:
+ {
+ } break;
+ }
+ for (int i = 0; i < Entry.NumberOfActions; i++)
+ Action_Change_Redo(Memory);
+ Memory->Action.Index++;
+}