/*===========================================================================*
 *                                                                           *
 *   Module  :   rppatch.h                                                   *
 *                                                                           *
 *   Purpose :   General patch handling.                                     *
 *                                                                           *
 *===========================================================================*/

/**
 * \defgroup rppatch RpPatch
 * \ingroup rpplugin
 *
 * Bezier patch library
 *
 * This library provides efficient evaluation of patches.
 */

#ifndef RPPATCH_H
#define RPPATCH_H

/*===========================================================================*
 * -- Include files -------------------------------------------------------- *
 *===========================================================================*/
#include "rwcore.h"
#include "rpworld.h"

#include "rpcriter.h"
#include "rppatch.rpe"

/*===========================================================================*
 * -- Defines -------------------------------------------------------------- *
 *===========================================================================*/

/**
 * \ingroup rppatch
 * \ref rpQUADPATCHNUMCONTROLPOINTS defines the number of control points in
 * a quadrilateral patch.
 *
 * \see RpQuadPatch
 * \see rpQUADPATCHNUMCONTROLINDICES
 * \see RpPatchMeshSetQuadPatch
 */
#define rpQUADPATCHNUMCONTROLPOINTS (16)

/**
 * \ingroup rppatch
 * \ref rpTRIPATCHNUMCONTROLPOINTS defines the number of control points in
 * a triangle patch.
 *
 * \see RpTriPatch
 * \see rpTRIPATCHNUMCONTROLINDICES
 * \see RpPatchMeshSetTriPatch
 */
#define rpTRIPATCHNUMCONTROLPOINTS (10)

/**
 * \ingroup rppatch
 * \ref rpQUADPATCHNUMCONTROLINDICES defines the number of control points
 * indices in a \ref RpQuadPatch quadrilateral patch.
 *
 * \see rpQUADPATCHNUMCONTROLPOINTS
 * \see RpPatchMeshSetQuadPatch
 */
#define rpQUADPATCHNUMCONTROLINDICES rpQUADPATCHNUMCONTROLPOINTS

/**
 * \ingroup rppatch
 * \ref rpTRIPATCHNUMCONTROLINDICES defines the number of control points
 * indices in a \ref RpTriPatch triangle patch.
 *
 * \see rpTRIPATCHNUMCONTROLPOINTS
 * \see RpPatchMeshSetTriPatch
 */
#define rpTRIPATCHNUMCONTROLINDICES rpTRIPATCHNUMCONTROLPOINTS

/**
 * \ingroup rppatch
 * \ref rpPATCHLODMAXVALUE defines the maximum value that can be returned for
 * the patch evaluation level of detail.
 *
 * \see rpPATCHSKINLODMAXVALUE
 * \see rpPATCHLODMINVALUE
 * \see RpPatchLODCallBack
 */
#define rpPATCHLODMAXVALUE (20)

/**
 * \ingroup rppatch
 * \ref rpPATCHSKINLODMAXVALUE defines the maximum value that can be returned
 * for the skinned patch evaluation level of detail.
 *
 * \see rpPATCHLODMAXVALUE
 * \see rpPATCHLODMINVALUE
 * \see RpPatchLODCallBack
 */
#define rpPATCHSKINLODMAXVALUE (18)

/**
 * \ingroup rppatch
 * \ref rpPATCHLODMINVALUE defines the minimum value that can be returned for
 * the patch evaluation level of detail.
 *
 * \see rpPATCHSKINLODMAXVALUE
 * \see rpPATCHLODMAXVALUE
 * \see RpPatchLODCallBack
 */
#define rpPATCHLODMINVALUE (4)

/*===========================================================================*
 * -- Global Types --------------------------------------------------------- *
 *===========================================================================*/

/**
 * \ingroup rppatch
 * \ref RpPatchMeshFlag patch mesh type flags.
 */
enum RpPatchMeshFlag
{
    rpNAPATCHMESHFLAG      = 0,
    rpPATCHMESHPOSITIONS   = 0x01, /**<Patch mesh contains control point
                                       positions.                          */
    rpPATCHMESHNORMALS     = 0x02, /**<Patch mesh contains control point
                                       normals.                            */
    rpPATCHMESHPRELIGHTS   = 0x04, /**<Patch mesh contains control point
                                       luminance values.                   */
    rpPATCHMESHTEXTURED    = 0x08, /**<Patch mesh contains a single set of
                                       control point texture coordinates.  */
    rpPATCHMESHTEXTURED2   = 0x10, /**<Patch mesh contains two sets of
                                       texture coordinates.                */
    rpPATCHMESHLIGHT       = 0x20, /**<Patch mesh will be lit.             */
    rpPATCHMESHMODULATEMATERIALCOLOR = 0x40,
                                   /**<Control point color will be
                                       modulated with the material color.  */
    rpPATCHMESHSMOOTHNORMALS = 0x80,
                                   /**<Patch mesh normals will be
                                       smoothed automatically.             */
    rpPATCHMESHFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpPatchMeshFlag RpPatchMeshFlag;

/**
 * \ingroup rppatch
 * \ref RpPatchMeshLockMode patch mesh lock flags.
 */
enum RpPatchMeshLockMode
{
    rpNAPATCHMESHLOCKMODE     = 0,
    rpPATCHMESHLOCKPATCHES    = 0x01, /**<Lock the mesh patches.            */
    rpPATCHMESHLOCKPOSITIONS  = 0x02, /**<Lock the control point positions. */
    rpPATCHMESHLOCKNORMALS    = 0x04, /**<Lock the control point normals.   */
    rpPATCHMESHLOCKPRELIGHTS  = 0x08, /**<Lock the control point luminance
                                          values.                           */
    rpPATCHMESHLOCKTEXCOORDS  = 0x10, /**<Lock the control points' first set
                                          of texture coordinates.           */
    rpPATCHMESHLOCKTEXCOORDS2 = 0x20, /**<Lock the control points' second set
                                          of texture coordinates.           */
    rpPATCHMESHLOCKALL        = 0x3f, /**<Combination of all the above.     */
    rpPATCHMESHLOCKMODEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpPatchMeshLockMode RpPatchMeshLockMode;

typedef struct RpPatchMeshDefinition RpPatchMeshDefinition;
/**
 * \ingroup rppatch
 * \struct RpPatchMeshDefinition
 * holds the definition sizes of the patch mesh. This data should be considered
 * read only.
 */
struct RpPatchMeshDefinition
{
    RwUInt32 flag;             /**<Patch mesh definition flag.            */
    RwUInt32 numControlPoints; /**<Number of control points.              */
    RwUInt32 numTriPatches;    /**<Number of tri patches.                 */
    RwUInt32 numQuadPatches;   /**<Number of quad patches.                */
    RwUInt32 numTexCoordSets;  /**<Number of sets of texture coordinates. */
};

typedef struct RpPatchMesh RpPatchMesh;
/**
 * \ingroup rppatch
 * \struct RpPatchMesh
 * holds the control point data for a patch mesh. The patch mesh should be
 * created with \ref RpPatchMeshCreate. The patch mesh should be locked with
 * \ref RpPatchMeshLock before the data is edited. Quadrilateral and triangle
 * patches can be defined from the control points with
 * \ref RpPatchMeshSetQuadPatch and \ref RpPatchMeshSetTriPatch respectivly.
 * The patch mesh should be unlocked with \ref RpPatchMeshUnlock before it is
 * added to an \ref RpAtomic with \ref RpPatchAtomicSetPatchMesh.
 *
 * \see RpPatchMesDefinition
 */
struct RpPatchMesh
{
    RwV3d       *positions;           /**<Control point positions.           */
    RwV3d       *normals;             /**<Control point normals.             */
    RwRGBA      *preLightColors;      /**<Control point pre-light colors.    */
    RwTexCoords *texCoords[rwMAXTEXTURECOORDS];
                                      /**<Control point texture coordinates. */
    RpPatchMeshDefinition definition; /**<Patch mesh definition data.        */
};

typedef struct RpQuadPatch RpQuadPatch;
/**
 * \ingroup rppatch
 * \struct RpQuadPatch
 * holds the control point indices for a quadrilateral patch. There are
 * \ref rpQUADPATCHNUMCONTROLINDICES indices for a  quadrilateral patch.
 *
 * \see RpPatchMeshSetQuadPatch
 */
struct RpQuadPatch
{
    RwUInt32 cpIndices[rpQUADPATCHNUMCONTROLINDICES]; /**<Control point
                                                          indices. */
};

typedef struct RpTriPatch RpTriPatch;
/**
 * \ingroup rppatch
 * \struct RpTriPatch
 * holds the control point indices for a triangle patch. There are
 * \ref rpTRIPATCHNUMCONTROLINDICES indices for a triangle patch.
 *
 * \see RpPatchMeshSetTriPatch
 */
struct RpTriPatch
{
    RwUInt32 cpIndices[rpTRIPATCHNUMCONTROLINDICES]; /**<Control point
                                                         indices. */
};

typedef struct RpPatchLODRange RpPatchLODRange;
/**
 * \ingroup rppatch
 * \struct RpPatchLODRange
 * holds the variables used by the default atomic LOD call back function.
 */
struct RpPatchLODRange
{
    RwUInt32 minLod; /**<Minimum LOD value. */
    RwUInt32 maxLod; /**<Maximum LOD value. */
    RwReal minRange; /**<Minimum LOD range. */
    RwReal maxRange; /**<Maximum LOD range. */
};

/**
 * \ingroup rppatch
 * \typedef RpPatchLODUserData
 * typedef for the user data passed to the \ref RpPatchLODCallBack
 * function which calculates the atomics' level of detail.
 *
 * \see RpPatchAtomicSetPatchLODCallBack
 * \see RpPatchAtomicGetPatchLODCallBack
 */
typedef void *RpPatchLODUserData;

/**
 * \ingroup rppatch
 * \typedef RpPatchLODCallBack
 * typedef for the patch atomic level of detail calculation function.
 *
 * \see RpPatchAtomicSetPatchLODCallBack
 * \see RpPatchAtomicGetPatchLODCallBack
 */
typedef RwUInt32 (* RpPatchLODCallBack)( RpAtomic *atomic,
                                         RpPatchLODUserData userData );

/*===========================================================================*
 * -- Plugin API Functions ------------------------------------------------- *
 *===========================================================================*/
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

/* ------------------------------------------------------------------------- *
 *    Plugin functions                                                       *
 * ------------------------------------------------------------------------- */
extern RwBool
RpPatchPluginAttach(void);

/* ------------------------------------------------------------------------- *
 *    Patch Mesh functions                                                   *
 * ------------------------------------------------------------------------- */
extern RpPatchMesh *
RpPatchMeshCreate( RwUInt32 numQuadPatches,
                   RwUInt32 numTriPatches,
                   RwUInt32 numControlPoints,
                   RwUInt32 definitionFlag );

extern RwBool
RpPatchMeshDestroy( RpPatchMesh *patchMesh );

extern RpPatchMesh *
RpPatchMeshLock( RpPatchMesh *patchMesh,
                 RwUInt32 lockMode );

extern RpPatchMesh *
RpPatchMeshUnlock( RpPatchMesh *patchMesh );

/* ------------------------------------------------------------------------- *
 *    Patch mesh helper functions                                            *
 * ------------------------------------------------------------------------- */

extern RpPatchMesh *
RpPatchMeshTransform( RpPatchMesh *patchMesh,
                      const RwMatrix *matrix );

/* ------------------------------------------------------------------------- */
#define RpPatchMeshGetFlagsMacro(patchMesh)                                 \
    (patchMesh->definition.flag)

#define RpPatchMeshSetFlagsMacro(patchMesh, flags)                          \
    (patchMesh->definition.flag = flags)

#define RpPatchMeshGetNumControlPointsMacro(patchMesh)                      \
    (patchMesh->definition.numControlPoints)

#define RpPatchMeshGetNumTriPatchesMacro(patchMesh)                         \
    (patchMesh->definition.numTriPatches)

#define RpPatchMeshGetNumQuadPatchesMacro(patchMesh)                        \
    (patchMesh->definition.numQuadPatches)

#define RpPatchMeshGetNumTexCoordSetsMacro(patchMesh)                       \
    (patchMesh->definition.numTexCoordSets)

#define RpPatchMeshGetPositionsMacro(patchMesh)                             \
    (patchMesh->positions)

#define RpPatchMeshGetNormalsMacro(patchMesh)                               \
    (patchMesh->normals)

#define RpPatchMeshGetPreLightColorsMacro(patchMesh)                        \
    (patchMesh->preLightColors)

#define RpPatchMeshGetTexCoordsMacro(patchMesh, index)                      \
    (patchMesh->texCoords[index])
/* ------------------------------------------------------------------------- */

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

/* ------------------------------------------------------------------------- */
extern RwUInt32
RpPatchMeshGetFlags( const RpPatchMesh *patchMesh );

extern RpPatchMesh *
RpPatchMeshSetFlags( RpPatchMesh *patchMesh,
                     RwUInt32 flags );

extern RwUInt32
RpPatchMeshGetNumControlPoints( const RpPatchMesh *patchMesh );

extern RwUInt32
RpPatchMeshGetNumTriPatches( const RpPatchMesh *patchMesh );

extern RwUInt32
RpPatchMeshGetNumQuadPatches( const RpPatchMesh *patchMesh );

extern RwUInt32
RpPatchMeshGetNumTexCoordSets( const RpPatchMesh *patchMesh );

extern RwV3d *
RpPatchMeshGetPositions( const RpPatchMesh *patchMesh );

extern RwV3d *
RpPatchMeshGetNormals( const RpPatchMesh *patchMesh );

extern RwRGBA *
RpPatchMeshGetPreLightColors( const RpPatchMesh *patchMesh );

extern RwTexCoords *
RpPatchMeshGetTexCoords( const RpPatchMesh *patchMesh,
                         RwTextureCoordinateIndex index );
/* ------------------------------------------------------------------------- */

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

/* ------------------------------------------------------------------------- */
#define RpPatchMeshGetFlags(patchMesh)                                      \
    RpPatchMeshGetFlagsMacro(patchMesh)

#define RpPatchMeshSetFlags(patchMesh, flags)                               \
    RpPatchMeshSetFlagsMacro(patchMesh, flags)

#define RpPatchMeshGetNumControlPoints(patchMesh)                           \
    RpPatchMeshGetNumControlPointsMacro(patchMesh)

#define RpPatchMeshGetNumTriPatches(patchMesh)                              \
    RpPatchMeshGetNumTriPatchesMacro(patchMesh)

#define RpPatchMeshGetNumQuadPatches(patchMesh)                             \
    RpPatchMeshGetNumQuadPatchesMacro(patchMesh)

#define RpPatchMeshGetNumTexCoordSets(patchMesh)                            \
    RpPatchMeshGetNumTexCoordSetsMacro(patchMesh)

#define RpPatchMeshGetPositions(patchMesh)                                  \
    RpPatchMeshGetPositionsMacro(patchMesh)

#define RpPatchMeshGetNormals(patchMesh)                                    \
    RpPatchMeshGetNormalsMacro(patchMesh)

#define RpPatchMeshGetPreLightColors(patchMesh)                             \
    RpPatchMeshGetPreLightColorsMacro(patchMesh)

#define RpPatchMeshGetTexCoords(patchMesh, index)                           \
    RpPatchMeshGetTexCoordsMacro(patchMesh, index)
/* ------------------------------------------------------------------------- */

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

/* ------------------------------------------------------------------------- *
 *    Patch streaming functions                                              *
 * ------------------------------------------------------------------------- */
extern RwUInt32
RpPatchMeshStreamGetSize( const RpPatchMesh *patchMesh );

extern RpPatchMesh *
RpPatchMeshStreamRead( RwStream *stream );

extern const RpPatchMesh *
RpPatchMeshStreamWrite( const RpPatchMesh *patchMesh,
                        RwStream *stream );

/* ------------------------------------------------------------------------- *
 *    Patch Mesh patch functions                                             *
 * ------------------------------------------------------------------------- */
extern RpPatchMesh *
RpPatchMeshSetQuadPatch( RpPatchMesh *patchMesh,
                         RwUInt32 quadIndex,
                         RpQuadPatch *quadPatch );

extern RpPatchMesh *
RpPatchMeshSetTriPatch( RpPatchMesh *patchMesh,
                        RwUInt32 triIndex,
                        RpTriPatch *triPatch );

extern RpQuadPatch *
RpPatchMeshGetQuadPatch( const RpPatchMesh *patchMesh,
                         RwUInt32 quadIndex );

extern RpTriPatch *
RpPatchMeshGetTriPatch( const RpPatchMesh *patchMesh,
                        RwUInt32 triIndex );

/* ------------------------------------------------------------------------- *
 *    Patch Mesh material functions                                          *
 * ------------------------------------------------------------------------- */
extern RpPatchMesh *
RpPatchMeshSetQuadPatchMaterial( RpPatchMesh *patchMesh,
                                 RwUInt32 quadIndex,
                                 RpMaterial *material );

extern RpPatchMesh *
RpPatchMeshSetTriPatchMaterial( RpPatchMesh *patchMesh,
                                RwUInt32 triIndex,
                                RpMaterial *material );

extern RpMaterial *
RpPatchMeshGetQuadPatchMaterial( const RpPatchMesh *patchMesh,
                                 RwUInt32 quadIndex );

extern RpMaterial *
RpPatchMeshGetTriPatchMaterial( const RpPatchMesh *patchMesh,
                                RwUInt32 triIndex );

extern const RpPatchMesh *
RpPatchMeshForAllMaterials( const RpPatchMesh *patchMesh,
                            RpMaterialCallBack callBack,
                            void *userData );

extern RwUInt32
RpPatchMeshGetNumMaterials( const RpPatchMesh *patchMesh );

extern RpMaterial *
RpPatchMeshGetMaterial( const RpPatchMesh *patchMesh,
                        RwUInt32 materialIndex );

/* ------------------------------------------------------------------------- *
 *    Patch Skin functions                                                   *
 * ------------------------------------------------------------------------- */
#if (defined(RPSKIN_H))

extern RpSkin *
RpPatchMeshGetSkin( RpPatchMesh *patchMesh );

extern RpPatchMesh *
RpPatchMeshSetSkin( RpPatchMesh *patchMesh,
                    RpSkin *skin );

#endif /* (defined(RPSKIN_H)) */

/* ------------------------------------------------------------------------- *
 *    Patch Atomic functions                                                 *
 * ------------------------------------------------------------------------- */
extern RpAtomic *
RpPatchAtomicSetPatchMesh( RpAtomic *atomic,
                           RpPatchMesh *patchMesh );

extern RpPatchMesh *
RpPatchAtomicGetPatchMesh( RpAtomic *atomic );

/* ------------------------------------------------------------------------- *
 *    Patch Atomic LOD functions                                             *
 * ------------------------------------------------------------------------- */
extern RwBool
RpPatchAtomicSetPatchLODCallBack( RpAtomic *atomic,
                                  RpPatchLODCallBack callback,
                                  RpPatchLODUserData userData );

extern RwBool
RpPatchAtomicGetPatchLODCallBack( const RpAtomic *atomic,
                                  RpPatchLODCallBack *callback,
                                  RpPatchLODUserData *userData );

/* ------------------------------------------------------------------------- *
 *    Patch default LOD range                                                *
 * ------------------------------------------------------------------------- */
extern RwBool
RpPatchSetDefaultLODCallBackRange( RpPatchLODRange *lodRange );

extern RwBool
RpPatchGetDefaultLODCallBackRange( RpPatchLODRange *lodRange );

/* ------------------------------------------------------------------------- */
#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* RPPATCH_H */
