GeneratingVisDialog.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. // GeneratingVisDialog.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "leveledit.h"
  22. #include "generatingvisdialog.h"
  23. #include "utils.h"
  24. #include "sceneeditor.h"
  25. #include "nodemgr.h"
  26. #include "vispointgenerator.h"
  27. #include "leveleditview.h"
  28. #include "groupmgr.h"
  29. #include "node.h"
  30. #include "VisPointNode.h"
  31. #include "camera.h"
  32. #include "cameramgr.h"
  33. #include "vismgr.h"
  34. #include "vissectorsampler.h"
  35. #include "visgenprogress.h"
  36. #include "collisiongroups.h"
  37. #ifdef _DEBUG
  38. #define new DEBUG_NEW
  39. #undef THIS_FILE
  40. static char THIS_FILE[] = __FILE__;
  41. #endif
  42. /////////////////////////////////////////////////////////////////////////////
  43. //
  44. // GeneratingVisDialogClass dialog
  45. //
  46. /////////////////////////////////////////////////////////////////////////////
  47. GeneratingVisDialogClass::GeneratingVisDialogClass (float granularity, CWnd *parent)
  48. : m_bStop (false),
  49. m_Granularity (granularity),
  50. m_SampleHeight (10.0f),
  51. m_CurrentPoint (0),
  52. m_TotalPoints (0),
  53. m_StartTime (0),
  54. m_FarmMode (false),
  55. m_IgnoreBias (false),
  56. m_SelectionOnly (false),
  57. CDialog(GeneratingVisDialogClass::IDD, parent)
  58. {
  59. //{{AFX_DATA_INIT(GeneratingVisDialogClass)
  60. // NOTE: the ClassWizard will add member initialization here
  61. //}}AFX_DATA_INIT
  62. //
  63. // Determine the section of the status file
  64. //
  65. DWORD process_id = ::GetCurrentProcessId ();
  66. m_StatusSection.Format ("%d", process_id);
  67. //
  68. // Get the installation directory of this application
  69. //
  70. TCHAR exe_path[MAX_PATH] = { 0 };
  71. ::GetModuleFileName (::AfxGetInstanceHandle (), exe_path, sizeof (exe_path));
  72. CString path = ::Strip_Filename_From_Path (exe_path);
  73. if (path[::lstrlen(path)-1] != '\\') {
  74. path += "\\";
  75. }
  76. m_StatusFilename = path + "status.vis";
  77. ::WritePrivateProfileString ("Status", m_StatusSection, "Point Gen", m_StatusFilename);
  78. return ;
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. //
  82. // GeneratingVisDialogClass
  83. //
  84. /////////////////////////////////////////////////////////////////////////////
  85. void
  86. GeneratingVisDialogClass::DoDataExchange (CDataExchange *pDX)
  87. {
  88. CDialog::DoDataExchange(pDX);
  89. //{{AFX_DATA_MAP(GeneratingVisDialogClass)
  90. DDX_Control(pDX, IDC_PROGRESS_CTRL, m_ProgressCtrl);
  91. //}}AFX_DATA_MAP
  92. return ;
  93. }
  94. BEGIN_MESSAGE_MAP(GeneratingVisDialogClass, CDialog)
  95. //{{AFX_MSG_MAP(GeneratingVisDialogClass)
  96. //}}AFX_MSG_MAP
  97. END_MESSAGE_MAP()
  98. //////////////////////////////////////////////////////////////////////////////
  99. //
  100. // OnInitDialog
  101. //
  102. //////////////////////////////////////////////////////////////////////////////
  103. BOOL
  104. GeneratingVisDialogClass::OnInitDialog (void)
  105. {
  106. CDialog::OnInitDialog ();
  107. m_ProgressCtrl.SetRange (0, 100);
  108. m_ProgressCtrl.SetPos (0);
  109. ShowWindow (SW_SHOW);
  110. PostMessage (WM_USER+101);
  111. return TRUE;
  112. }
  113. //////////////////////////////////////////////////////////////////////////////
  114. //
  115. // OnCancel
  116. //
  117. //////////////////////////////////////////////////////////////////////////////
  118. void
  119. GeneratingVisDialogClass::OnCancel (void)
  120. {
  121. m_bStop = true;
  122. return ;
  123. }
  124. //////////////////////////////////////////////////////////////////////////////
  125. //
  126. // Reset_Vis_Data_For_Nodes
  127. //
  128. //////////////////////////////////////////////////////////////////////////////
  129. void
  130. GeneratingVisDialogClass::Reset_Vis_Data_For_Nodes (NODE_LIST &node_list)
  131. {
  132. SceneEditorClass *scene = ::Get_Scene_Editor ();
  133. if (scene == NULL) {
  134. return ;
  135. }
  136. //
  137. // Reset vis for the current node list
  138. //
  139. for (int index = 0; index < node_list.Count (); index ++) {
  140. NodeClass *node = node_list[index];
  141. if (node != NULL) {
  142. scene->Reset_Vis_For_Node (node);
  143. }
  144. }
  145. return ;
  146. }
  147. //////////////////////////////////////////////////////////////////////////////
  148. //
  149. // Build_Node_List
  150. //
  151. //////////////////////////////////////////////////////////////////////////////
  152. void
  153. GeneratingVisDialogClass::Build_Node_List (NODE_LIST &node_list)
  154. {
  155. //
  156. // Build a list of nodes that should be used to calculate
  157. // vis renders
  158. //
  159. VisMgrClass::Build_Node_List (node_list, m_SelectionOnly);
  160. //
  161. // Determine which nodes to process if we
  162. // are in farm mode.
  163. //
  164. if (m_FarmMode) {
  165. int nodes = node_list.Count ();
  166. float nodes_per_processor = ((float)nodes) / ((float)m_TotalProcessors);
  167. int starting_node = (int)::floor (nodes_per_processor * (float)m_ProcessorIndex);
  168. int ending_node = (int)::ceil (nodes_per_processor * (float)(m_ProcessorIndex+1));
  169. ending_node = min (ending_node, nodes);
  170. //
  171. // Copy the nodes from the total list into a temporary list
  172. //
  173. NODE_LIST temp_list;
  174. for (int index = starting_node; index < ending_node; index ++) {
  175. temp_list.Add (node_list[index]);
  176. }
  177. node_list.Delete_All ();
  178. node_list = temp_list;
  179. }
  180. return ;
  181. }
  182. //////////////////////////////////////////////////////////////////////////////
  183. //
  184. // WindowProc
  185. //
  186. //////////////////////////////////////////////////////////////////////////////
  187. LRESULT
  188. GeneratingVisDialogClass::WindowProc
  189. (
  190. UINT message,
  191. WPARAM wParam,
  192. LPARAM lParam
  193. )
  194. {
  195. if (message == WM_USER+101) {
  196. ::Get_Main_View ()->Allow_Repaint (false);
  197. m_StartTime = ::GetTickCount();
  198. //
  199. // Build a list of nodes we should use during the vis-generation
  200. //
  201. NODE_LIST node_list;
  202. Build_Node_List (node_list);
  203. //
  204. // Reset vis if we are doing a selection set only
  205. //
  206. if (m_SelectionOnly) {
  207. Reset_Vis_Data_For_Nodes (node_list);
  208. }
  209. //
  210. // Generate a list of points we need to render
  211. //
  212. VisPointGeneratorClass generator (m_Granularity);
  213. generator.Set_Ignore_Bias (m_IgnoreBias);
  214. generator.Set_Vis_Sample_Height (m_SampleHeight);
  215. Generate_Points (node_list, generator);
  216. //
  217. // Update the dialog so the user know we are about to start rendering
  218. // vis points
  219. //
  220. ::ShowWindow (::GetDlgItem (m_hWnd, IDC_BUILD_LIST_CHECK_ICON), SW_SHOW);
  221. m_ProgressCtrl.SetPos (0);
  222. General_Pump_Messages ();
  223. //
  224. // Setup the vis render
  225. //
  226. SceneEditorClass *scene_editor = ::Get_Scene_Editor ();
  227. bool restore_vis_point_display = scene_editor->Are_Vis_Points_Displayed ();
  228. scene_editor->Display_Vis_Points (false);
  229. m_TotalPoints = generator.Get_Total_Points ();
  230. m_CurrentPoint = 0;
  231. scene_editor->Set_Total_Vis_Points (m_TotalPoints);
  232. //
  233. // Render the generated vis points
  234. //
  235. VIS_POINT_LIST &point_list = generator.Peek_Point_List ();
  236. Render_Vis_Points (point_list);
  237. //
  238. // Update the dialog so the user knows we are done
  239. //
  240. ::ShowWindow (::GetDlgItem (m_hWnd, IDC_BUILD_LIST_CHECK_ICON), SW_SHOW);
  241. General_Pump_Messages ();
  242. if (restore_vis_point_display) {
  243. scene_editor->Display_Vis_Points (true);
  244. }
  245. // Close the dialog
  246. ::Get_Main_View ()->Allow_Repaint (true);
  247. EndDialog (TRUE);
  248. }
  249. // Allow the base class to process this message
  250. return CDialog::WindowProc (message, wParam, lParam);
  251. }
  252. //////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Update_Time
  255. //
  256. //////////////////////////////////////////////////////////////////////////////
  257. void
  258. GeneratingVisDialogClass::Update_Time (void)
  259. {
  260. //
  261. // Compute the elapsed and estimated remaining time
  262. //
  263. DWORD cur_ticks = ::GetTickCount();
  264. DWORD elapsed_ticks;
  265. if (cur_ticks > m_StartTime) {
  266. elapsed_ticks = cur_ticks - m_StartTime;
  267. } else {
  268. elapsed_ticks = 0xFFFFFFFF - m_StartTime + cur_ticks;
  269. }
  270. DWORD avg_ticks = elapsed_ticks / m_CurrentPoint;
  271. DWORD remaining_ticks = (m_TotalPoints - m_CurrentPoint) * avg_ticks;
  272. float elapsed_minutes = (float)elapsed_ticks / 60000.0f;
  273. float remaining_minutes = (float)remaining_ticks / 60000.0f;
  274. //
  275. // Update the UI
  276. //
  277. CString status_text;
  278. status_text.Format ("Rendering %d of %d points.", m_CurrentPoint + 1, m_TotalPoints);
  279. SetDlgItemText (IDC_STATUS_TEXT, status_text);
  280. CString elapsed_time_text;
  281. elapsed_time_text.Format ("Elapsed: %.1f min. Remaining: %.1f min.",elapsed_minutes,remaining_minutes);
  282. SetDlgItemText (IDC_ELAPSED_TIME_TEXT, elapsed_time_text);
  283. m_ProgressCtrl.SetPos (((m_CurrentPoint + 1) * 100) / m_TotalPoints);
  284. General_Pump_Messages ();
  285. return ;
  286. }
  287. //////////////////////////////////////////////////////////////////////////////
  288. //
  289. // Render_Vis_Points
  290. //
  291. //////////////////////////////////////////////////////////////////////////////
  292. void
  293. GeneratingVisDialogClass::Render_Vis_Points (VIS_POINT_LIST &point_list)
  294. {
  295. SceneEditorClass *scene_editor = ::Get_Scene_Editor ();
  296. VisLogClass &vis_log = scene_editor->Get_Vis_Log ();
  297. //
  298. // Loop through all the points and vis-render them
  299. //
  300. int count = point_list.Count ();
  301. for (int index = 0; (index < count) && !m_bStop; index ++) {
  302. VisPointListClass *sub_point_list = point_list[index];
  303. //
  304. // Render vis for this point
  305. //
  306. Vector3 sample_point = sub_point_list->sample_point;
  307. VisSampleClass vis_sample = scene_editor->Update_Vis (sample_point, sub_point_list->transform);
  308. vis_log.Log_Sample (vis_sample);
  309. scene_editor->Create_Vis_Point (sub_point_list->transform);
  310. m_CurrentPoint ++;
  311. //
  312. // Update the estimated time remaining
  313. //
  314. Update_Time ();
  315. //
  316. // Render vis for any sub-points
  317. //
  318. for (int sub_point = 0; sub_point < sub_point_list->Count (); sub_point ++) {
  319. Matrix3D &transform = (*sub_point_list)[sub_point];
  320. //
  321. // Render vis in each of the directions available to us
  322. //
  323. vis_sample = scene_editor->Update_Vis (sample_point, transform, VisDirBitsType(VIS_FORWARD_BIT | VIS_LEFT_BIT | VIS_RIGHT_BIT | VIS_UP_BIT | VIS_DOWN_BIT));
  324. vis_log.Log_Sample (vis_sample);
  325. scene_editor->Create_Vis_Point (transform);
  326. // Increment our total count of points
  327. m_CurrentPoint ++;
  328. //
  329. // Update the estimated time remaining
  330. //
  331. Update_Time ();
  332. }
  333. //
  334. // Output our current status to the status file
  335. //
  336. if (m_FarmMode) {
  337. CString status;
  338. status.Format ("Sectors: %d%%", int(((m_CurrentPoint + 1) * 100) / m_TotalPoints));
  339. ::WritePrivateProfileString ("Status", m_StatusSection, status, m_StatusFilename);
  340. }
  341. }
  342. return ;
  343. }
  344. //////////////////////////////////////////////////////////////////////////////
  345. //
  346. // Generate_Points
  347. //
  348. //////////////////////////////////////////////////////////////////////////////
  349. void
  350. GeneratingVisDialogClass::Generate_Points
  351. (
  352. NODE_LIST & node_list,
  353. VisPointGeneratorClass &generator
  354. )
  355. {
  356. //
  357. // Count up the total number of polygongs
  358. //
  359. int total_polys = 0;
  360. int count = node_list.Count ();
  361. for (int index = 0; (index < count) && !m_bStop; index ++) {
  362. NodeClass *node = node_list[index];
  363. RenderObjClass *rendobj = node->Peek_Render_Obj ();
  364. if (rendobj != NULL) {
  365. total_polys += rendobj->Get_Num_Polys ();
  366. }
  367. }
  368. //
  369. // Now, ask all the nodes to generate vis points
  370. //
  371. for (index = 0; (index < count) && !m_bStop; index ++) {
  372. //
  373. // Update the UI
  374. //
  375. int poly_count = generator.Get_Polys_Processed ();
  376. CString status_text;
  377. status_text.Format ("Processing %d / %d nodes, %d / %d polys.", index + 1, count, poly_count, total_polys);
  378. SetDlgItemText (IDC_STATUS_TEXT, status_text);
  379. CString elapsed_text;
  380. elapsed_text.Format ("Elapsed Time: %.1f minutes.",(::GetTickCount() - m_StartTime) / 60000.0f);
  381. SetDlgItemText (IDC_ELAPSED_TIME_TEXT, elapsed_text);
  382. m_ProgressCtrl.SetPos ((index * 100) / count);
  383. General_Pump_Messages ();
  384. //
  385. // Generate the points
  386. //
  387. NodeClass *node = node_list[index];
  388. node->Add_Vis_Points (generator);
  389. }
  390. return ;
  391. }