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.

1651 lines
49 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: FlowerBox.cpp
  3. //
  4. // Desc: Fun screen saver
  5. // Original OpenGL version by Drew Bliss
  6. // Ported to Direct3D 8.0 by Mike Anderson
  7. //
  8. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #include <windows.h>
  11. #include <tchar.h>
  12. #include <d3d8.h>
  13. #include <d3dx8.h>
  14. #include <d3d8rgbrast.h>
  15. #include <stdio.h>
  16. #include <commctrl.h>
  17. #include <scrnsave.h>
  18. #include "d3dsaver.h"
  19. #include "FlowerBox.h"
  20. #include "Resource.h"
  21. #include "dxutil.h"
  22. #ifndef GL_FRONT
  23. #define GL_FRONT 0x0404
  24. #endif
  25. #ifndef GL_FRONT_AND_BACK
  26. #define GL_FRONT_AND_BACK 0x0408
  27. #endif
  28. // Minimum and maximum image sizes
  29. #define MINIMAGESIZE 10
  30. #define MAXIMAGESIZE 100
  31. // Color tables for checkboard, per-side and single color modes
  32. FLOAT base_checker_cols[MAXSIDES][NCCOLS][4] =
  33. {
  34. 1.0f, 0.0f, 0.0f, 1.0f,
  35. 0.0f, 1.0f, 0.0f, 1.0f,
  36. 0.0f, 1.0f, 0.0f, 1.0f,
  37. 0.0f, 0.0f, 1.0f, 1.0f,
  38. 0.0f, 0.0f, 1.0f, 1.0f,
  39. 1.0f, 0.0f, 1.0f, 1.0f,
  40. 1.0f, 0.0f, 1.0f, 1.0f,
  41. 0.0f, 1.0f, 1.0f, 1.0f,
  42. 0.0f, 1.0f, 1.0f, 1.0f,
  43. 1.0f, 1.0f, 0.0f, 1.0f,
  44. 1.0f, 1.0f, 0.0f, 1.0f,
  45. 0.5f, 0.5f, 1.0f, 1.0f,
  46. 0.5f, 0.5f, 1.0f, 1.0f,
  47. 1.0f, 0.5f, 0.5f, 1.0f,
  48. 1.0f, 0.5f, 0.5f, 1.0f,
  49. 1.0f, 0.0f, 0.0f, 1.0f
  50. };
  51. FLOAT checker_cols[MAXSIDES][NCCOLS][4];
  52. FLOAT base_side_cols[MAXSIDES][4] =
  53. {
  54. 1.0f, 0.0f, 0.0f, 1.0f,
  55. 0.0f, 1.0f, 0.0f, 1.0f,
  56. 0.0f, 0.0f, 1.0f, 1.0f,
  57. 1.0f, 0.0f, 1.0f, 1.0f,
  58. 0.0f, 1.0f, 1.0f, 1.0f,
  59. 1.0f, 1.0f, 0.0f, 1.0f,
  60. 0.5f, 0.5f, 1.0f, 1.0f,
  61. 1.0f, 0.5f, 0.5f, 1.0f
  62. };
  63. FLOAT side_cols[MAXSIDES][4];
  64. FLOAT base_solid_cols[4] =
  65. {
  66. 1.0f, 1.0f, 1.0f, 1.0f
  67. };
  68. FLOAT solid_cols[4];
  69. // Default configuration
  70. CONFIG config =
  71. {
  72. TRUE, FALSE, FALSE, TRUE, TRUE, MAXSUBDIV, ID_COL_PER_SIDE,
  73. (MAXIMAGESIZE+MINIMAGESIZE)/2, GEOM_CUBE, GL_FRONT
  74. };
  75. // A slider range
  76. typedef struct _RANGE
  77. {
  78. INT min_val;
  79. INT max_val;
  80. INT step;
  81. INT page_step;
  82. } RANGE;
  83. RANGE complexity_range = {MINSUBDIV, MAXSUBDIV, 1, 2};
  84. RANGE image_size_range = {MINIMAGESIZE, MAXIMAGESIZE, 1, 10};
  85. // Values to map a 2D point onto a 3D plane
  86. // Base point and axes to map X and Y coordinates onto
  87. struct PLANE_MAP
  88. {
  89. D3DXVECTOR3 base, x_axis, y_axis;
  90. PLANE_MAP(D3DXVECTOR3 tbase, D3DXVECTOR3 tx_axis, D3DXVECTOR3 ty_axis)
  91. { base = tbase; x_axis = tx_axis; y_axis = ty_axis; }
  92. PLANE_MAP(VOID) {};
  93. };
  94. // Data area used by the current geometry
  95. // Base points and generated points
  96. D3DXVECTOR3 pts[MAXPTS], npts[MAXPTS];
  97. MYVERTEX vertices[MAXPTS];
  98. // Scaling factor for spherical projection
  99. FLOAT vlen[MAXPTS];
  100. // Normals
  101. D3DXVECTOR3 normals[MAXPTS];
  102. // Vertex data indices
  103. WORD index[MAXPTS*2];
  104. // Triangle strip sizes
  105. INT strip_size[MAXSIDES*MAXSUBDIV];
  106. VOID InitCube(GEOMETRY *geom);
  107. VOID InitTetra(GEOMETRY *geom);
  108. VOID InitPyramids(GEOMETRY *geom);
  109. VOID InitCylinder(GEOMETRY *geom);
  110. VOID InitSpring(GEOMETRY *geom);
  111. GEOMETRY cube_geom = {InitCube};
  112. GEOMETRY tetra_geom = {InitTetra};
  113. GEOMETRY pyramids_geom = {InitPyramids};
  114. GEOMETRY cylinder_geom = {InitCylinder};
  115. GEOMETRY spring_geom = {InitSpring};
  116. GEOMETRY *geom_table[] =
  117. {
  118. &cube_geom,
  119. &tetra_geom,
  120. &pyramids_geom,
  121. &cylinder_geom,
  122. &spring_geom
  123. };
  124. #define BUF_SIZE 255
  125. TCHAR g_szSectName[BUF_SIZE];
  126. TCHAR g_szFname[BUF_SIZE];
  127. CFlowerBoxScreensaver* g_pMyFlowerBoxScreensaver = NULL;
  128. //-----------------------------------------------------------------------------
  129. // Name: WinMain()
  130. // Desc: Entry point to the program. Initializes everything, and goes into a
  131. // message-processing loop. Idle time is used to render the scene.
  132. //-----------------------------------------------------------------------------
  133. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  134. {
  135. HRESULT hr;
  136. CFlowerBoxScreensaver flowerboxSS;
  137. if( FAILED( hr = flowerboxSS.Create( hInst ) ) )
  138. {
  139. flowerboxSS.DisplayErrorMsg( hr );
  140. return 0;
  141. }
  142. return flowerboxSS.Run();
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Name: CFlowerBoxScreensaver()
  146. // Desc: Constructor
  147. //-----------------------------------------------------------------------------
  148. CFlowerBoxScreensaver::CFlowerBoxScreensaver( )
  149. {
  150. g_pMyFlowerBoxScreensaver = this;
  151. LoadString( NULL, IDS_DESCRIPTION, m_strWindowTitle, 200 );
  152. m_bUseDepthBuffer = TRUE;
  153. lstrcpy( m_strRegPath, TEXT("Software\\Microsoft\\Screensavers\\Flowerbox") );
  154. m_xr = 0;
  155. m_yr = 0;
  156. m_zr = 0;
  157. m_sf = 0;
  158. m_sfi = 0;
  159. m_phase = 0.0f;
  160. m_pGeomCur = NULL;
  161. m_floatrect.xSize = 0.0f;
  162. InitCommonControls();
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Name: RegisterSoftwareDevice()
  166. // Desc: This can register the D3D8RGBRasterizer or any other
  167. // pluggable software rasterizer.
  168. //-----------------------------------------------------------------------------
  169. HRESULT CFlowerBoxScreensaver::RegisterSoftwareDevice()
  170. {
  171. m_pD3D->RegisterSoftwareDevice( D3D8RGBRasterizer );
  172. return S_OK;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Name: FrameMove()
  176. // Desc: Called once per frame, the call is the entry point for animating
  177. // the scene.
  178. //-----------------------------------------------------------------------------
  179. HRESULT CFlowerBoxScreensaver::FrameMove()
  180. {
  181. // update floatrect
  182. RECT rcBounceBounds;
  183. if( m_floatrect.xSize == 0.0f )
  184. {
  185. // Initialize floatrect
  186. RECT rcBounds;
  187. DWORD dwParentWidth;
  188. DWORD dwParentHeight;
  189. rcBounds = m_rcRenderTotal;
  190. dwParentWidth = rcBounds.right - rcBounds.left;
  191. dwParentHeight = rcBounds.bottom - rcBounds.top;
  192. FLOAT sizeFact;
  193. FLOAT sizeScale;
  194. DWORD size;
  195. sizeScale = (FLOAT)config.image_size / 150.0f;
  196. // sizeFact = 0.25f + (0.5f * sizeScale); // range 25-75%
  197. // size = (DWORD) (sizeFact * ( ((FLOAT)(dwParentWidth + dwParentHeight)) / 2.0f ));
  198. sizeFact = 0.25f + (0.75f * sizeScale); // range 25-100%
  199. size = (DWORD) (sizeFact * ( dwParentWidth > dwParentHeight ? dwParentHeight : dwParentWidth ) );
  200. if( size > dwParentWidth )
  201. size = dwParentWidth;
  202. if( size > dwParentHeight )
  203. size = dwParentHeight;
  204. // Start floatrect centered on primary
  205. m_floatrect.xMin = rcBounds.left + (dwParentWidth - size) / 2.0f;
  206. m_floatrect.yMin = rcBounds.top + (dwParentHeight - size) / 2.0f;
  207. m_floatrect.xSize = (FLOAT)size;
  208. m_floatrect.ySize = (FLOAT)size;
  209. m_floatrect.xVel = 0.01f * (FLOAT) size;
  210. m_floatrect.yVel = 0.01f * (FLOAT) size;
  211. }
  212. rcBounceBounds = m_rcRenderTotal;
  213. FLOAT xMinOld = m_floatrect.xMin;
  214. FLOAT yMinOld = m_floatrect.yMin;
  215. m_floatrect.xMin += m_floatrect.xVel * 20.0f * m_fElapsedTime;
  216. m_floatrect.yMin += m_floatrect.yVel * 20.0f * m_fElapsedTime;
  217. if( m_floatrect.xVel < 0 && m_floatrect.xMin < rcBounceBounds.left ||
  218. m_floatrect.xVel > 0 && (m_floatrect.xMin + m_floatrect.xSize) > rcBounceBounds.right )
  219. {
  220. m_floatrect.xMin = xMinOld; // undo last move
  221. m_floatrect.xVel = -m_floatrect.xVel; // change direction
  222. }
  223. if( m_floatrect.yVel < 0 && m_floatrect.yMin < rcBounceBounds.top ||
  224. m_floatrect.yVel > 0 && (m_floatrect.yMin + m_floatrect.ySize) > rcBounceBounds.bottom )
  225. {
  226. m_floatrect.yMin = yMinOld; // undo last move
  227. m_floatrect.yVel = -m_floatrect.yVel; // change direction
  228. }
  229. if (config.spin)
  230. {
  231. m_xr += 3 * 20.0f * m_fElapsedTime;
  232. m_yr += 2 * 20.0f * m_fElapsedTime;
  233. }
  234. if (config.bloom)
  235. {
  236. m_sf += m_sfi * 20.0f * m_fElapsedTime;
  237. if (m_sfi > 0.0f && m_sf > m_pGeomCur->max_sf ||
  238. m_sfi < 0.0f && m_sf < m_pGeomCur->min_sf )
  239. {
  240. m_sfi = -m_sfi;
  241. }
  242. UpdatePts(m_pGeomCur, m_sf);
  243. }
  244. if (config.cycle_colors)
  245. {
  246. ComputeHsvColors();
  247. m_phase += (FLOAT)(2.5 * 20.0f * m_fElapsedTime * D3DX_PI/180.);
  248. }
  249. return S_OK;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Name: Render()
  253. // Desc: Called once per frame, the call is the entry point for 3d
  254. // rendering. This function sets up render states, clears the
  255. // viewport, and renders the scene.
  256. //-----------------------------------------------------------------------------
  257. HRESULT CFlowerBoxScreensaver::Render()
  258. {
  259. D3DVIEWPORT8 vp;
  260. // First, clear the entire back buffer to the background color
  261. vp.X = 0;
  262. vp.Y = 0;
  263. vp.Width = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left;
  264. vp.Height = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top;
  265. vp.MinZ = 0.0f;
  266. vp.MaxZ = 1.0f;
  267. m_pd3dDevice->SetViewport( &vp );
  268. m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0L );
  269. // Now determine what part of the floatrect, if any, intersects the current screen
  270. RECT rcFloatThisScreen;
  271. RECT rcFloatThisScreenClipped;
  272. rcFloatThisScreen.left = (INT)m_floatrect.xMin;
  273. rcFloatThisScreen.top = (INT)m_floatrect.yMin;
  274. rcFloatThisScreen.right = rcFloatThisScreen.left + (INT)m_floatrect.xSize;
  275. rcFloatThisScreen.bottom = rcFloatThisScreen.top + (INT)m_floatrect.ySize;
  276. if( !IntersectRect(&rcFloatThisScreenClipped, &rcFloatThisScreen, &m_rcRenderCurDevice) )
  277. {
  278. return S_OK; // no intersection, so nothing further to render on this screen
  279. }
  280. // Convert rcFloatThisScreen from screen to window coordinates
  281. OffsetRect(&rcFloatThisScreen, -m_rcRenderCurDevice.left, -m_rcRenderCurDevice.top);
  282. OffsetRect(&rcFloatThisScreenClipped, -m_rcRenderCurDevice.left, -m_rcRenderCurDevice.top);
  283. // Now set up the viewport to render to the clipped rect
  284. vp.X = rcFloatThisScreenClipped.left;
  285. vp.Y = rcFloatThisScreenClipped.top;
  286. vp.Width = rcFloatThisScreenClipped.right - rcFloatThisScreenClipped.left;
  287. vp.Height = rcFloatThisScreenClipped.bottom - rcFloatThisScreenClipped.top;
  288. vp.MinZ = 0.0f;
  289. vp.MaxZ = 1.0f;
  290. m_pd3dDevice->SetViewport( &vp );
  291. // Now set up the projection matrix to only render the onscreen part of the
  292. // rect to the viewport
  293. D3DXMATRIX matProj;
  294. FLOAT l,r,b,t;
  295. l = -0.8f;
  296. r = 0.8f;
  297. b = 0.8f;
  298. t = -0.8f;
  299. FLOAT cxUnclipped = (rcFloatThisScreen.right + rcFloatThisScreen.left) / 2.0f;
  300. FLOAT cyUnclipped = (rcFloatThisScreen.bottom + rcFloatThisScreen.top) / 2.0f;
  301. l *= (rcFloatThisScreenClipped.left - cxUnclipped) / (rcFloatThisScreen.left - cxUnclipped);
  302. r *= (rcFloatThisScreenClipped.right - cxUnclipped) / (rcFloatThisScreen.right - cxUnclipped);
  303. t *= (rcFloatThisScreenClipped.top - cyUnclipped) / (rcFloatThisScreen.top - cyUnclipped);
  304. b *= (rcFloatThisScreenClipped.bottom - cyUnclipped) / (rcFloatThisScreen.bottom - cyUnclipped);
  305. D3DXMatrixPerspectiveOffCenterLH( &matProj, l, r, b, t, 2.0f, 5.0f );
  306. m_pd3dDevice->SetTransform( D3DTS_PROJECTION , &matProj );
  307. // Begin the scene
  308. if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  309. {
  310. D3DXMATRIX mat, matx, maty, matz;
  311. D3DXMatrixRotationX( &matx, D3DXToRadian( (FLOAT)m_xr ) );
  312. D3DXMatrixRotationY( &maty, D3DXToRadian( (FLOAT)m_yr ) );
  313. D3DXMatrixRotationZ( &matz, D3DXToRadian( (FLOAT)m_zr ) );
  314. mat = matx * maty * matz;
  315. m_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
  316. DrawGeom(m_pGeomCur);
  317. // End the scene.
  318. m_pd3dDevice->EndScene();
  319. }
  320. return S_OK;
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Name: RestoreDeviceObjects()
  324. // Desc:
  325. //-----------------------------------------------------------------------------
  326. HRESULT CFlowerBoxScreensaver::RestoreDeviceObjects()
  327. {
  328. if( m_pd3dDevice == NULL )
  329. return S_OK;
  330. D3DXMATRIX matView;
  331. D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
  332. D3DXVECTOR3 vEyePt(0, 0, 3.5f);
  333. D3DXVECTOR3 vLookatPt(0, 0, 0);
  334. D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  335. m_pd3dDevice->SetTransform( D3DTS_VIEW , &matView );
  336. D3DLIGHT8 light;
  337. ZeroMemory( &light, sizeof(D3DLIGHT8) );
  338. light.Type = D3DLIGHT_POINT;
  339. light.Diffuse.r = 1.0f;
  340. light.Diffuse.g = 1.0f;
  341. light.Diffuse.b = 1.0f;
  342. light.Diffuse.a = 1.0f;
  343. light.Specular.r = 1.0f;
  344. light.Specular.g = 1.0f;
  345. light.Specular.b = 1.0f;
  346. light.Specular.a = 1.0f;
  347. light.Position.x = 2.0;
  348. light.Position.y = 2.0;
  349. light.Position.z = 10.0;
  350. light.Range = 1000.0f;
  351. light.Attenuation0 = 1.0f;
  352. m_pd3dDevice->SetLight(0, &light);
  353. m_pd3dDevice->LightEnable(0, TRUE);
  354. // Set some basic renderstates
  355. m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE , TRUE );
  356. m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE , TRUE );
  357. m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  358. m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR(0x40404040 ) );
  359. if( config.two_sided == GL_FRONT_AND_BACK )
  360. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  361. else
  362. m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
  363. NewConfig(&config);
  364. return S_OK;
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Name: InvalidateDeviceObjects()
  368. // Desc:
  369. //-----------------------------------------------------------------------------
  370. HRESULT CFlowerBoxScreensaver::InvalidateDeviceObjects()
  371. {
  372. return S_OK;
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Name: InitVlen()
  376. // Desc: Precomputes scaling factor for spherical projection
  377. //-----------------------------------------------------------------------------
  378. VOID CFlowerBoxScreensaver::InitVlen(GEOMETRY *geom, INT npts, D3DXVECTOR3 *pts)
  379. {
  380. const FLOAT RADIUS = 1;
  381. FLOAT d;
  382. FLOAT *vl;
  383. vl = vlen;
  384. while (npts-- > 0)
  385. {
  386. d = D3DXVec3Length(pts);
  387. // Don't allow really close points because this leads to
  388. // numeric instability and really large objects
  389. // assert(d > 0.01f);
  390. // Geometries are created with size one, filling the area
  391. // from -.5 to .5. This leads to distances generally less
  392. // than one, which leaves off half of the interesting morphing
  393. // effects due to the projection
  394. // Scaling up the scaling factor allows the values to
  395. // be both above and below one
  396. d *= geom->init_sf;
  397. // assert(d > 0.0001f);
  398. *vl++ = (RADIUS-d)/d;
  399. pts++;
  400. }
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Name: MapToSide()
  404. // Desc: Takes x,y coordinates in the range 0-1 and maps them onto the given
  405. // side plane for the current geometry
  406. //-----------------------------------------------------------------------------
  407. VOID MapToSide(PLANE_MAP *map, FLOAT x, FLOAT y, D3DXVECTOR3 *pt)
  408. {
  409. pt->x = x*map->x_axis.x+y*map->y_axis.x+map->base.x;
  410. pt->y = x*map->x_axis.y+y*map->y_axis.y+map->base.y;
  411. pt->z = x*map->x_axis.z+y*map->y_axis.z+map->base.z;
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Name: InitCube()
  415. // Desc: Initializes the cube's geometry
  416. //-----------------------------------------------------------------------------
  417. VOID InitCube(GEOMETRY *geom)
  418. {
  419. const INT CUBE_SIDES = 6;
  420. PLANE_MAP cube_planes[CUBE_SIDES] =
  421. {
  422. PLANE_MAP(D3DXVECTOR3(-0.5f, -0.5f, 0.5f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 1.0f, 0.0f)),
  423. PLANE_MAP(D3DXVECTOR3( 0.5f, -0.5f, -0.5f), D3DXVECTOR3(-1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 1.0f, 0.0f)),
  424. PLANE_MAP(D3DXVECTOR3( 0.5f, 0.5f, -0.5f), D3DXVECTOR3(-1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f)),
  425. PLANE_MAP(D3DXVECTOR3(-0.5f, -0.5f, -0.5f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f)),
  426. PLANE_MAP(D3DXVECTOR3( 0.5f, -0.5f, -0.5f), D3DXVECTOR3( 0.0f, 1.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f)),
  427. PLANE_MAP(D3DXVECTOR3(-0.5f, 0.5f, -0.5f), D3DXVECTOR3( 0.0f, -1.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f))
  428. };
  429. INT side, x, y;
  430. D3DXVECTOR3 *pt;
  431. unsigned short/*INT*/ *idx;
  432. INT *sz;
  433. INT side_pts;
  434. side_pts = (config.subdiv+1)*(config.subdiv+1);
  435. geom->nsides = CUBE_SIDES;
  436. geom->pts = &pts[0];
  437. geom->npts = &npts[0];
  438. geom->normals = &normals[0];
  439. geom->pVertices = &vertices[0];
  440. geom->min_sf = -1.1f;
  441. geom->max_sf = 5.1f;
  442. geom->sf_inc = 0.05f;
  443. geom->init_sf = 2.0f;
  444. // Generate triangle strip data
  445. sz = &strip_size[0];
  446. idx = &index[0];
  447. for (side = 0; side < geom->nsides; side++)
  448. {
  449. geom->sides[side].nstrips = config.subdiv;
  450. geom->sides[side].strip_size = sz;
  451. geom->sides[side].strip_index = idx;
  452. for (x = 0; x < config.subdiv; x++)
  453. {
  454. *sz++ = (config.subdiv+1)*2;
  455. for (y = 0; y < config.subdiv+1; y++)
  456. {
  457. *idx++ = side * side_pts + x * (config.subdiv + 1) + y;
  458. *idx++ = side * side_pts + (x + 1) * (config.subdiv + 1) + y;
  459. }
  460. }
  461. }
  462. // Generate base vertices
  463. pt = geom->pts;
  464. for (side = 0; side < geom->nsides; side++)
  465. {
  466. for (x = 0; x < config.subdiv+1; x++)
  467. {
  468. for (y = 0; y < config.subdiv+1; y++)
  469. {
  470. MapToSide(&cube_planes[side],
  471. (FLOAT)x/config.subdiv, (FLOAT)y/config.subdiv,
  472. pt);
  473. pt++;
  474. }
  475. }
  476. }
  477. geom->total_pts = geom->nsides*side_pts;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Name: InitTetra()
  481. // Desc: Initializes the tetrahedron's geometry
  482. //-----------------------------------------------------------------------------
  483. VOID InitTetra(GEOMETRY *geom)
  484. {
  485. const INT TETRA_SIDES = 4;
  486. const FLOAT SQRT3 = 1.73205f;
  487. const FLOAT SQRT3_2 = (SQRT3/2.0f);
  488. const FLOAT SQRT3_3 = (SQRT3/3.0f);
  489. const FLOAT SQRT3_6 = (SQRT3/6.0f);
  490. const FLOAT SQRT3_12 = (SQRT3/12.0f);
  491. const FLOAT TETRA_BASE = (-SQRT3/8.0f);
  492. PLANE_MAP tetra_planes[TETRA_SIDES] =
  493. {
  494. PLANE_MAP(D3DXVECTOR3(-0.5f, TETRA_BASE, SQRT3_6), D3DXVECTOR3(1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, SQRT3_2, -SQRT3_6)),
  495. PLANE_MAP(D3DXVECTOR3(0.0f, TETRA_BASE, -SQRT3_3), D3DXVECTOR3(-0.5f, 0.0f, SQRT3_2), D3DXVECTOR3(0.25f, SQRT3_2, SQRT3_12)),
  496. PLANE_MAP(D3DXVECTOR3(0.5f, TETRA_BASE, SQRT3_6), D3DXVECTOR3(-0.5f, 0.0f, -SQRT3_2), D3DXVECTOR3(-0.25f, SQRT3_2, SQRT3_12)),
  497. PLANE_MAP(D3DXVECTOR3(0.5f, TETRA_BASE, SQRT3_6), D3DXVECTOR3(-1.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -SQRT3_2)),
  498. };
  499. INT side, x, y;
  500. D3DXVECTOR3 *pt;
  501. unsigned short/*INT*/ *idx;
  502. INT *sz;
  503. unsigned short side_pts;
  504. unsigned short base_pt;
  505. unsigned short row_pts;
  506. FLOAT fx;
  507. side_pts = (config.subdiv+2)*(config.subdiv+1)/2;
  508. geom->nsides = TETRA_SIDES;
  509. geom->pts = &pts[0];
  510. geom->npts = &npts[0];
  511. geom->normals = &normals[0];
  512. geom->pVertices = &vertices[0];
  513. geom->min_sf = -1.1f;
  514. geom->max_sf = 5.2f;
  515. geom->sf_inc = 0.05f;
  516. geom->init_sf = 3.75f;
  517. // Generate triangle strip data
  518. sz = &strip_size[0];
  519. idx = &index[0];
  520. base_pt = 0;
  521. for (side = 0; side < geom->nsides; side++)
  522. {
  523. geom->sides[side].nstrips = config.subdiv;
  524. geom->sides[side].strip_size = sz;
  525. geom->sides[side].strip_index = idx;
  526. for (x = 0; x < config.subdiv; x++)
  527. {
  528. row_pts = config.subdiv-x+1;
  529. *sz++ = row_pts*2-1;
  530. *idx++ = base_pt;
  531. for (y = 0; y < row_pts-1; y++)
  532. {
  533. *idx++ = base_pt+row_pts+y;
  534. *idx++ = base_pt+1+y;
  535. }
  536. base_pt += row_pts;
  537. }
  538. base_pt++;
  539. }
  540. // Generate base vertices
  541. pt = geom->pts;
  542. for (side = 0; side < geom->nsides; side++)
  543. {
  544. for (x = 0; x < config.subdiv+1; x++)
  545. {
  546. fx = (FLOAT)x/config.subdiv;
  547. for (y = 0; y < config.subdiv-x+1; y++)
  548. {
  549. MapToSide(&tetra_planes[side],
  550. fx+(FLOAT)y/(config.subdiv*2),
  551. (FLOAT)y/config.subdiv,
  552. pt);
  553. pt++;
  554. }
  555. }
  556. }
  557. geom->total_pts = geom->nsides*side_pts;
  558. }
  559. //-----------------------------------------------------------------------------
  560. // Name: InitPyramids()
  561. // Desc: Initializes double pyramid geometry
  562. //-----------------------------------------------------------------------------
  563. VOID InitPyramids(GEOMETRY *geom)
  564. {
  565. const INT PYRAMIDS_SIDES = 8;
  566. PLANE_MAP pyramids_planes[PYRAMIDS_SIDES] =
  567. {
  568. PLANE_MAP(D3DXVECTOR3(-0.5f, 0.0f, 0.5f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.5f, -0.5f)),
  569. PLANE_MAP(D3DXVECTOR3( 0.5f, 0.0f, 0.5f), D3DXVECTOR3(-1.0f, 0.0f, 0.0f), D3DXVECTOR3( 0.0f, -0.5f, -0.5f)),
  570. PLANE_MAP(D3DXVECTOR3( 0.5f, 0.0f, 0.5f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f), D3DXVECTOR3(-0.5f, 0.5f, 0.0f)),
  571. PLANE_MAP(D3DXVECTOR3( 0.5f, 0.0f, -0.5f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f), D3DXVECTOR3(-0.5f, -0.5f, 0.0f)),
  572. PLANE_MAP(D3DXVECTOR3( 0.5f, 0.0f, -0.5f), D3DXVECTOR3(-1.0f, 0.0f, 0.0f), D3DXVECTOR3( 0.0f, 0.5f, 0.5f)),
  573. PLANE_MAP(D3DXVECTOR3(-0.5f, 0.0f, -0.5f), D3DXVECTOR3( 1.0f, 0.0f, 0.0f), D3DXVECTOR3( 0.0f, -0.5f, 0.5f)),
  574. PLANE_MAP(D3DXVECTOR3(-0.5f, 0.0f, -0.5f), D3DXVECTOR3( 0.0f, 0.0f, 1.0f), D3DXVECTOR3( 0.5f, 0.5f, 0.0f)),
  575. PLANE_MAP(D3DXVECTOR3(-0.5f, 0.0f, 0.5f), D3DXVECTOR3( 0.0f, 0.0f, -1.0f), D3DXVECTOR3( 0.5f, -0.5f, 0.0f))
  576. };
  577. INT side, x, y;
  578. D3DXVECTOR3 *pt;
  579. unsigned short/*INT*/ *idx;
  580. INT *sz;
  581. unsigned short side_pts;
  582. unsigned short base_pt;
  583. unsigned short row_pts;
  584. FLOAT fx;
  585. side_pts = (config.subdiv+2)*(config.subdiv+1)/2;
  586. geom->nsides = PYRAMIDS_SIDES;
  587. geom->pts = &pts[0];
  588. geom->npts = &npts[0];
  589. geom->normals = &normals[0];
  590. geom->pVertices = &vertices[0];
  591. geom->min_sf = -1.1f;
  592. geom->max_sf = 5.2f;
  593. geom->sf_inc = 0.05f;
  594. geom->init_sf = 3.0f;
  595. // Generate triangle strip data
  596. sz = &strip_size[0];
  597. idx = &index[0];
  598. base_pt = 0;
  599. for (side = 0; side < geom->nsides; side++) {
  600. geom->sides[side].nstrips = config.subdiv;
  601. geom->sides[side].strip_size = sz;
  602. geom->sides[side].strip_index = idx;
  603. for (x = 0; x < config.subdiv; x++) {
  604. row_pts = config.subdiv-x+1;
  605. *sz++ = row_pts*2-1;
  606. *idx++ = base_pt;
  607. for (y = 0; y < row_pts-1; y++) {
  608. *idx++ = base_pt+row_pts+y;
  609. *idx++ = base_pt+1+y;
  610. }
  611. base_pt += row_pts;
  612. }
  613. base_pt++;
  614. }
  615. // Generate base vertices
  616. pt = geom->pts;
  617. for (side = 0; side < geom->nsides; side++)
  618. {
  619. for (x = 0; x < config.subdiv+1; x++)
  620. {
  621. fx = (FLOAT)x/config.subdiv;
  622. for (y = 0; y < config.subdiv-x+1; y++)
  623. {
  624. MapToSide(&pyramids_planes[side],
  625. fx+(FLOAT)y/(config.subdiv*2),
  626. (FLOAT)y/config.subdiv,
  627. pt);
  628. pt++;
  629. }
  630. }
  631. }
  632. geom->total_pts = geom->nsides*side_pts;
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Name: InitCylinder()
  636. // Desc: Initializes the cylinder geometry
  637. //-----------------------------------------------------------------------------
  638. VOID InitCylinder(GEOMETRY *geom)
  639. {
  640. unsigned short side, x, y;
  641. D3DXVECTOR3 *pt;
  642. unsigned short/*INT*/ *idx;
  643. INT *sz;
  644. unsigned short base_pt;
  645. unsigned short row_pts;
  646. FLOAT fx, fz;
  647. double ang;
  648. geom->nsides = 1;
  649. geom->pts = &pts[0];
  650. geom->npts = &npts[0];
  651. geom->normals = &normals[0];
  652. geom->pVertices = &vertices[0];
  653. geom->min_sf = -2.5f;
  654. geom->max_sf = 8.5f;
  655. geom->sf_inc = 0.05f;
  656. geom->init_sf = 2.1f;
  657. // Generate triangle strip data
  658. // If version 1.1 then allocate the index buffer for glDrawElements
  659. sz = &strip_size[0];
  660. idx = &index[0];
  661. side = 0;
  662. geom->sides[side].nstrips = config.subdiv;
  663. geom->sides[side].strip_size = sz;
  664. geom->sides[side].strip_index = idx;
  665. row_pts = config.subdiv+1;
  666. base_pt = 0;
  667. for (x = 0; x < config.subdiv; x++) {
  668. *sz++ = row_pts*2;
  669. for (y = 0; y < row_pts; y++) {
  670. // Wrap around at the edge so the cylinder normals
  671. // are properly averaged
  672. if (x == config.subdiv-1) {
  673. *idx++ = y;
  674. }
  675. else {
  676. *idx++ = base_pt+row_pts+y;
  677. }
  678. *idx++ = base_pt+y;
  679. }
  680. base_pt += row_pts;
  681. }
  682. // Generate base vertices
  683. pt = geom->pts;
  684. ang = 0;
  685. for (x = 0; x < config.subdiv; x++)
  686. {
  687. fx = (FLOAT)cos(ang)*0.5f;
  688. fz = (FLOAT)sin(ang)*0.5f;
  689. for (y = 0; y < config.subdiv+1; y++)
  690. {
  691. pt->x = fx;
  692. pt->y = (FLOAT)y/config.subdiv-0.5f;
  693. pt->z = fz;
  694. pt++;
  695. }
  696. ang += (2*D3DX_PI)/config.subdiv;
  697. }
  698. geom->total_pts = geom->nsides*(config.subdiv+1)*config.subdiv;
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Name: InitSpring()
  702. // Desc: Initializes the spring geometry
  703. //-----------------------------------------------------------------------------
  704. VOID InitSpring(GEOMETRY *geom)
  705. {
  706. const FLOAT SPRING_RADIUS = 0.1f;
  707. const FLOAT SPRING_CENTER = (0.5f-SPRING_RADIUS);
  708. INT side, x, y;
  709. D3DXVECTOR3 *pt;
  710. unsigned short/*INT*/ *idx;
  711. INT *sz;
  712. double ang_center, ang_surf;
  713. FLOAT cs, sn;
  714. FLOAT rad;
  715. PLANE_MAP plane;
  716. INT spin_pts;
  717. INT row_pts;
  718. geom->nsides = 1;
  719. geom->pts = &pts[0];
  720. geom->npts = &npts[0];
  721. geom->normals = &normals[0];
  722. geom->pVertices = &vertices[0];
  723. geom->min_sf = -2.2f;
  724. geom->max_sf = 0.2f;
  725. geom->sf_inc = 0.05f;
  726. geom->init_sf = 1.0f;
  727. // Generate triangle strip data
  728. // If version 1.1 then allocate the index buffer for glDrawElements
  729. sz = &strip_size[0];
  730. idx = &index[0];
  731. side = 0;
  732. geom->sides[side].nstrips = config.subdiv;
  733. geom->sides[side].strip_size = sz;
  734. geom->sides[side].strip_index = idx;
  735. row_pts = config.subdiv;
  736. spin_pts = 4*config.subdiv+1;
  737. for (x = 0; x < config.subdiv; x++) {
  738. *sz++ = spin_pts*2;
  739. for (y = 0; y < spin_pts; y++) {
  740. *idx++ = x+row_pts*y;
  741. // Wrap around at the edge so the cylindrical surface
  742. // of the tube is seamless. Without this the normal
  743. // averaging would be incorrect and a seam would be visible
  744. if (x == config.subdiv-1) {
  745. *idx++ = row_pts*y;
  746. }
  747. else {
  748. *idx++ = x+row_pts*y+1;
  749. }
  750. }
  751. }
  752. // Generate base vertices
  753. pt = geom->pts;
  754. ang_center = 0;
  755. plane.y_axis.x = 0.0f;
  756. plane.y_axis.y = SPRING_RADIUS;
  757. plane.y_axis.z = 0.0f;
  758. plane.x_axis.y = 0.0f;
  759. for (x = 0; x < spin_pts; x++)
  760. {
  761. cs = (FLOAT)cos(ang_center);
  762. sn = (FLOAT)sin(ang_center);
  763. rad = 0.5f-(FLOAT)x/(spin_pts-1)*(SPRING_CENTER/2);
  764. plane.base.x = cs*rad;
  765. plane.base.y = -0.5f+(FLOAT)x/(spin_pts-1);
  766. plane.base.z = sn*rad;
  767. plane.x_axis.x = cs*SPRING_RADIUS;
  768. plane.x_axis.z = sn*SPRING_RADIUS;
  769. ang_surf = 0;
  770. for (y = 0; y < config.subdiv; y++)
  771. {
  772. MapToSide(&plane,
  773. (FLOAT)cos(ang_surf), (FLOAT)sin(ang_surf),
  774. pt);
  775. pt++;
  776. ang_surf += (2*D3DX_PI)/config.subdiv;
  777. }
  778. ang_center += (4*D3DX_PI)/(spin_pts-1);
  779. }
  780. geom->total_pts = geom->nsides*spin_pts*config.subdiv;
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Name: DrawGeom()
  784. // Desc: Draw the current geometry
  785. //-----------------------------------------------------------------------------
  786. VOID CFlowerBoxScreensaver::DrawGeom(GEOMETRY *geom)
  787. {
  788. if (config.smooth_colors)
  789. m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
  790. else
  791. m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
  792. if (config.color_pick == ID_COL_SINGLE)
  793. SetMaterialColor(solid_cols);
  794. for( INT i = 0; i < geom->total_pts; i++ )
  795. {
  796. geom->pVertices[i].p = *(D3DXVECTOR3*)&geom->npts[i];
  797. D3DXVec3Normalize( &geom->pVertices[i].n, (D3DXVECTOR3*)&geom->normals[i] );
  798. }
  799. m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX );
  800. WORD col0Indices[5000];
  801. INT numCol0Indices;
  802. WORD col1Indices[5000];
  803. INT numCol1Indices;
  804. INT side;
  805. INT strip;
  806. INT triangle;
  807. unsigned short *idx;
  808. BOOL bBackwards; // triangle backwards for original strip implementation
  809. BOOL bCol0; // col0 or col1 for this triangle?
  810. INT numThisColor; // num tris done in this color; helps determine bCol0
  811. for (side = 0; side < geom->nsides; side++)
  812. {
  813. numCol0Indices = 0;
  814. numCol1Indices = 0;
  815. bCol0 = TRUE;
  816. idx = geom->sides[side].strip_index;
  817. for (strip = 0; strip < geom->sides[side].nstrips; strip++, idx += 2)
  818. {
  819. numThisColor = 0;
  820. if( !config.triangle_colors )
  821. numThisColor++;
  822. bBackwards = FALSE;
  823. if( config.color_pick == ID_COL_CHECKER )
  824. bCol0 = ( strip & 1 );
  825. for( triangle = 0; triangle < geom->sides[side].strip_size[strip] - 2; triangle++ )
  826. {
  827. if( config.color_pick == ID_COL_CHECKER )
  828. {
  829. numThisColor++;
  830. if( numThisColor == 2 )
  831. {
  832. bCol0 = !bCol0;
  833. numThisColor = 0;
  834. }
  835. }
  836. if( bCol0 )
  837. {
  838. if( bBackwards )
  839. {
  840. col0Indices[numCol0Indices++] = *(idx+1);
  841. col0Indices[numCol0Indices++] = *(idx+0);
  842. col0Indices[numCol0Indices++] = *(idx+2);
  843. }
  844. else
  845. {
  846. col0Indices[numCol0Indices++] = *(idx+0);
  847. col0Indices[numCol0Indices++] = *(idx+1);
  848. col0Indices[numCol0Indices++] = *(idx+2);
  849. }
  850. }
  851. else
  852. {
  853. if( bBackwards )
  854. {
  855. col1Indices[numCol1Indices++] = *(idx+1);
  856. col1Indices[numCol1Indices++] = *(idx+0);
  857. col1Indices[numCol1Indices++] = *(idx+2);
  858. }
  859. else
  860. {
  861. col1Indices[numCol1Indices++] = *(idx+0);
  862. col1Indices[numCol1Indices++] = *(idx+1);
  863. col1Indices[numCol1Indices++] = *(idx+2);
  864. }
  865. }
  866. idx ++;
  867. bBackwards = !bBackwards;
  868. }
  869. }
  870. // Draw this side's col0 primitives
  871. if (config.color_pick == ID_COL_PER_SIDE)
  872. SetMaterialColor(side_cols[side]);
  873. else if (config.color_pick == ID_COL_CHECKER)
  874. SetMaterialColor(checker_cols[side][0]);
  875. m_pd3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0,
  876. geom->total_pts, numCol0Indices / 3,
  877. col0Indices, D3DFMT_INDEX16, &geom->pVertices[0], sizeof(MYVERTEX) );
  878. // Draw this side's col1 primitives, if any
  879. if (config.color_pick == ID_COL_CHECKER)
  880. {
  881. SetMaterialColor(checker_cols[side][1]);
  882. m_pd3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0,
  883. geom->total_pts, numCol1Indices / 3,
  884. col1Indices, D3DFMT_INDEX16, &geom->pVertices[0], sizeof(MYVERTEX) );
  885. }
  886. }
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Name: ComputeAveragedNormals()
  890. // Desc: Compute face-averaged normals for each vertex
  891. //-----------------------------------------------------------------------------
  892. VOID ComputeAveragedNormals(GEOMETRY *geom)
  893. {
  894. INT side, strip;
  895. INT *sz;
  896. unsigned short/*INT*/ *idx;
  897. INT idx1, idx2, idx3;
  898. INT tc, idc;
  899. D3DXVECTOR3 v1, v2, n1;
  900. memset(geom->normals, 0, sizeof(D3DXVECTOR3)*geom->total_pts);
  901. for (side = 0; side < geom->nsides; side++)
  902. {
  903. idx = geom->sides[side].strip_index;
  904. sz = geom->sides[side].strip_size;
  905. for (strip = 0; strip < geom->sides[side].nstrips; strip++)
  906. {
  907. idx1 = *idx++;
  908. idx2 = *idx++;
  909. // assert(idx1 >= 0 && idx1 < geom->total_pts &&
  910. // idx2 >= 0 && idx2 < geom->total_pts);
  911. tc = (*sz++)-2;
  912. for (idc = 0; idc < tc; idc++)
  913. {
  914. idx3 = *idx++;
  915. // assert(idx3 >= 0 && idx3 < geom->total_pts);
  916. v1 = geom->npts[idx3] - geom->npts[idx1];
  917. v2 = geom->npts[idx2] - geom->npts[idx1];
  918. D3DXVec3Cross( &n1, &v1, &v2 );
  919. // Triangle strip ordering causes half of the triangles
  920. // to be oriented oppositely from the others
  921. // Those triangles need to have their normals flipped
  922. // so the whole triangle strip has consistent normals
  923. if ((idc & 1) == 0)
  924. {
  925. n1.x = -n1.x;
  926. n1.y = -n1.y;
  927. n1.z = -n1.z;
  928. }
  929. geom->normals[idx1] += n1;
  930. geom->normals[idx2] += n1;
  931. geom->normals[idx3] += n1;
  932. idx1 = idx2;
  933. idx2 = idx3;
  934. }
  935. }
  936. }
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Name: UpdatePts()
  940. // Desc:
  941. //-----------------------------------------------------------------------------
  942. VOID CFlowerBoxScreensaver::UpdatePts(GEOMETRY *geom, FLOAT sf)
  943. {
  944. INT pt;
  945. FLOAT f, *vl;
  946. D3DXVECTOR3 *v;
  947. D3DXVECTOR3 *p;
  948. vl = vlen;
  949. p = &geom->pts[0];
  950. v = &geom->npts[0];
  951. for (pt = 0; pt < geom->total_pts; pt++)
  952. {
  953. f = (*vl++)*sf+1;
  954. v->x = p->x*f;
  955. v->y = p->y*f;
  956. v->z = p->z*f;
  957. p++;
  958. v++;
  959. }
  960. ComputeAveragedNormals(geom);
  961. }
  962. //-----------------------------------------------------------------------------
  963. // Name: ComputeHsvColors()
  964. // Desc:
  965. //-----------------------------------------------------------------------------
  966. VOID CFlowerBoxScreensaver::ComputeHsvColors(VOID)
  967. {
  968. FLOAT *cols;
  969. INT ncols;
  970. FLOAT ang, da;
  971. INT hex;
  972. FLOAT fhex, frac;
  973. FLOAT p, q, t;
  974. FLOAT sat, val;
  975. switch(config.color_pick)
  976. {
  977. case ID_COL_CHECKER:
  978. ncols = MAXSIDES*NCCOLS;
  979. cols = &checker_cols[0][0][0];
  980. break;
  981. case ID_COL_PER_SIDE:
  982. ncols = MAXSIDES;
  983. cols = &side_cols[0][0];
  984. break;
  985. case ID_COL_SINGLE:
  986. ncols = 1;
  987. cols = &solid_cols[0];
  988. break;
  989. }
  990. ang = m_phase;
  991. da = (FLOAT)((2*D3DX_PI)/ncols);
  992. val = sat = 1.0f;
  993. while (ncols > 0)
  994. {
  995. fhex = (FLOAT)(6*ang/(2*D3DX_PI));
  996. hex = (INT)fhex;
  997. frac = fhex-hex;
  998. hex = hex % 6;
  999. p = val*(1-sat);
  1000. q = val*(1-sat*frac);
  1001. t = val*(1-sat*(1-frac));
  1002. switch(hex)
  1003. {
  1004. case 0:
  1005. cols[0] = val;
  1006. cols[1] = t;
  1007. cols[2] = p;
  1008. break;
  1009. case 1:
  1010. cols[0] = q;
  1011. cols[1] = val;
  1012. cols[2] = p;
  1013. break;
  1014. case 2:
  1015. cols[0] = p;
  1016. cols[1] = val;
  1017. cols[2] = t;
  1018. break;
  1019. case 3:
  1020. cols[0] = p;
  1021. cols[1] = q;
  1022. cols[2] = val;
  1023. break;
  1024. case 4:
  1025. cols[0] = t;
  1026. cols[1] = p;
  1027. cols[2] = val;
  1028. break;
  1029. case 5:
  1030. cols[0] = val;
  1031. cols[1] = p;
  1032. cols[2] = q;
  1033. break;
  1034. }
  1035. ang += da;
  1036. cols += 4;
  1037. ncols--;
  1038. }
  1039. }
  1040. //-----------------------------------------------------------------------------
  1041. // Name: NewConfig()
  1042. // Desc:
  1043. //-----------------------------------------------------------------------------
  1044. VOID CFlowerBoxScreensaver::NewConfig(CONFIG *cnf)
  1045. {
  1046. // Set new config
  1047. config = *cnf;
  1048. HKEY hkey;
  1049. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath,
  1050. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  1051. {
  1052. DXUtil_WriteBoolRegKey( hkey, TEXT("Smooth"), config.smooth_colors );
  1053. DXUtil_WriteBoolRegKey( hkey, TEXT("Slanted"), config.triangle_colors );
  1054. DXUtil_WriteBoolRegKey( hkey, TEXT("Cycle"), config.cycle_colors );
  1055. DXUtil_WriteBoolRegKey( hkey, TEXT("Spin"), config.spin );
  1056. DXUtil_WriteBoolRegKey( hkey, TEXT("Bloom"), config.bloom );
  1057. DXUtil_WriteIntRegKey( hkey, TEXT("Subdiv"), config.subdiv );
  1058. DXUtil_WriteIntRegKey( hkey, TEXT("ColorPick"), config.color_pick );
  1059. DXUtil_WriteIntRegKey( hkey, TEXT("ImageSize"), config.image_size );
  1060. DXUtil_WriteIntRegKey( hkey, TEXT("Geom"), config.geom );
  1061. DXUtil_WriteIntRegKey( hkey, TEXT("TwoSided"), config.two_sided );
  1062. WriteScreenSettings( hkey );
  1063. RegCloseKey( hkey );
  1064. }
  1065. // Reset colors
  1066. memcpy(checker_cols, base_checker_cols, sizeof(checker_cols));
  1067. memcpy(side_cols, base_side_cols, sizeof(side_cols));
  1068. memcpy(solid_cols, base_solid_cols, sizeof(solid_cols));
  1069. // Reset geometry
  1070. m_pGeomCur = geom_table[config.geom];
  1071. m_pGeomCur->init(m_pGeomCur);
  1072. // assert(m_pGeomCur->total_pts <= MAXPTS);
  1073. InitVlen(m_pGeomCur, m_pGeomCur->total_pts, m_pGeomCur->pts);
  1074. m_sf = 0.0f;
  1075. m_sfi = m_pGeomCur->sf_inc;
  1076. UpdatePts(m_pGeomCur, m_sf);
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. // Name: SetupTrackbar()
  1080. // Desc: Setup a common control trackbar
  1081. //-----------------------------------------------------------------------------
  1082. VOID SetupTrackbar( HWND hDlg, INT item, INT lo, INT hi, INT lineSize,
  1083. INT pageSize, INT pos )
  1084. {
  1085. SendDlgItemMessage(
  1086. hDlg,
  1087. item,
  1088. TBM_SETRANGE,
  1089. (WPARAM) TRUE,
  1090. (LPARAM) MAKELONG( lo, hi )
  1091. );
  1092. SendDlgItemMessage(
  1093. hDlg,
  1094. item,
  1095. TBM_SETPOS,
  1096. (WPARAM) TRUE,
  1097. (LPARAM) pos
  1098. );
  1099. SendDlgItemMessage(
  1100. hDlg,
  1101. item,
  1102. TBM_SETPAGESIZE,
  1103. (WPARAM) 0,
  1104. (LPARAM) pageSize
  1105. );
  1106. SendDlgItemMessage(
  1107. hDlg,
  1108. item,
  1109. TBM_SETLINESIZE,
  1110. (WPARAM) 0,
  1111. (LPARAM) lineSize
  1112. );
  1113. }
  1114. //-----------------------------------------------------------------------------
  1115. // Name: GetTrackbarPos()
  1116. // Desc: Get the current position of a common control trackbar
  1117. //-----------------------------------------------------------------------------
  1118. INT GetTrackbarPos( HWND hDlg, INT item )
  1119. {
  1120. return
  1121. (INT)SendDlgItemMessage(
  1122. hDlg,
  1123. item,
  1124. TBM_GETPOS,
  1125. 0,
  1126. 0
  1127. );
  1128. }
  1129. // Temporary configuration for when the configuration dialog is active
  1130. // If the dialog is ok'ed then this becomes the current configuration,
  1131. // otherwise it is discarded
  1132. CONFIG temp_config;
  1133. //-----------------------------------------------------------------------------
  1134. // Name: ScreenSaverConfigureDialog()
  1135. // Desc:
  1136. //-----------------------------------------------------------------------------
  1137. BOOL CALLBACK CFlowerBoxScreensaver::ScreenSaverConfigureDialog(HWND hdlg, UINT msg,
  1138. WPARAM wpm, LPARAM lpm)
  1139. {
  1140. HWND hCtrl;
  1141. INT i;
  1142. switch(msg)
  1143. {
  1144. case WM_INITDIALOG:
  1145. InitCommonControls();
  1146. g_pMyFlowerBoxScreensaver->ReadSettings();
  1147. temp_config = config;
  1148. CheckRadioButton(hdlg, ID_COL_PICK_FIRST, ID_COL_PICK_LAST,
  1149. config.color_pick);
  1150. CheckDlgButton(hdlg, ID_COL_SMOOTH, config.smooth_colors);
  1151. CheckDlgButton(hdlg, ID_COL_TRIANGLE, config.triangle_colors);
  1152. CheckDlgButton(hdlg, ID_COL_CYCLE, config.cycle_colors);
  1153. CheckDlgButton(hdlg, ID_SPIN, config.spin);
  1154. CheckDlgButton(hdlg, ID_BLOOM, config.bloom);
  1155. CheckDlgButton(hdlg, ID_TWO_SIDED,
  1156. config.two_sided == GL_FRONT_AND_BACK);
  1157. SetupTrackbar( hdlg, ID_COMPLEXITY, MINSUBDIV, MAXSUBDIV,
  1158. complexity_range.step,
  1159. complexity_range.page_step,
  1160. config.subdiv);
  1161. SetupTrackbar( hdlg, ID_IMAGE_SIZE, MINIMAGESIZE, MAXIMAGESIZE,
  1162. image_size_range.step,
  1163. image_size_range.page_step,
  1164. config.image_size);
  1165. hCtrl = GetDlgItem(hdlg, ID_GEOM);
  1166. SendMessage(hCtrl, CB_RESETCONTENT, 0, 0);
  1167. // String storage
  1168. TCHAR geom_names[IDS_GEOM_COUNT][20];
  1169. for (i = 0; i < IDS_GEOM_COUNT; i++)
  1170. {
  1171. LoadString( NULL, i+IDS_GEOM_FIRST, geom_names[i],
  1172. sizeof(geom_names)/IDS_GEOM_COUNT );
  1173. SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)geom_names[i]);
  1174. }
  1175. SendMessage(hCtrl, CB_SETCURSEL, config.geom, 0);
  1176. SetFocus(GetDlgItem(hdlg, ID_COMPLEXITY));
  1177. return FALSE;
  1178. case WM_COMMAND:
  1179. switch(LOWORD(wpm))
  1180. {
  1181. case ID_COL_CHECKER:
  1182. case ID_COL_PER_SIDE:
  1183. case ID_COL_SINGLE:
  1184. temp_config.color_pick = LOWORD(wpm);
  1185. break;
  1186. case ID_COL_SMOOTH:
  1187. temp_config.smooth_colors = !temp_config.smooth_colors;
  1188. break;
  1189. case ID_COL_TRIANGLE:
  1190. temp_config.triangle_colors = !temp_config.triangle_colors;
  1191. break;
  1192. case ID_COL_CYCLE:
  1193. temp_config.cycle_colors = !temp_config.cycle_colors;
  1194. break;
  1195. case ID_SPIN:
  1196. temp_config.spin = !temp_config.spin;
  1197. break;
  1198. case ID_BLOOM:
  1199. temp_config.bloom = !temp_config.bloom;
  1200. break;
  1201. case ID_TWO_SIDED:
  1202. temp_config.two_sided =
  1203. temp_config.two_sided == GL_FRONT_AND_BACK ? GL_FRONT :
  1204. GL_FRONT_AND_BACK;
  1205. break;
  1206. case IDC_SCREENSETTINGS:
  1207. g_pMyFlowerBoxScreensaver->DoScreenSettingsDialog(hdlg);
  1208. break;
  1209. case IDOK:
  1210. temp_config.subdiv =
  1211. GetTrackbarPos(hdlg, ID_COMPLEXITY);
  1212. temp_config.image_size =
  1213. GetTrackbarPos(hdlg, ID_IMAGE_SIZE);
  1214. temp_config.geom =
  1215. (INT)SendMessage(GetDlgItem(hdlg, ID_GEOM), CB_GETCURSEL, 0, 0);
  1216. // NewConfig(&temp_config);
  1217. // Fall through
  1218. case IDCANCEL:
  1219. EndDialog(hdlg, LOWORD(wpm));
  1220. break;
  1221. }
  1222. return TRUE;
  1223. }
  1224. return FALSE;
  1225. }
  1226. //-----------------------------------------------------------------------------
  1227. // Name: SetMaterialColor()
  1228. // Desc:
  1229. //-----------------------------------------------------------------------------
  1230. HRESULT CFlowerBoxScreensaver::SetMaterialColor(FLOAT* pfColors)
  1231. {
  1232. D3DMATERIAL8 mtrl;
  1233. ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
  1234. mtrl.Diffuse.r = mtrl.Ambient.r = pfColors[0];
  1235. mtrl.Diffuse.g = mtrl.Ambient.g = pfColors[1];
  1236. mtrl.Diffuse.b = mtrl.Ambient.b = pfColors[2];
  1237. mtrl.Diffuse.a = mtrl.Ambient.a = pfColors[3];
  1238. mtrl.Specular.r = 0.8f;
  1239. mtrl.Specular.g = 0.8f;
  1240. mtrl.Specular.b = 0.8f;
  1241. mtrl.Specular.a = 1.0f;
  1242. mtrl.Power = 30.0f;
  1243. return m_pd3dDevice->SetMaterial(&mtrl);
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Name: ReadSettings()
  1247. // Desc: Read user preferences from registry
  1248. //-----------------------------------------------------------------------------
  1249. VOID CFlowerBoxScreensaver::ReadSettings()
  1250. {
  1251. HKEY hkey;
  1252. // Read OpenGL settings first, so OS upgrade cases work
  1253. ss_ReadSettings();
  1254. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath,
  1255. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  1256. {
  1257. DXUtil_ReadBoolRegKey( hkey, TEXT("Smooth"), &config.smooth_colors, config.smooth_colors );
  1258. DXUtil_ReadBoolRegKey( hkey, TEXT("Slanted"), &config.triangle_colors, config.triangle_colors );
  1259. DXUtil_ReadBoolRegKey( hkey, TEXT("Cycle"), &config.cycle_colors, config.cycle_colors );
  1260. DXUtil_ReadBoolRegKey( hkey, TEXT("Spin"), &config.spin, config.spin );
  1261. DXUtil_ReadBoolRegKey( hkey, TEXT("Bloom"), &config.bloom, config.bloom );
  1262. DXUtil_ReadIntRegKey( hkey, TEXT("Subdiv"), (DWORD*)&config.subdiv, config.subdiv );
  1263. if( config.subdiv < MINSUBDIV )
  1264. config.subdiv = MINSUBDIV;
  1265. if( config.subdiv > MAXSUBDIV )
  1266. config.subdiv = MAXSUBDIV;
  1267. DXUtil_ReadIntRegKey( hkey, TEXT("ColorPick"), (DWORD*)&config.color_pick, config.color_pick );
  1268. DXUtil_ReadIntRegKey( hkey, TEXT("ImageSize"), (DWORD*)&config.image_size, config.image_size );
  1269. DXUtil_ReadIntRegKey( hkey, TEXT("Geom"), (DWORD*)&config.geom, config.geom );
  1270. DXUtil_ReadIntRegKey( hkey, TEXT("TwoSided"), (DWORD*)&config.two_sided, config.two_sided );
  1271. ReadScreenSettings( hkey );
  1272. RegCloseKey( hkey );
  1273. }
  1274. }
  1275. //-----------------------------------------------------------------------------
  1276. // Name: ss_ReadSettings()
  1277. // Desc:
  1278. //-----------------------------------------------------------------------------
  1279. VOID CFlowerBoxScreensaver::ss_ReadSettings()
  1280. {
  1281. if( !ss_RegistrySetup( IDS_INI_SECTION, IDS_INIFILE ) )
  1282. return;
  1283. config.smooth_colors =
  1284. ss_GetRegistryInt( IDS_CONFIG_SMOOTH_COLORS, config.smooth_colors );
  1285. config.triangle_colors =
  1286. ss_GetRegistryInt( IDS_CONFIG_TRIANGLE_COLORS, config.triangle_colors );
  1287. config.cycle_colors =
  1288. ss_GetRegistryInt( IDS_CONFIG_CYCLE_COLORS, config.cycle_colors );
  1289. config.spin =
  1290. ss_GetRegistryInt( IDS_CONFIG_SPIN, config.spin );
  1291. config.bloom =
  1292. ss_GetRegistryInt( IDS_CONFIG_BLOOM, config.bloom );
  1293. config.subdiv =
  1294. ss_GetRegistryInt( IDS_CONFIG_SUBDIV, config.subdiv );
  1295. config.color_pick =
  1296. ss_GetRegistryInt( IDS_CONFIG_COLOR_PICK, config.color_pick );
  1297. config.image_size =
  1298. ss_GetRegistryInt( IDS_CONFIG_IMAGE_SIZE, config.image_size );
  1299. config.geom =
  1300. ss_GetRegistryInt( IDS_CONFIG_GEOM, config.geom );
  1301. config.two_sided =
  1302. ss_GetRegistryInt( IDS_CONFIG_TWO_SIDED, config.two_sided );
  1303. }
  1304. //-----------------------------------------------------------------------------
  1305. // Name: ss_GetRegistryString()
  1306. // Desc:
  1307. //-----------------------------------------------------------------------------
  1308. BOOL CFlowerBoxScreensaver::ss_RegistrySetup( int section, int file )
  1309. {
  1310. if( LoadString(m_hInstance, section, g_szSectName, BUF_SIZE) &&
  1311. LoadString(m_hInstance, file, g_szFname, BUF_SIZE) )
  1312. {
  1313. TCHAR pBuffer[100];
  1314. DWORD dwRealSize = GetPrivateProfileSection( g_szSectName, pBuffer, 100, g_szFname );
  1315. if( dwRealSize > 0 )
  1316. return TRUE;
  1317. }
  1318. return FALSE;
  1319. }
  1320. //-----------------------------------------------------------------------------
  1321. // Name: ss_GetRegistryString()
  1322. // Desc:
  1323. //-----------------------------------------------------------------------------
  1324. int CFlowerBoxScreensaver::ss_GetRegistryInt( int name, int iDefault )
  1325. {
  1326. TCHAR szItemName[BUF_SIZE];
  1327. if( LoadString( m_hInstance, name, szItemName, BUF_SIZE ) )
  1328. return GetPrivateProfileInt(g_szSectName, szItemName, iDefault, g_szFname);
  1329. return 0;
  1330. }
  1331. //-----------------------------------------------------------------------------
  1332. // Name: ss_GetRegistryString()
  1333. // Desc:
  1334. //-----------------------------------------------------------------------------
  1335. VOID CFlowerBoxScreensaver::ss_GetRegistryString( int name, LPTSTR lpDefault,
  1336. LPTSTR lpDest, int bufSize )
  1337. {
  1338. TCHAR szItemName[BUF_SIZE];
  1339. if( LoadString( m_hInstance, name, szItemName, BUF_SIZE ) )
  1340. GetPrivateProfileString(g_szSectName, szItemName, lpDefault, lpDest,
  1341. bufSize, g_szFname);
  1342. return;
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Name: DoConfig()
  1346. // Desc:
  1347. //-----------------------------------------------------------------------------
  1348. VOID CFlowerBoxScreensaver::DoConfig()
  1349. {
  1350. if( IDOK == DialogBox( NULL, MAKEINTRESOURCE( DLG_SCRNSAVECONFIGURE ),
  1351. m_hWndParent, (DLGPROC)ScreenSaverConfigureDialog ) )
  1352. {
  1353. NewConfig(&temp_config);
  1354. }
  1355. }