messagewindow.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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 : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/messagewindow.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 1/07/02 10:43a $*
  29. * *
  30. * $Revision:: 19 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "messagewindow.h"
  36. #include "assetmgr.h"
  37. #include "texture.h"
  38. #include "font3d.h"
  39. #include "objectives.h"
  40. #include "translatedb.h"
  41. #include "scene.h"
  42. #include "timemgr.h"
  43. #include "assets.h"
  44. #include "globalsettings.h"
  45. #include "smartgameobj.h"
  46. #include "evasettings.h"
  47. #include "soldier.h"
  48. #include "dynamicspeechanim.h"
  49. #include "combat.h"
  50. #include "camera.h"
  51. #include "scene.h"
  52. #include "ww3d.h"
  53. #include "wwmemlog.h"
  54. ////////////////////////////////////////////////////////////////
  55. // Constants
  56. ////////////////////////////////////////////////////////////////
  57. static const char *FONT_NAME = "FONT6X8.TGA";
  58. static const char *HEADER_FONT_NAME = "FONT8X8.TGA";
  59. ////////////////////////////////////////////////////////////////
  60. //
  61. // MessageWindowClass
  62. //
  63. ////////////////////////////////////////////////////////////////
  64. MessageWindowClass::MessageWindowClass (void) :
  65. TextWindow (NULL),
  66. DecayTime (6000),
  67. Scene (NULL),
  68. Camera (NULL),
  69. HeadModel (NULL),
  70. IsRectangleDirty (true)
  71. {
  72. MessageLog.Set_Growth_Step (1000);
  73. MessageLogColor.Set_Growth_Step (1000);
  74. return ;
  75. }
  76. ////////////////////////////////////////////////////////////////
  77. //
  78. // ~MessageWindowClass
  79. //
  80. ////////////////////////////////////////////////////////////////
  81. MessageWindowClass::~MessageWindowClass (void)
  82. {
  83. REF_PTR_RELEASE (Scene);
  84. REF_PTR_RELEASE (Camera);
  85. return ;
  86. }
  87. ////////////////////////////////////////////////////////////////
  88. //
  89. // Shutdown
  90. //
  91. ////////////////////////////////////////////////////////////////
  92. void
  93. MessageWindowClass::Shutdown (void)
  94. {
  95. if (TextWindow != NULL) {
  96. delete TextWindow;
  97. TextWindow = NULL;
  98. }
  99. if (HeadModel != NULL) {
  100. HeadModel->Remove ();
  101. }
  102. REF_PTR_RELEASE (HeadModel);
  103. Clear_Log ();
  104. return ;
  105. }
  106. ////////////////////////////////////////////////////////////////
  107. //
  108. // Initialize
  109. //
  110. ////////////////////////////////////////////////////////////////
  111. void
  112. MessageWindowClass::Initialize (void)
  113. {
  114. WWMEMLOG(MEM_GAMEDATA);
  115. //
  116. // Allocate the new text window
  117. //
  118. TextWindow = new TextWindowClass;
  119. EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
  120. //
  121. // Configure the backdrop for the text window
  122. //
  123. CurrentRect = settings->Get_Messages_Screen_Rect ();
  124. CurrentRect.Bottom = CurrentRect.Top + 1;
  125. TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
  126. settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
  127. settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());
  128. //
  129. // Configure the area where text can be displayed in the window
  130. //
  131. RectClass text_rect = settings->Get_Messages_Text_Rect ();
  132. text_rect.Bottom = text_rect.Top + 1;
  133. TextWindow->Set_Text_Area (text_rect);
  134. //
  135. // Configure the fonts for the window
  136. //
  137. TextWindow->Set_Heading_Font (HEADER_FONT_NAME);
  138. TextWindow->Set_Text_Font (FONT_NAME);
  139. //
  140. // Configure the columns
  141. //
  142. TextWindow->Add_Column (L"", 1.0F, Vector3 (1, 1, 1));
  143. TextWindow->Display_Columns (false);
  144. //
  145. // Configure the icon renderer
  146. //
  147. //IconRenderer.Reset ();
  148. //IconRenderer.Set_Hidden (true);
  149. //IconRenderer.Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());
  150. //
  151. // Create a scene to use for the head model
  152. //
  153. Scene = new SimpleSceneClass;
  154. Scene->Set_Ambient_Light(Vector3(1,1,1));
  155. //
  156. // Create a camera to use in the "head-scene"
  157. //
  158. Camera = new CameraClass ();
  159. Camera->Set_Position (Vector3 (0, 0, 2.0F));
  160. Camera->Set_View_Plane (DEG_TO_RADF (107.0), DEG_TO_RADF (74.0));
  161. Camera->Set_Clip_Planes (0.1F, 100.0F);
  162. Camera->Set_Projection_Type (CameraClass::ORTHO);
  163. //
  164. // Lookup the head model we'll use for conversations
  165. //
  166. //HeadModel = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("CX_HAVOC_HEAD");
  167. if (HeadModel != NULL) {
  168. HeadModel->Set_Hidden (true);
  169. //
  170. // Position the head model
  171. //
  172. Matrix3D tm (1);
  173. tm.Rotate_Z (DEG_TO_RADF (90));
  174. tm.Rotate_X (DEG_TO_RADF (90));
  175. tm.Set_Translation (Vector3 (-1.22F, 0.53F, 0));
  176. HeadModel->Set_Transform (tm);
  177. //
  178. // Add the head model to the scene
  179. //
  180. Scene->Add_Render_Object (HeadModel);
  181. }
  182. return ;
  183. }
  184. ////////////////////////////////////////////////////////////////
  185. //
  186. // Render
  187. //
  188. ////////////////////////////////////////////////////////////////
  189. void
  190. MessageWindowClass::Render (void)
  191. {
  192. WWMEMLOG(MEM_GAMEDATA);
  193. //
  194. // Update the window rectangle as necessary
  195. //
  196. if (IsRectangleDirty) {
  197. Update_Window_Rectangle ();
  198. }
  199. if (TextWindow != NULL) {
  200. TextWindow->Render ();
  201. }
  202. //IconRenderer.Render ();
  203. WW3D::Render (Scene, Camera);
  204. return ;
  205. }
  206. ////////////////////////////////////////////////////////////////
  207. //
  208. // On_Frame_Update
  209. //
  210. ////////////////////////////////////////////////////////////////
  211. void
  212. MessageWindowClass::On_Frame_Update (void)
  213. {
  214. WWMEMLOG(MEM_GAMEDATA);
  215. if (TextWindow == NULL || TextWindow->Is_Displayed () == false) {
  216. return ;
  217. }
  218. if (TextWindow->Get_Item_Count () == 0) {
  219. TextWindow->Display (false);
  220. //IconRenderer.Set_Hidden (true);
  221. if (HeadModel != NULL) {
  222. HeadModel->Set_Hidden (true);
  223. }
  224. Reset_Current_Rect ();
  225. } else {
  226. int items_to_remove = TextWindow->Get_Item_Count () - TextWindow->Get_Display_Count ();
  227. //
  228. // Remove messages from the top of the list if we have more then we
  229. // can display
  230. //
  231. for (int index = 0; index < items_to_remove; index ++) {
  232. TextWindow->Delete_Item (0);
  233. }
  234. //
  235. // Decay the entries
  236. //
  237. for (index = TextWindow->Get_Item_Count () - 1; index >= 0; index --) {
  238. //
  239. // Decay the time remaining on this message
  240. //
  241. int time_left = (int)TextWindow->Get_Item_Data (index);
  242. time_left -= TimeManager::Get_Frame_Ticks ();
  243. TextWindow->Set_Item_Data (index, (uint32)time_left);
  244. //
  245. // Should we remove this message?
  246. //
  247. if (time_left <= 0) {
  248. TextWindow->Delete_Item (index);
  249. }
  250. }
  251. }
  252. TextWindow->On_Frame_Update ();
  253. return ;
  254. }
  255. ////////////////////////////////////////////////////////////////
  256. //
  257. // Add_Message
  258. //
  259. ////////////////////////////////////////////////////////////////
  260. void
  261. MessageWindowClass::Add_Message
  262. (
  263. const WideStringClass & message,
  264. const Vector3 & color,
  265. SmartGameObj * game_obj,
  266. float decay_time
  267. )
  268. {
  269. WWMEMLOG(MEM_GAMEDATA);
  270. if (TextWindow == NULL) {
  271. return ;
  272. }
  273. //
  274. // Determine how long we should display the message for...
  275. //
  276. int decay_time_in_ms = DecayTime;
  277. if (decay_time != 0) {
  278. decay_time_in_ms = int(decay_time * 1000);
  279. }
  280. //
  281. // Add the message to the end of the list
  282. //
  283. if (message.Get_Length () > 0) {
  284. int item_index = TextWindow->Insert_Item (TextWindow->Get_Item_Count (), message);
  285. if (item_index != -1) {
  286. TextWindow->Set_Item_Color (item_index, 0, color);
  287. TextWindow->Set_Item_Data (item_index, decay_time_in_ms);
  288. }
  289. }
  290. //
  291. // Resize the window as necessary
  292. //
  293. Update_Window_Rectangle ();
  294. //
  295. // Make sure the window is displayed
  296. //
  297. if (message.Get_Length () > 0) {
  298. TextWindow->Display (true);
  299. }
  300. //
  301. // Get the name of the icon file we'll use
  302. //
  303. StringClass filename("hud_6x4_icon_default.tga",true);
  304. if (game_obj != NULL) {
  305. Strip_Path_From_Filename (filename, game_obj->Get_Info_Icon_Texture_Filename ());
  306. //
  307. // Try to play an animation on the head model
  308. //
  309. if (HeadModel != NULL) {
  310. SoldierGameObj *soldier = game_obj->As_SoldierGameObj ();
  311. if (soldier != NULL) {
  312. DynamicSpeechAnimClass *speech_anim = soldier->Get_Facial_Anim ();
  313. if (speech_anim != NULL) {
  314. HeadModel->Set_Animation( speech_anim, 0, RenderObjClass::ANIM_MODE_ONCE );
  315. }
  316. }
  317. }
  318. }
  319. //
  320. // Configure the icon renderer
  321. //
  322. //IconRenderer.Reset ();
  323. //IconRenderer.Set_Hidden (false);
  324. if (HeadModel != NULL) {
  325. HeadModel->Set_Hidden (false);
  326. }
  327. //
  328. // Log the message
  329. //
  330. MessageLog.Add (message);
  331. MessageLogColor.Add (color);
  332. //
  333. // Calculate the display rectangle of the icon
  334. //
  335. /*const HUDGlobalSettingsDef *hud_settings = HUDGlobalSettingsDef::Get_Instance ();
  336. RectClass icon_rect (Vector2 (0, 0), hud_settings->TargetIconSize);
  337. icon_rect += Render2DClass::Get_Screen_Resolution().Upper_Left () + settings->Get_Messages_Icon_Position ();*/
  338. //
  339. // Build the icon mesh
  340. //
  341. //IconRenderer.Set_Texture ( filename );
  342. //IconRenderer.Add_Quad (icon_rect, 0xFFFFFFFF);
  343. return ;
  344. }
  345. ////////////////////////////////////////////////////////////////
  346. //
  347. // Update_Window_Rectangle
  348. //
  349. ////////////////////////////////////////////////////////////////
  350. void
  351. MessageWindowClass::Update_Window_Rectangle (void)
  352. {
  353. //
  354. // Get the dimensions of the text window
  355. //
  356. EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
  357. if (settings == NULL || TextWindow == NULL) {
  358. return;
  359. }
  360. WWASSERT(settings != NULL);
  361. RectClass screen_rect = settings->Get_Messages_Screen_Rect ();
  362. RectClass text_rect = settings->Get_Messages_Text_Rect ();
  363. float top_border = text_rect.Top - screen_rect.Top;
  364. float bottom_border = screen_rect.Bottom - text_rect.Bottom;
  365. float vert_border = top_border + bottom_border;
  366. //
  367. // Resize the area (if needs be)
  368. //
  369. WWASSERT(TextWindow != NULL);
  370. float total_height = TextWindow->Get_Total_Display_Height ();
  371. if (IsRectangleDirty || (total_height > (CurrentRect.Height () - vert_border))) {
  372. CurrentRect.Bottom = WWMath::Clamp (CurrentRect.Top + total_height + vert_border, 0, screen_rect.Bottom);
  373. //
  374. // Resize the backdrop area
  375. //
  376. TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
  377. settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
  378. settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());
  379. //
  380. // Resize the text area
  381. //
  382. text_rect.Top = CurrentRect.Top + top_border;
  383. text_rect.Bottom = CurrentRect.Bottom - bottom_border;
  384. TextWindow->Set_Text_Area (text_rect);
  385. }
  386. IsRectangleDirty = false;
  387. return ;
  388. }
  389. ////////////////////////////////////////////////////////////////
  390. //
  391. // Clear
  392. //
  393. ////////////////////////////////////////////////////////////////
  394. void
  395. MessageWindowClass::Clear (void)
  396. {
  397. if (TextWindow != NULL) {
  398. TextWindow->Delete_All_Items ();
  399. }
  400. return ;
  401. }
  402. ////////////////////////////////////////////////////////////////
  403. //
  404. // Force_Display
  405. //
  406. ////////////////////////////////////////////////////////////////
  407. void
  408. MessageWindowClass::Force_Display (bool onoff)
  409. {
  410. if (TextWindow != NULL) {
  411. TextWindow->Display (onoff);
  412. }
  413. //IconRenderer.Set_Hidden (!onoff);
  414. if (HeadModel != NULL) {
  415. HeadModel->Set_Hidden (!onoff);
  416. }
  417. Reset_Current_Rect ();
  418. return ;
  419. }
  420. ////////////////////////////////////////////////////////////////
  421. //
  422. // Has_Data
  423. //
  424. ////////////////////////////////////////////////////////////////
  425. bool
  426. MessageWindowClass::Has_Data (void) const
  427. {
  428. return (TextWindow != NULL && TextWindow->Get_Item_Count () > 0);
  429. }
  430. ////////////////////////////////////////////////////////////////
  431. //
  432. // Reset_Current_Rect
  433. //
  434. ////////////////////////////////////////////////////////////////
  435. void
  436. MessageWindowClass::Reset_Current_Rect (void)
  437. {
  438. EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
  439. //
  440. // Shrink the rectangle so its only 1 pixel high (this will force
  441. // it to grow to the right size later on).
  442. //
  443. CurrentRect = settings->Get_Messages_Screen_Rect ();
  444. CurrentRect.Bottom = CurrentRect.Top + 1;
  445. return ;
  446. }