///////////////////////////////////////////////////////////////////////////////
//
// File: AVP_Laser.h
//
// Created by Andrew Southgate 12/11/2007
// 
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
// Handles rendering of the predators tri-laser thingy
//
///////////////////////////////////////////////////////////////////////////////

#if defined ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#if !defined __AVP_LASER_H__
#define __AVP_LASER_H__

#include "Animation/Asura_AnimationAttachment.h"
#include "Rendering/Asura_Colour.h"

class Asura_Photon;

class AVP_Laser
{
	static const int MAX_NUM_BEAMS = 3;
	static AVP_Laser *s_pxFirst;
	static AVP_Laser *s_pxLast;

	Asura_Vector_3 m_xOrigin;
	Asura_Matrix_3x3 m_xOrient;

	float m_fBeamRadius;
	float m_fBeamSpread;
	float m_fBeamSharpness;
	float m_fRadius;
	float m_fMaxLength;
	float m_fFallOffLength;
	float m_fTargetLerpValue;
	float m_fFallOffStartAngle;
	float m_fFallOffEndAngle;
	float m_fFallOffStartDistance;
	float m_fFallOffEndDistance;
	float m_fFallOffAngleEndIntensity;
	float m_fBeamVisibilityDistance;

	bool m_bOriginPhotonEnabled;
	float m_fOriginPhotonRadius;
	float m_fOriginPhotonFalloffScale;
	float m_fOriginPhotonFalloffPower;
	bool  m_bOriginPhotonEnableDistanceFade;
	float m_fOriginPhotonDistanceFadeStart;
	float m_fOriginPhotonDistanceFadeDist;

	bool m_bContactPhotonEnabled;
	float m_fContactPhotonRadius;
	float m_fContactPhotonFalloffScale;
	float m_fContactPhotonFalloffPower;
	bool  m_bContactPhotonEnableDistanceFade;
	float m_fContactPhotonDistanceFadeStart;
	float m_fContactPhotonDistanceFadeDist;
	float m_fContactPhotonBackOffDistance;

	u_int m_uNumBeams;
	static Asura_RGBA m_rgbaColour;
	Asura_RGBA m_xOriginPhotonColour;
	Asura_RGBA m_xContactPhotonColour;
	Asura_Guid m_uGuidToIgnore;
	float m_xBeamLengths[MAX_NUM_BEAMS];
	Asura_Photon *m_pxOriginPhoton;
	Asura_Photon *m_pxContactPhotons[MAX_NUM_BEAMS];

	bool m_bVisiblity;
	bool m_bActive;
#ifdef ASURA_ASSERT
	bool m_bPosValid;
	bool m_bOrientValid;
#endif

	AVP_Laser *m_pxNext;
	AVP_Laser *m_pxPrev;

public:
	AVP_Laser();
	~AVP_Laser();

	const Asura_Vector_3 &GetPosition() const {return m_xOrigin;}
	void SetPosition(Asura_Vector_3 xOrigin) {
		m_xOrigin = xOrigin;
#ifdef ASURA_ASSERT
		m_bPosValid = true;
#endif
	}

	const Asura_Matrix_3x3 &GetOrientation() const {return m_xOrient;}
	void SetOrientation(const Asura_Matrix_3x3 &xOrientation) {
		m_xOrient = xOrientation;
#ifdef ASURA_ASSERT
		m_bOrientValid = true;
#endif
	}

	float GetRadius() const {return m_fRadius;}
	void SetRadius(float fRadius) {m_fRadius = fRadius;}

	float GetMaximumLength() const {return m_fMaxLength;}
	void SetMaximumLength(float fMaxLength) {m_fMaxLength = fMaxLength;}

	float GetFallOffLength() const {return m_fFallOffLength;}
	void SetFallOffLength(float fFallOffLength) {m_fFallOffLength = fFallOffLength;}


	u_int GetNumBeams() const {return m_uNumBeams;}
	void SetNumBeams(u_int uNumBeams); 

	// The width of part of the beam at full intensity
	float GetBeamRadius() const {return m_fBeamRadius;}
	void SetBeamRadius(float fBeamRadius) {m_fBeamRadius = fBeamRadius;}

	// How much does the beam spread at point of emission
	float GetBeamSharpness() const {return m_fBeamSharpness;}
	void SetBeamSharpness(float fBeamSharpness) {m_fBeamSharpness = fBeamSharpness;}

	// How much does the beam spread over distance
	float GetBeamSpread() const {return m_fBeamSpread;}
	void SetBeamSpread(float fBeamSpread) {m_fBeamSpread = fBeamSpread;}

	float GetFallOffStartAngle() const {return m_fFallOffStartAngle;}
	void SetFallOffStartAngle(float fFallOffStartAngle) {m_fFallOffStartAngle = fFallOffStartAngle;}

	float GetFallOffStartDistance() const {return m_fFallOffStartDistance;}
	void SetFallOffStartDistance(float fFallOffStartDistance) {m_fFallOffStartDistance = fFallOffStartDistance;}

	float GetFallOffEndDistance() const {return m_fFallOffEndDistance;}
	void SetFallOffEndDistance(float fFallOffEndDistance) {m_fFallOffEndDistance = fFallOffEndDistance;}

	float GetBeamVisibilityDistance() const {return m_fBeamVisibilityDistance;}
	void SetBeamVisibilityDistance(float fBeamVisibilityDistance) {m_fBeamVisibilityDistance = fBeamVisibilityDistance;}


	float GetFallOffEndAngle() const {return m_fFallOffEndAngle;}
	void SetFallOffEndAngle(float fFallOffEndAngle) {m_fFallOffEndAngle = fFallOffEndAngle;}

	float GetFallOffAngleEndIntensity() const {return m_fFallOffAngleEndIntensity;}
	void SetFallOffAngleEndIntensity(float fFallOffAngleEndIntensity) {m_fFallOffAngleEndIntensity = fFallOffAngleEndIntensity;}


	// total width of the beam at any point = Radius + Sharpness + Distance * Spread
	// where Distance is the length traveled along the beam
	// Beam has full alpha when distance from closest point on beam < Radius
	// and lerps to zero alpha when distance == total width

	static Asura_RGBA GetColour() {return m_rgbaColour;}
	static void SetColour(Asura_RGBA rgbaColour) {m_rgbaColour = rgbaColour;}

	bool GetVisiblity() const {return m_bVisiblity;}
	void SetVisiblity(bool bVisiblity) {m_bVisiblity = bVisiblity;}

	// Does the same as the visibility flag but this is used by the animation attachment
	// so that the 2 dont interfere
	bool GetActive() const {return m_bActive;}
	void SetActive(bool bActive);

	Asura_Guid	GetGuidToIgnore(void) const				{ return(m_uGuidToIgnore); }
	void		SetGuidToIgnore(const Asura_Guid uGuid)	{ m_uGuidToIgnore = uGuid; }


	void SetOriginPhotonEnabled(bool bEnabled);
	void SetOriginPhotonRadius(float fRadius);
	void SetOriginPhotonColour(const Asura_RGBA &xColour);
	void SetOriginPhotonFalloffScale(float fScale);
	void SetOriginPhotonFalloffPower(float fPower);
	void SetOriginPhotonDistanceFade(bool bEnable, float fStart = 0.0f, float fDist = 0.0f);

	void SetContactPhotonEnabled(bool bEnabled);
	void SetContactPhotonRadius(float fRadius);
	void SetContactPhotonColour(const Asura_RGBA &xColour);
	void SetContactPhotonFalloffScale(float fScale);
	void SetContactPhotonFalloffPower(float fPower);
	void SetContactPhotonDistanceFade(bool bEnable, float fStart = 0.0f, float fDist = 0.0f);
	void SetContactPhotonBackOffDistance(float fDistance);


	static void Initialise();
	void Update();
	static void Render();
	static void Shutdown();
};

class AVP_AnimationAttachment_Laser : public Asura_AnimationAttachment
{
	typedef  Asura_AnimationAttachment PARENT;
public:

	// IMPORTANT: effect id must be an entity effect!
	AVP_AnimationAttachment_Laser( AVP_Laser *pLaser, bool bDeleteEffectWithParent );
	AVP_AnimationAttachment_Laser( const AVP_AnimationAttachment_Laser* pxOther );

	AVP_Laser *GetLaser() {return m_pxLaser;}

	virtual ~AVP_AnimationAttachment_Laser();

	virtual Asura_AnimationAttachment* Clone( Asura_Animation* pxParent );

	virtual void Update( float fTime, bool bIgnoreTimerFrameStamp );

	void SetOffset(const Asura_Vector_3 &xOffset) { m_xOffset = xOffset; }
	const Asura_Vector_3 &GetOffset() { return m_xOffset; }

	void SetTarget(const Asura_Vector_3 &xOrient);
	void SetTarget(const Asura_Guid uTargetGuid, const Asura_Hash_ID uTargetMPHash);
	void SetTargetEnabled(bool bEnable);
	void SetTargetLerpTime(float fTargetLerpTime);
	void SetTargetLerpValue(float fTargetLerpValue);

	const Asura_Vector_3 &GetTarget(void) const;
	bool GetTargetEnabled() const;
	float GetTargetLerpTime() const;
	float GetTargetLerpValue() const;
	
	void SetProjector(int uProjectorHandle, bool bDeleteWhenRemoved);
	int GetProjector() {return m_iProjectorHandle; }

	virtual bool LinkAttachment(Asura_Animation* pxParentAnimation,Asura_Hash_ID uMarkerHash,bool bDeleteWhenUnlinked = true);
	virtual bool LinkAttachment(Asura_Animation* pxParentAnimation,const char* pszMarkerName,bool bDeleteWhenUnlinked = true) {return PARENT::LinkAttachment(pxParentAnimation, pszMarkerName, bDeleteWhenUnlinked);}
	virtual void UnlinkAttachment();
	void UnlinkAttachment( bool bAndDelete ) { Asura_AnimationAttachment::UnlinkAttachment(bAndDelete); }

	virtual void OnParentVisibilityChanged( bool bInvisibility); 

private:
	bool m_bEnableTarget;
	bool m_bUsingTargetGuid;
	float m_fInverseTargetLerpTime;
	float m_fTargetLerpValue;
	Asura_Guid m_uTargetGuid;
	Asura_Hash_ID m_uTargetMPHash;
	Asura_Vector_3 m_xPrevTarget;
	Asura_Vector_3 m_xTarget;
	Asura_Vector_3 m_xCurTarget;
	Asura_Vector_3 m_xOffset;

	AVP_Laser *m_pxLaser;

	bool m_bDeleteProjector;
	int m_iProjectorHandle;

};

#endif // __AVP_LASER_H__
