// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "Noise.ih"
#include "render/bsdfs/BeckmannDistribution.ih"

OSPRAY_BEGIN_ISPC_NAMESPACE

struct Flakes
{
  float scale;
  float density;
  float spread;
  float jitter;
};

inline vec3f Flakes_eval(const Flakes &self, vec3f P, int &mask)
{
  vec3f N = make_vec3f(0.f, 0.f, 1.f);
  mask = 0;

  if (self.density <= 0.f || self.spread <= 0.f)
    return N;

  const BeckmannDistribution flakeDistribution =
      make_BeckmannDistribution(roughnessToAlpha(self.spread));
  P = P * self.scale;

  // Simple Worley cellular noise with jittered feature points
  // [Apodaca and Gritz, 1999, "Advanced RenderMan: Creating CGI for Motion
  // Pictures", pp. 255-261]
  const vec3f thisCell = floor(P) + 0.5f;
  float f1 = 1000.f;
  unsigned int cellRnd;

  for (int i = -1; i <= 1; i++) {
    for (int j = -1; j <= 1; j++) {
      for (int k = -1; k <= 1; k++) {
        const vec3f testCell = thisCell + make_vec3f(i, j, k);

        // generate a random ID for the test cell
        unsigned int rnd = cellNoise1ui(testCell);

        // generate the position of the feature point in the test cell
        const vec3f pos = testCell + self.jitter * (LCG_getFloat3(rnd) - 0.5f);

        // distance test
        const vec3f offset = pos - P;
        const float dist = dot(offset, offset); // actually dist^2
        if (dist < f1) {
          f1 = dist;
          cellRnd = rnd;
        }
      }
    }
  }

  // test whether the flake exists
  if (LCG_getFloat(cellRnd) <= self.density) {
    // generate a random normal for the flake
    float pdf;
    N = sample(flakeDistribution, pdf, LCG_getFloat2(cellRnd));
    mask = 1;
  }

  return normalize(N);
}

OSPRAY_END_ISPC_NAMESPACE
