#include #include #if WINDOWS #else #include #endif #if ARM #include #else #include #endif #include "imgui/imgui.h" #include "imgui/backends/imgui_impl_sdl.h" #include "imgui/backends/imgui_impl_opengl3.h" #if WINDOWS #include #else #include #endif #if defined(IMGUI_IMPL_OPENGL_ES2) #include #else #include #endif #define STB_IMAGE_IMPLEMENTATION #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" #if 0 #include #else #define IACA_START #define IACA_END #endif #include "defines.h" #include "my_math.h" #include "main.h" #include "debug.h" #include "functions.h" // #include "sharebuffer.h" SDL_atomic_t CurrentEntry; SDL_atomic_t QueuedEntries; SDL_atomic_t CompletedEntries; static bool32 IsRendering = false; static instruction_mode InstructionMode = instruction_mode_scalar; render_entry Entries[256]; SDL_Thread *thread[8]; SDL_sem *Semaphore; #include "memory.cpp" #include "effects.cpp" #include "keyframes.cpp" #include "layer.cpp" #include "strings.cpp" #if THREADED #include "threading.cpp" #else #endif #include "prenderer.cpp" #include "ffmpeg_backend.cpp" #include "bitmap_calls.cpp" #include "createcalls.cpp" #include "my_imgui_widgets.cpp" static void MainFunction(main_sdl *Main, memory *Memory, project_state *State, project_data *File, cache_pool *Cache, comp_buffer *CompBuffer) { Bitmap_Clear(CompBuffer->PackedBuffer, CompBuffer->Width, CompBuffer->Height, CompBuffer->BytesPerPixel); Bitmap_Clear(CompBuffer->UnpackedBuffer, CompBuffer->Width, CompBuffer->Height, CompBuffer->BytesPerPixel); for (int i = 0; i < File->NumberOfLayers; i++) { project_layer *Layer = File->Layer[i]; if (Layer->StartFrame <= File->CurrentFrame && Layer->EndFrame >= File->CurrentFrame) { if (State->UpdateKeyframes) { for (int p = 0; p < Layer->NumberOfEffects; p++) { for (int o = 0; o < Layer->Effect[p]->NumberOfProperties; o++) { CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Effect[p]->Property[o]); } } for (int r = 0; r < AmountOf(Layer->Property); r++) { CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Property[r]); } } Layer_UpdateBitmap(Layer, Memory, File->CurrentFrame); } } State->UpdateKeyframes = false; QueueCurrentFrame(File, CompBuffer, State); } #if 0 static void MainFunction(main_sdl *Main, project_debug *D, memory *Memory, sdl_input *Input, sdl_input *OldInput, project_state *State, brush_tool *Brush, project_data *File, cache_pool *Cache, pixel_buffer *CompBuffer) { ClearBuffer(CompBuffer); if (Cache->Frame[File->CurrentFrame].Cached) { FetchCache(&Cache->Frame[File->CurrentFrame], CompBuffer); } else { for (int i = 0; i < File->NumberOfLayers; i++) { if (File->Layer[i]->Raster.OriginalBuffer) { for (int p = 0; p < File->Layer[i]->NumberOfEffects; p++) { for (int o = 0; o < File->Layer[i]->Effect[p].NumberOfProperties; o++) { CalculateKeyframesLinearly(File->CurrentFrame, &File->Layer[i]->Effect[p].Property[o]); } } for (int r = 0; r < AmountOf(File->Layer[i]->Property); r++) { CalculateKeyframesLinearly(File->CurrentFrame, &File->Layer[i]->Property[r]); } if (File->Layer[i]->Raster.ToUpdate) { UpdateEffects(File->Layer[i], Memory); File->Layer[i]->Raster.ToUpdate = true; } } } if (State->DebugDisableCache) { RenderCurrentFrame(File, CompBuffer, State); } else { if (Cache->Interact == Clear) { Cache->Intermediate[0].Cached = 0; Cache->Intermediate[1].Cached = 0; Cache->Intermediate[2].Cached = 0; Cache->Interact = Inactive; } if (Cache->Interact == Active) { if (!Cache->Intermediate[0].Address) { Cache->Intermediate[0].Address = (uint64 *)Memory->Address + Memory->CurrentPosition; Memory->CurrentPosition += File->Width * File->Height * 4; Cache->Intermediate[1].Address = (uint64 *)Memory->Address + Memory->CurrentPosition; Memory->CurrentPosition += File->Width * File->Height * 4; Cache->Intermediate[2].Address = (uint64 *)Memory->Address + Memory->CurrentPosition; Memory->CurrentPosition += File->Width * File->Height * 4; } pixel_buffer TempBuffer = *CompBuffer; if (!Cache->Intermediate[0].Cached) { TempBuffer.OriginalBuffer = Cache->Intermediate[0].Address; ClearBuffer(&TempBuffer); for (int i = 0; i < Cache->InteractIndex; i++) { // RenderLayer(File->LayerPTR[i], &TempBuffer, State); // RenderCurrentFrame(File->LayerPTR[Cache->InteractIndex], &TempBuffer, State); } Cache->Intermediate[0].Cached = 1; } TempBuffer.OriginalBuffer = Cache->Intermediate[1].Address; ClearBuffer(&TempBuffer); // RenderLayer(File->LayerPTR[Cache->InteractIndex], &TempBuffer, State); // RenderCurrentFrame(File->LayerPTR[Cache->InteractIndex], &TempBuffer, State); if (!Cache->Intermediate[2].Cached) { TempBuffer.OriginalBuffer = Cache->Intermediate[2].Address; ClearBuffer(&TempBuffer); for (int i = Cache->InteractIndex + 1; i < File->NumberOfLayers; i++) { // RenderLayer(File->LayerPTR[i], &TempBuffer, State); // RenderCurrentFrame(File->LayerPTR[Cache->InteractIndex], &TempBuffer, State); } Cache->Intermediate[2].Cached = 1; } InteractToComp(CompBuffer, Cache); } else { for (int i = 0; i < File->NumberOfLayers; i++) { } } if (!Cache->Interact) { if (!Cache->Frame[File->CurrentFrame].Address) { Cache->Frame[File->CurrentFrame].Address = (uint64 *)Memory->Address + Memory->CurrentPosition; Memory->CurrentPosition += File->Width * File->Height * 4; } CacheFrame(&Cache->Frame[File->CurrentFrame], CompBuffer); Cache->Frame[File->CurrentFrame].Cached = true; } else { Cache->Frame[File->CurrentFrame].Cached = false; } } } } #endif static void DebugPrintMemoryUsage(memory Memory) { for (int i = 0; i < 8; i++) { memory_table Table = Memory.Slot[i]; printf("%s: %li bytes, %li kb\n", Table.Name, Table.CurrentPosition, Table.CurrentPosition / 1024); } } int main(int argc, char *argv[]) { global_memory GlobalMemory = {}; GlobalMemory.Size = ((uint64)4 * 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 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, 15 * 1024 * 1024, F_Layers, "Layers"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Effects, "Effects"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Keyframes, "Keyframe blocks"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings"); InitMemoryTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_LayerBitmaps, "Layer buffer"); InitMemoryTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_LoadedBitmaps, "Loaded bitmap buffer"); project_state State = {}; if (SDL_HasSSE2()) { InstructionMode = instruction_mode_sse; } if (SDL_HasAVX2()) { InstructionMode = instruction_mode_avx; } project_data File = {}; File.Width = 1280; File.Height = 720; File.NumberOfFrames = 65; File.FPS = 30; File.CurrentFrame = 1; File.StartFrame = 0; File.EndFrame = 65; #if DEBUG // 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 LoadTestFootage(&File, &State, &Memory); 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); cache_pool Cache = {}; Cache.Interact = Inactive; ui UI = {}; // 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); // void *asda = mmap(NULL, SHAREDMEMORY_SIZE, // PROT_READ | PROT_WRITE, // MAP_SHARED, fd, 0); // SharedMemoryInfo *shmp = (SharedMemoryInfo *)asda; // if (shmp == MAP_FAILED) // Assert(0); // if (sem_init(&shmp->sem1, 1, 0) == -1) // Assert(0); // if (sem_init(&shmp->sem2, 1, 0) == -1) // Assert(0); SDL_Init(SDL_INIT_VIDEO); Semaphore = SDL_CreateSemaphore(0); render_queue RenderInfo = {}; RenderInfo.File = &File; RenderInfo.State = &State; RenderInfo.CompBuffer = &CompBuffer; #if THREADED thread_info ThreadInfo[7]; for (int i = 0; i < 7; i++) { char str[256]; ThreadInfo[i].Index = i; ThreadInfo[i].RenderInfo = &RenderInfo; thread[i] = SDL_CreateThread(TestThread, str, &ThreadInfo[i]); } #endif sdl_input Input; sdl_input OldInput; // Decide GL+GLSL versions #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); #if DEBUG // uint32 ScreenSize[2] = {2560/1.2, 1600/1.2}; real32 ScreenSize[2] = {3840/1.2, 2160/1.2}; #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_CENTERED, SDL_WINDOWPOS_CENTERED, 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 SDL_Event Event; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable; (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::StyleColorsDark(); 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_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); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); while (State.IsRunning) { SDL_Event event; while (SDL_PollEvent(&event)) { ImGui_ImplSDL2_ProcessEvent(&event); if (event.type == SDL_DROPFILE) { printf("%s", event.drop.file); // AddSource(File, Memory, event.drop.file); } 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; } ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); if (!io.WantCaptureKeyboard) ImGui_ProcessInputs(&File, &State, &CompBuffer, &Memory, &UI, io); ImGui::DockSpaceOverViewport(); ImGui_Viewport(File, &State, &UI, CompBuffer, io, textureID); ImGui_File(&File, &State, &Memory, &UI, io); ImGui_EffectsPanel(&File, &State, &Memory, &UI, io); ImGui_PropertiesPanel(&File, &State, &UI, &Memory); ImGui_Timeline(&File, &State, &Memory, &UI, io); #if DEBUG if (Debug.ToggleWindow) { ImGui::ShowDemoWindow(); ImGui_DebugMemoryViewer(&File, &Memory); } #endif if (UI.TemporaryUpdateOverride) { UI.TemporaryUpdateOverride = 0; State.UpdateFrame = 1; } if (UI.Initializing) UI.Initializing--; // if (File.CurrentFrame != shmp->shared_framenumber) { // File.CurrentFrame = shmp->shared_framenumber; // } // 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. if (State.UpdateFrame && !IsRendering) { MainFunction(0, &Memory, &State, &File, &Cache, &CompBuffer); State.UpdateFrame = 0; } #if THREADED uint32 C = SDL_AtomicGet(&CompletedEntries); if (IsRendering) { while (C != 16) { C = SDL_AtomicGet(&CompletedEntries); CheckQueue(RenderInfo, 8); } C = SDL_AtomicGet(&CompletedEntries); if (C == 16) { Bitmap_ConvertPacking(CompBuffer.PackedBuffer, CompBuffer.UnpackedBuffer, CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel, 1); EndRenderState(&State); glBindTexture(GL_TEXTURE_2D, textureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CompBuffer.Width, CompBuffer.Height, GL_RGBA, GL_UNSIGNED_BYTE, CompBuffer.UnpackedBuffer); // shmp->shared_framenumber = File.CurrentFrame; // if (sem_post(&shmp->sem2) == -1) // Assert(0); } } #else OutputToViewport(&CompBuffer, &State, textureID); #endif 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); } for (int i = 0; i < 7; i++) { SDL_DetachThread(thread[i]); } // shm_unlink("/testl"); ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); SDL_Quit(); return 0; }