From 7f0a8278d756333ff05c32dd73a5238fd0daca4e Mon Sep 17 00:00:00 2001 From: Yggdrasil75 Date: Thu, 20 Nov 2025 14:45:30 -0500 Subject: [PATCH] better, still not great. will fix later. --- tests/g2chromatic2.cpp | 112 +++++++++++++++++++++++++++-------------- util/grid/grid2.hpp | 95 ++++++++++++++++++++++++++++++++-- 2 files changed, 167 insertions(+), 40 deletions(-) diff --git a/tests/g2chromatic2.cpp b/tests/g2chromatic2.cpp index 5cfa16c..4f5564f 100644 --- a/tests/g2chromatic2.cpp +++ b/tests/g2chromatic2.cpp @@ -20,6 +20,7 @@ #include #include #include +#include std::mutex m; std::atomic isGenerating{false}; @@ -28,7 +29,15 @@ std::future generationFuture; std::mutex previewMutex; std::atomic updatePreview{false}; frame currentPreviewFrame; -GLuint previewTexture = 0; +GLuint textu = 0; +std::string previewText; + +struct Shared { + std::mutex mutex; + Grid2 grid; + bool hasNewFrame = false; + int currentFrame = 0; +}; struct AnimationConfig { int width = 1024; @@ -69,21 +78,22 @@ void Preview(Grid2& grid) { } } -void livePreview(Grid2& grid) { - currentPreviewFrame = grid.getGridAsFrame(frame::colormap::RGB); - int image_width = currentPreviewFrame.getWidth(); - int image_height = currentPreviewFrame.getHeight(); - std::vector framedata = currentPreviewFrame.getData(); +void livePreview(const Grid2& grid) { + std::lock_guard lock(previewMutex); + + currentPreviewFrame = grid.getGridAsFrame(frame::colormap::RGBA); - GLuint textu; glGenTextures(1, &textu); glBindTexture(GL_TEXTURE_2D, textu); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image_width, image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, framedata.data()); - previewTexture = textu; + glBindTexture(GL_TEXTURE_2D, textu); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, currentPreviewFrame.getWidth(), currentPreviewFrame.getHeight(), + 0, GL_RGBA, GL_UNSIGNED_BYTE, currentPreviewFrame.getData().data()); + + updatePreview = true; } std::vector> pickSeeds(Grid2 grid, AnimationConfig config) { @@ -210,10 +220,16 @@ bool exportavi(std::vector frames, AnimationConfig config) { return success; } -void mainLogic(const AnimationConfig& config, Grid2& grid) { +void mainLogic(const AnimationConfig& config, Shared& state) { isGenerating = true; try { - grid = setup(config); + Grid2 grid = setup(config); + { + std:: lock_guard lock(state.mutex); + state.grid = grid; + state.hasNewFrame = true; + state.currentFrame = 0; + } Preview(grid); std::vector> seeds = pickSeeds(grid, config); std::vector frames; @@ -227,16 +243,21 @@ void mainLogic(const AnimationConfig& config, Grid2& grid) { expandPixel(grid,config,seeds); + std::lock_guard lock(state.mutex); + state.grid = grid; + state.hasNewFrame = true; + state.currentFrame = i; + // 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(); frames.push_back(bgrframe); //bgrframe.decompress(); //BMPWriter::saveBMP(std::format("output/grayscalesource.{}.bmp", i), bgrframe); bgrframe.compressFrameLZ78(); + bgrframe.printCompressionStats(); } } exportavi(frames,config); @@ -305,7 +326,7 @@ int main() { //ImGui::SetNextWindowSize(ImVec2(1110,667)); //auto beg = ImGui::Begin("Gradient thing", &window); //if (beg) { - std::cout << "stuff breaks at 223" << std::endl; + // 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); @@ -315,7 +336,7 @@ int main() { 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; + // std::cout << "context created" << std::endl; ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls ImGui::StyleColorsDark(); @@ -331,7 +352,7 @@ int main() { ImGui_ImplOpenGL3_Init(glsl_version); - std::cout << "created glfw window" << std::endl; + // std::cout << "created glfw window" << std::endl; // Our state @@ -345,8 +366,10 @@ int main() { static int i4 = 8; std::future mainlogicthread; + Shared state; Grid2 grid; AnimationConfig config; + previewText = "Please generate"; while (!glfwWindowShouldClose(window)) { glfwPollEvents(); @@ -370,7 +393,7 @@ int main() { if (ImGui::Button("Generate Animation")) { config = AnimationConfig(i1, i2, i3, f, i4); - mainlogicthread = std::async(std::launch::async, mainLogic, config, std::ref(grid)); + mainlogicthread = std::async(std::launch::async, mainLogic, config, std::ref(state)); } if (isGenerating) { @@ -381,58 +404,73 @@ int main() { cancelGeneration(); } - ImGui::Text("Generating..."); - } - //ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); // is this broken or is it just cause I have no refresh buffer in this loop? - - ImGui::Text("livepreview"); - if (isGenerating) { - livePreview(grid); - ImVec2 availableSize = ImGui::GetContentRegionAvail(); + // Check for new frames from the generation thread + bool hasNewFrame = false; + { + std::lock_guard lock(state.mutex); + if (state.hasNewFrame) { + livePreview(state.grid); + state.hasNewFrame = false; + previewText = "Generating... Frame: " + std::to_string(state.currentFrame); + } + } - float aspectRatio = static_cast(currentPreviewFrame.getWidth()) / - static_cast(currentPreviewFrame.getHeight()); - - ImVec2 imageSize = ImVec2(config.height,config.width); - ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left - ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right - auto ptex = const_cast(static_cast(currentPreviewFrame.getData().data())); - ImGui::ImageWithBg((ImTextureRef)ptex, imageSize, uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Text(previewText.c_str()); + if (textu != 0) { + ImVec2 imageSize = ImVec2(config.width * 0.3f, config.height * 0.3f); // Scale down for preview + ImVec2 uv_min = ImVec2(0.0f, 0.0f); + ImVec2 uv_max = ImVec2(1.0f, 1.0f); + ImGui::Image((void*)(intptr_t)textu, imageSize, uv_min, uv_max); + } else { + ImGui::Text("Generating preview..."); + } } else { ImGui::Text("No preview available"); ImGui::Text("Start generation to see live preview"); } - + //std::cout << "sleeping" << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + //std::cout << "ending" << std::endl; ImGui::End(); } - + + // std::cout << "ending frame" << std::endl; 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); + + // std::cout << "rendering" << std::endl; ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); //mainlogicthread.join(); + + // std::cout << "swapping buffers" << std::endl; } cancelGeneration(); + + // std::cout << "shutting down" << std::endl; ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); + // std::cout << "destroying" << std::endl; glfwDestroyWindow(window); - if (previewTexture != 0) { - glDeleteTextures(1, &previewTexture); - previewTexture = 0; + if (textu != 0) { + glDeleteTextures(1, &textu); + textu = 0; } glfwTerminate(); FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED); + + // std::cout << "printing" << std::endl; return 0; } //I need this: https://raais.github.io/ImStudio/ diff --git a/util/grid/grid2.hpp b/util/grid/grid2.hpp index 6d49a83..de8750b 100644 --- a/util/grid/grid2.hpp +++ b/util/grid/grid2.hpp @@ -67,7 +67,7 @@ public: return Positions.bucket_count(); } - bool empty() { + bool empty() const { return Positions.empty(); } @@ -194,7 +194,9 @@ protected: //TODO: spatial map SpatialGrid spatialGrid; float spatialCellSize = 2.0f; + public: + bool usable = false; //get position from id Vec2 getPositionID(size_t id) const { Vec2 it = Positions.at(id); @@ -459,6 +461,7 @@ public: shrinkIfNeeded(); updateNeighborMap(); + usable = true; return getAllIDs(); } @@ -620,6 +623,78 @@ public: } } + + + void getGridRegionAsRGBA(const Vec2& minCorner, const Vec2& maxCorner, + int& width, int& height, std::vector& rgbData) const { + TIME_FUNCTION; + // std::cout << "excessdebug g2.483" << std::endl; + // Calculate dimensions + width = static_cast(maxCorner.x - minCorner.x); + height = static_cast(maxCorner.y - minCorner.y); + + if (width <= 0 || height <= 0) { + width = height = 0; + rgbData.clear(); + rgbData.shrink_to_fit(); + return; + } + // std::cout << "excessdebug g2.494" << std::endl; + + // Initialize RGB data (3 bytes per pixel: R, G, B) + std::vector rgbaBuffer(width * height, Vec4(0.0f, 0.0f, 0.0f, 0.0f)); + + // For each position in the grid, find the corresponding pixel + for (const auto& [id, pos] : Positions) { + // std::cout << "excessdebug g2.501." << id << std::endl; + size_t size = Sizes.at(id); + + // Calculate pixel coordinates + int pixelXm = static_cast(pos.x - size/2 - minCorner.x); + int pixelXM = static_cast(pos.x + size/2 - minCorner.x); + int pixelYm = static_cast(pos.y - size/2 - minCorner.y); + int pixelYM = static_cast(pos.y + size/2 - minCorner.y); + + pixelXm = std::max(0, pixelXm); + pixelXM = std::min(width - 1, pixelXM); + pixelYm = std::max(0, pixelYm); + pixelYM = std::min(height - 1, pixelYM); + // std::cout << "excessdebug g2.514." << id << std::endl; + + // Ensure within bounds + if (pixelXM >= minCorner.x && pixelXm < width && pixelYM >= minCorner.y && pixelYm < height) { + // std::cout << "excessdebug g2.518." << id << " - (" << pixelXm << "," << pixelYM << ")" << std::endl; + const Vec4& color = Colors.at(id); + float srcAlpha = color.a; + float invSrcAlpha = 1.0f - srcAlpha; + for (int py = pixelYm; py <= pixelYM; ++py){ + for (int px = pixelXm; px <= pixelXM; ++px){ + // std::cout << "excessdebug g2.524." << id << " - (" << py << "," << px << ")" << std::endl; + int index = (py * width + px); + Vec4 dest = rgbaBuffer[index]; + + dest.r = color.r * srcAlpha + dest.r; // * invSrcAlpha; + dest.g = color.g * srcAlpha + dest.g; // * invSrcAlpha; + dest.b = color.b * srcAlpha + dest.b; // * invSrcAlpha; + dest.a = srcAlpha + dest.a; // * invSrcAlpha; + rgbaBuffer[index] = dest; + } + } + } + } + rgbData.resize(rgbaBuffer.size() * 4); + for (int i = 0; i < rgbaBuffer.size(); ++i) { + const Vec4& color = rgbaBuffer[i]; + int bgrIndex = i * 4; + + // Convert from [0,1] to [0,255] and store as RGB + rgbData[bgrIndex + 0] = static_cast(color.r * 255); + rgbData[bgrIndex + 1] = static_cast(color.g * 255); + rgbData[bgrIndex + 2] = static_cast(color.b * 255); + rgbData[bgrIndex + 2] = static_cast(color.a * 255); + + } + } //get full as rgb/bgr void getGridAsRGB(int& width, int& height, std::vector& rgbData) { @@ -645,6 +720,17 @@ public: resultFrame.setData(rgbData); return resultFrame; } + + frame getGridRegionAsFrameRGBA(const Vec2& minCorner, const Vec2& maxCorner) const { + TIME_FUNCTION; + int width, height; + std::vector rgbData; + getGridRegionAsRGBA(minCorner, maxCorner, width, height, rgbData); + + frame resultFrame(width, height, frame::colormap::RGB); + resultFrame.setData(rgbData); + return resultFrame; + } // Get region as frame (BGR format) frame getGridRegionAsFrameBGR(const Vec2& minCorner, const Vec2& maxCorner) const { @@ -659,7 +745,7 @@ public: } // Get entire grid as frame with specified format - frame getGridAsFrame(frame::colormap format = frame::colormap::RGB) { + frame getGridAsFrame(frame::colormap format = frame::colormap::RGB) const { TIME_FUNCTION; Vec2 minCorner, maxCorner; getBoundingBox(minCorner, maxCorner); @@ -669,6 +755,9 @@ public: case frame::colormap::RGB: Frame = std::move(getGridRegionAsFrameRGB(minCorner, maxCorner)); break; + case frame::colormap::RGBA: + Frame = std::move(getGridRegionAsFrameRGBA(minCorner, maxCorner)); + break; case frame::colormap::BGR: Frame = std::move(getGridRegionAsFrameBGR(minCorner, maxCorner)); break; @@ -708,7 +797,7 @@ public: } //get bounding box - void getBoundingBox(Vec2& minCorner, Vec2& maxCorner) { + void getBoundingBox(Vec2& minCorner, Vec2& maxCorner) const { TIME_FUNCTION; if (Positions.empty()) { minCorner = Vec2(0, 0);