animatedsoundmgr.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : ww3d2 *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/animatedsoundmgr.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 12/13/01 6:05p $*
  29. * *
  30. * $Revision:: 2 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "animatedsoundmgr.h"
  36. #include "ini.h"
  37. #include "inisup.h"
  38. #include "ffactory.h"
  39. #include "wwfile.h"
  40. #include <stdio.h>
  41. #include "definition.h"
  42. #include "definitionmgr.h"
  43. #include "definitionclassids.h"
  44. #include "wwaudio.h"
  45. #include "audiblesound.h"
  46. #include "htree.h"
  47. #include "hanim.h"
  48. //////////////////////////////////////////////////////////////////////
  49. // Static member initialization
  50. //////////////////////////////////////////////////////////////////////
  51. HashTemplateClass<StringClass, AnimatedSoundMgrClass::ANIM_SOUND_LIST *> AnimatedSoundMgrClass::AnimationNameHash;
  52. DynamicVectorClass<AnimatedSoundMgrClass::ANIM_SOUND_LIST *> AnimatedSoundMgrClass::AnimSoundLists;
  53. //////////////////////////////////////////////////////////////////////
  54. // Local inlines
  55. //////////////////////////////////////////////////////////////////////
  56. static WWINLINE INIClass *
  57. Get_INI (const char *filename)
  58. {
  59. INIClass *ini = NULL;
  60. //
  61. // Get the file from our filefactory
  62. //
  63. FileClass *file = _TheFileFactory->Get_File (filename);
  64. if (file) {
  65. //
  66. // Create the INI object
  67. //
  68. if (file->Is_Available ()) {
  69. ini = new INIClass (*file);
  70. }
  71. //
  72. // Close the file
  73. //
  74. _TheFileFactory->Return_File (file);
  75. }
  76. return ini;
  77. }
  78. static int
  79. Build_List_From_String
  80. (
  81. const char * buffer,
  82. const char * delimiter,
  83. StringClass ** string_list
  84. )
  85. {
  86. int count = 0;
  87. WWASSERT (buffer != NULL);
  88. WWASSERT (delimiter != NULL);
  89. WWASSERT (string_list != NULL);
  90. if ((buffer != NULL) &&
  91. (delimiter != NULL) &&
  92. (string_list != NULL))
  93. {
  94. int delim_len = ::strlen (delimiter);
  95. //
  96. // Determine how many entries there will be in the list
  97. //
  98. for (const char *entry = buffer;
  99. (entry != NULL) && (entry[1] != 0);
  100. entry = ::strstr (entry, delimiter))
  101. {
  102. //
  103. // Move past the current delimiter (if necessary)
  104. //
  105. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  106. entry += delim_len;
  107. }
  108. // Increment the count of entries
  109. count ++;
  110. }
  111. if (count > 0) {
  112. //
  113. // Allocate enough StringClass objects to hold all the strings in the list
  114. //
  115. (*string_list) = new StringClass[count];
  116. //
  117. // Parse the string and pull out its entries.
  118. //
  119. count = 0;
  120. for (entry = buffer;
  121. (entry != NULL) && (entry[1] != 0);
  122. entry = ::strstr (entry, delimiter))
  123. {
  124. //
  125. // Move past the current delimiter (if necessary)
  126. //
  127. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  128. entry += delim_len;
  129. }
  130. //
  131. // Copy this entry into its own string
  132. //
  133. StringClass entry_string = entry;
  134. char *delim_start = ::strstr (entry_string, delimiter);
  135. if (delim_start != NULL) {
  136. delim_start[0] = 0;
  137. }
  138. //
  139. // Add this entry to our list
  140. //
  141. if ((entry_string.Get_Length () > 0) || (count == 0)) {
  142. (*string_list)[count++] = entry_string;
  143. }
  144. }
  145. } else if (delim_len > 0) {
  146. count = 1;
  147. (*string_list) = new StringClass[count];
  148. (*string_list)[0] = buffer;
  149. }
  150. }
  151. //
  152. // Return the number of entries in our list
  153. //
  154. return count;
  155. }
  156. //////////////////////////////////////////////////////////////////////
  157. //
  158. // Initialize
  159. //
  160. //////////////////////////////////////////////////////////////////////
  161. void
  162. AnimatedSoundMgrClass::Initialize (const char *ini_filename)
  163. {
  164. //
  165. // Don't re-initialize...
  166. //
  167. if (AnimSoundLists.Count () > 0) {
  168. return ;
  169. }
  170. const char *DEFAULT_INI_FILENAME = "w3danimsound.ini";
  171. //
  172. // Determine which filename to use
  173. //
  174. const char *filename_to_use = ini_filename;
  175. if (filename_to_use == NULL) {
  176. filename_to_use = DEFAULT_INI_FILENAME;
  177. }
  178. //
  179. // Get the INI file which contains the data for this viewer
  180. //
  181. INIClass *ini_file = ::Get_INI (filename_to_use);
  182. if (ini_file != NULL) {
  183. //
  184. // Loop over all the sections in the INI
  185. //
  186. List<INISection *> &section_list = ini_file->Get_Section_List ();
  187. for ( INISection *section = section_list.First ();
  188. section != NULL && section->Is_Valid ();
  189. section = section->Next_Valid ())
  190. {
  191. //
  192. // Get the animation name from the section name
  193. //
  194. StringClass animation_name = section->Section;
  195. ::strupr (animation_name.Peek_Buffer ());
  196. //
  197. // Allocate a sound list
  198. //
  199. ANIM_SOUND_LIST *sound_list = new ANIM_SOUND_LIST;
  200. //
  201. // Loop over all the entries in this section
  202. //
  203. int entry_count = ini_file->Entry_Count (section->Section);
  204. for (int entry_index = 0; entry_index < entry_count; entry_index ++) {
  205. StringClass value;
  206. //
  207. // Get the data associated with this entry
  208. //
  209. const char *entry_name = ini_file->Get_Entry (section->Section, entry_index);
  210. ini_file->Get_String (value, section->Section, entry_name);
  211. //
  212. // Extract the parameters from the section
  213. //
  214. int len = value.Get_Length ();
  215. StringClass definition_name (len + 1, true);
  216. int frame_start = 0;
  217. //
  218. // Separate the parameters into an easy-to-handle data structure
  219. //
  220. StringClass *param_list = NULL;
  221. int param_count = ::Build_List_From_String (value, ",", &param_list);
  222. if (param_count == 2) {
  223. frame_start = ::atoi (param_list[0]);
  224. definition_name = param_list[1];
  225. definition_name.Trim ();
  226. delete [] param_list;
  227. //
  228. // Find this sound definition
  229. //
  230. DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (definition_name, CLASSID_SOUND);
  231. if (definition != NULL) {
  232. //
  233. // Tie the relevant information together and store it
  234. // in the list of sounds for this animation
  235. //
  236. ANIM_SOUND_INFO sound_info;
  237. sound_info.Frame = frame_start;
  238. sound_info.SoundDefinitionID = definition->Get_ID ();
  239. sound_list->Add (sound_info);
  240. }
  241. }
  242. }
  243. if (sound_list->Count () != 0) {
  244. //
  245. // Add this sound list to our hash-table and vector-array
  246. //
  247. AnimationNameHash.Insert (animation_name, sound_list);
  248. AnimSoundLists.Add (sound_list);
  249. } else {
  250. WWDEBUG_SAY (("AnimatedSoundMgrClass::Initialize -- No sounds added for %d!\n", animation_name.Peek_Buffer ()));
  251. delete sound_list;
  252. }
  253. }
  254. delete ini_file;
  255. }
  256. return ;
  257. }
  258. //////////////////////////////////////////////////////////////////////
  259. //
  260. // Shutdown
  261. //
  262. //////////////////////////////////////////////////////////////////////
  263. void
  264. AnimatedSoundMgrClass::Shutdown (void)
  265. {
  266. //
  267. // Reset the animation name hash
  268. //
  269. AnimationNameHash.Remove_All ();
  270. //
  271. // Free each of the sound objects
  272. //
  273. for (int index = 0; index < AnimSoundLists.Count (); index ++) {
  274. delete AnimSoundLists[index];
  275. }
  276. AnimSoundLists.Delete_All ();
  277. return ;
  278. }
  279. //////////////////////////////////////////////////////////////////////
  280. //
  281. // Does_Animation_Have_Embedded_Sounds
  282. //
  283. //////////////////////////////////////////////////////////////////////
  284. bool
  285. AnimatedSoundMgrClass::Does_Animation_Have_Embedded_Sounds (HAnimClass *anim)
  286. {
  287. return (Find_Sound_List (anim) != NULL);
  288. }
  289. //////////////////////////////////////////////////////////////////////
  290. //
  291. // Find_Sound_List
  292. //
  293. //////////////////////////////////////////////////////////////////////
  294. AnimatedSoundMgrClass::ANIM_SOUND_LIST *
  295. AnimatedSoundMgrClass::Find_Sound_List (HAnimClass *anim)
  296. {
  297. //
  298. // Build the full name of the animation
  299. //
  300. StringClass full_name (0, true);
  301. full_name = anim->Get_Name ();
  302. //
  303. // Make the name uppercase
  304. //
  305. ::strupr (full_name.Peek_Buffer ());
  306. //
  307. // Lookup the sound list for this animation
  308. //
  309. ANIM_SOUND_LIST *retval = AnimationNameHash.Get (full_name);
  310. return retval;
  311. }
  312. //////////////////////////////////////////////////////////////////////
  313. //
  314. // Trigger_Sound
  315. //
  316. //////////////////////////////////////////////////////////////////////
  317. float
  318. AnimatedSoundMgrClass::Trigger_Sound
  319. (
  320. HAnimClass * anim,
  321. float old_frame,
  322. float new_frame,
  323. const Matrix3D & tm
  324. )
  325. {
  326. if (anim == NULL) {
  327. return old_frame;
  328. }
  329. float retval = old_frame;
  330. //
  331. // Lookup the sound list for this animation
  332. //
  333. ANIM_SOUND_LIST *sound_list = Find_Sound_List (anim);
  334. if (sound_list != NULL) {
  335. for (int index = 0; index < sound_list->Count (); index ++) {
  336. int frame = (*sound_list)[index].Frame;
  337. //
  338. // Is the animation passing the frame we need?
  339. //
  340. if (old_frame < frame && new_frame >= frame) {
  341. //
  342. // Don't trigger the sound if its skipped to far past...
  343. //
  344. if (WWMath::Fabs (new_frame - old_frame) < 3.0F) {
  345. //
  346. // Play the sound
  347. //
  348. int def_id = (*sound_list)[index].SoundDefinitionID;
  349. WWAudioClass::Get_Instance ()->Create_Instant_Sound (def_id, tm);
  350. WWDEBUG_SAY (("Triggering Sound %d\n", GetTickCount ()));
  351. retval = frame;
  352. }
  353. }
  354. }
  355. //retval = true;
  356. }
  357. return retval;
  358. }