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.

695 lines
23 KiB

  1. #include "Swoosh.h"
  2. #include "Resource.h"
  3. #include <commdlg.h>
  4. #include <commctrl.h>
  5. #define SAFE_RELEASE(p) if(p){(p)->Release();(p)=NULL;};
  6. struct SimpleVertex
  7. {
  8. D3DXVECTOR3 pos;
  9. D3DCOLOR colour;
  10. float u,v;
  11. };
  12. #define FVF_SimpleVertex (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  13. #define PARTICLES_PER_VB 256
  14. typedef unsigned char UBYTE;
  15. CSwoosh g_Swoosh;
  16. const float pi = 3.1415926536f;
  17. const float pi2 = pi * 2.0f;
  18. const float TUBE_LENGTH = 20.0f;
  19. const float TUBE_RADIUS = 5.0f;
  20. const float FALLOFF_FACTOR = (255.0f/((TUBE_LENGTH*TUBE_LENGTH)+(TUBE_RADIUS*TUBE_RADIUS)))*0.98f;
  21. const float MAX_FLOW_RATE = 8.0f;
  22. const float MAX_ROLL_RATE = 4.0f;
  23. const float MAX_YAW_RATE = 5.0f;
  24. const float MIN_PARTICLE_SIZE = 0.01f;
  25. const float MAX_PARTICLE_SIZE = 0.5f;
  26. //**********************************************************************************
  27. int WINAPI WinMain( HINSTANCE hInstance , HINSTANCE , LPSTR lpCmdLine , int )
  28. {
  29. if ( FAILED(g_Swoosh.Create( hInstance )) )
  30. return -1;
  31. return g_Swoosh.Run();
  32. }
  33. //**********************************************************************************
  34. CSwoosh::CSwoosh()
  35. {
  36. D3DXMatrixLookAtLH( &m_Camera , &D3DXVECTOR3(0,0,0) , &D3DXVECTOR3(0,0,1) ,
  37. &D3DXVECTOR3(0,1,0) );
  38. m_fCameraYaw = m_fCameraRoll = 0;
  39. m_fYawDirection = 0;
  40. m_fYawPause = 6.0f;
  41. m_fParticleSize = 0.15f;
  42. m_dwNumParticles = MAX_PARTICLES;
  43. m_dwColourMix = 0x2000;
  44. m_dwColour1 = 0xffffff;
  45. m_dwColour2 = 0x0000ff;
  46. m_fFlowRate = 4.0f;
  47. m_fRollRate = 1.0f;
  48. m_fYawRate = 1.0f;
  49. m_dwFixedColour1 = 0xffffff;
  50. m_dwFixedColour2 = 0x1111ff;
  51. }
  52. //**********************************************************************************
  53. HRESULT CSwoosh::Create( HINSTANCE hInstance )
  54. {
  55. // Do base class Create
  56. HRESULT rc = CD3DScreensaver::Create( hInstance );
  57. if ( FAILED(rc) )
  58. return rc;
  59. // Initialise particles
  60. InitParticles();
  61. return S_OK;
  62. }
  63. //**********************************************************************************
  64. CSwoosh::DeviceObjects::DeviceObjects()
  65. {
  66. pBlobTexture = NULL;
  67. }
  68. //**********************************************************************************
  69. HRESULT CSwoosh::RegisterSoftwareDevice()
  70. {
  71. m_pD3D->RegisterSoftwareDevice( D3D8RGBRasterizer );
  72. return S_OK;
  73. }
  74. //**********************************************************************************
  75. void CSwoosh::InitParticles()
  76. {
  77. // Initialise particles, by evenly distributing them in a cylinder along the
  78. // z-axis [-30,30] with radius 3.0. Choose colours based on colour settings
  79. Particle* pparticle = m_Particles;
  80. for ( int i = 0 ; i < MAX_PARTICLES ; i++ )
  81. {
  82. // Pick z position for particle, evenly distribute in range [-TUBE_LENGTH,TUBE_LENGTH]
  83. pparticle->pos.z = (float(rand()&0x7fff) * (TUBE_LENGTH*2.0f/32767.0f)) - TUBE_LENGTH;
  84. // Pick (x,y) position for particle. We evenly distribute in a circle radius 3.0f
  85. float rad = (float(rand()&0x7fff) * (1.0f/32767.0f));
  86. rad = sqrtf(rad);
  87. rad *= TUBE_RADIUS;
  88. float angle = float(rand()&0x7fff) * (pi2/32767.0f);
  89. pparticle->pos.x = rad * sinf(angle);
  90. pparticle->pos.y = rad * cosf(angle);
  91. // Pick colour for particle. It's one of the two colour sets. Each colour set is
  92. // either one particular colour, or random (denoted by 0xffffffff)
  93. if ( DWORD(rand()&0x3fff) > m_dwColourMix )
  94. {
  95. if ( m_dwColour1 != 0xffffffff )
  96. pparticle->colour = m_dwColour1;
  97. else
  98. pparticle->colour = (rand()&0xff)|((rand()&0xff)<<8)|((rand()&0xff)<<16);
  99. }
  100. else
  101. {
  102. if ( m_dwColour2 != 0xffffffff )
  103. pparticle->colour = m_dwColour2;
  104. else
  105. pparticle->colour = (rand()&0xff)|((rand()&0xff)<<8)|((rand()&0xff)<<16);
  106. }
  107. pparticle++;
  108. }
  109. }
  110. //**********************************************************************************
  111. void CSwoosh::SetDevice( UINT iDevice )
  112. {
  113. // Point at the correct set of device data
  114. m_pDeviceObjects = &m_DeviceObjects[iDevice];
  115. // Figure out if vertices for this device should be software VP or not
  116. if ( m_RenderUnits[iDevice].dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  117. m_dwVertMemType = 0;
  118. else
  119. m_dwVertMemType = D3DUSAGE_SOFTWAREPROCESSING;
  120. }
  121. //**********************************************************************************
  122. HRESULT CSwoosh::RestoreDeviceObjects()
  123. {
  124. HRESULT rc;
  125. // Create "blob" texture
  126. rc = D3DXCreateTextureFromResource( m_pd3dDevice , NULL , MAKEINTRESOURCE(IDB_BLOB) ,
  127. &m_pDeviceObjects->pBlobTexture );
  128. if ( FAILED(rc) )
  129. return rc;
  130. // Create vertex buffer to hold particles
  131. rc = m_pd3dDevice->CreateVertexBuffer( sizeof(SimpleVertex)*4*PARTICLES_PER_VB ,
  132. D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|m_dwVertMemType ,
  133. FVF_SimpleVertex , D3DPOOL_DEFAULT ,
  134. &m_pDeviceObjects->pParticleVB );
  135. if ( FAILED(rc) )
  136. return rc;
  137. // Create index buffer to hold particle indices
  138. rc = m_pd3dDevice->CreateIndexBuffer( sizeof(WORD)*6*PARTICLES_PER_VB ,
  139. D3DUSAGE_WRITEONLY|m_dwVertMemType ,
  140. D3DFMT_INDEX16 , D3DPOOL_DEFAULT ,
  141. &m_pDeviceObjects->pParticleIB );
  142. if ( FAILED(rc) )
  143. return rc;
  144. // Populate index buffer with indices for a series of disjoint quads
  145. WORD* pidx;
  146. m_pDeviceObjects->pParticleIB->Lock( 0 , sizeof(WORD)*6*PARTICLES_PER_VB , (BYTE**)&pidx ,
  147. D3DLOCK_NOSYSLOCK );
  148. WORD index = 0;
  149. for ( int i = 0 ; i < PARTICLES_PER_VB ; i++ )
  150. {
  151. *pidx++ = index; *pidx++ = index+1; *pidx++ = index+3;
  152. *pidx++ = index; *pidx++ = index+3; *pidx++ = index+2;
  153. index += 4;
  154. }
  155. m_pDeviceObjects->pParticleIB->Unlock();
  156. // Set up world and view matrices
  157. D3DXMATRIX world;
  158. D3DXMatrixIdentity( &world );
  159. m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(0) , &world );
  160. m_pd3dDevice->SetTransform( D3DTS_VIEW , &m_Camera );
  161. // Set alpha blending mode to SRCALPHA:ONE
  162. m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , TRUE );
  163. m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
  164. m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND , D3DBLEND_ONE );
  165. // Set pixel pipe to single texture modulated by diffuse colour
  166. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLOROP , D3DTOP_MODULATE );
  167. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLORARG1 , D3DTA_TEXTURE );
  168. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLORARG2 , D3DTA_DIFFUSE );
  169. m_pd3dDevice->SetTextureStageState( 1 , D3DTSS_COLOROP , D3DTOP_DISABLE );
  170. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP , D3DTOP_SELECTARG2 );
  171. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE );
  172. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG2 , D3DTA_DIFFUSE );
  173. m_pd3dDevice->SetTextureStageState( 1 , D3DTSS_ALPHAOP , D3DTOP_DISABLE );
  174. // Bind "blob" texture to stage 0, and set filter mode to bilinear
  175. m_pd3dDevice->SetTexture( 0 , m_pDeviceObjects->pBlobTexture );
  176. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_MAGFILTER , D3DTEXF_LINEAR );
  177. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_MINFILTER , D3DTEXF_LINEAR );
  178. m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_MIPFILTER , D3DTEXF_POINT );
  179. // Disable culling, lighting, and specular
  180. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE , D3DCULL_NONE );
  181. m_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );
  182. m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE , FALSE );
  183. // Set vertex shader to fixed-function pipeline for SimpleVertex
  184. m_pd3dDevice->SetVertexShader( FVF_SimpleVertex );
  185. // Bind vertex stream 0 and index source to the particle VB/IB
  186. m_pd3dDevice->SetStreamSource( 0 , m_pDeviceObjects->pParticleVB , sizeof(SimpleVertex) );
  187. m_pd3dDevice->SetIndices( m_pDeviceObjects->pParticleIB , 0 );
  188. return S_OK;
  189. }
  190. //**********************************************************************************
  191. HRESULT CSwoosh::InvalidateDeviceObjects()
  192. {
  193. SAFE_RELEASE(m_pDeviceObjects->pParticleVB);
  194. SAFE_RELEASE(m_pDeviceObjects->pParticleIB);
  195. SAFE_RELEASE(m_pDeviceObjects->pBlobTexture);
  196. return S_OK;
  197. }
  198. //**********************************************************************************
  199. HRESULT CSwoosh::FrameMove()
  200. {
  201. UpdateParticles();
  202. UpdateCamera();
  203. return S_OK;
  204. }
  205. //**********************************************************************************
  206. void CSwoosh::UpdateCamera()
  207. {
  208. // Adjust camera roll
  209. m_fCameraRoll += m_fElapsedTime * m_fRollRate;
  210. // Adjust camera yaw. If we're not yawing, then countdown pause timer
  211. if ( m_fYawDirection == 0.0f )
  212. {
  213. m_fYawPause -= m_fElapsedTime;
  214. if ( m_fYawPause <= 0.0f )
  215. {
  216. // Done pausing, so reset timer and pick yaw direction
  217. m_fYawPause = 6.0f;
  218. if ( m_fCameraYaw == 0.0f )
  219. m_fYawDirection = m_fYawRate;
  220. else
  221. m_fYawDirection = -m_fYawRate;
  222. }
  223. }
  224. else
  225. {
  226. // Yawing, so adjust yaw parameter
  227. m_fCameraYaw += m_fElapsedTime * m_fYawDirection;
  228. // If we've hit the end, stop yawing
  229. if ( m_fYawDirection == m_fYawRate )
  230. {
  231. if ( m_fCameraYaw >= pi )
  232. {
  233. m_fCameraYaw = pi;
  234. m_fYawDirection = 0.0f;
  235. }
  236. }
  237. else
  238. {
  239. if ( m_fCameraYaw <= 0.0f )
  240. {
  241. m_fCameraYaw = 0.0f;
  242. m_fYawDirection = 0.0f;
  243. }
  244. }
  245. }
  246. // Compute matrices for roll and yaw components of orientation
  247. // We smooth out the yaw via a cos to give a nice slow rolloff at each end
  248. D3DXMATRIX roll,yaw;
  249. D3DXMatrixRotationZ( &roll , m_fCameraRoll );
  250. D3DXMatrixRotationY( &yaw , pi * 0.5f * (1.0f - cosf(m_fCameraYaw)) );
  251. D3DXMatrixLookAtLH( &m_Camera , &D3DXVECTOR3(0,0,0) , &D3DXVECTOR3(0,0,1) ,
  252. &D3DXVECTOR3(0,1,0) );
  253. // Compute final camera matrix
  254. m_Camera = m_Camera * yaw * roll;
  255. }
  256. //**********************************************************************************
  257. void CSwoosh::UpdateParticles()
  258. {
  259. Particle* pparticle = m_Particles;
  260. for ( DWORD i = 0 ; i < m_dwNumParticles ; i++ )
  261. {
  262. // Flow particle along cylinder
  263. pparticle->pos.z -= m_fElapsedTime * m_fFlowRate;
  264. // If we reached the end, warp to other end of cylinder
  265. if ( pparticle->pos.z < -TUBE_LENGTH )
  266. pparticle->pos.z += TUBE_LENGTH*2.0f;
  267. // Compute particle distance to camera and scale alpha
  268. // value by distance (to give slight fade out)
  269. float dist = (pparticle->pos.x * pparticle->pos.x) +
  270. (pparticle->pos.y * pparticle->pos.y) +
  271. (pparticle->pos.z * pparticle->pos.z);
  272. UBYTE alpha = UBYTE(255.0f - (dist * FALLOFF_FACTOR));
  273. pparticle->colour |= (alpha<<24);
  274. pparticle++;
  275. }
  276. }
  277. //**********************************************************************************
  278. HRESULT CSwoosh::Render()
  279. {
  280. // Clear the buffer, and set up projection matrix for this device
  281. m_pd3dDevice->Clear( 0 , NULL , D3DCLEAR_TARGET , 0 , 1.0f , 0 );
  282. SetProjectionMatrix( 0.1f , 200.0f );
  283. // Set camera
  284. m_pd3dDevice->SetTransform( D3DTS_VIEW , &m_Camera );
  285. m_pd3dDevice->BeginScene();
  286. RenderParticles();
  287. m_pd3dDevice->EndScene();
  288. return S_OK;
  289. }
  290. //**********************************************************************************
  291. void CSwoosh::RenderParticles()
  292. {
  293. DWORD particles_left = m_dwNumParticles;
  294. Particle* pparticle = m_Particles;
  295. // Compute offsets from particle center to make camera facing billboard
  296. // We cheat a little and use the same offsets for all the particles, orienting
  297. // them to be perpendicular to the view direction rather than to the view vector
  298. // to the particle centre. It's faster and the effect is close enough.
  299. D3DXVECTOR3 offset[4];
  300. D3DXVECTOR3 dx,dy;
  301. dx.x = m_Camera._11; dx.y = m_Camera._21; dx.z = m_Camera._31;
  302. dy.x = m_Camera._12; dy.y = m_Camera._22; dy.z = m_Camera._32;
  303. dx *= m_fParticleSize;
  304. dy *= m_fParticleSize;
  305. offset[0] = -dx+dy;
  306. offset[1] = dx+dy;
  307. offset[2] = -dx-dy;
  308. offset[3] = dx-dy;
  309. D3DXVECTOR3 look;
  310. look.x = m_Camera._13; look.y = m_Camera._23; look.z = m_Camera._33;
  311. DWORD batch_size = 0;
  312. SimpleVertex* pverts;
  313. m_pDeviceObjects->pParticleVB->Lock( 0 , 0 , (BYTE**)&pverts ,
  314. D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK );
  315. for ( DWORD i = 0 ; i < m_dwNumParticles ; i++ , pparticle++ )
  316. {
  317. // Don't render if it's behind us
  318. if ( ((pparticle->pos.x*look.x) + (pparticle->pos.y*look.y) +
  319. (pparticle->pos.z*look.z)) <= 0 )
  320. continue;
  321. // Tack particle onto buffer
  322. pverts->pos = pparticle->pos + offset[0];
  323. pverts->colour = pparticle->colour;
  324. pverts->u = 0; pverts->v = 0;
  325. pverts++;
  326. pverts->pos = pparticle->pos + offset[1];
  327. pverts->colour = pparticle->colour;
  328. pverts->u = 1; pverts->v = 0;
  329. pverts++;
  330. pverts->pos = pparticle->pos + offset[2];
  331. pverts->colour = pparticle->colour;
  332. pverts->u = 0; pverts->v = 1;
  333. pverts++;
  334. pverts->pos = pparticle->pos + offset[3];
  335. pverts->colour = pparticle->colour;
  336. pverts->u = 1; pverts->v = 1;
  337. pverts++;
  338. // If we've hit the buffer max, then flush it
  339. if ( ++batch_size == PARTICLES_PER_VB )
  340. {
  341. m_pDeviceObjects->pParticleVB->Unlock();
  342. m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 4*PARTICLES_PER_VB ,
  343. 0 , 2*PARTICLES_PER_VB );
  344. m_pDeviceObjects->pParticleVB->Lock( 0 , 0 , (BYTE**)&pverts ,
  345. D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK );
  346. batch_size = 0;
  347. }
  348. }
  349. // Flush last batch
  350. m_pDeviceObjects->pParticleVB->Unlock();
  351. if ( batch_size > 0 )
  352. {
  353. m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 4*batch_size ,
  354. 0 , 2*batch_size );
  355. }
  356. }
  357. //**********************************************************************************
  358. void CSwoosh::ReadSettings()
  359. {
  360. HKEY hkey;
  361. DWORD dwType = REG_DWORD;
  362. DWORD dwLength = sizeof(DWORD);
  363. // Couple of macros to reduce typing. We just want to check if the registry read was okay, if it wasn't
  364. // then we set a default value, if it was then we check against valid boundaries. For floats we also make
  365. // sure the float is finite (not NaN or +/-INF).
  366. #define DEFAULT_AND_BOUND(v,d,l,h) if (rc!=ERROR_SUCCESS){v=d;}else if(v<=l){v=l;}else if(v>h){v=h;};
  367. #define DEFAULT_AND_BOUND_FLOAT(v,d,l,h) if (rc!=ERROR_SUCCESS||!_finite(v)){v=d;}else if(v<l){v=l;}else if(v>h){v=h;};
  368. // Open our reg key
  369. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Swoosh"),
  370. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  371. {
  372. LONG rc;
  373. // Read NumParticles
  374. rc = RegQueryValueEx( hkey, TEXT("NumParticles"), NULL, &dwType, (BYTE*)&m_dwNumParticles, &dwLength);
  375. DEFAULT_AND_BOUND(m_dwNumParticles,MAX_PARTICLES/2,1,MAX_PARTICLES);
  376. // Read FlowRate (float, but we munge into DWORD datatype)
  377. rc = RegQueryValueEx( hkey, TEXT("fFlowRate"), NULL, &dwType, (BYTE*)&m_fFlowRate, &dwLength);
  378. DEFAULT_AND_BOUND_FLOAT(m_fFlowRate,4.0f,0,MAX_FLOW_RATE);
  379. // Read RollRate (float, but we munge into DWORD datatype)
  380. rc = RegQueryValueEx( hkey, TEXT("fRollRate"), NULL, &dwType, (BYTE*)&m_fRollRate, &dwLength);
  381. DEFAULT_AND_BOUND_FLOAT(m_fRollRate,1.0f,0,MAX_ROLL_RATE);
  382. // Read YawRate (float, but we munge into DWORD datatype)
  383. rc = RegQueryValueEx( hkey, TEXT("fYawRate"), NULL, &dwType, (BYTE*)&m_fYawRate, &dwLength);
  384. DEFAULT_AND_BOUND_FLOAT(m_fYawRate,1.0f,0,MAX_YAW_RATE);
  385. // Read ParticleSize (float, but we munge into DWORD datatype)
  386. rc = RegQueryValueEx( hkey, TEXT("fParticleSize"), NULL, &dwType, (BYTE*)&m_fParticleSize, &dwLength);
  387. DEFAULT_AND_BOUND_FLOAT(m_fParticleSize,0.15f,MIN_PARTICLE_SIZE,MAX_PARTICLE_SIZE);
  388. // Read ColourMix
  389. rc = RegQueryValueEx( hkey, TEXT("ColourMix"), NULL, &dwType, (BYTE*)&m_dwColourMix, &dwLength);
  390. DEFAULT_AND_BOUND(m_dwColourMix,0x2000,0,0x4000);
  391. // Read Colours
  392. rc = RegQueryValueEx( hkey, TEXT("Colour1"), NULL, &dwType, (BYTE*)&m_dwColour1, &dwLength);
  393. if ( rc != ERROR_SUCCESS )
  394. m_dwColour1 = 0xffffff;
  395. else if ( m_dwColour1 != 0xffffffff )
  396. m_dwColour1 &= 0x00ffffff;
  397. rc = RegQueryValueEx( hkey, TEXT("Colour2"), NULL, &dwType, (BYTE*)&m_dwColour2, &dwLength);
  398. if ( rc != ERROR_SUCCESS )
  399. m_dwColour2 = 0xffffffff;
  400. else if ( m_dwColour2 != 0xffffffff )
  401. m_dwColour2 &= 0x00ffffff;
  402. rc = RegQueryValueEx( hkey, TEXT("FixedColour1"), NULL, &dwType, (BYTE*)&m_dwFixedColour1, &dwLength);
  403. if ( rc != ERROR_SUCCESS )
  404. m_dwFixedColour1 = 0xffffff;
  405. else
  406. m_dwFixedColour1 &= 0x00ffffff;
  407. rc = RegQueryValueEx( hkey, TEXT("FixedColour2"), NULL, &dwType, (BYTE*)&m_dwFixedColour2, &dwLength);
  408. if ( rc != ERROR_SUCCESS )
  409. m_dwFixedColour2 = 0xffffff;
  410. else
  411. m_dwFixedColour2 &= 0x00ffffff;
  412. // Read settings for screen setup (multimon gubbins)
  413. ReadScreenSettings( hkey );
  414. // Done
  415. RegCloseKey( hkey );
  416. }
  417. }
  418. //**********************************************************************************
  419. void CSwoosh::WriteSettings()
  420. {
  421. HKEY hkey;
  422. DWORD dwType = REG_DWORD;
  423. DWORD dwLength = sizeof(DWORD);
  424. // Open our reg key
  425. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Swoosh"),
  426. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  427. {
  428. // Write out all the settings (we munge floats into DWORDs)
  429. RegSetValueEx( hkey, TEXT("NumParticles"), NULL, REG_DWORD, (BYTE*)&m_dwNumParticles, sizeof(DWORD) );
  430. RegSetValueEx( hkey, TEXT("ColourMix"), NULL, REG_DWORD, (BYTE*)&m_dwColourMix, sizeof(DWORD) );
  431. RegSetValueEx( hkey, TEXT("Colour1"), NULL, REG_DWORD, (BYTE*)&m_dwColour1, sizeof(DWORD) );
  432. RegSetValueEx( hkey, TEXT("Colour2"), NULL, REG_DWORD, (BYTE*)&m_dwColour2, sizeof(DWORD) );
  433. RegSetValueEx( hkey, TEXT("fFlowRate"), NULL, REG_DWORD, (BYTE*)&m_fFlowRate, sizeof(DWORD) );
  434. RegSetValueEx( hkey, TEXT("fRollRate"), NULL, REG_DWORD, (BYTE*)&m_fRollRate, sizeof(DWORD) );
  435. RegSetValueEx( hkey, TEXT("fYawRate"), NULL, REG_DWORD, (BYTE*)&m_fYawRate, sizeof(DWORD) );
  436. RegSetValueEx( hkey, TEXT("fParticleSize"), NULL, REG_DWORD, (BYTE*)&m_fParticleSize, sizeof(DWORD) );
  437. RegSetValueEx( hkey, TEXT("FixedColour1"), NULL, REG_DWORD, (BYTE*)&m_dwFixedColour1, sizeof(DWORD) );
  438. RegSetValueEx( hkey, TEXT("FixedColour2"), NULL, REG_DWORD, (BYTE*)&m_dwFixedColour2, sizeof(DWORD) );
  439. // Write screen settings out (multimon gubbins)
  440. WriteScreenSettings( hkey );
  441. // Done
  442. RegCloseKey( hkey );
  443. }
  444. }
  445. //**********************************************************************************
  446. void CSwoosh::DoConfig()
  447. {
  448. // Make sure we've got the common controls we need loaded
  449. InitCommonControls();
  450. // Do the dialog box
  451. DialogBox( m_hInstance , MAKEINTRESOURCE(IDD_SETTINGS) , NULL , ConfigDlgProcStub );
  452. }
  453. //**********************************************************************************
  454. BOOL CALLBACK CSwoosh::ConfigDlgProcStub( HWND hDlg , UINT msg , WPARAM wParam , LPARAM lParam )
  455. {
  456. return g_Swoosh.ConfigDlgProc( hDlg , msg , wParam , lParam );
  457. }
  458. //**********************************************************************************
  459. BOOL CSwoosh::ConfigDlgProc( HWND hDlg , UINT msg , WPARAM wParam , LPARAM lParam )
  460. {
  461. HWND hNumParticles = GetDlgItem( hDlg , IDC_NUM_PARTICLES );
  462. HWND hColourMix = GetDlgItem( hDlg , IDC_COLOUR_MIX );
  463. HWND hFlowRate = GetDlgItem( hDlg , IDC_FLOW_RATE );
  464. HWND hRollRate = GetDlgItem( hDlg , IDC_ROLL_RATE );
  465. HWND hYawRate = GetDlgItem( hDlg , IDC_YAW_RATE );
  466. HWND hParticleSize = GetDlgItem( hDlg , IDC_PARTICLE_SIZE );
  467. switch ( msg )
  468. {
  469. case WM_INITDIALOG:
  470. // Set up ranges on the sliders. Map floats into integer range [0,10000]
  471. SendMessage( hNumParticles , TBM_SETRANGE , FALSE , MAKELONG(0,MAX_PARTICLES) );
  472. SendMessage( hColourMix , TBM_SETRANGE , FALSE , MAKELONG(0,0x4000) );
  473. SendMessage( hFlowRate , TBM_SETRANGE , FALSE , MAKELONG(0,10000) );
  474. SendMessage( hRollRate , TBM_SETRANGE , FALSE , MAKELONG(0,10000) );
  475. SendMessage( hYawRate , TBM_SETRANGE , FALSE , MAKELONG(0,10000) );
  476. SendMessage( hParticleSize , TBM_SETRANGE , FALSE , MAKELONG(0,10000) );
  477. // Set initial values on the sliders
  478. SendMessage( hNumParticles , TBM_SETPOS , TRUE , m_dwNumParticles );
  479. SendMessage( hColourMix , TBM_SETPOS , TRUE , m_dwColourMix );
  480. SendMessage( hFlowRate , TBM_SETPOS , TRUE , DWORD(m_fFlowRate * (10000.0f/MAX_FLOW_RATE)) );
  481. SendMessage( hRollRate , TBM_SETPOS , TRUE , DWORD(m_fRollRate * (10000.0f/MAX_ROLL_RATE)) );
  482. SendMessage( hYawRate , TBM_SETPOS , TRUE , DWORD(m_fYawRate * (10000.0f/MAX_YAW_RATE)) );
  483. SendMessage( hParticleSize , TBM_SETPOS , TRUE ,
  484. DWORD((m_fParticleSize-MIN_PARTICLE_SIZE)*(10000.0f/(MAX_PARTICLE_SIZE-MIN_PARTICLE_SIZE))) );
  485. // Set up radio buttons for colour sets. Disable "pick.." button if multicoloured is selected
  486. if ( m_dwColour1 == 0xffffffff )
  487. {
  488. CheckRadioButton( hDlg , IDC_COLOUR1_MULTI , IDC_COLOUR1_FIXED , IDC_COLOUR1_MULTI );
  489. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR1_PICK ) , FALSE );
  490. }
  491. else
  492. CheckRadioButton( hDlg , IDC_COLOUR1_MULTI , IDC_COLOUR1_FIXED , IDC_COLOUR1_FIXED );
  493. if ( m_dwColour2 == 0xffffffff )
  494. {
  495. CheckRadioButton( hDlg , IDC_COLOUR2_MULTI , IDC_COLOUR2_FIXED , IDC_COLOUR2_MULTI );
  496. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR2_PICK ) , FALSE );
  497. }
  498. else
  499. CheckRadioButton( hDlg , IDC_COLOUR2_MULTI , IDC_COLOUR2_FIXED , IDC_COLOUR2_FIXED );
  500. return FALSE;
  501. case WM_COMMAND:
  502. switch ( LOWORD(wParam) )
  503. {
  504. case IDOK:
  505. ExtractDialogSettings( hDlg );
  506. WriteSettings();
  507. EndDialog( hDlg , IDOK );
  508. break;
  509. case IDCANCEL:
  510. EndDialog( hDlg , IDCANCEL );
  511. break;
  512. case IDC_SCREEN_SETTINGS:
  513. DoScreenSettingsDialog( hDlg );
  514. break;
  515. case IDC_COLOUR1_MULTI:
  516. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR1_PICK ) , FALSE );
  517. break;
  518. case IDC_COLOUR2_MULTI:
  519. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR2_PICK ) , FALSE );
  520. break;
  521. case IDC_COLOUR1_FIXED:
  522. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR1_PICK ) , TRUE );
  523. break;
  524. case IDC_COLOUR2_FIXED:
  525. EnableWindow( GetDlgItem( hDlg , IDC_COLOUR2_PICK ) , TRUE );
  526. break;
  527. case IDC_COLOUR1_PICK:
  528. m_dwFixedColour1 = PickColour( hDlg , m_dwFixedColour1 );
  529. break;
  530. case IDC_COLOUR2_PICK:
  531. m_dwFixedColour2 = PickColour( hDlg , m_dwFixedColour2 );
  532. break;
  533. }
  534. return TRUE;
  535. default:
  536. return FALSE;
  537. }
  538. }
  539. //**********************************************************************************
  540. DWORD CSwoosh::PickColour( HWND hParent , DWORD defcolour )
  541. {
  542. CHOOSECOLOR choose;
  543. static COLORREF custom[16];
  544. choose.lStructSize = sizeof(choose);
  545. choose.hwndOwner = hParent;
  546. choose.rgbResult = ((defcolour&0xff)<<16)|((defcolour&0xff00))|((defcolour&0xff0000)>>16);
  547. choose.lpCustColors = custom;
  548. choose.Flags = CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
  549. if ( ChooseColor( &choose ) )
  550. return ((choose.rgbResult&0xff)<<16)|((choose.rgbResult&0xff00)|(choose.rgbResult&0xff0000)>>16);
  551. else
  552. return defcolour;
  553. }
  554. //**********************************************************************************
  555. void CSwoosh::ExtractDialogSettings( HWND hDlg )
  556. {
  557. HWND hNumParticles = GetDlgItem( hDlg , IDC_NUM_PARTICLES );
  558. HWND hColourMix = GetDlgItem( hDlg , IDC_COLOUR_MIX );
  559. HWND hFlowRate = GetDlgItem( hDlg , IDC_FLOW_RATE );
  560. HWND hRollRate = GetDlgItem( hDlg , IDC_ROLL_RATE );
  561. HWND hYawRate = GetDlgItem( hDlg , IDC_YAW_RATE );
  562. HWND hParticleSize = GetDlgItem( hDlg , IDC_PARTICLE_SIZE );
  563. float f;
  564. m_dwNumParticles = SendMessage( hNumParticles , TBM_GETPOS , 0 , 0 );
  565. m_dwColourMix = SendMessage( hColourMix , TBM_GETPOS , 0 , 0 );
  566. f = (float)SendMessage( hFlowRate , TBM_GETPOS , 0 , 0 );
  567. m_fFlowRate = f * (MAX_FLOW_RATE/10000.0f);
  568. f = (float)SendMessage( hRollRate , TBM_GETPOS , 0 , 0 );
  569. m_fRollRate = f * (MAX_ROLL_RATE/10000.0f);
  570. f = (float)SendMessage( hYawRate , TBM_GETPOS , 0 , 0 );
  571. m_fYawRate = f * (MAX_YAW_RATE/10000.0f);
  572. f = (float)SendMessage( hParticleSize , TBM_GETPOS , 0 , 0 );
  573. m_fParticleSize = (f * ((MAX_PARTICLE_SIZE-MIN_PARTICLE_SIZE)/10000.0f)) + MIN_PARTICLE_SIZE;
  574. if ( IsDlgButtonChecked( hDlg , IDC_COLOUR1_MULTI ) )
  575. m_dwColour1 = 0xffffffff;
  576. else
  577. m_dwColour1 = m_dwFixedColour1;
  578. if ( IsDlgButtonChecked( hDlg , IDC_COLOUR2_MULTI ) )
  579. m_dwColour2 = 0xffffffff;
  580. else
  581. m_dwColour2 = m_dwFixedColour2;
  582. }