]> code.bitgloo.com Git - clyne/raytracer.git/commitdiff
un-fix threads; more refactoring
authorClyne Sullivan <clyne@bitgloo.com>
Wed, 15 May 2024 12:38:27 +0000 (08:38 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Wed, 15 May 2024 12:38:27 +0000 (08:38 -0400)
main.cpp
random.h
renderer.h
sphere.h

index bd749abd6bd5b61189a613779ec55ae336e3348c..edad534d1774c23f73f15755d0e0d4cb0185385e 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -1,7 +1,6 @@
 constexpr unsigned Width = 1000;
 constexpr double   Aspect = 16.0 / 9.0;
 constexpr unsigned Height = Width / Aspect;
-constexpr unsigned Threads = 3;
 
 #include "color.h"
 #include "ray.h"
@@ -26,14 +25,17 @@ constexpr unsigned Threads = 3;
 
 static View Camera;
 static World world;
+static int threads = 4;
 static int SamplesPerPixel = 20;
 static float Daylight = 0.5f;
-static std::unique_ptr<Renderer<Threads>> renderer;
+static std::unique_ptr<Renderer> renderer;
 static std::chrono::time_point<std::chrono::high_resolution_clock> renderStart;
 static std::chrono::duration<double> renderTime;
 
 static color ray_color(const ray& r, int depth = 50);
 static void initiateRender(SDL_Surface *canvas);
+static void showObjectControls(int index, Sphere& o);
+static void addRandomObject();
 
 int main()
 {
@@ -47,10 +49,10 @@ int main()
     ImGui_ImplSDL2_InitForSDLRenderer(window, painter);
     ImGui_ImplSDLRenderer2_Init(painter);
 
-    world.add(point3( 0.00, -100.50, -1.0), 100.0, Material::Lambertian, color(0.5, 1.0, 0.5));
-    world.add(point3(-0.50,    0.00, -1.2),   0.5, Material::Dielectric, color(1.0, 0.8, 0.8));
-    world.add(point3( 0.50,    0.00, -1.0),   0.5, Material::Metal,      color(0.5, 0.5, 0.5));
-    world.add(point3(-0.05,   -0.35, -0.7),   0.1, Material::Metal,      color(0.8, 0.6, 0.0));
+    world.add(point3(0.00, -100.50, -1.0), 100.0,
+        Material::Lambertian, color(0.5, 1.0, 0.5));
+    for (auto i : std::views::iota(0, 10))
+        addRandomObject();
 
     std::cout << "Spawning threads..." << std::endl;
     initiateRender(canvas);
@@ -73,11 +75,17 @@ int main()
 
         ImGui::Begin("settings", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
         ImGui::SliderFloat("fov", &Camera.fieldOfView, 10, 160);
-        ImGui::SetNextItemWidth(100); ImGui::InputDouble("X", &Camera.camera.x(), 0.1, 0.05, "%.2lf");
-        ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble("Y", &Camera.camera.y(), 0.1, 0.05, "%.2lf");
-        ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble("Z", &Camera.camera.z(), 0.1, 0.05, "%.2lf");
+        ImGui::SameLine(); ImGui::SetNextItemWidth(60);
+        ImGui::InputInt("T", &threads);
+        ImGui::SetNextItemWidth(100);
+        ImGui::InputDouble("X", &Camera.camera.x(), 0.1, 0.05, "%.2lf");
+        ImGui::SameLine(); ImGui::SetNextItemWidth(100);
+        ImGui::InputDouble("Y", &Camera.camera.y(), 0.1, 0.05, "%.2lf");
+        ImGui::SameLine(); ImGui::SetNextItemWidth(100);
+        ImGui::InputDouble("Z", &Camera.camera.z(), 0.1, 0.05, "%.2lf");
         ImGui::SliderInt("samples", &SamplesPerPixel, 1, 200);
         ImGui::SliderFloat("shade", &Daylight, 0.f, 1.f);
+
         if (ImGui::Button("recalculate")) {
             initiateRender(canvas);
         }
@@ -94,6 +102,7 @@ int main()
             renderer->stop();
             run = false;
         }
+
         if (*renderer) {
             SDL_DestroyTexture(tex);
             tex = SDL_CreateTextureFromSurface(painter, canvas);
@@ -114,35 +123,13 @@ int main()
         ImGui::End();
 
         ImGui::Begin("balls", nullptr, ImGuiWindowFlags_NoResize); {
-            char radius[] = "radius 0";
-            char mat[] = "mat 0";
-            char xpos[] = "x 0";
-            char ypos[] = "y 0";
-            char zpos[] = "z 0";
-
-            for (auto& o : std::views::drop(world.objects, 1)) {
-                ImGui::SetNextItemWidth(200);
-                ImGui::Combo(mat, reinterpret_cast<int *>(&o.M),
-                    "Lambertian\0Metal\0Dielectric\0");
-                ImGui::SameLine(); ImGui::SetNextItemWidth(100);
-                ImGui::InputDouble(radius, &o.radius, 0.1, 0.05, "%.2lf");
-                ImGui::SetNextItemWidth(100);
-                ImGui::InputDouble(xpos, &o.center.x(), 0.05, 0.05, "%.2lf");
-                ImGui::SameLine(); ImGui::SetNextItemWidth(100);
-                ImGui::InputDouble(ypos, &o.center.y(), 0.1, 0.05, "%.2lf");
-                ImGui::SameLine(); ImGui::SetNextItemWidth(100);
-                ImGui::InputDouble(zpos, &o.center.z(), 0.1, 0.05, "%.2lf");
-
-                radius[7]++;
-                mat[4]++;
-                xpos[2]++;
-                ypos[2]++;
-                zpos[2]++;
-            }
+            std::ranges::for_each(
+                std::views::zip(std::views::iota(0),
+                                std::views::drop(world.objects, 1)),
+                [](auto io) { std::apply(showObjectControls, io); });
+
             if (ImGui::Button("add")) {
-                const point3 pos = vec3::random() * vec3(4, 1.5, 4) - vec3(2, 0, 4);
-                const color col = vec3::random();
-                world.add(pos, randomN() * 0.5 + 0.1, Material::Lambertian, col);
+                addRandomObject();
                 initiateRender(canvas);
             }
             if (ImGui::Button("del")) {
@@ -200,5 +187,37 @@ void initiateRender(SDL_Surface *canvas)
     };
 
     Camera.recalculate();
-    renderer.reset(new Renderer<Threads>(func, Width, Height, (uint32_t *)canvas->pixels));
+    threads = std::clamp(threads, 1, Renderer::MaxThreads);
+    renderer.reset(new Renderer(threads, func, Width, Height,
+        (uint32_t *)canvas->pixels));
 }
+
+void showObjectControls(int index, Sphere& o)
+{
+    const auto idx = std::to_string(index);
+
+    ImGui::SetNextItemWidth(200);
+    ImGui::Combo((std::string("mat") + idx).c_str(), reinterpret_cast<int *>(&o.M),
+        "Lambertian\0Metal\0Dielectric\0");
+    ImGui::SameLine(); ImGui::SetNextItemWidth(100);
+    ImGui::InputDouble((std::string("radius") + idx).c_str(),
+        &o.radius, 0.1, 0.05, "%.2lf");
+    ImGui::SetNextItemWidth(100);
+    ImGui::InputDouble((std::string("x") + idx).c_str(),
+        &o.center.x(), 0.05, 0.05, "%.2lf");
+    ImGui::SameLine(); ImGui::SetNextItemWidth(100);
+    ImGui::InputDouble((std::string("y") + idx).c_str(),
+        &o.center.y(), 0.1, 0.05, "%.2lf");
+    ImGui::SameLine(); ImGui::SetNextItemWidth(100);
+    ImGui::InputDouble((std::string("z") + idx).c_str(),
+        &o.center.z(), 0.1, 0.05, "%.2lf");
+}
+
+void addRandomObject()
+{
+    const point3 pos = vec3::random() * vec3(6, 0.8, 3) - vec3(3, 0, 3.8);
+    const color col = vec3::random();
+    const auto mat = (int)(randomN() * ((int)Material::Undefined - 1));
+    world.add(pos, randomN() * 0.3 + 0.05, (Material)mat, col);
+}
+
index fb0c7b3ef79293dfa17caedd020a9ded9c2db717..ec6020905c00c8d9e1f6e0c7a3d1dba80d47fa5a 100644 (file)
--- a/random.h
+++ b/random.h
@@ -6,7 +6,7 @@
 inline double randomN()
 {
     static std::uniform_real_distribution<double> distribution (0.0, 1.0);
-    static std::mt19937 generator;
+    static std::mt19937 generator (std::random_device{}());
     return distribution(generator);
 }
 
index ec7b1705485e4c926f1ac4eac1e946ed8f3acb0c..864c0b8e3dc2959ef4e4085a4110c11ee9c312d1 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
 #include <algorithm>
 #include <atomic>
 #include <memory>
@@ -5,28 +8,32 @@
 #include <semaphore>
 #include <thread>
 
-template<int Threads>
 class Renderer
 {
-    std::counting_semaphore<Threads> Workers;
+public:
+    static constexpr int MaxThreads = 64;
+
+private:
+    int N;
+    std::counting_semaphore<MaxThreads> Workers;
     std::atomic_uint processed;
     unsigned total;
     std::atomic_bool Stop;
     std::unique_ptr<std::thread> primary;
 
 public:
-    Renderer(auto func, unsigned Width, unsigned Height, auto pbuf):
-        Workers(Threads), processed(0), total(Threads * 8)
+    Renderer(int n, auto func, unsigned width, unsigned height, auto pbuf):
+        N(n), Workers(N), processed(0), total(N * 8)
     {
         Stop.store(false);
 
         auto threads = std::views::transform(
             std::views::chunk(
                 std::views::cartesian_product(
-                    std::views::iota(0u, Width),
-                    std::views::iota(0u, Height),
+                    std::views::iota(0u, width),
+                    std::views::iota(0u, height),
                     std::views::single(pbuf)),
-                Width * Height / total),
+                width * height / total),
             [=, this](auto chunk) { return std::thread([=, this] { worker(func, chunk); }); });
 
         primary.reset(new std::thread([=, this] {
@@ -34,10 +41,8 @@ public:
                 Workers.acquire();
                 th.detach();
             }
-            for (auto i : std::views::iota(0, Threads))
+            for (int i : std::views::iota(0, N))
                 Workers.acquire();
-            for (auto i : std::views::iota(0, Threads))
-                Workers.release();
             Stop.store(true);
         }));
     }
@@ -73,4 +78,5 @@ private:
     }
 };
 
+#endif // RENDERER_H
 
index c27f29b3fa041412098cedbd6d575c62fa039c4d..3cb2c8ced88993d0885fd09d2406cb1d66095b64 100644 (file)
--- a/sphere.h
+++ b/sphere.h
 #include <tuple>
 
 enum class Material : int {
-    Lambertian,
+    Lambertian = 0,
     Metal,
-    Dielectric
+    Dielectric,
+    Undefined
 };
 
 struct Sphere