#include #include #if WINDOWS #include #else #include #include #endif #if ARM #include #include #else #include #endif #include "imgui/imgui.h" #include "imgui/backends/imgui_impl_sdl.h" #include "imgui/backends/imgui_impl_opengl3.h" #include #if defined(IMGUI_IMPL_OPENGL_ES2) #include #else #include #endif #define STB_IMAGE_IMPLEMENTATION #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "lib/stb_image_write.h" // TODO(fox): Used for thumbnails. The renderer could be expanded to do this // much more efficiently. #define STB_IMAGE_RESIZE_IMPLEMENTATION #include "lib/stb_image_resize.h" extern "C" { #include "lib/miniz.h" #include "lib/miniz.c" } #include "defines.h" #include "my_math.h" #include "structs.h" #if STABLE #include "stable_diffusion.h" #endif #include "memory.h" #include "main.h" #include "debug.h" #include "functions.h" // #include "sharebuffer.h" SDL_Thread *Thread[8]; SDL_sem *Semaphore; SDL_atomic_t CurrentEntry; SDL_atomic_t QueuedEntries; SDL_atomic_t CompletedEntries; render_entry Entries[256]; static uint64 BitmapBlockSize; static instruction_mode InstructionMode = instruction_mode_scalar; static uint32 RandomGlobalIncrement = 0; #if STABLE #include "lib/base64.c" #include #endif #include "memory.cpp" #include "undo.cpp" #include "io.cpp" #include "strings.cpp" #include "threading.cpp" #include "createcalls.cpp" #if STABLE #include "stable_diffusion.cpp" #endif // #include "ffmpeg_backend.cpp" #include "my_imgui_widgets.cpp" #include "prenderer.cpp" #include "gl_calls.cpp" #include "bezier.cpp" #include "effects_gl_shader.cpp" #include "effects.cpp" #include "effects_constructors.cpp" static void Main_RenderUI(ImGuiIO io, ImVec4 clear_color, SDL_Window *window) { ImGui::Render(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); SDL_GL_SwapWindow(window); } static void Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, SDL_Window *window, GLuint textureID) { ImGuiIO& io = ImGui::GetIO(); SDL_Event event = {}; while (SDL_PollEvent(&event)) { ImGui_ImplSDL2_ProcessEvent(&event); if (event.type == SDL_DROPFILE) { char *DropFile = event.drop.file; Source_Generate(File, State, Memory, DropFile); SDL_free(DropFile); } if (event.type == SDL_QUIT) State->IsRunning = false; if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) State->IsRunning = false; } if (State->Warp_WantSetPos) { ImGui::GetIO().WantSetMousePos = true; io.MousePos = State->Warp_PositionToSet; } ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); if (State->Warp_WantSetPos) { ImGui_WarpMouseFinish(State, io.MousePos); io.MouseDelta = {}; State->Warp_WantSetPos = false; } if (!io.WantCaptureKeyboard) ImGui_ProcessInputs(File, State, UI, Memory, io); sorted_file Sorted = File_Sort_Push(File, State, Memory); // These depend on sorting, so they can't be done in the ProcessInputs function: if (State->HotkeyInput) { switch (State->HotkeyInput) { case hotkey_none: { Assert(0); } break; case hotkey_transform: { Interact_Transform_Begin(File, Memory, State, io.MousePos, Sorted.CompArray, Sorted.LayerArray); } break; case hotkey_copy: { Clipboard_Store(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray); } break; case hotkey_paste: { Clipboard_Paste(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray); } break; } State->HotkeyInput = hotkey_none; } ImGui::DockSpaceOverViewport(); #if DEBUG if (Debug.ToggleWindow) { ImGui::ShowDemoWindow(); ImGui_DebugMemoryViewer(Memory, State); ImGui_DebugUndoTree(Memory, State); } #endif // if (State->FocusedWindow == focus_viewport && State->SetFocus) { // ImGui::SetNextWindowFocus(); // State->SetFocus = false; // } ImGui_Viewport(File, State, UI, Memory, io, textureID, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray); // if (State->FocusedWindow == focus_timeline && State->SetFocus) { // ImGui::SetNextWindowFocus(); // State->SetFocus = false; // } ImGui_Timeline(File, State, Memory, UI, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray); ImGui_File(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray); ImGui_PropertiesPanel(File, State, UI, Memory, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray); ImGui_ColorPanel(File, State, UI, Memory, io); ImGui_EffectsPanel(File, State, Memory, UI, io); #if STABLE if (UI->StableEnabled) { ImGui_SD_Prompt(File, State, UI, Memory, io, Sorted.CompArray, Sorted.LayerArray); ImGui_SD_Thumbnail(File, State, UI, Memory, io, Sorted.CompArray, Sorted.LayerArray, Sorted.SourceArray, Sorted.TempSourceCount); } #endif ImGui_Menu(File, State, UI, Memory, io); ImGui_Popups(File, State, UI, Memory, io); // NOTE(fox): If popup disappears unexpectedly it means something else took its focus! File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize); #if DEBUG Debug.Temp = {}; #endif ImGui::EndFrame(); } static void Render_Main(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion) { bool32 IsRendering = true; Renderer_Start(Data, OutputBuffer, RenderType, RenderRegion); while (IsRendering) { // Main_InputTest(File, State, &Memory, &UI); Renderer_Check(&IsRendering, RenderType); } } static void Layer_UpdateAllKeyframes(project_data *File, project_state *State, memory *Memory, block_layer *Layer, uint16 Index_Physical, sorted_property_info *SortedProperty, uint16 *SortedKeyframe, uint16 Frame_Current) { int32 Offset = (State->Interact_Active == interact_type_keyframe_move) ? (int32)State->Interact_Offset[0] : 0; int h = 0, c = 0, p = 0; property_channel *Property = NULL; while (Layer_LoopChannels(State, Memory, &SortedProperty, &SortedKeyframe, Layer, &Property, NULL, &h, &c, &p)) { Assert(Property); if (Property->Block_Bezier_Count) { real32 MinY, MaxY; Property_MinMax_Y(Memory, State, Property, SortedProperty, &MinY, &MaxY); real32 Y_Increment = 1 / (MaxY - MinY); v2 FirstPointPos[3]; bezier_point *FirstPointAddress = Bezier_LookupAddress(Memory, Property, SortedKeyframe[0]); Bezier_EvaluateValue(State, FirstPointAddress, FirstPointPos); v2 LastPointPos[3]; bezier_point *LastPointAddress = Bezier_LookupAddress(Memory, Property, SortedKeyframe[Property->Keyframe_Count - 1]); Bezier_EvaluateValue(State, LastPointAddress, LastPointPos); if (FirstPointPos[0].x >= Frame_Current) { Property->CurrentValue = FirstPointPos[0].y; } else if (LastPointPos[0].x <= Frame_Current) { Property->CurrentValue = LastPointPos[0].y; } else { int KeyframeIndex = 0; for (;;) { v2 PointPos[3]; bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, SortedKeyframe[KeyframeIndex + 1]); Bezier_EvaluateValue(State, PointAddress, PointPos, 1, Y_Increment); if (PointPos[0].x >= Frame_Current) break; KeyframeIndex++; } v2 PointPos[3]; bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, SortedKeyframe[KeyframeIndex]); Bezier_EvaluateValue(State, PointAddress, PointPos, 1, Y_Increment); v2 NextPointPos[3]; bezier_point *NextPointAddress = Bezier_LookupAddress(Memory, Property, SortedKeyframe[KeyframeIndex + 1]); Bezier_EvaluateValue(State, NextPointAddress, NextPointPos, 1, Y_Increment); if (PointAddress->Type == interpolation_type_hold) { Property->CurrentValue = PointPos[0].y; } else if (PointAddress->Type == interpolation_type_linear && NextPointAddress->Type == interpolation_type_linear) { real32 Ratio = (Frame_Current - PointPos[0].x) / (NextPointPos[0].x - PointPos[0].x); Property->CurrentValue = PointPos[0].y + ((NextPointPos[0].y - PointPos[0].y) * Ratio); } else { Property->CurrentValue = Bezier_SolveYForX(PointPos[0], PointPos[0] + PointPos[2], NextPointPos[0] + NextPointPos[1], NextPointPos[0], Frame_Current); } } } } } static void * Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray, uint32 CompIndex, int32 Frame_Current) { block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, Frame_Current); void *CompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex); uint64 Size = Comp->Width * Comp->Height * Comp->BytesPerPixel; Arbitrary_Zero((uint8 *)CompBuffer, Size); // if (Entry_Main->IsCached) // return CompBuffer; uint64 Comp_TimeStart = GetCPUTime(); sorted_comp_info *SortedCompInfo = &SortedCompArray[CompIndex]; sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex); for (int i = 0; i < SortedCompInfo->LayerCount; i++) { sorted_layer SortEntry = SortedLayerInfo[i]; uint32 Index_Physical = SortEntry.Block_Layer_Index; block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); if (Layer->Frame_Start <= Frame_Current && Layer->Frame_End > Frame_Current && Layer->IsVisible) { if (State->UpdateKeyframes) { sorted_property_info *SortedLayerProperties = SortedPropertyInfo + SortedLayerInfo->SortedPropertyStart; uint16 *SortedLayerKeyframes = SortedPropertyArray + SortedLayerInfo->SortedKeyframeStart; Layer_UpdateAllKeyframes(File, State, Memory, Layer, Index_Physical, SortedLayerProperties, SortedLayerKeyframes, Frame_Current); } layer_bitmap_state *BitmapState = &State->Render.Bitmap[Index_Physical]; void *BitmapAddress = NULL; void *RenderAddress = NULL; // result of masking, effects, and intermediate paint stroke int Width = 0, Height = 0, BytesPerPixel = 0; if (!Layer->IsPrecomp) { block_source *Source = NULL; if ((State->PreviewSource != -1) && Layer->IsSelected) { Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, State->PreviewSource); } else { Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); } if (Source->Type == source_type_principal || Source->Type == source_type_principal_temp) { BitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index, 0); } else { cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0); if (!Entry->IsCached) { uint64 Src_TimeStart = GetCPUTime(); block_string *Name = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index); int w = 0, h = 0; void *temp = stbi_load(Name->Char, &w, &h, NULL, 4); Source->Width = w; Source->Height = h; Source->BytesPerPixel = 4; uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel; void *Source_Address = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); Memory_Copy((uint8 *)Source_Address, (uint8 *)temp, Size); stbi_image_free(temp); BitmapState->ToUpdate = false; BitmapState->CurrentFrame = 0; Entry->CycleTime = GetCPUTime() - Src_TimeStart; Layer->x.CurrentValue = Comp->Width/2; Layer->y.CurrentValue = Comp->Height/2; Entry->IsCached = true; } BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); } Width = Source->Width; Height = Source->Height; BytesPerPixel = Source->BytesPerPixel; } else { block_composition *Precomp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index); BitmapAddress = Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, SortedPropertyInfo, SortedPropertyArray, Layer->Block_Source_Index, (int32)Layer->time.CurrentValue); Width = Precomp->Width; Height = Precomp->Height; BytesPerPixel = Precomp->BytesPerPixel; } Assert(BitmapAddress); uint64 ScratchSize = Width * Height * BytesPerPixel; RenderAddress = Memory_PushScratch(Memory, ScratchSize); Memory_Copy((uint8 *)RenderAddress, (uint8 *)BitmapAddress, ScratchSize); if (State->Interact_Active == interact_type_brush && State->Brush.LayerToPaint_Index == Index_Physical) { // TODO(fox): Do all these extra precomputes really make a difference in the renderer? rectangle RenderRegion = { 0, 0, Width, Height }; direct_info Info = { (real32)Width, (real32)Height, (real32)BytesPerPixel, (real32)Width * BytesPerPixel, Bitmap_ByteInfo(BytesPerPixel), blend_normal, RenderRegion, State->Brush.TransientBitmap}; Render_Main((void *)&Info, RenderAddress, render_type_notransform, State->Brush.CacheBounds); } else if (Layer->Block_Effect_Count || Layer->Block_Mask_Count) { Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Width, Height, BytesPerPixel); } Assert(Width); Assert(Height); transform_info T = Transform_Calculate(State, Memory, File, Layer, Comp, Width, Height, BytesPerPixel); T.SourceBuffer = RenderAddress; rectangle RenderRegion = {0, 0, Comp->Width, Comp->Height}; Render_Main((void *)&T, CompBuffer, render_type_main, RenderRegion); Memory_PopScratch(Memory, ScratchSize); } } Entry_Main->CycleTime = GetCPUTime() - Comp_TimeStart; Entry_Main->IsCached = true; return CompBuffer; } static void Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Window *window, GLuint textureID, ImGuiIO io) { block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); sorted_file Sorted = File_Sort_Push(File, State, Memory); void *MainCompBuffer = Render_Comp(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray, File->PrincipalCompIndex, State->Frame_Current); File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize); glBindTexture(GL_TEXTURE_2D, textureID); int ByteFlag2 = (MainComp->BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; if (State->FirstFrame) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MainComp->Width, MainComp->Height, 0, GL_RGBA, ByteFlag2, MainCompBuffer); State->FirstFrame = false; } glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MainComp->Width, MainComp->Height, GL_RGBA, ByteFlag2, MainCompBuffer); // TODO(fox): garbage collect AV state! State->UpdateFrame = false; State->UpdateKeyframes = false; } int main(int argc, char *argv[]) { global_memory GlobalMemory = {}; GlobalMemory.Size = ((uint64)1 * 1024 * 1024 * 1024); GlobalMemory.CurrentPosition = 0; #if WINDOWS GlobalMemory.Address = VirtualAlloc(0, GlobalMemory.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #else GlobalMemory.Address = mmap(0, GlobalMemory.Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #endif // 1 meg per block BitmapBlockSize = 1024 * 1024; memory Memory = {}; 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, 40 * 1024 * 1024, P_MiscCache, "Misc persistent"); Memory_InitTable(&GlobalMemory, &Memory, sizeof(project_data), F_File, "File", sizeof(project_data)); Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, F_Precomps, "Precomps", sizeof(block_composition)); Memory_InitTable(&GlobalMemory, &Memory, 2 * 1024 * 1024, F_Layers, "Layers", sizeof(block_layer)); Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, F_Sources, "Sources", sizeof(block_source)); Memory_InitTable(&GlobalMemory, &Memory, 2 * 1024 * 1024, F_Effects, "Properties", sizeof(block_effect)); Memory_InitTable(&GlobalMemory, &Memory, 2 * 1024 * 1024, F_Properties, "Properties", sizeof(property_channel)); Memory_InitTable(&GlobalMemory, &Memory, 4 * 1024 * 1024, F_Bezier, "Bezier paths (keyframes, masks)", sizeof(block_bezier)); Memory_InitTable(&GlobalMemory, &Memory, 4 * 1024 * 1024, F_Strings, "Strings", sizeof(block_string)); Memory_InitTable(&GlobalMemory, &Memory, (uint64)100 * 1024 * 1024, F_PrincipalBitmaps, "Principal bitmap data", BitmapBlockSize); Memory_InitTable(&GlobalMemory, &Memory, (uint64)5 * 1024 * 1024, B_Thumbnails, "Thumbnails"); 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 InstructionMode = instruction_mode_neon; #else // if (SDL_HasSSE2()) { // InstructionMode = instruction_mode_sse; // } if (SDL_HasAVX2()) { InstructionMode = instruction_mode_avx; } #endif project_state State_ = {}; project_state *State = &State_; project_data *File = (project_data *)Memory_Block_AllocateAddress(&Memory, F_File); *File = {}; File->Occupied = 1; // NOTE(fox): Right now I'm just gonna throw all dynamic allocs that can't // be simplified to the push/pop model here; will worry about how to best // use RAM later. State->Brush.PaintBuffer = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); uint64 ScratchPaintSize = 2048*2048*4; Memory.ScratchPos += ScratchPaintSize; State->Brush.TransientBitmap = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); ScratchPaintSize = 2048*2048*4; Memory.ScratchPos += ScratchPaintSize; State->Dump1 = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); Memory.ScratchPos += ScratchPaintSize; State->Dump2 = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); State->ClipboardBuffer = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); State->ClipboardSize = 1024*1024; Memory.ScratchPos += State->ClipboardSize; State->Test = ImDrawListSplitter(); block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps); MainComp->Width = 1280; MainComp->Height = 720; MainComp->FPS = 24; MainComp->BytesPerPixel = 4; MainComp->Frame_Count = 48; MainComp->Frame_End = 48; MainComp->Occupied = 1; MainComp->Name_String_Index = String_AddToFile(&Memory, "Main comp"); File->Comp_Count = 1; #if 0 { uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/a_small.jpg"); block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, File->Source_Count - 1); Source->IsSelected = true; } #endif SDL_Init(SDL_INIT_VIDEO); Semaphore = SDL_CreateSemaphore(0); int Index[7]; for (int i = 0; i < 7; i++) { Index[i] = i; Thread[i] = SDL_CreateThread(TestThread, "thread", (void *)&Index[i]); } // Decide GL+GLSL versions SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 const char* glsl_version = "#version 100"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(__APPLE__) // GL 3.2 Core + GLSL 150 const char* glsl_version = "#version 150"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); #else // GL 3.0 + GLSL 130 const char* glsl_version = "#version 130"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); // SDL_RenderSetScale(renderer, 2, 2) #if DEBUG #if ARM uint32 ScreenSize[2] = {(uint32)(2560/1.2), (uint32)(1600/1.2)}; #else real32 ScreenSize[2] = {3840/1.2, 2160/1.2}; #endif #else real32 ScreenSize[2]; SDL_DisplayMode current; int windowtest = SDL_GetCurrentDisplayMode(0, ¤t); if (windowtest == 0) { ScreenSize[0] = current.w; ScreenSize[1] = current.h; } else { ScreenSize[0] = 1920; ScreenSize[1] = 1080; } #endif SDL_Window* window = SDL_CreateWindow("Event Tester", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenSize[0], ScreenSize[1], window_flags); SDL_GLContext gl_context = SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { printf("Failed to initialize GLAD"); return -1; } GL_InitDefaultShader(); GL_InitDefaultVerts(); Effect_InitEntries(State); SDL_GL_MakeCurrent(window, gl_context); SDL_Event Event; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableSetMousePos; (void)io; // NOTE(fox): Instead of constructing the position of the windows on // startup with Docking API calls (which is experimental and incomplete) // I'm loading the window positions from this convenient tool. ImGui by // default saves window position to an external .ini file, which can be // loaded from disk or memory. io.IniFilename = NULL; ImGui::LoadIniSettingsFromMemory(ImGuiPrefs); // // ImGui::SaveIniSettingsToDisk("imgui.ini"); ImGui::StyleColorsDark(); ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.1f))); ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); Brush_CalcBitmapAlphaFromSize(&Memory, &State->Brush, 4); State_BindBrushTexture(&Memory, &State->Brush, 4); #if STABLE curl_global_init(CURL_GLOBAL_ALL); curl_state MainHandle = {}; curl_state ProgHandle = {}; #endif #if DEBUG sprintf(State->DummyName, "test2"); File_Open(File, State, &Memory, State->DummyName); State->UpdateFrame = true; State->MostRecentlySelectedLayer = 0; #endif while (State->IsRunning) { // State->Interact_Active = interact_type_layer_move; // State->Interact_Offset[1] = -3.0f; #if STABLE if (State->CurlActive) { Curl_Main(File, State, &Memory, &MainHandle, &ProgHandle); } #endif Main_InputTest(File, State, &Memory, &File->UI, window, textureID); if (State->IsPlaying) { block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(&Memory, F_Precomps, File->PrincipalCompIndex); Playhead_Increment(&State->Frame_Current, MainComp->Frame_Start, MainComp->Frame_End, 1); State->UpdateFrame = true; State->UpdateKeyframes = true; } if (State->UpdateFrame) { Main_Renderer(File, State, &Memory, window, textureID, io); } Assert(Debug.ScratchState == 0); #if DEBUG if (Debug.ReloadUI) { Main_RenderUI(io, clear_color, window); } #else Main_RenderUI(io, clear_color, window); #endif if (State->Initializing) State->Initializing--; } for (int i = 0; i < 7; i++) { SDL_DetachThread(Thread[i]); } ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); SDL_Quit(); return 0; }