/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program 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.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Commando                                                     *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/WeatherMgr.h          $*
 *                                                                                             *
 *                       Author:: Ian Leslie																	  *
 *                                                                                             *
 *                     $Modtime:: 1/15/02 7:26p       $*
 *                                                                                             *
 *                    $Revision:: 16                  $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#ifndef WEATHERMGR_H
#define WEATHERMGR_H


// Code controlling defines.
#define WEATHER_PARTICLE_SORT 0

// Includes.
#include "combatchunkid.h"
#include "pointgr.h"
#include "mempool.h"
#include "networkobject.h"
#include "random.h"
#include	"rendobj.h"
#include "saveloadsubsystem.h"
#include "soundenvironment.h"
#include "texture.h"
#include "vector.h"
#include "vector2.h"
#include "vector3.h"
#include "wwdebug.h"


// Class declarations.
class ChunkLoadClass;
class ChunkSaveClass;
class PhysicsSceneClass;

#if WEATHER_PARTICLE_SORT
class SortingIndexBufferClass;
#else
class	DX8IndexBufferClass;
#endif

class AudibleSoundClass;


class WindClass
{
	public:

		 WindClass (float heading, float speed, float variability, SoundEnvironmentClass *soundenvironment);
		~WindClass();

		Vector2 Get_Velocity()	{return (Velocity);}
		void	  Set (float heading, float speed, float variability);
		bool	  Update();

	protected:

		enum {
			OCTAVE_COUNT = 2
		};

		SoundEnvironmentClass *SoundEnvironment;
		float						  Heading;
		float						  Speed;
		float						  Variability;
		double					  Theta [OCTAVE_COUNT];
		Vector2					  Velocity;
		AudibleSoundClass		 *Sound;
};


class WeatherSystemClass : public RenderObjClass
{
	public:

		enum {
			GROWTH_STEP = 256
		};

		enum RenderModeEnum {
			RENDER_MODE_AXIS_ALIGNED,		// Render particle oriented about the particle's velocity vector (suitable for rain, for example).
			RENDER_MODE_CAMERA_ALIGNED,	// Render particle aligned with the camera direction (suitable for snow, for example).
			RENDER_MODE_SURFACE_ALIGNED	// Render particle such that it looks attached to the surface of an object.
		};

		 WeatherSystemClass (PhysicsSceneClass *scene,
									float emittersize,
								   float emitterheight,
								   float particledensity,
									float particlesperunitlength,
								   float particlewidth,
								   float particleheight,
								   float particlespeed,
								   const Vector2 &pageoffset,
									const Vector2 &pagesize,
								   unsigned pagecount,
									bool staticpageexists,
									float minstatictime,
									float maxstatictime,
									RenderModeEnum rendermode,
									bool decayaftercollision,
									bool prime);

		~WeatherSystemClass();
		RenderObjClass *Clone() const
		{
			WWASSERT (false);
			return (0);
		}

		void Set_Density (float density);
		void Render (RenderInfoClass &rinfo);
		void Get_Obj_Space_Bounding_Sphere (SphereClass &sphere) const;
		void Get_Obj_Space_Bounding_Box (AABoxClass &box) const;

		virtual bool Update (WindClass *wind, const Vector3 &cameraposition);

	protected:

		enum {
			VERTICES_PER_TRIANGLE = 3,
			MAX_IB_PARTICLE_COUNT = 2048,
			MAX_AGE					 = 1000000
		};

		struct RayStruct : public AutoPoolClass <RayStruct, GROWTH_STEP>
		{
			public:

				RayStruct		*Next;				  	// Next ray in list.
				bool				 Initialized;			// Has the ray been defined?
				bool				 RayCast;				// Does this ray need to be relocated in the emitter (and therefore needs to be raycast).
				Vector3			 ParticleVelocity;	// Velocity of all particles spawned by this ray.
				Vector2			 StartPosition;		// Start position of ray inside emitter.
				Vector3			 EndPosition;			// Point of collision of ray with environment.
				bool				 ValidSurfaceNormal;	// Does the ray intersect a phyical object?
				Vector3			 SurfaceNormal;		// Normal of surface ray intersects (if any).
		};

		struct ParticleStruct : public AutoPoolClass <ParticleStruct, GROWTH_STEP>
		{
			public:

				ParticleStruct *Prev;					// Previous particle in list.
				ParticleStruct *Next;					// Next particle in list.
				float				 CollisionTime;		// Time when particle hits something (in seconds).
				float				 LifeTime;				// Lifetime of particle (in seconds).
				float				 ElapsedTime;			// Time elapsed since birth of particle (in seconds).
				Vector3			 Velocity;				// Velocity of particle (in metres per second).
				Vector2			 UnitZVelocity;		// Velocity / Velocity.Z (precomputed for optimization purposes).
				Vector3			 CollisionPosition;	// Position of collision.
				Vector3			 CurrentPosition;		// Current position of particle (in world space).
				Vector3			 SurfaceNormal;		// Normal of surface particle collides with (if any).

				unsigned char	 Page;					// Texture page for this particle.
				unsigned char	 RenderMode;
				unsigned char	 Pad [2];				// Pad structure to 4-byte multiple.
		};

		// Utility functions.
		float Spawn_Count (float time) {return (ParticleDensity * EmitterSize * EmitterSize * time);}
		bool	Can_Spawn (const RayStruct *rayptr) {return (rayptr->EndPosition.Z < EmitterPosition.Z);}

		bool Spawn (RayStruct *suppliedrayptr = NULL);
		void Kill (ParticleStruct *particleptr);

		PhysicsSceneClass						*Scene;						// The scene that contains the weather system.
		float										 Age;							// Age of this weather system (in seconds).
		float										 EmitterSize;				// Size of square emitter (area of emitter = size * size).
		float										 EmitterHeight;			// Height of emitter (relative to camera).
		Vector3									 EmitterPosition;			// Centroid of emitter (in world space).
		float										 ParticleDensity;			// Density of particles (over area of emitter).
		float										 ParticlesPerUnitLength;
		float										 ParticleSpeed;
		Vector3									 ParticleVelocity;		// Dominant velocity vector of particles.
		float										 HalfParticleWidth;
		float										 HalfParticleHeight;
	   RayStruct								*RayHead;
		unsigned									 RayCount;
	   RayStruct								*RaySpawnPtr;
		RayStruct								*RayUpdatePtr;
		float										 MinRayEndZ;				// Current lowest Z-value of end of any ray (used to determine a bounding box around this render object).
		float										 SpawnCountFraction;		// Cumulative fractional spawn counts (for improved accuracy).
		Vector3									 SceneMin, SceneMax;		// Bounding box around the scene that the particle system lives in.
		Vector3									 ObjectMin, ObjectMax;	// Bounding box around this render object (for culling purposes).
		ParticleStruct							*ParticleHead;				// Head of list of particles in system.
		unsigned									 ParticleCount;			// No. of particles in system.

		#if WEATHER_PARTICLE_SORT
		SortingIndexBufferClass				*IndexBuffer;
		#else
		DX8IndexBufferClass					*IndexBuffer;
		#endif

		VertexMaterialClass					*Material;
		ShaderClass								 Shader;
		TextureClass							*Texture;
		Vector2									*TextureArray;
		RenderModeEnum							 RenderMode;
		bool										 DecayAfterCollision;
		unsigned									 PageCount;
		bool										 StaticPageExists;
		float										 MinStaticTime;
		float										 MaxStaticTime;
		Vector3									 CameraPosition;
		bool										 CameraPositionValid;

		static Random2Class					_RandomNumber;				// Random no. generator.
		static unsigned						_GlobalParticleCount;	// Total no. of particles over all weather systems.
};


class RainSystemClass : public WeatherSystemClass
{
	public:

					RainSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, SoundEnvironmentClass *soundenvironment, bool prime);
		virtual ~RainSystemClass();

		bool Update (WindClass *wind, const Vector3 &cameraposition);

	protected:

		enum {
			PAGE_COUNT = 4
		};

		AudibleSoundClass		 *Sound;					// Sound effect for rainfall.
		SoundEnvironmentClass *SoundEnvironment;
};


class SnowSystemClass : public WeatherSystemClass
{
	public:

		SnowSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, bool prime);

		bool Update (WindClass *wind, const Vector3 &cameraposition);

	protected:

		enum {
			PAGE_COUNT = 4
		};
};


class AshSystemClass : public WeatherSystemClass
{
	public:

		AshSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, bool prime);

		bool Update (WindClass *wind, const Vector3 &cameraposition);

	protected:

		enum {
			PAGE_COUNT = 4
		};
};


class WeatherParameterClass
{
	public:

		void Initialize();
		void Set (float targetvalue, float ramptime, bool override);
		void Set (float overrideramptime) {OverrideDuration = overrideramptime;}

		float Value() {return (CurrentValue);}

		bool Update (float time, bool override);
		void Update (float &value, float &target, float &duration, float time);

	private:

		float CurrentValue;
		float NormalValue;
		float NormalTarget;
		float	NormalDuration;
		float OverrideTarget;
		float OverrideDuration;

		friend class WeatherMgrClass;
};



class	WeatherMgrClass : public SaveLoadSubSystemClass, public NetworkObjectClass
{
	public:

		enum PrecipitationEnum {
			PRECIPITATION_FIRST,
			PRECIPITATION_RAIN = PRECIPITATION_FIRST,
			PRECIPITATION_SNOW,
			PRECIPITATION_ASH,
			PRECIPITATION_COUNT
		};

		 WeatherMgrClass();
		~WeatherMgrClass() {}

		uint32		Chunk_ID() const	{return (CHUNKID_WEATHER_MGR);}
		const char *Name() const		{return ("WeatherMgrClass");}
		void Delete (void)				{}
		virtual void Set_Delete_Pending (void) {};

		bool Save (ChunkSaveClass &csave);
		bool Load (ChunkLoadClass &cload);
		bool Load_Micro_Chunks (ChunkLoadClass &cload);
		void Export_Rare (BitStreamClass &packet);
		void Import_Rare (BitStreamClass &packet);

		static void Init (SoundEnvironmentClass *soundenvironment);
		static void	Reset();
		static void Shutdown();

		static bool Save_Dynamic (ChunkSaveClass &csave);
		static bool Load_Dynamic (ChunkLoadClass &cload);
		static bool Load_Dynamic_Micro_Chunks (ChunkLoadClass &cload);

		static bool Set_Wind (float heading, float speed, float variability, float ramptime = 0.0f);
		static bool Override_Wind (float heading, float speed, float variability, float ramptime = 0.0f);
		static void Get_Wind (float &heading, float &speed, float &variability);
		static void Restore_Wind (float ramptime);

		static bool Set_Precipitation (PrecipitationEnum precipitation, float density, float ramptime = 0.0f);
		static bool Override_Precipitation (PrecipitationEnum precipitation, float density, float ramptime = 0.0f);
		static void Get_Precipitation (PrecipitationEnum precipitation, float &density);
		static void Restore_Precipitation (float ramptime);

		static void Set_Fog_Enable (bool enabled)
		{
			_FogEnabled = enabled;
			Set_Dirty();
		}
		static bool Get_Fog_Enable()
		{
			return (_FogEnabled);
		}
		static bool Set_Fog_Range (float startdistance, float enddistance, float ramptime = 0.0f);
		static void Get_Fog_Range (float &startdistance, float &enddistance);

		static void Update (PhysicsSceneClass *scene, CameraClass *camera);
		static void Render (const CameraClass *camera);

	private:

		#define VARID_PARAMETER(varname) \
			VARID_ ## varname ## _CURRENT_VALUE, \
			VARID_ ## varname ## _NORMAL_VALUE,	\
			VARID_ ## varname ## _NORMAL_TARGET, \
			VARID_ ## varname ## _NORMAL_DURATION, \
			VARID_ ## varname ## _OVERRIDE_TARGET,	\
			VARID_ ## varname ## _OVERRIDE_DURATION

		// Constants.
		enum {
			CHUNKID_MICRO_CHUNKS			  = 0x03020113,
			CHUNKID_DYNAMIC_MICRO_CHUNKS = 0x11020245
		};

		enum {
			VARID_DUMMY = 0x09,

			VARID_PARAMETER (WIND_HEADING),
			VARID_PARAMETER (WIND_SPEED),
			VARID_PARAMETER (WIND_VARIABILITY),
			VARID_PARAMETER (RAIN_DENSITY),
			VARID_PARAMETER (SNOW_DENSITY),
			VARID_PARAMETER (ASH_DENSITY),

			VARID_WIND_OVERRIDE_COUNT,
			VARID_PRECIPITATION_OVERRIDE_COUNT,

			VARID_FOG_ENABLED,
			VARID_PARAMETER (FOG_START_DISTANCE),
			VARID_PARAMETER (FOG_END_DISTANCE)
		};

		#undef VARID_PARAMETER

		enum {
			PARAMETER_WIND_HEADING,
			PARAMETER_WIND_SPEED,
			PARAMETER_WIND_VARIABILITY,
			PARAMETER_RAIN_DENSITY,
			PARAMETER_SNOW_DENSITY,
			PARAMETER_ASH_DENSITY,
			PARAMETER_FOG_START_DISTANCE,
			PARAMETER_FOG_END_DISTANCE,
			PARAMETER_COUNT
		};

		static bool Set_Wind (float heading, float speed, float variability, float ramptime, bool override);
		static bool Set_Precipitation (PrecipitationEnum precipitation, float density, float ramptime, bool override);

		static bool Is_Dirty()							{return (_Dirty);}
		static void Set_Dirty (bool dirty = true)	{_Dirty = dirty;}

		static SoundEnvironmentClass *_SoundEnvironment;
		static WeatherParameterClass	_Parameters [PARAMETER_COUNT];
		static bool							_Prime;
		static bool							_Imported;
		static unsigned					_WindOverrideCount;
		static unsigned					_PrecipitationOverrideCount;

		static WindClass				  *_Wind;
		static WeatherSystemClass	  *_Precipitation [PRECIPITATION_COUNT];
		static bool							_FogEnabled;
		static bool							_Dirty;
};


// Externals.
extern WeatherMgrClass _TheWeatherMgr;


#endif // WEATHERMGR_H