textdisplay.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/textdisplay.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 1/02/02 2:27a $*
  29. * *
  30. * $Revision:: 55 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "textdisplay.h"
  36. #include "font3d.h"
  37. #include "assets.h"
  38. #include "render2D.h"
  39. #include "timemgr.h"
  40. #include "_globals.h"
  41. #include "registry.h"
  42. #include "wwprofile.h"
  43. #include "combat.h"
  44. #include "ccamera.h"
  45. #include "render2Dsentence.h"
  46. #include "wwmemlog.h"
  47. #include "consolemode.h"
  48. /*
  49. ** TextDisplayLine
  50. */
  51. TextDisplayLine::TextDisplayLine( const WideStringClass & text, unsigned long color ) :
  52. Time( 0 ),
  53. LineCount( 0 ),
  54. Text( text ),
  55. Color( color )
  56. {
  57. for( const WCHAR * ch = text; *ch; ch++ ) {
  58. if ( *ch == (WCHAR)'\n' ) {
  59. LineCount++;
  60. }
  61. }
  62. }
  63. /*
  64. ** TextDisplayGameMode
  65. */
  66. TextDisplayGameModeClass * TextDisplayGameModeClass::Instance = NULL;
  67. void TextDisplayGameModeClass::Init()
  68. {
  69. if (!ConsoleBox.Is_Exclusive()) {
  70. // Build Fonts
  71. WWASSERT(WW3DAssetManager::Get_Instance() != NULL);
  72. Font = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( "FONT8x8.TGA" );
  73. WWASSERT(Font != NULL);
  74. SET_REF_OWNER( Font );
  75. MonoFont = WW3DAssetManager::Get_Instance()->Get_Font3DInstance( "FONT8x8.TGA" );
  76. WWASSERT(MonoFont != NULL);
  77. SET_REF_OWNER( MonoFont );
  78. MonoFont->Set_Mono_Spaced();
  79. // Update Instance
  80. WWASSERT( TextDisplayGameModeClass::Instance == NULL );
  81. TextDisplayGameModeClass::Instance = this;
  82. DisplayVisWarning = false;
  83. MaxScrollLines = 30;
  84. ScrollLinesPersistTime = 10;
  85. Load_Registry_Keys();
  86. Display = new Render2DTextClass(Font);
  87. Display->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
  88. VerboseDisplay = new Render2DTextClass(Font);
  89. VerboseDisplay->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
  90. StatisticsDisplay = new Render2DTextClass(MonoFont);
  91. StatisticsDisplay->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() );
  92. RendererLines.Reset_Active();
  93. RendererColors.Reset_Active();
  94. TextChanged=true;
  95. VerboseTextChanged=true;
  96. DisplayY=0.0f;
  97. }
  98. return ;
  99. }
  100. void TextDisplayGameModeClass::Shutdown()
  101. {
  102. if (!ConsoleBox.Is_Exclusive()) {
  103. Save_Registry_Keys();
  104. Flush();
  105. delete StatisticsDisplay;
  106. StatisticsDisplay=NULL;
  107. delete VerboseDisplay;
  108. VerboseDisplay=NULL;
  109. delete Display;
  110. Display=NULL;
  111. REF_PTR_RELEASE( Font );
  112. REF_PTR_RELEASE( MonoFont );
  113. // Update Instance
  114. WWASSERT( TextDisplayGameModeClass::Instance == this );
  115. TextDisplayGameModeClass::Instance = NULL;
  116. }
  117. }
  118. /*
  119. **
  120. */
  121. void TextDisplayGameModeClass::Load_Registry_Keys(void)
  122. {
  123. RegistryClass * registry = new RegistryClass( APPLICATION_SUB_KEY_NAME_OPTIONS );
  124. WWASSERT( registry );
  125. if ( registry->Is_Valid() ) {
  126. MaxScrollLines = registry->Get_Int( "MaxScrollLines", MaxScrollLines );
  127. ScrollLinesPersistTime = registry->Get_Float( "ScrollLinesPersistTime", ScrollLinesPersistTime );
  128. }
  129. delete registry;
  130. }
  131. void TextDisplayGameModeClass::Save_Registry_Keys(void)
  132. {
  133. RegistryClass * registry = new RegistryClass( APPLICATION_SUB_KEY_NAME_OPTIONS );
  134. WWASSERT( registry );
  135. if ( registry->Is_Valid() ) {
  136. registry->Set_Int( "MaxScrollLines", MaxScrollLines );
  137. registry->Set_Float( "ScrollLinesPersistTime", ScrollLinesPersistTime );
  138. }
  139. delete registry;
  140. }
  141. /*
  142. **
  143. */
  144. void TextDisplayGameModeClass::Think()
  145. {
  146. WWPROFILE( "TextDisplay Think" );
  147. if (Font == NULL) {
  148. return;
  149. }
  150. // Update time on all scroll lines
  151. SLNode<TextDisplayLine> *linenode;
  152. for ( linenode = ScrollLines.Head(); linenode; linenode = linenode->Next() ) {
  153. TextDisplayLine *line = linenode->Data();
  154. line->Update_Time( TimeManager::Get_Frame_Seconds() );
  155. }
  156. // never have more than 2 over the max number
  157. while ( ScrollLines.Get_Count() && (Count_Scroll_Lines() >= MaxScrollLines + 2) ) {
  158. delete ScrollLines.Remove_Head();
  159. }
  160. // if there are lines to remove by count or time
  161. if ( ScrollLines.Get_Count() &&
  162. ((ScrollLines.Head()->Data()->Update_Time(0) > ScrollLinesPersistTime) ||
  163. (Count_Scroll_Lines() > MaxScrollLines) ) ) {
  164. // bump scroll position
  165. float char_height = Font->Char_Height();
  166. VerticalScroll += TimeManager::Get_Frame_Seconds() * char_height * 4;
  167. if ( VerticalScroll >= char_height ) {
  168. // top line is hidden, remove it
  169. VerticalScroll -= char_height;
  170. int lines = Count_Scroll_Lines();
  171. while ( ScrollLines.Get_Count() && (Count_Scroll_Lines() >= lines) ) {
  172. delete ScrollLines.Remove_Head();
  173. }
  174. }
  175. }
  176. // if no more need to be removed, clear scroll
  177. if ( ScrollLines.Get_Count() &&
  178. ((ScrollLines.Head()->Data()->Update_Time(0) > ScrollLinesPersistTime) ||
  179. (Count_Scroll_Lines() > MaxScrollLines) ) ) {
  180. } else {
  181. VerticalScroll = 0;
  182. }
  183. }
  184. void TextDisplayGameModeClass::Render()
  185. {
  186. WWMEMLOG(MEM_GAMEDATA);
  187. WWPROFILE( "TextDisplay Render" );
  188. if (Font == NULL) {
  189. return;
  190. }
  191. // Verbose help first
  192. if (VerboseTextChanged) {
  193. VerboseTextChanged=false;
  194. VerboseDisplay->Reset();
  195. VerboseDisplay->Set_Location( Vector2( 0, 0 ) );
  196. VerboseDisplay->Draw_Text( VerboseHelpText, 0xFF00FFFF );
  197. }
  198. VerboseDisplay->Render();
  199. // Then statistics
  200. StatisticsDisplayManager::Render( StatisticsDisplay );
  201. // And then the rest of the text...
  202. bool changed=TextChanged;
  203. TextChanged=false;
  204. if ( DisplayVisWarning && StatisticsDisplayManager::Is_Current_Display( "fps" ) ) {
  205. changed=true;
  206. }
  207. // never have more than 2 over the max number
  208. while ( ScrollLines.Get_Count() && (Count_Scroll_Lines() >= MaxScrollLines + 2) ) {
  209. delete ScrollLines.Remove_Head();
  210. changed=true;
  211. }
  212. // Check if the text lines have changed
  213. SLNode<TextDisplayLine> *linenode;
  214. if (!changed) {
  215. int j=0;
  216. WWASSERT(RendererLines.Count()==RendererColors.Count());
  217. for ( linenode = ScrollLines.Head(); linenode; linenode = linenode->Next(), j++ ) {
  218. if (j>=RendererLines.Count()) {
  219. changed=true;
  220. break;
  221. }
  222. if (RendererColors[j]!=linenode->Data()->Color || RendererLines[j]!=linenode->Data()->Text) {
  223. changed=true;
  224. break;
  225. }
  226. }
  227. }
  228. float y=WWMath::Floor( -VerticalScroll );
  229. if (y==0.0f && DisplayY!=0.0f) changed=true;
  230. float delta=y-DisplayY;
  231. DisplayY=y;
  232. if (!changed) {
  233. if (delta!=0.0f) Display->Move(Vector2(0.0f,delta));
  234. Display->Render();
  235. return;
  236. }
  237. // Display
  238. Display->Reset();
  239. // Cache the lines that are rendered
  240. RendererLines.Reset_Active();
  241. RendererColors.Reset_Active();
  242. for ( linenode = ScrollLines.Head(); linenode; linenode = linenode->Next() ) {
  243. Display->Draw_Text( linenode->Data()->Text, linenode->Data()->Color );
  244. RendererLines.Add(linenode->Data()->Text);
  245. RendererColors.Add(linenode->Data()->Color);
  246. }
  247. Display->Draw_Text( InputText );
  248. Display->Draw_Text( HelpText );
  249. if ( DisplayVisWarning && StatisticsDisplayManager::Is_Current_Display( "fps" ) ) {
  250. Vector2 pos = (Render2DClass::Get_Screen_Resolution().Upper_Left() + Render2DClass::Get_Screen_Resolution().Lower_Left()) * 0.5f;
  251. Display->Set_Location( pos );
  252. Display->Draw_Text( "Vis Sector Not Found!", 0xFF0000FF );
  253. }
  254. Display->Render();
  255. }
  256. void TextDisplayGameModeClass::Flush( void )
  257. {
  258. while ( ScrollLines.Get_Count() ) {
  259. delete ScrollLines.Remove_Head();
  260. }
  261. }
  262. int TextDisplayGameModeClass::Count_Scroll_Lines( void )
  263. {
  264. int count = 0;
  265. SLNode<TextDisplayLine> *linenode;
  266. for ( linenode = ScrollLines.Head(); linenode; linenode = linenode->Next() ) {
  267. count += linenode->Data()->Get_Line_Count();
  268. }
  269. return count;
  270. }
  271. /*
  272. ** Printing
  273. */
  274. void TextDisplayGameModeClass::Print( const char * string, const Vector4 & color )
  275. {
  276. if (Font == NULL) {
  277. return;
  278. }
  279. unsigned long col=(unsigned(color[0]*255.0f)<<24)|(unsigned(color[1]*255.0f)<<16)|(unsigned(color[2]*255.0f)<<8)|(unsigned(color[3]*255.0f));
  280. WideStringClass wide_string;
  281. wide_string.Convert_From( string );
  282. TextDisplayLine * line = new TextDisplayLine( wide_string, col );
  283. ScrollLines.Add_Tail( line );
  284. }
  285. void TextDisplayGameModeClass::Print( const WideStringClass & string, const Vector4 & color )
  286. {
  287. if (Font == NULL) {
  288. return;
  289. }
  290. unsigned long col=(unsigned(color[0]*255.0f)<<24)|(unsigned(color[1]*255.0f)<<16)|(unsigned(color[2]*255.0f)<<8)|(unsigned(color[3]*255.0f));
  291. TextDisplayLine * line = new TextDisplayLine( string, col );
  292. ScrollLines.Add_Tail( line );
  293. }
  294. void TextDisplayGameModeClass::Print( const char * string, const Vector3 & color )
  295. {
  296. if (Font == NULL) {
  297. return;
  298. }
  299. //TSS unsigned long col=(unsigned(color[0]*255.0f)<<24)|(unsigned(color[1]*255.0f)<<16)|(unsigned(color[2]*255.0f)<<8)|0xff;
  300. unsigned long col=(unsigned(color[0]*255.0f)<<16)|(unsigned(color[1]*255.0f)<<8)|(unsigned(color[2]*255.0f))|0xFF000000;
  301. WideStringClass wide_string;
  302. wide_string.Convert_From( string );
  303. TextDisplayLine * line = new TextDisplayLine( wide_string, col );
  304. ScrollLines.Add_Tail( line );
  305. }
  306. void TextDisplayGameModeClass::Print( const WideStringClass & string, const Vector3 & color )
  307. {
  308. if (Font == NULL) {
  309. return;
  310. }
  311. //TSS unsigned long col=(unsigned(color[0]*255.0f)<<24)|(unsigned(color[1]*255.0f)<<16)|(unsigned(color[2]*255.0f)<<8)|0xff;
  312. unsigned long col=(unsigned(color[0]*255.0f)<<16)|(unsigned(color[1]*255.0f)<<8)|(unsigned(color[2]*255.0f))|0xFF000000;
  313. TextDisplayLine * line = new TextDisplayLine( string, col );
  314. ScrollLines.Add_Tail( line );
  315. }
  316. void TextDisplayGameModeClass::Print_System( const char * format, ... )
  317. {
  318. va_list arg_list;
  319. va_start (arg_list, format);
  320. StringClass string;
  321. string.Format_Args( format, arg_list );
  322. va_end (arg_list);
  323. Print( string, Vector4( 1,1,0,1 ) );
  324. }
  325. void TextDisplayGameModeClass::Print_System( const WideStringClass & string )
  326. {
  327. Print( string, Vector4( 1,1,0,1 ) );
  328. }
  329. void TextDisplayGameModeClass::Print_Informational( const char * format, ... )
  330. {
  331. va_list arg_list;
  332. va_start (arg_list, format);
  333. StringClass string;
  334. string.Format_Args( format, arg_list );
  335. va_end (arg_list);
  336. Print( string, Vector4( 0.7f,0.7f,0.7f,1.0f ) );
  337. }
  338. void TextDisplayGameModeClass::Print_Informational( const WideStringClass & string )
  339. {
  340. Print( string, Vector4( 0.7f,0.7f,0.7f,1.0f ) );
  341. }
  342. /*
  343. ** TextDebugDisplayHandler
  344. */
  345. void TextDebugDisplayHandlerClass::Display_Text( const char * string, const Vector4 & color )
  346. {
  347. if (Get_Text_Display() != NULL) {
  348. Get_Text_Display()->Print( string, color );
  349. }
  350. }
  351. void TextDebugDisplayHandlerClass::Display_Text( const WideStringClass & string, const Vector4 & color )
  352. {
  353. if (Get_Text_Display() != NULL) {
  354. Get_Text_Display()->Print( string, color );
  355. }
  356. }
  357. /*
  358. ** StatisticsDisplay
  359. */
  360. static float _StatsScrollOffset = 0;
  361. static StringClass _StatsTitle;
  362. static StringClass _StatsText;
  363. static unsigned long _StatsColor = 0xFFFFFFFF;
  364. static Vector2 _StatsLocation( 0,0 );
  365. void StatisticsDisplayManager::Render(Render2DTextClass * renderer)
  366. {
  367. if (WWDEBUG_TRIGGER(WWDEBUG_TRIGGER_GENERIC0)) {
  368. _StatsScrollOffset -= 32.0f;
  369. }
  370. if (WWDEBUG_TRIGGER(WWDEBUG_TRIGGER_GENERIC1)) {
  371. _StatsScrollOffset += 32.0f;
  372. }
  373. renderer->Reset();
  374. renderer->Set_Location( _StatsLocation );
  375. renderer->Draw_Text( _StatsText, _StatsColor );
  376. renderer->Render();
  377. }
  378. void StatisticsDisplayManager::Set_Display( const char * title )
  379. {
  380. _StatsScrollOffset = 0;
  381. _StatsTitle = title;
  382. _StatsText = "";
  383. }
  384. bool StatisticsDisplayManager::Is_Current_Display( const char* title) // Returns true if "title" is currently active
  385. {
  386. return !stricmp( _StatsTitle, title );
  387. }
  388. void StatisticsDisplayManager::Set_Stat( const char * title, const char * text, unsigned long color, const Vector2& location )
  389. {
  390. if ( Is_Current_Display( title ) ) {
  391. _StatsText = text;
  392. _StatsColor = color;
  393. if ( location.Y == -240 ) {
  394. // Handle default case
  395. Vector2 pos = (Render2DClass::Get_Screen_Resolution().Upper_Left() + Render2DClass::Get_Screen_Resolution().Upper_Right()) * 0.5f;
  396. _StatsLocation = pos;
  397. } else {
  398. _StatsLocation = location;
  399. }
  400. }
  401. }