From e89dc91182a94e48ca9220a2fe075db680ddff04 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Tue, 16 Aug 2022 15:06:45 -0400 Subject: undo functional --- createcalls.cpp | 130 ++++++++++++++++++++++++----------------- ffmpeg_backend.cpp | 16 +++++- functions.h | 5 +- layer.cpp | 26 ++++++++- main.cpp | 5 +- main.h | 22 +++++++ my_imgui_widgets.cpp | 62 ++++++++++++++++---- undo.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++++++---- 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) @@ -81,6 +101,19 @@ ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, I return V2(Result); } +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) { @@ -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++; +} -- cgit v1.2.3