/*****************************************************************************
The Dark Mod GPL Source Code

This file is part of the The Dark Mod Source Code, originally based
on the Doom 3 GPL Source Code as published in 2011.

The Dark Mod Source Code 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. For details, see LICENSE.TXT.

Project: The Dark Mod (http://www.thedarkmod.com/)

******************************************************************************/

#ifndef DARKMOD_LAS_H
#define DARKMOD_LAS_H

//class darkModLAS;

// DarkMod globals (needed for Light.h)
#include "DarkModGlobals.h"

// idLight 
#include "Light.h"

// The PVS to AAS mapping table
#include "PVSToAASMapping.h"


/*!
* This structure tracks a light in relation to the area system
*/
typedef struct darkModLightRecord_s
{
	/*!
	* The light object
	*/
	idLight* p_idLight;

    /*!
	* index of the Area the light is currently located within
	*/
    int areaIndex;
    
    /*!
	* Last world position of the light 
	* This is tracked so that we don't bother to recalcluate movement between PVS
	* areas if the position has not changed this frame.
	*/
    idVec3 lastWorldPos;

    /*!
	* A flag used to track if this light has been updated yet this frame
	*/
    unsigned int lastFrameUpdated;
        
} darkModLightRecord_t;

//---------------------------------------------------------------------------

class darkModLAS
{
protected:

    // Each area (PVS) in the map has its own light list
    int m_numAreas;
	
	// The area index is the index into the array
	// Dereferencing it gives a list of darkModLightRecord_t pointers
	idLinkList<darkModLightRecord_t>** m_pp_areaLightLists;

    /*!
    * Called to update the lights in a given bounding area.  
    */
    void updateLights (idBounds updateBounds, int updateFrameIndex);

    /*!
    * This is used to identify which lights have not been updated this frame
    * This value should be updated once per game frame, (or some fraction thereof if lighting gets
    * updated less often)
    */ 
    unsigned int m_updateFrameIndex;

    /*!
    * This method is used to move a light from one area to another
    * @return false if failed
    * @return true if succeeded
    */ 
    bool moveLightBetweenAreas (darkModLightRecord_t* p_light, int oldAreaNum, int newAreaNum );

    bool traceLightPath( idVec3 to, idVec3 from, idEntity* ignore, idLight* light); // grayman #2853 // grayman #3584

    /*!
    * This method is used to add up all the light intensities contributed from
    * a specific region apon the line between the two test points.
    *
    * @param areaIndex index of the area within the Area System whose lights should
    *     be accumulated
    * @param testPoint1 first point along the line whose lighting is being tested
    * @param testPoint2 second point along the line whose lighting is being tested
    * @param p_ignoreEntity An entity whose occlusion of a light should not be considered
    * @param b_useShadows if true, then shadow volumes are considered
    * @returns the total intensity on the point from lights in the test area
    */
    void accumulateEffectOfLightsInArea 
	( 
		float& inout_totalIllumination,
		int areaIndex, 
		idVec3 testPoint1,
		idVec3 testPoint2,
		idEntity* p_ignoreEntity,
		bool b_useShadows
	);

    /*!
    * This method is used to add up all the light intensities contributed from
    * a specific region apon the line between the two test points.
    *
    * @param areaIndex index of the area within the Area System whose lights should
    *     be accumulated
    * @param box boundary of volume being tested
    * @param p_ignoreEntity An entity whose occlusion of a light should not be considered
    * @param b_useShadows if true, then shadow volumes are considered
    * @returns the total intensity on the point from lights in the test area
    */
	void accumulateEffectOfLightsInArea2 
	( 
		float& inout_totalIllumination,
		int areaIndex, 
		idBox box,
		idEntity* p_ignoreEntity,
		bool b_useShadows
	);

    // stgatilov #6546: added a way to completely disable LAS
	bool Disabled() const;

public:

   	void Save( idSaveGame *savefile ) const;
	void Restore( idRestoreGame *savefile );

    /*!
    * This mapping is used by certain queries
    * It is initialized in darkModLAS::initialize and cleared in darkModLAS::shutdown
    */
    PVSToAASMapping pvsToAASMappingTable;

	/*!
	* Constructor
	*/
	darkModLAS();

	/*!
	* Destructor
	*/
	~darkModLAS();

	/*!
	* Call this when the map is loaded to initialize the PVS tracking
	*
	* @param aasFileIndex: The aas file to use for mapping between PVS and AAS
	*  areas (useful for AI visibility and search routines)
	*/
	void initialize();

	/*!
	* Call this when the map is being shut down
	*/
	void shutDown();


    /*!
    * add a light on light spawn
    */
    void addLight (idLight* p_idLight);

    /*!
    * Remove a light on its destruction
    */
    void removeLight (idLight* p_idLight);

    /*!
    * updateLASState:
    * This does one frame of light awareness tracking updates. It updates every
    * light in the system and moves it from area to area as needed.
    */
    void updateLASState();

    /*!
    * This would  determine a light intensity rating by summing the intensities of the lights
    * able to shine on the line.
    *
    * @param areaIndex index of the area within the Area System whose lights should
    *     be accumulated
    * @param testPoint1 first point along the line whose lighting is being tested
    * @param testPoint2 second point along the line whose lighting is being tested
    * @param p_ignoreEntity An entity whose occlusion of a light should not be considered
    * @param b_useShadows if true, then shadow volumes are considered
    * @returns the total intensity on the point from lights in the test area
    */
    float queryLightingAlongLine
    (
		idVec3 testPoint1,
		idVec3 testPoint2,
		idEntity* p_ignoreEntity,
		bool b_useShadows
    );

    /*!
    * This would  determine a light intensity rating by summing the intensities of the lights
    * able to shine on the best line inside a bounding box, where best is 'the closest line
    * to the light center'.
    *
    * @param areaIndex index of the area within the Area System whose lights should
    *     be accumulated
    * @param box of potential test lines
    * @param p_ignoreEntity An entity whose occlusion of a light should not be considered
    * @param b_useShadows if true, then shadow volumes are considered
    * @returns the total intensity on the bounding box from lights in the test area
    */
    float queryLightingAlongBestLine
    (
		idBox box,
		idEntity* p_ignoreEntity,
		bool b_useShadows
    );

    /**
    * This method gets the name of the AAS for which the LAS was initialized
    */
    idStr getAASName();

#ifdef TIMING_BUILD
private:
	int queryLightingAlongLineTimer;
#endif

};

// The Dark Mod Light Awareness System
extern darkModLAS LAS;

#endif
