diff options
-rw-r--r-- | createcalls.cpp | 141 | ||||
-rw-r--r-- | debug.h | 3 | ||||
-rw-r--r-- | ffmpeg_backend.cpp | 3 | ||||
-rw-r--r-- | functions.h | 5 | ||||
-rw-r--r-- | gl_calls.cpp | 5 | ||||
-rw-r--r-- | main.cpp | 166 | ||||
-rw-r--r-- | main.h | 117 | ||||
-rw-r--r-- | memory.cpp | 33 | ||||
-rw-r--r-- | memory.h | 2 | ||||
-rw-r--r-- | my_imgui_widgets.cpp | 28 | ||||
-rw-r--r-- | strings.cpp | 6 | ||||
-rw-r--r-- | threading.cpp | 12 | ||||
-rw-r--r-- | undo.cpp | 745 |
13 files changed, 536 insertions, 730 deletions
diff --git a/createcalls.cpp b/createcalls.cpp index 3bd13f8..2c2df61 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -1,29 +1,92 @@ +static void +PostMsg(project_state *State, char *msg) +{ + State->MsgTime = 120; + State->Msg = msg; +} -static bool32 +static uint16 Source_Generate(project_data *File, project_state *State, memory *Memory, void *TempString) { Assert(File->Source_Count < MAX_SOURCES); bool32 IsVideo = 0; - if (AV_IsFileSupported((char *)Path, &IsVideo)) { - block_source *Source = - uint16 = String_AddToFile(Memory, (char *)TempString); + if (AV_IsFileSupported((char *)TempString, &IsVideo)) { + uint16 Index = Memory_Block_AllocateNew(Memory, F_Strings); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index); + History_Entry_Commit(Memory, "Add source"); + History_Action_Block_Swap(Memory, F_Sources, Source); + + Source->Occupied = 1; + Source->Block_String_Index = String_AddToFile(Memory, (char *)TempString); if (IsVideo) Source->SourceType = source_type_video; else Source->SourceType = source_type_image; - History_Entry_Commit(Memory, action_entry_default, "Add source"); - History_Action_Change(Memory, &Source->Path, &Source->Path, &Path, action_type_change_ptr); - uint32 i = File->NumberOfSources + 1; - History_Action_Change(Memory, &File->NumberOfSources, &File->NumberOfSources, &i, action_type_change_u16); + + History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count); + File->Source_Count++; History_Entry_End(Memory); - return 1; + return Index; } else { - void *Address = Memory_Rewind(Memory, STRING_SIZE, F_Strings); PostMsg(State, "File not supported..."); } - return 0; + return -1; +} + +static property_channel +Property_InitFloat(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX) { property_channel Property = {}; + Property.Name = Name; + Property.CurrentValue = Val; + Property.MinVal = MinVal; + Property.MaxVal = MaxVal; + Property.ScrubVal = ScrubVal; + return Property; +} + + +block_layer * Layer_Init(project_data *File, memory *Memory) +{ + block_layer *Layer = (block_layer *)Memory_Block_AllocateAddress(Memory, F_Layers); + History_Action_Block_Swap(Memory, F_Layers, Layer); + + *Layer = {}; + Layer->Occupied = 1; + + Layer->Block_String_Index = Memory_Block_AllocateNew(Memory, F_Strings); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); + sprintf(String->Char, "Layer %i", File->Layer_Count + 1); // CSbros... + + Layer->x = Property_InitFloat("X Position", 0.0f, 1.0f); + Layer->y = Property_InitFloat("Y Position", 0.0f, 1.0f); + Layer->ax = Property_InitFloat("Anchor X", 0.5f, 0.005f); + Layer->ay = Property_InitFloat("Anchor Y", 0.5f, 0.005f); + Layer->scale = Property_InitFloat("Scale", 1.0f, 0.005f); + Layer->rotation = Property_InitFloat("Rotation", 0.0f, 1.0f); + Layer->opacity = Property_InitFloat("Opacity", 1.0f, 0.005f, 0.0f, 1.0f); + Layer->time = Property_InitFloat("Frame Number", 0.0f, 1.0f, 0, 100000); + + History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count); + File->Layer_Count++; + + return Layer; +} + + +static void +Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, uint16 SourceIndex, int32 Frame_End) +{ + if (File->Layer_Count + 1 > MAX_LAYERS) { + Assert(0); + } + History_Entry_Commit(Memory,"Add layer from source"); + block_layer *Layer = Layer_Init(File, Memory); + Layer->Block_Source_Index = SourceIndex; + Layer->Frame_End = Frame_End; + History_Entry_End(Memory); + + State->UpdateFrame = true; } #if 0 @@ -37,25 +100,6 @@ IncrementFrame(project_data *File, int16 Amount) { } static void -PostMsg(project_state *State, char *msg) -{ - State->MsgTime = 120; - State->Msg = msg; -} - -static property_channel -InitFloatProperty(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX) { - property_channel Property = {}; - Property.Name = Name; - Property.CurrentValue.f = Val; - Property.MinVal.f = MinVal; - Property.MaxVal.f = MaxVal; - Property.ScrubVal.f = ScrubVal; - Property.VarType = type_real; - return Property; -} - -static void CreateKeyframeBlock(property_channel *Property, memory *Memory) { int16 a = Property->NumberOfKeyframeBlocks++; @@ -72,43 +116,6 @@ void * Layer_AllocateBitmap(memory *Memory, uint16 Width, uint16 Height, uint16 return Address; } -project_layer * Layer_Init(project_data *File, memory *Memory) -{ - 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. - History_Entry_Commit(Memory, action_entry_layerinit, "Create layer"); - History_Action_Change(Memory, &File->NumberOfLayers, &Index, &NextIndex, action_type_change_u16); - - File->Layer[Index] = (project_layer *)AllocateMemory(Memory, sizeof(project_layer), F_Layers); - - project_layer *Layer = File->Layer[Index]; - *Layer = {}; - Layer->BitmapInfo.CurrentFrame = -1; - - History_Entry_SetPointer(Memory, &Layer->BitmapInfo.AVInfo); - - History_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) { @@ -33,6 +33,9 @@ struct project_debug uint64 PixelCountChecked; // NOTE(fox): Pixel count isn't thread safe; don't use with multithreading! uint64 LayerCycleCount[64]; + uint32 UndoState = 0; + uint64 ScratchSize[6]; + uint32 ScratchState = 0; }; static project_debug Debug; diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp index 34abf35..b986d7a 100644 --- a/ffmpeg_backend.cpp +++ b/ffmpeg_backend.cpp @@ -125,7 +125,8 @@ void AV_Init(block_source *Source, av_info *AV, memory *Memory) // The two calls below theoretically shouldn't fail since we already tested them in IsFileSupported. AV->FileFormatContext = avformat_alloc_context(); - err = avformat_open_input(&AV->FileFormatContext, Source->Path, NULL, NULL);; + char *Path = (char *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Block_String_Index); + err = avformat_open_input(&AV->FileFormatContext, Path, NULL, NULL);; if (err < 0) { fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); Assert(0); diff --git a/functions.h b/functions.h index 1e044d1..88278fe 100644 --- a/functions.h +++ b/functions.h @@ -1,3 +1,6 @@ +static bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo); + +# if 0 // Buffer management @@ -16,7 +19,6 @@ static bool32 Source_Generate(project_data *File, project_state *State, memory * // Libav (ffmpeg) backend for decoding video -static bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo); static void AV_Init(char *filename, source *Source, memory *Memory); // Initializes all internal structs and calculates average PTS. static cached_bitmap * AV_LoadVideoFrame(source *Source, memory *Memory, int32 TimelineFrame); // Loads video frame at TimelineFrame. @@ -68,4 +70,5 @@ static bool32 CheckQueue(render_queue RenderInfo, uint16 Index); static void Effect_DrawColor(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, property_channel Property[]); static void Effect_Levels(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, property_channel Property[]); static void Effect_GaussianBlur(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, property_channel Property[]); +#endif diff --git a/gl_calls.cpp b/gl_calls.cpp index ba63fda..b08615a 100644 --- a/gl_calls.cpp +++ b/gl_calls.cpp @@ -78,8 +78,7 @@ const char *FragmentShaderEffectSource[] = {"", }; - -#include "effects_gl.cpp" +// #include "effects_gl.cpp" static void GL_InitDefaultShader() { DefaultVertexShader = glCreateShader(GL_VERTEX_SHADER); @@ -155,6 +154,7 @@ static void GL_InitDefaultVerts() { glEnableVertexAttribArray(1); } +#if 0 void GL_InitTexture(gl_effect_layer *Test) { @@ -378,3 +378,4 @@ Effect_GL_InitShader(int EffectIndex) return *ShaderProgram; } +#endif @@ -41,38 +41,40 @@ #include "main.h" #include "debug.h" -// #include "functions.h" +#include "functions.h" // #include "sharebuffer.h" -SDL_atomic_t CurrentEntry; -SDL_atomic_t QueuedEntries; -SDL_atomic_t CompletedEntries; +SDL_atomic_t Render_Interrupt; +// SDL_atomic_t CurrentEntry; +// 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]; -SDL_Thread *thread[8]; +// SDL_Thread *thread[8]; +SDL_Thread *MainRenderThread; SDL_sem *Semaphore; #include "memory.cpp" +#include "undo.cpp" #include "strings.cpp" +#if THREADED +#include "threading.cpp" +#endif #include "createcalls.cpp" #include "ffmpeg_backend.cpp" +#include "my_imgui_widgets.cpp" +#include "gl_calls.cpp" #if 0 #include "effects.cpp" #include "keyframes.cpp" #include "layer.cpp" #include "bezier.cpp" -#if THREADED -#include "threading.cpp" -#endif #include "prenderer.cpp" #include "bitmap_calls.cpp" -#include "my_imgui_widgets.cpp" -#include "gl_calls.cpp" -#include "undo.cpp" #endif @@ -129,16 +131,17 @@ int main(int argc, char *argv[]) { Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_AVInfo, "Image/video headers"); Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UndoBuffer, "Undo buffer"); - Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_MiscCache, "Misc persistent"); + Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_MiscCache, "Misc persistent"); Memory_InitTable(&GlobalMemory, &Memory, sizeof(project_data), F_File, "File", sizeof(project_data)); Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Precomps, "Precomps", sizeof(block_composition)); - // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Layers, "Layers"); - Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Sources, "Sources", sizeof(block_source)); + Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Layers, "Layers", sizeof(block_layer)); + Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Sources, "Sources", sizeof(block_source)); // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Effects, "Effects"); // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Keyframes, "Keyframe blocks"); - Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings"); + Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings", sizeof(block_string)); + Memory_InitTable(&GlobalMemory, &Memory, (uint64)64 * 1024 * 1024, B_ScratchSpace, "Scratch"); // Memory_InitTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer"); #if ARM @@ -153,7 +156,10 @@ int main(int argc, char *argv[]) { #endif project_state *State = (project_state *)Memory.Slot[P_MiscCache].Address; + *State = {}; project_data *File = (project_data *)Memory_Block_AllocateAddress(&Memory, F_File); + *File = {}; + File->Occupied = 1; block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps); MainComp->Width = 1280; @@ -164,68 +170,22 @@ int main(int argc, char *argv[]) { MainComp->Frame_Count = 48; MainComp->Frame_End = 48; - Source_Generate(File, State, Memory, "../asset/a.jpg"); - -#if 0 - -#if DEBUG - - LoadTestFootage(&File, &State, &Memory); - - // GDB and LLDB say this plain struct that's literally under 30 bytes is - // incomplete in the layers unless I do this... - layer_bitmap_info BitmapInfo; - BitmapInfo.ToUpdate = 0; - BitmapInfo.FrameOffset = 2; - av_info BS = {}; - BS.PreviousPTS = 0; - effect as = {}; -#endif - - uint16 BytesPerPixel = 4; - comp_buffer CompBuffer = {}; - CompBuffer.Width = File.Width; - CompBuffer.Height = File.Height; - CompBuffer.BytesPerPixel = BytesPerPixel; - CompBuffer.PackedBuffer = Layer_AllocateBitmap(&Memory, CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel); - CompBuffer.UnpackedBuffer = Layer_AllocateBitmap(&Memory, CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel); - - ui UI = {}; - - UI.Y_TimelinePercentZoomed = UI.Default_Y_TimelinePercentZoomed; - UI.Y_TimelinePercentOffset = UI.Default_Y_TimelinePercentOffset; - - // shm_unlink("/testl"); - // int fd = shm_open("/testl", O_CREAT | O_EXCL | O_RDWR, - // S_IRUSR | S_IWUSR); - // if (fd == -1) - // errExit("shm_open"); - - // if (ftruncate(fd, SHAREDMEMORY_SIZE) == -1) - // Assert(0); + { + uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/a.jpg"); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, 0); - // void *asda = mmap(NULL, SHAREDMEMORY_SIZE, - // PROT_READ | PROT_WRITE, - // MAP_SHARED, fd, 0); - // SharedMemoryInfo *shmp = (SharedMemoryInfo *)asda; + Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End); + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, 0); - // if (shmp == MAP_FAILED) - // Assert(0); + History_Undo(&Memory); + History_Redo(&Memory); + } - // if (sem_init(&shmp->sem1, 1, 0) == -1) - // Assert(0); - // if (sem_init(&shmp->sem2, 1, 0) == -1) - // Assert(0); + State->Render.MainCompBuffer = (void *)((uint8 *)Memory.Slot[P_MiscCache].Address + sizeof(project_state)); SDL_Init(SDL_INIT_VIDEO); - Semaphore = SDL_CreateSemaphore(0); - - render_queue RenderInfo = {}; - RenderInfo.File = &File; - RenderInfo.State = &State; - RenderInfo.CompBuffer = &CompBuffer; - +#if 0 #if THREADED thread_info ThreadInfo[7]; @@ -236,8 +196,7 @@ int main(int argc, char *argv[]) { thread[i] = SDL_CreateThread(TestThread, str, &ThreadInfo[i]); } #endif - sdl_input Input; - sdl_input OldInput; +#endif // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) @@ -322,22 +281,24 @@ int main(int argc, char *argv[]) { ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); + int64 i = 0; + while (i < MainComp->Width*MainComp->Height) { + *((uint32 *)State->Render.MainCompBuffer + i++) = 0xFF2F0000; + } + GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same -#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__) - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); -#endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CompBuffer.Width, CompBuffer.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, CompBuffer.PackedBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MainComp->Width, MainComp->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, State->Render.MainCompBuffer); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + // Semaphore = SDL_CreateSemaphore(0); + // MainRenderThread = SDL_CreateThread(MainRenderer, "Main render thread", &State->Render); - while (State.IsRunning) + while (State->IsRunning) { SDL_Event event; while (SDL_PollEvent(&event)) @@ -345,19 +306,19 @@ int main(int argc, char *argv[]) { ImGui_ImplSDL2_ProcessEvent(&event); if (event.type == SDL_DROPFILE) { char *DropFile = event.drop.file; - Source_Generate(&File, &State, &Memory, DropFile); + Source_Generate(File, State, &Memory, DropFile); SDL_free(DropFile); } if (event.type == SDL_QUIT) - State.IsRunning = false; + State->IsRunning = false; if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) - State.IsRunning = false; + State->IsRunning = false; } - if (UI.WantSetPos) { - ImGui::GetIO().WantSetMousePos = true; - io.MousePos = UI.SetPos; - } + // if (UI.WantSetPos) { + // ImGui::GetIO().WantSetMousePos = true; + // io.MousePos = UI.SetPos; + // } ImGui_ImplOpenGL3_NewFrame(); @@ -365,17 +326,18 @@ int main(int argc, char *argv[]) { ImGui::NewFrame(); - if (UI.WantSetPos) { - ImGui_WrapMouseFinish(&UI, io.MousePos); - io.MouseDelta = {}; - UI.WantSetPos = false; - } + // if (UI.WantSetPos) { + // ImGui_WrapMouseFinish(&UI, io.MousePos); + // io.MouseDelta = {}; + // UI.WantSetPos = false; + // } + + ImGui::DockSpaceOverViewport(); +#if 0 if (!io.WantCaptureKeyboard) ImGui_ProcessInputs(&File, &State, &CompBuffer, &Memory, &UI, io); - ImGui::DockSpaceOverViewport(); - ImGui_Viewport(File, &State, &UI, &Memory, CompBuffer, io, textureID); ImGui_File(&File, &State, &Memory, &UI, io); @@ -386,7 +348,12 @@ int main(int argc, char *argv[]) { ImGui_Timeline(&File, &State, &Memory, &UI, io); // ImGui_Graph(&File, &State, &Memory, &UI, io); +#endif + ImGui_Viewport(MainComp, textureID); + ImGui::ShowDemoWindow(); + +#if 0 #if DEBUG ImGui_DebugUndoTree(&File, &Memory); if (Debug.ToggleWindow) { @@ -410,7 +377,9 @@ int main(int argc, char *argv[]) { // Right now IsRendering does nothing. I have it here if we want to // completely detatch the rendering updater onto its own thread so the // UI never lags. +#endif +#if 0 if (State.UpdateFrame && !IsRendering) { MainFunction(0, &Memory, &State, &File, &CompBuffer); State.UpdateFrame = 0; @@ -433,6 +402,7 @@ int main(int argc, char *argv[]) { FinishRenderAndUpload(&State, &CompBuffer, textureID); } #endif +#endif ImGui::Render(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); @@ -441,15 +411,15 @@ int main(int argc, char *argv[]) { ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); SDL_GL_SwapWindow(window); } - for (int i = 0; i < 7; i++) { - SDL_DetachThread(thread[i]); - } + + // for (int i = 0; i < 7; i++) { + // SDL_DetachThread(thread[i]); + // } // shm_unlink("/testl"); ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); SDL_Quit(); -#endif return 0; } @@ -39,6 +39,10 @@ enum blend_mode blend_difference }; +struct block_string { + uint8 Occupied; + char Char[1024 - sizeof(uint8)]; +}; enum interpolation_type { @@ -59,12 +63,19 @@ struct block_bezier { bezier_point Point[MAX_KEYFRAMES_PER_BLOCK]; }; +struct render_state +{ + void *MainCompBuffer; +}; + struct project_state { bool32 UpdateKeyframes = 1; bool32 UpdateFrame = 1; // only refreshes frame; set UpdateKeyframes to update animation bool32 DebugDisableCache = 1; + render_state Render; + // tool Tool = tool_default; // pen_state Pen = {}; @@ -152,6 +163,58 @@ struct property_channel { bool32 IsToggled; }; +struct layer_bitmap_state { + // Image and video + bool32 ToUpdate = 1; + + // GL state + // gl_effect_layer Test; + // gl_effect_layer TestM; + + // Video state + int32 CurrentFrame = -1; // The last frame number rendered to the bitmap. -1 gurantees a load upon layer creation. + void *AVInfo; // Internal data containing current frame info +}; + +struct block_layer { + uint8 Occupied; + + uint16 Block_String_Index; + uint16 Block_Source_Index; + uint16 Block_Composition_Index; + + uint16 Block_Mask_Index[MAX_EFFECTS]; + uint16 Block_Mask_Count; + + uint16 Block_Effect_Index[MAX_MASKS]; + uint16 Block_Effect_Count; + + blend_mode BlendMode; + + union + { + property_channel Property[8]; + struct + { + property_channel x; + property_channel y; + property_channel ax; + property_channel ay; + property_channel rotation; + property_channel scale; + property_channel opacity; + property_channel time; + }; + }; + + bool32 IsSelected; + + int32 Frame_Offset; + int32 Frame_Start; + int32 Frame_End; + + uint32 LayerColor; +}; #if 0 @@ -170,20 +233,6 @@ struct gl_effect_layer { uint32 Stencil_Renderbuffer; }; -struct layer_bitmap_info { - // Image and video - void *BitmapBuffer; // Each layer has a persistent bitmap that the source data gets packed into. - int32 FrameOffset; // The "true" position of the layer, separate from StartFrame. Starts at zero and only gets incremented when the layer is moved. - bool32 ToUpdate = 1; - - gl_effect_layer Test; - gl_effect_layer TestM; - - // Video only - int32 CurrentFrame = -1; // The last frame number rendered to the bitmap. -1 gurantees a load upon layer creation. - void *AVInfo; // Internal data containing current frame info -}; - // Bitmaps from files are loaded into these temporary cache blocks. @@ -234,46 +283,6 @@ struct mask { uint32 NumberOfVerts; }; -struct project_layer { - char *Name; - blend_mode BlendMode; - - union - { - property_channel Property[8]; - struct - { - property_channel x; - property_channel y; - property_channel ax; - property_channel ay; - property_channel rotation; - property_channel scale; - property_channel opacity; - property_channel time; - }; - }; - - bool32 IsSelected; - - source *Source; - layer_bitmap_info BitmapInfo; - - effect *Effect[MAX_EFFECTS]; - uint16 NumberOfEffects; - - mask Mask[MAX_MASKS]; - uint16 NumberOfMasks; - - int32 StartFrame; - int32 EndFrame; - - uint32 LayerColor; - - // For rendering - transform_info TransformInfo; -}; - struct main_sdl { @@ -30,7 +30,6 @@ Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName) Index++; } Memory_Zero(Address_Playhead, Table->Block_ElementSize); - *Address_Playhead = 1; return Index; } @@ -41,7 +40,6 @@ Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 memory_table *Table = &Memory->Slot[TableName]; Assert(Table->Block_ElementSize != 0); uint8 *Address = (uint8 *)Table->Address + (Table->Block_ElementSize * Index); - Assert(*Address == 1); return (void *)Address; } @@ -49,7 +47,36 @@ static void * Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, TableName); - return Memory_Block_AddressAtIndex(Memory, F_File, FileIndex); + return Memory_Block_AddressAtIndex(Memory, TableName, FileIndex); +} + +static void * +Memory_PushScratch(memory *Memory, uint64 Size) { + memory_table *Table = &Memory->Slot[B_ScratchSpace]; + uint8 *Address = ((uint8 *)Table->Address + Memory->ScratchPos); + Memory->ScratchPos += Size; +#if DEBUG + Debug.ScratchSize[Debug.ScratchState] = Size; + Debug.ScratchState++; +#endif + return (void *)Address; +} + +static void +Memory_PopScratch(memory *Memory, uint64 Size) { + memory_table *Table = &Memory->Slot[B_ScratchSpace]; + Memory->ScratchPos -= Size; +#if DEBUG + Debug.ScratchState--; + Assert(Debug.ScratchSize[Debug.ScratchState] == Size); +#endif +} + +static void * +Memory_AddressAtOffset(memory *Memory, memory_table_list TableName, uint64 Offset) +{ + memory_table *Table = &Memory->Slot[TableName]; + return (void *)((uint8 *)Table->Address + Offset); } #if 0 @@ -14,6 +14,7 @@ enum memory_table_list { F_Nodes, F_Strings, + B_ScratchSpace, B_CachedBitmaps, }; @@ -59,6 +60,7 @@ struct history_entry_list { struct memory { memory_table Slot[16]; history_entry_list History; + uint64 ScratchPos; bool32 IsFileSaved; }; diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index a688283..e8159fe 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -2,6 +2,33 @@ #include "my_imgui_internal_widgets.h" #include "imgui_ops.h" +static void +ImGui_Viewport(block_composition *MainComp, GLuint textureID) +{ + bool open = true; + ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + + ImVec2 ViewportMin = ImGui::GetCursorScreenPos(); + ImVec2 ViewportScale = ImGui::GetContentRegionAvail(); + ImVec2 ViewportMax = ImVec2(ViewportMin.x + ViewportScale.x, ViewportMin.y + ViewportScale.y); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->AddRectFilled(ViewportMin, ViewportMax, IM_COL32(50, 50, 50, 255)); + draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255, 255, 255, 255)); + + ImVec2 CompZoom(MainComp->Width, MainComp->Height); + ImVec2 CompPos = ViewportMin + (ViewportMax - ViewportMin)*0.5 - CompZoom*0.5; + + // Actual composition texture + draw_list->PushClipRect(ViewportMin, ViewportMax, true); + draw_list->AddImage((void *)(intptr_t)textureID, ImVec2(CompPos.x, CompPos.y), + ImVec2(CompPos.x + CompZoom.x, CompPos.y + CompZoom.y)); + draw_list->PopClipRect(); + + ImGui::End(); +} + +#if 0 // 0 for timeline keyframe, 1 for graph keyframe, 2 for left graph handle, 3 for right graph handle static void ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, property_channel *Property, int32 b, ImGuiIO io, int16 Type) @@ -2595,3 +2622,4 @@ static char ImGuiPrefs[] = "[Window][DockSpaceViewport_11111111]" } #endif +#endif diff --git a/strings.cpp b/strings.cpp index b8560d1..ab410b2 100644 --- a/strings.cpp +++ b/strings.cpp @@ -27,10 +27,12 @@ static uint16 String_AddToFile(memory *Memory, char *Char) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, F_Strings); - void *Address = Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex); + History_Action_Block_Swap(Memory, F_Strings, String); + String->Occupied = 1; uint16 i = 0; while (Char[i] != '\0') { - *((char *)Address + i) = Char[i]; + String->Char[i] = Char[i]; i++; } return FileIndex; diff --git a/threading.cpp b/threading.cpp index c1cfe5c..ff891a6 100644 --- a/threading.cpp +++ b/threading.cpp @@ -1,3 +1,14 @@ + +static int +MainRenderer(void *ptr) +{ + for(;;) + { + SDL_SemWait(Semaphore); + } +} + +#if 0 static void PushRect(rectangle RenderRegion) { @@ -44,3 +55,4 @@ TestThread(void *ptr) } } } +#endif @@ -1,554 +1,295 @@ -// get ready for some MLG... - -// The undo system currently works in two layers: a lower-level structless -// stack that records "actions" and a higher-level array of "entries" that -// bundle actions together. An action can either record a single change to a -// specific memory address or a shift of pointers. Entries are what the user -// sees and can contain multiple actions (i.e. adding a source changes the -// value of the string and the increment of how many sources there are). -// Entries are allowed to call functions in case there's something that can't -// be incorporated into this memory model (i.e. deallocating libav contexts -// when a layer's creation is undone), though they should be used only -// when necessary. - -// These get four things pushed together: what type the data is, address, 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 History_Action_Change(memory *Memory, void *DataAddress, void *OriginalData, void *NewData, action_type ActionChange) +void Arbitrary_WriteInto(uint8 *Address_Read, uint8 *Address_Write, uint64 Size) { - Memory->Action.Entry[Memory->Action.Index].NumberOfActions++; - void *Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = ActionChange; - void *UndoEntry = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)UndoEntry = (ptrsize)DataAddress; - switch (ActionChange) - { - case action_type_change_u16: - { - uint16 OriginalValue = *(uint16 *)OriginalData; - uint16 NewValue = *(uint16 *)NewData; - uint16 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(uint16), P_UndoBuffer); - *(uint16 *)Data = Difference; - *(uint16 *)DataAddress = *(uint16 *)NewData; - } break; - case action_type_change_i16: - { - int16 OriginalValue = *(int16 *)OriginalData; - int16 NewValue = *(int16 *)NewData; - int16 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(int16 *)Data = Difference; - *(int16 *)DataAddress = *(int16 *)NewData; - } break; - case action_type_change_u32: - { - uint32 OriginalValue = *(uint32 *)OriginalData; - uint32 NewValue = *(uint32 *)NewData; - uint32 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(uint32), P_UndoBuffer); - *(uint32 *)Data = Difference; - *(uint32 *)DataAddress = *(uint32 *)NewData; - } break; - case action_type_change_i32: - { - int32 OriginalValue = *(int32 *)OriginalData; - int32 NewValue = *(int32 *)NewData; - int32 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(int32), P_UndoBuffer); - *(int32 *)Data = Difference; - *(int32 *)DataAddress = *(int32 *)NewData; - } break; - case action_type_change_r32: - { - real32 OriginalValue = *(real32 *)OriginalData; - real32 NewValue = *(real32 *)NewData; - real32 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(real32), P_UndoBuffer); - *(real32 *)Data = Difference; - *(real32 *)DataAddress = *(real32 *)NewData; - } break; - case action_type_change_u64: - { - uint64 OriginalValue = *(uint64 *)OriginalData; - uint64 NewValue = *(uint64 *)NewData; - uint64 Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - *(uint64 *)Data = Difference; - *(uint64 *)DataAddress = *(uint64 *)NewData; - } break; - case action_type_change_ptr: - { - ptrsize OriginalValue = *(ptrsize *)OriginalData; - ptrsize NewValue = *(ptrsize *)NewData; - ptrsize Difference = NewValue - OriginalValue; - void *Data = Memory_Advance(Memory, sizeof(ptrsize), P_UndoBuffer); - *(ptrsize *)Data = Difference; - *(ptrsize *)DataAddress = *(ptrsize *)NewData; - } break; - case action_type_change_string: - { - void *Data = Memory_Advance(Memory, STRING_SIZE, P_UndoBuffer); - CopyStrings(Data, OriginalData); - Data = Memory_Advance(Memory, STRING_SIZE, P_UndoBuffer); - CopyStrings(Data, NewData); - CopyStrings(DataAddress, NewData); - } break; - default: - { - Assert(0); - } - + uint64 i = 0; + while (i < Size) { + *(Address_Write + i) = *(Address_Read + i); + i++; } - Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = ActionChange; } -// Helper functions for common types of data changes. -void History_Action_Change_SwapBool(memory *Memory, bool32 *Bool) +void Arbitrary_Zero(uint8 *Address_Write, uint64 Size) { - bool32 OppositeBool = *Bool ^ 1; - History_Action_Change(Memory, Bool, Bool, &OppositeBool, action_type_change_i32); + uint64 i = 0; + while (i < Size) { + *(Address_Write + i) = 0; + i++; + } } -void History_Action_Change_V2(memory *Memory, v2 *DataAddress, v2 *OriginalData, v2 *NewData) +void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size) { - History_Action_Change(Memory, (void *)&DataAddress->x, (void *)&OriginalData->x, (void *)&NewData->x, action_type_change_r32); - History_Action_Change(Memory, (void *)&DataAddress->y, (void *)&OriginalData->y, (void *)&NewData->y, action_type_change_r32); + uint8 *Buffer_Scratch = (uint8 *)Memory_PushScratch(Memory, Size); + Arbitrary_WriteInto(Address_0, Buffer_Scratch, Size); + Arbitrary_WriteInto(Address_1, Address_0, Size); + Arbitrary_WriteInto(Buffer_Scratch, Address_1, Size); + Memory_PopScratch(Memory, Size); } -void History_Action_Change_Increment(memory *Memory, void *Data, action_type ActionChange) + +static void +Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction) { - switch (ActionChange) - { - case action_type_change_u16: - { - uint16 DataPlusOne = (*(uint16 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_i16: - { - int16 DataPlusOne = (*(int16 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_u32: - { - uint32 DataPlusOne = (*(uint32 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_i32: - { - int32 DataPlusOne = (*(int32 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_r32: - { - real32 DataPlusOne = (*(real32 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_u64: - { - uint64 DataPlusOne = (*(uint64 *)Data) + 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - default: - { - Assert(0); + if (Direction > 0) { + uint8 *AddressPlayhead = Address_End; + while ((ptrsize)AddressPlayhead >= (ptrsize)Address_Start) { + *(AddressPlayhead + ShiftAmount) = *AddressPlayhead; + AddressPlayhead--; + } + } else { + uint8 *AddressPlayhead = Address_Start; + while ((ptrsize)AddressPlayhead < (ptrsize)Address_End) { + *(AddressPlayhead - ShiftAmount) = *AddressPlayhead; + AddressPlayhead++; } } } -void History_Action_Change_Decrement(memory *Memory, void *Data, action_type ActionChange) +struct history_info { + uint16 ActionCount_Total; + uint16 ActionCount_EndOfPlayhead; + uint16 ActionCount_Current; + + uint64 ActionOffset_Total; + uint64 ActionOffset_EndOfPlayhead; + uint64 ActionOffset_Current; + + uint64 EntrySize_Current; +}; + +static uint64 +History_GetActionSize(history_entry_list *History, int i, uint16 ActionCount_EndOfPlayhead) +{ + history_action *Action = &History->Action[i]; + if (Action->Type == action_type_swap) + return Action->Size; + return 0; +} + +// Returns information on the undo tree based on three points of data: the +// total amount of entries, the location of the playhead, and whatever location +// SampleIndex is set to, which should be either one minus playhead or the playhead. + +// I wrote this with the intent of precomputing things like the tree's total +// size and the size of the current action, because calculating them in the +// Action_Redo/Undo calls got extremely confusing. + +static history_info +History_GetTreeInfo(history_entry_list *History, uint16 SampleIndex) { - switch (ActionChange) + history_info Info = {}; + + for (int i = 0; i < History->NumberOfEntries; i++) { - case action_type_change_u16: - { - uint16 DataPlusOne = (*(uint16 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_i16: - { - int16 DataPlusOne = (*(int16 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_u32: - { - uint32 DataPlusOne = (*(uint32 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_i32: - { - int32 DataPlusOne = (*(int32 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_r32: - { - real32 DataPlusOne = (*(real32 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - case action_type_change_u64: - { - uint64 DataPlusOne = (*(uint64 *)Data) - 1; - History_Action_Change(Memory, Data, Data, &DataPlusOne, ActionChange); - } break; - default: - { - Assert(0); - } + history_entry *Entry = &History->Entry[i]; + Info.ActionCount_Total += Entry->NumberOfActions; + if (i < History->EntryPlayhead) + Info.ActionCount_EndOfPlayhead += Entry->NumberOfActions; + if (i < SampleIndex) + Info.ActionCount_Current += Entry->NumberOfActions; } -} -static void -Arbitrary_ShiftData(action_shift_data ShiftData) { - int16 StopAt = ShiftData.Index; - if (ShiftData.Direction > 0) { - int16 i = ShiftData.NumberOf - 1; - while (i >= StopAt) { - uint8 *CurrentData = (uint8 *)ShiftData.StartingAddress + (ShiftData.Size * i); - uint8 *NextData = (uint8 *)ShiftData.StartingAddress + (ShiftData.Size * (i + ShiftData.Direction)); - uint32 Bytes = 0; - while (Bytes < ShiftData.Size) { - *NextData++ = *CurrentData++; - Bytes++; - } - i--; - } - } else { - int16 i = StopAt; - while (i <= ShiftData.NumberOf - 1) { - uint8 *CurrentData = (uint8 *)ShiftData.StartingAddress + (ShiftData.Size * i); - uint8 *NextData = (uint8 *)ShiftData.StartingAddress + (ShiftData.Size * (i - ShiftData.Direction)); - uint32 Bytes = 0; - while (Bytes < ShiftData.Size) { - *CurrentData++ = *NextData++; - Bytes++; - } - i++; - } + for (int i = 0; i < Info.ActionCount_Total; i++) + { + uint64 Size = History_GetActionSize(History, i, Info.ActionCount_EndOfPlayhead); + Info.ActionOffset_Total += Size; + if (i < Info.ActionCount_EndOfPlayhead) + Info.ActionOffset_EndOfPlayhead += Size; + + if (i < Info.ActionCount_Current) + Info.ActionOffset_Current += Size; + else if (i < Info.ActionCount_EndOfPlayhead) // Only increment the current size if i is between + Info.EntrySize_Current += Size; // the current count and playhead count! } + + return Info; } -void History_Action_Shift_2(memory *Memory, void *StartingAddress, uint32 Size, uint16 NumberOf, int16 Direction, int16 Index) +void History_Action_Undo(memory *Memory, history_info Info, history_action *ActionPointer, uint64 Action_Offset) { - Memory->Action.Entry[Memory->Action.Index].NumberOfActions++; - void *Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = action_type_shift; - action_shift_data *ShiftData = (action_shift_data *)Memory_Advance(Memory, sizeof(action_shift_data), P_UndoBuffer); - ShiftData->StartingAddress = StartingAddress; - ShiftData->Size = Size; - ShiftData->NumberOf = NumberOf; - ShiftData->Index = Index; - ShiftData->Direction = Direction; - Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = action_type_shift; - Arbitrary_ShiftData(*ShiftData); + history_entry_list *History = &Memory->History; + + // Only swap_bitmap should touch the data! + history_action Action = *ActionPointer; + + uint8 *Address_HistoryTree_Start = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, Action_Offset); + uint8 *Address_HistoryTree_End = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, Info.ActionOffset_Total); + uint8 *Address_Data = (uint8 *)Memory_AddressAtOffset(Memory, Action.TableName, Action.ByteOffset); + + if (Action.Type == action_type_swap) { + Arbitrary_SwapData(Memory, Address_HistoryTree_Start, Address_Data, Action.Size); + } else if (Action.Type == action_type_shift) { + // In order to shift back we have to start the address at where the + // shifted chunk is _now_, not when we called the function. + uint64 NewByteOffset = (Action.Direction > 0) ? Action.ByteOffset + Action.ShiftAmount : Action.ByteOffset - Action.ShiftAmount; + void *Address_Start = Memory_AddressAtOffset(Memory, Action.TableName, NewByteOffset); + uint8 *Address_End = (uint8 *)Address_Start + Action.Size; + // Direction also needs to be reversed. + int16 Direction = Action.Direction * -1; + Arbitrary_ShiftData((uint8 *)Address_Start, Address_End, Action.ShiftAmount, Direction); + } else { + Assert(0); + } } -void History_Action_Shift(memory *Memory, action_type ActionChange, void *DataAddress, int16 Direction, int16 Index) -{ - Memory->Action.Entry[Memory->Action.Index].NumberOfActions++; - void *Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = ActionChange; - switch (ActionChange) - { - case action_type_shift_keyframe: - { - void *DataPropertyAddress = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)DataPropertyAddress = (ptrsize)DataAddress; - void *DataDirection = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(ptrsize *)DataDirection = (ptrsize)Direction; - void *DataIndex = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(ptrsize *)DataIndex = (ptrsize)Index; - } break; - case action_type_shift_bezier: - { - void *DataPropertyAddress = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)DataPropertyAddress = (ptrsize)DataAddress; - void *DataDirection = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(ptrsize *)DataDirection = (ptrsize)Direction; - void *DataIndex = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(ptrsize *)DataIndex = (ptrsize)Index; - } break; - default: - { - Assert(0); - } break; +void History_Action_Redo(memory *Memory, history_info Info, history_action *ActionPointer, uint64 Action_Offset) { + + history_entry_list *History = &Memory->History; + + history_action Action = *ActionPointer; + + uint8 *Address_HistoryTree_Start = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, Action_Offset); + uint8 *Address_HistoryTree_End = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, Info.ActionOffset_Total); + uint8 *Address_Data = (uint8 *)Memory_AddressAtOffset(Memory, Action.TableName, Action.ByteOffset); + + if (Action.Type == action_type_swap) { + Arbitrary_SwapData(Memory, Address_HistoryTree_Start, Address_Data, Action.Size); + } else if (Action.Type == action_type_shift) { + void *Address_Start = Memory_AddressAtOffset(Memory, Action.TableName, Action.ByteOffset); + uint8 *Address_End = (uint8 *)Address_Start + Action.Size; + int16 Direction = Action.Direction; + Arbitrary_ShiftData((uint8 *)Address_Start, Address_End, Action.ShiftAmount, Direction); + } else { + Assert(0); } - Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = ActionChange; } -// Overwrite area with arbitrary-sized memory. Only use if the previous data -// doesn't need to be recorded, like pushing to the end of a stack. -void History_Action_StoreData(memory *Memory, void *DataAddress, uint64 ByteSize) -{ - Memory->Action.Entry[Memory->Action.Index].NumberOfActions++; - void *Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = action_type_storedata; - Data = Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - *(uint64 *)Data = ByteSize; - Data = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)Data = (ptrsize)DataAddress; - uint64 i = 0; - while (i < ByteSize) { - void *DataIndex = Memory_Advance(Memory, 1, P_UndoBuffer); - *(uint8 *)DataIndex = *((uint8 *)DataAddress + i++); +void History_Undo(memory *Memory) { + history_entry_list *History = &Memory->History; + if (History->EntryPlayhead == 0) return; + + // We want Current to represent the beginning of the current entry, so we + // subtract one from the playhead. + history_info Info = History_GetTreeInfo(History, History->EntryPlayhead - 1); + history_entry *Entry = &History->Entry[History->EntryPlayhead - 1]; + + // This puts us at the end of the current entry's offset. + uint64 ActionOffset_Stepback = Info.ActionOffset_Current + Info.EntrySize_Current; + + for (int i = Entry->NumberOfActions - 1; i >= 0; i--) { + history_action *Action = &History->Action[Info.ActionCount_Current + i]; + + // We step backwards only if the action is currently storing data. + if (Action->Type != action_type_shift) + ActionOffset_Stepback -= Action->Size; + + History_Action_Undo(Memory, Info, Action, ActionOffset_Stepback); } - Data = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)Data = (ptrsize)DataAddress; - Data = Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - *(uint64 *)Data = ByteSize; - Data = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - *(action_type *)Data = action_type_storedata; + + History->EntryPlayhead--; + } -// This is only called when we're certain the action is going to be taken. -void History_Entry_Commit(memory *Memory, action_entry_type Type, char *Name) -{ - // We need to at least clear NumberOfActions in case this index is being reused. - Memory->Action.Entry[Memory->Action.Index] = {}; - Memory->Action.Entry[Memory->Action.Index].Name = Name; - Memory->Action.Entry[Memory->Action.Index].Type = Type; - // Effectively deletes entries in front if we're beginning out of an undo. - // It wouldn't be all that much more difficult to support branched undoing - // now that I think about it... (would anyone use it though?) - if (Memory->Action.Index != Memory->Action.NumberOfEntries) { - Memory->Action.NumberOfEntries = Memory->Action.Index; +void History_Redo(memory *Memory) { + history_entry_list *History = &Memory->History; + if (History->EntryPlayhead == History->NumberOfEntries) return; + + // NOTE(fox): The third part of this function for recording the "current" + // action's size is only necessary for the undo call, so it's not correct on the redo. + history_info Info = History_GetTreeInfo(History, History->EntryPlayhead); + history_entry *Entry = &History->Entry[History->EntryPlayhead]; + + History->EntryPlayhead++; + + uint64 ActionOffset_Stepforward = Info.ActionOffset_Current; + + for (int i = 0; i < Entry->NumberOfActions; i++) { + history_action *Action = &History->Action[Info.ActionCount_Current + i]; + + History_Action_Redo(Memory, Info, Action, ActionOffset_Stepforward); + + // We step forwards only if the action is currently storing data. + if (Action->Type != action_type_shift) + ActionOffset_Stepforward += Action->Size; + } + } -void History_Entry_SetPointer(memory *Memory, void *Data) +// This is only called when we're certain the action is going to be taken. +void History_Entry_Commit(memory *Memory, char *Name) { - Memory->Action.Entry[Memory->Action.Index].ExtraPointer = Data; + history_entry_list *History = &Memory->History; + history_entry *Entry = &History->Entry[History->EntryPlayhead]; + Entry->Name = Name; + Entry->NumberOfActions = 0; + // Effectively deletes entries in front if we're beginning out of an undo. + if (History->NumberOfEntries != History->EntryPlayhead) + History->NumberOfEntries = History->EntryPlayhead; + History->NumberOfEntries++; + History->EntryPlayhead++; + Memory->IsFileSaved = false; +#if DEBUG + Assert(Debug.UndoState != 1); + Debug.UndoState = 1; +#endif } void History_Entry_End(memory *Memory) { - Memory->Action.Index++; - Memory->Action.NumberOfEntries++; + history_entry_list *History = &Memory->History; +#if DEBUG + Debug.UndoState = 0; +#endif } -// The pointer is unwinded. -void History_Action_Undo(memory *Memory) { - void *LastPos = Memory_Rewind(Memory, sizeof(action_type), P_UndoBuffer); - action_type *ActionType = (action_type *)LastPos; +// NOTE(fox): Shift is the only action that additionally changes the data after +// the info is put on the tree, since it's always the same function used. - switch (*ActionType) +static void History_Action_Add(memory *Memory, history_action ActionData, void *ReferenceData = NULL) +{ + history_entry_list *History = &Memory->History; + history_entry *Entry = &History->Entry[History->EntryPlayhead - 1]; + + history_info Info = History_GetTreeInfo(History, History->EntryPlayhead - 1); + + history_action *Action = &History->Action[Info.ActionCount_Total]; + *Action = ActionData; + + if (Action->Type == action_type_swap) { - case action_type_change_u16: - { - uint16 *Difference = (uint16 *)Memory_Rewind(Memory, sizeof(uint16), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(uint16 *)*Address -= *Difference; - } break; - case action_type_change_i16: - { - int16 *Difference = (int16 *)Memory_Rewind(Memory, sizeof(int16), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(int16 *)*Address -= *Difference; - } break; - case action_type_change_u32: - { - uint32 *Difference = (uint32 *)Memory_Rewind(Memory, sizeof(uint32), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(uint32 *)*Address -= *Difference; - } break; - case action_type_change_i32: - { - int32 *Difference = (int32 *)Memory_Rewind(Memory, sizeof(int32), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(int32 *)*Address -= *Difference; - } break; - case action_type_change_r32: - { - real32 *Difference = (real32 *)Memory_Rewind(Memory, sizeof(real32), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(real32 *)*Address -= *Difference; - } break; - case action_type_change_u64: - { - uint64 *Difference = (uint64 *)Memory_Rewind(Memory, sizeof(uint64), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(uint64 *)*Address -= *Difference; - } break; - case action_type_change_ptr: - { - ptrsize *Difference = (ptrsize *)Memory_Rewind(Memory, sizeof(ptrsize), P_UndoBuffer); - void **Address = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - *(ptrsize *)*Address -= *Difference; - } break; - case action_type_change_string: - { - Assert(0); - } break; - case action_type_shift_keyframe: - { - void *DataIndex = Memory_Rewind(Memory, sizeof(int16), P_UndoBuffer); - void *DataDirection = Memory_Rewind(Memory, sizeof(int16), P_UndoBuffer); - void **DataPropertyAddress = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - Keyframe_ShiftPointers((property_channel *)*DataPropertyAddress, *(int16 *)DataDirection * -1, *(int16 *)DataIndex); - } break; - case action_type_shift_bezier: - { - void *DataIndex = Memory_Rewind(Memory, sizeof(int16), P_UndoBuffer); - void *DataDirection = Memory_Rewind(Memory, sizeof(int16), P_UndoBuffer); - void **DataPropertyAddress = (void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - Mask_ShiftPointers((mask *)*DataPropertyAddress, *(int16 *)DataDirection * -1, *(int16 *)DataIndex); - } break; - case action_type_shift: - { - action_shift_data ShiftData = *(action_shift_data *)Memory_Rewind(Memory, sizeof(action_shift_data), P_UndoBuffer); - ShiftData.Direction *= -1; - Arbitrary_ShiftData(ShiftData); - } break; - case action_type_storedata: - { - uint64 *ByteSize = (uint64 *)Memory_Rewind(Memory, sizeof(uint64), P_UndoBuffer); - void *DataAddress = *(void **)Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - void *DataStart = Memory_Rewind(Memory, *ByteSize, P_UndoBuffer); - uint64 i = 0; - while (i < *ByteSize) { - void *DataIndex = Memory_GetAddressAt(Memory, i, P_UndoBuffer); - *((uint8 *)DataAddress + i++) = *(uint8 *)DataIndex; - } - DataStart = Memory_Rewind(Memory, sizeof(void *), P_UndoBuffer); - DataStart = Memory_Rewind(Memory, sizeof(uint64), P_UndoBuffer); - } break; - default: - { - Assert(0); - } break; + void *Address_HistoryTree = Memory_AddressAtOffset(Memory, P_UndoBuffer, Info.ActionOffset_Total); + void *Address_Data = Memory_AddressAtOffset(Memory, Action->TableName, Action->ByteOffset); + Arbitrary_WriteInto((uint8 *)Address_Data, (uint8 *)Address_HistoryTree, Action->Size); + } else if (Action->Type == action_type_shift) + { + void *Address_Start = Memory_AddressAtOffset(Memory, Action->TableName, Action->ByteOffset); + uint8 *Address_End = (uint8 *)Address_Start + Action->Size; + Arbitrary_ShiftData((uint8 *)Address_Start, Address_End, Action->ShiftAmount, Action->Direction); } - void *EndPos = Memory_Rewind(Memory, sizeof(action_type), P_UndoBuffer); + + Entry->NumberOfActions++; } -// The pointer is rewinded. -void History_Action_Redo(memory *Memory) { - void *LastPos = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); - action_type *ActionType = (action_type *)LastPos; +// Helper functions for different tables. - switch (*ActionType) - { - case action_type_change_u16: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - uint16 *Difference = (uint16 *)Memory_Advance(Memory, sizeof(uint16), P_UndoBuffer); - *(uint16 *)*Address += *Difference; - } break; - case action_type_change_i16: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - int16 *Difference = (int16 *)Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - *(int16 *)*Address += *Difference; - } break; - case action_type_change_u32: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - uint32 *Difference = (uint32 *)Memory_Advance(Memory, sizeof(uint32), P_UndoBuffer); - *(uint32 *)*Address += *Difference; - } break; - case action_type_change_i32: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - int32 *Difference = (int32 *)Memory_Advance(Memory, sizeof(int32), P_UndoBuffer); - *(int32 *)*Address += *Difference; - } break; - case action_type_change_r32: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - real32 *Difference = (real32 *)Memory_Advance(Memory, sizeof(real32), P_UndoBuffer); - *(real32 *)*Address += *Difference; - } break; - case action_type_change_u64: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - uint64 *Difference = (uint64 *)Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - *(uint64 *)*Address += *Difference; - } break; - case action_type_change_ptr: - { - void **Address = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - ptrsize *Difference = (ptrsize *)Memory_Advance(Memory, sizeof(ptrsize), P_UndoBuffer); - *(ptrsize *)*Address += *Difference; - } break; - case action_type_change_string: - { - Assert(0); - } break; - case action_type_shift_keyframe: - { - void **DataPropertyAddress = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - void *DataDirection = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - void *DataIndex = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - Keyframe_ShiftPointers((property_channel *)*DataPropertyAddress, *(int16 *)DataDirection, *(int16 *)DataIndex); - } break; - case action_type_shift_bezier: - { - void **DataPropertyAddress = (void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - void *DataDirection = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - void *DataIndex = Memory_Advance(Memory, sizeof(int16), P_UndoBuffer); - Mask_ShiftPointers((mask *)*DataPropertyAddress, *(int16 *)DataDirection, *(int16 *)DataIndex); - } break; - case action_type_shift: - { - action_shift_data ShiftData = *(action_shift_data *)Memory_Advance(Memory, sizeof(action_shift_data), P_UndoBuffer); - Arbitrary_ShiftData(ShiftData); - } break; - case action_type_storedata: - { - // NOTE(fox): Right now I'm only using this to overwrite data, so all we need to do is advance. - uint64 *ByteSize = (uint64 *)Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - void *DataAddress = *(void **)Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - void *DataEnd = Memory_Advance(Memory, *ByteSize, P_UndoBuffer); - DataEnd = Memory_Advance(Memory, sizeof(void *), P_UndoBuffer); - DataEnd = Memory_Advance(Memory, sizeof(uint64), P_UndoBuffer); - } break; - default: - { - Assert(0); - } break; - } - void *EndPos = Memory_Advance(Memory, sizeof(action_type), P_UndoBuffer); + +static void History_Action_Shift(memory *Memory, memory_table_list TableName, + void *Address0, void *Address1, uint64 Amount, int16 Direction) +{ + void *Address_Start = Memory->Slot[TableName].Address; + uint64 ByteOffset = (ptrsize)Address0 - (ptrsize)Address_Start; + uint64 Size = (ptrsize)Address1 - (ptrsize)Address0; + + history_action Action = { TableName, action_type_shift, Size, ByteOffset, Amount, Direction }; + + History_Action_Add(Memory, Action); } -void History_Undo(memory *Memory) { - if (Memory->Action.Index != 0) { - 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++) - History_Action_Undo(Memory); - } +static void History_Action_Block_Swap(memory *Memory, memory_table_list TableName, void *Address_Data) +{ + void *Address_Start = Memory->Slot[TableName].Address; + uint64 Size = Memory->Slot[TableName].Block_ElementSize; + uint64 ByteOffset = (ptrsize)Address_Data - (ptrsize)Address_Start; + history_action Action = { TableName, action_type_swap, Size, ByteOffset, 0 }; + History_Action_Add(Memory, Action); } -void History_Redo(memory *Memory) { - if (Memory->Action.Index != Memory->Action.NumberOfEntries) { - 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++) - History_Action_Redo(Memory); - Memory->Action.Index++; - } +// Remember to dereference pointers if taking the sizeof() a variable, or else Size will be 8! + +static void History_Action_Swap(memory *Memory, memory_table_list TableName, uint64 Size, void *Address_Data) +{ + void *Address_Start = Memory->Slot[TableName].Address; + uint64 ByteOffset = (ptrsize)Address_Data - (ptrsize)Address_Start; + history_action Action = { TableName, action_type_swap, Size, ByteOffset, 0 }; + History_Action_Add(Memory, Action); } |