#include #include #include #include #include #include #include #include "../util/grid/grid2.hpp" #include "../util/output/aviwriter.hpp" #include "../util/output/bmpwriter.hpp" #include "../util/timing_decorator.cpp" #include "../imgui/imgui.h" #include "../imgui/backends/imgui_impl_glfw.h" #include "../imgui/backends/imgui_impl_opengl3.h" #include struct AnimationConfig { int width = 1024; int height = 1024; int totalFrames = 480; float fps = 30.0f; int numSeeds = 8; }; Grid2 setup(AnimationConfig config) { TIME_FUNCTION; Grid2 grid; std::vector pos; std::vector colors; std::vector sizes; for (int y = 0; y < config.height; ++y) { for (int x = 0; x < config.width; ++x) { float gradient = (x + y) / float(config.width + config.height - 2); pos.push_back(Vec2(x,y)); colors.push_back(Vec4(gradient, gradient, gradient, 1.0f)); sizes.push_back(1.0f); } } grid.bulkAddObjects(pos,colors,sizes); return grid; } void Preview(Grid2 grid) { TIME_FUNCTION; int width; int height; //std::vector rgbData; frame rgbData = grid.getGridAsFrame(frame::colormap::RGB); bool success = BMPWriter::saveBMP("output/grayscalesource.bmp", rgbData); if (!success) { std::cout << "yo! this failed in Preview" << std::endl; } } std::vector> pickSeeds(Grid2 grid, AnimationConfig config) { TIME_FUNCTION; std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> xDist(0, config.width - 1); std::uniform_int_distribution<> yDist(0, config.height - 1); std::uniform_real_distribution<> colorDist(0.2f, 0.8f); std::vector> seeds; for (int i = 0; i < config.numSeeds; ++i) { Vec2 point(xDist(gen), yDist(gen)); Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 255); size_t id = grid.getPositionVec(point); grid.setColor(id, color); seeds.push_back(std::make_tuple(id,point, color)); } return seeds; } void expandPixel(Grid2& grid, AnimationConfig config, std::vector>& seeds) { TIME_FUNCTION; std::vector> newseeds; std::unordered_set visitedThisFrame; for (const auto& seed : seeds) { visitedThisFrame.insert(std::get<0>(seed)); } //#pragma omp parallel for for (const std::tuple& seed : seeds) { size_t id = std::get<0>(seed); Vec2 seedPOS = std::get<1>(seed); Vec4 seedColor = std::get<2>(seed); std::vector neighbors = grid.getNeighbors(id); //grid.setSize(id, grid.getSize(id)+4); for (size_t neighbor : neighbors) { if (visitedThisFrame.count(neighbor)) { continue; } visitedThisFrame.insert(neighbor); Vec2 neipos = grid.getPositionID(neighbor); Vec4 neighborColor = grid.getColor(neighbor); float distance = seedPOS.distance(neipos); float angle = seedPOS.directionTo(neipos); float normalizedAngle = (angle + M_PI) / (2.0f * M_PI); float blendFactor = 0.3f + 0.4f * std::sin(normalizedAngle * 2.0f * M_PI); blendFactor = std::clamp(blendFactor, 0.1f, 0.9f); Vec4 newcolor = Vec4( seedColor.r * blendFactor + neighborColor.r * (1.0f - blendFactor), seedColor.g * (1.0f - blendFactor) + neighborColor.g * blendFactor, seedColor.b * (0.5f + 0.5f * std::sin(normalizedAngle * 4.0f * M_PI)), 1.0f ); newcolor = newcolor.clamp(0.0f, 1.0f); grid.setColor(neighbor, newcolor); newseeds.emplace_back(neighbor, neipos, newcolor); } } seeds.clear(); seeds.shrink_to_fit(); seeds = std::move(newseeds); } //bool exportavi(std::vector> frames, AnimationConfig config) { bool exportavi(std::vector frames, AnimationConfig config) { TIME_FUNCTION; std::string filename = "output/chromatic_transformation.avi"; std::cout << "Frame count: " << frames.size() << std::endl; // Log compression statistics for all frames std::cout << "\n=== Frame Compression Statistics ===" << std::endl; size_t totalOriginalSize = 0; size_t totalCompressedSize = 0; for (int i = 0; i < frames.size(); ++i) { totalOriginalSize += frames[i].getSourceSize(); totalCompressedSize += frames[i].getTotalCompressedSize(); } double overallRatio = static_cast(totalOriginalSize) / totalCompressedSize; double overallSavings = (1.0 - 1.0/overallRatio) * 100.0; std::cout << "\n=== Overall Compression Summary ===" << std::endl; std::cout << "Total frames: " << frames.size() << std::endl; std::cout << "Compressed frames: " << frames.size() << std::endl; std::cout << "Total original size: " << totalOriginalSize << " bytes (" << std::fixed << std::setprecision(2) << (totalOriginalSize / (1024.0 * 1024.0)) << " MB)" << std::endl; std::cout << "Total compressed size: " << totalCompressedSize << " bytes (" << std::fixed << std::setprecision(2) << (totalCompressedSize / (1024.0 * 1024.0)) << " MB)" << std::endl; std::cout << "Overall compression ratio: " << std::fixed << std::setprecision(2) << overallRatio << ":1" << std::endl; std::cout << "Overall space savings: " << std::fixed << std::setprecision(1) << overallSavings << "%" << std::endl; std::filesystem::path dir = "output"; if (!std::filesystem::exists(dir)) { if (!std::filesystem::create_directories(dir)) { std::cout << "Failed to create output directory!" << std::endl; return false; } } bool success = AVIWriter::saveAVIFromCompressedFrames(filename, frames, frames[0].getWidth(), frames[0].getHeight(), config.fps); if (success) { // Check if file actually exists if (std::filesystem::exists(filename)) { auto file_size = std::filesystem::file_size(filename); std::cout << "\nAVI file created successfully: " << filename << " (" << file_size << " bytes, " << std::fixed << std::setprecision(2) << (file_size / (1024.0 * 1024.0)) << " MB)" << std::endl; } } else { std::cout << "Failed to save AVI file!" << std::endl; } return success; } void mainLogic(float f, int i1, int i2, int i3, int i4){ AnimationConfig config = AnimationConfig(i1, i2, i3, f, i4); // std::cout << "g2c2175" << std::endl; Grid2 grid = setup(config); // std::cout << "g2c2178" << std::endl; Preview(grid); std::vector> seeds = pickSeeds(grid,config); std::vector frames; for (int i = 0; i < config.totalFrames; ++i){ expandPixel(grid,config,seeds); // Print compression info for this frame if (i % 10 == 0 ) { frame bgrframe; std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl; bgrframe = grid.getGridAsFrame(frame::colormap::BGR); bgrframe.printCompressionStats(); //(bgrframe, i + 1); frames.push_back(bgrframe); //bgrframe.decompress(); //BMPWriter::saveBMP(std::format("output/grayscalesource.{}.bmp", i), bgrframe); bgrframe.compressFrameLZ78(); } } exportavi(frames,config); } static void glfw_error_callback(int error, const char* description) { fprintf(stderr, "GLFW Error %d: %s\n", error, description); } int main() { //static bool window = true; glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) { std::cerr << "gui stuff is dumb in c++." << std::endl; glfwTerminate(); return 1; } // COPIED VERBATIM FROM IMGUI. #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 (WebGL 1.0) const char* glsl_version = "#version 100"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(IMGUI_IMPL_OPENGL_ES3) // GL ES 3.0 + GLSL 300 es (WebGL 2.0) const char* glsl_version = "#version 300 es"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(__APPLE__) // GL 3.2 + GLSL 150 const char* glsl_version = "#version 150"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac #else // GL 3.0 + GLSL 130 const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only #endif //ImGui::SetNextWindowSize(ImVec2(1110,667)); //auto beg = ImGui::Begin("Gradient thing", &window); //if (beg) { std::cout << "stuff breaks at 223" << std::endl; bool application_not_closed = true; //float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); GLFWwindow* window = glfwCreateWindow((int)(1280), (int)(800), "Chromatic gradient generator thing", nullptr, nullptr); if (window == nullptr) return 1; glfwMakeContextCurrent(window); glfwSwapInterval(1); //IMGUI_CHECKVERSION(); //this might be more important than I realize. but cant run with it so currently ignoring. ImGui::CreateContext(); std::cout << "context created" << std::endl; ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls ImGui::StyleColorsDark(); ImGuiStyle& style = ImGui::GetStyle(); //style.ScaleAllSizes(1); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) //style.FontScaleDpi = 1; //will need to implement my own scaling at some point. currently just ignoring it. ImGui_ImplGlfw_InitForOpenGL(window, true); #ifdef __EMSCRIPTEN__ ImGui_ImplGlfw_InstallEmscriptenCallbacks(window, "#canvas"); #endif ImGui_ImplOpenGL3_Init(glsl_version); std::cout << "created glfw window" << std::endl; // Our state bool show_demo_window = true; bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); { static float f = 30.0f; static int i1 = 1024; static int i2 = 1024; static int i3 = 480; static int i4 = 8; ImGui::Begin("Gradient settings"); // Create a window called "Hello, world!" and append into it. //ImGui::Text(""); // Display some text (you can use a format strings too) //ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state //ImGui::Checkbox("Another Window", &show_another_window); ImGui::SliderFloat("fps", &f, 20.0f, 60.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::SliderInt("width", &i1, 256, 4096); ImGui::SliderInt("height", &i2, 256, 4096); ImGui::SliderInt("framecount", &i3, 10, 5000); ImGui::SliderInt("numSeeds", &i4, 0, 10); if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) mainLogic(f,i1,i2,i3,i4); ImGui::SameLine(); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); ImGui::End(); } ImGui::Render(); int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); //glViewport(0, 0, display_w, display_h); //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()); glfwSwapBuffers(window); } //ImGui::End(); FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED); return 0; } //I need this: https://raais.github.io/ImStudio/ // or this: https://github.com/tpecholt/imrad/ // g++ -std=c++23 -O3 -march=native -o ./bin/g2gradc ./tests/g2chromatic2.cpp -I./imgui -L./imgui -limgui -lstb `pkg-config --cflags --libs glfw3` && ./bin/g2gradc