diff --git a/tests/g3test2.cpp b/tests/g3test2.cpp index edb273a..e99dad6 100644 --- a/tests/g3test2.cpp +++ b/tests/g3test2.cpp @@ -1,228 +1,176 @@ -// main.cpp - Noise Grid Generator and Renderer #include -#include -#include #include #include "../util/grid/grid3.hpp" #include "../util/output/bmpwriter.hpp" -#include "../util/noise/pnoise2.hpp" +#include "../util/output/frame.hpp" #include "../util/timing_decorator.cpp" -// Constants -const size_t GRID_SIZE = 128; -const size_t RENDER_WIDTH = 512; -const size_t RENDER_HEIGHT = 512; +#include "../imgui/imgui.h" +#include "../imgui/backends/imgui_impl_glfw.h" +#include "../imgui/backends/imgui_impl_opengl3.h" +#include +#include "../stb/stb_image.h" -// Function to generate grayscale noise grid -void generateNoiseGrid(VoxelGrid& grid, PNoise2& noise) { - TIME_FUNCTION; - std::cout << "Generating 1024x1024x1024 noise grid..." << std::endl; - - // Generate Perlin noise in the grid - #pragma omp parallel for - for (size_t z = 0; z < GRID_SIZE; ++z) { +struct defaults { + int outWidth = 1024; + int outHeight = 1024; + size_t gridWidth = 1024; + size_t gridHeight = 1024; + size_t gridDepth = 1024; + float fps = 30.0f; + PNoise2 noise = PNoise2(42); +}; + +std::mutex PreviewMutex; +frame currentPreviewFrame; +GLuint textu = 0; +bool updatePreview; + +VoxelGrid setup(defaults config) { + float threshold = 0.3 * 255; + VoxelGrid grid(config.gridWidth, config.gridHeight, config.gridDepth); + std::cout << "Generating grid of size " << config.gridWidth << "x" << config.gridHeight << "x" << config.gridDepth << std::endl; + for (size_t z = 0; z < config.gridDepth; ++z) { if (z % 64 == 0) { - std::cout << "Processing layer " << z << " of " << GRID_SIZE << std::endl; + std::cout << "Processing layer " << z << " of " << config.gridDepth << std::endl; } - - //#pragma omp parallel for - for (size_t y = 0; y < GRID_SIZE; ++y) { - //#pragma omp parallel for - for (size_t x = 0; x < GRID_SIZE; ++x) { - // Create 3D noise coordinates (scaled for better frequency) - float scale = 0.05f; // Controls noise frequency - float noiseVal = noise.permute(Vec3f(x * scale, y * scale, z * scale)); - - // Convert from [-1, 1] to [0, 1] range - //float normalizedNoise = (noiseVal + 1.0f) * 0.5f; - - // Apply threshold to make some voxels "active" - // Higher threshold = sparser voxels - float threshold = 0.3; - float active = (noiseVal > threshold) ? noiseVal : 0.0f; - - // Create grayscale color based on noise value - uint8_t grayValue = static_cast(noiseVal * 255); - Vec3ui8 color(grayValue, grayValue, 0); - #pragma omp critical - if (active > threshold) { - grid.set(x, y, z, true, color); + + for (size_t y = 0; y < config.gridWidth; ++y) { + for (size_t x = 0; x < config.gridHeight; ++x) { + Vec4ui8 noisecolor = config.noise.permuteColor(Vec3f( x / 64, y / 64, z / 64)); + if (noisecolor.a > threshold) { + grid.set(Vec3T(x,y,z), true, Vec3ui8(noisecolor.xyz())); } } } } - std::cout << "Noise grid generation complete!" << std::endl; } -// Function to render grid from a specific viewpoint -bool renderView(const std::string& filename, VoxelGrid& grid, const Vec3f& position, - const Vec3f& direction, const Vec3f& up = Vec3f(0, 1, 0)) { - TIME_FUNCTION; - Camera cam(position, direction, up, 40); +void livePreview(VoxelGrid& grid, defaults config, Camera cam) { + std::lock_guard lock(PreviewMutex); - std::vector renderBuffer; - size_t width = RENDER_WIDTH; - size_t height = RENDER_HEIGHT; + currentPreviewFrame = grid.renderFrame(cam.posfor.origin, cam.posfor.direction, cam.up, cam.fov, config.outWidth, config.outHeight, frame::colormap::BGRA); + + 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); - // Render the view - frame output = grid.renderFrame(position, direction, up, 40, RENDER_WIDTH, RENDER_HEIGHT); - //grid.renderOut(renderBuffer, width, height, cam); + 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()); - // Save to BMP - bool success = BMPWriter::saveBMP(filename, output); - //bool success = BMPWriter::saveBMP(filename, renderBuffer, width, height); - - // if (success) { - // std::cout << "Saved: " << filename << std::endl; - // } else { - // std::cout << "Failed to save: " << filename << std::endl; - // } - - return success; + updatePreview = true; } -Vec3f rotateX(const Vec3f& vec, float angle) { - TIME_FUNCTION; - float cosA = cos(angle); - float sinA = sin(angle); - return Vec3f( - vec.x, - vec.y * cosA - vec.z * sinA, - vec.y * sinA + vec.z * cosA - ); +static void glfw_error_callback(int error, const char* description) +{ + fprintf(stderr, "GLFW Error %d: %s\n", error, description); } -Vec3f rotateY(const Vec3f& vec, float angle) { - TIME_FUNCTION; - float cosA = cos(angle); - float sinA = sin(angle); - return Vec3f( - vec.x * cosA + vec.z * sinA, - vec.y, - -vec.x * sinA + vec.z * cosA - ); -} - -Vec3f rotateZ(const Vec3f& vec, float angle) { - TIME_FUNCTION; - float cosA = cos(angle); - float sinA = sin(angle); - return Vec3f( - vec.x * cosA - vec.y * sinA, - vec.x * sinA + vec.y * cosA, - vec.z - ); -} int main() { - TIME_FUNCTION; - std::cout << "=== Noise Grid Generator and Renderer ===" << std::endl; - std::cout << "Grid Size: 1024x1024x1024 voxels" << std::endl; - std::cout << "Render Size: 512x512 pixels" << std::endl; - - // Initialize Perlin noise generator - PNoise2 noise; - - // Create voxel grid - VoxelGrid grid(GRID_SIZE, GRID_SIZE, GRID_SIZE); - - // Generate noise grid - generateNoiseGrid(grid, noise); - - // Define center of the grid for camera positioning - Vec3f gridCenter(GRID_SIZE / 2.0f, GRID_SIZE / 2.0f, GRID_SIZE / 2.0f); - - // Camera distance from center (outside the grid) - float cameraDistance = GRID_SIZE * 2.0f; - - int numFrames = 360; - - // Base camera position (looking from front) - Vec3f basePosition(0, 0, cameraDistance); - Vec3f baseDirection(0, 0, -1); // Looking towards negative Z (towards center) - Vec3f up(0, 1, 0); - - // // Render frames around 180 degrees - // for (int i = 0; i <= numFrames; i++) { - // float angle = (float)i / numFrames * M_PI; // 0 to π (180 degrees) - - // // Rotate camera position around Y axis - // Vec3f rotatedPos = rotateY(basePosition, angle); - // Vec3f finalPos = gridCenter + rotatedPos; - // //Vec3f rotatedDir = rotateY(baseDirection, angle); - // Vec3f rotatedDir = (gridCenter - finalPos).normalized(); - - // // Create filename with frame number - // char filename[256]; - // snprintf(filename, sizeof(filename), "output/framey_%03d.bmp", i); - - // // std::cout << "Rendering frame " << i << "/" << numFrames - // // << " (angle: " << (angle * 360.0f / M_PI) << " degrees)" << std::endl; - - // renderView(filename, grid, finalPos, rotatedDir, up); - // } - - // basePosition = Vec3f(0, 0, cameraDistance); - // baseDirection = Vec3f(0, 0, -1); - // up = Vec3f(0, 1, 0); - - // for (int i = 0; i <= numFrames; i++) { - // float angle = (float)i / numFrames * M_PI; // 0 to π (180 degrees) - - // // Rotate camera position around Y axis - // Vec3f rotatedPos = rotateZ(basePosition, angle); - // Vec3f finalPos = gridCenter + rotatedPos; - // //Vec3f rotatedDir = rotateY(baseDirection, angle); - // Vec3f rotatedDir = (gridCenter - finalPos).normalized(); - - // // Create filename with frame number - // char filename[256]; - // snprintf(filename, sizeof(filename), "output/framez_%03d.bmp", i); - - // // std::cout << "Rendering frame " << i << "/" << numFrames - // // << " (angle: " << (angle * 360.0f / M_PI) << " degrees)" << std::endl; - - // renderView(filename, grid, finalPos, rotatedDir, up); - // } - - // basePosition = Vec3f(0, 0, cameraDistance); - // baseDirection = Vec3f(0, 0, -1); - // up = Vec3f(0, 1, 0); - - for (int i = 0; i <= numFrames; i++) { - float angle = (float)i / numFrames * M_PI; // 0 to π (180 degrees) - - // Rotate camera position around Y axis - Vec3f rotatedPos = rotateX(basePosition, angle); - Vec3f finalPos = gridCenter + rotatedPos; - //Vec3f rotatedDir = rotateY(baseDirection, angle); - Vec3f rotatedDir = (gridCenter - finalPos).normalized(); - - // Create filename with frame number - char filename[256]; - snprintf(filename, sizeof(filename), "output/framex_%03d.bmp", i); - - std::cout << "Rendering frame " << i << "/" << numFrames - << " (angle: " << (angle * 360.0f / M_PI) << " degrees)" << std::endl; - - renderView(filename, grid, finalPos, rotatedDir, up); + 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 + + bool application_not_closed = true; + GLFWwindow* window = glfwCreateWindow((int)(1280), (int)(800), "voxelgrid live renderer", nullptr, nullptr); + if (window == nullptr) + return 1; + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + ImGui::StyleColorsDark(); + ImGuiStyle& style = ImGui::GetStyle(); + ImGui_ImplGlfw_InitForOpenGL(window, true); + + #ifdef __EMSCRIPTEN__ + ImGui_ImplGlfw_InstallEmscriptenCallbacks(window, "#canvas"); + #endif + ImGui_ImplOpenGL3_Init(glsl_version); + + 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(); + { + ImGui::Begin("settings"); + } + // 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; + } + - std::cout << "\nRendering zenith and nadir views..." << std::endl; - renderView("output/zenith_view.bmp", grid, - gridCenter + Vec3f(0, cameraDistance, 0), - Vec3f(0, -1, 0), // Look down - Vec3f(0, 0, -1)); // Adjust up vector for proper orientation - - // Nadir view (looking from below) - renderView("output/nadir_view.bmp", grid, - gridCenter + Vec3f(0, -cameraDistance, 0), - Vec3f(0, 1, 0), // Look up - Vec3f(0, 0, 1)); // Adjust up vector - - std::cout << "\n=== All renders complete! ===" << std::endl; - + // std::cout << "shutting down" << std::endl; + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + // std::cout << "destroying" << std::endl; + glfwDestroyWindow(window); + if (textu != 0) { + glDeleteTextures(1, &textu); + textu = 0; + } + glfwTerminate(); FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED); + + // std::cout << "printing" << std::endl; return 0; } \ No newline at end of file diff --git a/util/grid/grid3.hpp b/util/grid/grid3.hpp index b0167ff..5276621 100644 --- a/util/grid/grid3.hpp +++ b/util/grid/grid3.hpp @@ -197,7 +197,7 @@ public: return gridSize.z; } - frame renderFrame(const Vec3f& CamPos, const Vec3f& dir, const Vec3f& up, float fov, size_t outW, size_t outH) { + frame renderFrame(const Vec3f& CamPos, const Vec3f& dir, const Vec3f& up, float fov, size_t outW, size_t outH, frame::colormap colorformat = frame::colormap::RGB) { TIME_FUNCTION; Vec3f forward = (dir - CamPos).normalized(); Vec3f right = forward.cross(up).normalized(); @@ -234,10 +234,24 @@ public: hitVoxels.clear(); hitVoxels.shrink_to_fit(); // Set pixel color in buffer - size_t idx = (y * outW + x) * 3; - colorBuffer[idx + 0] = hitColor.x; - colorBuffer[idx + 1] = hitColor.y; - colorBuffer[idx + 2] = hitColor.z; + switch (colorformat) { + case frame::colormap::RGB: { + size_t idx = (y * outW + x) * 3; + colorBuffer[idx + 0] = hitColor.x; + colorBuffer[idx + 1] = hitColor.y; + colorBuffer[idx + 2] = hitColor.z; + break; + } + case frame::colormap::BGRA: { + size_t idx = (y * outW + x) * 4; + colorBuffer[idx + 3] = hitColor.x; + colorBuffer[idx + 2] = hitColor.y; + colorBuffer[idx + 1] = hitColor.z; + colorBuffer[idx + 0] = 1; + break; + } + + } } }