From 04b7ccfd87d802e6b9a22b86c8d098979164b8ba Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Mon, 15 Aug 2022 23:03:30 -0400 Subject: undo started --- bitmap_calls.cpp | 28 ++++++++++ createcalls.cpp | 41 +++++++++------ defines.h | 3 ++ ffmpeg_backend.cpp | 1 + functions.h | 6 ++- keyframes.cpp | 86 ++++++++++++------------------ main.cpp | 12 +++-- main.h | 27 ++++++++-- memory.cpp | 10 +++- my_imgui_widgets.cpp | 31 +++++++---- strings.cpp | 21 ++++++++ undo.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 325 insertions(+), 87 deletions(-) create mode 100644 undo.cpp diff --git a/bitmap_calls.cpp b/bitmap_calls.cpp index dd5c793..6425e6d 100644 --- a/bitmap_calls.cpp +++ b/bitmap_calls.cpp @@ -31,10 +31,17 @@ void Bitmap_ConvertPacking(void *Buffer, void *DestBuffer, uint16 Width, uint16 DPixel = Temp + Y*Width*4 + X*BytesPerPixel; } +#if ARM + if (InstructionMode == instruction_mode_neon) { + uint32x2x2_t Row = vld2_u32((uint32 *)Pixel); + vst2_u32((uint32 *)DPixel, Row); + X += 4; +#else if (InstructionMode == instruction_mode_sse || InstructionMode == instruction_mode_avx) { __m128i Row = _mm_loadu_si128((__m128i *)Pixel); _mm_storeu_si128((__m128i *)DPixel, Row); X+=4; +#endif } else { *(uint32 *)DPixel = *(uint32 *)Pixel; X++; @@ -101,8 +108,13 @@ static void Bitmap_Clear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel) { uint8 *Row = (uint8 *)Buffer; +#if ARM + uint32 Zero[4] = {0}; + uint32x2x4_t Zero8 = vld4_dup_u32(Zero); +#else __m256i Zero8 = _mm256_setzero_si256(); __m128i Zero = _mm_setzero_si128(); +#endif uint64 bytes = 0; uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel); @@ -110,10 +122,15 @@ Bitmap_Clear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel) while (bytes < TotalBytes) { uint8 *Pixel = Row + bytes; +#if ARM + if (InstructionMode == instruction_mode_neon) { + vst4_u32((uint32 *)Pixel, Zero8); +#else if (InstructionMode == instruction_mode_avx) { _mm256_storeu_si256((__m256i *)Pixel, Zero8); } else if (InstructionMode == instruction_mode_sse) { _mm_storeu_si128((__m128i *)Pixel, Zero); +#endif } else { *(uint32 *)Pixel = 0x00000000; } @@ -136,10 +153,15 @@ Bitmap_CalcPackedDimensions(uint16 Width, uint16 Height, uint16 *WidthP, uint16 static uint16 Bitmap_CalcByteOffset(uint16 BytesPerPixel) { uint16 ByteOffset = BytesPerPixel; +#if ARM + if (InstructionMode == instruction_mode_neon) + ByteOffset = 8*BytesPerPixel; +#else if (InstructionMode == instruction_mode_avx) ByteOffset = 8*BytesPerPixel; if (InstructionMode == instruction_mode_sse) ByteOffset = 4*BytesPerPixel; +#endif return ByteOffset; } @@ -174,12 +196,18 @@ Bitmap_CopyToPointer(void *Input, void *Output, uint16 BytesPerPixel, uint64 Tot int pp = 0; uint8 *Pixel = (uint8 *)Row + bytes; uint8 *Pixel2 = (uint8 *)Row2 + bytes; +#if ARM + if (InstructionMode == instruction_mode_neon) { + uint32x2x4_t OutputPixel = vld4_u32((uint32 *)Pixel); + vst4_u32((uint32 *)Pixel2, OutputPixel); +#else if (InstructionMode == instruction_mode_avx) { __m256i OutputPixel = _mm256_loadu_si256((__m256i *)Pixel); _mm256_storeu_si256((__m256i *)Pixel2, OutputPixel); } else if (InstructionMode == instruction_mode_sse) { __m128i OutputPixel = _mm_loadu_si128((__m128i *)Pixel); _mm_storeu_si128((__m128i *)Pixel2, OutputPixel); +#endif } else { *(uint32 *)Pixel2 = *(uint32 *)Pixel; } diff --git a/createcalls.cpp b/createcalls.cpp index 633a37a..4564d59 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -8,31 +8,35 @@ IncrementFrame(project_data *File, int16 Amount) { } static bool32 -Source_Generate(project_data *File, memory *Memory, char *Path) +Source_Generate(project_data *File, memory *Memory, void *Path) { Assert(File->NumberOfSources < MAX_SOURCES); source *Source = &File->Source[File->NumberOfSources]; bool32 Found = 0; + /* + // TODO(fox): Unbreak stbi! int w, h; if (stbi_info(Path, &w, &h, NULL)) { - Source->Info.Width = w; - Source->Info.Height = h; Source->SourceType = source_type_image; Found = true; } + */ - if (!Found && AV_IsFileSupported(Path)) { + // TODO(fox): This cast won't work above STRING_MAX. + if (!Found && AV_IsFileSupported((char *)Path)) { Source->SourceType = source_type_video; Found = true; } if (Found) { - Source->Info.BytesPerPixel = 4; - Source->Path = Path; - File->NumberOfSources++; + Action_Change_Commit(Memory, &Source->Path, &Path, action_change_ptr); + uint32 i = File->NumberOfSources + 1; + Action_Change_Commit(Memory, &File->NumberOfSources, &i, action_change_u16); return 1; + } else { + // PostMsg(State, "File open fail..."); } return 0; @@ -133,7 +137,7 @@ project_layer * Layer_Init(project_data *File, memory *Memory) File->Layer[a] = (project_layer *)AllocateMemory(Memory, sizeof(project_layer), F_Layers); - File->Layer[a]->Name = (char *)AllocateMemory(Memory, 256, F_Strings); + 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); @@ -386,14 +390,20 @@ Layer_ScreenSpaceToLocal(project_layer *Layer, ui *UI, comp_buffer CompBuffer, I static void LoadTestFootage(project_data *File, project_state *State, memory *Memory) { - if (!Source_Generate(File, Memory, "../asset/24.mp4")) - PostMsg(State, "File open fail..."); - source *Source = &File->Source[0]; + 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]; SelectLayer(File->Layer[0], State, 0); // AddEffect(File->Layer[0], Memory, 3); + /* mask *Mask = &File->Layer[0]->Mask[0]; File->Layer[0]->NumberOfMasks = 1; Mask->Point[0].Pos = V2(200, 200); @@ -421,11 +431,12 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory) Mask->Point[4].HandleBezier = true; Mask->NumberOfPoints = 5; + */ // if (!Source_Generate(File, Memory, "../asset/test.png")) // PostMsg(State, "File open fail..."); - if (!Source_Generate(File, Memory, "../asset/debug.png")) - PostMsg(State, "File open fail..."); + // if (!Source_Generate(File, Memory, "../asset/debug.png")) + // PostMsg(State, "File open fail..."); // property_channel *Property = &File->Layer[0]->x; // ManualKeyframeInsertF(Property, Memory, 1, 500); @@ -439,8 +450,8 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory) // Layer_CreateFromSource(File, State, Memory, Source); - if (!Source_Generate(File, Memory, "../asset/p.mp4")) - PostMsg(State, "File open fail..."); + // if (!Source_Generate(File, Memory, "../asset/p.mp4")) + // PostMsg(State, "File open fail..."); // source *Source2 = &File->Source[1]; // project_layer *Layer2 = Layer_Init(File, Memory); // AV_Init(Source2, &Layer2->BitmapInfo, Memory); diff --git a/defines.h b/defines.h index e9a11de..b919afb 100644 --- a/defines.h +++ b/defines.h @@ -15,6 +15,9 @@ typedef uint64_t uint64; typedef float real32; typedef double real64; +// is there a compiler variable for 32 vs 64 bit like this? +typedef uint64 ptrsize; + #define NORMALIZED_COL_MIN { .col = V4(0.0f, 0.0f, 0.0f, 0.0f) } #define NORMALIZED_COL_MAX { .col = V4(1.0f, 1.0f, 1.0f, 1.0f) } #define NORMALIZED_REAL_MIN { 0.0f } diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp index b3d5be8..f437285 100644 --- a/ffmpeg_backend.cpp +++ b/ffmpeg_backend.cpp @@ -173,6 +173,7 @@ void AV_Init(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory) fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); } + Source->Info.BytesPerPixel = 4; Source->Info.FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den; Source->Info.Width = AV->VideoCodecContext->width; Source->Info.Height = AV->VideoCodecContext->height; diff --git a/functions.h b/functions.h index 81f18ee..7f8f5d3 100644 --- a/functions.h +++ b/functions.h @@ -12,7 +12,7 @@ static uint64 Bitmap_CalcUnpackedBytes(uint16 Width, uint16 Height, uint16 Bytes static void Bitmap_ConvertPacking(void *Buffer, void *DestBuffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, uint16 Which); static void Bitmap_CalcHistogram(void *Data, void *Input, uint16 BytesPerPixel, uint64 TotalBytes); -static bool32 Source_Generate(project_data *File, memory *Memory, char *Path); // Fills out source info if the source is a supported file. +static bool32 Source_Generate(project_data *File, memory *Memory, void *Path); // Fills out source info if the source is a supported file. // Libav (ffmpeg) backend for decoding video @@ -32,3 +32,7 @@ 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_Undo(memory *Memory); +static void Action_Redo(memory *Memor); + diff --git a/keyframes.cpp b/keyframes.cpp index d2813a9..25c41c0 100644 --- a/keyframes.cpp +++ b/keyframes.cpp @@ -5,14 +5,6 @@ KeyframeLookupMemory(property_channel *Property, int16 i) { return &Property->KeyframeBlock[b]->Keyframe[k]; } -static 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]; -} - static keyframe* PushKeyframe(property_channel *Property) { int16 i = Property->NumberOfTotalKeyframes; @@ -21,7 +13,6 @@ PushKeyframe(property_channel *Property) { return &Property->KeyframeBlock[b]->Keyframe[k]; } -// (extremely bad) static temp_keyframe_list GetSelectedKeyframes(project_data *File) { @@ -42,20 +33,6 @@ GetSelectedKeyframes(project_data *File) return KeyframeList; } -static 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; -} - static void SelectKeyframe(project_data *File, project_layer *Layer, property_channel *Property, keyframe *Keyframe) { @@ -77,6 +54,7 @@ DeselectKeyframe(project_data *File, project_layer *Layer, property_channel *Pro static void CheckKeyframeSort(property_channel *Property, int32 Increment, int32 b) { + /* int32 i = KeyframeMemoryToIndex(Property, b); if (Increment > 0) { if (i+1 != Property->NumberOfTotalKeyframes) { @@ -99,10 +77,12 @@ CheckKeyframeSort(property_channel *Property, int32 Increment, int32 b) } } } + */ } static void ShiftKeyframeIndex(property_channel *Property, int16 Increment, int16 StopAt) { + /* if (Increment > 0) { int16 i = Property->NumberOfTotalKeyframes - 1; while (i > StopAt) { @@ -116,6 +96,7 @@ ShiftKeyframeIndex(property_channel *Property, int16 Increment, int16 StopAt) { i++; } } + */ } static void @@ -143,6 +124,7 @@ DeleteKeyframeFromMemory(property_channel *Property, int16 Increment, int16 Stop static void ResortPropertyChannel(property_channel *Property) { + /* for (int16 i = 0; i < Property->NumberOfTotalKeyframes; i++) { Property->SortedIndex[i] = i; @@ -163,6 +145,7 @@ ResortPropertyChannel(property_channel *Property) { if (Swaps == 0) break; } + */ } static void @@ -211,10 +194,12 @@ CalculatePropertyMinMax(property_channel *Property) { static void IncrementKeyframes(property_channel *Property, int16 Increment) { + /* for (int i = 0; i < Property->NumberOfTotalKeyframes; i++) { keyframe *Keyframe = KeyframeLookupIndex(Property, i); Keyframe->FrameNumber += Increment; } + */ } static void @@ -235,8 +220,8 @@ static 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); + keyframe *Keyframe = KeyframeLookupMemory(Property, b - 1); + keyframe *NextKeyframe = KeyframeLookupMemory(Property, b); real32 XSpan = NextKeyframe->FrameNumber - Keyframe->FrameNumber; // TODO(fox): Fix this! #if WINDOWS @@ -251,8 +236,8 @@ ClampKeyframeHandles(property_channel *Property, int16 b, int16 dir) { } if (dir == 1) { if (b < Property->NumberOfTotalKeyframes - 1) { - keyframe *Keyframe = KeyframeLookupIndex(Property, b); - keyframe *NextKeyframe = KeyframeLookupIndex(Property, b + 1); + keyframe *Keyframe = KeyframeLookupMemory(Property, b); + keyframe *NextKeyframe = KeyframeLookupMemory(Property, b + 1); real32 XSpan = NextKeyframe->FrameNumber - Keyframe->FrameNumber; if (Keyframe->TangentRight.x > XSpan) Keyframe->TangentRight.x = XSpan; @@ -281,55 +266,53 @@ ClampSurroundingKeyframeHandles(property_channel *Property, int16 b) { static 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; + keyframe *FirstKeyframe = &Property->KeyframeBlock[0]->Keyframe[0]; + if (CurrentFrame > FirstKeyframe->FrameNumber) { + Keyframe = &Property->KeyframeBlock[0]->Keyframe[1]; } 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 = &Property->KeyframeBlock[0]->Keyframe[0]; + } + } else { + uint32 Index = Property->NumberOfTotalKeyframes - 1; + bool32 Found = false; + while (!Found) { + keyframe *CurrentKeyframe = KeyframeLookupMemory(Property, Index); + if (CurrentKeyframe->FrameNumber < CurrentFrame) { + ShiftKeyframes(Property, 1, i - 1); + Found = true; + } else { + Index--; } } Keyframe = PushKeyframe(Property); - Property->NumberOfTotalKeyframes++; } + if (Keyframe->FrameNumber != CurrentFrame) + 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); + Keyframe->ImguiID = RandomGlobalIncrement++; CalculatePropertyMinMax(Property); + */ } static void CalculateKeyframesLinearly(uint16 CurrentFrame, struct property_channel *Property) { - + /* keyframe *FirstKeyframe = KeyframeLookupIndex(Property, 0); keyframe *LastKeyframe = KeyframeLookupIndex(Property, Property->NumberOfTotalKeyframes - 1); @@ -385,4 +368,5 @@ CalculateKeyframesLinearly(uint16 CurrentFrame, struct property_channel *Propert } } } + */ } diff --git a/main.cpp b/main.cpp index 2153ae6..ac4ddd1 100644 --- a/main.cpp +++ b/main.cpp @@ -51,6 +51,7 @@ SDL_atomic_t QueuedEntries; SDL_atomic_t CompletedEntries; static bool32 IsRendering = false; static instruction_mode InstructionMode = instruction_mode_scalar; +static uint32 RandomGlobalIncrement = 0; render_entry Entries[256]; @@ -73,6 +74,7 @@ SDL_sem *Semaphore; #include "createcalls.cpp" #include "my_imgui_widgets.cpp" #include "gl_calls.cpp" +#include "undo.cpp" static void @@ -224,11 +226,10 @@ int main(int argc, char *argv[]) { memory Memory = {}; - // TODO(fox): Make clean-up functions when these get deleted! InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_AVInfo, "Image/video headers"); - InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_SourceBitmapTable, "Source bitmap tables"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_VectorPoints, "Vector Points"); + InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UndoBuffer, "Undo buffer"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_MiscCache, "Misc cache"); InitMemoryTable(&GlobalMemory, &Memory, 15 * 1024 * 1024, F_Layers, "Layers"); @@ -259,6 +260,10 @@ int main(int argc, char *argv[]) { File.StartFrame = 0; File.EndFrame = 65; + LoadTestFootage(&File, &State, &Memory); + + Assert(0); + #if DEBUG // GDB and LLDB say this plain struct that's literally under 30 bytes is // incomplete in the layers unless I do this... @@ -313,6 +318,7 @@ int main(int argc, char *argv[]) { RenderInfo.File = &File; RenderInfo.State = &State; RenderInfo.CompBuffer = &CompBuffer; + #if THREADED thread_info ThreadInfo[7]; @@ -383,8 +389,6 @@ int main(int argc, char *argv[]) { TestGL_InitDefaultShader(); TestGL_InitDefaultVerts(); - LoadTestFootage(&File, &State, &Memory); - SDL_GL_MakeCurrent(window, gl_context); SDL_Event Event; diff --git a/main.h b/main.h index e77042f..4e48fc5 100644 --- a/main.h +++ b/main.h @@ -29,10 +29,12 @@ enum memory_table_list { // B = cached data, often cleared P_AVInfo, - P_SourceBitmapTable, P_VectorPoints, - P_MiscCache, // don't put this in final + P_UndoBuffer, + P_MiscCache, + // The structs that these four blocks correspond to (project_layer, effect, + // keyframe_block, char[STRING_SIZE]) are guranteed equal size. F_Layers, F_Effects, F_Keyframes, @@ -165,6 +167,17 @@ struct gl_effect_layer { static gl_vertex_shader GL_Vertices; +enum action_change_type { + action_change_u16, + action_change_i16, + action_change_u32, + action_change_i32, + action_change_r32, + action_change_u64, + action_change_ptr, + action_change_string, +}; + union val { real32 f; v4 col; @@ -180,6 +193,9 @@ struct keyframe { // Probably should think of something smarter. v2 TangentLeft; v2 TangentRight; + // NOTE(fox): We need some sort of unique constant to give to ImGui in + // order for dragging to work. + uint32 ImguiID; }; struct keyframe_block { @@ -189,7 +205,6 @@ struct keyframe_block { struct property_channel { char *Name; keyframe_block *KeyframeBlock[MAX_KEYFRAME_BLOCKS]; - uint16 SortedIndex[MAX_KEYFRAME_BLOCKS * MAX_KEYFRAMES_PER_BLOCK]; uint16 NumberOfKeyframeBlocks; uint16 NumberOfSelectedKeyframes; uint16 NumberOfTotalKeyframes; @@ -299,8 +314,6 @@ struct effect { bool32 IsActive = 1; }; - - struct transform_info { real32 XAxisPX; real32 XAxisPY; @@ -323,6 +336,7 @@ struct transform_info { struct mask_point { v2 Pos; bool32 HandleBezier; + bool32 IsSelected; v2 TangentLeft; v2 TangentRight; }; @@ -330,6 +344,7 @@ struct mask_point { struct mask { mask_point Point[16]; uint16 NumberOfPoints; + uint16 NumberOfSelectedPoints; void *TriangulatedPointCache; uint32 NumberOfVerts; }; @@ -435,6 +450,8 @@ enum selection_type selection_layer, selection_effect, selection_keyframe, + selection_maskpoint, + selection_source }; enum tool { diff --git a/memory.cpp b/memory.cpp index dd581b7..7c08f91 100644 --- a/memory.cpp +++ b/memory.cpp @@ -1,12 +1,18 @@ + static void InitMemoryTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name) { memory_table *Table = &Memory->Slot[TableName]; Table->Name = Name; - Table->Address = (uint64 *)((uint8 *)GlobalMemory->Address + GlobalMemory->CurrentPosition); + Table->Address = (ptrsize *)((uint8 *)GlobalMemory->Address + GlobalMemory->CurrentPosition); Table->Size = Size; GlobalMemory->CurrentPosition += Size; } +// NOTE(fox): Currently memory acts like simple stack that can only grow forwards. +// Undos/deletes create "holes." Once someone undos/deletes enough to trigger +// the limit or we start caring more about space, I'll revamp the system to +// keep track of free holes and allow those to be returned. + static void* AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) { void *Address; @@ -14,7 +20,7 @@ AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) { if (Table->CurrentPosition + Size > Table->Size) { return NULL; } - Address = (uint64 *)((uint8 *)Table->Address + Table->CurrentPosition); + Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition); Table->CurrentPosition += Size; return Address; } diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 4a4427c..d1d8d83 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -416,16 +416,19 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp // The handle itself - draw_list->AddNgon(Point0_ScreenPos, 10, col, 8, 5.0f); + if (Point0->IsSelected) { + col = ImGui::GetColorU32(ImGuiCol_ButtonHovered); + draw_list->AddNgon(Point0_ScreenPos_Left, 10, col, 8, 5.0f); + draw_list->AddNgon(Point0_ScreenPos_Right, 10, col, 8, 5.0f); + draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Left, col, 2.0f); + draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Right, col, 2.0f); + } - draw_list->AddNgon(Point0_ScreenPos_Left, 10, col, 8, 5.0f); - draw_list->AddNgon(Point0_ScreenPos_Right, 10, col, 8, 5.0f); - draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Left, col, 2.0f); - draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Right, col, 2.0f); + draw_list->AddNgon(Point0_ScreenPos, 10, col, 8, 5.0f); int max = 1; - if (Point0->HandleBezier) { + if (Point0->HandleBezier && Point0->IsSelected) { max = 3; } @@ -440,11 +443,14 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp ImGui::SetCursorScreenPos(Point0_ScreenPos_Right - ImVec2(PointSize/2, PointSize/2)); } - ImGui::Button("##point", ImVec2(PointSize, PointSize)); + ImGui::InvisibleButton("##point", ImVec2(PointSize, PointSize), ImGuiButtonFlags_MouseButtonLeft); if (ImGui::IsItemHovered()) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } + if (ImGui::IsItemActivated() && b == 0) { + Point0->IsSelected = 1; + } if (ImGui::IsItemActive()) { // TODO(fox): Combine this with the anchor point code. ImVec2 MouseIncrement = io.MouseDelta * (ImVec2(CompBuffer.Width, CompBuffer.Height) / UI->CompZoom); @@ -1258,7 +1264,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, // TODO(fox): Reformat this so it's all done in one loop. for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) { - keyframe *Keyframe = KeyframeLookupIndex(Property, b); + keyframe *Keyframe = KeyframeLookupMemory(Property, b); real32 MinVal = Property->LocalMinVal.f; real32 MaxVal = Property->LocalMaxVal.f; @@ -1533,7 +1539,14 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB DeleteSelectedKeyframes(File, Memory); State->UpdateKeyframes = true; State->UpdateFrame = true; - } break; + } + case selection_maskpoint: + { + } + case selection_source: + { + } + break; } } diff --git a/strings.cpp b/strings.cpp index c1b9c9f..6caedd0 100644 --- a/strings.cpp +++ b/strings.cpp @@ -13,3 +13,24 @@ EffectConsoleCallback(ImGuiInputTextCallbackData* data) } return 0; } + +static void +CopyStrings(void *Dest, void *Data) +{ + for (int i = 0; i < STRING_SIZE; i++) + { + *((char *)Dest + i) = *((char *)Data + i); + } +} + +static void * +String_GenerateFromChar(memory *Memory, char *Char) +{ + void *Address = AllocateMemory(Memory, STRING_SIZE, F_Strings); + uint16 i = 0; + while (Char[i] != '\0') { + *((char *)Address + i) = Char[i]; + i++; + } + return Address; +} diff --git a/undo.cpp b/undo.cpp new file mode 100644 index 0000000..7858f8d --- /dev/null +++ b/undo.cpp @@ -0,0 +1,146 @@ +// get ready for some MLG... + +// These get four things pushed together: the address of what's being +// changed, what type the data is, the original data, and the type again. +// The type is encoded twice so we always know how big the data is whether +// we're undoing or redoing. +// 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 *UndoEntry = AllocateMemory(Memory, sizeof(void *), P_UndoBuffer); + *(ptrsize *)UndoEntry = (ptrsize)OriginalData; + void *Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer); + *(action_change_type *)Data = ActionChange; + switch (ActionChange) + { + case action_change_u16: + { + uint16 OriginalValue = *(uint16 *)OriginalData; + uint16 NewValue = *(uint16 *)NewData; + uint16 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(uint16), P_UndoBuffer); + *(uint16 *)Data = Difference; + *(uint16 *)OriginalData = *(uint16 *)NewData; + } break; + case action_change_i16: + { + int16 OriginalValue = *(int16 *)OriginalData; + int16 NewValue = *(int16 *)NewData; + int16 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(int16), P_UndoBuffer); + *(int16 *)Data = Difference; + *(int16 *)OriginalData = *(int16 *)NewData; + } break; + case action_change_u32: + { + uint32 OriginalValue = *(uint32 *)OriginalData; + uint32 NewValue = *(uint32 *)NewData; + uint32 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(uint32), P_UndoBuffer); + *(uint32 *)Data = Difference; + *(uint32 *)OriginalData = *(uint32 *)NewData; + } break; + case action_change_i32: + { + int32 OriginalValue = *(int32 *)OriginalData; + int32 NewValue = *(int32 *)NewData; + int32 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(int32), P_UndoBuffer); + *(int32 *)Data = Difference; + *(int32 *)OriginalData = *(int32 *)NewData; + } break; + case action_change_r32: + { + real32 OriginalValue = *(real32 *)OriginalData; + real32 NewValue = *(real32 *)NewData; + real32 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(real32), P_UndoBuffer); + *(real32 *)Data = Difference; + *(real32 *)OriginalData = *(real32 *)NewData; + } break; + case action_change_u64: + { + uint64 OriginalValue = *(uint64 *)OriginalData; + uint64 NewValue = *(uint64 *)NewData; + uint64 Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(uint64), P_UndoBuffer); + *(uint64 *)Data = Difference; + *(uint64 *)OriginalData = *(uint64 *)NewData; + } break; + case action_change_ptr: + { + ptrsize OriginalValue = *(ptrsize *)OriginalData; + ptrsize NewValue = *(ptrsize *)NewData; + ptrsize Difference = NewValue - OriginalValue; + void *Data = AllocateMemory(Memory, sizeof(ptrsize), P_UndoBuffer); + *(ptrsize *)Data = Difference; + *(ptrsize *)OriginalData = *(ptrsize *)NewData; + } break; + case action_change_string: + { + void *Data = AllocateMemory(Memory, STRING_SIZE, P_UndoBuffer); + CopyStrings(Data, OriginalData); + Data = AllocateMemory(Memory, STRING_SIZE, P_UndoBuffer); + CopyStrings(Data, NewData); + CopyStrings(OriginalData, NewData); + } break; + } + Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer); + *(action_change_type *)Data = ActionChange; +} + +// 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) { + memory_table *Table = &Memory->Slot[P_UndoBuffer]; + uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition; + action_change_type *ActionType = (action_change_type *)LastPos - 1; + uint8 *TableAddress; + switch (*ActionType) + { + case action_change_u16: + { + uint16 *Difference = (uint16 *)ActionType - 1; + TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type); + void *Address = (void *)*(ptrsize *)TableAddress; + *(uint16 *)Address -= *Difference; + } break; + case action_change_ptr: + { + ptrsize *Difference = (ptrsize *)ActionType - 1; + TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type); + void *Address = (void *)*(ptrsize *)TableAddress; + *(ptrsize *)Address -= *Difference; + } break; + } + Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address); +} + +// The pointer is rewinded. +void Action_Redo(memory *Memory) { + memory_table *Table = &Memory->Slot[P_UndoBuffer]; + uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition; + void *Address = (void *)*(ptrsize *)LastPos; + action_change_type *ActionType = (action_change_type *)(LastPos + sizeof(void *)); + uint8 *TableAddress; + switch (*ActionType) + { + case action_change_u16: + { + uint16 *Difference = (uint16 *)(ActionType + 1); + TableAddress = (uint8 *)Difference + sizeof(uint16) + sizeof(action_change_type); + *(uint16 *)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; + } + Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address); +} -- cgit v1.2.3