SoundSceneObj.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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 : WWAudio *
  23. * *
  24. * $Archive:: /Commando/Code/WWAudio/SoundSceneObj.cpp $*
  25. * *
  26. * $Modtime:: 11/02/01 11:58a $*
  27. * *
  28. * $Revision:: 16 $*
  29. * *
  30. *---------------------------------------------------------------------------------------------*
  31. * Functions: *
  32. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  33. #include "SoundSceneObj.h"
  34. #include "camera.h"
  35. #include "rendobj.h"
  36. #include "persistfactory.h"
  37. #include "SoundChunkIDs.h"
  38. #include "utils.h"
  39. //////////////////////////////////////////////////////////////////////////////////
  40. // Save/Load constants
  41. //////////////////////////////////////////////////////////////////////////////////
  42. enum
  43. {
  44. CHUNKID_VARIABLES = 0x03270459,
  45. CHUNKID_BASE_CLASS
  46. };
  47. enum
  48. {
  49. VARID_ATTACHED_OBJ = 0x01,
  50. VARID_ATTACHED_BONE,
  51. VARID_USER_DATA,
  52. VARID_USER_OBJ,
  53. VARID_ID
  54. };
  55. //////////////////////////////////////////////////////////////////////////////////
  56. // Static member initialization
  57. //////////////////////////////////////////////////////////////////////////////////
  58. DynamicVectorClass<SoundSceneObjClass *> SoundSceneObjClass::m_GlobalSoundList;
  59. uint32 SoundSceneObjClass::m_NextAvailableID = SOUND_OBJ_START_ID;
  60. CriticalSectionClass SoundSceneObjClass::m_IDListMutex;
  61. //////////////////////////////////////////////////////////////////////////////////
  62. // Mutex managment
  63. //////////////////////////////////////////////////////////////////////////////////
  64. /*
  65. class HandleMgrClass
  66. {
  67. public:
  68. HandleMgrClass (void) { SoundSceneObjClass::m_IDListMutex = ::CreateMutex (NULL, FALSE, NULL); }
  69. ~HandleMgrClass (void) { ::CloseHandle (SoundSceneObjClass::m_IDListMutex); }
  70. };
  71. HandleMgrClass _GlobalMutexHandleMgr;
  72. */
  73. ////////////////////////////////////////////////////////////////////////////////////////////////
  74. //
  75. // SoundSceneObjClass
  76. //
  77. ////////////////////////////////////////////////////////////////////////////////////////////////
  78. SoundSceneObjClass::SoundSceneObjClass (void)
  79. : m_Scene (NULL),
  80. m_PhysWrapper (NULL),
  81. m_pCallback (NULL),
  82. m_AttachedObject (NULL),
  83. m_UserData (0),
  84. m_UserObj (NULL),
  85. m_ID (SOUND_OBJ_DEFAULT_ID),
  86. m_RegisteredEvents (AudioCallbackClass::EVENT_NONE)
  87. {
  88. m_ID = m_NextAvailableID ++;
  89. Register_Sound_Object (this);
  90. return ;
  91. }
  92. ////////////////////////////////////////////////////////////////////////////////////////////////
  93. //
  94. // SoundSceneObjClass
  95. //
  96. ////////////////////////////////////////////////////////////////////////////////////////////////
  97. SoundSceneObjClass::SoundSceneObjClass (const SoundSceneObjClass &src)
  98. : m_Scene (NULL),
  99. m_PhysWrapper (NULL),
  100. m_pCallback (NULL),
  101. m_AttachedObject (NULL),
  102. m_UserData (0),
  103. m_UserObj (NULL),
  104. m_ID (SOUND_OBJ_DEFAULT_ID),
  105. m_RegisteredEvents (AudioCallbackClass::EVENT_NONE)
  106. {
  107. m_ID = m_NextAvailableID ++;
  108. (*this) = src;
  109. Register_Sound_Object (this);
  110. return ;
  111. }
  112. ////////////////////////////////////////////////////////////////////////////////////////////////
  113. //
  114. // ~SoundSceneObjClass
  115. //
  116. ////////////////////////////////////////////////////////////////////////////////////////////////
  117. SoundSceneObjClass::~SoundSceneObjClass (void)
  118. {
  119. Register_Callback (AudioCallbackClass::EVENT_NONE, NULL);
  120. REF_PTR_RELEASE (m_UserObj);
  121. REF_PTR_RELEASE (m_AttachedObject);
  122. Unregister_Sound_Object (this);
  123. return ;
  124. }
  125. ////////////////////////////////////////////////////////////////////////////////////////////////
  126. //
  127. // operator=
  128. //
  129. ////////////////////////////////////////////////////////////////////////////////////////////////
  130. const SoundSceneObjClass &
  131. SoundSceneObjClass::operator= (const SoundSceneObjClass &src)
  132. {
  133. m_Scene = src.m_Scene;
  134. m_pCallback = src.m_pCallback;
  135. m_RegisteredEvents = src.m_RegisteredEvents;
  136. Attach_To_Object (src.m_AttachedObject, src.m_AttachedBone);
  137. PersistClass::operator= ((const PersistClass &)src);
  138. return (*this);
  139. }
  140. ////////////////////////////////////////////////////////////////////////////////////////////////
  141. //
  142. // Attach_To_Object
  143. //
  144. ////////////////////////////////////////////////////////////////////////////////////////////////
  145. void
  146. SoundSceneObjClass::Attach_To_Object
  147. (
  148. RenderObjClass * render_obj,
  149. const char * bone_name
  150. )
  151. {
  152. REF_PTR_SET (m_AttachedObject, render_obj);
  153. if (m_AttachedObject != NULL && bone_name != NULL) {
  154. m_AttachedBone = m_AttachedObject->Get_Bone_Index (bone_name);
  155. } else {
  156. m_AttachedBone = -1;
  157. }
  158. return ;
  159. }
  160. ////////////////////////////////////////////////////////////////////////////////////////////////
  161. //
  162. // Attach_To_Object
  163. //
  164. ////////////////////////////////////////////////////////////////////////////////////////////////
  165. void
  166. SoundSceneObjClass::Attach_To_Object
  167. (
  168. RenderObjClass * render_obj,
  169. int bone_index
  170. )
  171. {
  172. if (m_AttachedObject != render_obj || m_AttachedBone != bone_index) {
  173. //
  174. // Record the attachment
  175. //
  176. REF_PTR_SET (m_AttachedObject, render_obj);
  177. m_AttachedBone = bone_index;
  178. //
  179. // Update the transform
  180. //
  181. Apply_Auto_Position ();
  182. }
  183. return ;
  184. }
  185. //////////////////////////////////////////////////////////////////////////////
  186. //
  187. // Apply_Auto_Position
  188. //
  189. //////////////////////////////////////////////////////////////////////////////
  190. void
  191. SoundSceneObjClass::Apply_Auto_Position (void)
  192. {
  193. // If the sound is attached to an object, then update its transform
  194. // based on this link.
  195. if (m_AttachedObject != NULL) {
  196. // Determine which transform to use
  197. Matrix3D transform (1);
  198. if (m_AttachedBone >= 0) {
  199. transform = m_AttachedObject->Get_Bone_Transform (m_AttachedBone);
  200. } else {
  201. transform = m_AttachedObject->Get_Transform ();
  202. //
  203. // Convert the camera's transform to an object transform
  204. //
  205. if (m_AttachedObject->Class_ID () == RenderObjClass::CLASSID_CAMERA) {
  206. Matrix3D cam_to_world (Vector3 (0, 0, -1), Vector3 (-1, 0, 0), Vector3 (0, 1, 0), Vector3 (0, 0, 0));
  207. transform = transform * cam_to_world;
  208. }
  209. }
  210. // Update the sound's transform
  211. Set_Transform (transform);
  212. }
  213. return ;
  214. }
  215. //////////////////////////////////////////////////////////////////////////////////
  216. //
  217. // Save
  218. //
  219. //////////////////////////////////////////////////////////////////////////////////
  220. bool
  221. SoundSceneObjClass::Save (ChunkSaveClass &csave)
  222. {
  223. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  224. PersistClass::Save (csave);
  225. csave.End_Chunk ();
  226. csave.Begin_Chunk (CHUNKID_VARIABLES);
  227. WRITE_MICRO_CHUNK (csave, VARID_ATTACHED_OBJ, m_AttachedObject);
  228. WRITE_MICRO_CHUNK (csave, VARID_ATTACHED_BONE, m_AttachedBone);
  229. WRITE_MICRO_CHUNK (csave, VARID_USER_DATA, m_UserData);
  230. WRITE_MICRO_CHUNK (csave, VARID_USER_OBJ, m_UserObj);
  231. WRITE_MICRO_CHUNK (csave, VARID_ID, m_ID);
  232. csave.End_Chunk ();
  233. return true;
  234. }
  235. //////////////////////////////////////////////////////////////////////////////////
  236. //
  237. // Load
  238. //
  239. //////////////////////////////////////////////////////////////////////////////////
  240. bool
  241. SoundSceneObjClass::Load (ChunkLoadClass &cload)
  242. {
  243. uint32 id = SOUND_OBJ_DEFAULT_ID;
  244. while (cload.Open_Chunk ()) {
  245. switch (cload.Cur_Chunk_ID ()) {
  246. case CHUNKID_BASE_CLASS:
  247. PersistClass::Load (cload);
  248. break;
  249. case CHUNKID_VARIABLES:
  250. {
  251. //
  252. // Read all the variables from their micro-chunks
  253. //
  254. while (cload.Open_Micro_Chunk ()) {
  255. switch (cload.Cur_Micro_Chunk_ID ()) {
  256. READ_MICRO_CHUNK (cload, VARID_ATTACHED_OBJ, m_AttachedObject);
  257. READ_MICRO_CHUNK (cload, VARID_ATTACHED_BONE, m_AttachedBone);
  258. READ_MICRO_CHUNK (cload, VARID_USER_DATA, m_UserData);
  259. READ_MICRO_CHUNK (cload, VARID_USER_OBJ, m_UserObj);
  260. READ_MICRO_CHUNK (cload, VARID_ID, id);
  261. }
  262. cload.Close_Micro_Chunk ();
  263. }
  264. }
  265. break;
  266. }
  267. cload.Close_Chunk ();
  268. }
  269. //
  270. // Set the ID (this will cause the sound object to
  271. // be re-inserted in the master sorted list)
  272. //
  273. if (id != SOUND_OBJ_DEFAULT_ID) {
  274. Set_ID (id);
  275. }
  276. //
  277. // Max sure the next available ID is the largest ID in existence
  278. //
  279. m_NextAvailableID = max (m_NextAvailableID, m_ID + 1);
  280. //
  281. // We need to 'swizzle' the attached object pointer. We saved the pointer's
  282. // value, and need to map it (hopefully) to the new value.
  283. //
  284. if (m_AttachedObject != NULL) {
  285. SaveLoadSystemClass::Request_Ref_Counted_Pointer_Remap ((RefCountClass **)&m_AttachedObject);
  286. }
  287. return true;
  288. }
  289. //////////////////////////////////////////////////////////////////////////////////
  290. //
  291. // On_Frame_Update
  292. //
  293. //////////////////////////////////////////////////////////////////////////////////
  294. bool
  295. SoundSceneObjClass::On_Frame_Update (unsigned int /*milliseconds*/)
  296. {
  297. Apply_Auto_Position ();
  298. return true;
  299. }
  300. //////////////////////////////////////////////////////////////////////////////////
  301. //
  302. // Set_ID
  303. //
  304. //////////////////////////////////////////////////////////////////////////////////
  305. void
  306. SoundSceneObjClass::Set_ID (uint32 id)
  307. {
  308. //
  309. // Remove the sound object from our sorted list
  310. //
  311. Unregister_Sound_Object (this);
  312. //
  313. // Change the sound object's ID
  314. //
  315. m_ID = id;
  316. //
  317. // Reinsert the sound object in our sorted list
  318. //
  319. Register_Sound_Object (this);
  320. return ;
  321. }
  322. //////////////////////////////////////////////////////////////////////////////////
  323. //
  324. // Register_Sound_Object
  325. //
  326. //////////////////////////////////////////////////////////////////////////////////
  327. void
  328. SoundSceneObjClass::Register_Sound_Object (SoundSceneObjClass *sound_obj)
  329. {
  330. int sound_id = sound_obj->Get_ID ();
  331. CriticalSectionClass::LockClass lock(m_IDListMutex);
  332. //
  333. // Special case a non-ID
  334. //
  335. if (sound_id == SOUND_OBJ_DEFAULT_ID) {
  336. m_GlobalSoundList.Insert (0, sound_obj);
  337. } else {
  338. //
  339. // Check to ensure the object isn't already in the list
  340. //
  341. int index = 0;
  342. if (Find_Sound_Object (sound_id, &index) == false) {
  343. //
  344. // Insert the object into the list
  345. //
  346. m_GlobalSoundList.Insert (index, sound_obj);
  347. }
  348. }
  349. return ;
  350. }
  351. //////////////////////////////////////////////////////////////////////////////////
  352. //
  353. // Unregister_Sound_Object
  354. //
  355. //////////////////////////////////////////////////////////////////////////////////
  356. void
  357. SoundSceneObjClass::Unregister_Sound_Object (SoundSceneObjClass *sound_obj)
  358. {
  359. CriticalSectionClass::LockClass lock(m_IDListMutex);
  360. //
  361. // Try to find the object in the list
  362. //
  363. int index = 0;
  364. if (Find_Sound_Object (sound_obj->Get_ID (), &index)) {
  365. //
  366. // Remove the object from the list
  367. //
  368. m_GlobalSoundList.Delete (index);
  369. }
  370. return ;
  371. }
  372. //////////////////////////////////////////////////////////////////////////////////
  373. //
  374. // Find_Sound_Object
  375. //
  376. //////////////////////////////////////////////////////////////////////////////////
  377. bool
  378. SoundSceneObjClass::Find_Sound_Object (uint32 id_to_find, int *index)
  379. {
  380. CriticalSectionClass::LockClass lock(m_IDListMutex);
  381. bool found = false;
  382. (*index) = 0;
  383. int min_index = 0;
  384. int max_index = m_GlobalSoundList.Count () - 1;
  385. //
  386. // Keep looping until we've closed the window of possiblity
  387. //
  388. bool keep_going = (max_index >= min_index);
  389. while (keep_going) {
  390. //
  391. // Calculate what slot we are currently looking at
  392. //
  393. int curr_index = min_index + ((max_index - min_index) / 2);
  394. uint32 curr_id = m_GlobalSoundList[curr_index]->Get_ID ();
  395. //
  396. // Did we find the right slot?
  397. //
  398. if (id_to_find == curr_id) {
  399. (*index) = curr_index;
  400. keep_going = false;
  401. found = true;
  402. } else {
  403. //
  404. // Stop if we've narrowed the window to one entry
  405. //
  406. keep_going = (max_index > min_index);
  407. //
  408. // Move the window to the appropriate side
  409. // of the test index.
  410. //
  411. if (id_to_find < curr_id) {
  412. max_index = curr_index - 1;
  413. (*index) = curr_index;
  414. } else {
  415. min_index = curr_index + 1;
  416. (*index) = curr_index + 1;
  417. }
  418. }
  419. }
  420. return found;
  421. }