#include "constants.h"
#include "artisoptions.h"

#ifndef TYPES_H
#define TYPES_H

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <time.h>
#ifndef __CUDA_ARCH__
#include <gsl/gsl_rng.h>
#endif
//#include <gsl/gsl_sf_expint.h>

struct time
{
  double start; // time at start of this timestep.
  double width; // Width of timestep.
  double mid; // Mid time in step - computed logarithmically.
  double gamma_dep; // cmf gamma ray energy deposition rate
  double positron_dep; // cmf positron energy deposition rate
  double electron_dep; // cmf positron energy deposition rate
  double alpha_dep; // cmf positron energy deposition rate
  double cmf_lum; // cmf luminosity light curve
  int pellet_decays; // Number of pellets that decay in this time step.
};

/// Coolinglist
///============================================================================
enum coolingtype {
  COOLINGTYPE_FF         = 880,
  COOLINGTYPE_FB         = 881,
  COOLINGTYPE_COLLEXC    = 882,
  COOLINGTYPE_COLLION    = 883,
};

typedef struct cellhistorycoolinglist_t
{
  enum coolingtype type;
  int element;
  int ion;
  int level;
  int upperlevel;
} cellhistorycoolinglist_t;

/*enum heatingtype {
  HEATINGTYPE_FF         = 884,
  HEATINGTYPE_BF         = 885,
  HEATINGTYPE_COLLDEEXC  = 886,
  HEATINGTYPE_COLLRECOMB = 887,
};*/

typedef struct heatingcoolingrates
{
  double cooling_collisional;
  double cooling_fb;
  double cooling_ff;
  double cooling_adiabatic;
  double heating_collisional;
  double heating_bf;
  double heating_ff;
  double heating_dep;
  double nt_frac_heating; // = heatingrates.gamma / total_gamma_deposition, = get_nt_frac_heating(modelgridindex) when T_e solver runs
} heatingcoolingrates_t;

/// PHIXSLIST

typedef struct fullphixslist_t
{
  double nu_edge;
  int element;
  int ion;
  int level;
  int phixstargetindex;
  int index_in_groundphixslist;
} fullphixslist_t;

typedef struct groundphixslist_t
{
  double nu_edge;
  //double photoion_contr;
  double gamma_contr;
  //double stimrecomb_contr;
  //double bfheating_contr;
  int element;
  int ion;
  int level;
  int phixstargetindex;
} groundphixslist_t;

typedef struct phixslist_t
{
  groundphixslist_t *groundcont;
  double *kappa_bf_contr;
#if (DETAILED_BF_ESTIMATORS_ON)
  double *gamma_contr;
#endif
} phixslist_t;

enum packet_type {
  TYPE_ESCAPE = 32,
  TYPE_RADIOACTIVE_PELLET = 100,
  TYPE_GAMMA = 10,
  TYPE_RPKT = 11,
  TYPE_KPKT = 12,
  TYPE_MA = 13,
  TYPE_NTLEPTON = 20,
  TYPE_PRE_KPKT = 120,
  TYPE_GAMMA_KPKT = 121,
};

enum cell_boundary {
  NEG_X = 101,
  POS_X = 102,
  NEG_Y = 103,
  POS_Y = 104,
  NEG_Z = 105,
  POS_Z = 106,
  NONE = 107,
};

typedef struct mastate_t
{
  int element;              /// macro atom of type element (this is an element index)
  int ion;                  /// in ionstage ion (this is an ion index)
  int level;                /// and level=level (this is a level index)
  int activatingline;       /// Linelistindex of the activating line for bb activated MAs, -99 else.
} mastate_t;

typedef struct packet
{
  int where;      /// The grid cell that the packet is in.
  enum packet_type type;       /// Identifies the type of packet (k-, r-, etc.)
  enum cell_boundary last_cross; /// To avoid rounding errors on cell crossing.
  int interactions;/// debug: number of interactions the packet undergone
  int nscatterings;   /// records number of electron scatterings a r-pkt undergone since it was emitted
  int last_event;  /// debug: stores information about the packets history
  double pos[3];  /// Position of the packet (x,y,z).
  double dir[3];  /// Direction of propagation. (x,y,z). Always a unit vector.
  double e_cmf;   /// The energy the packet carries in the co-moving frame.
  double e_rf;    /// The energy the packet carries in the rest frame.
  double nu_cmf;  /// The frequency in the co-moving frame.
  double nu_rf;   /// The frequency in the rest frame.
  int next_trans;  /// This keeps track of the next possible line interaction of a rpkt by storing
                   /// its linelist index (to overcome numerical problems in propagating the rpkts).
  int emissiontype;   /// records how the packet was emitted if it is a r-pkt
  double em_pos[3];   /// Position of the packet (x,y,z).
  int em_time;
  double prop_time; // internal clock to track how far in time the packet has been propagated
  int absorptiontype;     /// records linelistindex of the last absorption
                          /// negative values give ff-abs (-1), bf-abs (-2), compton scattering of gammas (-3),
                          /// photoelectric effect of gammas (-4), pair production of gammas (-5)
                          /// decaying pellets of the 52Fe chain (-6) and pellets which decayed before the
                          /// onset of the simulation (-7)
                          /// decay of a positron pellet (-10)
  int trueemissiontype;  // emission type coming from a kpkt to rpkt (last thermal emission)
  int trueem_time;
  double absorptionfreq;  /// records nu_cmf of packet at last absorption
  double absorptiondir[3]; /// Direction of propagation (x,y,z) when a packet was last absorbed in a line. Always a unit vector.
  //short timestep;
  double stokes[3]; //I, Q and U Stokes parameters
  double pol_dir[3]; //unit vector which defines the coordinate system against which Q and U are measured; should always be perpendicular to dir
  double tdecay;  /// Time at which pellet decays.
  enum packet_type escape_type; /// Flag to tell us in which form it escaped from the grid.
  int escape_time; /// Time at which is passes out of the grid.
                   /// Pos, dir, where, e_rf, nu_rf should all remain set at the exit point.
  int scat_count;  /// WHAT'S THAT???
  int number;     /// A unique number to identify which packet caused potential troubles.
  bool originated_from_particlenotgamma;    // first-non-pellet packet type was gamma
  int pellet_decaytype;           // index into decay::decaytypes
  int pellet_nucindex;           // nuclide index of the decaying species
  float trueemissionvelocity;
  mastate_t mastate;
} PKT;

enum ma_action {
  /// Radiative deexcitation rate from this level.
  MA_ACTION_RADDEEXC = 0,
  /// Collisional deexcitation rate from this level.
  MA_ACTION_COLDEEXC = 1,
  /// Radiative recombination from this level.
  MA_ACTION_RADRECOMB = 2,
  /// Collisional recombination rate from this level.
  MA_ACTION_COLRECOMB = 3,
  /// Rate for internal downward transitions to same ionisation stage.
  MA_ACTION_INTERNALDOWNSAME = 4,
  /// Rate for internal upward transitions to same ionisation stage.
  MA_ACTION_INTERNALDOWNLOWER = 5,
  /// Rate for internal downward transitions to lower ionisation stage.
  MA_ACTION_INTERNALUPSAME = 6,
  /// Rate for internal upward transitions to higher ionisation stage.
  MA_ACTION_INTERNALUPHIGHER = 7,
  /// Rate for internal upward transitions to higher ionisation stage due to non-thermal collisions.
  MA_ACTION_INTERNALUPHIGHERNT = 8,
  MA_ACTION_COUNT = 9,
};

/// GRID
///============================================================================
typedef struct compositionlist_entry
{
  float abundance;         /// Abundance of the element (by mass!).
  float *groundlevelpop;   /// Pointer to an array of floats which contains the groundlevel populations
                           /// of all included ionisation stages for the element.
  float *partfunct;        /// Pointer to an array of floats which contains the partition functions
                           /// of all included ionisation stages for the element.
  //float *ltepartfunct;     /// Pointer to an array of floats which contains the LTE partition functions
  //                         /// of all included ionisation stages for the element.
} compositionlist_entry;

typedef struct gridcell
{
  double pos_init[3]; /// Initial co-ordinates of inner most corner of cell.
  // int xyz[3];         /// Integer position of cell in grid.
  int modelgridindex;
} CELL;

typedef struct mgicooling_t
{
  double *contrib;
} mgicooling_t;

#define NSYN 1 /* number of frequency points in syn calculation */

enum ray_status {
  ACTIVE = 1,
  WAITING = 2,
  FINISHED = 3,
};

typedef struct syn_ray
{
  double tstart; /* time at which the ray enters the grid */
  double rstart[3]; /* vector position at which the ray enters the grid */
  double pos[3]; /* current position of the ray */
  double nu_rf[NSYN]; /*rest frame frequencies of rays */
  double nu_rf_init[NSYN]; /*rest frame frequencies of rays at start - for a test only */
  double nu_cmf[NSYN]; /*cmf freqencies */
  double e_rf[NSYN]; /*rest frame energy of rays */
  double e_cmf[NSYN]; /* cmf energies of rays */
  int where; /* the grid cell the ray is in */
  int lindex[NSYN]; /* array of ray positions in the line list */
  enum cell_boundary last_cross; /* last boundary crossed */
  enum ray_status status; /*WAITING, then ACTIVE then FINISHED*/
} RAY;

/// ATOMIC DATA
///============================================================================

typedef struct phixstarget_entry
{
  double *spontrecombcoeff;
  #if (!NO_LUT_PHOTOION)
    double *corrphotoioncoeff;
  #endif
  #if (!NO_LUT_BFHEATING)
  double *bfheating_coeff;
  #endif
  double *bfcooling_coeff;

  double probability;        // fraction of phixs cross section leading to this final level
  int levelindex;         // index of upper ion level after photoionisation
} phixstarget_entry;

typedef struct levellist_entry
{
  double epsilon;                            /// Excitation energy of this level relative to the neutral ground level.
  int *uptrans_lineindicies;    /// Allowed upward transitions from this level
  int *downtrans_lineindicies;  /// Allowed downward transitions from this level
  int nuptrans;
  int ndowntrans;
  double phixs_threshold;                    /// Energy of first point in the photion_xs table
  phixstarget_entry *phixstargets;  /// pointer to table of target states and probabilities
  float *photoion_xs;               /// Pointer to a lookup-table providing photoionisation cross-sections for this level.
  int nphixstargets;                         /// length of phixstargets array:
  float stat_weight;                           /// Statistical weight of this level.

  int cont_index;                            /// Index of the continuum associated to this level. Negative number.
#if (!NO_LUT_PHOTOION || !NO_LUT_BFHEATING)
  int closestgroundlevelcont;
#endif

  bool metastable;                            ///

//  double photoion_xs_nu_edge;              /// nu of the first grid point in the photoion_xs lookup-table.

//double *spontrecombcoeff_E;
//double *photoioncoeff_below;
//double *photoioncoeff_above;
//double *corrphotoioncoeff_above;
//double *bfheating_coeff_above;
//double *stimulated_bfcooling_coeff;
//double *stimulated_recomb_coeff;

//float *modified_spontrecombcoeff;
//float *stimrecombcoeff;
//float *modified_stimrecombcoeff;

///float population;
///float sahafact;
///float spontaneousrecomb_ratecoeff;
///float modifiedspontaneousrecomb_ratecoeff;
///float corrphotoion_ratecoeff;
///float modifiedcorrphotoion_ratecoeff;

/// time dependent macroatom event rates
//double rad_deexc;                          /// Radiative deexcitation rate from this level.
//double internal_down_same;                 /// Rate for internal downward transitions within the same ionisation stage.
//double internal_up_same;                   /// Rate for internal upward transitions within the same ionisation stage.

} levellist_entry;

typedef struct ionlist_entry
{
  levellist_entry *levels;                   /// Carries information for each level: 0,1,...,nlevels-1
  int ionstage;                              /// Which ionisation stage: XI=0, XII=1, XIII=2, ...
  int nlevels;                               /// Number of levels for this ionisation stage
  int nlevels_nlte;                          /// number of nlte levels for this ion
  int first_nlte;                            /// index into nlte_pops array of a grid cell
  int ionisinglevels;                        /// Number of levels which have a bf-continuum
  int maxrecombininglevel;                   /// level index of the highest level with a non-zero recombination rate
  int nlevels_groundterm;
  int coolingoffset;
  int ncoolingterms;
  int uniqueionindex;
  float *Alpha_sp;
  double ionpot;                             /// Ionisation threshold to the next ionstage
  //int nbfcontinua;
  //ionsphixslist_t *phixslist;
} ionlist_entry;

typedef struct elementlist_entry
{
  ionlist_entry *ions;              /// Carries information for each ion: 0,1,...,nions-1
  int nions;                                 /// Number of ions for the current element
  int anumber;                               /// Atomic number
//  int uppermost_ion;                       /// Highest ionisation stage which has a decent population for a given cell
                                             /// Be aware that this must not be used outside of the update_grid routine
                                             /// and their daughters. Neither it will work with OpenMP threads.
  float abundance;                           ///
  float mass;                                /// Atomic mass number in multiple of MH
} elementlist_entry;

typedef struct linelist_entry
{
  double nu;                                 /// Frequency of the line transition
  float einstein_A;
  float osc_strength;
  float coll_str;
  int elementindex;                        /// It's a transition of element (not its atomic number,
                                           /// but the (x-1)th element included in the simulation.
  int ionindex;                            /// The same for the elements ion
  int upperlevelindex;                     /// And the participating upper
  int lowerlevelindex;                     /// and lower levels
  bool forbidden;
} linelist_entry;

typedef struct bflist_t
{
  int elementindex;
  int ionindex;
  int levelindex;
  int phixstargetindex;
} bflist_t;

typedef struct nne_solution_paras
{
  int cellnumber;
} nne_solution_paras;

typedef struct gslintegration_paras
{
  double nu_edge;
  double T;
  float *photoion_xs;
} gslintegration_paras;

typedef struct rpkt_cont_opacity_struct
{
  double nu; // frequency at which opacity was calculated
  double total;
  double es;
  double ff;
  double bf;
  double ffheating;
  //double bfheating;
  int modelgridindex;
  bool recalculate_required; // e.g. when cell or timestep has changed
} rpkt_cont_opacity_struct;

/// Cell history
///============================================================================
// typedef struct coolinglist_contributions
// {
//   double contribution;
// } coolinglist_contributions;

typedef struct
{
  double corrphotoioncoeff;
#if (SEPARATE_STIMRECOMB)
  double stimrecombcoeff;
#endif
} chphixstargets_struct;

typedef struct chlevels_struct
{
  double processrates[MA_ACTION_COUNT];
  chphixstargets_struct *chphixstargets;
  double bfheatingcoeff;
} chlevels_struct;

typedef struct chions_struct
{
  chlevels_struct *chlevels;              /// Pointer to the ions levellist.
} chions_struct;

typedef struct chelements_struct
{
  chions_struct *chions;                  /// Pointer to the elements ionlist.
} chelements_struct;

typedef struct cellhistory_struct
{
  double *cooling_contrib;    /// Cooling contributions by the different processes.
  chelements_struct *chelements;            /// Pointer to a nested list which helds compositional
                                            /// information for all the elements=0,1,...,nelements-1
  int cellnumber;                           /// Identifies the cell the data is valid for.
  int bfheating_mgi;
} cellhistory_struct;

#endif //TYPES_H


/* vector/gsl_vector_long_double.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_VECTOR_LONG_DOUBLE_H__
#define __GSL_VECTOR_LONG_DOUBLE_H__

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_block_long_double.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  long double *data;
  gsl_block_long_double *block;
  int owner;
}
gsl_vector_long_double;

typedef struct
{
  gsl_vector_long_double vector;
} _gsl_vector_long_double_view;

typedef _gsl_vector_long_double_view gsl_vector_long_double_view;

typedef struct
{
  gsl_vector_long_double vector;
} _gsl_vector_long_double_const_view;

typedef const _gsl_vector_long_double_const_view gsl_vector_long_double_const_view;

/* Allocation */

gsl_vector_long_double *gsl_vector_long_double_alloc (const size_t n);
gsl_vector_long_double *gsl_vector_long_double_calloc (const size_t n);

gsl_vector_long_double *gsl_vector_long_double_alloc_from_block (gsl_block_long_double * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

gsl_vector_long_double *gsl_vector_long_double_alloc_from_vector (gsl_vector_long_double * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

void gsl_vector_long_double_free (gsl_vector_long_double * v);

/* Views */

_gsl_vector_long_double_view
gsl_vector_long_double_view_array (long double *v, size_t n);

_gsl_vector_long_double_view
gsl_vector_long_double_view_array_with_stride (long double *base,
                                         size_t stride,
                                         size_t n);

_gsl_vector_long_double_const_view
gsl_vector_long_double_const_view_array (const long double *v, size_t n);

_gsl_vector_long_double_const_view
gsl_vector_long_double_const_view_array_with_stride (const long double *base,
                                               size_t stride,
                                               size_t n);

_gsl_vector_long_double_view
gsl_vector_long_double_subvector (gsl_vector_long_double *v,
                            size_t i,
                            size_t n);

_gsl_vector_long_double_view
gsl_vector_long_double_subvector_with_stride (gsl_vector_long_double *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

_gsl_vector_long_double_const_view
gsl_vector_long_double_const_subvector (const gsl_vector_long_double *v,
                                  size_t i,
                                  size_t n);

_gsl_vector_long_double_const_view
gsl_vector_long_double_const_subvector_with_stride (const gsl_vector_long_double *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

void gsl_vector_long_double_set_zero (gsl_vector_long_double * v);
void gsl_vector_long_double_set_all (gsl_vector_long_double * v, long double x);
int gsl_vector_long_double_set_basis (gsl_vector_long_double * v, size_t i);

int gsl_vector_long_double_fread (FILE * stream, gsl_vector_long_double * v);
int gsl_vector_long_double_fwrite (FILE * stream, const gsl_vector_long_double * v);
int gsl_vector_long_double_fscanf (FILE * stream, gsl_vector_long_double * v);
int gsl_vector_long_double_fprintf (FILE * stream, const gsl_vector_long_double * v,
                              const char *format);

int gsl_vector_long_double_memcpy (gsl_vector_long_double * dest, const gsl_vector_long_double * src);

int gsl_vector_long_double_reverse (gsl_vector_long_double * v);

int gsl_vector_long_double_swap (gsl_vector_long_double * v, gsl_vector_long_double * w);
int gsl_vector_long_double_swap_elements (gsl_vector_long_double * v, const size_t i, const size_t j);

long double gsl_vector_long_double_max (const gsl_vector_long_double * v);
long double gsl_vector_long_double_min (const gsl_vector_long_double * v);
void gsl_vector_long_double_minmax (const gsl_vector_long_double * v, long double * min_out, long double * max_out);

size_t gsl_vector_long_double_max_index (const gsl_vector_long_double * v);
size_t gsl_vector_long_double_min_index (const gsl_vector_long_double * v);
void gsl_vector_long_double_minmax_index (const gsl_vector_long_double * v, size_t * imin, size_t * imax);

int gsl_vector_long_double_add (gsl_vector_long_double * a, const gsl_vector_long_double * b);
int gsl_vector_long_double_sub (gsl_vector_long_double * a, const gsl_vector_long_double * b);
int gsl_vector_long_double_mul (gsl_vector_long_double * a, const gsl_vector_long_double * b);
int gsl_vector_long_double_div (gsl_vector_long_double * a, const gsl_vector_long_double * b);
int gsl_vector_long_double_scale (gsl_vector_long_double * a, const long double x);
int gsl_vector_long_double_add_constant (gsl_vector_long_double * a, const long double x);
int gsl_vector_long_double_axpby (const long double alpha, const gsl_vector_long_double * x, const long double beta, gsl_vector_long_double * y);
long double gsl_vector_long_double_sum (const gsl_vector_long_double * a);

int gsl_vector_long_double_equal (const gsl_vector_long_double * u,
                            const gsl_vector_long_double * v);

int gsl_vector_long_double_isnull (const gsl_vector_long_double * v);
int gsl_vector_long_double_ispos (const gsl_vector_long_double * v);
int gsl_vector_long_double_isneg (const gsl_vector_long_double * v);
int gsl_vector_long_double_isnonneg (const gsl_vector_long_double * v);

INLINE_DECL long double gsl_vector_long_double_get (const gsl_vector_long_double * v, const size_t i);
INLINE_DECL void gsl_vector_long_double_set (gsl_vector_long_double * v, const size_t i, long double x);
INLINE_DECL long double * gsl_vector_long_double_ptr (gsl_vector_long_double * v, const size_t i);
INLINE_DECL const long double * gsl_vector_long_double_const_ptr (const gsl_vector_long_double * v, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
long double
gsl_vector_long_double_get (const gsl_vector_long_double * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

INLINE_FUN
void
gsl_vector_long_double_set (gsl_vector_long_double * v, const size_t i, long double x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

INLINE_FUN
long double *
gsl_vector_long_double_ptr (gsl_vector_long_double * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (long double *) (v->data + i * v->stride);
}

INLINE_FUN
const long double *
gsl_vector_long_double_const_ptr (const gsl_vector_long_double * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const long double *) (v->data + i * v->stride);
}
#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_LONG_DOUBLE_H__ */


// Copyright (C) 2015 Vincent Lejeune
// For conditions of distribution and use, see copyright notice in License.txt
#pragma once
#include <vulkan\vulkan.h>
#include <array>
#include <gsl/gsl>

#define CHECK_VKRESULT(cmd) { VkResult res = (cmd); if (res != VK_SUCCESS) throw; }

namespace structures
{
	constexpr VkAttachmentDescription attachment_description(
		VkFormat format,
		VkAttachmentLoadOp load_op,
		VkAttachmentStoreOp store_op,
		VkImageLayout initial_layout,
		VkImageLayout final_layout,
		VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT,
		VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
		VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE,
		VkAttachmentDescriptionFlags flag = 0)
	{
		return{ flag, format, sample_count, load_op, store_op, stencil_load_op, stencil_store_op, initial_layout, final_layout };
	}
}


#ifndef __GSL_MATRIX_H__
#define __GSL_MATRIX_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <gsl/gsl_matrix_complex_long_double.h>
#include <gsl/gsl_matrix_complex_double.h>
#include <gsl/gsl_matrix_complex_float.h>

#include <gsl/gsl_matrix_long_double.h>
#include <gsl/gsl_matrix_double.h>
#include <gsl/gsl_matrix_float.h>

#include <gsl/gsl_matrix_ulong.h>
#include <gsl/gsl_matrix_long.h>

#include <gsl/gsl_matrix_uint.h>
#include <gsl/gsl_matrix_int.h>

#include <gsl/gsl_matrix_ushort.h>
#include <gsl/gsl_matrix_short.h>

#include <gsl/gsl_matrix_uchar.h>
#include <gsl/gsl_matrix_char.h>

#endif /* __GSL_MATRIX_H__ */


#pragma once

#include <gsl/span>
#include "simple_math.h"

constexpr auto VECTOR_SIZE = sizeof(float) * 4;

class CBufferBase;

struct CBufferAlign
{
	size_t size;
	explicit CBufferAlign(size_t size_ = VECTOR_SIZE) : size(size_) {}
};

__forceinline CBufferAlign cbuff_align(size_t size = VECTOR_SIZE)
{
	return CBufferAlign(size);
}

class ICBuffer
{
public:
	virtual ~ICBuffer() = default;
	virtual void write(CBufferBase& cbuf) const = 0;

	size_t cbuffer_size() const;

	template <typename T>
	static size_t cbuffer_size()
	{
		T t;
		return t.cbuffer_size();
	}
};

class CBufferBase
{
protected:
	size_t offset_ = 0;
	size_t alignment_ = 0;

public:
	virtual ~CBufferBase() = default;
	bool align(size_t size = VECTOR_SIZE);
	void add(size_t size);
	void reset();

	size_t offset() const { return offset_; }
	size_t alignment() const { return alignment_; }

	template <typename T>
	CBufferBase& operator<<(const T& data) = delete;

	template <typename T>
	CBufferBase& operator<<(const gsl::span<T>& data) = delete;

	template <typename T>
	CBufferBase& operator<<(const gsl::span<const T>& data) = delete;

	CBufferBase& operator<<(const CBufferAlign& align_of);

	template <typename T, size_t size>
	__forceinline CBufferBase& operator<<(const std::array<T, size>& array)
	{
		return *this << gsl::span<const T>(array);
	}

	template <typename T, size_t size>
	__forceinline CBufferBase& operator<<(const T(&array)[size])
	{
		return *this << gsl::span<const T>(array);
	}

	template <typename T>
	__forceinline CBufferBase& operator<<(const dirty_t<T>& value)
	{
		return *this << value.data();
	}

	virtual void write(const void* data, size_t size)
	{
		align(size);
		add(size);
	}
};

template <>
CBufferBase& CBufferBase::operator<<(const int32_t& data);
template <>
CBufferBase& CBufferBase::operator<<(const uint32_t& data);
template <>
CBufferBase& CBufferBase::operator<<(const float& data);
template <>
CBufferBase& CBufferBase::operator<<(const DirectX::SimpleMath::Matrix& data);
template <>
CBufferBase& CBufferBase::operator<<(const DirectX::SimpleMath::Vector2& data);
template <>
CBufferBase& CBufferBase::operator<<(const DirectX::SimpleMath::Vector3& data);
template <>
CBufferBase& CBufferBase::operator<<(const DirectX::SimpleMath::Vector4& data);
template <>
CBufferBase& CBufferBase::operator<<(const gsl::span<float>& data);
template <>
CBufferBase& CBufferBase::operator<<(const gsl::span<const float>& data);

template <>
__forceinline CBufferBase& CBufferBase::operator<<(const DWORD& data)
{
	return *this << static_cast<uint32_t>(data);
}

template <>
__forceinline CBufferBase& CBufferBase::operator<<(const bool& data)
{
	return *this << (data ? 1 : 0);
}

class CBufferWriter : public CBufferBase
{
	uint8_t* ptr = nullptr;

public:
	CBufferWriter(uint8_t* ptr_);

private:
	void write(const void* data, size_t size) override;
};


#ifndef DART_META_H
#define DART_META_H

/*----- System Includes -----*/

#include <memory>
#include <gsl/gsl>
#include <type_traits>

/*----- Local Includes -----*/

#include "shim.h"

/*----- Type Declarations -----*/

namespace dart {

  namespace meta {

    template <class...>
    using void_t = void;

    template <class T>
    struct identity {
      using type = T;
    };

    // Removes one level of "pointer to const", "pointer to volatile"
    // "reference to const", "reference to volatile", etc,
    // to make working with strings easier.
    // Like std::decay except it doesn't decay C arrays,
    // but it otherwise much stronger.
    template <class T>
    struct canonical_type {
      using type = T;
    };
    template <class T>
    struct canonical_type<T const> {
      using type = T;
    };
    template <class T>
    struct canonical_type<T volatile> {
      using type = T;
    };
    template <class T>
    struct canonical_type<T const volatile> {
      using type = T;
    };
    template <class T>
    struct canonical_type<T&> {
      using type = T&;
    };
    template <class T>
    struct canonical_type<T const&> {
      using type = T&;
    };
    template <class T>
    struct canonical_type<T volatile&> {
      using type = T&;
    };
    template <class T>
    struct canonical_type<T const volatile&> {
      using type = T&;
    };
    template <class T>
    struct canonical_type<T*> {
      using type = T*;
    };
    template <class T>
    struct canonical_type<T const*> {
      using type = T*;
    };
    template <class T>
    struct canonical_type<T volatile*> {
      using type = T*;
    };
    template <class T>
    struct canonical_type<T const volatile*> {
      using type = T*;
    };
    template <class T, size_t len>
    struct canonical_type<T (&)[len]> {
      using type = T (&)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T const (&)[len]> {
      using type = T (&)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T volatile (&)[len]> {
      using type = T (&)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T const volatile (&)[len]> {
      using type = T (&)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T (*)[len]> {
      using type = T (*)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T const (*)[len]> {
      using type = T (*)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T volatile (*)[len]> {
      using type = T (*)[len];
    };
    template <class T, size_t len>
    struct canonical_type<T const volatile (*)[len]> {
      using type = T (*)[len];
    };
    template <class T>
    using canonical_type_t = typename canonical_type<T>::type;

    template <class T>
    struct is_ptr_to_const : std::false_type {};
    template <class T>
    struct is_ptr_to_const<T const*> : std::true_type {};

    // Create type traits to check for each type of comparison.
    template <class Lhs, class Rhs, class = void>
    struct are_comparable : std::false_type {};
    template <class Lhs, class Rhs>
    struct are_comparable<
      Lhs,
      Rhs,
      void_t<decltype(std::declval<Lhs>() == std::declval<Rhs>())>
    > : std::true_type {};

    template <class T, class = void>
    struct is_dereferenceable : std::false_type {};
    template <class T>
    struct is_dereferenceable<
      T,
      void_t<decltype(*std::declval<T>())>
    > : std::true_type {};

    template <class...>
    struct conjunction : std::true_type {};
    template <class B1>
    struct conjunction<B1> : B1 {};
    template <class B1, class... Bn>
    struct conjunction<B1, Bn...> :
      std::conditional_t<
        bool(B1::value),
        conjunction<Bn...>,
        B1
      >
    {};

    template <class...>
    struct disjunction : std::false_type {};
    template <class B1>
    struct disjunction<B1> : B1 {};
    template <class B1, class... Bn>
    struct disjunction<B1, Bn...> :
      std::conditional_t<
        bool(B1::value),
        B1,
        disjunction<Bn...>
      >
    {};

    template <class B>
    struct negation : std::integral_constant<bool, !bool(B::value)> {};

    template <class T, class... Ts>
    struct contained : disjunction<std::is_same<T, Ts>...> {};
    template <class T, class... Ts>
    struct not_contained : conjunction<negation<std::is_same<T, Ts>>...> {};

    template <class... Types>
    struct types {
      template <class T, class =
        std::enable_if_t<
          contained<T, Types...>::value
        >
      >
      types(T) {}
    };
    template <class... Types>
    struct not_types {
      template <class T, class =
        std::enable_if_t<
          not_contained<T, Types...>::value
        >
      >
      not_types(T) {}
    };

    template <class...>
    struct first_type {
      using type = void;
    };
    template <class T, class... Ts>
    struct first_type<T, Ts...> {
      using type = T;
    };
    template <class... Ts>
    using first_type_t = typename first_type<Ts...>::type;

    namespace detail {

      template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
      struct detector {
        using value_t = std::false_type;
        using type = Default;
      };

      template <class Default, template <class...> class Op, class... Args>
      struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
        // Note that std::void_t is a C++17 feature
        using value_t = std::true_type;
        using type = Op<Args...>;
      };

    }

    struct nonesuch {
      nonesuch(nonesuch const&) = delete;
      nonesuch(nonesuch&&) = delete;
      ~nonesuch() = delete;
    };

    template <template <class...> class Op, class... Args>
    using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
    template <template <class...> class Op, class... Args>
    using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
    template <class Default, template <class...> class Op, class... Args>
    using detected_or = detail::detector<Default, void, Op, Args...>;

    template <class T>
    using strv_t = decltype(std::declval<T>().strv());
    template <class T>
    using integer_t = decltype(std::declval<T>().integer());
    template <class T>
    using decimal_t = decltype(std::declval<T>().decimal());
    template <class T>
    using boolean_t = decltype(std::declval<T>().boolean());
    template <class T>
    using get_type_t = decltype(std::declval<T>().get_type());

    template <class T>
    struct is_dartlike :
      meta::conjunction<
        is_detected<strv_t, T>,
        is_detected<integer_t, T>,
        is_detected<decimal_t, T>,
        is_detected<boolean_t, T>,
        is_detected<get_type_t, T>
      >
    {};

    template <class T, template <class> class Template>
    struct is_specialization_of : std::false_type {};
    template <class... Args, template <class> class Template>
    struct is_specialization_of<Template<Args...>, Template> : std::true_type {};

    template <class T, template <template <class> class> class Compound>
    struct is_higher_specialization_of : std::false_type {};
    template <template <class> class Inner, template <template <class> class> class Outer>
    struct is_higher_specialization_of<Outer<Inner>, Outer> : std::true_type {};

    template <class T>
    struct is_span : std::false_type {};
#ifdef DART_USING_GSL_LITE
    template <class T>
    struct is_span<gsl::span<T>> : std::true_type {};
#else
    template <class T, std::size_t extent>
    struct is_span<gsl::span<T, extent>> : std::true_type {};
#endif

    template <class T>
    struct is_std_smart_ptr : std::false_type {};
    template <class T, class Del>
    struct is_std_smart_ptr<std::unique_ptr<T, Del>> : std::true_type {};
    template <class T>
    struct is_std_smart_ptr<std::shared_ptr<T>> : std::true_type {};
    template <class T>
    struct is_std_smart_ptr<std::weak_ptr<T>> : std::true_type {};

    template <size_t pos>
    struct priority_tag : priority_tag<pos - 1> {};
    template <>
    struct priority_tag<0> {};

    namespace detail {
      template <class T>
      struct is_builtin_string_impl : std::false_type {};
      template <>
      struct is_builtin_string_impl<char*> : std::true_type {};
      template <>
      struct is_builtin_string_impl<wchar_t*> : std::true_type {};
      template <>
      struct is_builtin_string_impl<char16_t*> : std::true_type {};
      template <>
      struct is_builtin_string_impl<char32_t*> : std::true_type {};
      template <size_t len>
      struct is_builtin_string_impl<char (&)[len]> : std::true_type {};
      template <size_t len>
      struct is_builtin_string_impl<wchar_t (&)[len]> : std::true_type {};
      template <size_t len>
      struct is_builtin_string_impl<char16_t (&)[len]> : std::true_type {};
      template <size_t len>
      struct is_builtin_string_impl<char32_t (&)[len]> : std::true_type {};
    }

    template <class T>
    struct is_builtin_string : detail::is_builtin_string_impl<canonical_type_t<T>> {};

    template <class T>
    struct is_std_string : std::false_type {};
    template <class CharT, class Traits, class Allocator>
    struct is_std_string<std::basic_string<CharT, Traits, Allocator>> : std::true_type {};

    template <class T>
    struct is_std_string_view : std::false_type {};
    template <class CharT, class Traits>
    struct is_std_string_view<shim::basic_string_view<CharT, Traits>> : std::true_type {};

    template <class T>
    struct is_string :
      meta::disjunction<
        is_builtin_string<T>,
        is_std_string<T>,
        is_std_string_view<T>
      >
    {};

    template <class T>
    struct spannable_value_type {
      template <class U>
      static typename U::value_type detect(priority_tag<1>);
      template <class U>
      static typename U::element_type detect(priority_tag<0>);
      template <class U>
      static nonesuch detect(...);
      using type = std::remove_cv_t<decltype(detect<T>(priority_tag<1> {}))>;
    };
    template <class T>
    using spannable_value_type_t = typename spannable_value_type<T>::type;
  }

}

#undef DART_COMPARE_HELPER

#endif


#include <bindings.cmacros.h>
#include <gsl/gsl_vector.h>

BC_INLINE2(GSL_COMPLEX_AT,gsl_vector_complex*,size_t,gsl_complex*)
BC_INLINE2(GSL_COMPLEX_FLOAT_AT,gsl_vector_complex_float*,size_t,gsl_complex_float*)
/* BC_INLINE2(GSL_COMPLEX_LONG_DOUBLE_AT,gsl_vector_complex_long_double*,size_t,gsl_complex_long_double*) */


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include "DrawableGameComponent.h"
#include "MatrixHelper.h"
#include "DirectionalLight.h"

namespace Library
{
	class ProxyModel;
	class AnimationPlayer;
	class Model;
	class AnimationClip;
}

namespace Rendering
{
	class SkinnedModelMaterial;

	class AnimationDemo final : public Library::DrawableGameComponent
	{
	public:
		AnimationDemo(Library::Game& game, const std::shared_ptr<Library::Camera>& camera);
		AnimationDemo(const AnimationDemo&) = delete;
		AnimationDemo(AnimationDemo&&) = default;
		AnimationDemo& operator=(const AnimationDemo&) = default;
		AnimationDemo& operator=(AnimationDemo&&) = default;
		~AnimationDemo();

		bool ManualAdvanceEnabled() const;
		void SetManualAdvanceEnabled(bool enabled);
		void ToggleManualAdvance();

		const std::unique_ptr<Library::AnimationPlayer>& AnimationPlayer() const;
		void TogglePause();
		void RestartClip();

		void IncrementCurrentKeyframe();
		void DecrementCurrentKeyframe();

		bool InterpolationEnabled() const;
		void SetInterpolationEnabled(bool enabled);
		void ToggleInterpolation();

		float AmbientLightIntensity() const;
		void SetAmbientLightIntensity(float intensity);

		float DirectionalLightIntensity() const;
		void SetDirectionalLightIntensity(float intensity);

		const DirectX::XMFLOAT3& LightDirection() const;
		void RotateDirectionalLight(DirectX::XMFLOAT2 amount);

		virtual void Initialize() override;
		virtual void Update(const Library::GameTime& gameTime) override;
		virtual void Draw(const Library::GameTime& gameTime) override;

	private:
		inline static const float RotationRate{ DirectX::XM_PI };

		std::shared_ptr<SkinnedModelMaterial> mMaterial;
		DirectX::XMFLOAT4X4 mWorldMatrix{ Library::MatrixHelper::Identity };
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		Library::DirectionalLight mDirectionalLight;
		std::unique_ptr<Library::ProxyModel> mProxyModel;
		bool mUpdateMaterial{ true };
		bool mUpdateMaterialBoneTransforms{ true };
		std::unique_ptr<Library::AnimationPlayer> mAnimationPlayer;
		bool mManualAdvanceEnabled{ false };
		std::shared_ptr<Library::Model> mSkinnedModel;
	};
}


#pragma once

#include "Availability.h"
#include "Library.h"
#include "OctreeTileID.h"
#include "TileAvailabilityFlags.h"

#include <gsl/span>

#include <cstddef>
#include <memory>
#include <vector>

namespace CesiumGeometry {

class CESIUMGEOMETRY_API OctreeAvailability final {
public:
  /**
   * @brief Constructs a new instance.
   *
   * @param subtreeLevels The number of levels in each subtree.
   * @param maximumLevel The index of the maximum level in this tileset.
   */
  OctreeAvailability(uint32_t subtreeLevels, uint32_t maximumLevel) noexcept;

  /**
   * @brief Determines the currently known availability status of the given
   * tile.
   *
   * @param tileID The {@link CesiumGeometry::OctreeTileID} for the tile.
   *
   * @return The {@link TileAvailabilityFlags} for this tile encoded into a
   * uint8_t.
   */
  uint8_t computeAvailability(const OctreeTileID& tileID) const noexcept;

  /**
   * @brief Attempts to add an availability subtree into the existing overall
   * availability tree.
   *
   * @param tileID The {@link CesiumGeometry::OctreeTileID} for the tile.
   * @param newSubtree The {@link CesiumGeometry::AvailabilitySubtree} to add.
   *
   * @return Whether the insertion was successful.
   */
  bool addSubtree(
      const OctreeTileID& tileID,
      AvailabilitySubtree&& newSubtree) noexcept;

  /**
   * @brief Determines the currently known availability status of the given
   * tile.
   *
   * Priming with a known parent subtree node avoids the need to traverse the
   * entire availability tree so far. The node must have a loaded subtree
   *
   * @param tileID The tile ID to get the availability for.
   * @param pNode The subtree node to look for the tileID in. The tileID should
   * be within this subtree node.
   *
   * @return The {@link TileAvailabilityFlags} for this tile encoded into a
   * uint8_t.
   */
  uint8_t computeAvailability(
      const OctreeTileID& tileID,
      const AvailabilityNode* pNode) const noexcept;

  /**
   * @brief Attempts to add a child subtree node onto the given parent node.
   *
   * Priming with a known parent subtree node avoids the need to traverse the
   * entire availability tree so far. If the parent node is nullptr and the
   * tile ID indicates this is the root tile, the subtree will be attached to
   * the root.
   *
   * @param tileID The root tile's ID of the subtree we are trying to add.
   * @param pParentNode The parent subtree node. The tileID should fall exactly
   * at the end of this parent subtree.
   *
   * @return The newly created node if the insertion was successful, nullptr
   * otherwise.
   */
  AvailabilityNode*
  addNode(const OctreeTileID& tileID, AvailabilityNode* pParentNode) noexcept;

  /**
   * @brief Attempts to add a loaded subtree onto the given node.
   *
   * The node must have been created earlier from a call to addNode.
   *
   * @param pNode The node on which to add the subtree.
   * @param newSubtree The new subtree to add.
   *
   * @return Whether the insertion was successful.
   */
  bool addLoadedSubtree(
      AvailabilityNode* pNode,
      AvailabilitySubtree&& newSubtree) noexcept;
  /**
   * @brief Find the child node index corresponding to this tile ID and parent
   * node.
   *
   * Attempts to find the child node for the tile with the given ID and parent
   * node. The parent node is used to speed up the search significantly. Note
   * that if the given tile ID does not correspond exactly to an immediate
   * child node of the parent node, nullptr will be returned. If a tileID
   * outside the given parent node's subtree is given, an incorrect child index
   * may be returned.
   *
   * @param tileID The tile ID of the child node we are looking for.
   * @param pParentNode The immediate parent to the child node we are looking
   * for.
   * @return The child node index if found, std::nullopt otherwise.
   */
  std::optional<uint32_t> findChildNodeIndex(
      const OctreeTileID& tileID,
      const AvailabilityNode* pParentNode) const;

  /**
   * @brief Find the child node corresponding to this tile ID and parent node.
   *
   * Attempts to find the child node for the tile with the given ID and parent
   * node. The parent node is used to speed up the search significantly. Note
   * that if the given tile ID does not correspond exactly to an immediate
   * child node of the parent node, nullptr will be returned. If a tileID
   * outside the given parent node's subtree is given, an incorrect child index
   * may be returned.
   *
   * @param tileID The tile ID of the child node we are looking for.
   * @param pParentNode The immediate parent to the child node we are looking
   * for.
   * @return The child node if found, nullptr otherwise.
   */
  AvailabilityNode* findChildNode(
      const OctreeTileID& tileID,
      AvailabilityNode* pParentNode) const;

  /**
   * @brief Gets the number of levels in each subtree.
   */
  constexpr inline uint32_t getSubtreeLevels() const noexcept {
    return this->_subtreeLevels;
  }

  /**
   * @brief Gets the index of the maximum level in this implicit tileset.
   */
  constexpr inline uint32_t getMaximumLevel() const noexcept {
    return this->_maximumLevel;
  }

  /**
   * @brief Gets a pointer to the root subtree node of this implicit tileset.
   */
  AvailabilityNode* getRootNode() noexcept { return this->_pRoot.get(); }

private:
  uint32_t _subtreeLevels;
  uint32_t _maximumLevel;
  uint32_t _maximumChildrenSubtrees;
  std::unique_ptr<AvailabilityNode> _pRoot;
};

} // namespace CesiumGeometry


#ifndef EMPHASIS_RINIT_H_INCLUDED
#define EMPHASIS_RINIT_H_INCLUDED

#include <nlopt.h>

#if (defined(_WIN32) || defined(__WIN32__)) && !defined(__LCC__)
#  define REMP_EXPORT extern "C" __declspec(dllexport)
#else
#  define REMP_EXPORT extern "C"
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* some function pointers into nlopt to be filled in by R */

REMP_EXPORT nlopt_opt(*remp_create)(nlopt_algorithm, unsigned);
REMP_EXPORT void(*remp_destroy)(nlopt_opt);
REMP_EXPORT nlopt_result(*remp_optimize)(nlopt_opt, double *, double *);
REMP_EXPORT nlopt_result(*remp_set_min_objective)(nlopt_opt, nlopt_func, void *);
REMP_EXPORT nlopt_result(*remp_set_max_objective)(nlopt_opt, nlopt_func, void *);
REMP_EXPORT nlopt_result(*remp_set_lower_bounds)(nlopt_opt, const double *);
REMP_EXPORT nlopt_result(*remp_set_lower_bounds1)(nlopt_opt, double);
REMP_EXPORT nlopt_result(*remp_set_upper_bounds)(nlopt_opt, const double *);
REMP_EXPORT nlopt_result(*remp_set_upper_bounds1)(nlopt_opt, double);
REMP_EXPORT nlopt_result(*remp_set_xtol_rel)(nlopt_opt, double);
REMP_EXPORT nlopt_result(*remp_set_xtol_abs)(nlopt_opt, double);

#ifdef __cplusplus
}
#endif

#endif