/** * \defgroup rtltmap RtLtMap * \ingroup rttool * * Lightmap Generation Toolkit for RenderWare. */ #ifndef RTLTMAP_H #define RTLTMAP_H /*===========================================================================* *--- Includes --------------------------------------------------------------* *===========================================================================*/ #include "rwcore.h" #include "rpworld.h" #include "rpltmap.h" /** * \ingroup rtltmap * \typedef RtLtMapIlluminateSampleCallBack * \ref RtLtMapIlluminateSampleCallBack is the callback to be called, from * within \ref RtLtMapIlluminate, for groups of samples in the objects * currently being illuminated. * * For lightmapped objects, samples are grouped on a per-polygon basis and * for vertex-lit objects, samples are grouped on a per-object basis (see * \ref RtLtMapObjectFlags). * * This callback will receive an array of color values to fill in, each * representing one sample in the current object - this may correspond to * a texel in the current object's lightmap or the prelight colour of a * vertex, depending on whether the object is lightmapped and/or vertex-lit. * It will receive positions (in world-space) for each sample and the normal * vector (again, in world-space) of each sample (normals are interpolated * across polygons for non-flat-shaded materials. See \ref RtLtMapMaterialFlags). * For lightmap samples (not vertex-lighting samples), it will receive * barycentric coordinates within the current polygon. It will also receive * a list of RpLights affecting the current object. * * The barycentric coordinates may be used, for example, to allow a callback * to easily import existing lighting data (e.g from previously generated * lightmaps in a different format, or from an art package with lighting * functionality). * * NOTE: The alpha channel of the RwRGBA results array must NOT be modified. * These values are used internally and their modification may result in * unwanted visual artifacts in the resulting lighting solution. * * The default RtLtMapIlluminateSampleCallBacks supplied with RtLtMap is * \ref RtLtMapDefaultSampleCallBack. This callback performs point and area * lighting (the area lights use are those passed to \ref RtLtMapIlluminate). * * \param results A pointer to an array of \ref RwRGBA sample color values * \param samplePositions A pointer to an array of \ref RwV3d values specifying the * world-space positions of each of the samples in the results array * \param baryCoords A pointer to an array of \ref RwV3d values specifying the * barycentric coordinates (within the current polygon) of * each of the samples in the results array * \param numSamples The length of the results, samplePositions, baryCoords and normals arrays * \param lights An array of pointers to \ref RpLight's affecting the current object * \param numLights The length of the lights array * \param normals A pointer to an array of \ref RwV3d values specifying the * world-space, unit normals of each of the samples in the results array * * \return A pointer to the results array on success, NULL otherwise * * \see RtLtMapIlluminate * \see RtLtMapIlluminateVisCallBack * \see RtLtMapIlluminateProgressCallBack */ typedef RwRGBA *(*RtLtMapIlluminateSampleCallBack)(RwRGBA *results, RwV3d *samplePositions, RwV3d *baryCoords, RwUInt32 numSamples, RpLight **lights, RwUInt32 numLights, RwV3d *normals); /** * \ingroup rtltmap * \typedef RtLtMapIlluminateVisCallBack * \ref RtLtMapIlluminateVisCallBack is the callback to be called, from * within \ref RtLtMapIlluminate, to determine the visibility between a * sample and a light. * * This callback is called for all samples in the current * \ref RtLtMapLightingSession and for each light source which may * potentially affect each of those samples (this may not be all the * lights in the scene, as some hierarchical culling is performed). * Each sample may represent a texel in the current object's lightmap * or the prelight color of a vertex, depending on whether the object * is lightmapped and/or vertex-lit (see \ref RtLtMapObjectFlags). * * The callback will receive a pointer to the world of the current * \ref RtLtMapLightingSession (this may be used to perform intersection * tests), the world-space position of the sample, the world-space * position of the light, a pointer to a light and a pointer to an * \ref RwRGBAReal result value. * * If the light pointer is NULL, this means that the current light * is an area light (as opposed to an \ref RpLight), of an internal * format. The area lights use are those passed to \ref RtLtMapIlluminate. * * The callback should return FALSE to signify that the light is wholly * occluded w.r.t the sample position, otherwise it should return TRUE. * Partial degrees of (color-frequency-dependent) occlusion may be * expressed by modifying the RwRGBAReal value. This defaults to bright * white but may be reduced to signify that the light from the light * source should be attenuated. This could be used to take into account * light-filtering objects in the scene (such as coloured glass or fog). * * The default RtLtMapIlluminateVisCallBack supplied with RtLtMap is * \ref RtLtMapDefaultVisCallBack. This callback performs visibility * tests using the line-intersection tests from \ref rtintersect. It tests * for occlusion by RpWorldSectors and RpAtomics and it respects the * relevant \ref RtLtMapObjectFlags and \ref RtLtMapMaterialFlags but it * does not filter light; visibility is determined to be either one or zero. * * \param world The world of the current RtLtMapLightingSession * \param result An RwRGBAReal value to attentuate this light's * contribution to the current sample * \param samplePos The world-space positiuon of the sample * \param lightPos The world-space positiuon of the light * \param light A pointer to the light (NULL if it is an are light) * * \return TRUE if the light is visible from the sample, FALSE if it is occluded * * \see RtLtMapIlluminate * \see RtLtMapIlluminateSampleCallBack * \see RtLtMapIlluminateProgressCallBack */ typedef RwBool (*RtLtMapIlluminateVisCallBack)(RpWorld *world, RwRGBAReal *result, RwV3d *samplePos, RwV3d *lightPos, RpLight *light); /** * \ingroup rtltmap * \typedef RtLtMapIlluminateProgressCallBack * \ref RtLtMapIlluminateProgressCallBack is the callback to be called, from * within \ref RtLtMapIlluminate, to allow a user to track lighting progress. * * The progress callback will be called at several stages during lighting, * with a different 'message' parameter value used at each stage (see * \ref RtLtMapProgressMessage). It will be called at the very start of * lighting (for a given \ref RtLtMapLightingSession), before any samples * are lit. It will also be called at the very end of lighting, after all * samples have been lit. It will be called before and after each lighting * 'slice' (see \ref RtLtMapIlluminate) and also after each group of * samples have been lit. * * For lightmapped objects, samples are grouped on a per-polygon basis and * for vertex-lit objects, samples are grouped on a per-object basis (see * \ref RtLtMapObjectFlags). * * The progress callback will receive a RwReal value specifying the percentage * of samples already lit in the current \ref RtLtMapLightingSession (see * \ref RtLtMapLightingSessionGetNumSamples). * * By returning FALSE, the progress callback may cause early termination of * the current lighting 'slice' (this may be used, for example, to keep * the time spent lighting each slice fairly constant). * * There is no default progress callback supplied with RtLtMap. * * \param message A \ref RtLtMapProgressMessage identifying the stage * of the current call to the progress callback * \param value The percentage of samples already lit in the * current \ref RtLtMapLightingSession * * \return FALSE to immediately terminate lighting, otherwise TRUE * * \see RtLtMapIlluminate * \see RtLtMapIlluminateSampleCallBack * \see RtLtMapIlluminateVisCallBack */ typedef RwBool (*RtLtMapIlluminateProgressCallBack)(RwInt32 message, RwReal value); /** * \ingroup rtltmap * \ref RtLtMapProgressMessage is an enumerated type identifying the different * stages at which the \ref RtLtMapIlluminateProgressCallBack may be called * from within \ref RtLtMapIlluminate. * * \see RtLtMapIlluminateProgressCallBack * \see RtLtMapIlluminate */ enum RtLtMapProgressMessage { rtLTMAPPROGRESSNAMESSAGE = 0, rtLTMAPPROGRESSSTART = 1, /**< This is issued at the beginning of * an incremental lighting session */ rtLTMAPPROGRESSSTARTSLICE = 2, /**< This is issued at the beginning of every * slice in an incremental lighting session */ rtLTMAPPROGRESSUPDATE = 3, /**< This is issued after the lighting of each * lightmapped triangle or vertex-lit object */ rtLTMAPPROGRESSENDSLICE = 4, /**< This is issued at the end of every slice * in an incremental lighting session */ rtLTMAPPROGRESSEND = 5, /**< This is issued at the end of an * incremental lighting session */ rtLTMAPPROGRESSFORCEENUMSIZEINT = 0x7FFFFFFF }; typedef enum RtLtMapProgressMessage RtLtMapProgressMessage; typedef struct RtLtMapLightingSession RtLtMapLightingSession; /** * \ingroup rtltmap * \typedef RtLtMapLightingSession * The \ref RtLtMapLightingSession structure holds information to be passed to * \ref RtLtMapIlluminate. It is used to parameterize the lighting process. * * The \ref RtLtMapLightingSession structure encapsulates a set of objects and * keeps track of the proportion of samples, within that set, that have already * been lit by calls to \ref RtLtMapIlluminate. Each call performs lighting for * one 'slice' of the whole 'session'. If the camera member is non-NULL, it is * important that the camera is not moved between lighting slices. * * The \ref RtLtMapLightingSession is also passed to * \ref RtLtMapLightMapsCreate, \ref RtLtMapLightMapsClear, * \ref RtLtMapLightMapsDestroy and \ref RtLtMapAreaLightGroupCreate, * though not all of the session structure's member will be used in * each of these cases. * * \see RtLtMapIlluminate * \see RtLtMapLightMapsCreate * \see RtLtMapLightMapsClear * \see RtLtMapLightMapsDestroy * \see RtLtMapAreaLightGroupCreate */ struct RtLtMapLightingSession { RpWorld *world; /**< This world is that in which collisions are performed * during illumination (for the purposes of lighting * visibility determination) */ RwCamera *camera; /**< An optional pointer to a camera. The camera's frustum * may be used to cull objects and/or triangles from the * set of those to be processed. */ RpWorldSector **sectorList; /**< An optional array of \ref RpWorldSector pointers, * specifying which sectors in the world to light. If * this is NULL, then all sectors in the world (or those * inside the optional camera's frustum) will be lit. */ RwInt32 numSectors; /**< The length of the sectorList array. If this is set to * '-1' then none of the sectors in the world will be lit. */ RpAtomic **atomicList; /**< An optional array of \ref RpAtomic pointers, * specifying which atomics to light. If this is NULL * then all atomics in the world (or those inside the * optional camera's frustum) will be lit. */ RwInt32 numAtomics; /**< The length of the atomicList array. If this is set to * '-1' then none of the atomics in the world will be lit. */ RwUInt32 startSample; /**< Lighting for the current 'slice' should begin with this * sample. It is the user's responsibility to increment this * value after each slice. Note that partial lighting is * quantized to be per-polygon (for lightmapped objects). * startSample will always be rounded down, not up. */ RwUInt32 numSamples; /**< This specifies how many lightmap samples should be lit. * If it is left zero then all samples in the current set * of objects will be lit. Note that partial lighting is * quantized to be per-polygon (for lightmapped objects). * numSamples will always be rounded up, not down. */ RwUInt32 totalSamples;/**< This specifies how many lightmap samples will be lit in * total for the world specified (this is filled in by * \ref RtLtMapIlluminate, not the calling function). */ RtLtMapIlluminateSampleCallBack sampleCallBack; /**< A \ref RtLtMapIlluminateSampleCallBack * to use during lighting. If this is left * NULL, the default callback will be used. */ RtLtMapIlluminateVisCallBack visCallBack; /**< A \ref RtLtMapIlluminateVisCallBack * to use during lighting. If this is left * NULL, the default callback will be used. */ RtLtMapIlluminateProgressCallBack progressCallBack; /**< A \ref RtLtMapIlluminateProgressCallBack * to use during lighting. If this is left * NULL, no progress callback will be used. */ }; /** * \ingroup rtltmap * \ref RtLtMapMaterialFlags is an enumerated type specifying the different * lightmap-related flags which may be applied to materials. These values * will be taken into consideration within \ref RtLtMapIlluminate. * * \see RtLtMapMaterialGetFlags * \see RtLtMapMaterialSetFlags * \see RtLtMapMaterialGetAreaLightColor * \see RtLtMapMaterialSetAreaLightColor * \see RtLtMapMaterialGetLightMapDensityModifier * \see RtLtMapMaterialSetLightMapDensityModifier * \see RtLtMapMaterialGetAreaLightDensityModifier * \see RtLtMapMaterialSetAreaLightDensityModifier * \see RtLtMapMaterialSetAreaLightRadiusModifier * \see RtLtMapMaterialGetAreaLightRadiusModifier * \see RtLtMapIlluminate * \see RtLtMapAreaLightGroupCreate * \see RtLtMapIlluminateVisCallBack */ enum RtLtMapMaterialFlags { rtLTMAPMATERIALNAFLAG = 0, rtLTMAPMATERIALLIGHTMAP = 1, /**< This material should be lightmapped * [for non-lightmapped materials within lightmapped objects, * texel values will be set to (0, 0, 0) (or (255, 255, 255) if * the rtLTMAPMATERIALAREALIGHT flag is present, so that light- * emitting textures appear as bright as the light which they are * emittering) and the mesh may be 'shrunk' in UV-space so as not * to waste lightmap texels] */ rtLTMAPMATERIALAREALIGHT = 2, /**< This material is an area light emitter * (see \ref RtLtMapAreaLightGroupCreate) */ rtLTMAPMATERIALNOSHADOW = 4, /**< This material does not block light */ rtLTMAPMATERIALSKY = 8, /**< This material blocks everything but directional * lights, to allow sky polygons to occlude geometry * and yet emit directional light (sky or sun light, * being as if cast from an infinite distance) */ rtLTMAPMATERIALFLATSHADE = 16, /**< This material will be lit as if flat-shaded * (polygon normals will be used during illumination) */ rtLTMAPMATERIALFLAGFORCEENUMSIZEINT = 0x7FFFFFFF }; typedef enum RtLtMapMaterialFlags RtLtMapMaterialFlags; /** * \ingroup rtltmap * \ref RtLtMapObjectFlags is an enumerated type specifying the different * lightmap-related flags which may be applied to world sectors and * atomics. These values will be taken into consideration within * \ref RtLtMapLightMapsCreate and \ref RtLtMapIlluminate. * * \see RtLtMapAtomicGetFlags * \see RtLtMapAtomicSetFlags * \see RtLtMapWorldSectorGetFlags * \see RtLtMapWorldSectorSetFlags * \see RtLtMapLightMapsCreate * \see RtLtMapIlluminate * \see RtLtMapIlluminateVisCallBack */ enum RtLtMapObjectFlags { rtLTMAPOBJECTNAFLAG = 0, rtLTMAPOBJECTLIGHTMAP = 1, /**< This object is to be lightmapped */ rtLTMAPOBJECTVERTEXLIGHT = 2, /**< This object's vertex prelight colours should * be lit within \ref RtLtMapIlluminate. */ rtLTMAPOBJECTNOSHADOW = 4, /**< This object does not cast shadows (useful, for * example, for moving objects for which dynamic * shadows are to be rendered - such as doors) */ rtLTMAPOBJECTFLAGFORCEENUMSIZEINT = 0x7FFFFFFF }; typedef enum RtLtMapObjectFlags RtLtMapObjectFlags; /* Area-lighting stuff:* ***********************/ /** * \ingroup rtltmap * \typedef RtLtMapAreaLightGroup * \ref RtLtMapAreaLightGroup is a structure which acts as a container * for area lights created by a call to \ref RtLtMapAreaLightGroupCreate. * The containers may be chained and passed to \ref RtLtMapIlluminate. * Each container has an optional pointer to a RwFrame which is used to * transform the contained area lights relative to the world of the current * \ref RtLtMapLightingSession and relative to each other (such that, for * example, lights from multiple worlds, which are connected by portals, * or which are composed of atomics and not world sectors, may be used * within a single call to \ref RtLtMapIlluminate). * * \see RtLtMapAreaLightGroupCreate * \see RtLtMapAreaLightGroupDestroy * \see RtLtMapIlluminate * \see RtLtMapIlluminateVisCallBack */ typedef struct RtLtMapAreaLightGroup RtLtMapAreaLightGroup; struct RtLtMapAreaLightGroup { RwSList *meshes; /**< A list of hierarchically-grouped area lights */ RwFrame *frame; /**< An (optional) pointer to a frame (owned by something else) * whose LTM specifies the coordinate system of this container, * relative to the world of the current \ref RtLtMapLightingSession. */ RtLtMapAreaLightGroup *next; /**< A pointer for chaining are light groups together */ }; /* Area light triangles are grouped by source mesh (this may change) */ typedef struct LtMapAreaLightMesh LtMapAreaLightMesh; struct LtMapAreaLightMesh { RwUInt32 flags; /* To hold hierarchical visibility culling flags, * relevant to the object/triangle *currently* being lit. */ RpMaterial *material; /* The emitter material, containing colour, etc */ RwSphere sphere; /* Each mesh has an associated center and radius */ RwReal ROI; /* Centred on the above sphere, the R.O.I. of the * samples in this mesh (a conservative estimate) */ RwSList *triangles; /* A list of the area light triangles in this mesh */ }; /* Area light samples are grouped by source triangle */ typedef struct LtMapAreaLight LtMapAreaLight; struct LtMapAreaLight { RwUInt16 flags; /* To hold hierarchical visibility culling flags, * relevant to the object/triangle *currently* being lit. */ RwUInt16 numSamples; /* Number of area light samples in this triangle */ RwReal areaPerSample; /* (triangleArea / numSamples) for this triangle */ RwPlane plane; /* This 'area light' is a triangle, this is its plane. */ RwSphere sphere; /* This bounds the triangle's points in world-space (it's * not worth storing 3 points, coarse culling is fine) */ RwV3d *lights; /* Array of area light sample positions (in world-space) */ }; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Lightmap creation functionality: */ extern RtLtMapLightingSession * RtLtMapLightMapsCreate(RtLtMapLightingSession *session, RwReal density, RwRGBA *color); extern void RtLtMapLightMapsDestroy(RtLtMapLightingSession *session); extern RpAtomic * RtLtMapAtomicLightMapDestroy(RpAtomic *atomic); extern RpWorldSector * RtLtMapWorldSectorLightMapDestroy(RpWorldSector *sector); extern RwReal RtLtMapGetVertexWeldThreshold(void); extern RwBool RtLtMapSetVertexWeldThreshold(RwReal threshold); extern RwUInt32 RtLtMapLightMapGetDefaultSize(void); extern RwBool RtLtMapLightMapSetDefaultSize(RwUInt32 size); extern RwUInt32 RtLtMapAtomicGetLightMapSize(RpAtomic *atomic); extern RpAtomic * RtLtMapAtomicSetLightMapSize(RpAtomic *atomic, RwUInt32 size); extern RwUInt32 RtLtMapWorldSectorGetLightMapSize(RpWorldSector *sector); extern RpWorldSector * RtLtMapWorldSectorSetLightMapSize(RpWorldSector *sector, RwUInt32 size); extern RwUInt32 RtLtMapAtomicGetFlags(RpAtomic *atomic); extern RpAtomic * RtLtMapAtomicSetFlags(RpAtomic *atomic, RwUInt32 flags); extern RwUInt32 RtLtMapWorldSectorGetFlags(RpWorldSector *sector); extern RpWorldSector * RtLtMapWorldSectorSetFlags(RpWorldSector *sector, RwUInt32 flags); /* Lightmap illumination functionality: */ extern RwUInt32 RtLtMapIlluminate(RtLtMapLightingSession *session, RtLtMapAreaLightGroup *lights); extern RwReal RtLtMapGetSliverAreaThreshold(void); extern RwBool RtLtMapSetSliverAreaThreshold(RwReal threshold); extern RwRGBA * RtLtMapDefaultSampleCallBack(RwRGBA *results, RwV3d *samplePositions, RwV3d * __RWUNUSED__ baryCoords, RwUInt32 numSamples, RpLight **lights, RwUInt32 numLights, RwV3d *normals); extern RwBool RtLtMapDefaultVisCallBack(RpWorld *world, RwRGBAReal __RWUNUSED__ *result, RwV3d *samplePos, RwV3d *lightPos, RpLight __RWUNUSED__ *light); extern RtLtMapLightingSession * RtLtMapLightingSessionInitialize(RtLtMapLightingSession *session, RpWorld *world); extern RwInt32 RtLtMapLightingSessionGetNumSamples(RtLtMapLightingSession *session); extern RwInt32 RtLtMapWorldSectorGetNumSamples(RpWorldSector *sector); extern RwInt32 RtLtMapAtomicGetNumSamples(RpAtomic *atomic); extern RtLtMapLightingSession * RtLtMapImagesPurge(RtLtMapLightingSession *session); extern RpAtomic * RtLtMapAtomicImagePurge(RpAtomic *atomic); extern RpWorldSector * RtLtMapWorldSectorImagePurge(RpWorldSector *sector); extern RtLtMapLightingSession * RtLtMapLightMapsClear(RtLtMapLightingSession *session, RwRGBA *color); extern RpAtomic * RtLtMapAtomicLightMapClear(RpAtomic *atomic, RwRGBA *color); extern RpWorldSector * RtLtMapWorldSectorLightMapClear(RpWorldSector *sector, RwRGBA *color); /* Material/area-lighting functionality: */ extern RtLtMapAreaLightGroup * RtLtMapAreaLightGroupCreate(RtLtMapLightingSession *session, RwReal density); extern RwBool RtLtMapAreaLightGroupDestroy(RtLtMapAreaLightGroup *lights); extern RwUInt32 RtLtMapMaterialGetFlags(RpMaterial *material); extern RpMaterial * RtLtMapMaterialSetFlags(RpMaterial *material, RwUInt32 flags); extern RwReal RtLtMapMaterialGetLightMapDensityModifier(RpMaterial *material); extern RpMaterial * RtLtMapMaterialSetLightMapDensityModifier(RpMaterial *material, RwReal modifier); extern RwRGBA RtLtMapMaterialGetAreaLightColor(RpMaterial *material); extern RpMaterial * RtLtMapMaterialSetAreaLightColor(RpMaterial *material, RwRGBA color); extern RwReal RtLtMapMaterialGetAreaLightDensityModifier(RpMaterial *material); extern RpMaterial * RtLtMapMaterialSetAreaLightDensityModifier(RpMaterial *material, RwReal modifier); extern RwReal RtLtMapMaterialGetAreaLightRadiusModifier(RpMaterial *material); extern RpMaterial * RtLtMapMaterialSetAreaLightRadiusModifier(RpMaterial *material, RwReal modifier); extern RwUInt32 RtLtMapGetMaxAreaLightSamplesPerMesh(void); extern RwBool RtLtMapSetMaxAreaLightSamplesPerMesh(RwUInt32 maxSamples); extern RwReal RtLtMapGetAreaLightDensityModifier(void); extern RwBool RtLtMapSetAreaLightDensityModifier(RwReal modifier); extern RwReal RtLtMapGetAreaLightRadiusModifier(void); extern RwBool RtLtMapSetAreaLightRadiusModifier(RwReal modifier); extern RwReal RtLtMapGetAreaLightErrorCutoff(void); extern RwBool RtLtMapSetAreaLightErrorCutoff(RwReal tolerance); /* Texture-saving functionality: */ extern RwTexDictionary * RtLtMapTexDictionaryCreate(RtLtMapLightingSession *session); extern const RwChar * RtLtMapGetDefaultPrefixString(void); extern RwBool RtLtMapSetDefaultPrefixString(RwChar *string); extern RwUInt32 RtLtMapGetLightMapCounter(void); extern RwBool RtLtMapSetLightMapCounter(RwUInt32 value); #if (defined(SKY2_DRVMODEL_H) || defined(NULLSKY_DRVMODEL_H)) /* PS2-specific functionality: */ extern RwTexture *RtLtMapSkyLightMapMakeDarkMap(RwTexture *lightMap); extern RwTexture *RtLtMapSkyBaseTextureProcess(RwTexture *texture); extern RpAtomic *RtLtMapSkyAtomicBaseTexturesProcess(RpAtomic *atomic); extern RpWorldSector * RtLtMapSkyWorldSectorBaseTexturesProcess(RpWorldSector *sector); extern RtLtMapLightingSession * RtLtMapSkyBaseTexturesProcess(RtLtMapLightingSession *session); #endif /* (defined(SKY2_DRVMODEL_H) || defined(NULLSKY_DRVMODEL_H)) */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* RTLTMAP_H */