better, still not great. will fix later.

This commit is contained in:
Yggdrasil75
2025-11-20 14:45:30 -05:00
parent 75daa0f501
commit 7f0a8278d7
2 changed files with 167 additions and 40 deletions

View File

@@ -20,6 +20,7 @@
#include <atomic> #include <atomic>
#include <future> #include <future>
#include <mutex> #include <mutex>
#include <chrono>
std::mutex m; std::mutex m;
std::atomic<bool> isGenerating{false}; std::atomic<bool> isGenerating{false};
@@ -28,7 +29,15 @@ std::future<void> generationFuture;
std::mutex previewMutex; std::mutex previewMutex;
std::atomic<bool> updatePreview{false}; std::atomic<bool> updatePreview{false};
frame currentPreviewFrame; 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 { struct AnimationConfig {
int width = 1024; int width = 1024;
@@ -69,21 +78,22 @@ void Preview(Grid2& grid) {
} }
} }
void livePreview(Grid2& grid) { void livePreview(const Grid2& grid) {
currentPreviewFrame = grid.getGridAsFrame(frame::colormap::RGB); std::lock_guard<std::mutex> lock(previewMutex);
int image_width = currentPreviewFrame.getWidth();
int image_height = currentPreviewFrame.getHeight(); currentPreviewFrame = grid.getGridAsFrame(frame::colormap::RGBA);
std::vector<uint8_t> framedata = currentPreviewFrame.getData();
GLuint textu;
glGenTextures(1, &textu); glGenTextures(1, &textu);
glBindTexture(GL_TEXTURE_2D, textu); glBindTexture(GL_TEXTURE_2D, textu);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 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_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 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<std::tuple<size_t, Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config) { std::vector<std::tuple<size_t, Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config) {
@@ -210,10 +220,16 @@ bool exportavi(std::vector<frame> frames, AnimationConfig config) {
return success; return success;
} }
void mainLogic(const AnimationConfig& config, Grid2& grid) { void mainLogic(const AnimationConfig& config, Shared& state) {
isGenerating = true; isGenerating = true;
try { try {
grid = setup(config); Grid2 grid = setup(config);
{
std:: lock_guard<std::mutex> lock(state.mutex);
state.grid = grid;
state.hasNewFrame = true;
state.currentFrame = 0;
}
Preview(grid); Preview(grid);
std::vector<std::tuple<size_t, Vec2, Vec4>> seeds = pickSeeds(grid, config); std::vector<std::tuple<size_t, Vec2, Vec4>> seeds = pickSeeds(grid, config);
std::vector<frame> frames; std::vector<frame> frames;
@@ -227,16 +243,21 @@ void mainLogic(const AnimationConfig& config, Grid2& grid) {
expandPixel(grid,config,seeds); expandPixel(grid,config,seeds);
std::lock_guard<std::mutex> lock(state.mutex);
state.grid = grid;
state.hasNewFrame = true;
state.currentFrame = i;
// Print compression info for this frame // Print compression info for this frame
if (i % 10 == 0 ) { if (i % 10 == 0 ) {
frame bgrframe; frame bgrframe;
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl; std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
bgrframe = grid.getGridAsFrame(frame::colormap::BGR); bgrframe = grid.getGridAsFrame(frame::colormap::BGR);
bgrframe.printCompressionStats();
frames.push_back(bgrframe); frames.push_back(bgrframe);
//bgrframe.decompress(); //bgrframe.decompress();
//BMPWriter::saveBMP(std::format("output/grayscalesource.{}.bmp", i), bgrframe); //BMPWriter::saveBMP(std::format("output/grayscalesource.{}.bmp", i), bgrframe);
bgrframe.compressFrameLZ78(); bgrframe.compressFrameLZ78();
bgrframe.printCompressionStats();
} }
} }
exportavi(frames,config); exportavi(frames,config);
@@ -305,7 +326,7 @@ int main() {
//ImGui::SetNextWindowSize(ImVec2(1110,667)); //ImGui::SetNextWindowSize(ImVec2(1110,667));
//auto beg = ImGui::Begin("Gradient thing", &window); //auto beg = ImGui::Begin("Gradient thing", &window);
//if (beg) { //if (beg) {
std::cout << "stuff breaks at 223" << std::endl; // std::cout << "stuff breaks at 223" << std::endl;
bool application_not_closed = true; bool application_not_closed = true;
//float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); //float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor());
GLFWwindow* window = glfwCreateWindow((int)(1280), (int)(800), "Chromatic gradient generator thing", nullptr, nullptr); GLFWwindow* window = glfwCreateWindow((int)(1280), (int)(800), "Chromatic gradient generator thing", nullptr, nullptr);
@@ -315,7 +336,7 @@ int main() {
glfwSwapInterval(1); glfwSwapInterval(1);
//IMGUI_CHECKVERSION(); //this might be more important than I realize. but cant run with it so currently ignoring. //IMGUI_CHECKVERSION(); //this might be more important than I realize. but cant run with it so currently ignoring.
ImGui::CreateContext(); ImGui::CreateContext();
std::cout << "context created" << std::endl; // std::cout << "context created" << std::endl;
ImGuiIO& io = ImGui::GetIO(); (void)io; ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
@@ -331,7 +352,7 @@ int main() {
ImGui_ImplOpenGL3_Init(glsl_version); ImGui_ImplOpenGL3_Init(glsl_version);
std::cout << "created glfw window" << std::endl; // std::cout << "created glfw window" << std::endl;
// Our state // Our state
@@ -345,8 +366,10 @@ int main() {
static int i4 = 8; static int i4 = 8;
std::future<void> mainlogicthread; std::future<void> mainlogicthread;
Shared state;
Grid2 grid; Grid2 grid;
AnimationConfig config; AnimationConfig config;
previewText = "Please generate";
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
glfwPollEvents(); glfwPollEvents();
@@ -370,7 +393,7 @@ int main() {
if (ImGui::Button("Generate Animation")) { if (ImGui::Button("Generate Animation")) {
config = AnimationConfig(i1, i2, i3, f, i4); 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) { if (isGenerating) {
@@ -381,58 +404,73 @@ int main() {
cancelGeneration(); cancelGeneration();
} }
ImGui::Text("Generating..."); // Check for new frames from the generation thread
} bool hasNewFrame = false;
//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? {
std::lock_guard<std::mutex> lock(state.mutex);
ImGui::Text("livepreview"); if (state.hasNewFrame) {
if (isGenerating) { livePreview(state.grid);
livePreview(grid); state.hasNewFrame = false;
ImVec2 availableSize = ImGui::GetContentRegionAvail(); previewText = "Generating... Frame: " + std::to_string(state.currentFrame);
}
}
float aspectRatio = static_cast<float>(currentPreviewFrame.getWidth()) / ImGui::Text(previewText.c_str());
static_cast<float>(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<void*>(static_cast<const void*>(currentPreviewFrame.getData().data()));
ImGui::ImageWithBg((ImTextureRef)ptex, imageSize, uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
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 { } else {
ImGui::Text("No preview available"); ImGui::Text("No preview available");
ImGui::Text("Start generation to see live preview"); 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(); ImGui::End();
} }
// std::cout << "ending frame" << std::endl;
ImGui::Render(); ImGui::Render();
int display_w, display_h; int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h); glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, 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); 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); glClear(GL_COLOR_BUFFER_BIT);
// std::cout << "rendering" << std::endl;
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window); glfwSwapBuffers(window);
//mainlogicthread.join(); //mainlogicthread.join();
// std::cout << "swapping buffers" << std::endl;
} }
cancelGeneration(); cancelGeneration();
// std::cout << "shutting down" << std::endl;
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
// std::cout << "destroying" << std::endl;
glfwDestroyWindow(window); glfwDestroyWindow(window);
if (previewTexture != 0) { if (textu != 0) {
glDeleteTextures(1, &previewTexture); glDeleteTextures(1, &textu);
previewTexture = 0; textu = 0;
} }
glfwTerminate(); glfwTerminate();
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED); FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
// std::cout << "printing" << std::endl;
return 0; return 0;
} }
//I need this: https://raais.github.io/ImStudio/ //I need this: https://raais.github.io/ImStudio/

View File

@@ -67,7 +67,7 @@ public:
return Positions.bucket_count(); return Positions.bucket_count();
} }
bool empty() { bool empty() const {
return Positions.empty(); return Positions.empty();
} }
@@ -194,7 +194,9 @@ protected:
//TODO: spatial map //TODO: spatial map
SpatialGrid spatialGrid; SpatialGrid spatialGrid;
float spatialCellSize = 2.0f; float spatialCellSize = 2.0f;
public: public:
bool usable = false;
//get position from id //get position from id
Vec2 getPositionID(size_t id) const { Vec2 getPositionID(size_t id) const {
Vec2 it = Positions.at(id); Vec2 it = Positions.at(id);
@@ -459,6 +461,7 @@ public:
shrinkIfNeeded(); shrinkIfNeeded();
updateNeighborMap(); updateNeighborMap();
usable = true;
return getAllIDs(); return getAllIDs();
} }
@@ -620,6 +623,78 @@ public:
} }
} }
void getGridRegionAsRGBA(const Vec2& minCorner, const Vec2& maxCorner,
int& width, int& height, std::vector<uint8_t>& rgbData) const {
TIME_FUNCTION;
// std::cout << "excessdebug g2.483" << std::endl;
// Calculate dimensions
width = static_cast<int>(maxCorner.x - minCorner.x);
height = static_cast<int>(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<Vec4> 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<int>(pos.x - size/2 - minCorner.x);
int pixelXM = static_cast<int>(pos.x + size/2 - minCorner.x);
int pixelYm = static_cast<int>(pos.y - size/2 - minCorner.y);
int pixelYM = static_cast<int>(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<unsigned char>(color.r * 255);
rgbData[bgrIndex + 1] = static_cast<unsigned char>(color.g * 255);
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.b * 255);
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.a * 255);
}
}
//get full as rgb/bgr //get full as rgb/bgr
void getGridAsRGB(int& width, int& height, std::vector<uint8_t>& rgbData) { void getGridAsRGB(int& width, int& height, std::vector<uint8_t>& rgbData) {
@@ -645,6 +720,17 @@ public:
resultFrame.setData(rgbData); resultFrame.setData(rgbData);
return resultFrame; return resultFrame;
} }
frame getGridRegionAsFrameRGBA(const Vec2& minCorner, const Vec2& maxCorner) const {
TIME_FUNCTION;
int width, height;
std::vector<uint8_t> 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) // Get region as frame (BGR format)
frame getGridRegionAsFrameBGR(const Vec2& minCorner, const Vec2& maxCorner) const { frame getGridRegionAsFrameBGR(const Vec2& minCorner, const Vec2& maxCorner) const {
@@ -659,7 +745,7 @@ public:
} }
// Get entire grid as frame with specified format // 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; TIME_FUNCTION;
Vec2 minCorner, maxCorner; Vec2 minCorner, maxCorner;
getBoundingBox(minCorner, maxCorner); getBoundingBox(minCorner, maxCorner);
@@ -669,6 +755,9 @@ public:
case frame::colormap::RGB: case frame::colormap::RGB:
Frame = std::move(getGridRegionAsFrameRGB(minCorner, maxCorner)); Frame = std::move(getGridRegionAsFrameRGB(minCorner, maxCorner));
break; break;
case frame::colormap::RGBA:
Frame = std::move(getGridRegionAsFrameRGBA(minCorner, maxCorner));
break;
case frame::colormap::BGR: case frame::colormap::BGR:
Frame = std::move(getGridRegionAsFrameBGR(minCorner, maxCorner)); Frame = std::move(getGridRegionAsFrameBGR(minCorner, maxCorner));
break; break;
@@ -708,7 +797,7 @@ public:
} }
//get bounding box //get bounding box
void getBoundingBox(Vec2& minCorner, Vec2& maxCorner) { void getBoundingBox(Vec2& minCorner, Vec2& maxCorner) const {
TIME_FUNCTION; TIME_FUNCTION;
if (Positions.empty()) { if (Positions.empty()) {
minCorner = Vec2(0, 0); minCorner = Vec2(0, 0);