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

#pragma once

// ospray
#include "rkcommon/math/AffineSpace.ih"
#include "rkcommon/math/vec.ih"
// embree
#include "Embree.h"

OSPRAY_BEGIN_ISPC_NAMESPACE

// NOTE(jda) - this MUST match Embree's RayHit structure layout!
struct Ray
{
  /* ray input data */
  vec3f org; /*!< ray origin */
  float t0; /*!< start of valid ray interval */

  vec3f dir; /*!< ray direction */
  float time; //!< Time of this ray for motion blur, in 0..1

  float t; /*!< end of valid ray interval, or distance to hit point after
              'intersect' */
  uint32 mask; //!< Used to mask out objects during traversal
  uint32 rayID;
  uint32 flags;

  /* hit data */
  vec3f Ng; /*! geometry normal*/

  float u; //!< Barycentric u coordinate of hit
  float v; //!< Barycentric v coordinate of hit

  uint32 primID; //!< primitive ID
  uint32 geomID; //!< geometry ID
  uint32 instID; //!< instance ID
#ifdef RTC_GEOMETRY_INSTANCE_ARRAY
  uint32 instPrimID; // not used, but need to pad
#endif
};

// Hit query functions ////////////////////////////////////////////////////////

inline bool noHit(const Ray &ray)
{
  return ray.geomID == RTC_INVALID_GEOMETRY_ID;
}

inline bool hadHit(const Ray &ray)
{
  return !noHit(ray);
}

// Ray initialization /////////////////////////////////////////////////////////

inline void setRay(Ray &ray,
    const vec3f &ray_org,
    const vec3f &ray_dir,
    const float t0,
    const float t1,
    const float time = 0.5f)
{
  ray.org = ray_org;
  ray.dir = ray_dir;
  ray.t0 = t0;
  ray.t = t1;
  ray.time = time;
  ray.mask = -1;
  ray.geomID = RTC_INVALID_GEOMETRY_ID;
  ray.primID = RTC_INVALID_GEOMETRY_ID;
  ray.instID = RTC_INVALID_GEOMETRY_ID;
}

inline void setRay(Ray &ray,
    const vec3f &ray_org,
    const vec3f &ray_dir,
    const float time = 0.5f)
{
  setRay(ray, ray_org, ray_dir, 0.f, inf, time);
}

inline void setRay(Ray &ray, const float t0, const float t1)
{
  setRay(ray, ray.org, ray.dir, t0, t1, ray.time);
}

// Ray transformation helpers /////////////////////////////////////////////////

inline void transformRay(Ray &ray, const AffineSpace3f &xfm)
{
  ray.org = xfmPoint(xfm, ray.org);
  ray.dir = xfmVector(xfm, ray.dir);
  ray.Ng = xfmVector(transposed(xfm.l), ray.Ng);
}

OSPRAY_END_ISPC_NAMESPACE
