// Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include <omni/math/linalg/vec.h>

#include <carb/settings/ISettings.h>

namespace omni
{
namespace kit
{
namespace raycastquery
{

inline void adjustRayToSection(Ray& ray)
{
    static constexpr char kSectionEnabledSettingPath[] = "/rtx/sectionPlane/enabled";
    static constexpr char kSectionPlaneSettingPath[] = "/rtx/sectionPlane/plane";

    auto settings = carb::getCachedInterface<carb::settings::ISettings>();
    if (!settings->get<bool>(kSectionEnabledSettingPath))
    {
        return;
    }

    using namespace omni::math::linalg;

    vec4<float> plane;
    settings->getAsFloatArray(kSectionPlaneSettingPath, &plane[0], 4);

    vec3 const planeNormal(plane[0], plane[1], plane[2]);

    vec4 const rayOrigin4(ray.origin.x, ray.origin.y, ray.origin.z, 1.f);
    vec3 const rayDir(ray.direction.x, ray.direction.y, ray.direction.z);

    float const originPlaneDistance = -rayOrigin4.Dot(plane);
    bool const originCulled = originPlaneDistance > 0.f;
    float const dirNormalCos = rayDir.Dot(planeNormal);

    bool const sameNormalDirection = dirNormalCos > 0.f;
    float const rayDist = (dirNormalCos != 0) ? (originPlaneDistance / dirNormalCos) : ray.maxT;

    if (originCulled)
    {
        if (sameNormalDirection)
        {
            // move minT so it's starting from the section plane.
            ray.minT = ray.minT > rayDist ? ray.minT : rayDist;
        }
        else
        {
            // the entire ray is culled.
            ray.minT = ray.maxT = std::numeric_limits<float>::infinity();
        }
    }
    else
    {
        if (sameNormalDirection)
        {
            // the entire ray is within non-culled section, no adjustment needed
        }
        else
        {
            // move maxT so it ends on the section plane
            ray.maxT = ray.maxT < rayDist ? ray.maxT : rayDist;
        }
    }
}
}
}
}
