/*
 * Data structures for Lightmap conversion toolkit
 *
 * Copyright (c) Criterion Software Limited
 */

/***************************************************************************
 *                                                                         *
 * Module  : rtltmapcnv.h                                                  *
 *                                                                         *
 * Purpose :                                                               *
 *                                                                         *
 **************************************************************************/

#ifndef RTLTMAPCONVERT_H
#define RTLTMAPCONVERT_H

/**
 * \defgroup rtltmapcnv RtLtMapCnv
 * \ingroup lighting
 *
 * Lightmap Conversion toolkit for RenderWare.
 *
 */

/**
 * \ingroup rtltmapcnv
 * \page rtltmapcnvoverview RtLtMap Conversion Toolkit Overview
 *
 * \par Requirements
 * \li \b Headers: rwcore.h, rpworld.h, rprandom.h, rpltmap.h, rtltmap.h
 * \li \b Libraries: rwcore, rpworld, rpcollis, rprandom, rpltmap, rppvs, rtbary, rtintsec, rtltmap
 * \li \b Plugin \b attachments: \ref RpWorldPluginAttach, \ref RpCollisionPluginAttach,
 *     \ref RpRandomPluginAttach, \ref RpLtMapPluginAttach, \ref RpPVSPluginAttach
 *
 * \subsection ltmapcnvtoolkitoverview Overview
 *
 * The \ref rtltmapcnv toolkit contains a set of functions for
 * converting lightmaps. This toolkit suppliments \ref rtltmap, a lightmap
 * generation toolkit.
 *
 * Many major modelling packages provide the functionality to generate
 * lightmaps. \ref rtltmapcnv provides a set of functionality to postprocess
 * these lightmaps into a form that RenderWare can use.
 *
 * The conversion is a two stage process and is similar to generating lightmaps
 * using \ref rtltmap. Firstly, lightmaps need to be allocated and associated
 * with objects, and the UV coordinates for the lightmap pass need to be calculated
 * (see \ref RtLtMapLightMapsCreate).
 *
 * Secondly, the imported lightmaps are converted. (see \ref RtLtMapCnvWorldConvert and
 * \ref RtLtMapCnvAtomicConvert). This involves re-mapping each triangle lightmap
 * in the imported lightmaps to RenderWare's lightmaps. The triangle lightmaps
 * can be rescaled and re-oriented during the conversion. As a results,
 * the final result may differ from the original.
 *
 * Lightmaps generated by this toolkit support tristripped geometry
 * (unusual for lightmap implementations) and so will render very quickly,
 * especially on such platforms as PlayStation 2. A few visual artifacts remain due
 * to this tristrip support and the conversion although, in the vast majority
 * of cases, they will go unnoticed or easily be worked around.
 */

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

#include "rwcore.h"
#include "rpworld.h"
#include "rpusrdat.h"

#include "rtltmapcnv.rpe"          /* automatically generated header file */

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

/****************************************************************************
 Global Vars
 */
extern RwChar rtLtMapCnvUVtxUserDataName[];
extern RwChar rtLtMapCnvVVtxUserDataName[];
extern RwChar rtLtMapCnvPolyUserDataName[];

/****************************************************************************
 Global Types
 */

/**
 * \ingroup rtltmapcnv
 * \ref RtLtMapCnvErrorFlags is an enumerated type specifying the different
 * errors which may occur during lightmap conversion. The flags are bitfields
 * to represent more than one type of error.
 */
enum RtLtMapCnvErrorFlags
{
    rtLTMAPERROR_NONE                      = ((int)0x00000000),

    rtLTMAPERROR_IMPORTEDUVSOVERONEDOTZERO = ((int)0x00000001),/**< A flag to indicate a UV out of range error. */
    rtLTMAPERROR_GENERATEDLIGHTMAPNOTFOUND = ((int)0x00000002),/**< A flag to indicate a RenderWare lightmap was not found. */
    rtLTMAPERROR_NOGENERATEDLIGHTMAPS      = ((int)0x00000004),/**< A flag to indicate no RenderWare lightmaps were found. */
    rtLTMAPERROR_IMPORTEDLIGHTMAPNOTFOUND  = ((int)0x00000008),/**< A flag to indicate an imported lightmap was not found. */
    rtLTMAPERROR_NOIMPORTEDLIGHTMAPS       = ((int)0x00000010),/**< A flag to indicate no imported lightmaps were found. */

    RTLTMAPERROR_FORCEENUMSIZEINT        = RWFORCEENUMSIZEINT
};

typedef enum RtLtMapCnvErrorFlags RtLtMapCnvErrorFlags;

typedef struct rtLtMapCnvImageList rtLtMapCnvImageList;

/**
 * \ingroup rtltmapcnv
 * \struct rtLtMapCnvImageList
 * The rtLtMapCnvImageList is an internal use only data structure for matching the imported lightmap image
 * with the RenderWare lightmap texture, referenced by imported lightmap name.
 */
struct rtLtMapCnvImageList
{
    RwTexture   *texture;           /**< Internal use only. Pointer to RenderWare's lightmap texture. */
    RwImage     *image;             /**< Internal use only. Pointer to the imported lightmap image. */
    RwChar      *name;              /**< The name reference of the lightmap. */

    rtLtMapCnvImageList *next;      /**< Next pointer in the list. */
};


typedef struct RtLtMapCnvWorldSectorData RtLtMapCnvWorldSectorData;

/**
 * \ingroup rtltmapcnv
 * \struct RtLtMapCnvWorldSectorData
 * The RtLtMapCnvWorldSectorData holds the imported lightmap data required for
 * converting to RenderWare format.
 *
 * The structure stores the imported UV lightmap co-ordinates array and the
 * lightmap texture name reference array.
 *
 * \see RtLtMapCnvWorldSectorCnvDataCreate
 * \see RtLtMapCnvWorldSectorCnvDataDestroy
 * \see RtLtMapCnvWorldSectorGetUArray
 * \see RtLtMapCnvWorldSectorGetVArray
 * \see RtLtMapCnvWorldSectorGetTexNameArray
 */
struct RtLtMapCnvWorldSectorData
{
    RpWorldSector *worldSector;     /**< The parent world sector pointer. */

    RpUserDataArray *texName;       /**< A data array storing the texture name reference per triangle. */
    RpUserDataArray *vtxU;          /**< A data array storing the U lightmap co-ordinate per vertex. */
    RpUserDataArray *vtxV;          /**< A data array storing the V lightmap co-ordinate per vertex. */
};


typedef struct RtLtMapCnvWorldSession RtLtMapCnvWorldSession;

/**
 * \ingroup rtltmapcnv
 * \struct RtLtMapCnvWorldSession
 *
 * The RtLtMapCnvWorldSession structure holds information to be passed to
 * \ref RtLtMapCnvWorldConvert. It is used to parameterize the conversion
 * process.
 *
 * \see RtLtMapCnvWorldSectorCnvDataCreate
 * \see RtLtMapCnvWorldSectorCnvDataDestroy
 * \see RtLtMapCnvWorldConvert
 * \see RtLtMapCnvWorldSessionGetRejectionFactor
 * \see RtLtMapCnvWorldSessionSetRejectionFactor
 * \see RtLtMapCnvWorldSessionGetGreedyRasterization
 * \see RtLtMapCnvWorldSessionSetGreedyRasterization
 * \see RtLtMapCnvWorldSessionGetImportedLtMapResample
 * \see RtLtMapCnvWorldSessionSetImportedLtMapResample
 */
struct RtLtMapCnvWorldSession
{
    RpWorld     *world;                     /**< This is the world whose lightmaps are converted
                                             * during the conversion process. */
    RwUInt32    errorFlag;                  /**< A flag for returing the error status in the event
                                             * of an error during conversion. */

    RwInt32              numSector;         /**< Internal use only. */
    RtLtMapCnvWorldSectorData *sectorList;  /**< Internal use only. */

    RwUInt32     samplingFactor;            /**< Specifies the scaling factor for the RenderWare sample image,
                                             * generated from the imported lightmaps during conversion. */
    RwBool      reSampleImportedLightmap;   /**< Specifies if the imported lightmap is to be rescaled to the working
                                             * image size. */
    RwBool      useGreedyRasterization;     /**< Specifies if greedy rasterization is to used. */
    RwReal      smallSizeRejectionFactor;   /**< Specifies the small triangle rejection threshold. */

    rtLtMapCnvImageList *headILTM;          /**< Internal use only. */
    RwInt32     ILTMCount;                  /**< Internal use only. */

    rtLtMapCnvImageList *headRWLTM;         /**< Internal use only. */
    RwInt32     RWLTMCount;                 /**< Internal use only. */
};


typedef struct RtLtMapCnvAtomicSession RtLtMapCnvAtomicSession;

/**
 * \ingroup rtltmapcnv
 * \struct RtLtMapCnvAtomicSession
 *
 * The RtLtMapCnvAtomicSession structure holds information to be passed to
 * \ref RtLtMapCnvAtomicConvert. It is used to parameterize the conversion
 * process.
 *
 * The structure stores the imported UV lightmap co-ordinates array and the
 * lightmap texture name reference array.
 *
 * \see RtLtMapCnvAtomicCnvDataCreate
 * \see RtLtMapCnvAtomicCnvDataDestroy
 * \see RtLtMapCnvAtomicGetUArray
 * \see RtLtMapCnvAtomicGetVArray
 * \see RtLtMapCnvAtomicGetTexNameArray
 * \see RtLtMapCnvAtomicConvert
 * \see RtLtMapCnvAtomicSessionGetRejectionFactor
 * \see RtLtMapCnvAtomicSessionSetRejectionFactor
 * \see RtLtMapCnvAtomicSessionGetGreedyRasterization
 * \see RtLtMapCnvAtomicSessionSetGreedyRasterization
 * \see RtLtMapCnvAtomicSessionGetImportedLtMapResample
 * \see RtLtMapCnvAtomicSessionSetImportedLtMapResample
 */
struct RtLtMapCnvAtomicSession
{
    RpAtomic     *atomic;                     /**< The atomic whose lightmaps are converted
                                               * during the conversion process. */
    RwUInt32    errorFlag;                    /**< A flag for returing the error status in the event
                                               * of an error during conversion. */

    RpGeometry      *geometry;                /**< Internal use only. */

    RpUserDataArray *texName;                 /**< A user data array storing the texture name reference per triangle.*/
    RpUserDataArray *vtxU;                    /**< A user data array storing the U lightmap co-ordinate per vertex. */
    RpUserDataArray *vtxV;                    /**< A user data array storing the V lightmap co-ordinate per vertex. */


    RwUInt32     samplingFactor;            /**< Specifies the scaling factor for the RenderWare sample image,
                                             * generated from the imported lightmaps during conversion. */
    RwBool      reSampleImportedLightmap;   /**< Specifies if the imported lightmap is to be rescaled to the working
                                             * image size. */
    RwBool      useGreedyRasterization;     /**< Specifies if greedy rasterization is to used. */
    RwReal      smallSizeRejectionFactor;   /**< Specifies the small triangle rejection threshold. */

    rtLtMapCnvImageList *headILTM;          /**< Internal use only. */
    RwInt32     ILTMCount;                  /**< Internal use only. */

    rtLtMapCnvImageList *headRWLTM;         /**< Internal use only. */
    RwInt32     RWLTMCount;                 /**< Internal use only. */
};

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

#define RtLtMapCnvAnySetImportedLtMapResampleMacro(ses,resample)\
        ((ses)->reSampleImportedLightmap = (resample))

#define RtLtMapCnvAnySetGreedyRasterizationMacro(ses,greedy)\
        ((ses)->useGreedyRasterization = (greedy))

#define RtLtMapCnvAnySetRejectionFactorMacro(ses,factor)\
        ((ses)->smallSizeRejectionFactor = (factor))

#define RtLtMapCnvAnyGetImportedLtMapResampleMacro(ses)\
        ((ses)->reSampleImportedLightmap)

#define RtLtMapCnvAnyGetGreedyRasterizationMacro(ses)\
        ((ses)->useGreedyRasterization)

#define RtLtMapCnvAnyGetRejectionFactorMacro(ses)\
        ((ses)->smallSizeRejectionFactor)

#define RtLtMapCnvAnySetVtxUVMacro(a,b,c)\
MACRO_START\
{\
            RpUserDataArraySetReal((a)->vtxU,(b),(c)->u);\
            RpUserDataArraySetReal((a)->vtxV,(b),(c)->v);\
}\
MACRO_STOP

#define RtLtMapCnvAnyGetVtxUVMacro(data,idx,tex)\
MACRO_START\
{\
            tex->u = RpUserDataArrayGetReal((data)->vtxU,(idx));\
            tex->v = RpUserDataArrayGetReal((data)->vtxV,(idx));\
}\
MACRO_STOP

#define RtLtMapCnvAnySetLightMapNameMacro(data,idx,name)\
        RpUserDataArraySetString((data)->texName,(idx),(name));\

#define RtLtMapCnvAnyGetLightMapNameMacro(data,idx) \
        (RpUserDataArrayGetString((data)->texName,(idx)))


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

extern RwBool
RtLtMapCnvWorldIsConvertible(RpWorld *world);

extern RtLtMapCnvWorldSession *
RtLtMapCnvWorldSessionCreate(RpWorld *world);

extern void
RtLtMapCnvWorldSessionDestroy(RtLtMapCnvWorldSession *session);

extern RwBool
RtLtMapCnvWorldConvert(RtLtMapCnvWorldSession *session, RwUInt32 factor);

extern RpUserDataArray *
RtLtMapCnvWorldSectorGetTexNameArray(RpWorldSector *ws);

extern RpUserDataArray *
RtLtMapCnvWorldSectorGetUArray(RpWorldSector *ws);

extern RpUserDataArray *
RtLtMapCnvWorldSectorGetVArray(RpWorldSector *ws);

extern RpWorldSector *
RtLtMapCnvWorldSectorCnvDataCreate(RpWorldSector *ws);

extern RpWorldSector *
RtLtMapCnvWorldSectorCnvDataDestroy(RpWorldSector *ws);

extern RwBool
RtLtMapCnvAtomicIsConvertible(RpAtomic *atomic);

extern RtLtMapCnvAtomicSession *
RtLtMapCnvAtomicSessionCreate(RpAtomic *atomic);

extern void
RtLtMapCnvAtomicSessionDestroy(RtLtMapCnvAtomicSession *session);

extern RwBool
RtLtMapCnvAtomicConvert(RtLtMapCnvAtomicSession *session, RwUInt32 factor);

extern RpUserDataArray *
RtLtMapCnvAtomicGetTexNameArray(RpAtomic *atm);

extern RpUserDataArray *
RtLtMapCnvAtomicGetUArray(RpAtomic *atm);

extern RpUserDataArray *
RtLtMapCnvAtomicGetVArray(RpAtomic *atm);

extern RpAtomic *
RtLtMapCnvAtomicCnvDataCreate(RpAtomic *atm);

extern RpAtomic *
RtLtMapCnvAtomicCnvDataDestroy(RpAtomic *atm);


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

extern void
RtLtMapCnvWorldSectorSetVtxUV( RtLtMapCnvWorldSectorData *data,
                            RwInt32 idx,
                            RwTexCoords *tex);

extern void
RtLtMapCnvWorldSectorGetVtxUV( RtLtMapCnvWorldSectorData *data,
                            RwInt32 idx,
                            RwTexCoords *tex);

extern void
RtLtMapCnvWorldSectorSetLightMapName(  RtLtMapCnvWorldSectorData *data,
                                    RwInt32 idx,
                                    RwChar *name);

extern RwChar *
RtLtMapCnvWorldSectorGetLightMapName(  RtLtMapCnvWorldSectorData *data,
                                    RwInt32 idx);

extern void
RtLtMapCnvWorldSessionSetImportedLtMapResample(
                                          RtLtMapCnvWorldSession *session,
                                          RwBool resample);
extern RwBool
RtLtMapCnvWorldSessionGetImportedLtMapResample(
                                          RtLtMapCnvWorldSession *session);


extern void
RtLtMapCnvWorldSessionSetGreedyRasterization(
                                          RtLtMapCnvWorldSession *session,
                                          RwBool greedy);
extern RwBool
RtLtMapCnvWorldSessionGetGreedyRasterization(
                                          RtLtMapCnvWorldSession *session);


extern void
RtLtMapCnvWorldSessionSetRejectionFactor(
                                          RtLtMapCnvWorldSession *session,
                                          RwReal factor);

extern RwReal
RtLtMapCnvWorldSessionGetRejectionFactor(
                                          RtLtMapCnvWorldSession *session);

extern void
RtLtMapCnvAtomicSetVtxUV(RtLtMapCnvAtomicSession *session,
                            RwInt32 idx,
                            RwTexCoords *tex);

extern void
RtLtMapCnvAtomicGetVtxUV( RtLtMapCnvAtomicSession *session,
                            RwInt32 idx,
                            RwTexCoords *tex);

extern void
RtLtMapCnvAtomicSetLightMapName( RtLtMapCnvAtomicSession *session,
                                    RwInt32 idx,
                                    RwChar *name);

extern RwChar *
RtLtMapCnvAtomicGetLightMapName( RtLtMapCnvAtomicSession *session,
                                    RwInt32 idx);

extern void
RtLtMapCnvAtomicSessionSetImportedLtMapResample(
                                          RtLtMapCnvAtomicSession *session,
                                          RwBool resample);
extern RwBool
RtLtMapCnvAtomicSessionGetImportedLtMapResample(
                                          RtLtMapCnvAtomicSession *session);


extern void
RtLtMapCnvAtomicSessionSetGreedyRasterization(
                                          RtLtMapCnvAtomicSession *session,
                                          RwBool greedy);
extern RwBool
RtLtMapCnvAtomicSessionGetGreedyRasterization(
                                          RtLtMapCnvAtomicSession *session);


extern void
RtLtMapCnvAtomicSessionSetRejectionFactor(
                                          RtLtMapCnvAtomicSession *session,
                                          RwReal factor);

extern RwReal
RtLtMapCnvAtomicSessionGetRejectionFactor(
                                          RtLtMapCnvAtomicSession *session);

#else

#define RtLtMapCnvWorldSectorSetVtxUV(data,idx,tex)\
        RtLtMapCnvAnySetVtxUVMacro(data,idx,tex)

#define RtLtMapCnvWorldSectorGetVtxUV(data,idx,tex)\
        RtLtMapCnvAnyGetVtxUVMacro(data,idx,tex)

#define RtLtMapCnvWorldSectorSetLightMapName(data,idx,name)\
        RtLtMapCnvAnySetLightMapNameMacro(data,idx,name)

#define RtLtMapCnvWorldSectorGetLightMapName(data,idx)\
        RtLtMapCnvAnyGetLightMapNameMacro(data,idx)

#define RtLtMapCnvWorldSectorGetLightMapName(data,idx)\
        RtLtMapCnvAnyGetLightMapNameMacro(data,idx)

#define RtLtMapCnvWorldSessionSetImportedLtMapResample(ses,resample)\
        RtLtMapCnvAnySetImportedLtMapResampleMacro(ses,resample)

#define RtLtMapCnvWorldSessionSetGreedyRasterization(ses,greedy)\
        RtLtMapCnvAnySetGreedyRasterizationMacro(ses,greedy)

#define RtLtMapCnvWorldSessionSetRejectionFactor(ses,factor)\
        RtLtMapCnvAnySetRejectionFactorMacro(ses,factor)

#define RtLtMapCnvWorldSessionGetImportedLtMapResample(ses)\
        RtLtMapCnvAnyGetImportedLtMapResampleMacro(ses)

#define RtLtMapCnvWorldSessionGetGreedyRasterization(ses)\
        RtLtMapCnvAnyGetGreedyRasterizationMacro(ses)

#define RtLtMapCnvWorldSessionGetRejectionFactor(ses)\
        RtLtMapCnvAnyGetRejectionFactorMacro(ses)

#define RtLtMapCnvAtomicSetVtxUV(data,idx,tex)\
        RtLtMapCnvAnySetVtxUVMacro(data,idx,tex)

#define RtLtMapCnvAtomicGetVtxUV(data,idx,tex)\
        RtLtMapCnvAnyGetVtxUVMacro(data,idx,tex)

#define RtLtMapCnvAtomicSetLightMapName(data,idx,name)\
        RtLtMapCnvAnySetLightMapNameMacro(data,idx,name)

#define RtLtMapCnvAtomicGetLightMapName(data,idx)\
        RtLtMapCnvAnyGetLightMapNameMacro(data,idx)

#define RtLtMapCnvAtomicGetLightMapName(data,idx)\
        RtLtMapCnvAnyGetLightMapNameMacro(data,idx)

#define RtLtMapCnvAtomicSessionSetImportedLtMapResample(ses,resample)\
        RtLtMapCnvAnySetImportedLtMapResampleMacro(ses,resample)

#define RtLtMapCnvAtomicSessionSetGreedyRasterization(ses,greedy)\
        RtLtMapCnvAnySetGreedyRasterizationMacro(ses,greedy)

#define RtLtMapCnvAtomicSessionSetRejectionFactor(ses,factor)\
        RtLtMapCnvAnySetRejectionFactorMacro(ses,factor)

#define RtLtMapCnvAtomicSessionGetImportedLtMapResample(ses)\
        RtLtMapCnvAnyGetImportedLtMapResampleMacro(ses)

#define RtLtMapCnvAtomicSessionGetGreedyRasterization(ses)\
        RtLtMapCnvAnyGetGreedyRasterizationMacro(ses)

#define RtLtMapCnvAtomicSessionGetRejectionFactor(ses)\
        RtLtMapCnvAnyGetRejectionFactorMacro(ses)

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

extern rtLtMapCnvImageList *
_rtLtMapCnvImageCacheGet(   const rtLtMapCnvImageList *imglist,
                                const RwChar *name);

extern rtLtMapCnvImageList *
_rtLtMapCnvImageCacheAdd(   const rtLtMapCnvImageList *imglist,
                                const RwChar *name);
extern void
_rtLtMapCnvImageCacheDestroy( rtLtMapCnvImageList *imglist);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#endif                          /* RTLtMapCnv_H */

