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

#pragma once

#include "DGEnum.h"
#include "rkcommon/math/vec.ih"

OSPRAY_BEGIN_ISPC_NAMESPACE

struct Material;
struct Renderer;

/* differential geometry information that gives more detailed
   information on the actual geometry that a ray has hit */
struct DifferentialGeometry
{
  vec3f P; // world space location of the hit-point, includes epsilon offset
           // towards front side
  vec3f lP; // local instance space location of the hit-point
  vec3f Ng; // geometry normal if DG_NG was set, possibly not
            // normalized/facefordwarded if DG_NORMALIZE and/or DG_FACEFORWARD
            // weren't specified
  vec3f Ns; // shading normal if DG_NS was set, possibly not
            // normalized/facefordwarded if DG_NORMALIZE and/or DG_FACEFORWARD
            // weren't specified
  vec3f dPds; // tangent, the partial derivative of the hit-point wrt. tc s
  vec3f dPdt; // bi-tangent, the partial derivative of the hit-point wrt. tc t
  vec2f st; // texture coordinates if DG_TEXCOORD was set
  vec4f color; // interpolated vertex color (rgba) if DG_COLOR was set; defaults
               // to vec4f(1.f) if queried but not present in geometry
  int32 primID; // hit primitive (-1 if no hit), e.g. for Ptex

  float areaPDF; // for geometryLights
  float epsilon; // adaptive epsilon, isotropic in object-space

  Material *material; // pointer to hit-point's material
  const Renderer *uniform renderer; // pointer to renderer being used
  unsigned int objID; // user definable model id (0xffff none)
  unsigned int instID; // user definable instance id (0xffff none)

  float pixelFootprint; // 1:1 mapping between pixels and texels
};

// assumed precision of intersection routines
#define ulpEpsilon 0x1.0fp-21f

inline float calcEpsilon(const vec3f &P, float t)
{
  return reduce_max(make_vec4f(abs(P), t)) * ulpEpsilon;
}

inline float calcEpsilon(const vec3f &P, const vec3f &dir, float t)
{
  // convert ray-space t to object-/world-space using max(dir) instead of
  // costly length; the error is at most sqrt(3)~1.7, quite acceptable for eps
  return calcEpsilon(P, reduce_max(abs(dir)) * t);
}

OSPRAY_END_ISPC_NAMESPACE
