/***************************************************************************
 *                                                                         *
 * Module  : nhsbary.h                                                     *
 *                                                                         *
 * Purpose : Barycentric operations                                        *
 *                                                                         *
 **************************************************************************/

#ifndef NHSBARY_H
#define NHSBARY_H

/****************************************************************************
 Includes
 */

#include "rwcore.h"
#include "rpdbgerr.h"

/****************************************************************************
 Global types
 */

typedef double RwDReal;

typedef struct RwDV3d RwDV3d;
struct RwDV3d
{
    RwDReal x;
    RwDReal y;
    RwDReal z;
};

typedef RwDReal      RtDV4d[4];
typedef RtDV4d       RtDM4d[4];

/****************************************************************************
 Defines
 */

#define _AREA2_EPSILON (((RwReal)1)/((RwReal)(1<<12)))
#define  _AREA_EPSILON (((RwReal)1)/((RwReal)(1<<6)))

#if (defined(RWDEBUG) && defined(RWVERBOSE))
#define RWMONITOR(_x) RWMESSAGE(_x)
#endif /* (defined(RWDEBUG) && defined(RWVERBOSE)) */

#if (!defined(RWMONITOR))
#define RWMONITOR(_x)          /* No op */
#endif /* (!defined(RWMONITOR)) */

#if (!defined(BARY_EPSILON))
#define BARY_EPSILON (((RwReal)1)/((RwReal)(1<<10)))
#endif /* (!defined(BARY_EPSILON)) */

#define WithinEpsilonOfZero(_x, _epsilon) \
   ((-(_epsilon) < (_x)) && ((_x) < (_epsilon)))

#define _rtImportWorldCartFromBaryMacro(_out, _b, _v0, _v1, _v2)        \
MACRO_START                                                             \
{                                                                       \
    (_out)->x = (RwReal)( ((_v0)->x * (_b)[0]) +                        \
                          ((_v1)->x * (_b)[1]) +                        \
                          ((_v2)->x * (_b)[2]) );                       \
    (_out)->y = (RwReal)( ((_v0)->y * (_b)[0]) +                        \
                          ((_v1)->y * (_b)[1]) +                        \
                          ((_v2)->y * (_b)[2]) );                       \
    (_out)->z = (RwReal)( ((_v0)->z * (_b)[0]) +                        \
                          ((_v1)->z * (_b)[1]) +                        \
                          ((_v2)->z * (_b)[2]) );                       \
}                                                                       \
MACRO_STOP

#define _rtImportWorldBaryFromCartMacro(_out, _m, _in)  \
MACRO_START                                             \
{                                                       \
    (_out)[0] = ( (_m)[0][0] * (_in)->x +               \
                  (_m)[1][0] * (_in)->y +               \
                  (_m)[2][0] * (_in)->z +               \
                  (_m)[3][0] );                         \
    (_out)[1] = ( (_m)[0][1] * (_in)->x +               \
                  (_m)[1][1] * (_in)->y +               \
                  (_m)[2][1] * (_in)->z +               \
                  (_m)[3][1] );                         \
    (_out)[2] = ( (_m)[0][2] * (_in)->x +               \
                  (_m)[1][2] * (_in)->y +               \
                  (_m)[2][2] * (_in)->z +               \
                  (_m)[3][2] );                         \
    (_out)[3] = ( (_m)[0][3] * (_in)->x +               \
                  (_m)[1][3] * (_in)->y +               \
                  (_m)[2][3] * (_in)->z +               \
                  (_m)[3][3] );                         \
}                                                       \
MACRO_STOP

#define _rtImportWorldBaryFromEdgeMacro(_out, _m, _in)          \
MACRO_START                                                     \
{                                                               \
    (_out)[0] = ( (_m)[0][0] * (_in)->x +                       \
                  (_m)[1][0] * (_in)->y +                       \
                  (_m)[2][0] * (_in)->z );                      \
    (_out)[1] = ( (_m)[0][1] * (_in)->x +                       \
                  (_m)[1][1] * (_in)->y +                       \
                  (_m)[2][1] * (_in)->z );                      \
    (_out)[2] = ( (_m)[0][2] * (_in)->x +                       \
                  (_m)[1][2] * (_in)->y +                       \
                  (_m)[2][2] * (_in)->z );                      \
    (_out)[3] = ( (_m)[0][3] * (_in)->x +                       \
                  (_m)[1][3] * (_in)->y +                       \
                  (_m)[2][3] * (_in)->z );                      \
}                                                               \
MACRO_STOP

#if (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ))

#define _rtImportWorldCartFromBary(_out, _b, _v0, _v1, _v2)     \
        _rtImportWorldCartFromBaryMacro(_out, _b, _v0, _v1, _v2)

#define _rtImportWorldBaryFromCart(_out, _m, _in)               \
        _rtImportWorldBaryFromCartMacro(_out, _m, _in)

#define _rtImportWorldBaryFromEdge(_out, _m, _in)               \
        _rtImportWorldBaryFromEdgeMacro(_out, _m, _in)

#endif /* (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )) */


/****************************************************************************
 Function prototypes
 */

#ifdef    __cplusplus
extern              "C"
{
#endif                          /* __cplusplus */

extern              RwBool
_rtImportBarycentricFromCartesianMatrix(RtDM4d m,
                                        RwReal * const area,
                                        const RwV3d * const c0,
                                        const RwV3d * const c1,
                                        const RwV3d * const c2);

#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )

extern void
_rtImportWorldCartFromBary(RwV3d *out, RtDV4d weights,
                           RwV3d *v0, RwV3d *v1, RwV3d *v2);

extern void
_rtImportWorldBaryFromCart(RtDV4d out,
                           RtDM4d mat,
                           const RwV3d * const in);

extern void
_rtImportWorldBaryFromEdge(RtDV4d out,
                           RtDM4d mat,
                           const RwV3d * const in);

#endif /* ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ) */

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#endif                          /* NHSBARY_H */
