Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1096 lines
32 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: state.cpp
  3. //
  4. // Desc: STATE
  5. //
  6. // Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include "stdafx.h"
  9. //-----------------------------------------------------------------------------
  10. // Name: STATE constructor
  11. // Desc: global state init
  12. // translates variables set from the dialog boxes
  13. //-----------------------------------------------------------------------------
  14. STATE::STATE( CONFIG* pConfig )
  15. {
  16. ZeroMemory( &m_textureInfo, sizeof(TEXTUREINFO)*MAX_TEXTURES );
  17. m_pConfig = pConfig;
  18. m_resetStatus = 0;
  19. m_pClearVB = NULL;
  20. m_pNState = NULL;
  21. m_pd3dDevice = NULL;
  22. m_pWorldMatrixStack = NULL;
  23. m_pLeadPipe = NULL;
  24. m_nodes = NULL;
  25. m_pFState = NULL;
  26. m_maxDrawThreads = 0;
  27. m_nTextures = 0;
  28. m_bUseTexture = FALSE;
  29. m_nSlices = 0;
  30. m_radius = 0;
  31. m_drawMode = 0;
  32. m_maxPipesPerFrame = 0;
  33. m_nPipesDrawn = 0;
  34. m_nDrawThreads = 0;
  35. m_fLastTime = 0.0f;
  36. m_drawScheme = FRAME_SCHEME_RANDOM; // default draw scheme
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Name:
  40. // Desc:
  41. //-----------------------------------------------------------------------------
  42. HRESULT STATE::InitDeviceObjects( IDirect3DDevice8* pd3dDevice )
  43. {
  44. m_pd3dDevice = pd3dDevice;
  45. if( m_view.SetWinSize( g_pMyPipesScreensaver->GetSurfaceDesc()->Width,
  46. g_pMyPipesScreensaver->GetSurfaceDesc()->Height ) )
  47. m_resetStatus |= RESET_RESIZE_BIT;
  48. return S_OK;
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Name:
  52. // Desc:
  53. //-----------------------------------------------------------------------------
  54. HRESULT STATE::RestoreDeviceObjects()
  55. {
  56. int anDefaultResource[1];
  57. anDefaultResource[0] = IDB_DEFTEX;
  58. m_bUseTexture = FALSE;
  59. if( m_pConfig->bTextured )
  60. {
  61. if( SUCCEEDED( LoadTextureFiles( 1, m_pConfig->strTextureName, anDefaultResource ) ) )
  62. m_bUseTexture = TRUE;
  63. }
  64. DRAW_THREAD* pThread = m_drawThreads;
  65. for( int i=0; i<m_maxDrawThreads; i++ )
  66. {
  67. pThread->InitDeviceObjects( m_pd3dDevice );
  68. pThread->RestoreDeviceObjects();
  69. pThread++;
  70. }
  71. D3DXCreateMatrixStack( 0, &m_pWorldMatrixStack );
  72. m_view.SetProjMatrix( m_pd3dDevice );
  73. D3DCAPS8 d3d8caps;
  74. ZeroMemory( &d3d8caps, sizeof(D3DCAPS8) );
  75. m_pd3dDevice->GetDeviceCaps( &d3d8caps );
  76. if( d3d8caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE )
  77. {
  78. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  79. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  80. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  81. }
  82. else if( d3d8caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1 )
  83. {
  84. if( m_bUseTexture )
  85. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  86. else
  87. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
  88. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
  89. }
  90. if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR )
  91. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  92. else if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFPOINT )
  93. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  94. if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR )
  95. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  96. else if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFPOINT )
  97. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  98. if( d3d8caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP )
  99. {
  100. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
  101. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );
  102. m_pd3dDevice->SetRenderState( D3DRS_WRAP0, D3DWRAP_U | D3DWRAP_V );
  103. }
  104. else if( d3d8caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP )
  105. {
  106. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
  107. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
  108. }
  109. m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  110. m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  111. m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  112. m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x00 );
  113. m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
  114. m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  115. m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
  116. m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  117. m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
  118. if( d3d8caps.PrimitiveMiscCaps & D3DPMISCCAPS_CULLCW )
  119. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
  120. else
  121. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  122. // Set up the lighting states
  123. ZeroMemory( &m_light, sizeof(D3DLIGHT8) );
  124. m_light.Type = D3DLIGHT_DIRECTIONAL;
  125. m_light.Diffuse.r = 1.0f;
  126. m_light.Diffuse.g = 1.0f;
  127. m_light.Diffuse.b = 1.0f;
  128. m_light.Diffuse.a = 1.0f;
  129. if( m_bUseTexture )
  130. {
  131. m_light.Specular.r = 0.0f;
  132. m_light.Specular.g = 0.0f;
  133. m_light.Specular.b = 0.0f;
  134. }
  135. else
  136. {
  137. m_light.Specular.r = 0.6f;
  138. m_light.Specular.g = 0.6f;
  139. m_light.Specular.b = 0.6f;
  140. }
  141. m_light.Specular.a = 1.0f;
  142. m_light.Position.x = 0.0f;
  143. m_light.Position.y = -50.0f;
  144. m_light.Position.z = -150.0f;
  145. m_light.Ambient.r = 0.1f;
  146. m_light.Ambient.g = 0.1f;
  147. m_light.Ambient.b = 0.1f;
  148. m_light.Ambient.a = 1.1f;
  149. D3DXVec3Normalize( (D3DXVECTOR3*)&m_light.Direction, &D3DXVECTOR3(m_light.Position.x, m_light.Position.y, m_light.Position.z) );
  150. m_light.Range = 1000.0f;
  151. m_pd3dDevice->SetLight( 0, &m_light );
  152. m_pd3dDevice->LightEnable( 0, TRUE );
  153. m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  154. if( m_bUseTexture )
  155. m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xFF2F2F2F );
  156. else
  157. m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF );
  158. InitMaterials();
  159. // set 'reference' radius value
  160. m_radius = 1.0f;
  161. // convert tesselation from dwTesselFact(0.0-2.0) to tessLevel(0-MAX_TESS)
  162. int tessLevel = (int) (m_pConfig->dwTesselFact * (MAX_TESS+1) / 2.0001f);
  163. m_nSlices = (tessLevel+2) * 4;
  164. // Allocate basic NODE_ARRAY
  165. // NODE_ARRAY size is determined in Reshape (based on window size)
  166. m_nodes = new NODE_ARRAY;
  167. // Set drawing mode, and initialize accordingly. For now, either all normal
  168. // or all flex pipes are drawn, but they could be combined later.
  169. // Can assume here that if there's any possibility that normal pipes
  170. // will be drawn, NORMAL_STATE will be initialized so that dlists are
  171. // built
  172. // Again, since have either NORMAL or FLEX, set maxPipesPerFrame,
  173. // maxDrawThreads
  174. if( m_pConfig->bMultiPipes )
  175. m_maxDrawThreads = MAX_DRAW_THREADS;
  176. else
  177. m_maxDrawThreads = 1;
  178. m_nDrawThreads = 0; // no active threads yet
  179. m_nPipesDrawn = 0;
  180. // maxPipesPerFrame is set in Reset()
  181. // Create a square for rendering the clear transition
  182. SAFE_RELEASE( m_pClearVB );
  183. m_pd3dDevice->CreateVertexBuffer( 4*sizeof(D3DTLVERTEX),
  184. D3DUSAGE_WRITEONLY, D3DFVF_TLVERTEX,
  185. D3DPOOL_MANAGED, &m_pClearVB );
  186. // Size the background image
  187. D3DTLVERTEX* vBackground;
  188. m_pClearVB->Lock( 0, 0, (BYTE**)&vBackground, 0 );
  189. for( i=0; i<4; i ++ )
  190. {
  191. vBackground[i].p = D3DXVECTOR4( 0.0f, 0.0f, 0.95f, 1.0f );
  192. vBackground[i].color = 0x20000000;
  193. }
  194. vBackground[0].p.y = (FLOAT)m_view.m_winSize.height;
  195. vBackground[1].p.y = (FLOAT)m_view.m_winSize.height;
  196. vBackground[1].p.x = (FLOAT)m_view.m_winSize.width;
  197. vBackground[3].p.x = (FLOAT)m_view.m_winSize.width;
  198. m_pClearVB->Unlock();
  199. if( m_pConfig->bFlexMode )
  200. {
  201. m_drawMode = DRAW_FLEX;
  202. m_pFState = new FLEX_STATE( this );
  203. m_pNState = NULL;
  204. }
  205. else
  206. {
  207. m_drawMode = DRAW_NORMAL;
  208. m_pNState = new NORMAL_STATE( this );
  209. m_pFState = NULL;
  210. }
  211. return S_OK;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Name:
  215. // Desc:
  216. //-----------------------------------------------------------------------------
  217. HRESULT STATE::FrameMove( FLOAT fElapsedTime )
  218. {
  219. return S_OK;
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Name: Render
  223. // Desc: - Top-level pipe drawing routine
  224. // - Each pipe thread keeps drawing new pipes until we reach maximum number
  225. // of pipes per frame - then each thread gets killed as soon as it gets
  226. // stuck. Once number of drawing threads reaches 0, we start a new
  227. // frame
  228. //-----------------------------------------------------------------------------
  229. HRESULT STATE::Render()
  230. {
  231. int i;
  232. int nKilledThreads = 0;
  233. BOOL bChooseNewLead = FALSE;
  234. DRAW_THREAD* pThread;
  235. // Reset the frame if its time
  236. if( m_resetStatus != 0 )
  237. {
  238. if( FALSE == FrameReset() )
  239. return S_OK;
  240. }
  241. // Check each pipe's status
  242. pThread = m_drawThreads;
  243. for( i=0; i<m_nDrawThreads; i++ )
  244. {
  245. if( pThread->m_pPipe->IsStuck() )
  246. {
  247. m_nPipesDrawn++;
  248. if( m_nPipesDrawn > m_maxPipesPerFrame )
  249. {
  250. // Reaching pipe saturation - kill this pipe thread
  251. if( (m_drawScheme == FRAME_SCHEME_CHASE) &&
  252. (pThread->m_pPipe == m_pLeadPipe) )
  253. bChooseNewLead = TRUE;
  254. pThread->KillPipe();
  255. nKilledThreads++;
  256. }
  257. else
  258. {
  259. // Start up another pipe
  260. if( ! pThread->StartPipe() )
  261. {
  262. // we won't be able to draw any more pipes this frame
  263. // (probably out of nodes)
  264. m_maxPipesPerFrame = m_nPipesDrawn;
  265. }
  266. }
  267. }
  268. pThread++;
  269. }
  270. // Whenever one or more pipes are killed, compact the thread list
  271. if( nKilledThreads )
  272. {
  273. CompactThreadList();
  274. m_nDrawThreads -= nKilledThreads;
  275. }
  276. if( m_nDrawThreads == 0 )
  277. {
  278. // This frame is finished - mark for reset on next Draw
  279. m_resetStatus |= RESET_NORMAL_BIT;
  280. return S_OK;
  281. }
  282. if( bChooseNewLead )
  283. {
  284. // We're in 'chase mode' and need to pick a new lead pipe
  285. ChooseNewLeadPipe();
  286. }
  287. // Draw each pipe
  288. pThread = m_drawThreads;
  289. for( i=0; i<m_nDrawThreads; i++ )
  290. {
  291. pThread->Render();
  292. pThread++;
  293. }
  294. return S_OK;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Name:
  298. // Desc:
  299. //-----------------------------------------------------------------------------
  300. HRESULT STATE::InvalidateDeviceObjects()
  301. {
  302. int i;
  303. // Cleanup threads
  304. DRAW_THREAD* pThread = m_drawThreads;
  305. for( i=0; i<m_maxDrawThreads; i++ )
  306. {
  307. pThread->InvalidateDeviceObjects();
  308. pThread->DeleteDeviceObjects();
  309. pThread++;
  310. }
  311. SAFE_RELEASE( m_pClearVB );
  312. // Cleanup textures
  313. for( i=0; i<m_nTextures; i++ )
  314. {
  315. SAFE_RELEASE( m_textureInfo[i].pTexture );
  316. }
  317. SAFE_RELEASE( m_pWorldMatrixStack );
  318. return S_OK;
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Name:
  322. // Desc:
  323. //-----------------------------------------------------------------------------
  324. HRESULT STATE::DeleteDeviceObjects()
  325. {
  326. return S_OK;
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Name: STATE destructor
  330. // Desc:
  331. //-----------------------------------------------------------------------------
  332. STATE::~STATE()
  333. {
  334. SAFE_DELETE( m_pNState );
  335. SAFE_DELETE( m_pFState );
  336. SAFE_DELETE( m_nodes );
  337. // Delete any RC's - should be done by ~THREAD, but since common lib
  338. // deletes shareRC, have to do it here
  339. DRAW_THREAD* pThread = m_drawThreads;
  340. for( int i=0; i<m_maxDrawThreads; i++ )
  341. {
  342. pThread->KillPipe();
  343. pThread++;
  344. }
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Name: CalcTexRepFactors
  348. // Desc:
  349. //-----------------------------------------------------------------------------
  350. void STATE::CalcTexRepFactors()
  351. {
  352. ISIZE winSize;
  353. D3DXVECTOR2 texFact;
  354. winSize = m_view.m_winSize;
  355. // Figure out repetition factor of texture, based on bitmap size and
  356. // screen size.
  357. //
  358. // We arbitrarily decide to repeat textures that are smaller than
  359. // 1/8th of screen width or height.
  360. for( int i = 0; i < m_nTextures; i++ )
  361. {
  362. m_texRep[i].x = m_texRep[i].y = 1;
  363. if( (texFact.x = winSize.width / m_textureInfo[i].width / 8.0f) >= 1.0f)
  364. m_texRep[i].x = (int) (texFact.x+0.5f);
  365. if( (texFact.y = winSize.height / m_textureInfo[i].height / 8.0f) >= 1.0f)
  366. m_texRep[i].y = (int) (texFact.y+0.5f);
  367. }
  368. // ! If display list based normal pipes, texture repetition is embedded
  369. // in the dlists and can't be changed. So use the smallest rep factors.
  370. // mf: Should change this so smaller textures are replicated close to
  371. // the largest texture, then same rep factor will work well for all
  372. if( m_pNState )
  373. {
  374. //put smallest rep factors in texRep[0]; (mf:this is ok for now, as
  375. // flex pipes and normal pipes don't coexist)
  376. for( i = 1; i < m_nTextures; i++ )
  377. {
  378. if( m_texRep[i].x < m_texRep[0].x )
  379. m_texRep[0].x = m_texRep[i].x;
  380. if( m_texRep[i].y < m_texRep[0].y )
  381. m_texRep[0].y = m_texRep[i].y;
  382. }
  383. }
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Name: LoadTextureFiles
  387. // Desc: - Load user texture files. If texturing on but no user textures, or
  388. // problems loading them, load default texture resource
  389. // mf: later, may want to have > 1 texture resource
  390. //-----------------------------------------------------------------------------
  391. HRESULT STATE::LoadTextureFiles( int nTextures, TCHAR strTextureFileNames[MAX_PATH][MAX_TEXTURES], int* anDefaultTextureResource )
  392. {
  393. HRESULT hr;
  394. m_nTextures = 0;
  395. for( int i=0; i<nTextures; i++ )
  396. {
  397. SAFE_RELEASE( m_textureInfo[i].pTexture );
  398. if( !m_pConfig->bDefaultTexture )
  399. {
  400. WIN32_FIND_DATA findFileData;
  401. HANDLE hFind = FindFirstFile( strTextureFileNames[i], &findFileData);
  402. if (hFind != INVALID_HANDLE_VALUE)
  403. {
  404. // Load texture in strTextureFileNames[i] using D3DX
  405. hr = D3DXCreateTextureFromFileEx( m_pd3dDevice, strTextureFileNames[i],
  406. D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8,
  407. D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR,
  408. D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, &m_textureInfo[i].pTexture );
  409. if( FAILED( hr ) )
  410. {
  411. SAFE_RELEASE( m_textureInfo[i].pTexture );
  412. }
  413. }
  414. }
  415. if( m_textureInfo[i].pTexture == NULL )
  416. {
  417. // Load default texture in resource anDefaultTextureResource[i]
  418. hr = D3DXCreateTextureFromResourceEx( m_pd3dDevice, NULL, MAKEINTRESOURCE( anDefaultTextureResource[i] ),
  419. D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8,
  420. D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR,
  421. D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, &m_textureInfo[i].pTexture );
  422. if( FAILED( hr ) )
  423. {
  424. SAFE_RELEASE( m_textureInfo[i].pTexture );
  425. }
  426. }
  427. if( m_textureInfo[i].pTexture == NULL )
  428. {
  429. // Couldn't load texture
  430. return E_FAIL;
  431. }
  432. else
  433. {
  434. D3DSURFACE_DESC d3dDesc;
  435. ZeroMemory( &d3dDesc, sizeof(D3DSURFACE_DESC) );
  436. m_textureInfo[i].pTexture->GetLevelDesc( 0, &d3dDesc );
  437. m_textureInfo[i].width = d3dDesc.Width;
  438. m_textureInfo[i].height = d3dDesc.Height;
  439. }
  440. }
  441. m_nTextures = nTextures;
  442. CalcTexRepFactors();
  443. return S_OK;
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Name: Repaint
  447. // Desc: This is called when a WM_PAINT msg has been sent to the window. The paint
  448. // will overwrite the frame buffer, screwing up the scene if pipes is in single
  449. // buffer mode. We set resetStatus accordingly to clear things up on next
  450. // draw.
  451. //-----------------------------------------------------------------------------
  452. void STATE::Repaint()
  453. {
  454. m_resetStatus |= RESET_REPAINT_BIT;
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Name: Reshape
  458. // Desc: - called on resize, expose
  459. // - always called on app startup
  460. // - set new window size for VIEW object, and set resetStatus for validation
  461. // at draw time
  462. //-----------------------------------------------------------------------------
  463. void STATE::Reshape( int width, int height )
  464. {
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Name: ResetView
  468. // Desc: Called on FrameReset resulting from change in viewing paramters (e.g. from
  469. // a Resize event).
  470. //-----------------------------------------------------------------------------
  471. void STATE::ResetView()
  472. {
  473. IPOINT3D numNodes;
  474. // Have VIEW calculate the node array size based on view params
  475. m_view.CalcNodeArraySize( &numNodes );
  476. // Resize the node array
  477. m_nodes->Resize( &numNodes );
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Name: FrameReset
  481. // Desc: Start a new frame of pipes
  482. // The resetStatus parameter indicates what triggered the Reset.
  483. //-----------------------------------------------------------------------------
  484. BOOL STATE::FrameReset()
  485. {
  486. int i;
  487. float xRot = 0.0f;
  488. float zRot = 0.0f;
  489. // Kill off any active pipes ! (so they can shut down ok)
  490. DRAW_THREAD* pThread = m_drawThreads;
  491. for( i=0; i<m_nDrawThreads; i++ )
  492. {
  493. pThread->KillPipe();
  494. pThread++;
  495. }
  496. m_nDrawThreads = 0;
  497. // Clear the screen
  498. if( FALSE == Clear() )
  499. return FALSE;
  500. // Check for window resize status
  501. if( m_resetStatus & RESET_RESIZE_BIT )
  502. {
  503. ResetView();
  504. }
  505. // Reset the node states to empty
  506. m_nodes->Reset();
  507. // Call any pipe-specific state resets, and get any recommended
  508. // pipesPerFrame counts
  509. if( m_pNState )
  510. {
  511. m_pNState->Reset();
  512. }
  513. if( m_pFState )
  514. {
  515. m_pFState->Reset();
  516. //mf: maybe should figure out min spherical view dist
  517. xRot = CPipesScreensaver::fRand(-5.0f, 5.0f);
  518. zRot = CPipesScreensaver::fRand(-5.0f, 5.0f);
  519. }
  520. m_maxPipesPerFrame = CalcMaxPipesPerFrame();
  521. // Set new number of drawing threads
  522. if( m_maxDrawThreads > 1 )
  523. {
  524. // Set maximum # of pipes per frame
  525. m_maxPipesPerFrame = (int) (m_maxPipesPerFrame * 1.5);
  526. // Set # of draw threads
  527. m_nDrawThreads = SS_MIN( m_maxPipesPerFrame, CPipesScreensaver::iRand2( 2, m_maxDrawThreads ) );
  528. // Set chase mode if applicable, every now and then
  529. BOOL bUseChase = m_pNState || (m_pFState && m_pFState->OKToUseChase());
  530. if( bUseChase && (!CPipesScreensaver::iRand(5)) )
  531. {
  532. m_drawScheme = FRAME_SCHEME_CHASE;
  533. }
  534. }
  535. else
  536. {
  537. m_nDrawThreads = 1;
  538. }
  539. m_nPipesDrawn = 0;
  540. // for now, either all NORMAL or all FLEX for each frame
  541. pThread = m_drawThreads;
  542. for( i=0; i<m_nDrawThreads; i++ )
  543. {
  544. PIPE* pNewPipe;
  545. // Rotate Scene
  546. D3DXVECTOR3 xAxis = D3DXVECTOR3(1.0f,0.0f,0.0f);
  547. D3DXVECTOR3 yAxis = D3DXVECTOR3(0.0f,1.0f,0.0f);
  548. D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
  549. // Set up the modeling view
  550. m_pWorldMatrixStack->LoadIdentity();
  551. m_pWorldMatrixStack->RotateAxis( &yAxis, m_view.m_yRot );
  552. // create approppriate pipe for this thread slot
  553. switch( m_drawMode )
  554. {
  555. case DRAW_NORMAL:
  556. pNewPipe = (PIPE*) new NORMAL_PIPE(this);
  557. break;
  558. case DRAW_FLEX:
  559. // There are several kinds of FLEX pipes
  560. // so have FLEX_STATE decide which one to create
  561. pNewPipe = m_pFState->NewPipe( this );
  562. break;
  563. }
  564. pThread->SetPipe( pNewPipe );
  565. if( m_drawScheme == FRAME_SCHEME_CHASE )
  566. {
  567. if( i == 0 )
  568. {
  569. // this will be the lead pipe
  570. m_pLeadPipe = pNewPipe;
  571. pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
  572. }
  573. else
  574. {
  575. pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_CHASE );
  576. }
  577. }
  578. // If texturing, pick a random texture for this thread
  579. if( m_bUseTexture )
  580. {
  581. int index = PickRandomTexture( i, m_nTextures );
  582. pThread->SetTexture( &m_textureInfo[index] );
  583. // Flex pipes need to be informed of the texture, so they
  584. // can dynamically calculate various texture params
  585. if( m_pFState )
  586. ((FLEX_PIPE *) pNewPipe)->SetTexParams( &m_textureInfo[index],
  587. &m_texRep[index] );
  588. }
  589. // Launch the pipe (assumed: always more nodes than pipes starting, so
  590. // StartPipe cannot fail)
  591. // ! All pipe setup needs to be done before we call StartPipe, as this
  592. // is where the pipe starts drawing
  593. pThread->StartPipe();
  594. // Kind of klugey, but if in chase mode, I set chooseStartPos here,
  595. // since first startPos used in StartPipe() should be random
  596. if( (i == 0) && (m_drawScheme == FRAME_SCHEME_CHASE) )
  597. pNewPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
  598. pThread++;
  599. m_nPipesDrawn++;
  600. }
  601. // Increment scene rotation for normal reset case
  602. if( m_resetStatus & RESET_NORMAL_BIT )
  603. m_view.IncrementSceneRotation();
  604. // clear reset status
  605. m_resetStatus = 0;
  606. return TRUE;
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Name: CalcMaxPipesPerFrame
  610. // Desc:
  611. //-----------------------------------------------------------------------------
  612. int STATE::CalcMaxPipesPerFrame()
  613. {
  614. int nCount=0, fCount=0;
  615. if( m_pFState )
  616. fCount = m_pFState->GetMaxPipesPerFrame();
  617. if( m_pNState )
  618. nCount = m_bUseTexture ? NORMAL_TEX_PIPE_COUNT : NORMAL_PIPE_COUNT;
  619. return SS_MAX( nCount, fCount );
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Name: PickRandomTexture
  623. // Desc: Pick a random texture index from a list. Remove entry from list as it
  624. // is picked. Once all have been picked, or starting a new frame, reset.
  625. //-----------------------------------------------------------------------------
  626. int STATE::PickRandomTexture( int iThread, int nTextures )
  627. {
  628. if( nTextures == 0 )
  629. return 0;
  630. static int pickSet[MAX_TEXTURES] = {0};
  631. static int nPicked = 0;
  632. int i, index;
  633. if( iThread == 0 )
  634. {
  635. // new frame - force reset
  636. nPicked = nTextures;
  637. }
  638. // reset condition
  639. if( ++nPicked > nTextures )
  640. {
  641. for( i = 0; i < nTextures; i ++ ) pickSet[i] = 0;
  642. nPicked = 1; // cuz
  643. }
  644. // Pick a random texture index
  645. index = CPipesScreensaver::iRand( nTextures );
  646. while( pickSet[index] )
  647. {
  648. // this index has alread been taken, try the next one
  649. if( ++index >= nTextures )
  650. index = 0;
  651. }
  652. // Hopefully, the above loop will exit :). This means that we have
  653. // found a texIndex that is available
  654. pickSet[index] = 1; // mark as taken
  655. return index;
  656. }
  657. //-----------------------------------------------------------------------------
  658. // Name: Clear
  659. // Desc: Clear the screen. Depending on resetStatus, use normal clear or
  660. // fancy transitional clear.
  661. //-----------------------------------------------------------------------------
  662. BOOL STATE::Clear()
  663. {
  664. if( m_resetStatus & RESET_NORMAL_BIT )
  665. {
  666. // do the normal transitional clear
  667. static DWORD s_dwCount = 0;
  668. static FLOAT s_fLastStepTime = DXUtil_Timer( TIMER_GETAPPTIME );
  669. if( s_dwCount == 0 )
  670. s_dwCount = 30;
  671. float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
  672. if( fCurTime - s_fLastStepTime > 0.016 )
  673. {
  674. s_fLastStepTime = fCurTime;
  675. s_dwCount--;
  676. if( s_dwCount == 0 )
  677. {
  678. m_pd3dDevice->SetTexture( 0, NULL );
  679. m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  680. m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
  681. 0x00000000, 1.0f, 0L );
  682. return TRUE;
  683. }
  684. else
  685. {
  686. m_pd3dDevice->SetTexture( 0, NULL );
  687. m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  688. m_pd3dDevice->SetVertexShader( D3DFVF_TLVERTEX );
  689. m_pd3dDevice->SetStreamSource( 0, m_pClearVB, sizeof(D3DTLVERTEX) );
  690. m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  691. return FALSE;
  692. }
  693. }
  694. else
  695. {
  696. return FALSE;
  697. }
  698. }
  699. else
  700. {
  701. // do a fast one-shot clear
  702. m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
  703. 0x00000000, 1.0f, 0L );
  704. return TRUE;
  705. }
  706. }
  707. //-----------------------------------------------------------------------------
  708. // Name: DrawValidate
  709. // Desc: Validation done before every Draw
  710. // For now, this just involves checking resetStatus
  711. //-----------------------------------------------------------------------------
  712. void STATE::DrawValidate()
  713. {
  714. }
  715. //-----------------------------------------------------------------------------
  716. // Name: CompactThreadList
  717. // Desc: - Compact the thread list according to number of pipe threads killed
  718. // - The pipes have been killed, but the RC's in each slot are still valid
  719. // and reusable. So we swap up entries with valid pipes. This means that
  720. // the ordering of the RC's in the thread list will change during the life
  721. // of the program. This should be OK.
  722. //-----------------------------------------------------------------------------
  723. #define SWAP_SLOT( a, b ) \
  724. DRAW_THREAD pTemp; \
  725. pTemp = *(a); \
  726. *(a) = *(b); \
  727. *(b) = pTemp;
  728. void STATE::CompactThreadList()
  729. {
  730. if( m_nDrawThreads <= 1 )
  731. // If only one active thread, it must be in slot 0 from previous
  732. // compactions - so nothing to do
  733. return;
  734. int iEmpty = 0;
  735. DRAW_THREAD* pThread = m_drawThreads;
  736. for( int i=0; i<m_nDrawThreads; i++ )
  737. {
  738. if( pThread->m_pPipe )
  739. {
  740. if( iEmpty < i )
  741. {
  742. // swap active pipe thread and empty slot
  743. SWAP_SLOT( &(m_drawThreads[iEmpty]), pThread );
  744. }
  745. iEmpty++;
  746. }
  747. pThread++;
  748. }
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Name: ChooseNewLeadPipe
  752. // Desc: Choose a new lead pipe for chase mode.
  753. //-----------------------------------------------------------------------------
  754. void STATE::ChooseNewLeadPipe()
  755. {
  756. // Pick one of the active pipes at random to become the new lead
  757. int iLead = CPipesScreensaver::iRand( m_nDrawThreads );
  758. m_pLeadPipe = m_drawThreads[iLead].m_pPipe;
  759. m_pLeadPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
  760. m_pLeadPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Name: DRAW_THREAD constructor
  764. // Desc:
  765. //-----------------------------------------------------------------------------
  766. DRAW_THREAD::DRAW_THREAD()
  767. {
  768. m_pd3dDevice = NULL;
  769. m_pPipe = NULL;
  770. m_pTextureInfo = NULL;
  771. }
  772. //-----------------------------------------------------------------------------
  773. // Name: DRAW_THREAD destructor
  774. // Desc:
  775. //-----------------------------------------------------------------------------
  776. DRAW_THREAD::~DRAW_THREAD()
  777. {
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Name: SetPipe
  781. // Desc:
  782. //-----------------------------------------------------------------------------
  783. void DRAW_THREAD::SetPipe( PIPE* pPipe )
  784. {
  785. m_pPipe = pPipe;
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Name: SetTexture
  789. // Desc:
  790. //-----------------------------------------------------------------------------
  791. void DRAW_THREAD::SetTexture( TEXTUREINFO* pTextureInfo )
  792. {
  793. m_pTextureInfo = pTextureInfo;
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Name:
  797. // Desc:
  798. //-----------------------------------------------------------------------------
  799. HRESULT DRAW_THREAD::InitDeviceObjects( IDirect3DDevice8* pd3dDevice )
  800. {
  801. m_pd3dDevice = pd3dDevice;
  802. return S_OK;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Name:
  806. // Desc:
  807. //-----------------------------------------------------------------------------
  808. HRESULT DRAW_THREAD::RestoreDeviceObjects()
  809. {
  810. return S_OK;
  811. }
  812. //-----------------------------------------------------------------------------
  813. // Name:
  814. // Desc:
  815. //-----------------------------------------------------------------------------
  816. HRESULT DRAW_THREAD::FrameMove( FLOAT fElapsedTime )
  817. {
  818. return S_OK;
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Name: Render()
  822. // Desc: - Draw pipe in thread slot, according to its type
  823. //-----------------------------------------------------------------------------
  824. HRESULT DRAW_THREAD::Render()
  825. {
  826. m_pPipe->Draw();
  827. return S_OK;
  828. }
  829. //-----------------------------------------------------------------------------
  830. // Name:
  831. // Desc:
  832. //-----------------------------------------------------------------------------
  833. HRESULT DRAW_THREAD::InvalidateDeviceObjects()
  834. {
  835. return S_OK;
  836. }
  837. //-----------------------------------------------------------------------------
  838. // Name:
  839. // Desc:
  840. //-----------------------------------------------------------------------------
  841. HRESULT DRAW_THREAD::DeleteDeviceObjects()
  842. {
  843. return S_OK;
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Name: StartPipe
  847. // Desc: Starts up pipe of the approppriate type. If can't find an empty node
  848. // for the pipe to start on, returns FALSE;
  849. //-----------------------------------------------------------------------------
  850. BOOL DRAW_THREAD::StartPipe()
  851. {
  852. // call pipe-type specific Start function
  853. m_pPipe->Start();
  854. // check status
  855. if( m_pPipe->NowhereToRun() )
  856. return FALSE;
  857. else
  858. return TRUE;
  859. }
  860. //-----------------------------------------------------------------------------
  861. // Name: KillPipe
  862. // Desc:
  863. //-----------------------------------------------------------------------------
  864. void DRAW_THREAD::KillPipe()
  865. {
  866. SAFE_DELETE( m_pPipe );
  867. }