W3DDisplay.cpp 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DDisplay.cpp ///////////////////////////////////////////////////////
  24. //
  25. // W3D Implementation for the Game Display which is responsible for creating
  26. // and maintaning the entire visual display
  27. //
  28. // Author: Colin Day, April 2001
  29. //
  30. ///////////////////////////////////////////////////////////////////////////////
  31. static void drawFramerateBar(void);
  32. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  33. #include <stdlib.h>
  34. #include <windows.h>
  35. #include <io.h>
  36. #include <time.h>
  37. // USER INCLUDES //////////////////////////////////////////////////////////////
  38. #include "Common/ThingFactory.h"
  39. #include "Common/GameEngine.h"
  40. #include "Common/GlobalData.h"
  41. #include "Common/PerfTimer.h"
  42. #include "Common/FileSystem.h"
  43. #include "Common/LocalFileSystem.h"
  44. #include "Common/Player.h"
  45. #include "Common/PlayerList.h"
  46. #include "Common/ThingTemplate.h"
  47. #include "Common/GameLOD.h"
  48. #include "Common/DrawModule.h"
  49. #include "GameLogic/AIPathfind.h"
  50. #include "GameLogic/Module/PhysicsUpdate.h"
  51. #include "GameClient/Drawable.h"
  52. #include "GameClient/GameText.h"
  53. #include "GameClient/GraphDraw.h"
  54. #include "GameClient/Line2D.h"
  55. #include "GameClient/Mouse.h"
  56. #include "GameClient/GlobalLanguage.h"
  57. #include "GameClient/Water.h"
  58. #include "GameNetwork/NetworkInterface.h"
  59. #include "Common/ModelState.h"
  60. #include "Lib/BaseType.h"
  61. #include "W3DDevice/Common/W3DConvert.h"
  62. #include "W3DDevice/GameClient/W3DAssetManager.h"
  63. #include "W3DDevice/GameClient/W3DGameClient.h"
  64. #include "W3DDevice/GameClient/W3DFileSystem.h"
  65. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  66. #include "W3DDevice/GameClient/HeightMap.h"
  67. #include "W3DDevice/GameClient/WorldHeightMap.h"
  68. #include "W3DDevice/GameClient/W3DScene.h"
  69. #include "W3DDevice/GameClient/W3DTerrainTracks.h"
  70. #include "W3DDevice/GameClient/W3DWater.h"
  71. #include "W3DDevice/GameClient/W3DVideoBuffer.h"
  72. #include "W3DDevice/GameClient/W3DShaderManager.h"
  73. #include "W3DDevice/GameClient/W3DDebugDisplay.h"
  74. #include "W3DDevice/GameClient/W3DProjectedShadow.h"
  75. #include "W3DDevice/GameClient/W3DShroud.h"
  76. #include "WWMath/WWMath.h"
  77. #include "WWLib/Registry.h"
  78. #include "WW3D2/WW3D.h"
  79. #include "WW3D2/PredLod.h"
  80. #include "WW3D2/Part_Emt.h"
  81. #include "WW3D2/Part_Ldr.h"
  82. #include "WW3D2/DX8Caps.h"
  83. #include "WW3D2/WW3DFormat.h"
  84. #include "WW3D2/agg_def.h"
  85. #include "WW3D2/Render2DSentence.h"
  86. #include "WW3D2/SortingRenderer.h"
  87. #include "WW3D2/Textureloader.h"
  88. #include "WW3D2/DX8WebBrowser.h"
  89. #include "WW3D2/Mesh.h"
  90. #include "WW3D2/HLOD.h"
  91. #include "WW3D2/Meshmatdesc.h"
  92. #include "WW3D2/Meshmdl.h"
  93. #include "WW3D2/rddesc.h"
  94. #include "targa.h"
  95. #include "Lib/BaseType.h"
  96. #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd
  97. #include "GameLogic/GameLogic.h"
  98. #ifdef DUMP_PERF_STATS
  99. #include "GameLogic/PartitionManager.h"
  100. #endif
  101. #include "WinMain.h"
  102. #ifdef _INTERNAL
  103. // for occasional debugging...
  104. //#pragma optimize("", off)
  105. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  106. #endif
  107. // DEFINE AND ENUMS ///////////////////////////////////////////////////////////
  108. #define W3D_DISPLAY_DEFAULT_BIT_DEPTH 32
  109. #define no_SAMPLE_DYNAMIC_LIGHT 1
  110. #ifdef SAMPLE_DYNAMIC_LIGHT
  111. static W3DDynamicLight * theDynamicLight = NULL;
  112. static Real theLightXOffset = 0.1f;
  113. static Real theLightYOffset = 0.07f;
  114. static Int theFlashCount = 0;
  115. #endif
  116. //*****************************************************************************************
  117. //*****************************************************************************************
  118. //**** Start Statistical Dump *************************************************************
  119. //*****************************************************************************************
  120. #ifdef DUMP_PERF_STATS
  121. #include <cstdarg>
  122. class StatDumpClass
  123. {
  124. public:
  125. StatDumpClass( const char *fname );
  126. ~StatDumpClass();
  127. void dumpStats( Bool brief = FALSE, Bool flagSpikes = FALSE );
  128. protected:
  129. FILE *m_fp;
  130. };
  131. //=============================================================================
  132. //Open the file once at the beginning of the game -- everything appends to it.
  133. //=============================================================================
  134. StatDumpClass::StatDumpClass( const char *fname )
  135. {
  136. char buffer[ _MAX_PATH ];
  137. GetModuleFileName( NULL, buffer, sizeof( buffer ) );
  138. char *pEnd = buffer + strlen( buffer );
  139. while( pEnd != buffer )
  140. {
  141. if( *pEnd == '\\' )
  142. {
  143. *pEnd = 0;
  144. break;
  145. }
  146. pEnd--;
  147. }
  148. AsciiString fullPath;
  149. fullPath.format( "%s\\%s", buffer, fname );
  150. m_fp = fopen( fullPath.str(), "wt" );
  151. }
  152. //=============================================================================
  153. //Close the file at the end of the application
  154. //=============================================================================
  155. StatDumpClass::~StatDumpClass()
  156. {
  157. if( m_fp )
  158. {
  159. fclose( m_fp );
  160. }
  161. }
  162. static const char *getCurrentTimeString(void)
  163. {
  164. time_t aclock;
  165. time(&aclock);
  166. struct tm *newtime = localtime(&aclock);
  167. return asctime(newtime);
  168. }
  169. //=============================================================================
  170. //Dump the stats
  171. //=============================================================================
  172. static Bool s_notFirstDump = FALSE;
  173. void StatDumpClass::dumpStats( Bool brief, Bool flagSpikes )
  174. {
  175. if( !m_fp )
  176. {
  177. return;
  178. }
  179. Bool beBrief = brief & s_notFirstDump;
  180. s_notFirstDump = TRUE;
  181. fprintf( m_fp, "----------------------------------------------------------------\n" );
  182. fprintf( m_fp, "Performance Statistical Dump -- Frame %d\n", TheGameLogic->getFrame() );
  183. if ( ! beBrief )
  184. {
  185. //static char buf[1024];
  186. fprintf( m_fp, "Time:\t%s", getCurrentTimeString() );
  187. fprintf( m_fp, "Map:\t%s\n", TheGlobalData->m_mapName.str());
  188. fprintf( m_fp, "Side:\t%s\n", ThePlayerList->getLocalPlayer()->getSide().str());
  189. fprintf( m_fp, "----------------------------------------------------------------\n" );
  190. }
  191. //FPS
  192. Real fps = TheDisplay->getAverageFPS();
  193. fprintf( m_fp, "Average FPS: %.1f (%.5f msec)\n", fps, 1000.0f / fps );
  194. if ( flagSpikes && fps<20.0f )
  195. fprintf( m_fp, " FPS OUT OF TOLERANCE\n" );
  196. //Rendering stats
  197. fprintf( m_fp, "Draws: %d \nSkins: %d \nSortedPolys: %d \nSkinPolys: %d\n",(Int)Debug_Statistics::Get_Draw_Calls(),
  198. (Int)Debug_Statistics::Get_DX8_Skin_Renders(),
  199. (Int)Debug_Statistics::Get_Sorting_Polygons(), (Int)Debug_Statistics::Get_DX8_Skin_Polygons());
  200. Int onScreenParticleCount = TheParticleSystemManager->getOnScreenParticleCount();
  201. if ( flagSpikes )
  202. {
  203. if ( Debug_Statistics::Get_Draw_Calls()>2000 )
  204. fprintf( m_fp, " DRAWS OUT OF TOLERANCE(2000)\n" );
  205. if ( Debug_Statistics::Get_Sorting_Polygons() > (onScreenParticleCount*2) + 300 )
  206. fprintf( m_fp, " NON-PARTICLE-SORTS OUT OF TOLERANCE(300)\n" );
  207. if ( Debug_Statistics::Get_DX8_Skin_Renders()>100 )
  208. fprintf( m_fp, " SKINS OUT OF TOLERANCE(100)\n" );
  209. }
  210. //Object stats
  211. UnsignedInt objCount = TheGameLogic->getObjectCount();
  212. UnsignedInt objScreenCount = TheGameClient->getRenderedObjectCount();
  213. fprintf( m_fp, "Objects: %d in world (%d onscreen)\n", objCount, objScreenCount );
  214. if ( flagSpikes && objCount > 800 )
  215. fprintf( m_fp, " OBJS OUT OF TOLERANCE(800)\n" );
  216. //AI stats
  217. UnsignedInt numAI, numMoving, numAttacking, numWaitingForPath, overallFailedPathfinds;
  218. TheGameLogic->getAIMetricsStatistics( &numAI, &numMoving, &numAttacking, &numWaitingForPath, &overallFailedPathfinds );
  219. fprintf( m_fp, "\n" );
  220. fprintf( m_fp, "AI Statistics:\n" );
  221. fprintf( m_fp, " Total AI Objects: %d\n", numAI );
  222. fprintf( m_fp, " -moving: %d\n", numMoving );
  223. fprintf( m_fp, " -attacking: %d\n", numAttacking );
  224. fprintf( m_fp, " -waiting for path: %d\n", numWaitingForPath );
  225. fprintf( m_fp, " Total failed pathfinds: %d\n", overallFailedPathfinds );
  226. if ( flagSpikes && overallFailedPathfinds > 0 )
  227. fprintf( m_fp, " FAILEDPATHFINDS OUT OF TOLERANCE(0)\n" );
  228. fprintf( m_fp, "\n" );
  229. // Script stats
  230. Real timeLastFrame, slowScript1, slowScript2;
  231. AsciiString slowScripts = TheScriptEngine->getStats(&timeLastFrame, &slowScript1, &slowScript2);
  232. fprintf( m_fp, "\n" );
  233. fprintf( m_fp, "Script Engine Statistics:\n" );
  234. fprintf( m_fp, " Total time last frame: %.5f msec\n", timeLastFrame*1000 );
  235. fprintf( m_fp, " -Slowest 2 scripts %s\n", slowScripts.str() );
  236. fprintf( m_fp, " -Slowest 2 script times %.5f msec, %.5f msec \n", slowScript1*1000, slowScript2*1000 );
  237. if ( flagSpikes && slowScript1*1000 > 0.2f || slowScript2*1000 > 0.2f )
  238. fprintf( m_fp, " SLOW SCRIPT OUT OF TOLERANCE(0.2)\n" );
  239. fprintf( m_fp, "\n" );
  240. //PartitionMgr stats
  241. double gcoTimeThisFrameTotal, gcoTimeThisFrameAvg;
  242. ThePartitionManager->getPMStats(gcoTimeThisFrameTotal, gcoTimeThisFrameAvg);
  243. fprintf(m_fp, "Partition Manager Statistics:\n");
  244. fprintf(m_fp, " Total time for object scans this frame is %.5f msec\n", gcoTimeThisFrameTotal);
  245. fprintf(m_fp, " Avg time per object scan this frame is %.5f msec\n", gcoTimeThisFrameAvg);
  246. fprintf( m_fp, "\n" );
  247. // setup texture stats
  248. Debug_Statistics::Record_Texture_Mode(Debug_Statistics::RECORD_TEXTURE_SIMPLE/*RECORD_TEXTURE_NONE*/);
  249. fprintf( m_fp, "Video Statistics:\n" );
  250. //Particle system stats
  251. fprintf( m_fp, " Particle Systems: %d\n", TheParticleSystemManager->getParticleSystemCount() );
  252. Int totalParticles = TheParticleSystemManager->getParticleCount();
  253. fprintf( m_fp, " Particles: %d in world (%d onscreen)\n", totalParticles, onScreenParticleCount );
  254. if ( flagSpikes && totalParticles > TheGlobalData->m_maxParticleCount - 10 )
  255. fprintf( m_fp, " PARTICLES OUT OF TOLERANCE(CAP-10)\n" );
  256. if ( flagSpikes && onScreenParticleCount > TheGlobalData->m_maxParticleCount - 10 )
  257. fprintf( m_fp, " ON_SCREEN_PARTICLES OUT OF TOLERANCE(CAP-10)\n" );
  258. // polygons this frame
  259. Int polyPerFrame = Debug_Statistics::Get_DX8_Polygons();
  260. Int polyPerSecond = (Int)(polyPerFrame * fps);
  261. fprintf( m_fp, " Polygons: %d per frame (%d per second)\n", polyPerFrame, polyPerSecond );
  262. // vertices this frame
  263. fprintf( m_fp, " Vertices: %d\n", Debug_Statistics::Get_DX8_Vertices() );
  264. //
  265. // I'm adjusting the texture memory usage counter by subtracting
  266. // out the terrain alpha texture (since it's really == terrain texture).
  267. //
  268. fprintf( m_fp, " Video RAM: %d\n", Debug_Statistics::Get_Record_Texture_Size() - 1376256 );
  269. // terrain stats
  270. fprintf( m_fp, " 3-Way Blends: %d/%d, \n Shoreline Blends: %d/%d\n", TheTerrainRenderObject->getNumExtraBlendTiles(TRUE),TheTerrainRenderObject->getNumExtraBlendTiles(FALSE), TheTerrainRenderObject->getNumShoreLineTiles(TRUE),TheTerrainRenderObject->getNumShoreLineTiles(FALSE));
  271. if ( flagSpikes && TheTerrainRenderObject->getNumExtraBlendTiles(TRUE) > 2000 )
  272. fprintf( m_fp, " 3-WAYS OUT OF TOLERANCE(2000)\n" );
  273. if ( flagSpikes && TheTerrainRenderObject->getNumShoreLineTiles(TRUE) > 2000 )
  274. fprintf( m_fp, " SHORELINES OUT OF TOLERANCE(2000)\n" );
  275. fprintf( m_fp, "\n" );
  276. #if defined(_DEBUG) || defined(_INTERNAL)
  277. if ( ! beBrief )
  278. {
  279. TheAudio->audioDebugDisplay( NULL, NULL, m_fp );
  280. fprintf( m_fp, "\n" );
  281. }
  282. #endif
  283. #ifdef MEMORYPOOL_DEBUG
  284. //Report memory usage.
  285. TheMemoryPoolFactory->debugMemoryReport( REPORT_FACTORYINFO | REPORT_POOLINFO, 0, 0, m_fp );
  286. #else
  287. fprintf( m_fp, "Memory Report -- unavailable \n(build doesn't have MEMORYPOOL_DEBUG defined)\n" );
  288. #endif
  289. fprintf( m_fp, "\n" );
  290. fprintf( m_fp, "%s", TheSubsystemList->dumpTimesForAll().str());
  291. if ( ! beBrief )
  292. {
  293. fprintf( m_fp, "----------------------------------------------------------------\n" );
  294. fprintf( m_fp, "END -- Frame %d\n", TheGameLogic->getFrame() );
  295. fprintf( m_fp, "----------------------------------------------------------------\n" );
  296. }
  297. fprintf( m_fp, "\n\n" );
  298. fflush(m_fp);
  299. }
  300. StatDumpClass TheStatDump("StatisticsDump.txt");
  301. #endif //DUMP_PERF_STATS
  302. //*****************************************************************************************
  303. //**** End Statistical Dump ***************************************************************
  304. //*****************************************************************************************
  305. //*****************************************************************************************
  306. ///////////////////////////////////////////////////////////////////////////////
  307. // DEFINITIONS ////////////////////////////////////////////////////////////////
  308. ///////////////////////////////////////////////////////////////////////////////
  309. //=============================================================================
  310. RTS3DScene *W3DDisplay::m_3DScene = NULL;
  311. RTS2DScene *W3DDisplay::m_2DScene = NULL;
  312. RTS3DInterfaceScene *W3DDisplay::m_3DInterfaceScene = NULL;
  313. W3DAssetManager *W3DDisplay::m_assetManager = NULL;
  314. //=============================================================================
  315. // note, can't use the ones from PerfTimer.h 'cuz they are currently
  316. // only valid when "-vtune" is used... (srj)
  317. inline Int64 getPerformanceCounter()
  318. {
  319. Int64 tmp;
  320. QueryPerformanceCounter((LARGE_INTEGER*)&tmp);
  321. return tmp;
  322. }
  323. inline Int64 getPerformanceCounterFrequency()
  324. {
  325. Int64 tmp;
  326. QueryPerformanceFrequency((LARGE_INTEGER*)&tmp);
  327. return tmp;
  328. }
  329. // W3DDisplay::W3DDisplay =====================================================
  330. /** */
  331. //=============================================================================
  332. W3DDisplay::W3DDisplay()
  333. {
  334. Int i;
  335. m_initialized = false;
  336. m_assetManager = NULL;
  337. m_3DScene = NULL;
  338. m_2DScene = NULL;
  339. m_3DInterfaceScene = NULL;
  340. m_averageFPS = TheGlobalData->m_framesPerSecondLimit;
  341. #if defined(_DEBUG) || defined(_INTERNAL)
  342. m_timerAtCumuFPSStart = 0;
  343. #endif
  344. for (i=0; i<LightEnvironmentClass::MAX_LIGHTS; i++)
  345. m_myLight[i] = NULL;
  346. m_2DRender = NULL;
  347. m_isClippedEnabled = FALSE;
  348. m_clipRegion.lo.x = 0;
  349. m_clipRegion.lo.y = 0;
  350. m_clipRegion.hi.x = 0;
  351. m_clipRegion.hi.y = 0;
  352. for (i = 0; i < DisplayStringCount; i++)
  353. m_displayStrings[i] = NULL;
  354. } // end W3DDisplay
  355. // W3DDisplay::~W3DDisplay ====================================================
  356. /** */
  357. //=============================================================================
  358. W3DDisplay::~W3DDisplay()
  359. {
  360. // get rid of the debug display
  361. delete m_debugDisplay;
  362. // delete the display strings
  363. for (int i = 0; i < DisplayStringCount; i++)
  364. TheDisplayStringManager->freeDisplayString(m_displayStrings[i]);
  365. // delete 2D renderer
  366. if( m_2DRender )
  367. {
  368. m_2DRender->Reset();
  369. delete m_2DRender;
  370. m_2DRender = NULL;
  371. } // end if
  372. //
  373. // delete all our views now since they are W3D views and we need to
  374. // free them BEFORE we shutdown W3D
  375. //
  376. Display::deleteViews();
  377. REF_PTR_RELEASE( m_3DScene );
  378. REF_PTR_RELEASE( m_2DScene );
  379. REF_PTR_RELEASE( m_3DInterfaceScene );
  380. for (Int j=0; j<LightEnvironmentClass::MAX_LIGHTS; j++)
  381. REF_PTR_RELEASE( m_myLight[j] );
  382. PredictiveLODOptimizerClass::Free();
  383. // shutdown
  384. Debug_Statistics::Shutdown_Statistics();
  385. W3DShaderManager::shutdown();
  386. m_assetManager->Free_Assets();
  387. delete m_assetManager;
  388. WW3D::Shutdown();
  389. WWMath::Shutdown();
  390. DX8WebBrowser::Shutdown();
  391. delete TheW3DFileSystem;
  392. TheW3DFileSystem = NULL;
  393. } // end ~W3DDisplay
  394. #define MIN_DISPLAY_RESOLUTION_X 800
  395. #define MIN_DISPLAY_RESOLUTOIN_Y 600
  396. Bool IS_FOUR_BY_THREE_ASPECT( Real x, Real y )
  397. {
  398. if ( y == 0 )
  399. return FALSE;
  400. Real aspectRatio = fabs( x / y );
  401. return (( aspectRatio > 1.332f) && ( aspectRatio < 1.334f));
  402. }
  403. /*Return number of screen modes supported by the current device*/
  404. Int W3DDisplay::getDisplayModeCount(void)
  405. {
  406. const RenderDeviceDescClass &devDesc=WW3D::Get_Render_Device_Desc(0);
  407. const DynamicVectorClass <ResolutionDescClass> &resolutions=devDesc.Enumerate_Resolutions();
  408. Int numResolutions=0;
  409. /* Bool needStencil=false;
  410. Bool needDestinationAlpha=false;
  411. Int minBitDepth=16;
  412. //Walk through all resolutions and determine which ones are compatible with other settings
  413. //chosen by user. For example, 32-bit may be required for shadows, occlusion, soft water edge, etc.
  414. if (TheGlobalData->m_useShadowVolumes || (TheGlobalData->m_enableBehindBuildingMarkers && TheGameLogic->getShowBehindBuildingMarkers()))
  415. needStencil=true;
  416. if (TheGlobalData->m_showSoftWaterEdge)
  417. { minBitDepth=32;
  418. }
  419. */
  420. for (int res = 0; res < resolutions.Count (); res ++)
  421. {
  422. // Is this the resolution we are looking for?
  423. if (resolutions[res].BitDepth >= 24 && resolutions[res].Width >= MIN_DISPLAY_RESOLUTION_X
  424. && IS_FOUR_BY_THREE_ASPECT( (Real)resolutions[res].Width, (Real)resolutions[res].Height ) ) //only accept 4:3 aspect ratio modes.
  425. {
  426. numResolutions++;
  427. }
  428. }
  429. return numResolutions;
  430. }
  431. void W3DDisplay::getDisplayModeDescription(Int modeIndex, Int *xres, Int *yres, Int *bitDepth)
  432. {
  433. Int numResolutions=0;
  434. const RenderDeviceDescClass &devDesc=WW3D::Get_Render_Device_Desc(0);
  435. const DynamicVectorClass <ResolutionDescClass> &resolutions=devDesc.Enumerate_Resolutions();
  436. for (int res = 0; res < resolutions.Count (); res ++)
  437. {
  438. // Is this the resolution we are looking for?
  439. if ( resolutions[res].BitDepth >= 24 && resolutions[res].Width >= MIN_DISPLAY_RESOLUTION_X
  440. && IS_FOUR_BY_THREE_ASPECT( (Real)resolutions[res].Width, (Real)resolutions[res].Height ) ) //only accept 4:3 aspect ratio modes.
  441. {
  442. if (numResolutions == modeIndex)
  443. { //found the mode
  444. *xres=resolutions[res].Width;
  445. *yres=resolutions[res].Height;
  446. *bitDepth=resolutions[res].BitDepth;
  447. return;
  448. }
  449. numResolutions++;
  450. }
  451. }
  452. }
  453. void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate)
  454. {
  455. if (m_windowed)
  456. return; //we don't allow gamma to change in window because it would affect desktop.
  457. DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false);
  458. }
  459. /*Giant hack in order to keep the game from getting stuck when alt-tabbing*/
  460. void Reset_D3D_Device(bool active)
  461. {
  462. if (TheDisplay && WW3D::Is_Initted() && !TheDisplay->getWindowed())
  463. {
  464. if (active)
  465. {
  466. //switch back to desired mode when user alt-tabs back into game
  467. WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true);
  468. OSVERSIONINFO osvi;
  469. osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
  470. if (GetVersionEx(&osvi))
  471. { //check if we're running Win9x variant since they have buggy alt-tab that requires
  472. //reloading all textures.
  473. if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  474. { //only do this on Win9x boxes because it makes alt-tab very slow.
  475. WW3D::_Invalidate_Textures();
  476. }
  477. }
  478. }
  479. else
  480. {
  481. //switch to windowed mode whenever the user alt-tabs out of game. Don't restore assets after reset since we'll do it when returning.
  482. WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true, false);
  483. }
  484. }
  485. }
  486. /** Set resolution of display */
  487. //=============================================================================
  488. Bool W3DDisplay::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed )
  489. {
  490. if (WW3D_ERROR_OK == WW3D::Set_Device_Resolution(xres,yres,bitdepth,windowed,true))
  491. {
  492. Render2DClass::Set_Screen_Resolution(RectClass(0, 0, xres, yres));
  493. Display::setDisplayMode(xres, yres, bitdepth, windowed);
  494. return TRUE;
  495. }
  496. //set back to the original mode.
  497. WW3D::Set_Device_Resolution(getWidth(),getHeight(),getBitDepth(),getWindowed(), true);
  498. Render2DClass::Set_Screen_Resolution(RectClass(0, 0, getWidth(),getHeight()));
  499. Display::setDisplayMode(getWidth(),getHeight(),getBitDepth(), getWindowed());
  500. return FALSE; //did not change to a new mode.
  501. }
  502. /** Set width of display */
  503. //=============================================================================
  504. void W3DDisplay::setWidth( UnsignedInt width )
  505. {
  506. // extending functionality
  507. Display::setWidth( width );
  508. // our 2D renderer will use mapping coords to make (0,0) the upper left
  509. // of the screen with (width,height) at the lower right
  510. m_2DRender->Set_Coordinate_Range( RectClass( 0, 0, getWidth(), getHeight() ) );
  511. } // end set width
  512. // W3DDisplay::setHeight ======================================================
  513. /** Set height of display */
  514. //=============================================================================
  515. void W3DDisplay::setHeight( UnsignedInt height )
  516. {
  517. // extending functionality
  518. Display::setHeight( height );
  519. // our 2D renderer will use mapping coords to make (0,0) the upper left
  520. // of the screen with (width,height) at the lower right
  521. m_2DRender->Set_Coordinate_Range( RectClass( 0, 0, getWidth(), getHeight() ) );
  522. } // end set height
  523. // W3DDisplay::initAssets =====================================================
  524. /** */
  525. //=============================================================================
  526. void W3DDisplay::initAssets( void )
  527. {
  528. } // end initAssets
  529. // W3DDisplay::init3DScene ====================================================
  530. /** */
  531. //=============================================================================
  532. void W3DDisplay::init3DScene( void )
  533. {
  534. } // end init3DScene
  535. // W3DDisplay::init2DScene ====================================================
  536. /** This is the 2D scene, you can use it to draw on a 2D plane over the
  537. * 3D background */
  538. //=============================================================================
  539. void W3DDisplay::init2DScene( void )
  540. {
  541. } // end init2DScene
  542. // W3DDisplay::init ===========================================================
  543. /** Initialize or re-initialize the W3D display system. Here we need to
  544. * create our window, and get our 3D hardware setup and online */
  545. //=============================================================================
  546. void W3DDisplay::init( void )
  547. {
  548. //
  549. // call our base class init, this method should be able to handle re-entry
  550. // with its own logic
  551. //
  552. Display::init();
  553. // handle re-entry for ourselves
  554. if( m_initialized )
  555. {
  556. /// @todo W3DDisplay needs RE-init logic!
  557. return;
  558. } // end if
  559. // Override the W3D File system
  560. TheW3DFileSystem = NEW W3DFileSystem;
  561. // init the Westwood math library
  562. WWMath::Init();
  563. // create our 3D interface scene
  564. m_3DInterfaceScene = NEW_REF( RTS3DInterfaceScene, () );
  565. m_3DInterfaceScene->Set_Ambient_Light( Vector3( 1, 1, 1 ) );
  566. // create our 2D scene
  567. m_2DScene = NEW_REF( RTS2DScene, () );
  568. m_2DScene->Set_Ambient_Light( Vector3( 1, 1, 1 ) );
  569. // create our 3D scene
  570. m_3DScene =NEW_REF( RTS3DScene, () );
  571. #if defined(_DEBUG) || defined(_INTERNAL)
  572. if( TheGlobalData->m_wireframe )
  573. m_3DScene->Set_Polygon_Mode( SceneClass::LINE );
  574. #endif
  575. //============================================================================
  576. // m_myLight = NEW_REF
  577. //============================================================================
  578. Int lindex;
  579. for (lindex=0; lindex<TheGlobalData->m_numGlobalLights; lindex++)
  580. { m_myLight[lindex] = NEW_REF( LightClass, (LightClass::DIRECTIONAL) );
  581. }
  582. setTimeOfDay( TheGlobalData->m_timeOfDay ); //set each light to correct values for given time
  583. for (lindex=0; lindex<TheGlobalData->m_numGlobalLights; lindex++)
  584. { m_3DScene->setGlobalLight( m_myLight[lindex], lindex );
  585. }
  586. #ifdef SAMPLE_DYNAMIC_LIGHT
  587. theDynamicLight = NEW_REF(W3DDynamicLight, ());
  588. Real red = 1;
  589. Real green = 1;
  590. Real blue = 0;
  591. if(red==0 && blue==0 && green==0) {
  592. red = green = blue = 1;
  593. }
  594. theDynamicLight->Set_Ambient( Vector3( red, green, blue ) );
  595. theDynamicLight->Set_Diffuse( Vector3( red, green, blue) );
  596. theDynamicLight->Set_Position(Vector3(0, 0, 4));
  597. theDynamicLight->Set_Far_Attenuation_Range(1, 8);
  598. // Note: Don't Add_Render_Object dynamic lights.
  599. m_3DScene->addDynamicLight( theDynamicLight );
  600. #endif
  601. // create a new asset manager
  602. m_assetManager = NEW W3DAssetManager;
  603. m_assetManager->Register_Prototype_Loader(&_ParticleEmitterLoader );
  604. m_assetManager->Register_Prototype_Loader(&_AggregateLoader);
  605. m_assetManager->Set_WW3D_Load_On_Demand( true );
  606. if (TheGlobalData->m_incrementalAGPBuf)
  607. {
  608. SortingRendererClass::SetMinVertexBufferSize(1);
  609. }
  610. if (WW3D::Init( ApplicationHWnd ) != WW3D_ERROR_OK)
  611. throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
  612. WW3D::Set_Prelit_Mode( WW3D::PRELIT_MODE_LIGHTMAP_MULTI_PASS );
  613. WW3D::Set_Collision_Box_Display_Mask(0x00); ///<set to 0xff to make collision boxes visible
  614. WW3D::Enable_Static_Sort_Lists(true);
  615. WW3D::Set_Thumbnail_Enabled(false);
  616. WW3D::Set_Screen_UV_Bias( TRUE ); ///< this makes text look good :)
  617. WW3D::Set_Texture_Bitdepth(32);
  618. setWindowed( TheGlobalData->m_windowed );
  619. // create a 2D renderer helper
  620. m_2DRender = NEW Render2DClass;
  621. DEBUG_ASSERTCRASH( m_2DRender, ("Cannot create Render2DClass") );
  622. // set our default width and height and bit depth
  623. /// @todo we should set this according to options read from a file
  624. setWidth( TheGlobalData->m_xResolution );
  625. setHeight( TheGlobalData->m_yResolution );
  626. setBitDepth( W3D_DISPLAY_DEFAULT_BIT_DEPTH );
  627. if( WW3D::Set_Render_Device( 0,
  628. getWidth(),
  629. getHeight(),
  630. getBitDepth(),
  631. getWindowed(),
  632. true ) != WW3D_ERROR_OK )
  633. {
  634. // Getting the device at the default bit depth (32) didn't work, so try
  635. // getting a 16 bit display. (Voodoo 1-3 only supported 16 bit.) jba.
  636. setBitDepth( 16 );
  637. if( WW3D::Set_Render_Device( 0,
  638. getWidth(),
  639. getHeight(),
  640. getBitDepth(),
  641. getWindowed(),
  642. true ) != WW3D_ERROR_OK )
  643. {
  644. WW3D::Shutdown();
  645. WWMath::Shutdown();
  646. throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
  647. DEBUG_ASSERTCRASH( 0, ("Unable to set render device\n") );
  648. return;
  649. }
  650. } // end if
  651. //Check if level was never set and default to setting most suitable for system.
  652. if (TheGameLODManager->getStaticLODLevel() == STATIC_GAME_LOD_UNKNOWN)
  653. TheGameLODManager->setStaticLODLevel(TheGameLODManager->findStaticLODLevel());
  654. else
  655. { //Static LOD level was applied during GameLOD manager init except for texture reduction
  656. //which needs to be applied here.
  657. Int txtReduction=TheWritableGlobalData->m_textureReductionFactor;
  658. if (txtReduction > 0)
  659. { WW3D::Set_Texture_Reduction(txtReduction,32);
  660. //Tell LOD manager that texture reduction was applied.
  661. TheGameLODManager->setCurrentTextureReduction(txtReduction);
  662. }
  663. }
  664. if (TheGlobalData->m_displayGamma != 1.0f)
  665. setGamma(TheGlobalData->m_displayGamma,0.0f,1.0f,FALSE);
  666. initAssets();
  667. init2DScene();
  668. init3DScene();
  669. W3DShaderManager::init();
  670. // Create and initialize the debug display
  671. m_nativeDebugDisplay = NEW W3DDebugDisplay();
  672. m_debugDisplay = m_nativeDebugDisplay;
  673. if ( m_nativeDebugDisplay )
  674. {
  675. m_nativeDebugDisplay->init();
  676. GameFont *font;
  677. if (TheGlobalLanguageData && TheGlobalLanguageData->m_nativeDebugDisplay.name.isNotEmpty())
  678. {
  679. font=TheFontLibrary->getFont(
  680. TheGlobalLanguageData->m_nativeDebugDisplay.name,
  681. TheGlobalLanguageData->m_nativeDebugDisplay.size,
  682. TheGlobalLanguageData->m_nativeDebugDisplay.bold);
  683. }
  684. else
  685. font=TheFontLibrary->getFont( AsciiString("FixedSys"), 8, FALSE );
  686. m_nativeDebugDisplay->setFont( font );
  687. m_nativeDebugDisplay->setFontHeight( 13 );
  688. m_nativeDebugDisplay->setFontWidth( 9 );
  689. }
  690. DX8WebBrowser::Initialize();
  691. // we're now online
  692. m_initialized = true;
  693. if( TheGlobalData->m_displayDebug )
  694. {
  695. m_debugDisplayCallback = StatDebugDisplay;
  696. }
  697. } // end init
  698. // W3DDisplay::reset ===========================================================
  699. /** Reset the W3D display system. Here we need to
  700. * remove the objects from the previous map. */
  701. //=============================================================================
  702. void W3DDisplay::reset( void )
  703. {
  704. Display::reset();
  705. // Remove all render objects.
  706. SceneIterator *sceneIter = m_3DScene->Create_Iterator();
  707. sceneIter->First();
  708. while(!sceneIter->Is_Done()) {
  709. RenderObjClass * robj = sceneIter->Current_Item();
  710. robj->Add_Ref();
  711. m_3DScene->Remove_Render_Object(robj);
  712. robj->Release_Ref();
  713. sceneIter->Next();
  714. }
  715. m_3DScene->Destroy_Iterator(sceneIter);
  716. m_isClippedEnabled = FALSE;
  717. // release any unused assets from W3D
  718. /// @todo really need that "scene abstraction", having this stuff in the display is icky
  719. m_assetManager->Release_Unused_Assets();
  720. if (TheWritableGlobalData)
  721. TheWritableGlobalData->m_drawSkyBox =0;
  722. }
  723. const UnsignedInt START_CUMU_FRAME = LOGICFRAMES_PER_SECOND / 2; // skip first half-sec
  724. /** Update a moving average of the last 30 fps measurements. Also try to filter out temporary spikes.
  725. This code is designed to be used by the GameLOD sytems to determine the correct dynamic LOD setting.
  726. */
  727. void W3DDisplay::updateAverageFPS(void)
  728. {
  729. const Real MaximumFrameTimeCutoff = 0.5f; //largest frame interval (seconds) we accept before ignoring it as a momentary "spike"
  730. const Int FPS_HISTORY_SIZE = 30; //keep track of the last 30 frames
  731. static Int64 lastUpdateTime64 = 0;
  732. static Int historyOffset = 0;
  733. static Int numSamples = 0;
  734. static double fpsHistory[FPS_HISTORY_SIZE];
  735. Int64 freq64 = getPerformanceCounterFrequency();
  736. Int64 time64 = getPerformanceCounter();
  737. #if defined(_DEBUG) || defined(_INTERNAL)
  738. if (TheGameLogic->getFrame() == START_CUMU_FRAME)
  739. {
  740. m_timerAtCumuFPSStart = time64;
  741. }
  742. #endif
  743. Int64 timeDiff = time64 - lastUpdateTime64;
  744. // convert elapsed time to seconds
  745. double elapsedSeconds = (double)timeDiff/(double)(freq64);
  746. if (elapsedSeconds <= MaximumFrameTimeCutoff) //make sure it's not a spike
  747. {
  748. // append new sameple to fps history.
  749. if (historyOffset >= FPS_HISTORY_SIZE)
  750. historyOffset = 0;
  751. double currentFPS = 1.0/elapsedSeconds;
  752. fpsHistory[historyOffset++] = currentFPS;
  753. numSamples++;
  754. if (numSamples > FPS_HISTORY_SIZE)
  755. numSamples = FPS_HISTORY_SIZE;
  756. }
  757. if (numSamples)
  758. {
  759. // determine average frame rate over our past history.
  760. Real average=0;
  761. for (Int i=0,j=historyOffset-1; i<numSamples; i++,j--)
  762. {
  763. if (j < 0)
  764. j=FPS_HISTORY_SIZE-1; // wrap around to front of buffer
  765. average += fpsHistory[j];
  766. }
  767. m_averageFPS = average / (Real)numSamples;
  768. }
  769. lastUpdateTime64 = time64;
  770. }
  771. #if defined(_DEBUG) || defined(_INTERNAL) //debug hack to view object under mouse stats
  772. ICoord2D TheMousePos;
  773. #endif
  774. // W3DDisplay::gatherDebugStats ===================================================
  775. /** Compute and display debug stats on screen */
  776. //=============================================================================
  777. void W3DDisplay::gatherDebugStats( void )
  778. {
  779. static UnsignedInt s_framesRenderedSinceLastUpdate = 0;
  780. static Int64 s_lastUpdateTime64 = 0;
  781. static double s_timeSinceLastUpdateInSecs = 0.0;
  782. static Int s_drawCallsSinceLastUpdate = 0;
  783. static Int s_sortedPolysSinceLastUpdate = 0;
  784. // allocate the display strings if needed
  785. if( m_displayStrings[0] == NULL )
  786. {
  787. GameFont *font;
  788. if (TheGlobalLanguageData && TheGlobalLanguageData->m_nativeDebugDisplay.name.isNotEmpty())
  789. {
  790. font=TheFontLibrary->getFont(
  791. TheGlobalLanguageData->m_nativeDebugDisplay.name,
  792. TheGlobalLanguageData->m_nativeDebugDisplay.size,
  793. TheGlobalLanguageData->m_nativeDebugDisplay.bold);
  794. }
  795. else
  796. font = TheFontLibrary->getFont( AsciiString("FixedSys"), 8, FALSE );
  797. for (int i = 0; i < DisplayStringCount; i++)
  798. {
  799. if (m_displayStrings[i] == NULL)
  800. {
  801. m_displayStrings[i] = TheDisplayStringManager->newDisplayString();
  802. DEBUG_ASSERTCRASH( m_displayStrings[i], ("Failed to create DisplayString") );
  803. m_displayStrings[i]->setFont( font );
  804. }
  805. }
  806. } // end if
  807. if (m_benchmarkDisplayString == NULL)
  808. {
  809. GameFont *thisFont = TheFontLibrary->getFont( AsciiString("FixedSys"), 8, FALSE );
  810. m_benchmarkDisplayString = TheDisplayStringManager->newDisplayString();
  811. DEBUG_ASSERTCRASH( m_benchmarkDisplayString, ("Failed to create DisplayString") );
  812. m_benchmarkDisplayString->setFont( thisFont );
  813. }
  814. ++s_framesRenderedSinceLastUpdate;
  815. s_drawCallsSinceLastUpdate += Debug_Statistics::Get_Draw_Calls();
  816. s_sortedPolysSinceLastUpdate += Debug_Statistics::Get_Sorting_Polygons();
  817. Int64 freq64 = getPerformanceCounterFrequency();
  818. Int64 time64 = getPerformanceCounter();
  819. s_timeSinceLastUpdateInSecs = ((double)(time64 - s_lastUpdateTime64) / (double)(freq64));
  820. #ifdef EXTENDED_STATS
  821. static FILE *pListFile = NULL;
  822. static Int64 lastFrameTime=0;
  823. static samples = 0;
  824. if (pListFile == NULL) {
  825. pListFile = fopen("FrameRateLog.txt", "w");
  826. }
  827. samples++;
  828. if (pListFile && lastFrameTime && samples<100) {
  829. float timeSinceLastFrame = (float)((double)(time64-lastFrameTime) / (double)(freq64));
  830. fprintf(pListFile, "%d ", (int)(1/timeSinceLastFrame));
  831. }
  832. lastFrameTime = time64;
  833. #endif
  834. // we update stats on a delay
  835. const Real UPDATE_RATE_SECS = 2.0;
  836. if( s_timeSinceLastUpdateInSecs >= UPDATE_RATE_SECS || TheGlobalData->m_constantDebugUpdate )
  837. {
  838. UnicodeString unibuffer, unibuffer2;
  839. UnicodeString fpsString;
  840. // setup texture stats
  841. Debug_Statistics::Record_Texture_Mode(Debug_Statistics::RECORD_TEXTURE_SIMPLE/*RECORD_TEXTURE_NONE*/);
  842. // frames per second
  843. double fps = (Real)s_framesRenderedSinceLastUpdate / s_timeSinceLastUpdateInSecs;
  844. double drawsPerFrame = Debug_Statistics::Get_Draw_Calls(); //(Real)s_drawCallsSinceLastUpdate / (Real)s_framesRenderedSinceLastUpdate;
  845. double sortPolysPerFrame = Debug_Statistics::Get_Sorting_Polygons(); //(Real)s_sortedPolysSinceLastUpdate / (Real)s_framesRenderedSinceLastUpdate;
  846. double skinDrawsPerFrame = Debug_Statistics::Get_DX8_Skin_Renders();
  847. if (fps<0.1) fps = 0.1;
  848. double ms = 1000.0f/fps;
  849. #if defined(_DEBUG) || defined(_INTERNAL)
  850. double cumuTime = ((double)(time64 - m_timerAtCumuFPSStart) / (double)(freq64));
  851. if (cumuTime < 0.0) cumuTime = 0.0;
  852. Int numFrames = (Int)TheGameLogic->getFrame() - (Int)START_CUMU_FRAME;
  853. double cumuFPS = (numFrames > 0 && cumuTime > 0.0) ? (numFrames / cumuTime) : 0.0;
  854. double skinPolysPerFrame = Debug_Statistics::Get_DX8_Skin_Polygons();
  855. Int LOD = TheGlobalData->m_terrainLOD;
  856. //unibuffer.format( L"FPS: %.2f, %.2fms mapLOD=%d [cumu FPS=%.2f] draws: %.2f sort: %.2f", fps, ms, LOD, cumuFPS, drawsPerFrame,sortPolysPerFrame);
  857. if (TheGlobalData->m_useFpsLimit)
  858. unibuffer.format( L"%.2f/%d FPS, ", fps, TheGameEngine->getFramesPerSecondLimit());
  859. else
  860. unibuffer.format( L"%.2f FPS, ", fps);
  861. unibuffer2.format( L"%.2fms [cumuFPS=%.2f] draws: %d skins: %d sortP: %d skinP: %d LOD %d", ms, cumuFPS, (Int)drawsPerFrame,(Int)skinDrawsPerFrame,(Int)sortPolysPerFrame, (Int)skinPolysPerFrame, LOD);
  862. unibuffer.concat(unibuffer2);
  863. #else
  864. //Int LOD = TheGlobalData->m_terrainLOD;
  865. //unibuffer.format( L"FPS: %.2f, %.2fms mapLOD=%d draws: %.2f sort %.2f", fps, ms, LOD, drawsPerFrame,sortPolysPerFrame);
  866. unibuffer.format( L"FPS: %.2f, %.2fms draws: %.2f skins: %.2f sort %.2f", fps, ms, drawsPerFrame,skinDrawsPerFrame,sortPolysPerFrame);
  867. if (TheGlobalData->m_useFpsLimit)
  868. {
  869. unibuffer2.format(L", FPSLock %d",TheGlobalData->m_framesPerSecondLimit);
  870. unibuffer.concat(unibuffer2);
  871. }
  872. #endif
  873. fpsString.format( L"FPS: %.2f", fps);
  874. m_benchmarkDisplayString->setText( fpsString );
  875. Int polyPerFrame = Debug_Statistics::Get_DX8_Polygons();
  876. #ifdef EXTENDED_STATS
  877. static float gameOverheadMS = 0.0f;
  878. static float consoleMS = 0.0f;
  879. static float threeDOverheadMS = 0.0f;
  880. static float terrainMS = 0.0f;
  881. static float objectMS = 0.0f;
  882. static float overlapMS = 0.0f;
  883. static int extendedStats = 0;
  884. const int SHOW_STATS_TIME=12; // show extended stats for 5 cycles == 10 seconds.
  885. static enum {disabled, sync, gameOverhead, console, threeDOverhead, terrain, objects, overlap, normal} statMode = disabled;
  886. if (statMode == sync) {
  887. extendedStats = SHOW_STATS_TIME;
  888. statMode = gameOverhead;
  889. } else if (statMode == gameOverhead) {
  890. gameOverheadMS = ms;
  891. statMode = console;
  892. DX8Wrapper::stats.m_disableTerrain = true;
  893. DX8Wrapper::stats.m_disableOverhead = true;
  894. DX8Wrapper::stats.m_disableWater = true;
  895. DX8Wrapper::stats.m_disableObjects = true;
  896. DX8Wrapper::stats.m_disableConsole = false;
  897. DX8Wrapper::stats.m_debugLinesToShow = 1;
  898. } else if (statMode == console) {
  899. consoleMS = ms;
  900. statMode = threeDOverhead;
  901. DX8Wrapper::stats.m_disableTerrain = true;
  902. DX8Wrapper::stats.m_disableOverhead = true;
  903. DX8Wrapper::stats.m_disableWater = true;
  904. DX8Wrapper::stats.m_disableObjects = true;
  905. DX8Wrapper::stats.m_disableConsole = true;
  906. DX8Wrapper::stats.m_debugLinesToShow = 1;
  907. } else if (statMode == threeDOverhead) {
  908. threeDOverheadMS = ms;
  909. statMode = terrain;
  910. DX8Wrapper::stats.m_disableTerrain = false;
  911. DX8Wrapper::stats.m_disableOverhead = true;
  912. DX8Wrapper::stats.m_disableWater = true;
  913. DX8Wrapper::stats.m_disableObjects = true;
  914. DX8Wrapper::stats.m_disableConsole = true;
  915. DX8Wrapper::stats.m_debugLinesToShow = 1;
  916. } else if (statMode == terrain) {
  917. terrainMS = ms;
  918. statMode = objects;
  919. DX8Wrapper::stats.m_disableOverhead = true;
  920. DX8Wrapper::stats.m_disableTerrain = true;
  921. DX8Wrapper::stats.m_disableWater = true;
  922. DX8Wrapper::stats.m_disableObjects = false;
  923. DX8Wrapper::stats.m_disableConsole = true;
  924. DX8Wrapper::stats.m_debugLinesToShow = 1;
  925. } else if (statMode == objects) {
  926. objectMS = ms;
  927. statMode = overlap;
  928. DX8Wrapper::stats.m_disableOverhead = false;
  929. DX8Wrapper::stats.m_disableTerrain = false;
  930. DX8Wrapper::stats.m_disableWater = false;
  931. DX8Wrapper::stats.m_disableObjects = false;
  932. DX8Wrapper::stats.m_disableConsole = true;
  933. DX8Wrapper::stats.m_sleepTime = (int)(terrainMS);
  934. DX8Wrapper::stats.m_debugLinesToShow = 1;
  935. } else if (statMode == overlap) {
  936. overlapMS = ms;
  937. statMode = normal;
  938. DX8Wrapper::stats.m_disableOverhead = false;
  939. DX8Wrapper::stats.m_disableTerrain = false;
  940. DX8Wrapper::stats.m_disableWater = false;
  941. DX8Wrapper::stats.m_disableObjects = false;
  942. DX8Wrapper::stats.m_disableConsole = true;
  943. DX8Wrapper::stats.m_sleepTime = 0;
  944. DX8Wrapper::stats.m_debugLinesToShow = 1;
  945. } else if (statMode == normal) {
  946. overlapMS = (ms + ((int)terrainMS) - overlapMS );
  947. statMode = disabled;
  948. extendedStats = SHOW_STATS_TIME;
  949. // Done collecting stats. Re-enable stuff
  950. DX8Wrapper::stats.m_disableConsole = false;
  951. DX8Wrapper::stats.m_debugLinesToShow = -1;
  952. } else if (!DX8Wrapper::stats.m_showingStats) {
  953. // start collecting extended info.
  954. DX8Wrapper::stats.m_showingStats = true;
  955. DX8Wrapper::stats.m_disableOverhead = false;
  956. DX8Wrapper::stats.m_disableTerrain = true;
  957. DX8Wrapper::stats.m_disableWater = true;
  958. DX8Wrapper::stats.m_disableObjects = true;
  959. DX8Wrapper::stats.m_disableConsole = true;
  960. DX8Wrapper::stats.m_debugLinesToShow = 1;
  961. statMode = sync;
  962. gameOverheadMS = 0.0f;
  963. threeDOverheadMS = 0.0f;
  964. terrainMS = 0.0f;
  965. objectMS = 0.0f;
  966. }
  967. if (statMode != disabled) {
  968. unibuffer.format(L"FPS: %.2f, %.2fms - Collecting extended stats.", fps, ms);
  969. } else if (extendedStats>0) {
  970. extendedStats--;
  971. unibuffer.format( L"FPS: %.2f, %.2fms - OH %.2fms, Console %.2fms, 3D OH %.2fms, Terrain %.2fms, Obs %.2fms, CPU %.2fms",
  972. fps, ms, gameOverheadMS, consoleMS, threeDOverheadMS, terrainMS, objectMS, overlapMS);
  973. if (extendedStats==SHOW_STATS_TIME-2) {
  974. char bufferA[ 256 ];
  975. sprintf( bufferA, "FPS: %.2f, %.2fms - OH %.2fms, Console %.2fms, 3D OH %.2fms, Terrain %.2fms, Obs %.2fms, CPU %.2fms\n",
  976. fps, ms, gameOverheadMS, consoleMS, threeDOverheadMS, terrainMS, objectMS, overlapMS);
  977. ::OutputDebugString(bufferA);
  978. if (pListFile) {
  979. fprintf(pListFile, "\n%s", bufferA);
  980. }
  981. sprintf( bufferA, "Polygons: per frame %d, per second %d\n", polyPerFrame,
  982. (Int)(polyPerFrame*fps));
  983. ::OutputDebugString(bufferA);
  984. if (pListFile) {
  985. fprintf(pListFile, "%s", bufferA);
  986. fflush(pListFile);
  987. }
  988. }
  989. }
  990. if (pListFile) {
  991. fprintf(pListFile, "\nFPS: %.2f, %.2fms\n", fps, ms);
  992. fflush(pListFile);
  993. }
  994. if (pListFile) {
  995. samples = 0;
  996. if (statMode != disabled) {
  997. fprintf(pListFile, "Stat%d-", statMode);
  998. }
  999. }
  1000. #endif
  1001. // check for debug D3D
  1002. Bool debugD3D=false;
  1003. RegistryClass registry ("Software\\Microsoft\\Direct3d");
  1004. if (registry.Is_Valid ()) {
  1005. if (registry.Get_Int ("LoadDebugRuntime", 0) == 1) {
  1006. debugD3D = true;
  1007. }
  1008. }
  1009. if (debugD3D) {
  1010. unibuffer.concat(L", DEBUG D3D");
  1011. }
  1012. #ifdef _DEBUG
  1013. unibuffer.concat(L", DEBUG app");
  1014. #endif
  1015. m_displayStrings[FPS]->setText( unibuffer );
  1016. // Actual GameLogic frame number
  1017. unibuffer.format(L"Frame: %d", TheGameLogic->getFrame());
  1018. m_displayStrings[Frame]->setText( unibuffer );
  1019. // polygons this frame
  1020. unibuffer.format( L"Polygons: per frame %d, per second %d", polyPerFrame,
  1021. (Int)(polyPerFrame*fps));
  1022. m_displayStrings[Polygons]->setText( unibuffer );
  1023. // vertices this frame
  1024. unibuffer.format( L"Vertices: %d", Debug_Statistics::Get_DX8_Vertices() );
  1025. m_displayStrings[Vertices]->setText( unibuffer );
  1026. //
  1027. // I'm adjusting the texture memory usage counter by subtracting
  1028. // out the terrain alpha texture (since it's really == terrain texture).
  1029. //
  1030. unibuffer.format( L"Video RAM: %d", Debug_Statistics::Get_Record_Texture_Size() - 1376256 );
  1031. m_displayStrings[VideoRam]->setText( unibuffer );
  1032. s_lastUpdateTime64 = time64;
  1033. s_timeSinceLastUpdateInSecs = 0.0f;
  1034. s_framesRenderedSinceLastUpdate = 0;
  1035. s_drawCallsSinceLastUpdate = 0;
  1036. s_sortedPolysSinceLastUpdate = 0;
  1037. // terrain stats
  1038. unibuffer.format( L"3-Way Blends: %d/%d, Shoreline Blends: %d/%d", TheTerrainRenderObject->getNumExtraBlendTiles(TRUE),
  1039. TheTerrainRenderObject->getNumExtraBlendTiles(FALSE),
  1040. TheTerrainRenderObject->getNumShoreLineTiles(TRUE),
  1041. TheTerrainRenderObject->getNumShoreLineTiles(FALSE));
  1042. m_displayStrings[TerrainStats]->setText( unibuffer );
  1043. // misc debug info
  1044. Coord3D camPos;
  1045. TheTacticalView->getPosition(&camPos);
  1046. Real zoom = TheTacticalView->getZoom();
  1047. Real pitch = TheTacticalView->getPitch();
  1048. Real FXPitch = TheTacticalView->getFXPitch();
  1049. Real angle = TheTacticalView->getAngle();
  1050. Real FOV = TheTacticalView->getFieldOfView();
  1051. //Real desiredHeight = TheTacticalView->getHeightAboveGround();
  1052. Real terrainHeight = TheTacticalView->getTerrainHeightUnderCamera();
  1053. Real actualHeightAboveGround = TheTacticalView->getCurrentHeightAboveGround();
  1054. unibuffer.format( L"Camera zoom: %g, pitch: %g/%g, yaw: %g, pos: %g, %g, %g, FOV: %g\n Height above ground: %g Terrain height: %g",
  1055. zoom,
  1056. pitch,
  1057. FXPitch,
  1058. angle,
  1059. camPos.x, camPos.y, camPos.z,
  1060. FOV,
  1061. /*
  1062. zoom,
  1063. pitch * 180.0f / PI,
  1064. FXPitch * 180.0f / PI,
  1065. angle * 180.0f / PI,
  1066. camPos.x, camPos.y, camPos.z,
  1067. FOV * 180.0f / PI,
  1068. */
  1069. actualHeightAboveGround, terrainHeight );
  1070. m_displayStrings[DebugInfo]->setText( unibuffer );
  1071. // display the keyboard modifier and mouse states.
  1072. unibuffer.format( L"States: " );
  1073. if( TheKeyboard->isShift() )
  1074. {
  1075. unibuffer.concat( L"Shift(" );
  1076. if( TheKeyboard->getModifierFlags() & KEY_STATE_LSHIFT )
  1077. {
  1078. unibuffer.concat( L"L" );
  1079. }
  1080. if( TheKeyboard->getModifierFlags() & KEY_STATE_RSHIFT )
  1081. {
  1082. unibuffer.concat( L"R" );
  1083. }
  1084. unibuffer.concat( L") " );
  1085. }
  1086. if( TheKeyboard->isCtrl() )
  1087. {
  1088. unibuffer.concat( L"Ctrl(" );
  1089. if( TheKeyboard->getModifierFlags() & KEY_STATE_LCONTROL )
  1090. {
  1091. unibuffer.concat( L"L" );
  1092. }
  1093. if( TheKeyboard->getModifierFlags() & KEY_STATE_RCONTROL )
  1094. {
  1095. unibuffer.concat( L"R" );
  1096. }
  1097. unibuffer.concat( L") " );
  1098. }
  1099. if( TheKeyboard->isAlt() )
  1100. {
  1101. unibuffer.concat( L"Alt(" );
  1102. if( TheKeyboard->getModifierFlags() & KEY_STATE_LALT )
  1103. {
  1104. unibuffer.concat( L"L" );
  1105. }
  1106. if( TheKeyboard->getModifierFlags() & KEY_STATE_RALT )
  1107. {
  1108. unibuffer.concat( L"R" );
  1109. }
  1110. unibuffer.concat( L") " );
  1111. }
  1112. const MouseIO *mouseStatus = TheMouse->getMouseStatus();
  1113. if( mouseStatus->leftState )
  1114. {
  1115. unibuffer.concat( L"LMB " );
  1116. }
  1117. if( mouseStatus->middleState )
  1118. {
  1119. unibuffer.concat( L"MMB " );
  1120. }
  1121. if( mouseStatus->rightState )
  1122. {
  1123. unibuffer.concat( L"RMB " );
  1124. }
  1125. Object *object = NULL;
  1126. #if defined(_DEBUG) || defined(_INTERNAL) //debug hack to view object under mouse stats
  1127. Drawable *draw = TheTacticalView->pickDrawable(&TheMousePos, FALSE, (PickType)0xffffffff );
  1128. #else
  1129. Drawable *draw = TheGameClient->findDrawableByID( TheInGameUI->getMousedOverDrawableID() );
  1130. #endif
  1131. if( draw )
  1132. object = draw->getObject();
  1133. if( object )
  1134. {
  1135. unibuffer2.format( L"Moused over object: %S (%d) ", object->getTemplate()->getName().str(), object->getID() );
  1136. unibuffer.concat( unibuffer2 );
  1137. }
  1138. else
  1139. {
  1140. unibuffer.concat( L"Moused over object: TERRAIN " );
  1141. }
  1142. m_displayStrings[ KEY_MOUSE_STATES ]->setText( unibuffer );
  1143. //display the x and y mouse coordinates
  1144. const MouseIO *mouseIO = TheMouse->getMouseStatus();
  1145. Coord3D worldPos;
  1146. TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos);
  1147. unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", mouseIO->pos.x, mouseIO->pos.y,
  1148. worldPos.x, worldPos.y, worldPos.z);
  1149. m_displayStrings[MousePosition]->setText( unibuffer );
  1150. //display the number of particles in the world and being displayed on screen
  1151. Int totalParticles = TheParticleSystemManager->getParticleCount();
  1152. Int onScreenParticleCount = TheParticleSystemManager->getOnScreenParticleCount();
  1153. unibuffer.format( L"Particles: %d in world, %d being displayed", totalParticles, onScreenParticleCount );
  1154. m_displayStrings[Particles]->setText( unibuffer );
  1155. //display the number of objects in the world
  1156. UnsignedInt objCount = TheGameLogic->getObjectCount();
  1157. UnsignedInt objScreenCount = TheGameClient->getRenderedObjectCount();
  1158. unibuffer.format(L"Objects: %d in world, %d being displayed", objCount, objScreenCount );
  1159. m_displayStrings[Objects]->setText( unibuffer );
  1160. // Network incoming bandwidth stats
  1161. if (TheNetwork != NULL) {
  1162. unibuffer.format(L"IN: %.2f bytes/sec, %.2f packets/sec",
  1163. TheNetwork->getIncomingBytesPerSecond(), TheNetwork->getIncomingPacketsPerSecond());
  1164. m_displayStrings[NetIncoming]->setText( unibuffer );
  1165. // Network outgoing bandwidth stats
  1166. unibuffer.format(L"OUT: %.2f bytes/sec, %.2f packets/sec",
  1167. TheNetwork->getOutgoingBytesPerSecond(), TheNetwork->getOutgoingPacketsPerSecond());
  1168. m_displayStrings[NetOutgoing]->setText( unibuffer );
  1169. // Network performance stats
  1170. unibuffer.format(L"Run Ahead: %d, Net FPS: %d, Packet arrival cushion: %d",
  1171. TheNetwork->getRunAhead(), TheNetwork->getFrameRate(), TheNetwork->getPacketArrivalCushion());
  1172. m_displayStrings[NetStats]->setText( unibuffer );
  1173. // Client frame rate averages for all players in the game. This only works right for the packet router.
  1174. unibuffer.clear();
  1175. Int numPlayers = TheNetwork->getNumPlayers();
  1176. for (Int i = 0; i < numPlayers; ++i) {
  1177. UnicodeString tempstr;
  1178. tempstr.format(L"%s: %d ", TheNetwork->getPlayerName(i).str(), TheNetwork->getSlotAverageFPS(i));
  1179. unibuffer.concat(tempstr);
  1180. }
  1181. m_displayStrings[NetFPSAverages]->setText( unibuffer );
  1182. } else {
  1183. // unibuffer.format(L"IN: 0.0 bytes/sec, 0.0 packets/sec");
  1184. // m_displayStrings[NetIncoming]->setText( unibuffer );
  1185. // Network outgoing bandwidth stats
  1186. // unibuffer.format(L"OUT: 0.0 bytes/sec, 0.0 packets/sec");
  1187. // m_displayStrings[NetOutgoing]->setText( unibuffer );
  1188. unibuffer.format(L"");
  1189. // unibuffer.format(L"Network not present");
  1190. m_displayStrings[NetOutgoing]->setText(unibuffer);
  1191. m_displayStrings[NetIncoming]->setText(unibuffer);
  1192. m_displayStrings[NetStats]->setText(unibuffer);
  1193. m_displayStrings[NetFPSAverages]->setText( unibuffer );
  1194. }
  1195. // selected object info stats
  1196. unibuffer.format( L"Select Info: '%d' drawables selected", TheInGameUI->getSelectCount() );
  1197. //Sorry, guys. I need a special kluge here to get constantdebug results for angry mob.
  1198. //Do no be cross with me.
  1199. //if there is not exactly one drawable selected it will report on the moused-over drawable
  1200. if (TheInGameUI->getSelectCount() == 1)
  1201. draw = TheInGameUI->getFirstSelectedDrawable();
  1202. if( draw )
  1203. {
  1204. Object *obj = draw->getObject();
  1205. AsciiString objectName;
  1206. objectName.set( "No-Name" );
  1207. if( obj && obj->getName().isEmpty() == FALSE )
  1208. objectName = obj->getName();
  1209. unibuffer.format( L"Select Info: '%S'(%S) at (%.3f,%.3f,%.3f)",
  1210. draw->getTemplate()->getName().str(),
  1211. objectName.str(),
  1212. draw->getPosition()->x,
  1213. draw->getPosition()->y,
  1214. draw->getPosition()->z
  1215. );
  1216. const PhysicsBehavior *physics = obj->getPhysics();
  1217. PhysicsTurningType turnType = physics ? physics->getTurning() : TURN_NONE;
  1218. const DrawableLocoInfo *locoInfo = draw->getLocoInfo();
  1219. if( locoInfo )
  1220. {
  1221. unibuffer2.format( L"\nPhysics Info -- Turn: %d, Pitch(accel): %.3f(%.3f), Roll(accel): %.3f(%.3f)",
  1222. turnType,
  1223. locoInfo->m_accelerationPitch, locoInfo->m_accelerationPitchRate,
  1224. locoInfo->m_accelerationRoll, locoInfo->m_accelerationRollRate );
  1225. unibuffer.concat( unibuffer2 );
  1226. }
  1227. // (gth) compute some stats about the rendering cost of this drawable
  1228. #if defined(_DEBUG) || defined(_INTERNAL)
  1229. RenderCost rcost;
  1230. for (DrawModule** dm = draw->getDrawModules(); *dm; ++dm)
  1231. {
  1232. (*dm)->getRenderCost(rcost);
  1233. }
  1234. if (rcost.getDrawCallCount() > 0)
  1235. {
  1236. unibuffer2.format( L"\ndraw calls: %d(+%d) sort meshes: %d skins: %d bones: %d",rcost.getDrawCallCount(),rcost.getShadowDrawCount(),rcost.getSortedMeshCount(),rcost.getSkinMeshCount(),rcost.getBoneCount());
  1237. unibuffer.concat( unibuffer2 );
  1238. }
  1239. #endif
  1240. unibuffer.concat( L"\nModelStates: " );
  1241. ModelConditionFlags mcFlags = draw->getModelConditionFlags();
  1242. const numEntriesPerLine = 4;
  1243. int lineCount = 0;
  1244. for( int i = 0; i < MODELCONDITION_COUNT; i++ )
  1245. {
  1246. if( mcFlags.test( i ) )
  1247. {
  1248. unibuffer2.format( L"%S ", ModelConditionFlags::getBitNames()[ i ] );
  1249. unibuffer.concat( unibuffer2 );
  1250. lineCount++;
  1251. if( lineCount == numEntriesPerLine )
  1252. {
  1253. lineCount = 0;
  1254. unibuffer.concat( L"\n" );
  1255. }
  1256. }
  1257. }
  1258. //Render ALL modelcondition statii
  1259. } // end if
  1260. m_displayStrings[ SelectedInfo ]->setText( unibuffer );
  1261. }
  1262. }
  1263. // W3DDisplay::drawDebugStats =================================================
  1264. /** Draw debug statistics */
  1265. //=============================================================================
  1266. void W3DDisplay::drawDebugStats( void )
  1267. {
  1268. Int x = 3;
  1269. Int y = 3;
  1270. Color textColor = GameMakeColor( 255, 255, 255, 255 );
  1271. Color dropColor = GameMakeColor( 0, 0, 0, 255 );
  1272. int linesOfStrings = DisplayStringCount;
  1273. #ifdef EXTENDED_STATS
  1274. if (DX8Wrapper::stats.m_debugLinesToShow > -1)
  1275. {
  1276. linesOfStrings = DX8Wrapper::stats.m_debugLinesToShow;
  1277. }
  1278. #endif
  1279. Int w, h;
  1280. for (int i = 0; i < linesOfStrings; i++)
  1281. {
  1282. m_displayStrings[i]->draw( x, y, textColor, dropColor );
  1283. m_displayStrings[i]->getSize(&w, &h);
  1284. y += h;
  1285. }
  1286. } // end drawDebugStats
  1287. // W3DDisplay::drawFPSStats =================================================
  1288. /** Draw the FPS on the screen */
  1289. //=============================================================================
  1290. void W3DDisplay::drawFPSStats( void )
  1291. {
  1292. Int x = 3;
  1293. Int y = 20;
  1294. Color textColor = GameMakeColor( 255, 255, 255, 255 );
  1295. Color dropColor = GameMakeColor( 0, 0, 0, 255 );
  1296. int linesOfStrings = 1;
  1297. for (int i = 0; i < linesOfStrings; i++)
  1298. {
  1299. m_benchmarkDisplayString->draw( x, y, textColor, dropColor );
  1300. }
  1301. }
  1302. //=============================================================================
  1303. void StatDebugDisplay( DebugDisplayInterface *, void *, FILE *fp )
  1304. {
  1305. DEBUG_CRASH(("This should never be called directly, but is just a placeholder for drawDebugStats()"));
  1306. }
  1307. // W3DDisplay::drawCurrentDebugDisplay =================================================
  1308. /** Draw current debug display */
  1309. //=============================================================================
  1310. void W3DDisplay::drawCurrentDebugDisplay( void )
  1311. {
  1312. if (m_debugDisplayCallback == StatDebugDisplay)
  1313. {
  1314. drawDebugStats();
  1315. }
  1316. else
  1317. {
  1318. if ( m_debugDisplay && m_debugDisplayCallback )
  1319. {
  1320. m_debugDisplay->reset();
  1321. m_debugDisplayCallback( m_debugDisplay, m_debugDisplayUserData );
  1322. }
  1323. }
  1324. } // end drawCurrentDebugDisplay
  1325. // W3DDisplay::calculateTerrainLOD =================================================
  1326. /** Calculates an adequately speedy terrain Level Of Detail. */
  1327. //=============================================================================
  1328. void W3DDisplay::calculateTerrainLOD( void )
  1329. {
  1330. const Int NUM_SAMPLES=20;
  1331. const Int NUM_TO_DISCARD=5;
  1332. Int64 freq64 = getPerformanceCounterFrequency();
  1333. char buf[_MAX_PATH];
  1334. float frameTime = 0;
  1335. float maxTimeLimit = TheGlobalData->m_terrainLODTargetTimeMS/1000.0f;
  1336. TerrainLOD goodLOD = TERRAIN_LOD_MIN;
  1337. TerrainLOD curLOD = TERRAIN_LOD_AUTOMATIC;
  1338. Int count = 0;
  1339. #ifdef _DEBUG
  1340. // just go to TERRAIN_LOD_NO_WATER, mirror off.
  1341. TheWritableGlobalData->m_terrainLOD = TERRAIN_LOD_NO_WATER;
  1342. m_3DScene->drawTerrainOnly(false);
  1343. TheTerrainRenderObject->adjustTerrainLOD(0);
  1344. return;
  1345. #endif
  1346. do {
  1347. Int i;
  1348. float timeForFrame=0;
  1349. frameTime = 0;
  1350. switch(curLOD) {
  1351. default: curLOD = TERRAIN_LOD_DISABLE; break;
  1352. case TERRAIN_LOD_AUTOMATIC: curLOD = TERRAIN_LOD_MAX; break;
  1353. case TERRAIN_LOD_MAX: curLOD = TERRAIN_LOD_NO_WATER; break;
  1354. case TERRAIN_LOD_HALF_CLOUDS: curLOD = TERRAIN_LOD_DISABLE; break;
  1355. case TERRAIN_LOD_NO_WATER: curLOD = TERRAIN_LOD_HALF_CLOUDS; break;
  1356. }
  1357. if (curLOD == TERRAIN_LOD_DISABLE) {
  1358. break;
  1359. }
  1360. TheWritableGlobalData->m_terrainLOD = curLOD;
  1361. m_3DScene->drawTerrainOnly(true);
  1362. TheTerrainRenderObject->adjustTerrainLOD(0);
  1363. for (i=0; i<NUM_SAMPLES; i++) {
  1364. Int64 startTime64 = getPerformanceCounter();
  1365. // start render block
  1366. updateViews();
  1367. if (WW3D::Begin_Render( true, true, Vector3( 0.0f, 0.0f, 0.0f ) ) == WW3D_ERROR_OK)
  1368. { // draw all views of the world
  1369. drawViews();
  1370. // render is all done!
  1371. WW3D::End_Render();
  1372. }
  1373. Int64 time64 = getPerformanceCounter();
  1374. timeForFrame = (float)((double)(time64-startTime64) / (double)(freq64));
  1375. sprintf(buf, "%.2fms ", timeForFrame*1000.0f);
  1376. ::OutputDebugString(buf);
  1377. if (i>=NUM_TO_DISCARD) {
  1378. frameTime += timeForFrame;
  1379. if (i>NUM_TO_DISCARD+1 &&
  1380. (timeForFrame / ((i+1)-NUM_TO_DISCARD)) > 2*maxTimeLimit) {
  1381. i++;
  1382. break;
  1383. }
  1384. }
  1385. }
  1386. frameTime /= ((i)-NUM_TO_DISCARD);
  1387. count++;
  1388. sprintf(buf, "\n LOD %d, time %.2fms\n", curLOD, frameTime*1000.0f);
  1389. ::OutputDebugString(buf);
  1390. if (frameTime<maxTimeLimit && goodLOD<curLOD) {
  1391. goodLOD = curLOD;
  1392. }
  1393. if (frameTime < maxTimeLimit) break;
  1394. } while (count<10);
  1395. TheWritableGlobalData->m_terrainLOD = goodLOD;
  1396. m_3DScene->drawTerrainOnly(false);
  1397. TheTerrainRenderObject->adjustTerrainLOD(0);
  1398. #ifdef _DEBUG
  1399. DEBUG_ASSERTCRASH(count<10, ("calculateTerrainLOD") );
  1400. #endif
  1401. }
  1402. Real W3DDisplay::getAverageFPS()
  1403. {
  1404. return m_averageFPS;
  1405. }
  1406. Int W3DDisplay::getLastFrameDrawCalls()
  1407. {
  1408. return Debug_Statistics::Get_Draw_Calls();
  1409. }
  1410. //DECLARE_PERF_TIMER(BigAssRenderLoop)
  1411. // W3DDisplay::draw ===========================================================
  1412. /** Draw the entire W3D Display */
  1413. //=============================================================================
  1414. //DECLARE_PERF_TIMER(W3DDisplay_draw)
  1415. void W3DDisplay::draw( void )
  1416. {
  1417. //USE_PERF_TIMER(W3DDisplay_draw)
  1418. static UnsignedInt syncTime = 0;
  1419. extern HWND ApplicationHWnd;
  1420. if (ApplicationHWnd && ::IsIconic(ApplicationHWnd)) {
  1421. return;
  1422. }
  1423. updateAverageFPS();
  1424. if (TheGlobalData->m_enableDynamicLOD && TheGameLogic->getShowDynamicLOD())
  1425. {
  1426. DynamicGameLODLevel lod=TheGameLODManager->findDynamicLODLevel(m_averageFPS);
  1427. TheGameLODManager->setDynamicLODLevel(lod);
  1428. }
  1429. else
  1430. { //if dynamic LOD is turned off, force highest LOD
  1431. TheGameLODManager->setDynamicLODLevel(DYNAMIC_GAME_LOD_VERY_HIGH);
  1432. }
  1433. if (TheGlobalData->m_terrainLOD == TERRAIN_LOD_AUTOMATIC && TheTerrainRenderObject)
  1434. {
  1435. calculateTerrainLOD();
  1436. }
  1437. #ifdef EXTENDED_STATS
  1438. AGAIN:
  1439. #endif
  1440. #ifdef DUMP_PERF_STATS
  1441. if( TheGlobalData->m_dumpPerformanceStatistics )
  1442. {
  1443. TheStatDump.dumpStats( FALSE, TRUE );
  1444. TheWritableGlobalData->m_dumpPerformanceStatistics = FALSE;
  1445. }
  1446. //The <= GAME_REPLAY essentially means, GAME_SINGLE_PLAYER || GAME_LAN || GAME_SKIRMISH || GAME_REPLAY
  1447. else if ( TheGlobalData->m_dumpStatsAtInterval && TheGameLogic->getGameMode() <= GAME_REPLAY )
  1448. {
  1449. Int interval = TheGlobalData->m_statsInterval;
  1450. if ( TheGameLogic->getFrame() > 0 && (TheGameLogic->getFrame() % interval) == 0 )
  1451. {
  1452. TheStatDump.dumpStats( TRUE, TRUE );
  1453. TheInGameUI->message( UnicodeString( L"-stats is running, at interval: %d." ), TheGlobalData->m_statsInterval );
  1454. }
  1455. }
  1456. #endif
  1457. // compute debug statistics for display later
  1458. if ( m_debugDisplayCallback == StatDebugDisplay
  1459. #if defined(_DEBUG) || defined(_INTERNAL)
  1460. || TheGlobalData->m_benchmarkTimer > 0
  1461. #endif
  1462. )
  1463. {
  1464. gatherDebugStats();
  1465. }
  1466. #ifdef EXTENDED_STATS
  1467. else
  1468. {
  1469. DX8Wrapper::stats.m_showingStats = false;
  1470. }
  1471. #endif
  1472. #ifdef SAMPLE_DYNAMIC_LIGHT
  1473. Vector3 loc;
  1474. loc = theDynamicLight->Get_Position();
  1475. loc.X += theLightXOffset;
  1476. if(loc.X>128) theLightXOffset = -theLightXOffset;
  1477. if(loc.X<0) theLightXOffset = -theLightXOffset;
  1478. loc.Y += theLightYOffset;
  1479. if(loc.Y>128) theLightYOffset = -theLightYOffset;
  1480. if(loc.Y<0) theLightYOffset = -theLightYOffset;
  1481. theDynamicLight->Set_Position(loc);
  1482. #endif
  1483. /// @todo Make more explicit drawing layers(ground, ground UI, objects, object UI, overlay UI)
  1484. ///@todo: Ask Vegas why the LOD optimizer hangs particle system.
  1485. //
  1486. // Predictive LOD optimizer optimizes the mesh LOD levels to match
  1487. // the given polygon budget
  1488. //
  1489. //PredictiveLODOptimizerClass::Optimize_LODs( 5000 );
  1490. Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
  1491. freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
  1492. freezeTime = freezeTime || TheGameLogic->isGamePaused();
  1493. // hack to let client spin fast in network games but still do effects at the same pace. -MDC
  1494. static UnsignedInt lastFrame = ~0;
  1495. freezeTime = freezeTime || (lastFrame == TheGameClient->getFrame());
  1496. lastFrame = TheGameClient->getFrame();
  1497. /// @todo: I'm assuming the first view is our main 3D view.
  1498. W3DView *primaryW3DView=(W3DView *)getFirstView();
  1499. if (!freezeTime && TheScriptEngine->isTimeFast())
  1500. {
  1501. primaryW3DView->updateCameraMovements(); // Update camera motion effects.
  1502. syncTime += TheW3DFrameLengthInMsec;
  1503. return;
  1504. }
  1505. Debug_Statistics::Begin_Statistics(); //reset all counters (polygons, vertices, etc) before drawing
  1506. //update state of all the terrain tracks (fade, remove, etc.)
  1507. /// @todo: Is there a better place to put per-frame updates like this?
  1508. if(TheGlobalData->m_loadScreenRender != TRUE)
  1509. {
  1510. if (TheTerrainTracksRenderObjClassSystem)
  1511. TheTerrainTracksRenderObjClassSystem->update();
  1512. //Shroud data is needed to render all other views, so handle this first.
  1513. if (TheTerrainRenderObject)
  1514. {
  1515. //update the shroud surface here since it may be needed by reflections
  1516. if (TheTerrainRenderObject->getMap()) //make sure a valid map is loaded into terrain.
  1517. {
  1518. if (TheTerrainRenderObject->getShroud())
  1519. {
  1520. TheTerrainRenderObject->getShroud()->render(primaryW3DView->get3DCamera());
  1521. }
  1522. }
  1523. }
  1524. }
  1525. if (!freezeTime)
  1526. {
  1527. /// @todo Decouple framerate from timestep
  1528. // for now, use constant time steps to avoid animations running independent of framerate
  1529. syncTime += TheW3DFrameLengthInMsec;
  1530. // allow W3D to update its internals
  1531. // WW3D::Sync( GetTickCount() );
  1532. }
  1533. WW3D::Sync( syncTime );
  1534. // Fast & Frozen time limits the time to 33 fps.
  1535. Int minTime = 30;
  1536. static Int prevTime = timeGetTime(), now;
  1537. now=timeGetTime();
  1538. if (TheTacticalView->getTimeMultiplier()>1)
  1539. {
  1540. static Int timeMultiplierCounter = 1;
  1541. timeMultiplierCounter--;
  1542. if (timeMultiplierCounter>1)
  1543. return;
  1544. timeMultiplierCounter = TheTacticalView->getTimeMultiplier();
  1545. // limit the framerate, because while fast time is on, the game logic is running as fast as it can.
  1546. }
  1547. else
  1548. {
  1549. now = timeGetTime();
  1550. prevTime = now - minTime; // do the first frame immediately.
  1551. }
  1552. do {
  1553. {
  1554. if(TheGlobalData->m_loadScreenRender != TRUE)
  1555. {
  1556. // limit the framerate
  1557. while(TheGlobalData->m_useFpsLimit && (now - prevTime) < minTime-1)
  1558. {
  1559. now = timeGetTime();
  1560. }
  1561. prevTime = now;
  1562. }
  1563. }
  1564. // update all views of the world - recomputes data which will affect drawing
  1565. if (DX8Wrapper::_Get_D3D_Device8() && (DX8Wrapper::_Get_D3D_Device8()->TestCooperativeLevel()) == D3D_OK)
  1566. { //Checking if we have the device before updating views because the heightmap crashes otherwise while
  1567. //trying to refresh the visible terrain geometry.
  1568. // if(TheGlobalData->m_loadScreenRender != TRUE)
  1569. updateViews();
  1570. TheParticleSystemManager->update();//LORENZEN AND WILCZYNSKI MOVED THIS FROM ITS NATIVE POSITION, ABOVE
  1571. //FOR THE PURPOSE OF LETTING THE PARTICLE SYSTEM LOOK UP THE RENDER OBJECT"S
  1572. //TRANSFORM MATRIX, WHILE IT IS STILL VALID (HAVING DONE ITS CLIENT TRANSFORMS
  1573. //BUT NOT YET RESETTING TOT HE LOGICAL TRANSFORM)
  1574. //THE RESULT IS THAT PARTICLESYSTEMS LINKED TO BONES IN DRAWABLES.OBJECTS
  1575. //MOVE WITH THE CLIENT TRANSFORMS, NOW.
  1576. //REVOLUTIONARY!
  1577. //-LORENZEN
  1578. if (TheWaterRenderObj && TheGlobalData->m_waterType == 2)
  1579. TheWaterRenderObj->updateRenderTargetTextures(primaryW3DView->get3DCamera()); //do a render into each texture
  1580. //Can't render into textures while rendering to screen so these textures need to be updated
  1581. //before we enter main rendering loop.
  1582. if (TheW3DProjectedShadowManager)
  1583. TheW3DProjectedShadowManager->updateRenderTargetTextures();
  1584. }
  1585. Debug_Statistics::End_Statistics(); //record number of polygons rendered in RenderTargetTextures.
  1586. //Store number of polygons rendered in renderTargetTextures.
  1587. Int numRenderTargetPolygons=Debug_Statistics::Get_DX8_Polygons();
  1588. Int numRenderTargetVertices=Debug_Statistics::Get_DX8_Vertices();
  1589. // start render block
  1590. #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
  1591. if ( (TheGameLogic->getFrame() % 30 == 1) || ( ! ( !TheGameLogic->isGamePaused() && TheGlobalData->m_TiVOFastMode) ) )
  1592. #else
  1593. if ( (TheGameLogic->getFrame() % 30 == 1) || ( ! (!TheGameLogic->isGamePaused() && TheGlobalData->m_TiVOFastMode && TheGameLogic->isInReplayGame())) )
  1594. #endif
  1595. {
  1596. //USE_PERF_TIMER(BigAssRenderLoop)
  1597. static Bool couldRender = true;
  1598. if ((TheGlobalData->m_breakTheMovie == FALSE) && (TheGlobalData->m_disableRender == false) && WW3D::Begin_Render( true, true, Vector3( 0.0f, 0.0f, 0.0f ), TheWaterTransparency->m_minWaterOpacity ) == WW3D_ERROR_OK)
  1599. {
  1600. if(TheGlobalData->m_loadScreenRender == TRUE)
  1601. {
  1602. TheInGameUI->draw();
  1603. if( TheMouse )
  1604. TheMouse->draw(); //keep applying the current cursor style so it remains hidden if needed.
  1605. WW3D::End_Render();
  1606. continue;
  1607. }
  1608. couldRender = true;
  1609. // add the number of verts/polygons drawn before the main scene
  1610. if (numRenderTargetPolygons || numRenderTargetVertices)
  1611. Debug_Statistics::Record_DX8_Polys_And_Vertices(numRenderTargetPolygons,numRenderTargetVertices,ShaderClass::_PresetOpaqueShader);
  1612. // draw all views of the world
  1613. drawViews();
  1614. // draw the user interface
  1615. TheInGameUI->DRAW();
  1616. // end of video example code
  1617. // draw the mouse
  1618. if( TheMouse )
  1619. TheMouse->DRAW();
  1620. if ( m_videoStream && m_videoBuffer )
  1621. {
  1622. drawVideoBuffer( m_videoBuffer, 0, 0, getWidth(), getHeight() );
  1623. }
  1624. if( m_copyrightDisplayString )
  1625. {
  1626. Int x, y, dX, dY;
  1627. m_copyrightDisplayString->getSize(&dX, &dY);
  1628. x = (getWidth() / 2) - (dX /2);
  1629. y = getHeight() - dY - 20 ;
  1630. m_copyrightDisplayString->draw(x, y, GameMakeColor(0,0,0,255), GameMakeColor(0,0,0,0),0,0);
  1631. }
  1632. // render letter box before debug display so debug info isn't hidden
  1633. renderLetterBox(now);
  1634. // display cinematicText over the black
  1635. if( m_cinematicText != AsciiString::TheEmptyString && m_cinematicTextFrames != 0)
  1636. {
  1637. DisplayString *displayString = TheDisplayStringManager->newDisplayString();
  1638. // set word wrap if neccessary
  1639. Int wordWrapWidth = TheDisplay->getWidth() - 20;
  1640. displayString->setWordWrap( wordWrapWidth );
  1641. displayString->setWordWrapCentered( TRUE );
  1642. UnicodeString text;
  1643. text.translate( m_cinematicText );
  1644. displayString->setText( text );
  1645. Color color = GameMakeColor( 255, 255, 255, 255 ); // white
  1646. Color backColor = GameMakeColor( 0, 0, 0, 0 ); // black
  1647. displayString->setFont( m_cinematicFont );
  1648. Int height = TheDisplay->getHeight() * .9;
  1649. Int width;
  1650. if( displayString->getWidth() > TheDisplay->getWidth() )
  1651. width = 20;
  1652. else
  1653. width = ( TheDisplay->getWidth() - displayString->getWidth() ) / 2;
  1654. displayString->draw( width, height, color, backColor );
  1655. m_cinematicTextFrames--;
  1656. }
  1657. if ( m_debugDisplayCallback )
  1658. {
  1659. // draw the current debug display
  1660. drawCurrentDebugDisplay();
  1661. }
  1662. #if defined(_DEBUG) || defined(_INTERNAL)
  1663. if (TheGlobalData->m_benchmarkTimer > 0)
  1664. {
  1665. drawFPSStats();
  1666. }
  1667. #endif
  1668. #if defined(_DEBUG) || defined(_INTERNAL)
  1669. if (TheGlobalData->m_debugShowGraphicalFramerate)
  1670. {
  1671. drawFramerateBar();
  1672. }
  1673. #endif
  1674. #ifdef PERF_TIMERS
  1675. TheGraphDraw->render();
  1676. TheGraphDraw->clear();
  1677. #endif
  1678. // render is all done!
  1679. WW3D::End_Render();
  1680. }
  1681. else
  1682. {
  1683. if (couldRender)
  1684. {
  1685. couldRender = false;
  1686. DEBUG_LOG(("Could not do WW3D::Begin_Render()! Are we ALT-Tabbed out?\n"));
  1687. }
  1688. }
  1689. }
  1690. if (TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript() || TheGameLogic->isGamePaused())
  1691. {
  1692. freezeTime = false; // We're frozen for debug or for pause, and need to continue out of the loop.
  1693. }
  1694. } while (freezeTime && !TheTacticalView->isCameraMovementFinished());
  1695. #ifdef EXTENDED_STATS
  1696. if (DX8Wrapper::stats.m_disableOverhead) {
  1697. goto AGAIN;
  1698. }
  1699. #endif
  1700. } // end draw
  1701. #define LETTER_BOX_FADE_TIME 1000.0f ///1000 ms.
  1702. /** Render letter-box border at top/bottom of display
  1703. */
  1704. void W3DDisplay::renderLetterBox(UnsignedInt currentTime)
  1705. {
  1706. if (m_letterBoxEnabled)
  1707. { if (m_letterBoxFadeLevel != 1.0f)
  1708. {
  1709. m_letterBoxFadeLevel = (currentTime - m_letterBoxFadeStartTime)/LETTER_BOX_FADE_TIME;
  1710. if (m_letterBoxFadeLevel > 1.0f)
  1711. m_letterBoxFadeLevel = 1.0f;
  1712. }
  1713. UnsignedInt lbcolor = (Int)(m_letterBoxFadeLevel * 255.0f) << 24;
  1714. #ifdef SLIDE_LETTERBOX
  1715. Int height = (Int)(getHeight() * 0.12f * m_letterBoxFadeLevel);
  1716. TheTacticalView->setOrigin(0, height);
  1717. #else
  1718. drawFillRect( 0, 0, m_width, (m_height-(9.0f/16.0f * m_width))*0.5f, lbcolor );
  1719. drawFillRect( 0, m_height-(m_height-(9.0f/16.0f * m_width))*0.5f, m_width, m_height, lbcolor );
  1720. #endif
  1721. }
  1722. else
  1723. { //letter box is disabled, but may still be fading out
  1724. if (m_letterBoxFadeLevel != 0.0f)
  1725. {
  1726. m_letterBoxFadeLevel = 1.0f - (currentTime - m_letterBoxFadeStartTime)/LETTER_BOX_FADE_TIME;
  1727. if (m_letterBoxFadeLevel < 0.0f)
  1728. m_letterBoxFadeLevel = 0.0f;
  1729. UnsignedInt lbcolor = (Int)(m_letterBoxFadeLevel * 255.0f) << 24;
  1730. #ifdef SLIDE_LETTERBOX
  1731. Int height = (Int)(getHeight() * 0.12f * m_letterBoxFadeLevel);
  1732. TheTacticalView->setOrigin(0, height);
  1733. #else
  1734. drawFillRect( 0, 0, m_width, (m_height-(9.0f/16.0f * m_width))*0.5f, lbcolor );
  1735. //drawFillRect( 0, m_height-(m_height-(9.0f/16.0f * m_width))*0.5f, m_width, m_height, lbcolor );
  1736. #endif
  1737. }
  1738. else
  1739. { //box has finished fading out
  1740. #ifdef SLIDE_LETTERBOX
  1741. TheTacticalView->setOrigin(0, 0);
  1742. #else
  1743. m_letterBoxEnabled = FALSE;
  1744. #endif
  1745. }
  1746. }
  1747. }
  1748. Bool W3DDisplay::isLetterBoxFading(void)
  1749. {
  1750. if (m_letterBoxEnabled && m_letterBoxFadeLevel != 1.0f)
  1751. return TRUE;
  1752. if (!m_letterBoxEnabled && m_letterBoxFadeLevel != 0.0f)
  1753. return TRUE;
  1754. return FALSE;
  1755. }
  1756. //WST 10/2/2002 added query function. JSC Integrated 5/20/03
  1757. Bool W3DDisplay::isLetterBoxed(void)
  1758. {
  1759. return (m_letterBoxEnabled);
  1760. }
  1761. // W3DDisplay::createLightPulse ===============================================
  1762. /** Create a "light pulse" which is a dynamic light that grows, decays
  1763. * and vanishes over several frames */
  1764. //=============================================================================
  1765. void W3DDisplay::createLightPulse( const Coord3D *pos, const RGBColor *color,
  1766. Real innerRadius, Real attenuationWidth,
  1767. UnsignedInt increaseFrameTime,
  1768. UnsignedInt decayFrameTime//, Bool donut
  1769. )
  1770. {
  1771. if (innerRadius+attenuationWidth<2.0*PATHFIND_CELL_SIZE_F + 1.0f) {
  1772. return; // it basically won't make any visual difference. jba.
  1773. }
  1774. W3DDynamicLight * theDynamicLight = m_3DScene->getADynamicLight();
  1775. // turn it on.
  1776. theDynamicLight->setEnabled(true);
  1777. theDynamicLight->Set_Ambient( Vector3( color->red, color->green, color->blue ) );
  1778. theDynamicLight->Set_Diffuse( Vector3( color->red, color->green, color->blue) );
  1779. theDynamicLight->Set_Position(Vector3(pos->x, pos->y, pos->z));
  1780. theDynamicLight->Set_Far_Attenuation_Range(innerRadius, innerRadius + attenuationWidth);
  1781. theDynamicLight->setFrameFade(increaseFrameTime, decayFrameTime);
  1782. theDynamicLight->setDecayRange();
  1783. theDynamicLight->setDecayColor();
  1784. //theDynamicLight->setDonut(donut);
  1785. // (gth) CNC3 enable far attenuation. C&C3 defaults to disabled. Must enable to match Generals. MW 8-06-03
  1786. theDynamicLight->Set_Flag(LightClass::FAR_ATTENUATION,true);
  1787. }
  1788. void W3DDisplay::toggleLetterBox(void)
  1789. {
  1790. m_letterBoxEnabled = !m_letterBoxEnabled;
  1791. m_letterBoxFadeStartTime = timeGetTime();
  1792. //WST 9/18/2002 This is not a script api to prevent cheat. JSC Integrated 5/20/03
  1793. if( TheTacticalView )
  1794. {
  1795. TheTacticalView->setZoomLimited( !m_letterBoxEnabled );
  1796. }
  1797. }
  1798. void W3DDisplay::enableLetterBox(Bool enable)
  1799. {
  1800. if (enable)
  1801. {
  1802. if (!m_letterBoxEnabled)
  1803. { //letterbox mode not previously enabled
  1804. m_letterBoxEnabled = TRUE;
  1805. m_letterBoxFadeStartTime = timeGetTime();
  1806. //WST 9/18/2002 - This is not a script api to prevent cheat. JSC Integrated 5/20/03
  1807. if( TheTacticalView )
  1808. {
  1809. TheTacticalView->setZoomLimited( 0 );
  1810. }
  1811. }
  1812. }
  1813. else
  1814. {
  1815. if (m_letterBoxEnabled)
  1816. { //letterbox mode no previously disabled
  1817. m_letterBoxEnabled = FALSE;
  1818. m_letterBoxFadeStartTime = timeGetTime();
  1819. //WST 9/18/2002. JSC Integrated 5/20/03
  1820. if( TheTacticalView )
  1821. {
  1822. TheTacticalView->setZoomLimited( 1 );
  1823. }
  1824. }
  1825. }
  1826. }
  1827. // W3DDisplay::setTimeOfDay ===================================================
  1828. /** */
  1829. //=============================================================================
  1830. void W3DDisplay::setTimeOfDay( TimeOfDay tod )
  1831. {
  1832. const GlobalData::TerrainLighting *ol=&TheGlobalData->m_terrainObjectsLighting[tod][0];
  1833. if( m_3DScene )
  1834. {
  1835. m_3DScene->Set_Ambient_Light( Vector3(ol->ambient.red, ol->ambient.green, ol->ambient.blue) );
  1836. }
  1837. for (Int i=0; i<LightEnvironmentClass::MAX_LIGHTS; i++)
  1838. {
  1839. if( m_myLight[i] )
  1840. {
  1841. ol=&TheGlobalData->m_terrainObjectsLighting[tod][i];
  1842. m_myLight[i]->Set_Ambient( Vector3( 0.0f, 0.0f, 0.0f ) );
  1843. m_myLight[i]->Set_Diffuse( Vector3(ol->diffuse.red, ol->diffuse.green, ol->diffuse.blue ) );
  1844. m_myLight[i]->Set_Specular( Vector3(0,0,0) );
  1845. Matrix3D mtx;
  1846. mtx.Set(Vector3(1,0,0), Vector3(0,1,0), Vector3(ol->lightPos.x, ol->lightPos.y, ol->lightPos.z), Vector3(0,0,0));
  1847. m_myLight[i]->Set_Transform(mtx);
  1848. }
  1849. }
  1850. if(TheTerrainRenderObject) {
  1851. TheTerrainRenderObject->setTimeOfDay(tod);
  1852. TheTacticalView->forceRedraw();
  1853. }
  1854. }
  1855. // W3DDisplay::drawLine =======================================================
  1856. /** draw a line on the display in pixel coordinates with the specified color */
  1857. //=============================================================================
  1858. void W3DDisplay::drawLine( Int startX, Int startY,
  1859. Int endX, Int endY,
  1860. Real lineWidth,
  1861. UnsignedInt lineColor )
  1862. {
  1863. /// @todo we need to consider the efficiency of the 2D renderer
  1864. m_2DRender->Reset();
  1865. m_2DRender->Enable_Texturing( FALSE );
  1866. m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ),
  1867. lineWidth, lineColor );
  1868. m_2DRender->Render();
  1869. } // end drawLine
  1870. // W3DDisplay::drawLine =======================================================
  1871. /** draw a line on the display in pixel coordinates with the specified color */
  1872. //=============================================================================
  1873. void W3DDisplay::drawLine( Int startX, Int startY,
  1874. Int endX, Int endY,
  1875. Real lineWidth,
  1876. UnsignedInt lineColor1,UnsignedInt lineColor2 )
  1877. {
  1878. /// @todo we need to consider the efficiency of the 2D renderer
  1879. m_2DRender->Reset();
  1880. m_2DRender->Enable_Texturing( FALSE );
  1881. m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ),
  1882. lineWidth, lineColor1, lineColor2 );
  1883. m_2DRender->Render();
  1884. } // end drawLine
  1885. // W3DDisplay::drawOpenRect ===================================================
  1886. //=============================================================================
  1887. void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height,
  1888. Real lineWidth, UnsignedInt lineColor )
  1889. {
  1890. if (m_isClippedEnabled)
  1891. {
  1892. ICoord2D start, end, returnStart, returnEnd;
  1893. start.x = startX;
  1894. start.y = startY;
  1895. end.x = start.x;
  1896. end.y = start.y + height;
  1897. if(ClipLine2D(&start, &end, &returnStart, &returnEnd, &m_clipRegion ))
  1898. drawLine( returnStart.x, returnStart.y, returnEnd.x, returnEnd.y, lineWidth, lineColor);
  1899. end.x = start.x + width;
  1900. end.y = start.y;
  1901. if(ClipLine2D(&start, &end, &returnStart, &returnEnd, &m_clipRegion ))
  1902. drawLine( returnStart.x, returnStart.y, returnEnd.x, returnEnd.y, lineWidth, lineColor);
  1903. start.x = startX + width;
  1904. start.y = startY;
  1905. end.x = start.x;
  1906. end.y = start.y + height;
  1907. if(ClipLine2D(&start, &end, &returnStart, &returnEnd, &m_clipRegion ))
  1908. drawLine( returnStart.x, returnStart.y, returnEnd.x, returnEnd.y, lineWidth, lineColor);
  1909. start.x = startX;
  1910. start.y = startY + height;
  1911. end.x = start.x + width;
  1912. end.y = start.y;
  1913. if(ClipLine2D(&start, &end, &returnStart, &returnEnd, &m_clipRegion ))
  1914. drawLine( returnStart.x, returnStart.y, returnEnd.x, returnEnd.y, lineWidth, lineColor);
  1915. }
  1916. else
  1917. {
  1918. /// @todo we need to consider the efficiency of the 2D renderer
  1919. m_2DRender->Reset();
  1920. m_2DRender->Enable_Texturing( FALSE );
  1921. m_2DRender->Add_Outline( RectClass( startX, startY,
  1922. startX + width, startY + height ),
  1923. lineWidth, lineColor );
  1924. // render it now!
  1925. m_2DRender->Render();
  1926. }
  1927. } // end drawOpenRect
  1928. // W3DDisplay::drawFillRect ===================================================
  1929. //=============================================================================
  1930. void W3DDisplay::drawFillRect( Int startX, Int startY, Int width, Int height,
  1931. UnsignedInt color )
  1932. {
  1933. /// @todo we need to consider the efficiency of the 2D renderer
  1934. m_2DRender->Reset();
  1935. m_2DRender->Enable_Texturing( FALSE );
  1936. m_2DRender->Add_Rect( RectClass( startX, startY,
  1937. startX + width, startY + height ),
  1938. 0, 0, color );
  1939. // render it now!
  1940. m_2DRender->Render();
  1941. } // end drawFillRect
  1942. void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, Int percent, UnsignedInt color)
  1943. {
  1944. // sanity
  1945. if(percent < 1 || percent > 100)
  1946. return;
  1947. m_2DRender->Reset();
  1948. m_2DRender->Enable_Texturing( FALSE );
  1949. // The rectanges are numberd as follows
  1950. //(x,y) |---------|
  1951. // | 4 | 1 |
  1952. // |----+----|
  1953. // | 3 | 2 |
  1954. // |---------| (x + width, y + width)
  1955. //
  1956. // we're done, lets just draw one rectangle for it all.
  1957. if(percent == 100)
  1958. {
  1959. m_2DRender->Add_Rect(RectClass( startX, startY,
  1960. startX + width, startY + height), 0,0, color);
  1961. }
  1962. else if( percent> 75)
  1963. {
  1964. //rectangle #1 & 2
  1965. m_2DRender->Add_Rect(RectClass( startX + width/2, startY,
  1966. startX + width, startY + height), 0,0, color);
  1967. // rectangle #3
  1968. m_2DRender->Add_Rect(RectClass( startX, startY + height/2,
  1969. startX + width/2, startY + height), 0,0, color);
  1970. // draw the part of rectangle 4
  1971. Real remain = percent - 75;
  1972. if(remain > 12)
  1973. {
  1974. //draw the full triangle
  1975. m_2DRender->Add_Tri(Vector2(startX, startY),
  1976. Vector2(startX, startY + height/2),
  1977. Vector2(startX + width/2, startY + height/2),
  1978. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  1979. // draw the part of triangle
  1980. Real percentDraw = (Real)(remain - 12)/ 13;
  1981. m_2DRender->Add_Tri(Vector2(startX, startY),
  1982. Vector2(startX + width/2, startY + height/2),
  1983. Vector2(startX + (width/2 * percentDraw), startY),
  1984. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  1985. }
  1986. else
  1987. {
  1988. // draw the part of triangle
  1989. Real percentDraw = (Real)(remain)/ 12;
  1990. m_2DRender->Add_Tri(Vector2(startX, startY + height/2 - (height/2 * percentDraw)),
  1991. Vector2(startX, startY + height/2),
  1992. Vector2(startX + width/2, startY + height/2),
  1993. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  1994. }
  1995. }
  1996. else if( percent > 50)
  1997. {
  1998. //rectangle #1 & 2
  1999. m_2DRender->Add_Rect(RectClass( startX + width/2, startY,
  2000. startX + width, startY + height), 0,0, color);
  2001. // draw the part of rectangle 3
  2002. Real remain = percent - 50;
  2003. if(remain > 12)
  2004. {
  2005. //draw the full triangle
  2006. m_2DRender->Add_Tri(Vector2(startX + width/2, startY + height/2),
  2007. Vector2(startX, startY + height),
  2008. Vector2(startX + width/2, startY + height),
  2009. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2010. // draw the part of triangle
  2011. Real percentDraw = (Real)(remain - 12)/ 13;
  2012. m_2DRender->Add_Tri(Vector2(startX, startY + height - (height/2 * percentDraw)),
  2013. Vector2(startX, startY + height),
  2014. Vector2(startX + width/2, startY + height/2),
  2015. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2016. }
  2017. else
  2018. {
  2019. // draw the part of triangle
  2020. Real percentDraw = (Real)(remain)/ 12;
  2021. m_2DRender->Add_Tri(Vector2(startX + width/2, startY + height),
  2022. Vector2(startX + width/2, startY + height/2),
  2023. Vector2(startX + width/2 - ( width/2 * percentDraw), startY + height),
  2024. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2025. }
  2026. }
  2027. else if(percent > 25)
  2028. {
  2029. // rectangel #1
  2030. m_2DRender->Add_Rect(RectClass( startX + width/2, startY,
  2031. startX + width, startY + height/2), 0,0, color);
  2032. // draw the part of rectangle 2
  2033. Real remain = percent - 25;
  2034. if(remain > 12)
  2035. {
  2036. //draw the full triangle
  2037. m_2DRender->Add_Tri(Vector2(startX + width/2, startY + height/2),
  2038. Vector2(startX + width, startY + height),
  2039. Vector2(startX + width, startY + height/2),
  2040. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2041. // draw the part of triangle
  2042. Real percentDraw = (Real)(remain - 12)/ 13;
  2043. m_2DRender->Add_Tri(Vector2(startX + width/2, startY + height/2),
  2044. Vector2(startX + width - (width/2 * percentDraw), startY + height),
  2045. Vector2(startX + width, startY + height),
  2046. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2047. }
  2048. else
  2049. {
  2050. // draw the part of triangle
  2051. Real percentDraw = (Real)(remain)/ 12;
  2052. m_2DRender->Add_Tri(Vector2(startX + width, startY + height/2),
  2053. Vector2(startX + width/2, startY + height/2),
  2054. Vector2(startX + width, startY + height/2 + ( height/2 * percentDraw)),
  2055. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2056. }
  2057. }
  2058. else
  2059. {
  2060. // draw the part of rectangle 1
  2061. if(percent > 12)
  2062. {
  2063. //draw the full triangle
  2064. m_2DRender->Add_Tri(Vector2(startX + width/2, startY),
  2065. Vector2(startX + width/2, startY + height/2),
  2066. Vector2(startX + width, startY),
  2067. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2068. // draw the part of triangle
  2069. Real percentDraw = (Real)(percent - 12)/ 13;
  2070. m_2DRender->Add_Tri(Vector2(startX + width, startY),
  2071. Vector2(startX + width/2, startY + height/2),
  2072. Vector2(startX + width, startY + (height/2 * percentDraw)),
  2073. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2074. }
  2075. else
  2076. {
  2077. // draw the part of triangle
  2078. Real percentDraw = (Real)(percent)/ 12;
  2079. m_2DRender->Add_Tri(Vector2(startX + width/2, startY),
  2080. Vector2(startX + width/2, startY + height/2),
  2081. Vector2(startX + width/2 + (width/2 * percentDraw), startY ),
  2082. Vector2(0,0),Vector2(0,0),Vector2(0,0),color);
  2083. }
  2084. }
  2085. // render it now!
  2086. m_2DRender->Render();
  2087. }
  2088. //--------------------------------------------------------------------------------------------------------------------
  2089. // W3DDisplay::drawRemainingRectClock
  2090. // Variation added by Kris -- October 2002
  2091. // This version will overlay a clock progress from the specified percentage to 100%. Essentially, this function will
  2092. // "reveal" an icon as it progresses towards completion.
  2093. //--------------------------------------------------------------------------------------------------------------------
  2094. void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int height, Int percent, UnsignedInt color)
  2095. {
  2096. // sanity
  2097. if( percent < 0 || percent > 99 )
  2098. return;
  2099. m_2DRender->Reset();
  2100. m_2DRender->Enable_Texturing( FALSE );
  2101. // The rectanges are numbered as follows
  2102. //(x,y) |---------|
  2103. // | 4 | 1 |
  2104. // |----+----|
  2105. // | 3 | 2 |
  2106. // |---------| (x + width, y + width)
  2107. //
  2108. Int midX = startX + width/2;
  2109. Int midY = startY + height/2;
  2110. Int endX = startX + width;
  2111. Int endY = startY + height;
  2112. Int halfWidth = width/2;
  2113. Int halfHeight = height/2;
  2114. if( percent == 0 )
  2115. {
  2116. // We just started, so draw the entire remaining rectangle.
  2117. // #1, #2, #3, and #4
  2118. m_2DRender->Add_Rect( RectClass( startX, startY, endX, endY ), 0, 0, color );
  2119. }
  2120. else if( percent < 25 )
  2121. {
  2122. //1-25%
  2123. //-----
  2124. //Rectangle #3 & 4
  2125. m_2DRender->Add_Rect( RectClass( startX, startY, midX, endY ), 0, 0, color );
  2126. //Rectangle #2
  2127. m_2DRender->Add_Rect( RectClass( midX, midY, endX, endY ), 0, 0, color );
  2128. //Handle rectangle #1 than needs partial rendering.
  2129. if( percent < 13 )
  2130. {
  2131. //1-12%
  2132. //-----
  2133. //Draw the 2nd half of rectangle #1
  2134. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( endX, midY ), Vector2( endX, startY ),
  2135. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2136. //Draw the last part of the 1st portion of rectangle #1
  2137. Real percentDraw = (Real)( 13 - percent ) / 13;
  2138. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( endX, startY ), Vector2( endX - halfWidth * percentDraw, startY ),
  2139. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2140. }
  2141. else
  2142. {
  2143. //13-24%
  2144. //------
  2145. //Draw the last part of the 2nd half of rectangle #1
  2146. Real percentDraw = (Real)( percent - 13 ) / 12;
  2147. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( endX, midY ), Vector2( endX, startY + halfHeight * percentDraw ),
  2148. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2149. }
  2150. }
  2151. else if( percent < 50 )
  2152. {
  2153. //25-49%
  2154. //------
  2155. //rectangle #3 & 4
  2156. m_2DRender->Add_Rect( RectClass( startX, startY, midX, endY ), 0, 0, color );
  2157. //Handle rectangle #2 that needs partial rendering.
  2158. if( percent < 38 )
  2159. {
  2160. //25-37%
  2161. //-----
  2162. //Draw the 2nd half of rectangle #2
  2163. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( midX, endY ), Vector2( endX, endY ),
  2164. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2165. //Draw the last part of the 1st portion of rectangle #2
  2166. Real percentDraw = (Real)( percent - 25 ) / 13;
  2167. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( endX, endY ), Vector2( endX, midY + halfHeight * percentDraw ),
  2168. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2169. }
  2170. else
  2171. {
  2172. //38-49%
  2173. //------
  2174. //Draw the last part of the 2nd half of rectangle #1
  2175. Real percentDraw = (Real)( percent - 38 ) / 12;
  2176. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( midX, endY ), Vector2( endX - halfWidth * percentDraw, endY ),
  2177. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2178. }
  2179. }
  2180. else if( percent < 75 )
  2181. {
  2182. //50-74%
  2183. //------
  2184. //Rectangle #4
  2185. m_2DRender->Add_Rect( RectClass( startX, startY, midX, midY ), 0, 0, color );
  2186. //Handle rectangle #3 that needs partial rendering.
  2187. if( percent < 63 )
  2188. {
  2189. //50-62%
  2190. //-----
  2191. //Draw the 2nd half of rectangle #3
  2192. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( startX, midY ), Vector2( startX, endY ),
  2193. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2194. //Draw the last part of the 1st portion of rectangle #3
  2195. Real percentDraw = (Real)( percent - 50 ) / 13;
  2196. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( startX, endY ), Vector2( midX - halfWidth * percentDraw, endY ),
  2197. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2198. }
  2199. else
  2200. {
  2201. //62-74%
  2202. //------
  2203. //Draw the last part of the 2nd half of rectangle #3
  2204. Real percentDraw = (Real)( percent - 62 ) / 12;
  2205. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( startX, midY ), Vector2( startX, endY - halfHeight * percentDraw ),
  2206. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2207. }
  2208. }
  2209. else
  2210. {
  2211. //75-99%
  2212. //------
  2213. //Handle rectangle #4 that needs partial rendering.
  2214. if( percent < 87 )
  2215. {
  2216. //75-87%
  2217. //-----
  2218. //Draw the 2nd half of rectangle #4
  2219. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( midX, startY ), Vector2( startX, startY ),
  2220. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2221. //Draw the last part of the 1st portion of rectangle #4
  2222. Real percentDraw = (Real)( percent - 75 ) / 13;
  2223. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( startX, startY ), Vector2( startX, midY - halfHeight * percentDraw ),
  2224. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2225. }
  2226. else
  2227. {
  2228. //88-99%
  2229. //------
  2230. //Draw the last part of the 2nd half of rectangle #4
  2231. Real percentDraw = (Real)( percent - 88 ) / 12;
  2232. m_2DRender->Add_Tri( Vector2( midX, midY ), Vector2( midX, startY ), Vector2( startX + halfWidth * percentDraw, startY ),
  2233. Vector2( 0, 0 ), Vector2( 0, 0 ), Vector2( 0, 0 ), color );
  2234. }
  2235. }
  2236. // render it now!
  2237. m_2DRender->Render();
  2238. }
  2239. // W3DDisplay::drawImage ======================================================
  2240. /** Draws an images at the screen coordinates and keeps it within the end
  2241. * screen coords specified */
  2242. //=============================================================================
  2243. void W3DDisplay::drawImage( const Image *image, Int startX, Int startY,
  2244. Int endX, Int endY, Color color, DrawImageMode mode)
  2245. {
  2246. // sanity
  2247. if( image == NULL )
  2248. return;
  2249. // !!
  2250. // Remember to update the GUIEditDisplay::drawImage when you make
  2251. // changes to this, it technically uses W3D code to render itself,
  2252. // but it not derived on the W3DDisplay
  2253. // !!
  2254. const Region2D *uv = image->getUV();
  2255. m_2DRender->Reset();
  2256. m_2DRender->Enable_Texturing( TRUE );
  2257. Bool doAlphaReset=FALSE;
  2258. ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW
  2259. switch (mode)
  2260. {
  2261. case DRAW_IMAGE_ALPHA: //nothing to do since alpha is the default state
  2262. break;
  2263. case DRAW_IMAGE_GRAYSCALE:
  2264. m_2DRender->Enable_Grayscale(true);
  2265. break;
  2266. case DRAW_IMAGE_ADDITIVE:
  2267. m_2DRender->Enable_Additive(true);
  2268. doAlphaReset = TRUE;
  2269. break;
  2270. case DRAW_IMAGE_SOLID:
  2271. m_2DRender->Enable_Additive(false);
  2272. m_2DRender->Enable_Alpha(false);
  2273. doAlphaReset = TRUE;
  2274. default:
  2275. break;
  2276. }
  2277. // if we have raw texture data we will use it, otherwise we are referencing filenames
  2278. if( BitTest( image->getStatus(), IMAGE_STATUS_RAW_TEXTURE ) )
  2279. m_2DRender->Set_Texture( (TextureClass *)(image->getRawTextureData()) );
  2280. else
  2281. m_2DRender->Set_Texture( image->getFilename().str() );
  2282. RectClass screen_rect(startX,startY,endX,endY);
  2283. RectClass uv_rect(uv->lo.x,uv->lo.y,uv->hi.x,uv->hi.y);
  2284. if (m_isClippedEnabled)
  2285. { //need to clip this quad to clip rectangle
  2286. //
  2287. // Check for completely clipped
  2288. //
  2289. if ( endX <= m_clipRegion.lo.x ||
  2290. endY <= m_clipRegion.lo.y)
  2291. {
  2292. return; //nothing to render
  2293. } else {
  2294. RectClass clipped_rect;
  2295. RectClass clipped_uv_rect;
  2296. if( BitTest( image->getStatus(), IMAGE_STATUS_ROTATED_90_CLOCKWISE ) )
  2297. {
  2298. //
  2299. // Clip the polygons to the specified area
  2300. //
  2301. clipped_rect.Left = __max (screen_rect.Left, m_clipRegion.lo.x);
  2302. clipped_rect.Right = __min (screen_rect.Right, m_clipRegion.hi.x);
  2303. clipped_rect.Top = __max (screen_rect.Top, m_clipRegion.lo.y);
  2304. clipped_rect.Bottom = __min (screen_rect.Bottom, m_clipRegion.hi.y);
  2305. //
  2306. // Clip the texture to the specified area
  2307. //
  2308. float percent = ((clipped_rect.Left - screen_rect.Left) / screen_rect.Width ());
  2309. clipped_uv_rect.Top = uv_rect.Top + (uv_rect.Height () * percent);
  2310. percent = ((clipped_rect.Right - screen_rect.Left) / screen_rect.Width ());
  2311. clipped_uv_rect.Bottom = uv_rect.Top + (uv_rect.Height () * percent);
  2312. percent = ((clipped_rect.Top - screen_rect.Top) / screen_rect.Height ());
  2313. clipped_uv_rect.Right = uv_rect.Right - (uv_rect.Width () * percent);
  2314. percent = ((clipped_rect.Bottom - screen_rect.Top) / screen_rect.Height ());
  2315. clipped_uv_rect.Left = uv_rect.Right - (uv_rect.Width () * percent);
  2316. }
  2317. else
  2318. {
  2319. //
  2320. // Clip the polygons to the specified area
  2321. //
  2322. clipped_rect.Left = __max (screen_rect.Left, m_clipRegion.lo.x);
  2323. clipped_rect.Right = __min (screen_rect.Right, m_clipRegion.hi.x);
  2324. clipped_rect.Top = __max (screen_rect.Top, m_clipRegion.lo.y);
  2325. clipped_rect.Bottom = __min (screen_rect.Bottom, m_clipRegion.hi.y);
  2326. //
  2327. // Clip the texture to the specified area
  2328. //
  2329. float percent = ((clipped_rect.Left - screen_rect.Left) / screen_rect.Width ());
  2330. clipped_uv_rect.Left = uv_rect.Left + (uv_rect.Width () * percent);
  2331. percent = ((clipped_rect.Right - screen_rect.Left) / screen_rect.Width ());
  2332. clipped_uv_rect.Right = uv_rect.Left + (uv_rect.Width () * percent);
  2333. percent = ((clipped_rect.Top - screen_rect.Top) / screen_rect.Height ());
  2334. clipped_uv_rect.Top = uv_rect.Top + (uv_rect.Height () * percent);
  2335. percent = ((clipped_rect.Bottom - screen_rect.Top) / screen_rect.Height ());
  2336. clipped_uv_rect.Bottom = uv_rect.Top + (uv_rect.Height () * percent);
  2337. }
  2338. //
  2339. // Use the clipped rectangles to render
  2340. //
  2341. screen_rect = clipped_rect;
  2342. uv_rect = clipped_uv_rect;
  2343. }
  2344. }
  2345. // if rotated 90 degrees clockwise we have to adjust the uv coords
  2346. if( BitTest( image->getStatus(), IMAGE_STATUS_ROTATED_90_CLOCKWISE ) )
  2347. {
  2348. m_2DRender->Add_Tri( Vector2( screen_rect.Left, screen_rect.Top ),
  2349. Vector2( screen_rect.Left, screen_rect.Bottom ),
  2350. Vector2( screen_rect.Right, screen_rect.Top ),
  2351. Vector2( uv_rect.Right, uv_rect.Top),
  2352. Vector2( uv_rect.Left, uv_rect.Top),
  2353. Vector2( uv_rect.Right, uv_rect.Bottom ),
  2354. color );
  2355. m_2DRender->Add_Tri( Vector2( screen_rect.Right, screen_rect.Bottom ),
  2356. Vector2( screen_rect.Right, screen_rect.Top ),
  2357. Vector2( screen_rect.Left, screen_rect.Bottom ),
  2358. Vector2( uv_rect.Left, uv_rect.Bottom ),
  2359. Vector2( uv_rect.Right, uv_rect.Bottom ),
  2360. Vector2( uv_rect.Left, uv_rect.Top ),
  2361. color );
  2362. } // end if
  2363. else
  2364. {
  2365. // just draw as normal
  2366. m_2DRender->Add_Quad( screen_rect, uv_rect, color );
  2367. } // end else
  2368. m_2DRender->Render();
  2369. //reset to default states for next time this method is called.
  2370. m_2DRender->Enable_Grayscale(false); //never leave it in this mode
  2371. if (doAlphaReset)
  2372. m_2DRender->Enable_Alpha(true);
  2373. } // end drawImage
  2374. //============================================================================
  2375. // W3DDisplay::createVideoBuffer
  2376. //============================================================================
  2377. VideoBuffer* W3DDisplay::createVideoBuffer( void )
  2378. {
  2379. VideoBuffer::Type format = VideoBuffer::TYPE_UNKNOWN;
  2380. /// @todo query video player for supported formats - we assume bink formats here
  2381. // first try to use the native format
  2382. WW3DFormat displayFormat = DX8Wrapper::getBackBufferFormat();
  2383. if ( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( displayFormat ))
  2384. {
  2385. format = W3DVideoBuffer::W3DFormatToType( displayFormat );
  2386. }
  2387. if ( format == VideoBuffer::TYPE_UNKNOWN )
  2388. {
  2389. if ( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( WW3D_FORMAT_X8R8G8B8 ))
  2390. {
  2391. format = VideoBuffer::TYPE_X8R8G8B8;
  2392. }
  2393. else if ( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( WW3D_FORMAT_R8G8B8 ))
  2394. {
  2395. format = VideoBuffer::TYPE_R8G8B8;
  2396. }
  2397. else if ( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( WW3D_FORMAT_R5G6B5 ))
  2398. {
  2399. format = VideoBuffer::TYPE_R5G6B5;
  2400. }
  2401. else if ( DX8Wrapper::Get_Current_Caps()->Support_Texture_Format( WW3D_FORMAT_X1R5G5B5 ))
  2402. {
  2403. format = VideoBuffer::TYPE_X1R5G5B5;
  2404. }
  2405. else
  2406. {
  2407. // card does not support any of the formats we need
  2408. return NULL;
  2409. }
  2410. }
  2411. // on low mem machines, render every video in 16bit except for the EA Logo movie
  2412. if(!TheGlobalData->m_playIntro )//&& TheGameLODManager && (!TheGameLODManager->didMemPass() || W3DShaderManager::getChipset() == DC_GEFORCE2))
  2413. format = VideoBuffer::TYPE_R5G6B5;
  2414. W3DVideoBuffer *buffer = NEW W3DVideoBuffer( format );
  2415. return buffer;
  2416. }
  2417. //============================================================================
  2418. // W3DDisplay::drawVideoBuffer
  2419. //============================================================================
  2420. void W3DDisplay::drawVideoBuffer( VideoBuffer *buffer, Int startX, Int startY, Int endX, Int endY )
  2421. {
  2422. W3DVideoBuffer *vbuffer = (W3DVideoBuffer*) buffer;
  2423. m_2DRender->Reset();
  2424. m_2DRender->Enable_Texturing( TRUE );
  2425. m_2DRender->Set_Texture( vbuffer->texture() );
  2426. m_2DRender->Add_Quad( RectClass( startX, startY, endX, endY ),
  2427. vbuffer->Rect( 0, 0, 1, 1) );
  2428. m_2DRender->Render();
  2429. }
  2430. // W3DDisplay::setClipRegion ============================================
  2431. /** Set the clipping region for images.
  2432. @todo: Make this work for all primitives, not just drawImage. */
  2433. //=============================================================================
  2434. void W3DDisplay::setClipRegion( IRegion2D *region )
  2435. {
  2436. // assign new region
  2437. m_clipRegion = *region;
  2438. m_isClippedEnabled = TRUE;
  2439. } // end setClipRegion
  2440. //=============================================================================
  2441. /* we don't really need to override this call, since we will soon be called to
  2442. update every shroud cell explicitly...
  2443. */
  2444. void W3DDisplay::clearShroud()
  2445. {
  2446. // nothing
  2447. }
  2448. //=============================================================================
  2449. void W3DDisplay::setBorderShroudLevel(UnsignedByte level)
  2450. {
  2451. if (TheTerrainRenderObject && TheTerrainRenderObject->getShroud())
  2452. {
  2453. TheTerrainRenderObject->getShroud()->setBorderShroudLevel((W3DShroudLevel)level);
  2454. }
  2455. }
  2456. //=============================================================================
  2457. void W3DDisplay::setShroudLevel( Int x, Int y, CellShroudStatus setting )
  2458. {
  2459. if (TheTerrainRenderObject && TheTerrainRenderObject->getShroud())
  2460. {
  2461. #ifdef INTENSE_DEBUG
  2462. TheTerrainRenderObject->getShroud()->setShroudFilter(false);
  2463. #endif
  2464. if( setting == CELLSHROUD_SHROUDED )
  2465. TheTerrainRenderObject->getShroud()->setShroudLevel(x, y, (W3DShroudLevel)TheGlobalData->m_shroudAlpha );
  2466. else if( setting == CELLSHROUD_FOGGED )
  2467. TheTerrainRenderObject->getShroud()->setShroudLevel(x, y, (W3DShroudLevel)TheGlobalData->m_fogAlpha );///< @todo placeholder to get feedback on logic work while graphic side being decided
  2468. else
  2469. TheTerrainRenderObject->getShroud()->setShroudLevel(x, y, (W3DShroudLevel)TheGlobalData->m_clearAlpha );
  2470. //Logic is saying shroud. We can add alpha levels here in client if needed.
  2471. // W3DShroud is a 0-255 alpha byte. Logic shroud is a double reference count.
  2472. TheTerrainRenderObject->notifyShroudChanged();
  2473. }
  2474. }
  2475. //=============================================================================
  2476. ///Utility function to dump data into a .BMP file
  2477. static void CreateBMPFile(LPTSTR pszFile, char *image, Int width, Int height)
  2478. {
  2479. HANDLE hf; // file handle
  2480. BITMAPFILEHEADER hdr; // bitmap file-header
  2481. PBITMAPINFOHEADER pbih; // bitmap info-header
  2482. LPBYTE lpBits; // memory pointer
  2483. DWORD dwTotal; // total count of bytes
  2484. DWORD cb; // incremental count of bytes
  2485. BYTE *hp; // byte pointer
  2486. DWORD dwTmp;
  2487. PBITMAPINFO pbmi;
  2488. pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER));
  2489. pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  2490. pbmi->bmiHeader.biWidth = width;
  2491. pbmi->bmiHeader.biHeight = height;
  2492. pbmi->bmiHeader.biPlanes = 1;
  2493. pbmi->bmiHeader.biBitCount = 24;
  2494. pbmi->bmiHeader.biCompression = BI_RGB;
  2495. pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 * pbmi->bmiHeader.biHeight * 24;
  2496. pbmi->bmiHeader.biClrImportant = 0;
  2497. pbih = (PBITMAPINFOHEADER) pbmi;
  2498. lpBits = (LPBYTE) image;
  2499. // Create the .BMP file.
  2500. hf = CreateFile(pszFile,
  2501. GENERIC_READ | GENERIC_WRITE,
  2502. (DWORD) 0,
  2503. NULL,
  2504. CREATE_ALWAYS,
  2505. FILE_ATTRIBUTE_NORMAL,
  2506. (HANDLE) NULL);
  2507. if (hf == INVALID_HANDLE_VALUE)
  2508. return;
  2509. hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
  2510. // Compute the size of the entire file.
  2511. hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
  2512. pbih->biSize + pbih->biClrUsed
  2513. * sizeof(RGBQUAD) + pbih->biSizeImage);
  2514. hdr.bfReserved1 = 0;
  2515. hdr.bfReserved2 = 0;
  2516. // Compute the offset to the array of color indices.
  2517. hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
  2518. pbih->biSize + pbih->biClrUsed
  2519. * sizeof (RGBQUAD);
  2520. // Copy the BITMAPFILEHEADER into the .BMP file.
  2521. if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
  2522. (LPDWORD) &dwTmp, NULL))
  2523. return;
  2524. // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
  2525. if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD),(LPDWORD) &dwTmp, NULL))
  2526. return;
  2527. // Copy the array of color indices into the .BMP file.
  2528. dwTotal = cb = pbih->biSizeImage;
  2529. hp = lpBits;
  2530. if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
  2531. return;
  2532. // Close the .BMP file.
  2533. if (!CloseHandle(hf))
  2534. return;
  2535. // Free memory.
  2536. LocalFree( (HLOCAL) pbmi);
  2537. }
  2538. ///Save Screen Capture to a file
  2539. void W3DDisplay::takeScreenShot(void)
  2540. {
  2541. char leafname[256];
  2542. char pathname[1024];
  2543. static int frame_number = 1;
  2544. Bool done = false;
  2545. while (!done) {
  2546. #ifdef CAPTURE_TO_TARGA
  2547. sprintf( leafname, "%s%.3d.tga", "sshot", frame_number++);
  2548. #else
  2549. sprintf( leafname, "%s%.3d.bmp", "sshot", frame_number++);
  2550. #endif
  2551. strcpy(pathname, TheGlobalData->getPath_UserData().str());
  2552. strcat(pathname, leafname);
  2553. if (_access( pathname, 0 ) == -1)
  2554. done = true;
  2555. }
  2556. // Lock front buffer and copy
  2557. IDirect3DSurface8 *fb;
  2558. fb=DX8Wrapper::_Get_DX8_Front_Buffer();
  2559. D3DSURFACE_DESC desc;
  2560. fb->GetDesc(&desc);
  2561. RECT bounds;
  2562. POINT point;
  2563. GetClientRect(ApplicationHWnd,&bounds);
  2564. point.x=bounds.left; point.y=bounds.top;
  2565. ClientToScreen(ApplicationHWnd, &point);
  2566. bounds.left=point.x; bounds.top=point.y;
  2567. point.x=bounds.right; point.y=bounds.bottom;
  2568. ClientToScreen(ApplicationHWnd, &point);
  2569. bounds.right=point.x; bounds.bottom=point.y;
  2570. D3DLOCKED_RECT lrect;
  2571. DX8_ErrorCode(fb->LockRect(&lrect,&bounds,D3DLOCK_READONLY));
  2572. unsigned int x,y,index,index2,width,height;
  2573. width=bounds.right-bounds.left;
  2574. height=bounds.bottom-bounds.top;
  2575. char *image=NEW char[3*width*height];
  2576. #ifdef CAPTURE_TO_TARGA
  2577. //bytes are mixed in targa files, not rgb order.
  2578. for (y=0; y<height; y++)
  2579. {
  2580. for (x=0; x<width; x++)
  2581. {
  2582. // index for image
  2583. index=3*(x+y*width);
  2584. // index for fb
  2585. index2=y*lrect.Pitch+4*x;
  2586. image[index]=*((char *) lrect.pBits + index2+2);
  2587. image[index+1]=*((char *) lrect.pBits + index2+1);
  2588. image[index+2]=*((char *) lrect.pBits + index2+0);
  2589. }
  2590. }
  2591. fb->Release();
  2592. Targa targ;
  2593. memset(&targ.Header,0,sizeof(targ.Header));
  2594. targ.Header.Width=width;
  2595. targ.Header.Height=height;
  2596. targ.Header.PixelDepth=24;
  2597. targ.Header.ImageType=TGA_TRUECOLOR;
  2598. targ.SetImage(image);
  2599. targ.YFlip();
  2600. targ.Save(pathname,TGAF_IMAGE,false);
  2601. #else //capturing to bmp file
  2602. //bmp is same byte order
  2603. for (y=0; y<height; y++)
  2604. {
  2605. for (x=0; x<width; x++)
  2606. {
  2607. // index for image
  2608. index=3*(x+y*width);
  2609. // index for fb
  2610. index2=y*lrect.Pitch+4*x;
  2611. image[index]=*((char *) lrect.pBits + index2+0);
  2612. image[index+1]=*((char *) lrect.pBits + index2+1);
  2613. image[index+2]=*((char *) lrect.pBits + index2+2);
  2614. }
  2615. }
  2616. fb->Release();
  2617. //Flip the image
  2618. char *ptr,*ptr1;
  2619. char v,v1;
  2620. for (y = 0; y < (height >> 1); y++)
  2621. {
  2622. /* Compute address of lines to exchange. */
  2623. ptr = (image + ((width * y) * 3));
  2624. ptr1 = (image + ((width * (height - 1)) * 3));
  2625. ptr1 -= ((width * y) * 3);
  2626. /* Exchange all the pixels on this scan line. */
  2627. for (x = 0; x < (width * 3); x++)
  2628. {
  2629. v = *ptr;
  2630. v1 = *ptr1;
  2631. *ptr = v1;
  2632. *ptr1 = v;
  2633. ptr++;
  2634. ptr1++;
  2635. }
  2636. }
  2637. CreateBMPFile(pathname, image, width, height);
  2638. #endif
  2639. delete [] image;
  2640. UnicodeString ufileName;
  2641. ufileName.translate(leafname);
  2642. TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
  2643. }
  2644. /** Start/Stop campturing an AVI movie*/
  2645. void W3DDisplay::toggleMovieCapture(void)
  2646. {
  2647. WW3D::Toggle_Movie_Capture("Movie",30);
  2648. }
  2649. #if defined(_DEBUG) || defined(_INTERNAL)
  2650. static FILE *AssetDumpFile=NULL;
  2651. void dumpMeshAssets(MeshClass *mesh)
  2652. {
  2653. if (mesh)
  2654. {
  2655. TextureClass *texture;
  2656. //MaterialInfoClass *material = mesh->Get_Material_Info();
  2657. MeshModelClass *model=mesh->Get_Model();
  2658. for (int stage=0;stage<MeshMatDescClass::MAX_TEX_STAGES;++stage)
  2659. {
  2660. for (int pass=0;pass<model->Get_Pass_Count();++pass)
  2661. {
  2662. if (model->Has_Texture_Array(pass,stage))
  2663. {
  2664. for (int i=0;i<model->Get_Polygon_Count();++i)
  2665. {
  2666. if ((texture=model->Peek_Texture(i,pass,stage)) != NULL)
  2667. {
  2668. fprintf(AssetDumpFile,"\t%s\n",texture->Get_Texture_Name());
  2669. }
  2670. }
  2671. }
  2672. else
  2673. {
  2674. if ((texture=model->Peek_Single_Texture(pass,stage)) != NULL)
  2675. {
  2676. fprintf(AssetDumpFile,"\t%s\n",texture->Get_Texture_Name());
  2677. }
  2678. }
  2679. }
  2680. }
  2681. }
  2682. }
  2683. void dumpHLODAssets(HLodClass *hlod)
  2684. {
  2685. if (hlod)
  2686. {
  2687. //model composed of multiple meshes.
  2688. for (Int i=0; i<hlod->Get_Num_Sub_Objects(); i++)
  2689. {
  2690. RenderObjClass *subObj=hlod->Get_Sub_Object(i);
  2691. if (subObj->Class_ID() == RenderObjClass::CLASSID_HLOD)
  2692. dumpHLODAssets((HLodClass *)subObj);
  2693. else
  2694. if (subObj->Class_ID() == RenderObjClass::CLASSID_MESH)
  2695. dumpMeshAssets((MeshClass *)subObj);
  2696. }
  2697. }
  2698. }
  2699. //-------------------------------------------------------------------------------------------------
  2700. /** dump all used models/textures to a file.*/
  2701. //-------------------------------------------------------------------------------------------------
  2702. void W3DDisplay::dumpModelAssets(const char *path)
  2703. {
  2704. if (m_3DScene)
  2705. {
  2706. AssetDumpFile=fopen(path,"w");
  2707. if (AssetDumpFile)
  2708. {
  2709. fprintf(AssetDumpFile,"Models and Textures used on %s:\n\n",TheGlobalData->m_mapName.str());
  2710. SceneIterator *sceneIter = m_3DScene->Create_Iterator();
  2711. sceneIter->First();
  2712. while(!sceneIter->Is_Done())
  2713. {
  2714. RenderObjClass * robj = sceneIter->Current_Item();
  2715. if (robj->Class_ID() == RenderObjClass::CLASSID_HLOD)
  2716. { fprintf(AssetDumpFile,"%s.W3D:\n",robj->Get_Name());
  2717. dumpHLODAssets((HLodClass *)robj);
  2718. }
  2719. else
  2720. if (robj->Class_ID() == RenderObjClass::CLASSID_MESH)
  2721. { fprintf(AssetDumpFile,"%s.W3D:\n",robj->Get_Name());
  2722. dumpMeshAssets((MeshClass *)robj);
  2723. }
  2724. sceneIter->Next();
  2725. }
  2726. m_3DScene->Destroy_Iterator(sceneIter);
  2727. fclose(AssetDumpFile);
  2728. }
  2729. }
  2730. }
  2731. #endif //only include above code in debug and internal
  2732. //-------------------------------------------------------------------------------------------------
  2733. /** Preload using the W3D asset manager the model referenced by the string parameter */
  2734. //-------------------------------------------------------------------------------------------------
  2735. void W3DDisplay::preloadModelAssets( AsciiString model )
  2736. {
  2737. if( m_assetManager )
  2738. {
  2739. AsciiString nameWithExtension;
  2740. nameWithExtension.format( "%s.w3d", model.str() );
  2741. m_assetManager->Load_3D_Assets( nameWithExtension.str() );
  2742. } // end if
  2743. } // end preloadModelAssets
  2744. //-------------------------------------------------------------------------------------------------
  2745. /** Preload using the W3D asset manager the texture referenced by the string parameter */
  2746. //-------------------------------------------------------------------------------------------------
  2747. void W3DDisplay::preloadTextureAssets( AsciiString texture )
  2748. {
  2749. if( m_assetManager )
  2750. {
  2751. TextureClass *theTexture = m_assetManager->Get_Texture( texture.str() );
  2752. theTexture->Release_Ref();//release reference
  2753. } // end if
  2754. } // end preloadModelAssets
  2755. //-------------------------------------------------------------------------------------------------
  2756. //-------------------------------------------------------------------------------------------------
  2757. void W3DDisplay::doSmartAssetPurgeAndPreload(const char* usageFileName)
  2758. {
  2759. if (!m_assetManager || !usageFileName || !*usageFileName)
  2760. return;
  2761. DynamicVectorClass<StringClass> names(8000);
  2762. // use TheFileSystem here so we can bigify these files
  2763. File* f = TheFileSystem->openFile(usageFileName, File::READ | File::TEXT);
  2764. if (f)
  2765. {
  2766. for (;;)
  2767. {
  2768. AsciiString tmp;
  2769. if (f->scanString(tmp) == FALSE)
  2770. break;
  2771. // allow for comments in the file. Note that this doesn't allow for comments
  2772. // with spaces! doh. oh well. better than nothing.
  2773. if (tmp.str()[0] == ';')
  2774. continue;
  2775. names.Add(StringClass(tmp.str()));
  2776. }
  2777. f->close();
  2778. }
  2779. // just free everything if there's no exclusion list file (send in an empty list)
  2780. m_assetManager->Free_Assets_With_Exclusion_List(names);
  2781. }
  2782. //-------------------------------------------------------------------------------------------------
  2783. //-------------------------------------------------------------------------------------------------
  2784. #if defined(_DEBUG) || defined(_INTERNAL)
  2785. void W3DDisplay::dumpAssetUsage(const char* mapname)
  2786. {
  2787. if (!m_assetManager || !mapname || !*mapname)
  2788. return;
  2789. DynamicVectorClass<StringClass> names(8000);
  2790. m_assetManager->Create_Asset_List(names);
  2791. const char* leafname = strrchr(mapname, '\\');
  2792. if (leafname)
  2793. ++leafname; // point to first character after the last backslash
  2794. else
  2795. leafname = mapname; // point to the start of the filename
  2796. char buf[256];
  2797. int idx = 1;
  2798. while (true)
  2799. {
  2800. sprintf(buf, "AssetUsage_%s_%04d.txt",leafname,idx);
  2801. if (_access(buf, 0) != 0)
  2802. break; // it exists, we're good
  2803. ++idx;
  2804. }
  2805. FILE *fp = fopen(buf, "w");
  2806. if (fp)
  2807. {
  2808. for (int i=0; i<names.Count(); i++)
  2809. {
  2810. const char* n = names[i];
  2811. fprintf(fp, "%s\n", n);
  2812. }
  2813. fclose(fp);
  2814. }
  2815. }
  2816. #endif
  2817. //-------------------------------------------------------------------------------------------------
  2818. static void drawFramerateBar(void)
  2819. {
  2820. static DWORD prevTime = timeGetTime();
  2821. DWORD now = timeGetTime();
  2822. Real percTime = (1000.0f / (now - prevTime) ) / (1000.0f / TheGlobalData->m_framesPerSecondLimit);
  2823. if (percTime > 1.0f)
  2824. percTime = 1.0f;
  2825. else if (percTime < 0.0f)
  2826. percTime = 0.0f;
  2827. Int width = REAL_TO_INT(percTime * TheDisplay->getWidth());
  2828. UnsignedInt colorToUse = GameMakeColor( REAL_TO_UNSIGNEDBYTE((1.0f - percTime) * 255),
  2829. REAL_TO_UNSIGNEDBYTE(percTime * 255),
  2830. 0,
  2831. 0x7F);
  2832. TheDisplay->drawFillRect(1, 1, width, 15, colorToUse);
  2833. prevTime = now;
  2834. }