SoundSceneObj.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. ** Command & Conquer Generals(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:: 8/24/01 5:10p $*
  27. * *
  28. * $Revision:: 15 $*
  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. REF_PTR_RELEASE (m_UserObj);
  120. REF_PTR_RELEASE (m_AttachedObject);
  121. Unregister_Sound_Object (this);
  122. return ;
  123. }
  124. ////////////////////////////////////////////////////////////////////////////////////////////////
  125. //
  126. // operator=
  127. //
  128. ////////////////////////////////////////////////////////////////////////////////////////////////
  129. const SoundSceneObjClass &
  130. SoundSceneObjClass::operator= (const SoundSceneObjClass &src)
  131. {
  132. m_Scene = src.m_Scene;
  133. m_pCallback = src.m_pCallback;
  134. m_RegisteredEvents = src.m_RegisteredEvents;
  135. Attach_To_Object (src.m_AttachedObject, src.m_AttachedBone);
  136. PersistClass::operator= ((const PersistClass &)src);
  137. return (*this);
  138. }
  139. ////////////////////////////////////////////////////////////////////////////////////////////////
  140. //
  141. // Attach_To_Object
  142. //
  143. ////////////////////////////////////////////////////////////////////////////////////////////////
  144. void
  145. SoundSceneObjClass::Attach_To_Object
  146. (
  147. RenderObjClass * render_obj,
  148. const char * bone_name
  149. )
  150. {
  151. REF_PTR_SET (m_AttachedObject, render_obj);
  152. if (m_AttachedObject != NULL && bone_name != NULL) {
  153. m_AttachedBone = m_AttachedObject->Get_Bone_Index (bone_name);
  154. } else {
  155. m_AttachedBone = -1;
  156. }
  157. return ;
  158. }
  159. ////////////////////////////////////////////////////////////////////////////////////////////////
  160. //
  161. // Attach_To_Object
  162. //
  163. ////////////////////////////////////////////////////////////////////////////////////////////////
  164. void
  165. SoundSceneObjClass::Attach_To_Object
  166. (
  167. RenderObjClass * render_obj,
  168. int bone_index
  169. )
  170. {
  171. if (m_AttachedObject != render_obj || m_AttachedBone != bone_index) {
  172. //
  173. // Record the attachment
  174. //
  175. REF_PTR_SET (m_AttachedObject, render_obj);
  176. m_AttachedBone = bone_index;
  177. //
  178. // Update the transform
  179. //
  180. Apply_Auto_Position ();
  181. }
  182. return ;
  183. }
  184. //////////////////////////////////////////////////////////////////////////////
  185. //
  186. // Apply_Auto_Position
  187. //
  188. //////////////////////////////////////////////////////////////////////////////
  189. void
  190. SoundSceneObjClass::Apply_Auto_Position (void)
  191. {
  192. // If the sound is attached to an object, then update its transform
  193. // based on this link.
  194. if (m_AttachedObject != NULL) {
  195. // Determine which transform to use
  196. Matrix3D transform (1);
  197. if (m_AttachedBone >= 0) {
  198. transform = m_AttachedObject->Get_Bone_Transform (m_AttachedBone);
  199. } else {
  200. transform = m_AttachedObject->Get_Transform ();
  201. //
  202. // Convert the camera's transform to an object transform
  203. //
  204. if (m_AttachedObject->Class_ID () == RenderObjClass::CLASSID_CAMERA) {
  205. Matrix3D cam_to_world (Vector3 (0, 0, -1), Vector3 (-1, 0, 0), Vector3 (0, 1, 0), Vector3 (0, 0, 0));
  206. #ifdef ALLOW_TEMPORARIES
  207. transform = transform * cam_to_world;
  208. #else
  209. transform.postMul(cam_to_world);
  210. #endif
  211. }
  212. }
  213. // Update the sound's transform
  214. Set_Transform (transform);
  215. }
  216. return ;
  217. }
  218. //////////////////////////////////////////////////////////////////////////////////
  219. //
  220. // Save
  221. //
  222. //////////////////////////////////////////////////////////////////////////////////
  223. bool
  224. SoundSceneObjClass::Save (ChunkSaveClass &csave)
  225. {
  226. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  227. PersistClass::Save (csave);
  228. csave.End_Chunk ();
  229. csave.Begin_Chunk (CHUNKID_VARIABLES);
  230. WRITE_MICRO_CHUNK (csave, VARID_ATTACHED_OBJ, m_AttachedObject);
  231. WRITE_MICRO_CHUNK (csave, VARID_ATTACHED_BONE, m_AttachedBone);
  232. WRITE_MICRO_CHUNK (csave, VARID_USER_DATA, m_UserData);
  233. WRITE_MICRO_CHUNK (csave, VARID_USER_OBJ, m_UserObj);
  234. WRITE_MICRO_CHUNK (csave, VARID_ID, m_ID);
  235. csave.End_Chunk ();
  236. return true;
  237. }
  238. //////////////////////////////////////////////////////////////////////////////////
  239. //
  240. // Load
  241. //
  242. //////////////////////////////////////////////////////////////////////////////////
  243. bool
  244. SoundSceneObjClass::Load (ChunkLoadClass &cload)
  245. {
  246. uint32 id = SOUND_OBJ_DEFAULT_ID;
  247. while (cload.Open_Chunk ()) {
  248. switch (cload.Cur_Chunk_ID ()) {
  249. case CHUNKID_BASE_CLASS:
  250. PersistClass::Load (cload);
  251. break;
  252. case CHUNKID_VARIABLES:
  253. {
  254. //
  255. // Read all the variables from their micro-chunks
  256. //
  257. while (cload.Open_Micro_Chunk ()) {
  258. switch (cload.Cur_Micro_Chunk_ID ()) {
  259. READ_MICRO_CHUNK (cload, VARID_ATTACHED_OBJ, m_AttachedObject);
  260. READ_MICRO_CHUNK (cload, VARID_ATTACHED_BONE, m_AttachedBone);
  261. READ_MICRO_CHUNK (cload, VARID_USER_DATA, m_UserData);
  262. READ_MICRO_CHUNK (cload, VARID_USER_OBJ, m_UserObj);
  263. READ_MICRO_CHUNK (cload, VARID_ID, id);
  264. }
  265. cload.Close_Micro_Chunk ();
  266. }
  267. }
  268. break;
  269. }
  270. cload.Close_Chunk ();
  271. }
  272. //
  273. // Set the ID (this will cause the sound object to
  274. // be re-inserted in the master sorted list)
  275. //
  276. if (id != SOUND_OBJ_DEFAULT_ID) {
  277. Set_ID (id);
  278. }
  279. //
  280. // Max sure the next available ID is the largest ID in existence
  281. //
  282. m_NextAvailableID = max (m_NextAvailableID, m_ID + 1);
  283. //
  284. // We need to 'swizzle' the attached object pointer. We saved the pointer's
  285. // value, and need to map it (hopefully) to the new value.
  286. //
  287. if (m_AttachedObject != NULL) {
  288. SaveLoadSystemClass::Request_Ref_Counted_Pointer_Remap ((RefCountClass **)&m_AttachedObject);
  289. }
  290. return true;
  291. }
  292. //////////////////////////////////////////////////////////////////////////////////
  293. //
  294. // On_Frame_Update
  295. //
  296. //////////////////////////////////////////////////////////////////////////////////
  297. bool
  298. SoundSceneObjClass::On_Frame_Update (unsigned int /*milliseconds*/)
  299. {
  300. Apply_Auto_Position ();
  301. return true;
  302. }
  303. //////////////////////////////////////////////////////////////////////////////////
  304. //
  305. // Set_ID
  306. //
  307. //////////////////////////////////////////////////////////////////////////////////
  308. void
  309. SoundSceneObjClass::Set_ID (uint32 id)
  310. {
  311. //
  312. // Remove the sound object from our sorted list
  313. //
  314. Unregister_Sound_Object (this);
  315. //
  316. // Change the sound object's ID
  317. //
  318. m_ID = id;
  319. //
  320. // Reinsert the sound object in our sorted list
  321. //
  322. Register_Sound_Object (this);
  323. return ;
  324. }
  325. //////////////////////////////////////////////////////////////////////////////////
  326. //
  327. // Register_Sound_Object
  328. //
  329. //////////////////////////////////////////////////////////////////////////////////
  330. void
  331. SoundSceneObjClass::Register_Sound_Object (SoundSceneObjClass *sound_obj)
  332. {
  333. int sound_id = sound_obj->Get_ID ();
  334. CriticalSectionClass::LockClass lock(m_IDListMutex);
  335. //
  336. // Special case a non-ID
  337. //
  338. if (sound_id == SOUND_OBJ_DEFAULT_ID) {
  339. m_GlobalSoundList.Insert (0, sound_obj);
  340. } else {
  341. //
  342. // Check to ensure the object isn't already in the list
  343. //
  344. int index = 0;
  345. if (Find_Sound_Object (sound_id, &index) == false) {
  346. //
  347. // Insert the object into the list
  348. //
  349. m_GlobalSoundList.Insert (index, sound_obj);
  350. }
  351. }
  352. return ;
  353. }
  354. //////////////////////////////////////////////////////////////////////////////////
  355. //
  356. // Unregister_Sound_Object
  357. //
  358. //////////////////////////////////////////////////////////////////////////////////
  359. void
  360. SoundSceneObjClass::Unregister_Sound_Object (SoundSceneObjClass *sound_obj)
  361. {
  362. CriticalSectionClass::LockClass lock(m_IDListMutex);
  363. //
  364. // Try to find the object in the list
  365. //
  366. int index = 0;
  367. if (Find_Sound_Object (sound_obj->Get_ID (), &index)) {
  368. //
  369. // Remove the object from the list
  370. //
  371. m_GlobalSoundList.Delete (index);
  372. }
  373. return ;
  374. }
  375. //////////////////////////////////////////////////////////////////////////////////
  376. //
  377. // Find_Sound_Object
  378. //
  379. //////////////////////////////////////////////////////////////////////////////////
  380. bool
  381. SoundSceneObjClass::Find_Sound_Object (uint32 id_to_find, int *index)
  382. {
  383. CriticalSectionClass::LockClass lock(m_IDListMutex);
  384. bool found = false;
  385. (*index) = 0;
  386. int min_index = 0;
  387. int max_index = m_GlobalSoundList.Count () - 1;
  388. //
  389. // Keep looping until we've closed the window of possiblity
  390. //
  391. bool keep_going = (max_index >= min_index);
  392. while (keep_going) {
  393. //
  394. // Calculate what slot we are currently looking at
  395. //
  396. int curr_index = min_index + ((max_index - min_index) / 2);
  397. uint32 curr_id = m_GlobalSoundList[curr_index]->Get_ID ();
  398. //
  399. // Did we find the right slot?
  400. //
  401. if (id_to_find == curr_id) {
  402. (*index) = curr_index;
  403. keep_going = false;
  404. found = true;
  405. } else {
  406. //
  407. // Stop if we've narrowed the window to one entry
  408. //
  409. keep_going = (max_index > min_index);
  410. //
  411. // Move the window to the appropriate side
  412. // of the test index.
  413. //
  414. if (id_to_find < curr_id) {
  415. max_index = curr_index - 1;
  416. (*index) = curr_index;
  417. } else {
  418. min_index = curr_index + 1;
  419. (*index) = curr_index + 1;
  420. }
  421. }
  422. }
  423. return found;
  424. }