#pragma once #include #include #include #include #include #include #include namespace lantern { struct Error { std::string message; }; struct Vec3 { double x{}, y{}, z{}; }; struct Ray { Vec3 origin; Vec3 direction; }; // Finite, unit direction required. struct Aabb { Vec3 low; Vec3 high; }; struct Sphere { std::uint32_t id{}; Vec3 center; double radius{}; }; struct Hit { std::uint32_t id{}; double distance{}; }; inline constexpr std::size_t max_spheres = 128; inline constexpr std::size_t max_samples = 1'048'576; // Explicit algorithm and owned state: useful reproducibility, not cryptography. class Rng { public: explicit Rng(std::uint64_t seed) noexcept : state_{seed} {} [[nodiscard]] std::uint64_t next() noexcept; [[nodiscard]] double uniform() noexcept; // [0, 1), using the high 53 bits. private: std::uint64_t state_; }; struct DirectionSample { Vec3 direction; double pdf{}; }; // Density per steradian. [[nodiscard]] std::expected cosine_hemisphere(double u, double v); [[nodiscard]] std::expected cosine_integral(std::size_t samples, std::uint64_t seed); [[nodiscard]] std::expected power_weight(double pdf_a, double pdf_b); // Linear-sample statistics. Display transforms belong AFTER averaging. class Moments { public: [[nodiscard]] std::expected add(double value); [[nodiscard]] std::size_t count() const noexcept { return count_; } [[nodiscard]] double mean() const noexcept { return mean_; } [[nodiscard]] double sample_variance() const noexcept { return count_ > 1 ? m2_ / static_cast(count_ - 1) : 0; } private: std::size_t count_{}; double mean_{}, m2_{}; }; [[nodiscard]] std::expected box_hit(const Ray& ray, const Aabb& box); // Owns copied primitives and its index. Construction is transactional; no query // borrows the caller's span after build() returns. Binary median splits are an // educational baseline, not SAH, spatial splits, or a measured speed promise. class SceneIndex { public: [[nodiscard]] static std::expected build(std::span spheres); [[nodiscard]] std::expected, Error> closest(const Ray& ray) const; [[nodiscard]] std::expected, Error> linear_closest(const Ray& ray) const; [[nodiscard]] std::size_t node_count() const noexcept { return nodes_.size(); } private: struct Node { Aabb bounds; std::size_t first{}, count{}, left{}, right{}; }; std::size_t build_node(std::size_t first, std::size_t count); std::vector spheres_; std::vector nodes_; }; } // namespace lantern