From af4e6ebe3f2f08982c039308cebe39505ec58666 Mon Sep 17 00:00:00 2001 From: yggdrasil75 Date: Sat, 14 Feb 2026 09:32:55 -0500 Subject: [PATCH] direct render tris, and moving some stuff out of main. --- tests/g3etest.cpp | 76 ++------------------------ util/grid/mesh.hpp | 132 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 73 deletions(-) diff --git a/tests/g3etest.cpp b/tests/g3etest.cpp index c5dedb7..dbfa83f 100644 --- a/tests/g3etest.cpp +++ b/tests/g3etest.cpp @@ -37,7 +37,7 @@ struct defaults { float lodDropoff = 0.1; PNoise2 noise = PNoise2(42); - int meshResolution = 32; + int meshResolution = 128; float meshIsoLevel = 0.4f; }; @@ -82,12 +82,6 @@ std::vector renderFrameTimes; int frameHistoryIndex = 0; bool firstFrameMeasured = false; -// Stats update timer -std::chrono::steady_clock::time_point lastStatsUpdate; -const std::chrono::seconds STATS_UPDATE_INTERVAL(60); -std::string cachedStats; -bool statsNeedUpdate = true; - Scene scene; bool meshNeedsUpdate = false; @@ -188,13 +182,6 @@ void addStar(const defaults& config, const stardefaults& starconf, Octree& meshNeedsUpdate = true; } -void updateStatsCache(Octree& grid) { - std::stringstream gridstats; - grid.printStats(gridstats); - cachedStats = gridstats.str(); - lastStatsUpdate = std::chrono::steady_clock::now(); - statsNeedUpdate = false; -} void livePreview(Octree& grid, defaults& config, const Camera& cam) { std::lock_guard lock(PreviewMutex); @@ -204,7 +191,7 @@ void livePreview(Octree& grid, defaults& config, const Camera& cam) { if (meshNeedsUpdate) { scene.clear(); std::shared_ptr planetMesh = grid.generateMesh(1, config.meshIsoLevel, config.meshResolution); - std::shared_ptr starMesh = grid.generateMesh(2, config.meshIsoLevel, config.meshResolution); + std::shared_ptr starMesh = grid.generateMesh(2, config.meshIsoLevel, config.meshResolution / 4); scene.addMesh(planetMesh); scene.addMesh(starMesh); @@ -213,7 +200,6 @@ void livePreview(Octree& grid, defaults& config, const Camera& cam) { // planetMesh.setIsoLevel(config.meshIsoLevel); // planetMesh.update(grid); meshNeedsUpdate = false; - statsNeedUpdate = true; } auto renderStart = std::chrono::high_resolution_clock::now(); @@ -254,10 +240,6 @@ void livePreview(Octree& grid, defaults& config, const Camera& cam) { } auto now = std::chrono::steady_clock::now(); - if (statsNeedUpdate || (now - lastStatsUpdate) > STATS_UPDATE_INTERVAL) { - updateStatsCache(grid); - } - if (textu == 0) { glGenTextures(1, &textu); } @@ -404,13 +386,10 @@ int main() { float deltaTime = 0.016f; renderFrameTimes.resize(FRAME_HISTORY_SIZE, 0.0); - lastStatsUpdate = std::chrono::steady_clock::now(); - statsNeedUpdate = true; bool worldPreview = false; if (grid.load("output/Treegrid.yggs")) { gridInitialized = true; - updateStatsCache(grid); resetView(cam, config.gridSizecube); meshNeedsUpdate = true; } @@ -565,7 +544,7 @@ int main() { createSphere(config, sphereConf, grid); addStar(config, starConf, grid); gridInitialized = true; - statsNeedUpdate = true; + scene.updateStats(); resetView(cam, config.gridSizecube); grid.generateLODs(); @@ -585,53 +564,8 @@ int main() { fluidUI.renderUI(); } - { - ImGui::Begin("Planet Preview"); - if (worldPreview) { - if (gridInitialized) { - livePreview(grid, config, cam); - } - } - - if (gridInitialized && textureInitialized) { - ImGui::Image((void*)(intptr_t)textu, ImVec2(config.outWidth, config.outHeight)); - } else if (gridInitialized) { - ImGui::Text("Preview not generated yet"); - } else { - ImGui::Text("No grid generated"); - } - - ImGui::Text("Render Performance:"); - if (renderFPS > 0) { - // Color code based on FPS - ImVec4 fpsColor; - if (renderFPS >= 30.0) { - fpsColor = ImVec4(0.0f, 1.0f, 0.0f, 1.0f); // Green for good FPS - } else if (renderFPS >= 15.0) { - fpsColor = ImVec4(1.0f, 1.0f, 0.0f, 1.0f); // Yellow for okay FPS - } else { - fpsColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f); // Red for poor FPS - } - - ImGui::TextColored(fpsColor, "FPS: %.1f", renderFPS); - ImGui::Text("Frame time: %.1f ms", avgRenderFrameTime * 1000.0); - - // Simple progress bar for frame time - ImGui::Text("%.1f/100 ms", avgRenderFrameTime * 1000.0); - - // Show latest frame time - ImGui::Text("Latest: %.1f ms", renderFrameTime * 1000.0); - } - - ImGui::Separator(); - - if (gridInitialized) { - auto now = std::chrono::steady_clock::now(); - if ((now - lastStatsUpdate) > STATS_UPDATE_INTERVAL) updateStatsCache(grid); - ImGui::TextUnformatted(cachedStats.c_str()); - } - ImGui::End(); - } + scene.drawSceneWindow("Planet Preview", cam, 0.01, 1000); + scene.drawGridStats(); { ImGui::Begin("controls"); diff --git a/util/grid/mesh.hpp b/util/grid/mesh.hpp index c494654..83f3455 100644 --- a/util/grid/mesh.hpp +++ b/util/grid/mesh.hpp @@ -9,10 +9,16 @@ #include #include #include +#include #include "../../eigen/Eigen/Dense" #include "../../eigen/Eigen/Geometry" #include "./camera.hpp" #include "../output/frame.hpp" +#include "../imgui/imgui.h" +#include "../imgui/backends/imgui_impl_glfw.h" +#include "../imgui/backends/imgui_impl_opengl3.h" +#include +#include "../stb/stb_image.h" using Vector2f = Eigen::Vector2f; using Vector3f = Eigen::Vector3f; @@ -236,13 +242,26 @@ public: outFrame.setData(buffer, colorformat); return outFrame; } -}; + void printStats(std::ostream& os = std::cout) const { + os << "========================================\n"; + os << " Mesh STATS \n"; + os << "========================================\n"; + os << "Structure:\n"; + os << " Total Vertices : " << _vertices.size() << "\n"; + os << " Total Tris : " << _tris.size() << "\n"; + os << " Total Polys : " << _polys.size() << "\n"; + os << " colors : " << _colors.size() << "\n"; + } +}; class Scene { private: std::vector> _meshes; - + std::string cachedStats; + std::chrono::steady_clock::time_point lastStatsUpdate; + bool statsNeedUpdate = true; + const std::chrono::seconds STATS_UPDATE_INTERVAL{60}; public: Scene() {} @@ -268,6 +287,115 @@ public: return Mesh::rasterizeTriangles(allTriangles, width, height, colorformat); } + + void drawSceneWindow(const char* windowTitle, Camera& cam, float nearClip = 0.1f, float farClip = 1000.0f, bool showFps = true) { + ImGui::Begin(windowTitle); + + // Get the position and size of the content area within the ImGui window + ImVec2 canvas_p = ImGui::GetCursorScreenPos(); + ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); + + if (canvas_sz.x < 1.0f || canvas_sz.y < 1.0f) { + ImGui::End(); + return; + } + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + // Clip drawing to the specific window area + draw_list->PushClipRect(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), true); + + // Draw background + draw_list->AddRectFilled(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), IM_COL32(20, 20, 20, 255)); + + // Collect and project triangles + std::vector allTriangles; + for (auto& mesh : _meshes) { + std::vector meshTris = mesh->project_2d(cam, (int)canvas_sz.y, (int)canvas_sz.x, nearClip, farClip); + allTriangles.insert(allTriangles.end(), meshTris.begin(), meshTris.end()); + } + + // Sort by depth (Painter's Algorithm) + std::sort(allTriangles.begin(), allTriangles.end(), [](const Triangle2D& a, const Triangle2D& b) { + return a.depth > b.depth; + }); + + // Draw triangles + for (const auto& tri : allTriangles) { + ImVec2 p1(canvas_p.x + tri.a.x(), canvas_p.y + tri.a.y()); + ImVec2 p2(canvas_p.x + tri.b.x(), canvas_p.y + tri.b.y()); + ImVec2 p3(canvas_p.x + tri.c.x(), canvas_p.y + tri.c.y()); + + // Simple culling optimization + // float minX = std::min({p1.x, p2.x, p3.x}); + // float minY = std::min({p1.y, p2.y, p3.y}); + // float maxX = std::max({p1.x, p2.x, p3.x}); + // float maxY = std::max({p1.y, p2.y, p3.y}); + + // if (maxX < canvas_p.x || minX > canvas_p.x + canvas_sz.x || + // maxY < canvas_p.y || minY > canvas_p.y + canvas_sz.y) { + // continue; + // } + + // float r = std::clamp(tri.color.x(), 0.0f, 1.0f); + // float g = std::clamp(tri.color.y(), 0.0f, 1.0f); + // float b = std::clamp(tri.color.z(), 0.0f, 1.0f); + + ImU32 col = ImGui::ColorConvertFloat4ToU32(ImVec4(tri.color.x(), tri.color.y(), tri.color.z(), 1.0f)); + draw_list->AddTriangleFilled(p1, p2, p3, col); + } + + // Draw FPS Counter + if (showFps) { + char fpsText[32]; + snprintf(fpsText, sizeof(fpsText), "FPS: %.1f", ImGui::GetIO().Framerate); + + ImVec2 txtSz = ImGui::CalcTextSize(fpsText); + // Position: Top Right with 10px padding + ImVec2 txtPos = ImVec2(canvas_p.x + canvas_sz.x - txtSz.x - 10.0f, canvas_p.y + 10.0f); + + // Semi-transparent background for text + draw_list->AddRectFilled( + ImVec2(txtPos.x - 5.0f, txtPos.y - 2.0f), + ImVec2(txtPos.x + txtSz.x + 5.0f, txtPos.y + txtSz.y + 2.0f), + IM_COL32(0, 0, 0, 150), + 4.0f + ); + + draw_list->AddText(txtPos, IM_COL32(255, 255, 255, 255), fpsText); + } + + draw_list->PopClipRect(); + + // Invisible button to handle inputs over the viewport area + ImGui::InvisibleButton("viewport_btn", canvas_sz); + + ImGui::End(); + } + + void printStats(std::ostream& os = std::cout) const { + os << "========================================\n"; + os << " Scene STATS \n"; + os << "========================================\n"; + for (auto m : _meshes) { + m->printStats(os); + } + } + + void drawGridStats() { + auto now = std::chrono::steady_clock::now(); + if ((now - lastStatsUpdate) > STATS_UPDATE_INTERVAL || statsNeedUpdate) { + std::stringstream meshStats; + printStats(meshStats); + cachedStats = meshStats.str(); + lastStatsUpdate = std::chrono::steady_clock::now(); + statsNeedUpdate = false; + } + ImGui::TextUnformatted(cachedStats.c_str()); + } + void updateStats() { + statsNeedUpdate = true; + } }; #endif