// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later

/**
 * @file volume.hpp
 * @brief ボリュームレンダリング / 参加媒質 (DRW-61〜62)
 *
 * DRW-61: 均質参加媒質 (霧・ミスト)
 * DRW-62: 不均質ボリューム (煙・雲・炎)
 */

#ifndef CALX_IMAGE_RENDER_VOLUME_HPP
#define CALX_IMAGE_RENDER_VOLUME_HPP

#include <image/geometry/primitives.hpp>
#include <image/types/RGB.hpp>
#include <cmath>
#include <functional>
#include <algorithm>
#include <random>

namespace calx::image {

/// Henyey-Greenstein 位相関数
template<typename T>
T henyeyGreenstein(T cosTheta, T g) {
    constexpr T pi4 = T(4) * T(3.14159265358979323846);
    T g2 = g * g;
    T denom = T(1) + g2 - T(2) * g * cosTheta;
    return (T(1) - g2) / (pi4 * denom * std::sqrt(denom));
}

/// 均質参加媒質 (DRW-61)
template<typename T>
struct HomogeneousMedium {
    T sigmaA;  // 吸収係数
    T sigmaS;  // 散乱係数
    T g;       // 位相関数の非対称パラメータ [-1, 1]
    RGB<T> albedo{T(1), T(1), T(1)};  // 散乱アルベド (色)

    T sigmaT() const { return sigmaA + sigmaS; }

    /// Beer-Lambert 減衰
    RGB<T> transmittance(T distance) const {
        T t = std::exp(-sigmaT() * distance);
        return {t, t, t};
    }

    /// レイマーチング: 霧の効果を適用
    RGB<T> applyFog(const RGB<T>& surfaceColor, T distance,
                     const RGB<T>& fogColor = {T(0.7), T(0.7), T(0.8)}) const {
        T t = std::exp(-sigmaT() * distance);
        return surfaceColor * t + fogColor * (T(1) - t);
    }
};

/// 不均質ボリューム (DRW-62)
template<typename T>
struct HeterogeneousMedium {
    /// 密度関数: (x, y, z) → 密度 [0, 1]
    std::function<T(T, T, T)> densityField;

    T sigmaAMax;  // 最大吸収係数
    T sigmaSMax;  // 最大散乱係数
    T g = T(0);
    RGB<T> albedo{T(1), T(1), T(1)};
    RGB<T> emissionColor{T(0), T(0), T(0)};  // 発光色 (炎用)

    /// レイマーチングで色と透過率を計算
    /// origin → origin + dir * maxDist の間を stepSize でサンプリング
    RGB<T> raymarch(const Point3D<T>& origin, const Point3D<T>& dir,
                     T maxDist, T stepSize = T(0.1),
                     const RGB<T>& lightDir = {T(0), T(1), T(0)},
                     const RGB<T>& lightColor = {T(1), T(1), T(1)}) const {
        RGB<T> accum{T(0), T(0), T(0)};
        T transmittance = T(1);

        for (T t = T(0); t < maxDist && transmittance > T(0.01); t += stepSize) {
            auto p = origin + t * dir;
            T density = densityField ? densityField(p.x, p.y, p.z) : T(0);
            if (density <= T(0)) continue;

            T sigmaT = (sigmaAMax + sigmaSMax) * density;
            T dt = std::exp(-sigmaT * stepSize);

            // 発光
            accum = accum + emissionColor * density * transmittance * stepSize;

            // 散乱 (簡易: 光源方向の透過率)
            RGB<T> scatter = albedo * lightColor * density * sigmaSMax * transmittance * stepSize;
            accum = accum + scatter;

            transmittance *= dt;
        }
        return accum;
    }
};

} // namespace calx::image

#endif
