/*
**	Command & Conquer Generals(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) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: GameLOD.h ///////////////////////////////////////////////////////////
//
// Used to set detail levels of various game systems.
//
// Author: Mark Wilczynski, Sept 2002
//
//
///////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef _GAME_LOD_H_
#define _GAME_LOD_H_

enum ParticlePriorityType;

#define MAX_LOD_PRESETS_PER_LEVEL	32	//number of hardware configs preset for each low,medium,high
#define MAX_BENCH_PROFILES	16

//Make sure this enum stays in sync with GameLODNames[]
enum StaticGameLODLevel
{
	STATIC_GAME_LOD_UNKNOWN=-1,
	STATIC_GAME_LOD_LOW,
	STATIC_GAME_LOD_MEDIUM,
	STATIC_GAME_LOD_HIGH,
	STATIC_GAME_LOD_CUSTOM,	//make sure this remains last!
	STATIC_GAME_LOD_COUNT
};

enum DynamicGameLODLevel
{
	DYNAMIC_GAME_LOD_UNKNOWN=-1,
	DYNAMIC_GAME_LOD_LOW,
	DYNAMIC_GAME_LOD_MEDIUM,
	DYNAMIC_GAME_LOD_HIGH,
	DYNAMIC_GAME_LOD_VERY_HIGH,
	DYNAMIC_GAME_LOD_COUNT
};

//Make sure this stays in sync with CPUNames[] in gamelod.cpp
enum CpuType
{
	XX,	//unknown type
	P3,
	P4,
	K7,
};

//Keep this in sync with VideoNames in Gamelod.cpp
enum ChipsetType
{	DC_UNKNOWN,
	DC_VOODOO2,
	DC_VOODOO3,
	DC_VOODOO4,
	DC_VOODOO5,
	DC_TNT,
	DC_TNT2,
	DC_GEFORCE2,
	DC_RADEON,
	DC_GENERIC_PIXEL_SHADER_1_1,
	DC_GEFORCE3,
	DC_GEFORCE4,
	DC_GENERIC_PIXEL_SHADER_1_4,
	DC_RADEON_8500,
	DC_GENERIC_PIXEL_SHADER_2_0,
	DC_RADEON_9700,
	DC_MAX
};

struct StaticGameLODInfo
{
	StaticGameLODInfo();
	//Static LOD constants
	Int m_minFPS;	///< minimum fps in order to recommend this LOD.
	Int m_minProcessorFPS;	///< minimum CPU time (in ms) to recommend this LOD.
	Int m_sampleCount2D; ///<How many 2-D (UI) samples should we allow simultaneously (Note: Hardware may support less than the desired number)
	Int m_sampleCount3D; ///<How many 3-D (World) samples should we allow simultaneously (Note: Hardware may support less than the desired number)
	Int m_streamCount; ///<How many streaming audio things should we allow simultaneously (Note: Hardware may support less than the desired number)
	Int m_maxParticleCount; ///<maximum number of particles that can exist
	Bool m_useShadowVolumes;	///<use volumetric shadows if available.
	Bool m_useShadowDecals;	///<use 2D Decal shadows.
	Bool m_useCloudMap;	///<use cloud shadows scrolling over terrain.
	Bool m_useLightMap;	///<use noise pattern over terrain to break up tiling.
	Bool m_showSoftWaterEdge;	///<feather water edge if supported by hardware.
	Int m_maxTankTrackEdges;	///<maximum length of tank track
	Int m_maxTankTrackOpaqueEdges;	///<maximum length of tank track before it starts fading.
	Int m_maxTankTrackFadeDelay;	///<maximum amount of time a tank track segment remains visible.
	Bool m_useBuildupScaffolds;		///<draw scaffold during structure building.
	Bool m_useTreeSway;		///<sway trees to simulate wind.
	Bool m_useEmissiveNightMaterials; ///<perform second lighting pass on night buildings. 
	Int m_textureReduction;	///<reduce texture resolution by dividing in half n times.
	Bool m_useFpsLimit;	///<don't lock fps to 30hz
	Bool m_enableDynamicLOD;	///<don't do dynamic lod based on current fps.
	Bool m_useTrees;			///<don't include trees on map.

};

struct DynamicGameLODInfo
{
	DynamicGameLODInfo();
	//Dynamic LOD constants
	Int m_minFPS;	///< minimum fps in order to recommend his LOD.
	UnsignedInt m_dynamicParticleSkipMask;
	UnsignedInt m_dynamicDebrisSkipMask;
	Real m_slowDeathScale;
	ParticlePriorityType m_minDynamicParticlePriority;
	ParticlePriorityType m_minDynamicParticleSkipPriority;
};

struct LODPresetInfo
{
	LODPresetInfo() : m_cpuType(XX),m_mhz(1),m_cpuPerfIndex(1.0f),m_videoType(DC_UNKNOWN),m_memory(1) {};
	CpuType  m_cpuType;
	Int	 m_mhz;
	Real m_cpuPerfIndex;	//used to select preset for unidentified cpu's
	ChipsetType  m_videoType;
	Int  m_memory;
};

struct BenchProfile
{
	BenchProfile() : m_cpuType(XX),m_mhz(1),m_intBenchIndex(1.0f),m_floatBenchIndex(1.0f),m_memBenchIndex(1.0f) {};

	CpuType  m_cpuType;
	Int	 m_mhz;
	Real m_intBenchIndex;
	Real m_floatBenchIndex;
	Real m_memBenchIndex;
};

class GameLODManager
{
public:
	GameLODManager(void);
	~GameLODManager();

	const char *getStaticGameLODLevelName(StaticGameLODLevel level);
	const char *getDynamicGameLODLevelName(DynamicGameLODLevel level);
	StaticGameLODLevel findStaticLODLevel(void);	///< calculate the optimal static LOD level for this system.
	Bool setStaticLODLevel(StaticGameLODLevel level);	///< set the current static LOD level.
	StaticGameLODLevel getStaticLODLevel(void) { return m_currentStaticLOD;}
	DynamicGameLODLevel findDynamicLODLevel(Real averageFPS);	///<given an average fps, return the optimal dynamic LOD.
	Bool setDynamicLODLevel(DynamicGameLODLevel level);	///< set the current dynamic LOD level.
	DynamicGameLODLevel getDynamicLODLevel(void) { return m_currentDynamicLOD;}
	void init(void);	///<initialize tables of preset LOD's.
	void setCurrentTextureReduction(Int val) {m_currentTextureReduction = val;}
	Int getCurrentTextureReduction(void) {return m_currentTextureReduction;}
	Int getStaticGameLODIndex(AsciiString name);
	Int getDynamicGameLODIndex(AsciiString name);
	inline Bool isParticleSkipped(void);
	inline Bool isDebrisSkipped(void);
	inline Real getSlowDeathScale(void);
	inline ParticlePriorityType getMinDynamicParticlePriority(void);		///<priority at which particles will still render at current FPS.
	inline ParticlePriorityType	getMinDynamicParticleSkipPriority(void);	///<priority at which particles will never be skipped at any FPS.
	Int getRecommendedTextureReduction(void);	///<return the optimal texture reduction for the system.
	Int getLevelTextureReduction(StaticGameLODLevel level);	///<return texture reduction specified in INI for this game detail.
	LODPresetInfo *newLODPreset(StaticGameLODLevel index);
	BenchProfile *newBenchProfile(void);
	Bool didMemPass( void );
	void setReallyLowMHz(Int mhz) { m_reallyLowMHz = mhz; }
	Bool isReallyLowMHz() const { return m_cpuFreq < m_reallyLowMHz; }

	StaticGameLODInfo m_staticGameLODInfo[STATIC_GAME_LOD_COUNT];
	DynamicGameLODInfo m_dynamicGameLODInfo[DYNAMIC_GAME_LOD_COUNT];
	LODPresetInfo m_lodPresets[STATIC_GAME_LOD_CUSTOM][MAX_LOD_PRESETS_PER_LEVEL];
	BenchProfile m_benchProfiles[MAX_BENCH_PROFILES];

protected:
	void applyStaticLODLevel(StaticGameLODLevel level);
	void applyDynamicLODLevel(DynamicGameLODLevel level);
	void refreshCustomStaticLODLevel(void);	///<grabs current globaldata values and makes them the custom detail setting.

	static const FieldParse m_staticGameLODFieldParseTable[];
	StaticGameLODLevel m_currentStaticLOD;		///< current value of static LOD.
	DynamicGameLODLevel m_currentDynamicLOD;		///< current value of dynamic LOD.
	Int m_numParticleGenerations;	///<number of particles that have been generated since dynamic LOD reduction started.
	Int m_dynamicParticleSkipMask;	///<mask used to enable rendering of every Nth particle.
	Int m_numDebrisGenerations;		///<number of debris that have been generated since dynamic LOD reduction started.
	Int m_dynamicDebrisSkipMask;	///<mask used to enable rendering of every Nth debris.
	Real m_slowDeathScale;			///<values < 1.0f are used to accelerate deaths
	ParticlePriorityType m_minDynamicParticlePriority;	///<only priorities above/including this value are allowed to render.
	ParticlePriorityType m_minDynamicParticleSkipPriority;	///<priorities above/including this value never skip particles.
	Bool m_videoPassed;
	Bool m_cpuPassed;
	Bool m_memPassed;
	Int m_numLevelPresets[STATIC_GAME_LOD_CUSTOM];
	Int m_numBenchProfiles;
	StaticGameLODLevel m_idealDetailLevel;
	ChipsetType m_videoChipType;
	CpuType m_cpuType;
	Int m_numRAM;
	Int m_cpuFreq;
	Real m_intBenchIndex;
	Real m_floatBenchIndex;
	Real m_memBenchIndex;
	Real m_compositeBenchIndex;
	Real m_currentTextureReduction;
	Int m_reallyLowMHz;
};

Bool GameLODManager::isParticleSkipped(void)
{
	return (++m_numParticleGenerations & m_dynamicParticleSkipMask) != m_dynamicParticleSkipMask;
}

Bool GameLODManager::isDebrisSkipped(void)
{
	return (++m_numDebrisGenerations & m_dynamicDebrisSkipMask) != m_dynamicDebrisSkipMask;
}

Real GameLODManager::getSlowDeathScale(void)
{
	return m_slowDeathScale;
}

ParticlePriorityType GameLODManager::getMinDynamicParticlePriority(void)
{
	return m_minDynamicParticlePriority;
}

ParticlePriorityType GameLODManager::getMinDynamicParticleSkipPriority(void)
{
	return m_minDynamicParticleSkipPriority;
}

extern GameLODManager *TheGameLODManager;
#endif _GAME_LOD_H_