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

#pragma once

#define _CRT_SECURE_NO_WARNINGS

/* size of screen tiles */
#define TILE_SIZE_X 8
#define TILE_SIZE_Y 8

/* vertex and triangle layout */
struct Vertex   { float x,y,z,r;  }; // FIXME: rename to Vertex4f
struct Triangle { int v0, v1, v2; };

/* include embree API */
#include "../../../include/embree3/rtcore.isph"
RTC_NAMESPACE_USE

/* include optional vector library */
#include "../math/math.isph"
#include "../math/vec.isph"
#include "../math/affinespace.isph"
#include "../core/ray.isph"
#include "camera.isph"
#include "scene_device.h"
#include "noise.isph"
#if !defined(ISPC)
#include "../../../common/algorithms/parallel_for.h"
#endif

enum Mode {
  MODE_NORMAL = 0,
  MODE_STREAM = 1
};

extern RTCDevice g_device;
extern uniform Mode g_mode;
extern uniform RTCIntersectContextFlags g_iflags_coherent;
extern uniform RTCIntersectContextFlags g_iflags_incoherent;

/* error reporting function */
unmasked void error_handler(void* uniform userPtr, uniform RTCError code, const uniform int8* uniform str = NULL);

/* returns time stamp counter */
extern "C" uniform int64 get_tsc();

/* declare some standard library functions */
extern "C" void abort ();
extern "C" void exit(uniform int);
extern "C" uniform int puts ( const uniform int8* uniform str );
extern "C" uniform int putchar ( uniform int character );

/* face forward for shading normals */
inline Vec3f faceforward( const Vec3f& N, const Vec3f& I, const Vec3f& Ng ) {
  Vec3f NN = N; return dot(I, Ng) < 0 ? NN : neg(NN);
}

/* GLFW keys codes */
#if !defined(GLFW_KEY_F1)
#define GLFW_KEY_F1                 290
#define GLFW_KEY_F2                 291
#define GLFW_KEY_F3                 292
#define GLFW_KEY_F4                 293
#define GLFW_KEY_F5                 294
#define GLFW_KEY_F6                 295
#define GLFW_KEY_F7                 296
#define GLFW_KEY_F8                 297
#define GLFW_KEY_F9                 298
#define GLFW_KEY_F10                299
#define GLFW_KEY_F11                300
#define GLFW_KEY_F12                301
#endif

extern void device_key_pressed_default(uniform int key);
extern void (* uniform key_pressed_handler)(uniform int key);

export void renderFrameStandard(uniform int* uniform pixels,
                         const uniform unsigned int width,
                         const uniform unsigned int height,
                         const uniform float time,
                         const uniform ISPCCamera& camera);

uniform unsigned int getNumHWThreads();

#if defined(ISPC)
#define ALIGNED_STRUCT_(x)
#define __aligned(x)
#define MAYBE_UNUSED
#endif

/* draws progress bar */
extern "C" unmasked void progressStart();
extern "C" unmasked uniform bool progressMonitor(void* uniform ptr, const uniform double n);
extern "C" unmasked void progressEnd();

Vec2f  getTextureCoordinatesSubdivMesh(void* uniform mesh, const unsigned int primID, const float u, const float v);

float  getTextureTexel1f(const uniform Texture* uniform texture, float u, float v);
Vec3f  getTextureTexel3f(const uniform Texture* uniform texture, float u, float v);

enum ISPCInstancingMode { ISPC_INSTANCING_NONE, ISPC_INSTANCING_GEOMETRY, ISPC_INSTANCING_GROUP };

/* ray statistics */
#if !defined(TASKING_PPL) // not supported with PPL because threadIndex is not unique and atomics are too expensive
#define RAY_STATS
#endif

struct RayStats
{
  int numRays;
  int pad[32-1];
};

#if defined(RAY_STATS)
#if defined(ISPC)
inline void RayStats_addRay(uniform RayStats& stats)       { stats.numRays += popcnt(lanemask()); }
inline void RayStats_addShadowRay(uniform RayStats& stats) { stats.numRays += popcnt(lanemask()); }
#else // C++
__forceinline void RayStats_addRay(RayStats& stats)        { stats.numRays++; }
__forceinline void RayStats_addShadowRay(RayStats& stats)  { stats.numRays++; }
#endif
#else // disabled
inline void RayStats_addRay(uniform RayStats& stats)       {}
inline void RayStats_addShadowRay(uniform RayStats& stats) {}
#endif

extern uniform RayStats* uniform g_stats;

inline bool nativePacketSupported(RTCDevice device)
{
  if (sizeof(float) == 1*4) return true;
  else if (sizeof(float) == 4*4) return rtcGetDeviceProperty(device,RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED);
  else if (sizeof(float) == 8*4) return rtcGetDeviceProperty(device,RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED);
  else if (sizeof(float) == 16*4) return rtcGetDeviceProperty(device,RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED);
  else return false;
}
