Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
8.3 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "decals.h"
  8. #include "igamesystem.h"
  9. #include "utlsymbol.h"
  10. #include "utldict.h"
  11. #include "keyvalues.h"
  12. #include "filesystem.h"
  13. #include <ctype.h>
  14. #ifdef CLIENT_DLL
  15. #include "iefx.h"
  16. #endif
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. #define DECAL_LIST_FILE "scripts/decals_subrect.txt"
  20. //#define DECAL_LIST_FILE "scripts/decals.txt"
  21. #define TRANSLATION_DATA_SECTION "TranslationData"
  22. //-----------------------------------------------------------------------------
  23. // Purpose:
  24. //-----------------------------------------------------------------------------
  25. class CDecalEmitterSystem : public IDecalEmitterSystem, public CAutoGameSystem
  26. {
  27. public:
  28. CDecalEmitterSystem( char const *name ) : CAutoGameSystem( name )
  29. {
  30. }
  31. virtual bool Init();
  32. virtual void Shutdown();
  33. virtual void LevelInitPreEntity();
  34. // Public interface
  35. virtual int GetDecalIndexForName( char const *decalname );
  36. virtual char const *TranslateDecalForGameMaterial( char const *decalName, unsigned char gamematerial );
  37. private:
  38. char const *ImpactDecalForGameMaterial( int gamematerial );
  39. void LoadDecalsFromScript( char const *filename );
  40. void Clear();
  41. struct DecalListEntry
  42. {
  43. DecalListEntry()
  44. {
  45. name = UTL_INVAL_SYMBOL;
  46. precache_index = -1;
  47. weight = 1.0f;
  48. }
  49. CUtlSymbol name;
  50. int precache_index;
  51. float weight;
  52. };
  53. struct DecalEntry
  54. {
  55. DecalEntry()
  56. {
  57. }
  58. DecalEntry( const DecalEntry& src )
  59. {
  60. int c = src.indices.Count();
  61. for ( int i = 0; i < c; i++ )
  62. {
  63. indices.AddToTail( src.indices[ i ] );
  64. }
  65. }
  66. DecalEntry& operator = ( const DecalEntry& src )
  67. {
  68. if ( this == &src )
  69. return *this;
  70. int c = src.indices.Count();
  71. for ( int i = 0; i < c; i++ )
  72. {
  73. indices.AddToTail( src.indices[ i ] );
  74. }
  75. return *this;
  76. }
  77. CUtlVector< int > indices;
  78. };
  79. CUtlVector< DecalListEntry > m_AllDecals;
  80. CUtlDict< DecalEntry, int > m_Decals;
  81. CUtlSymbolTable m_DecalFileNames;
  82. CUtlDict< int, int > m_GameMaterialTranslation;
  83. };
  84. static CDecalEmitterSystem g_DecalSystem( "CDecalEmitterSystem" );
  85. IDecalEmitterSystem *decalsystem = &g_DecalSystem;
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. // Input : *decalname -
  89. // Output : int
  90. //-----------------------------------------------------------------------------
  91. int CDecalEmitterSystem::GetDecalIndexForName( char const *decalname )
  92. {
  93. if ( !decalname || !decalname[ 0 ] )
  94. return -1;
  95. int idx = m_Decals.Find( decalname );
  96. if ( idx == m_Decals.InvalidIndex() )
  97. return -1;
  98. DecalEntry *e = &m_Decals[ idx ];
  99. Assert( e );
  100. int count = e->indices.Count();
  101. if ( count <= 0 )
  102. return -1;
  103. float totalweight = 0.0f;
  104. int slot = 0;
  105. for ( int i = 0; i < count; i++ )
  106. {
  107. int idx = e->indices[ i ];
  108. DecalListEntry *item = &m_AllDecals[ idx ];
  109. Assert( item );
  110. if ( !totalweight )
  111. {
  112. slot = idx;
  113. }
  114. // Always assume very first slot will match
  115. totalweight += item->weight;
  116. if ( !totalweight || random->RandomFloat(0,totalweight) < item->weight )
  117. {
  118. slot = idx;
  119. }
  120. }
  121. return m_AllDecals[ slot ].precache_index;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. // Output : Returns true on success, false on failure.
  126. //-----------------------------------------------------------------------------
  127. bool CDecalEmitterSystem::Init()
  128. {
  129. LoadDecalsFromScript( DECAL_LIST_FILE );
  130. return true;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. //-----------------------------------------------------------------------------
  135. void CDecalEmitterSystem::LevelInitPreEntity()
  136. {
  137. // Precache all entries
  138. int c = m_AllDecals.Count();
  139. for ( int i = 0 ; i < c; i++ )
  140. {
  141. DecalListEntry& e = m_AllDecals[ i ];
  142. #if defined( CLIENT_DLL )
  143. e.precache_index = effects->Draw_DecalIndexFromName( (char *)m_DecalFileNames.String( e.name ) );
  144. #else
  145. e.precache_index = engine->PrecacheDecal( m_DecalFileNames.String( e.name ) );
  146. #endif
  147. }
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. // Input : *filename -
  152. //-----------------------------------------------------------------------------
  153. void CDecalEmitterSystem::LoadDecalsFromScript( char const *filename )
  154. {
  155. KeyValues *kv = new KeyValues( filename );
  156. Assert( kv );
  157. if ( kv )
  158. {
  159. KeyValues *translation = NULL;
  160. if ( kv->LoadFromFile( filesystem, filename ) )
  161. {
  162. KeyValues *p = kv;
  163. while ( p )
  164. {
  165. if ( p->GetFirstSubKey() )
  166. {
  167. char const *keyname = p->GetName();
  168. if ( !Q_stricmp( keyname, TRANSLATION_DATA_SECTION ) )
  169. {
  170. translation = p;
  171. }
  172. else
  173. {
  174. DecalEntry entry;
  175. for ( KeyValues *sub = p->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
  176. {
  177. MEM_ALLOC_CREDIT();
  178. DecalListEntry decal;
  179. decal.precache_index = -1;
  180. decal.name = m_DecalFileNames.AddString( sub->GetName() );
  181. decal.weight = sub->GetFloat();
  182. // Add to global list
  183. int idx = m_AllDecals.AddToTail( decal );
  184. // Add index only to local list
  185. entry.indices.AddToTail( idx );
  186. }
  187. // Add entry to main dictionary
  188. m_Decals.Insert( keyname, entry );
  189. }
  190. }
  191. p = p->GetNextKey();
  192. }
  193. }
  194. else
  195. {
  196. Msg( "CDecalEmitterSystem::LoadDecalsFromScript: Unable to load '%s'\n", filename );
  197. }
  198. if ( !translation )
  199. {
  200. Msg( "CDecalEmitterSystem::LoadDecalsFromScript: Script '%s' missing section '%s'\n",
  201. filename,
  202. TRANSLATION_DATA_SECTION );
  203. }
  204. else
  205. {
  206. // Now parse game material to entry translation table
  207. for ( KeyValues *sub = translation->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
  208. {
  209. // Don't add NULL string to list
  210. if ( !Q_stricmp( sub->GetString(), "" ) )
  211. continue;
  212. int idx = m_Decals.Find( sub->GetString() );
  213. if ( idx != m_Decals.InvalidIndex() )
  214. {
  215. const char *value = sub->GetName();
  216. int gameMaterial;
  217. if ( !V_isdigit( value[0]) )
  218. {
  219. gameMaterial = toupper( value[0] );
  220. }
  221. else
  222. {
  223. gameMaterial = atoi( value );
  224. }
  225. char gm[ 2 ];
  226. gm[0] = gameMaterial;
  227. gm[1] = 0;
  228. m_GameMaterialTranslation.Insert( gm, idx );
  229. }
  230. else
  231. {
  232. Msg( "CDecalEmitterSystem::LoadDecalsFromScript: Translation for game material type '%s' references unknown decal '%s'\n",
  233. sub->GetName(), sub->GetString() );
  234. }
  235. }
  236. }
  237. kv->deleteThis();
  238. }
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose:
  242. // Input : gamematerial -
  243. // Output : char const
  244. //-----------------------------------------------------------------------------
  245. char const *CDecalEmitterSystem::ImpactDecalForGameMaterial( int gamematerial )
  246. {
  247. char gm[ 2 ];
  248. gm[0] = (char)gamematerial;
  249. gm[1] = 0;
  250. int idx = m_GameMaterialTranslation.Find( gm );
  251. if ( idx == m_GameMaterialTranslation.InvalidIndex() )
  252. return NULL;
  253. return m_Decals.GetElementName( m_GameMaterialTranslation.Element(idx) );
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose:
  257. //-----------------------------------------------------------------------------
  258. void CDecalEmitterSystem::Shutdown()
  259. {
  260. Clear();
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. //-----------------------------------------------------------------------------
  265. void CDecalEmitterSystem::Clear()
  266. {
  267. m_DecalFileNames.RemoveAll();
  268. m_Decals.Purge();
  269. m_AllDecals.Purge();
  270. m_GameMaterialTranslation.Purge();
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. // Input : *decalName -
  275. // gamematerial -
  276. // Output : char const
  277. //-----------------------------------------------------------------------------
  278. char const *CDecalEmitterSystem::TranslateDecalForGameMaterial( char const *decalName, unsigned char gamematerial )
  279. {
  280. if ( gamematerial == CHAR_TEX_CONCRETE )
  281. return decalName;
  282. if ( !Q_stricmp( decalName, "Impact.Concrete" ) )
  283. {
  284. if ( gamematerial == '-' )
  285. return "";
  286. char const *d = ImpactDecalForGameMaterial( gamematerial );
  287. if ( d )
  288. {
  289. return d;
  290. }
  291. }
  292. return decalName;
  293. }