//===========================================================================//
// File:	renderer.hpp                                                        //
// Project: MUNGA           Brick: Renderer Manager	                       //
// Contents: Interface specification Renderer and Renderer Manager			  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/21/94  ECH  Initial coding.                                            //
// 01/22/95	 ECH	Added NotifyOfBecomingUninterestingEntity						  //
// 05/25/95	 CPB	Moved GetLinkedEntity into public accessability for gauges //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#if !defined(RENDERER_HPP)
#	define RENDERER_HPP

#	if !defined(INTEREST_HPP)
#		include <interest.hpp>
#	endif

#	if !defined(RNDORGN_HPP)
#		include <rndorgn.hpp>
#	endif

#	if !defined(RESOURCE_HPP)
#		include <resource.hpp>
#	endif

	class DamageZone;
	class Subsystem;

	//~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer support types ~~~~~~~~~~~~~~~~~~~~~~~~~

	typedef Scalar RendererRate;
	extern const RendererRate DefaultRendererRate;

	typedef Scalar RendererComplexity;
	extern const RendererComplexity MaxRendererComplexity;
	extern const RendererComplexity MinRendererComplexity;

	typedef Scalar RendererFrameBudget;
	extern const RendererFrameBudget DefaultRendererFrameBudget;

	enum RendererPriority
	{
		LowRendererPriority = 0,
		DefaultRendererPriority,
		HighRendererPriority
	};

	enum RendererStatus
	{
		InactiveRendererStatus,
		LoadingRendererStatus,
		RunningRendererStatus
	};

	//##########################################################################
	//###########################    Renderer    ###############################
	//##########################################################################

	class Renderer__NotifyOfNewInterestingEntityMessage;
	class Renderer__NotifyOfBecomingUninterestingEntityMessage;

	class Renderer__StartEntityEffectMessage;
	class Renderer__StopAllEntityEffectsMessage;
	class Renderer__StartEntityAlarmMessage;
	class Renderer__StopEntityAlarmMessage;

	class Renderer:
		public Receiver
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Destruction, and Testing
	//
	public:
		~Renderer();

		Logical
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Control and processing
	//
	public:
		//
		//-----------------------------------------------------------------------
		// LoadMission, Shutdown
		//-----------------------------------------------------------------------
		//
		void
			LoadMission(Mission *mission);
		void
			Shutdown();

		//
		//-----------------------------------------------------------------------
		// LinkToEntity
		//
		// This method links the renderer to an entity.  Overrides must call
		// the inherited method.
		//-----------------------------------------------------------------------
		//
		virtual void
			LinkToEntity(Entity *entity);

		//
		//-----------------------------------------------------------------------
		// UnlinkFromEntity
		//-----------------------------------------------------------------------
		//
		virtual void
			UnlinkFromEntity();

		//
		//-----------------------------------------------------------------------
		// SetRendererStatusToRunning
		//-----------------------------------------------------------------------
		//
		void
			SetRendererStatusToRunning();

		//
		//-----------------------------------------------------------------------
		// UpdateInterestOrigin
		//-----------------------------------------------------------------------
		//
		void
			UpdateInterestOrigin(Time target_render_time);

		//
		//-----------------------------------------------------------------------
		// Execute
		//-----------------------------------------------------------------------
		//
		void
			Execute(
				Time target_render_time,
				RendererComplexity complexity_update
			);
		virtual Logical
			ExecuteBackground();

		//
		//-----------------------------------------------------------------------
		// Complete a rendering cycle (starts new frame)
		//-----------------------------------------------------------------------
		//
		virtual Logical
			CompleteCycle();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessors
	//
	public:
		//
		//-----------------------------------------------------------------------
		// GetLinkedEntity
		//-----------------------------------------------------------------------
		//
		Entity*
			GetLinkedEntity();

		//
		//-----------------------------------------------------------------------
		// GetRendererStatus
		//-----------------------------------------------------------------------
		//
		RendererStatus
			GetRendererStatus();

		//
		//-----------------------------------------------------------------------
		// Misc
		//-----------------------------------------------------------------------
		//
      RendererComplexity
			GetCalibrationComplexity();
      Time
			GetCalibrationFrameDuration();
		RendererRate
			GetCalibrationRate();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Interest Manager support
	//
	public:
		//
		//-----------------------------------------------------------------------
		// NotifyOfNewInterestingEntity
		//-----------------------------------------------------------------------
		//
		virtual void
			NotifyOfNewInterestingEntity(Entity *) {}

		//
		//-----------------------------------------------------------------------
		// NotifyOfBecomingUninterestingEntity
		//-----------------------------------------------------------------------
		//
		virtual void
			NotifyOfBecomingUninterestingEntity(Entity *) {}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message Support
	//
	public:
		enum {
      	NotifyOfNewInterestingEntityMessageID = Receiver::NextMessageID,
			NotifyOfBecomingUninterestingEntityMessageID,
			StartEntityEffectMessageID,
			StopAllEntityEffectsMessageID,
			StartEntityAlarmMessageID,
			StopEntityAlarmMessageID,
			NextMessageID
		};

		typedef Renderer__NotifyOfNewInterestingEntityMessage
      	NotifyOfNewInterestingEntityMessage;
		typedef Renderer__NotifyOfBecomingUninterestingEntityMessage
			NotifyOfBecomingUninterestingEntityMessage;
		typedef Renderer__StartEntityEffectMessage
			StartEntityEffectMessage;
		typedef Renderer__StopAllEntityEffectsMessage
			StopAllEntityEffectsMessage;
		typedef Renderer__StartEntityAlarmMessage
			StartEntityAlarmMessage;
		typedef Renderer__StopEntityAlarmMessage
			StopEntityAlarmMessage;

		static const HandlerEntry
			MessageHandlerEntries[];
		static MessageHandlerSet
			MessageHandlers;

		void
			NotifyOfNewInterestingEntityMessageHandler(
				NotifyOfNewInterestingEntityMessage *message
			);
		void
			NotifyOfBecomingUninterestingEntityMessageHandler(
				NotifyOfBecomingUninterestingEntityMessage *message
			);
		void
			StartEntityEffectMessageHandler(
				StartEntityEffectMessage *message
			);
		void
			StopAllEntityEffectsMessageHandler(
				StopAllEntityEffectsMessage *message
			);
		void
			StartEntityAlarmMessageHandler(
				StartEntityAlarmMessage *message
			);
		void
			StopEntityAlarmMessageHandler(
				StopEntityAlarmMessage *message
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	public:
		static Derivation ClassDerivations;
		static SharedData DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction
	//
	protected:
		//
		//-----------------------------------------------------------------------
		// Construction
		//
		// Where calibration_rate indicates the update rate, and
		// calibration_complexity indicates an arbitrary "maximum" complexity
		// level passed to the renderer.  The renderer manager will dynamically
		// vary the value of complexity based on the actual frame rate that the
		// renderer is able to maintain (if the total system load exceeds
		// 100% of the maximum, each renderer's actual frame rate will drop
		// below the requested rate: the renderer manager will detect this and
		// lower the complexity value). The renderer manager will then
		// periodically invoke the renderer's execute function, passing it the
		// value indicated in complexity.
		//-----------------------------------------------------------------------
		//
		Renderer(
			RendererRate calibration_rate,
			RendererComplexity calibration_complexity,
			RendererPriority calibration_priority,
			InterestType interest_type,
			InterestDepth depth_calibration,
			ClassID class_ID=TrivialReceiverClassID,
			SharedData &virtual_data=DefaultData
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Protected accessors
	//
	protected:
		//
		//-----------------------------------------------------------------------
		// GetInterestOrigin
		//-----------------------------------------------------------------------
		//
      RendererOrigin*
      	GetInterestOrigin();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Protected implementations
	//
   protected:
		//
		//-----------------------------------------------------------------------
		// Execute
		//
		// This method is called by the rendering manager to execute renderer
		// updates.  Overrides must call the inherited method.
		//-----------------------------------------------------------------------
		//
		virtual void
			ExecuteImplementation(
				RendererComplexity complexity_update,
				RendererOrigin::InterestingEntityIterator *iterator
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private implementations
	//
	private:
		virtual void
			LoadMissionImplementation(Mission *mission);
		virtual void
			ShutdownImplementation();
		virtual void
			StartEntityEffectImplementation(
				Entity *entity,
				DamageZone *damage_zone,
				ResourceDescription::ResourceID resource_ID
			)
			{}
		virtual void
			StopAllEntityEffectsImplementation(Entity *entity)
			{}
		virtual void
			StartEntityAlarmImplementation(
				Entity *entity,
				Subsystem *subsystem,
				Enumeration condition,
				ResourceDescription::ResourceID resource_ID
			)
			{}
		virtual void
			StopEntityAlarmImplementation(
				Entity *entity,
				Subsystem *subsystem,
				Enumeration condition
			)
			{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private data
	//
	private:
		//
		// Current running state of the renderer
		//
		RendererStatus
			rendererStatus;

		//
		// Renderer frame rate related valriables
		//
		RendererRate
			calibrationRate;
		Time
			calibrationFrameDuration,
         nextRenderTime;

		//
		// Renderer complexity, depth, and priority
		// control related variables
		//
		RendererComplexity
			calibrationComplexity;
		RendererPriority
			calibrationPriority;
		InterestType
			interestType;
		InterestDepth
			depthCalibration;
		RendererFrameBudget
			framePercentBudget;

		//
		// Sockets
      //
		SlotOf<RendererOrigin*>
			rendererOriginSocket;
		SlotOf<Entity*>
			entitySocket;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~

   inline Entity*
      Renderer::GetLinkedEntity()
   {
		Check(&entitySocket);
      return entitySocket.GetCurrent();
   }

   inline RendererOrigin*
      Renderer::GetInterestOrigin()
   {
      Check(&rendererOriginSocket);
      return rendererOriginSocket.GetCurrent();
   }

	inline RendererStatus
		Renderer::GetRendererStatus()
   {
		Check(this);
      return rendererStatus;
   }

   inline Logical
      Renderer::CompleteCycle()
	{
   	Check(this);
   	return True;
	}

   inline RendererComplexity
   	Renderer::GetCalibrationComplexity()
   {
   	Check(this);
   	return calibrationComplexity;
   }

	inline Time
   	Renderer::GetCalibrationFrameDuration()
   {
   	Check(this);
		return calibrationFrameDuration;
   }

	inline RendererRate
   	Renderer::GetCalibrationRate()
   {
   	Check(this);
		return calibrationRate;
   }

	inline Logical
		Renderer::ExecuteBackground()
	{
   	Check(this);
      return False;
   }

	//##########################################################################
	//########################    RendererManager    ###########################
	//##########################################################################

	class RendererManager:
		public Receiver
	{
		friend class Renderer;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction. Testing
	//
	public:
		RendererManager();
		~RendererManager();

		Logical
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Control, and processing
	//
	public:
		//
		//-----------------------------------------------------------------------
		// UpdateInterestOrigins
		//
		// Called by the application to update the renderers interest origins
		// before the interest manager performs its execute method.
		//-----------------------------------------------------------------------
		//
		void
			UpdateInterestOrigins(Time target_render_time);

		//
		//-----------------------------------------------------------------------
		// Execute
		//
		// Perform renderer management functions
		//-----------------------------------------------------------------------
		//
		void
			Execute(
         	Time target_render_time,
				Time target_frame_duration,
				Time actual_frame_duration
			);

		//
		//-----------------------------------------------------------------------
		// Complete Cycle
		//
		// Perform renderer complete cycle functions
		//-----------------------------------------------------------------------
		//
		void
			CompleteCycles();

		//
		//-----------------------------------------------------------------------
		// AreRenderersRunning
		//-----------------------------------------------------------------------
		//
		Logical
			AreRenderersRunning();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Effects and Alarms
	//
	public:
		void
			StartEntityEffect(
				Entity *entity,
				DamageZone *damage_zone,
				ResourceDescription::ResourceID resource_ID
			);

		void
			StopAllEntityEffects(Entity *entity);

		void
			StartEntityAlarm(
				Entity *entity,
				Subsystem *subsystem,
				Enumeration condition,
				ResourceDescription::ResourceID resource_ID
			);

		void
			StopEntityAlarm(
				Entity *entity,
				Subsystem *subsystem,
				Enumeration condition
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private methods
	//
	private:
		void
			StartRenderer(Renderer *renderer);
		void
			StopRenderer(Renderer *renderer);

		void
			RendererManager::PostRendererEvent(
				Entity *entity,
				Receiver::Message *message
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private data
	//
	private:
		SChainOf<Renderer*>
			renderers;
	};

	//~~~~~~~~~~~~~~ Renderer__NotifyOfNewInterestingEntityMessage ~~~~~~~~~~~~~

	class Renderer__NotifyOfNewInterestingEntityMessage:
		public Receiver::Message
	{
	public:
		Renderer__NotifyOfNewInterestingEntityMessage(
			Entity *interesting_entity
		);

		Entity*
			GetInterestingEntity();

	private:
		EntityID
			entityID;
	};

	//~~~~~~~~~~ Renderer__NotifyOfBecomingUninterestingEntityMessage ~~~~~~~~~~

	class Renderer__NotifyOfBecomingUninterestingEntityMessage:
		public Receiver::Message
	{
	public:
		Renderer__NotifyOfBecomingUninterestingEntityMessage(
			Entity *uninteresting_entity
		);

		Entity*
			GetUninterestingEntity()
				{return uninterestingEntity;}

	private:
		Entity
			*uninterestingEntity;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~ Renderer__EntityMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~

	class Renderer__EntityMessage:
		public Receiver::Message
	{
	public:
		Renderer__EntityMessage(
			Receiver::MessageID message_ID,
			size_t message_size,
			Entity *entity
		);

		Entity*
			GetEntity();

	private:
		EntityID
			entityID;
	};

	//~~~~~~~~~~~~~~~~~~ Renderer__StartEntityEffectMessage ~~~~~~~~~~~~~~~~~~~~

	class Renderer__StartEntityEffectMessage:
		public Renderer__EntityMessage
	{
	public:
		Renderer__StartEntityEffectMessage(
			Entity *entity,
			DamageZone *damage_zone,
			ResourceDescription::ResourceID resource_ID
		);

		DamageZone*
			GetDamageZone()
				{return damageZone;}
		ResourceDescription::ResourceID
			GetResourceID()
				{return resourceID;}

	private:
		DamageZone
			*damageZone;
		ResourceDescription::ResourceID
			resourceID;
	};

	//~~~~~~~~~~~~~~~~~~ Renderer__StopAllEntityEffectsMessage ~~~~~~~~~~~~~~~~~

	class Renderer__StopAllEntityEffectsMessage:
		public Renderer__EntityMessage
	{
	public:
		Renderer__StopAllEntityEffectsMessage(Entity *entity);
	};

	//~~~~~~~~~~~~~~~~~~ Renderer__StartEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~

	class Renderer__StartEntityAlarmMessage:
		public Renderer__EntityMessage
	{
	public:
		Renderer__StartEntityAlarmMessage(
			Entity *entity,
			Subsystem *alarm_subsystem,
			Enumeration alarm_condition,
			ResourceDescription::ResourceID resource_ID
		);

		Subsystem*
			GetSubsystem()
				{return subsystem;}
		Enumeration
			GetCondition()
				{return condition;}
		ResourceDescription::ResourceID
			GetResourceID()
				{return resourceID;}

	private:
		Subsystem
			*subsystem;
		Enumeration
			condition;
		ResourceDescription::ResourceID
			resourceID;
	};

	//~~~~~~~~~~~~~~~~~~ Renderer__StopEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~~

	class Renderer__StopEntityAlarmMessage:
		public Renderer__EntityMessage
	{
	public:
		Renderer__StopEntityAlarmMessage(
			Entity *entity,
			Subsystem *alarm_subsystem,
			Enumeration alarm_condition
		);

		Subsystem*
			GetSubsystem()
				{return subsystem;}
		Enumeration
			GetCondition()
				{return condition;}

	private:
		Subsystem
			*subsystem;
		Enumeration
			condition;
	};

	//~~~~~~~~~~~~~~~~~~~~~~ RendererManager inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~

	inline void
		RendererManager::StartEntityEffect(
			Entity *entity,
			DamageZone *damage_zone,
			ResourceDescription::ResourceID resource_ID
		)
	{
		Renderer::StartEntityEffectMessage
			message(entity, damage_zone, resource_ID);
		PostRendererEvent(entity, &message);
	}

	inline void
		RendererManager::StopAllEntityEffects(Entity *entity)
	{
		Renderer::StopAllEntityEffectsMessage
			message(entity);
		PostRendererEvent(entity, &message);
	}

	inline void
		RendererManager::StartEntityAlarm(
			Entity *entity,
			Subsystem *alarm_subsystem,
			Enumeration alarm_condition,
			ResourceDescription::ResourceID resource_ID
		)
	{
		Renderer::StartEntityAlarmMessage
			message(entity, alarm_subsystem, alarm_condition, resource_ID);
		PostRendererEvent(entity, &message);
	}

	inline void
		RendererManager::StopEntityAlarm(
			Entity *entity,
			Subsystem *alarm_subsystem,
			Enumeration alarm_condition
		)
	{
		Renderer::StopEntityAlarmMessage
			message(entity, alarm_subsystem, alarm_condition);
		PostRendererEvent(entity, &message);
	}

#endif

