LoadScreen.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #define LOADSCREEN_CPP
  2. /*************************************************************************************************\
  3. LoadScreen.cpp : Implementation of the LoadScreen component.
  4. //---------------------------------------------------------------------------//
  5. // Copyright (C) Microsoft Corporation. All rights reserved. //
  6. //===========================================================================//
  7. \*************************************************************************************************/
  8. #include <windows.h>
  9. #include <ddraw.h>
  10. #include "LoadScreen.h"
  11. #include "aAnimObject.h"
  12. #include "tgaInfo.h"
  13. #include "mclib.h"
  14. #include "Prefs.h"
  15. #include "multplyr.h"
  16. #include "mission.h"
  17. #include "gameSound.h"
  18. float loadProgress = 0.0f;
  19. long LoadScreen::xProgressLoc = 0;
  20. long LoadScreen::yProgressLoc = 0;
  21. long LoadScreen::xWaitLoc = 0;
  22. long LoadScreen::yWaitLoc = 0;
  23. bool LoadScreen::turnOffAsyncMouse = false;
  24. TGAFileHeader* LoadScreen::progressTextureMemory = 0;
  25. TGAFileHeader* LoadScreen::progressBackground = 0;
  26. TGAFileHeader* LoadScreen::mergedTexture = 0;
  27. TGAFileHeader* LoadScreen::waitingForPlayersMemory = 0;
  28. LoadScreen* LoadScreenWrapper::enterScreen = NULL;
  29. LoadScreen* LoadScreenWrapper::exitScreen = NULL;
  30. extern volatile bool mc2IsInMouseTimer;
  31. extern volatile bool mc2IsInDisplayBackBuffer;
  32. extern void (*AsynFunc)(RECT& WinRect,DDSURFACEDESC2& mouseSurfaceDesc );
  33. extern CPrefs prefs;
  34. //
  35. // Returns the number of bits in a given mask. Used to determine if we are in 555 mode vs 565 mode.
  36. WORD GetNumberOfBits( DWORD dwMask );
  37. void MouseTimerInit();
  38. void MouseTimerKill();
  39. LoadScreenWrapper::LoadScreenWrapper()
  40. {
  41. //How about, for shits and giggles we toss the static members we created for single player when this inits for multiplayer
  42. // or any other player!!!!
  43. if ( enterScreen )
  44. delete enterScreen;
  45. if ( exitScreen )
  46. delete exitScreen;
  47. enterScreen = exitScreen = NULL;
  48. enterScreen = new LoadScreen;
  49. exitScreen = new LoadScreen;
  50. bFirstTime = 0;
  51. }
  52. LoadScreenWrapper::~LoadScreenWrapper()
  53. {
  54. if ( enterScreen )
  55. delete enterScreen;
  56. if ( exitScreen )
  57. delete exitScreen;
  58. enterScreen = exitScreen = NULL;
  59. }
  60. void LoadScreenWrapper::init( FitIniFile& file )
  61. {
  62. enterScreen->init( file );
  63. // changeRes();
  64. bFirstTime = 0;
  65. }
  66. void LoadScreenWrapper::changeRes()
  67. {
  68. const char* Appendix = NULL;
  69. switch( prefs.resolution )
  70. {
  71. case 0:
  72. Appendix = "_640";
  73. break;
  74. case 1:
  75. break;
  76. case 2:
  77. Appendix = "_1024";
  78. break;
  79. case 3:
  80. Appendix = "_1280";
  81. break;
  82. case 4:
  83. Appendix = "_1600";
  84. break;
  85. default:
  86. Assert( 0, 0, "Unexpected resolution found in prefs" );
  87. break;
  88. }
  89. char fileName[256];
  90. sprintf( fileName, "mcl_loadingscreen" );
  91. if ( Appendix )
  92. strcat( fileName, Appendix );
  93. FullPathFileName path;
  94. path.init( artPath, fileName, ".fit" );
  95. FitIniFile outFile;
  96. if ( NO_ERR != outFile.open( path ) )
  97. {
  98. char error[256];
  99. sprintf( error, "couldn't open file %s", path );
  100. Assert( 0, 0, error );
  101. return;
  102. }
  103. //The 0x2 means that we do NOT want to flush this texture when we toss
  104. // the texture cache before a mission. BUT we DO want the texture to cache out
  105. // to make more room for stuff.
  106. exitScreen->init( outFile, 0x2 );
  107. exitScreen->setupOutAnims();
  108. LoadScreen::changeRes( outFile );
  109. }
  110. void LoadScreen::changeRes( FitIniFile& outFile )
  111. {
  112. if ( progressBackground )
  113. delete [] progressBackground;
  114. progressBackground = NULL;
  115. if ( waitingForPlayersMemory )
  116. delete [] waitingForPlayersMemory;
  117. waitingForPlayersMemory = NULL;
  118. if ( !progressBackground )
  119. {
  120. char progressPath[256];
  121. char progressBackgroundPath[256];
  122. long result = outFile.seekBlock( "LoadingBar" );
  123. gosASSERT( result == NO_ERR );
  124. outFile.readIdLong( "XLocation", xProgressLoc );
  125. outFile.readIdLong( "YLocation", yProgressLoc );
  126. outFile.readIdString( "FileName", progressPath, 255 );
  127. outFile.readIdString( "BackgroundFileName", progressBackgroundPath, 255);
  128. File tgaFile;
  129. FullPathFileName path;
  130. path.init( artPath, progressBackgroundPath, ".tga" );
  131. if ( NO_ERR != tgaFile.open( path ) )
  132. {
  133. char error[256];
  134. sprintf( error, "couldn't open file %s", path );
  135. Assert( 0, 0, error );
  136. return;
  137. }
  138. long size = tgaFile.fileSize();
  139. progressBackground = (TGAFileHeader*)new char[size];
  140. tgaFile.read( (unsigned char*)progressBackground, tgaFile.fileSize() );
  141. tgaFile.close();
  142. path.init( artPath, progressPath, ".tga" );
  143. if ( NO_ERR != tgaFile.open( path ) )
  144. {
  145. char error[256];
  146. sprintf( error, "couldn't open file %s", path );
  147. Assert( 0, 0, error );
  148. return;
  149. }
  150. size = tgaFile.fileSize();
  151. progressTextureMemory = (TGAFileHeader*)new char[size];
  152. tgaFile.read( (unsigned char*)progressTextureMemory, tgaFile.fileSize() );
  153. mergedTexture = (TGAFileHeader*)new char[size];
  154. memcpy( mergedTexture, progressTextureMemory, size );
  155. tgaFile.close();
  156. result = outFile.seekBlock( "WaitImage" );
  157. gosASSERT( result == NO_ERR );
  158. outFile.readIdString( "FileName", progressPath, 255 );
  159. outFile.readIdLong( "XLocation", xWaitLoc );
  160. outFile.readIdLong( "YLocation", yWaitLoc );
  161. path.init( artPath, progressPath, ".tga" );
  162. if ( NO_ERR != tgaFile.open( path ) )
  163. {
  164. char error[256];
  165. sprintf( error, "couldn't open file %s", path );
  166. Assert( 0, 0, error );
  167. return;
  168. }
  169. size = tgaFile.fileSize();
  170. waitingForPlayersMemory = (TGAFileHeader*)new char[size];
  171. tgaFile.read( (unsigned char*)waitingForPlayersMemory, tgaFile.fileSize() );
  172. flipTopToBottom( (BYTE*)(waitingForPlayersMemory + 1), waitingForPlayersMemory->pixel_depth,
  173. waitingForPlayersMemory->width, waitingForPlayersMemory->height );
  174. }
  175. }
  176. void LoadScreenWrapper::begin()
  177. {
  178. waitForResChange = 0;
  179. bFirstTime = true;
  180. enterScreen->begin();
  181. }
  182. void LoadScreenWrapper::update()
  183. {
  184. if ( loadProgress > 99 )
  185. soundSystem->playDigitalSample( LOAD_DOORS_OPENING );
  186. else if ( bFirstTime )
  187. soundSystem->playDigitalSample( LOAD_DOORS_CLOSING );
  188. bFirstTime = 0;
  189. if ( waitForResChange ) // waiting one more render to force
  190. {
  191. status = READYTOLOAD;
  192. waitForResChange = 0;
  193. }
  194. else
  195. {
  196. if ( Environment.screenWidth == 800 )
  197. {
  198. enterScreen->update();
  199. status = enterScreen->getStatus();
  200. if ( status == READYTOLOAD )
  201. {
  202. waitForResChange = 1;
  203. changeRes();
  204. status = RUNNING;
  205. }
  206. }
  207. else
  208. {
  209. exitScreen->update();
  210. status = exitScreen->getStatus();
  211. }
  212. }
  213. }
  214. void LoadScreenWrapper::render( int xOffset, int yOffset )
  215. {
  216. if ( Environment.screenWidth == 800 )
  217. {
  218. enterScreen->render( xOffset, yOffset );
  219. }
  220. else
  221. exitScreen->render( xOffset, yOffset );
  222. }
  223. //-------------------------------------------------------------------------------------------------
  224. //-------------------------------------------------------------------------------------------------
  225. //-------------------------------------------------------------------------------------------------
  226. LoadScreen::LoadScreen( )
  227. {
  228. progressBackground = 0;
  229. progressTextureMemory = 0;
  230. animIndices = 0;
  231. }
  232. //-------------------------------------------------------------------------------------------------
  233. LoadScreen::~LoadScreen()
  234. {
  235. if ( progressBackground )
  236. delete [] progressBackground;
  237. if ( progressTextureMemory )
  238. delete [] progressTextureMemory;
  239. if ( mergedTexture )
  240. delete [] mergedTexture;
  241. if ( animIndices )
  242. delete [] animIndices;
  243. if ( waitingForPlayersMemory)
  244. delete [] waitingForPlayersMemory;
  245. animIndices = NULL;
  246. waitingForPlayersMemory = progressBackground = progressTextureMemory = mergedTexture = NULL;
  247. }
  248. void LoadScreen::begin()
  249. {
  250. for ( int i = 0; i < animObjectsCount; i++ )
  251. {
  252. //The assign below will overwrite the assign in defaultConstructor, leaking the memory
  253. animObjects[i].animInfo.destroy();
  254. animObjects[i].animInfo = inAnims[animIndices[i]];
  255. animObjects[i].animInfo.begin();
  256. animObjects[i].update();
  257. }
  258. loadProgress = 0;
  259. //-----------------------------------------------
  260. //Turn the mouse cursor OFF until load is done.
  261. // This will be keep ghost images from occuring.
  262. userInput->mouseOff();
  263. }
  264. void LoadScreen::init(FitIniFile& file, DWORD neverFlush)
  265. {
  266. LogisticsScreen::init( file, "Static", "Text", "Rect", "Button", "Edit", "AnimObject", neverFlush );
  267. file.seekBlock( "AnimationTopOut" );
  268. outAnims[0].init( &file, "" );
  269. file.seekBlock( "AnimationBottomOut" );
  270. outAnims[1].init( &file, "" );
  271. file.seekBlock( "AnimationLeftOut" );
  272. outAnims[2].init( &file, "" );
  273. file.seekBlock( "AnimationRightOut" );
  274. outAnims[3].init( &file, "" );
  275. file.seekBlock( "AnimationTopIn" );
  276. inAnims[0].init( &file, "" );
  277. file.seekBlock( "AnimationBottomIn" );
  278. inAnims[1].init( &file, "" );
  279. file.seekBlock( "AnimationLeftIn" );
  280. inAnims[2].init( &file, "" );
  281. file.seekBlock( "AnimationRightIn" );
  282. inAnims[3].init( &file, "" );
  283. file.seekBlock( "AnimationTop2In" );
  284. inAnims[4].init( &file, "" );
  285. file.seekBlock( "AnimationTop2Out" );
  286. outAnims[4].init( &file, "" );
  287. text.init( &file, "AnimObject18" );
  288. if ( animObjectsCount )
  289. {
  290. char blockName[256];
  291. animIndices = new int[animObjectsCount];
  292. for ( int i= 0; i < animObjectsCount; i++ )
  293. {
  294. sprintf( blockName, "AnimObject%ld", i );
  295. file.seekBlock( blockName );
  296. file.readIdString( "AnimationOut", blockName, 255 );
  297. if ( strstr( blockName, "2" ) )
  298. animIndices[i] = 4;
  299. else if ( strstr( blockName, "Top" ) )
  300. animIndices[i] = 0;
  301. else if ( strstr( blockName, "Bottom" ) )
  302. animIndices[i] = 1;
  303. else if ( strstr( blockName, "Left" ) )
  304. animIndices[i] = 2;
  305. else
  306. animIndices[i] = 3;
  307. }
  308. }
  309. }
  310. void LoadScreen::update()
  311. {
  312. status = RUNNING;
  313. LogisticsScreen::update();
  314. bool bDone = true;
  315. for ( int i = 0; i < animObjectsCount; i++ )
  316. {
  317. bDone &= animObjects[i].isDone();
  318. }
  319. if ( bDone )
  320. {
  321. if ( loadProgress < 99.f )
  322. {
  323. for ( int i = 0; i < animObjectsCount; i++ )
  324. {
  325. //The assign below will overwrite the assign in begin, leaking the memory
  326. animObjects[i].animInfo.destroy();
  327. animObjects[i].animInfo = outAnims[animIndices[i]];
  328. animObjects[i].begin();
  329. animObjects[i].update();
  330. }
  331. status = READYTOLOAD;
  332. prefs.applyPrefs( true );
  333. turnOffAsyncMouse = mc2UseAsyncMouse;
  334. if ( !mc2UseAsyncMouse )
  335. MouseTimerInit();
  336. mc2UseAsyncMouse = true;
  337. AsynFunc = ProgressTimer;
  338. }
  339. else
  340. {
  341. loadProgress = 0;
  342. status = NEXT;
  343. //YIKES!! We could be checking the if before the null and executing after!! Block the thread!
  344. //Wait for thread to finish.
  345. while (mc2IsInMouseTimer)
  346. ;
  347. //ONLY set the mouse BLT data at the end of each update. NO MORE FLICKERING THEN!!!
  348. // BLOCK THREAD WHILE THIS IS HAPPENING
  349. mc2IsInDisplayBackBuffer = true;
  350. AsynFunc = NULL;
  351. mc2UseAsyncMouse = turnOffAsyncMouse;
  352. if ( !mc2UseAsyncMouse)
  353. MouseTimerKill();
  354. mc2IsInDisplayBackBuffer = false;
  355. //Force mouse Cursors to smaller or larger depending on new video mode.
  356. userInput->initMouseCursors("cursors");
  357. userInput->mouseOn();
  358. }
  359. }
  360. else
  361. {
  362. userInput->mouseOff();
  363. }
  364. }
  365. void LoadScreen::render( int x, int y )
  366. {
  367. //ignoring animation information...
  368. LogisticsScreen::render();
  369. int curX = animObjects[0].animInfo.getXDelta();
  370. int curY = animObjects[0].animInfo.getYDelta();
  371. text.move( x + curX, y + curY );
  372. text.render( );
  373. text.move( -x - curX, -y - curY);
  374. }
  375. void ProgressTimer( RECT& WinRect,DDSURFACEDESC2& mouseSurfaceDesc )
  376. {
  377. if ( !LoadScreen::progressBackground )
  378. return;
  379. long destX = 0;
  380. long destY = 0;
  381. BYTE* pMem = (BYTE*)(LoadScreen::mergedTexture + 1);
  382. long destRight = 0;
  383. long destBottom = 0;
  384. long srcWidth = 0;
  385. long srcDepth = 0;
  386. if ( loadProgress > 0 && loadProgress < 100 )
  387. {
  388. destX = 0;
  389. destY = 0;
  390. long destWidth = LoadScreen::progressBackground->width;
  391. long destHeight = LoadScreen::progressBackground->height;
  392. float widthIncPerProgress = (float)destWidth * 0.01f;
  393. long* pLSrc = (long*)(LoadScreen::progressBackground+1);
  394. long* pLDest = (long*)(LoadScreen::mergedTexture+1);
  395. // merge background and current progress together...
  396. for ( int i = 0; i < 2; i++ )
  397. {
  398. for ( int y = 0; y < destHeight; y++ )
  399. {
  400. for ( long x = 0; x < LoadScreen::progressBackground->width; x++ )
  401. {
  402. if ( x < destWidth )
  403. *pLDest++ = *pLSrc++;
  404. else
  405. {
  406. pLDest++;
  407. pLSrc++;
  408. }
  409. }
  410. }
  411. pLSrc = (long*)( LoadScreen::progressTextureMemory + 1 );
  412. pLDest = (long*)(LoadScreen::mergedTexture+1);
  413. destWidth = loadProgress * widthIncPerProgress;
  414. }
  415. destX = WinRect.left + (LoadScreen::xProgressLoc);
  416. destY = WinRect.top + (LoadScreen::yProgressLoc);
  417. pMem = (BYTE*)(LoadScreen::mergedTexture + 1);
  418. destRight = destX + LoadScreen::progressBackground->width;
  419. destBottom = (destY + LoadScreen::progressBackground->height);
  420. srcWidth = LoadScreen::progressBackground->width;
  421. srcDepth = LoadScreen::progressBackground->pixel_depth/8;
  422. }
  423. else if ( loadProgress == 1000 )
  424. {
  425. destX = WinRect.left + LoadScreen::xWaitLoc;
  426. destY = WinRect.top + LoadScreen::yWaitLoc;
  427. pMem = (BYTE*)(LoadScreen::waitingForPlayersMemory + 1);
  428. destRight = destX + LoadScreen::waitingForPlayersMemory->width;
  429. destBottom = (destY + LoadScreen::waitingForPlayersMemory->height);
  430. destRight = destRight > WinRect.right ? WinRect.right : destRight;
  431. destBottom = destBottom > WinRect.bottom ? WinRect.top : destBottom;
  432. srcWidth = LoadScreen::waitingForPlayersMemory->width;
  433. srcDepth = LoadScreen::waitingForPlayersMemory->pixel_depth/8;
  434. }
  435. else
  436. return;
  437. // now put it on the screen...
  438. long destWidth = destRight - destX;
  439. long destHeight = destBottom - destY;
  440. for ( int y = 0; y < destHeight; y++ )
  441. {
  442. BYTE* pSrc = pMem + y * srcWidth * srcDepth;
  443. BYTE* pDest = (MemoryPtr)mouseSurfaceDesc.lpSurface + destX * mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount/8 +
  444. ((destY + y) * mouseSurfaceDesc.lPitch);
  445. for ( long x = 0; x < destWidth; x++ )
  446. {
  447. DWORD mColor = *(long*)pSrc;
  448. BYTE baseAlpha = 0;
  449. BYTE baseColorRed = (mColor & 0x00ff0000)>>16;
  450. BYTE baseColorGreen = (mColor & 0x0000ff00)>>8;
  451. BYTE baseColorBlue = (mColor & 0x000000ff);
  452. pSrc += 4;
  453. if ( mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32 )
  454. {
  455. (*(long*)pDest) = mColor;
  456. pDest += 4;
  457. }
  458. else if ( mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 24 )
  459. {
  460. if ( !baseAlpha )
  461. {
  462. pDest++;
  463. pDest++;
  464. pDest++;
  465. }
  466. *pDest++ = baseColorRed;
  467. *pDest++ = baseColorGreen;
  468. *pDest++ = baseColorBlue;
  469. }
  470. else if ( mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 16 )
  471. {
  472. bool in555Mode = false;
  473. if (GetNumberOfBits(mouseSurfaceDesc.ddpfPixelFormat.dwGBitMask) == 5)
  474. in555Mode = true;
  475. if ( !baseAlpha )
  476. {
  477. long clr;
  478. if (in555Mode)
  479. {
  480. clr = (baseColorRed >> 3) << 10;
  481. clr += (baseColorGreen >> 3) << 5;
  482. clr += (baseColorBlue >> 3);
  483. }
  484. else
  485. {
  486. clr = (baseColorRed >> 3) << 11;
  487. clr += (baseColorGreen >> 2) << 5;
  488. clr += (baseColorBlue >> 3);
  489. }
  490. *pDest++ = clr & 0xff;
  491. *pDest++ = clr >> 8;
  492. }
  493. else
  494. {
  495. pDest++;
  496. pDest++;
  497. }
  498. }
  499. }
  500. }
  501. }
  502. void LoadScreen::setupOutAnims()
  503. {
  504. for ( int i = 0; i < animObjectsCount; i++ )
  505. {
  506. //The assign below will overwrite the assign in begin, leaking the memory
  507. animObjects[i].animInfo.destroy();
  508. animObjects[i].animInfo = outAnims[animIndices[i]];
  509. animObjects[i].begin();
  510. animObjects[i].update();
  511. }
  512. }
  513. //*************************************************************************************************
  514. // end of file ( LoadScreen.cpp )