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

#pragma once

#include "BSDF.ih"

OSPRAY_BEGIN_ISPC_NAMESPACE

struct Velvety
{
  BSDF super;

  /*! The falloff of horizon scattering. 0 no falloff,
   *  and inf means maximum falloff. */
  float f;
};

inline BSDF_EvalRes Velvety_eval(
    const varying Velvety *uniform self, const vec3f &wo, const vec3f &wi)
{
  BSDF_EvalRes res;

  const float cosThetaO = clamp(dot(wo, getN(&self->super)));
  const float cosThetaI = clamp(dot(wi, getN(&self->super)));
  const float sinThetaO = sqrt(1.0f - cosThetaO * cosThetaO);
  const float horizonScatter = pow(sinThetaO, self->f);
  res.pdf = cosineSampleHemispherePDF(cosThetaI);
  res.value =
      (horizonScatter * cosThetaI * (float)one_over_pi) * self->super.albedo;
  return res;
}

inline BSDF_SampleRes Velvety_sample(
    const varying Velvety *uniform self, const vec3f &wo, const vec2f &s, float)
{
  BSDF_SampleRes res;

  const vec3f localDir = cosineSampleHemisphere(s);
  res.wi = getFrame(&self->super) * localDir;
  res.type = BSDF_DIFFUSE_REFLECTION;
  BSDF_EvalRes eval = Velvety_eval(self, wo, res.wi);
  res.pdf = eval.pdf;
  res.weight = eval.value * rcp(eval.pdf);
  return res;
}

inline void Velvety_Constructor(varying Velvety *uniform self,
    const varying linear3f *uniform frame,
    vec3f R,
    float f)
{
  BSDF_Constructor(
      &self->super, R, BSDF_DIFFUSE_REFLECTION, BSDF_TYPE_VELVETY, frame);

  self->f = f;
}

inline varying BSDF *uniform Velvety_create(uniform ShadingContext *uniform ctx,
    const varying linear3f *uniform frame,
    vec3f R,
    float f)
{
  varying Velvety *uniform self =
      (varying Velvety * uniform) ShadingContext_alloc(ctx, sizeof(Velvety));
  Velvety_Constructor(self, frame, R, f);
  return &self->super;
}

OSPRAY_END_ISPC_NAMESPACE
