UndoMgr.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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 : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/UndoMgr.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 4/19/01 11:34a $*
  29. * *
  30. * $Revision:: 9 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "stdafx.h"
  36. #include "undomgr.h"
  37. #include "utils.h"
  38. #include "nodemgr.h"
  39. #include "node.h"
  40. #include "leveleditdoc.h"
  41. #include "leveleditview.h"
  42. #include "mover.h"
  43. #include "zonenode.h"
  44. #include "damagezonenode.h"
  45. ////////////////////////////////////////////////////////////////////////////////////
  46. //
  47. // Local constants
  48. //
  49. ////////////////////////////////////////////////////////////////////////////////////
  50. const LPCTSTR OPERATION_NAMES[OPERATION_COUNT] =
  51. {
  52. "Move",
  53. "Rotate",
  54. "Delete",
  55. "Resize"
  56. };
  57. //**************************************************************************************************************//
  58. //
  59. // Start of UndoMgrClass
  60. //
  61. //**************************************************************************************************************//
  62. ///////////////////////////////////////////////////////////
  63. //
  64. // Free_Buffer_List
  65. //
  66. ///////////////////////////////////////////////////////////
  67. void
  68. UndoMgrClass::Free_Buffer_List (void)
  69. {
  70. // Free each buffer in our array
  71. for (int index = 0; index < m_iCurrentBuffer; index ++) {
  72. SAFE_DELETE (m_pBuffers[index]);
  73. }
  74. // Reset the current index
  75. m_iCurrentBuffer = 0;
  76. return ;
  77. }
  78. ///////////////////////////////////////////////////////////
  79. //
  80. // Begin_Operation
  81. //
  82. ///////////////////////////////////////////////////////////
  83. void
  84. UndoMgrClass::Begin_Operation
  85. (
  86. OPERATION_TYPE type,
  87. const NODE_LIST &nodes_affected
  88. )
  89. {
  90. UndoBufferClass *pbuffer = new UndoBufferClass;
  91. ASSERT (pbuffer != NULL);
  92. if (pbuffer != NULL) {
  93. // Pass the identifcation information onto the new buffer
  94. pbuffer->Set_Operation_Type (type);
  95. pbuffer->Set_ID (m_dwNextOperationID++);
  96. // Capture the current state of the world in the buffer
  97. switch (type)
  98. {
  99. case OPERATION_MOVE:
  100. case OPERATION_ROTATE:
  101. {
  102. // Record the positions and orientations of the nodes
  103. pbuffer->Capture_Position (nodes_affected);
  104. }
  105. break;
  106. case OPERATION_DELETE:
  107. {
  108. // Make 'backups' of the node that will be deleted
  109. pbuffer->Capture_Existence (nodes_affected);
  110. }
  111. break;
  112. case OPERATION_RESIZE:
  113. {
  114. // Record the width, height, and depth of the nodes
  115. pbuffer->Capture_Dimensions (nodes_affected);
  116. }
  117. break;
  118. }
  119. // Push this undo buffer onto the end of our 'stack'
  120. Push_Buffer (pbuffer);
  121. }
  122. return ;
  123. }
  124. ///////////////////////////////////////////////////////////
  125. //
  126. // Push_Buffer
  127. //
  128. ///////////////////////////////////////////////////////////
  129. void
  130. UndoMgrClass::Push_Buffer (UndoBufferClass *pbuffer)
  131. {
  132. // Param OK?
  133. ASSERT (pbuffer != NULL);
  134. if (pbuffer != NULL) {
  135. // Can we just add the buffer onto the end of the array?
  136. if (m_iCurrentBuffer < UNDO_LEVELS) {
  137. m_pBuffers[m_iCurrentBuffer++] = pbuffer;
  138. } else {
  139. // Push the first entry off the list and move everything else down a position
  140. SAFE_DELETE (m_pBuffers[0]);
  141. ::memmove (&m_pBuffers[0], &m_pBuffers[1], sizeof (UndoBufferClass *) * (UNDO_LEVELS - 1));
  142. // Now simply add the buffer to the end of the array
  143. m_iCurrentBuffer = UNDO_LEVELS;
  144. m_pBuffers[m_iCurrentBuffer-1] = pbuffer;
  145. }
  146. }
  147. return ;
  148. }
  149. //////////////////////////////////////////////////////////
  150. //
  151. // Get_Next_Undo_Name
  152. //
  153. //////////////////////////////////////////////////////////
  154. LPCTSTR
  155. UndoMgrClass::Get_Next_Undo_Name (void) const
  156. {
  157. LPCTSTR pundo_name = NULL;
  158. // If we have an undo stack, then return the name of the topmost buffer
  159. if (m_iCurrentBuffer > 0) {
  160. pundo_name = m_pBuffers[m_iCurrentBuffer - 1]->Get_Operation_Name ();
  161. }
  162. // Return the undo name
  163. return pundo_name;
  164. }
  165. //////////////////////////////////////////////////////////
  166. //
  167. // Perform_Undo
  168. //
  169. //////////////////////////////////////////////////////////
  170. void
  171. UndoMgrClass::Perform_Undo (int ilevels)
  172. {
  173. // Loop through the undo levels and restore the world state at each...
  174. int imin_index = ::max((m_iCurrentBuffer - ilevels), 0);
  175. for (int index = (m_iCurrentBuffer - 1); index >= imin_index; index --) {
  176. // Undo this level
  177. m_pBuffers[index]->Restore_State ();
  178. SAFE_DELETE (m_pBuffers[index]);
  179. m_iCurrentBuffer --;
  180. }
  181. return ;
  182. }
  183. //**************************************************************************************************************//
  184. //
  185. // End of UndoMgrClass
  186. //
  187. //**************************************************************************************************************//
  188. //**************************************************************************************************************//
  189. //
  190. // Start of UndoBufferClass
  191. //
  192. //**************************************************************************************************************//
  193. //////////////////////////////////////////////////////////
  194. //
  195. // operator=
  196. //
  197. //////////////////////////////////////////////////////////
  198. const UndoBufferClass::NodeStateClass &
  199. UndoBufferClass::NodeStateClass::operator= (const NodeStateClass &src)
  200. {
  201. MEMBER_ADD (node_ptr, src.node_ptr);
  202. transform = src.transform;
  203. dimensions = src.dimensions;
  204. return *this;
  205. }
  206. //////////////////////////////////////////////////////////
  207. //
  208. // ~NodeStateClass
  209. //
  210. //////////////////////////////////////////////////////////
  211. UndoBufferClass::NodeStateClass::~NodeStateClass (void)
  212. {
  213. MEMBER_RELEASE (node_ptr);
  214. return ;
  215. }
  216. //////////////////////////////////////////////////////////
  217. //
  218. // Capture_Dimensions
  219. //
  220. //////////////////////////////////////////////////////////
  221. void
  222. UndoBufferClass::Capture_Dimensions (const NODE_LIST &node_list)
  223. {
  224. // Loop through all the nodes in the list and copy their dimensions
  225. for (int index = 0; index < node_list.Count (); index ++) {
  226. NodeClass *node = node_list[index];
  227. if (node != NULL) {
  228. //
  229. // This operation only applies to zones. Is this a zone?
  230. //
  231. if ( node->Get_Type () == NODE_TYPE_ZONE ||
  232. node->Get_Type () == NODE_TYPE_DAMAGE_ZONE)
  233. {
  234. Box3DClass *box = NULL;
  235. if (node->Get_Type () == NODE_TYPE_ZONE) {
  236. ZoneNodeClass *zone = (ZoneNodeClass *)node;
  237. box = zone->Get_Box ();
  238. } else {
  239. DamageZoneNodeClass *zone = (DamageZoneNodeClass *)node;
  240. box = zone->Get_Box ();
  241. }
  242. //
  243. // Copy the node's dimensions
  244. //
  245. NodeStateClass state;
  246. MEMBER_ADD (state.node_ptr, node);
  247. state.dimensions = box->Get_Dimensions ();
  248. state.transform = node->Get_Transform ();
  249. //
  250. // Add this state information to our list
  251. //
  252. m_StateList.Add (state);
  253. }
  254. }
  255. }
  256. return ;
  257. }
  258. //////////////////////////////////////////////////////////
  259. //
  260. // Capture_Existence
  261. //
  262. //////////////////////////////////////////////////////////
  263. void
  264. UndoBufferClass::Capture_Existence (const NODE_LIST &node_list)
  265. {
  266. // Loop through all the nodes in the list and copy their pointers
  267. for (int index = 0; index < node_list.Count (); index ++) {
  268. NodeClass *node = node_list[index];
  269. if (node != NULL && node->Get_Type () != NODE_TYPE_WAYPOINT) {
  270. // Store this node in our state manager
  271. NodeStateClass state;
  272. MEMBER_ADD (state.node_ptr, node);
  273. // Add this state information to our list
  274. m_StateList.Add (state);
  275. }
  276. }
  277. return ;
  278. }
  279. //////////////////////////////////////////////////////////
  280. //
  281. // Capture_Position
  282. //
  283. //////////////////////////////////////////////////////////
  284. void
  285. UndoBufferClass::Capture_Position (const NODE_LIST &node_list)
  286. {
  287. // Loop through all the nodes in the list and copy their position information
  288. for (int index = 0; index < node_list.Count (); index ++) {
  289. NodeClass *node = node_list[index];
  290. if (node != NULL) {
  291. // Copy the node's state information
  292. NodeStateClass state;
  293. MEMBER_ADD (state.node_ptr, node);
  294. state.transform = node->Get_Transform ();
  295. // Add this state information to our list
  296. m_StateList.Add (state);
  297. }
  298. }
  299. return ;
  300. }
  301. //////////////////////////////////////////////////////////
  302. //
  303. // Restore_State
  304. //
  305. //////////////////////////////////////////////////////////
  306. void
  307. UndoBufferClass::Restore_State (void)
  308. {
  309. // Turn painting off
  310. CLevelEditView::Allow_Repaint (false);
  311. //
  312. // Loop through all the entries in our state list,
  313. // and restore their state
  314. //
  315. for (int index = 0; index < m_StateList.Count (); index ++) {
  316. // Alias the state structure
  317. NodeStateClass &state = m_StateList[index];
  318. // What type of undo operation is this?
  319. switch (m_Type)
  320. {
  321. case OPERATION_MOVE:
  322. case OPERATION_ROTATE:
  323. {
  324. //
  325. // Reset this node's position and orientation
  326. //
  327. if (state.node_ptr != NULL) {
  328. state.node_ptr->Set_Transform (state.transform);
  329. }
  330. }
  331. break;
  332. case OPERATION_RESIZE:
  333. {
  334. NodeClass *node = state.node_ptr;
  335. ASSERT (node != NULL);
  336. //
  337. // This operation only applies to zones, so if
  338. // this node is a zone, then resize it.
  339. //
  340. if ( node->Get_Type () == NODE_TYPE_ZONE ||
  341. node->Get_Type () == NODE_TYPE_DAMAGE_ZONE)
  342. {
  343. Box3DClass *box = NULL;
  344. if (node->Get_Type () == NODE_TYPE_ZONE) {
  345. ZoneNodeClass *zone = (ZoneNodeClass *)node;
  346. box = zone->Get_Box ();
  347. } else {
  348. DamageZoneNodeClass *zone = (DamageZoneNodeClass *)node;
  349. box = zone->Get_Box ();
  350. }
  351. ASSERT (box != NULL);
  352. box->Set_Dimensions (state.dimensions);
  353. node->Set_Transform (state.transform);
  354. }
  355. }
  356. break;
  357. case OPERATION_DELETE:
  358. {
  359. // Add the 'deleted' node back into the world
  360. ASSERT (state.node_ptr != NULL);
  361. if (state.node_ptr != NULL) {
  362. ::Get_Scene_Editor ()->Add_Node (state.node_ptr);
  363. state.node_ptr->On_Restore ();
  364. state.node_ptr->Hide (false);
  365. }
  366. }
  367. break;
  368. }
  369. }
  370. // Ensure the main view is updated
  371. ::Refresh_Main_View ();
  372. // Turn painting back on
  373. CLevelEditView::Allow_Repaint (true);
  374. return ;
  375. }
  376. //////////////////////////////////////////////////////////
  377. //
  378. // Get_Operation_Name
  379. //
  380. //////////////////////////////////////////////////////////
  381. LPCTSTR
  382. UndoBufferClass::Get_Operation_Name (void)
  383. {
  384. return OPERATION_NAMES[m_Type];
  385. }
  386. //**************************************************************************************************************//
  387. //
  388. // End of UndoBufferClass
  389. //
  390. //**************************************************************************************************************//