#include #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" #include #if defined(IMGUI_IMPL_OPENGL_ES2) #include #else #include #endif #define STB_IMAGE_IMPLEMENTATION #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" extern "C" { #include #include #include #include #include } #if 0 #include #else #define IACA_START #define IACA_END #endif #define internal static #define local_persist static #define global_variable static #define SwitchBool(Bool) if((Bool)) {(Bool) = 0;} else {(Bool) = 1;} #define AmountOf(Array) sizeof((Array)) / sizeof((Array)[1]) typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64; typedef int32 bool32; typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64; typedef float real32; typedef double real64; #define NORMALIZED_COL_MIN { .col = V4(0.0f, 0.0f, 0.0f, 0.0f) } #define NORMALIZED_COL_MAX { .col = V4(1.0f, 1.0f, 1.0f, 1.0f) } #define NORMALIZED_REAL_MIN { 0.0f } #define NORMALIZED_REAL_MAX { 1.0f } // All of these MIN/MAX values are arbitrarily chosen; they can probably be // increased if the user requires it. #define PROPERTY_REAL_MAX 1000000 #define PROPERTY_REAL_MIN -1000000 #define MAX_LAYERS 2048 #define MAX_EFFECTS 32 #define MAX_SOURCES 1024 #define MAX_PROPERTIES_PER_EFFECT 16 #define MAX_KEYFRAME_BLOCKS 64 #define MAX_KEYFRAMES_PER_BLOCK 32 #define STRING_SIZE 256 #define MAX_SELECTED_PROPERTIES 16 #include "my_math.h" #include "main.h" #include "debug.h" global_variable uint32 volatile CompletedJobs; global_variable uint32 volatile NextEntryToDo; global_variable uint32 volatile EntryCount; global_variable bool32 IsRendering = false; global_variable bool32 AVXEnabled = true; render_entry Entries[256]; SDL_Thread *thread[8]; SDL_sem *Semaphore; #include "memory.cpp" #include "effects.cpp" #include "keyframes.cpp" #include "layer.cpp" #include "threading.cpp" #include "prenderer.cpp" #include "video.cpp" #include "createcalls.cpp" #include "my_imgui_widgets.cpp" // #include "sharebuffer.h" internal void MainFunction(main_sdl *Main, memory *Memory, project_state *State, project_data *File, cache_pool *Cache, pixel_buffer *CompBuffer) { SSE_ClearBuffer(CompBuffer); for (int i = 0; i < File->NumberOfLayers; i++) { project_layer *Layer = File->Layer[i]; if (Layer->RenderInfo) { // Keyframe updating 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]); } } // Video updating if (Layer->SourceType == source_video) { // && Layer->VideoCurrentFrame != File->CurrentFrame - Layer->VideoFrameOffset) { video_source *Source = (video_source *)Layer->RenderInfo; LoadVideoFrame(Source, Memory, File->CurrentFrame); // TODO(fox): Make above check work! UpdateEffects(Layer, Memory); Source->Raster.ToUpdate = true; } // Effect updating if (Layer->SourceType == source_image) { image_source *Source = (image_source *)Layer->RenderInfo; if (Source->Raster.ToUpdate) { UpdateEffects(Layer, Memory); Source->Raster.ToUpdate = false; } } } } State->UpdateKeyframes = false; QueueCurrentFrame(File, CompBuffer, State); } #if 0 internal 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 internal 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)2 * 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 = {}; InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UIState, "UI state"); // TODO(fox): Make clean-up functions when these get deleted! InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_SourceData, "Image/video headers"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_ProjectSettings, "Project settings"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 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, 1024 * 1024 * 1024, B_Scratch, "Scratch buffer"); if (!SDL_HasAVX2()) { AVXEnabled = false; printf("CPU does not have AVX2!"); return -1; } project_state State = {}; project_data File = {}; File.Width = 1280; File.Height = 720; File.NumberOfFrames = 65; File.FPS = 30; File.CurrentFrame = 1; File.StartFrame = 0; File.EndFrame = 65; // char String[1024]; // uint16 Size = 1024; // getcwd(String, Size); // printf("dir: %s", String); pixel_buffer CompBuffer = CreateBuffer(File.Width, File.Height, &Memory); cache_pool Cache = {}; Cache.Interact = Inactive; ui UI = {}; // File.NumberOfSources = 2; // File.Source[0] = (char *)AllocateMemory(&Memory, STRING_SIZE, F_Strings); // File.Source[1] = (char *)AllocateMemory(&Memory, STRING_SIZE, F_Strings); // sprintf(File.Source[0], "../asset/b.jpg"); // sprintf(File.Source[1], "../asset/24.mp4"); // CreateLayerFromSource(&File, &State, &Memory, File.Source[0]); // CreateLayerFromSource(&File, &State, &Memory, File.Source[1]); #if 1 // 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); // CreateLayer(&File, &Memory); // CreateRenderInfo(File.Layer[1], &Memory, File, video, "./asset/24.mp4"); // File.Layer[1]->Name = "yuyu"; // File.Layer[1]->StartFrame = 0; // File.Layer[1]->EndFrame = 65; #else CreateDebugLayer(&File, &Memory, 12, 8); File.Layer[0]->Name = "debug"; File.Layer[0]->StartFrame = 0; File.Layer[0]->EndFrame = 65; #endif // CreateLayer(&File, &Memory); // CreateRenderInfo(File.Layer[0], &Memory, File, image, "./asset/r.jpg"); // File.Layer[0]->Name = "Robot"; // File.Layer[0]->x.CurrentValue.f = 200; // File.Layer[0]->y.CurrentValue.f = 250; // File.Layer[0]->scale.CurrentValue.f = 1.1; // File.Layer[0]->opacity.CurrentValue.f = 1.0; // File.Layer[0]->StartFrame = 0; // File.Layer[0]->EndFrame = 65; // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 2, 100); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 60, 500); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 3, 300); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 8, 800); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 5, 500); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 6, 600); // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, 7, 700); // File.Layer[0]->x.KeyframeBlock[0]->Keyframe[2].IsSelected = true; // File.Layer[0]->x.KeyframeBlock[0]->Keyframe[3].IsSelected = true; // File.Layer[0]->x.KeyframeBlock[0]->Keyframe[4].IsSelected = true; // File.Layer[0]->x.KeyframeBlock[0]->Keyframe[6].IsSelected = true; // DeleteSelectedKeyframes(&File, &Memory); // for (int16 i = 0; i < 10; i++) { // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, i*6 + 3, i*100); // } // int16 kef = 2; // for (int16 i = 0; i < kef; i++) { // int16 p = kef - i; // ManualKeyframeInsertF(&File.Layer[0]->x, &Memory, p*4, p*100); // } // &File.Layer[1]->x.KeyframeBlock[0]->Keyframe[2]; // KeyframeDelete(&File.Layer[1]->x, &Memory, 2); // AddEffect(File.Layer[0], &Memory, 0); // AddEffect(File.Layer[0], &Memory, 0); for (int i = 0; i < 3; i++) // CreateLayer(&File, &Memory); // DebugPrintMemoryUsage(Memory); SDL_Init(SDL_INIT_VIDEO); Semaphore = SDL_CreateSemaphore(0); render_queue RenderInfo = {}; RenderInfo.File = &File; RenderInfo.State = &State; RenderInfo.CompBuffer = &CompBuffer; 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]); } 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); // uint32 ScreenSize[2] = {2560/1.2, 1600/1.2}; // real32 ScreenSize[2] = {3840/1.2, 2160/1.2}; 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; } 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, 1146); 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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 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.OriginalBuffer); 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_PropertiesPanel(&File, &State, &UI, &Memory); ImGui_Timeline(&File, &State, &Memory, &UI, io); #if DEBUG if (Debug.ToggleWindow) ImGui::ShowDemoWindow(); #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; // } if (State.UpdateFrame && !IsRendering) { MainFunction(0, &Memory, &State, &File, &Cache, &CompBuffer); State.UpdateFrame = 0; } if (IsRendering) { while (CompletedJobs != 16) { CheckQueue(RenderInfo, 8); } if (CompletedJobs == 16) { #if PACKEDRGB Unpack4x4Chunk(&CompBuffer); // SSE_CopyToBuffer(CompBuffer); #else PackBitmapRGB(&CompBuffer); #endif EndRenderState(&State); glBindTexture(GL_TEXTURE_2D, textureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CompBuffer.Width, CompBuffer.Height, GL_RGBA, GL_UNSIGNED_BYTE, CompBuffer.EffectBuffer); // shmp->shared_framenumber = File.CurrentFrame; // if (sem_post(&shmp->sem2) == -1) // Assert(0); } } 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; }