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

#pragma once

#include "BSDF.ih"
#include "GGXDistribution.ih"

OSPRAY_BEGIN_ISPC_NAMESPACE

// Oren-Nayar BRDF.
// [Fujii, 2012, "A tiny improvement of Oren-Nayar reflectance model"]
struct OrenNayar
{
  BSDF super;

  float roughness;
};

inline BSDF_EvalRes OrenNayar_eval(
    const varying BSDF *uniform super, const vec3f &wo, const vec3f &wi)
{
  const varying OrenNayar *uniform self =
      (const varying OrenNayar *uniform)super;
  BSDF_EvalRes res;

  float cosThetaO = max(dot(wo, getN(super)), 0.f);
  float cosThetaI = max(dot(wi, getN(super)), 0.f);

  float s = dot(wo, wi) - cosThetaO * cosThetaI;
  float sInvt = (s > 0.f) ? (s * rcp_safe(max(cosThetaO, cosThetaI))) : s;
  res.value = self->super.albedo
      * (cosThetaI * (1.f + self->roughness * sInvt)
          * rcp((float)pi + ((float)pi / 2.f - 2.f / 3.f) * self->roughness));
  res.pdf = cosineSampleHemispherePDF(cosThetaI);
  return res;
}

inline BSDF_SampleRes OrenNayar_sample(
    const varying BSDF *uniform super, const vec3f &wo, const vec2f &s, float)
{
  const vec3f localDir = cosineSampleHemisphere(s);
  BSDF_SampleRes res;
  res.wi = getFrame(super) * localDir;
  BSDF_EvalRes eval = OrenNayar_eval(super, wo, res.wi);
  res.pdf = eval.pdf;
  res.type = BSDF_DIFFUSE_REFLECTION;
  res.weight = eval.value * rcp(eval.pdf);
  return res;
}

inline void OrenNayar_Constructor(varying OrenNayar *uniform self,
    const varying linear3f *uniform frame,
    const vec3f &R,
    float roughness)
{
  BSDF_Constructor(
      &self->super, R, BSDF_DIFFUSE_REFLECTION, BSDF_TYPE_OREN_NAYAR, frame);

  self->roughness = roughness;
}

inline varying BSDF *uniform OrenNayar_create(
    uniform ShadingContext *uniform ctx,
    const varying linear3f *uniform frame,
    const vec3f &R,
    float roughness)
{
  varying OrenNayar *uniform self = (varying OrenNayar * uniform)
      ShadingContext_alloc(ctx, sizeof(OrenNayar));
  OrenNayar_Constructor(self, frame, R, roughness);
  return &self->super;
}

OSPRAY_END_ISPC_NAMESPACE
