// Copyright (c) 2021 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.
//
#include <OgnPerturbPointsDatabase.h>
#include <cstdlib>

namespace omni {
namespace graph {
namespace test {

// This is the implementation of the OGN node defined in OgnPerturbPoints.ogn
class OgnPerturbPoints
{
    static auto& copy(OgnPerturbPointsDatabase& db)
    {
        CARB_PROFILE_ZONE(carb::profiler::kCaptureMaskDefault, "Acquiring Data");
        db.outputs.points = db.inputs.points;
        return db.outputs.points();
    }
public:
    // Perturb an array of points by random amounts within the limits of the bounding cube formed by the diagonal
    // corners "minimum" and "maximum".
    static bool compute(OgnPerturbPointsDatabase& db)
    {
        const auto& minimum = db.inputs.minimum();
        GfVec3f rangeSize = db.inputs.maximum() - minimum;

        // No points mean nothing to perturb
        const auto& inputPoints = db.inputs.points();
        size_t pointCount = inputPoints.size();
        if (pointCount == 0)
        {
            return true;
        }

        // How much of the surface should be perturbed
        auto percentModified = db.inputs.percentModified();
        percentModified = (percentModified > 100.0f ? 100.0f : (percentModified < 0.0f ? 0.0f : percentModified));
        size_t pointsToModify = (size_t)((percentModified * (float)pointCount) / 100.0f);

        auto& pointArray = copy(db);

        CARB_PROFILE_ZONE(carb::profiler::kCaptureMaskDefault, "Perturbing Data");
        size_t index{ 0 };
        while (index < pointsToModify)
        {
            auto& point = pointArray[index++];
            GfVec3f offset{
                minimum[0] + static_cast<float>(rand()) / (static_cast<float>(RAND_MAX/(rangeSize[0]))),
                minimum[1] + static_cast<float>(rand()) / (static_cast<float>(RAND_MAX/(rangeSize[1]))),
                minimum[2] + static_cast<float>(rand()) / (static_cast<float>(RAND_MAX/(rangeSize[2])))
            };

            point = point + offset;
        }

        return true;
    }
};

REGISTER_OGN_NODE()

} // namespace test
} // namespace graph
} // namespace omni
