PLASMAOB.CXX
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:25k
源码类别:

Windows编程

开发平台:

Visual C++

  1. //+---------------------------------------------------------------------------
  2. //
  3. //  Microsoft Windows
  4. //  Copyright 1992 - 1997 Microsoft Corporation.
  5. //
  6. //  File:       plasmaob.cxx
  7. //
  8. //  Contents:   Plasma Fractal engine object
  9. //
  10. //  Classes:    CPlasma
  11. //
  12. //  Functions:  StartGraphicsThread
  13. //              Normalize
  14. //
  15. //  History:    4-23-94   stevebl   Created
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <windows.h>
  19. #include <ole2.h>
  20. #include <plasmcid.h>
  21. #include "plasma.h"
  22. #include <stdio.h>
  23. #include <strmhelp.h>
  24. #include <palsize.h>
  25. #include <math.h>
  26. #define MAX_RANDOM 50.0
  27. #define MIN_RANDOM 0
  28. //+---------------------------------------------------------------------------
  29. //
  30. //  Function:   StartGraphicsThread
  31. //
  32. //  Synopsis:   Global function used to bootstrap into the GraphicsThread
  33. //              member of the CPlasma class.
  34. //
  35. //  Arguments:  [lpdwParam] - not used
  36. //
  37. //  History:    4-15-94   stevebl   Created
  38. //
  39. //----------------------------------------------------------------------------
  40. DWORD StartGraphicsThread(LPDWORD lpdwParam)
  41. {
  42.     return (((CPlasma *)lpdwParam)->GraphicsThread());
  43. }
  44. //+---------------------------------------------------------------------------
  45. //
  46. //  Member:     CPlasma::QueryInterface
  47. //
  48. //  Synopsis:   standard OLE method
  49. //
  50. //  Arguments:  [riid] - id of desired interface
  51. //              [ppv]  - pointer to receive interface
  52. //
  53. //  Returns:    S_OK on success
  54. //              E_NOINTERFACE if the requested interface isn't supported
  55. //
  56. //  History:    4-23-94   stevebl   Created
  57. //
  58. //----------------------------------------------------------------------------
  59. HRESULT STDMETHODCALLTYPE CPlasma::QueryInterface(REFIID riid, LPVOID * ppv)
  60. {
  61.     *ppv = NULL;
  62.     if (IsEqualGUID(IID_IFractalEngine, riid))
  63.     {
  64.         *ppv = (IFractalEngine *)this;
  65.     }
  66.     else if (IsEqualGUID(IID_IPersist, riid))
  67.     {
  68.         *ppv = (IPersist *)this;
  69.     }
  70.     else if (IsEqualGUID(IID_IPersistStream, riid))
  71.     {
  72.         *ppv = (IPersistStream *)this;
  73.     }
  74.     else if (IsEqualGUID(IID_IUnknown, riid))
  75.     {
  76.         *ppv = (IUnknown *)(IFractalEngine *)this;
  77.     }
  78.     if (*ppv)
  79.     {
  80.         ((IUnknown *)*ppv)->AddRef();
  81.         return(S_OK);
  82.     }
  83.     return(E_NOINTERFACE);
  84. }
  85. //+---------------------------------------------------------------------------
  86. //
  87. //  Member:     CPlasma::AddRef
  88. //
  89. //  Synopsis:   increments the reference count
  90. //
  91. //  Returns:    new reference count
  92. //
  93. //  History:    4-23-94   stevebl   Created
  94. //
  95. //----------------------------------------------------------------------------
  96. ULONG STDMETHODCALLTYPE CPlasma::AddRef(void)
  97. {
  98.     return(++_cRef);
  99. }
  100. //+---------------------------------------------------------------------------
  101. //
  102. //  Member:     CPlasma::Release
  103. //
  104. //  Synopsis:   decrements the reference count
  105. //
  106. //  Returns:    new reference count
  107. //
  108. //  History:    4-23-94   stevebl   Created
  109. //
  110. //----------------------------------------------------------------------------
  111. ULONG STDMETHODCALLTYPE CPlasma::Release(void)
  112. {
  113.     ULONG cRef = --_cRef;
  114.     if (0 == cRef)
  115.     {
  116.         delete this;
  117.         gcRef--;
  118.     }
  119.     return(cRef);
  120. }
  121. // IPersist methods
  122. //+---------------------------------------------------------------------------
  123. //
  124. //  Member:     CPlasma::GetClassID
  125. //
  126. //  Synopsis:   returns the object's class ID
  127. //
  128. //  Arguments:  [pclsid] - pointer to recieve the class ID
  129. //
  130. //  Returns:    S_OK
  131. //
  132. //  History:    4-23-94   stevebl   Created
  133. //
  134. //----------------------------------------------------------------------------
  135. HRESULT CPlasma::GetClassID(LPCLSID pclsid)
  136. {
  137.     memcpy(pclsid, &CLSID_PLASMA, sizeof(GUID));
  138.     return(S_OK);
  139. }
  140. // IPersistStream methods
  141. //+---------------------------------------------------------------------------
  142. //
  143. //  Member:     CPlasma::IsDirty
  144. //
  145. //  Synopsis:   used to determine if the state of the object has changed
  146. //
  147. //  Returns:    S_OK if it is dirty
  148. //              S_FALSE if it is not dirty
  149. //
  150. //  History:    4-23-94   stevebl   Created
  151. //
  152. //----------------------------------------------------------------------------
  153. HRESULT CPlasma::IsDirty(void)
  154. {
  155.     if (_fDirty)
  156.     {
  157.         return(S_OK);
  158.     }
  159.     else
  160.     {
  161.         return(S_FALSE);
  162.     }
  163. }
  164. //+---------------------------------------------------------------------------
  165. //
  166. //  Member:     CPlasma::Load
  167. //
  168. //  Synopsis:   loads the fractal properties from a stream
  169. //
  170. //  Arguments:  [pStm] - pointer to an IStream interface
  171. //
  172. //  Returns:    S_OK on success
  173. //              E_FAIL on error
  174. //              E_OUTOFMEMORY if there's not enough memory (can't happen here)
  175. //
  176. //  History:    4-23-94   stevebl   Created
  177. //
  178. //----------------------------------------------------------------------------
  179. HRESULT CPlasma::Load(LPSTREAM pStm)
  180. {
  181.     if (WAIT_OBJECT_0 == WaitForSingleObject(_hRunning, 0))
  182.     {
  183.         return(E_FAIL);
  184.     }
  185.     HRESULT hr;
  186.     if (FAILED(hr = ReadDouble(pStm, &_dRandomnessFactor, NULL)))
  187.     {
  188.         return(hr);
  189.     }
  190.     _fDirty = FALSE;
  191.     return(S_OK);
  192. }
  193. //+---------------------------------------------------------------------------
  194. //
  195. //  Member:     CPlasma::Save
  196. //
  197. //  Synopsis:   saves the fractal properties to a stream
  198. //
  199. //  Arguments:  [pStm]        - pointer to an IStream interface
  200. //              [fClearDirty] - TRUE if the dirty flag should be cleared
  201. //
  202. //  Returns:    S_OK on success
  203. //
  204. //  History:    4-23-94   stevebl   Created
  205. //
  206. //----------------------------------------------------------------------------
  207. HRESULT CPlasma::Save(LPSTREAM pStm, BOOL fClearDirty)
  208. {
  209.     if (WAIT_OBJECT_0 == WaitForSingleObject(_hRunning, 0))
  210.     {
  211.         return(E_FAIL);
  212.     }
  213.     HRESULT hr;
  214.     if (FAILED(hr = WriteDouble(pStm, _dRandomnessFactor, NULL)))
  215.     {
  216.         return(hr);
  217.     }
  218.     if (fClearDirty)
  219.     {
  220.         _fDirty = FALSE;
  221.     }
  222.     return(S_OK);
  223. }
  224. //+---------------------------------------------------------------------------
  225. //
  226. //  Member:     CPlasma::GetSizeMax
  227. //
  228. //  Synopsis:   used to determine the maximum size of the object's data
  229. //
  230. //  Arguments:  [pcbSize] - pointer to recieve the max size
  231. //
  232. //  Returns:    S_OK
  233. //
  234. //  History:    4-23-94   stevebl   Created
  235. //
  236. //----------------------------------------------------------------------------
  237. HRESULT CPlasma::GetSizeMax(ULARGE_INTEGER * pcbSize)
  238. {
  239.     pcbSize->HighPart = 0;
  240.     pcbSize->LowPart = SizeDouble();
  241.     return(S_OK);
  242. }
  243. // IFractalEngine methods
  244. //+---------------------------------------------------------------------------
  245. //
  246. //  Member:     CPlasma::Init
  247. //
  248. //  Synopsis:   Initializes the graph engine and saves a pointer to the
  249. //              IFractalHost interface that WinFract passes in as
  250. //              the engine is initialized.
  251. //
  252. //  Arguments:  [pfh] - pointer to an IFractalHost interface
  253. //
  254. //  Returns:    S_OK
  255. //
  256. //  History:    4-23-94   stevebl   Created
  257. //
  258. //----------------------------------------------------------------------------
  259. HRESULT STDMETHODCALLTYPE CPlasma::Init(IFractalHost *pfh)
  260. {
  261.     _pfh = pfh;
  262.     // NOTE that I don't addref this pointer!  That would create a circular
  263.     // reference count paradox.
  264.     return(S_OK);
  265. }
  266. //+---------------------------------------------------------------------------
  267. //
  268. //  Member:     CPlasma::SetDefaults
  269. //
  270. //  Synopsis:   initializes the graph engine with its default values
  271. //
  272. //  Returns:    S_OK
  273. //
  274. //  History:    4-23-94   stevebl   Created
  275. //
  276. //----------------------------------------------------------------------------
  277. HRESULT STDMETHODCALLTYPE CPlasma::SetDefaults(void)
  278. {
  279.     _dRandomnessFactor = 2.0;
  280.     _fDirty = TRUE;
  281.     SetEvent(_hRestart);
  282.     return(S_OK);
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. //  Member:     CPlasma::SetProperties
  287. //
  288. //  Synopsis:   Displays the graph engine's property dialog box.
  289. //
  290. //  Arguments:  [hwnd] - handle to the parent window
  291. //
  292. //  Returns:    S_OK
  293. //
  294. //  History:    4-23-94   stevebl   Created
  295. //
  296. //----------------------------------------------------------------------------
  297. HRESULT STDMETHODCALLTYPE CPlasma::SetProperties(HWND hwnd)
  298. {
  299.     ShowDialog(ghinst, MAKEINTRESOURCE(PROPERTIES), hwnd);
  300.     return(S_OK);
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. //  Member:     CPlasma::GetExtent
  305. //
  306. //  Synopsis:   retrieves the extent of the graph
  307. //
  308. //  Arguments:  [pdLeft]   - x value at the left of the graph
  309. //              [pdTop]    - y value at the top of the graph
  310. //              [pdRight]  - x value at the right of the graph
  311. //              [pdBottom] - y value at the bottom of the graph
  312. //
  313. //  Returns:    S_OK
  314. //
  315. //  History:    4-23-94   stevebl   Created
  316. //
  317. //----------------------------------------------------------------------------
  318. HRESULT STDMETHODCALLTYPE CPlasma::GetExtent(
  319.     double *pdLeft,
  320.     double *pdTop,
  321.     double *pdRight,
  322.     double *pdBottom)
  323. {
  324.     *pdLeft = -1.0;
  325.     *pdTop = 1.0;
  326.     *pdRight = 1.0;
  327.     *pdBottom = -1.0;
  328.     return(S_OK);
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. //  Member:     CPlasma::SetExtent
  333. //
  334. //  Synopsis:   sets the graph's extent
  335. //
  336. //  Arguments:  [dLeft]   - x value at the left of the graph
  337. //              [dTop]    - y value at the top of the graph
  338. //              [dRight]  - x value at the right of the graph
  339. //              [dBottom] - y value at the bottom of the graph
  340. //
  341. //  Returns:    S_OK - extents set
  342. //              E_FAIL - the graph was running so the extents couldn't be set
  343. //
  344. //  History:    4-23-94   stevebl   Created
  345. //
  346. //----------------------------------------------------------------------------
  347. HRESULT STDMETHODCALLTYPE CPlasma::SetExtent(
  348.     double dLeft,
  349.     double dTop,
  350.     double dRight,
  351.     double dBottom)
  352. {
  353.     if (WAIT_OBJECT_0 == WaitForSingleObject(_hRunning, 0))
  354.     {
  355.         return(E_FAIL);
  356.     }
  357.     _fDirty = TRUE;
  358.     SetEvent(_hRestart);
  359.     return(S_OK);
  360. }
  361. //+---------------------------------------------------------------------------
  362. //
  363. //  Member:     CPlasma::SetGraphSize
  364. //
  365. //  Synopsis:   Tells the graph engine how big the graph is
  366. //
  367. //  Arguments:  [uWidth]  - width of graph (in pixels)
  368. //              [uHeight] - height of graph (in pixels)
  369. //
  370. //  Returns:    S_OK - success
  371. //              E_FAIL - the graph was running or a value was illegal
  372. //
  373. //  History:    4-23-94   stevebl   Created
  374. //
  375. //----------------------------------------------------------------------------
  376. HRESULT STDMETHODCALLTYPE CPlasma::SetGraphSize(
  377.     unsigned int uWidth,
  378.     unsigned int uHeight)
  379. {
  380.     if (WAIT_OBJECT_0 == WaitForSingleObject(_hRunning, 0))
  381.     {
  382.         return(E_FAIL);
  383.     }
  384.     if (uWidth == 0 || uHeight == 0)
  385.     {
  386.         return(E_FAIL);
  387.     }
  388.     _uWidth = uWidth;
  389.     _uHeight = uHeight;
  390.     SetEvent(_hRestart);
  391.     return(S_OK);
  392. }
  393. //+---------------------------------------------------------------------------
  394. //
  395. //  Member:     CPlasma::Start
  396. //
  397. //  Synopsis:   starts the graph engine
  398. //
  399. //  Returns:    S_OK on success
  400. //
  401. //  History:    4-23-94   stevebl   Created
  402. //
  403. //----------------------------------------------------------------------------
  404. HRESULT STDMETHODCALLTYPE CPlasma::Start(void)
  405. {
  406.     SetEvent(_hRunning);
  407.     return(S_OK);
  408. }
  409. //+---------------------------------------------------------------------------
  410. //
  411. //  Member:     CPlasma::Stop
  412. //
  413. //  Synopsis:   stops the graph engine
  414. //
  415. //  Returns:    S_OK on success
  416. //
  417. //  History:    4-23-94   stevebl   Created
  418. //
  419. //----------------------------------------------------------------------------
  420. HRESULT STDMETHODCALLTYPE CPlasma::Stop(void)
  421. {
  422.     ResetEvent(_hRunning);
  423.     return(S_OK);
  424. }
  425. // Methods that aren't part of any interface
  426. //+---------------------------------------------------------------------------
  427. //
  428. //  Member:     CPlasma::Initialize
  429. //
  430. //  Synopsis:   called by the clas factory to initialize the object
  431. //
  432. //  Returns:    TRUE on success
  433. //              FALSE if the object couldn't be initialized
  434. //
  435. //  History:    4-23-94   stevebl   Created
  436. //
  437. //----------------------------------------------------------------------------
  438. BOOL CPlasma::Initialize(void)
  439. {
  440.     _hRestart = CreateEvent(
  441.         NULL,
  442.         TRUE,   // must be manually reset
  443.         TRUE,   // initially signaled
  444.         NULL);
  445.     if (_hRestart == NULL)
  446.     {
  447.         return(FALSE);  // couldn't create an event
  448.     }
  449.     _hRunning = CreateEvent(
  450.         NULL,
  451.         TRUE,
  452.         FALSE,
  453.         NULL);
  454.     if (_hRunning == NULL)
  455.     {
  456.         return(FALSE);
  457.     }
  458.     _hEngine = CreateThread(
  459.         (LPSECURITY_ATTRIBUTES)NULL,
  460.         0,
  461.         (LPTHREAD_START_ROUTINE) StartGraphicsThread,
  462.         this,
  463.         0,
  464.         &_dwThreadId);
  465.     if (_hEngine == NULL)
  466.     {
  467.         return(FALSE);  // couldn't start the graphics thread
  468.     }
  469.     return(TRUE);
  470. }
  471. //+---------------------------------------------------------------------------
  472. //
  473. //  Member:     CPlasma::GraphicsThread
  474. //
  475. //  Synopsis:   main entry point for the engine's graphics thread
  476. //
  477. //  History:    4-23-94   stevebl   Created
  478. //
  479. //  Notes:      This routine enters into an eternal loop.  It will continue
  480. //              looping until the class is destroyed at which point this
  481. //              thread will be simply terminated.
  482. //
  483. //  Algorithm:  Wait for the engine to be started.
  484. //              Clear the graph.
  485. //              Plot the points at the graph's four corners.
  486. //              Divide it into four quadrants and call Subdivide for each.
  487. //              After falling out of the recursion, check to see if the
  488. //              graph has been aborted.
  489. //              If not, notify that the graph has been completed.
  490. //              Loop back around to the beginning.
  491. //
  492. //----------------------------------------------------------------------------
  493. DWORD CPlasma::GraphicsThread(void)
  494. {
  495.     do
  496.     {
  497.         // wait here until someone starts the graphics engine
  498.         WaitForSingleObject(_hRunning, INFINITE);
  499.         // reset the _hRestart event so that we won't immediately fall out
  500.         // of the engine
  501.         ResetEvent(_hRestart);
  502.         // Now begin drawing the graph
  503.         // erase the background
  504.         _pfh->Rect(0, 0, (int) _uWidth - 1, (int) _uHeight - 1, 0);
  505.         // Seed the random number generator
  506.         srand((UINT)GetTickCount());
  507.         // plot the upper corner
  508.         _pfh->Point(0, 0, rand() % (PALETTESIZE -1 ));
  509.         // begin the recursion
  510.         Subdivide(0, 0, (int) _uWidth, (int) _uHeight);
  511.         // We're either done drawing the graph now or we have been restarted
  512.         if (WAIT_TIMEOUT == WaitForSingleObject(_hRestart, 0))
  513.         {
  514.             // Tell our clients that we're finished
  515.             _pfh->DoneDrawingGraph();
  516.             ResetEvent(_hRunning);
  517.         }
  518.     } while (TRUE);
  519.     return(0);
  520. }
  521. //+---------------------------------------------------------------------------
  522. //
  523. //  Function:   Normalize
  524. //
  525. //  Synopsis:   Makes sure that the value is within the legal color set.
  526. //
  527. //  Arguments:  [iTemp] - color index value
  528. //
  529. //  Returns:    0 <= iTemp < (PALETTESIZE - 1)
  530. //
  531. //  History:    4-28-94   stevebl   Created
  532. //
  533. //  Notes:      There are a couple ways this could be achieved, most of them
  534. //              are undesirable.
  535. //
  536. //              For instance, we could just perform a modulus operation on
  537. //              the value:
  538. //
  539. //                  iTemp = iTemp % (PALETTESIZE - 1)
  540. //
  541. //              This would have the effect of causing numbers to wrap
  542. //              around (PALETTESIZE - 1 would become 0).  This would be bad because
  543. //              in order for the graph to look good we want all the points to
  544. //              transition as smoothley as possible.  Doing it this way
  545. //              would cause the graph to have an area where the elevation
  546. //              suddenly changed dramaticaly when it should have been very
  547. //              smooth.
  548. //
  549. //              Another option would be to just truncate the value:
  550. //
  551. //              if (iTemp) > PALETTESIZE - 2) iTemp = PALETTESIZE - 2
  552. //
  553. //              This would cause our graph to have areas where it is
  554. //              artificially flat.
  555. //
  556. //              Instead, this routine reflects the value back down into a
  557. //              range of values.  For every unit the value is over
  558. //              PALETTESIZE - 2, it is made to be that many units under
  559. //              PALETTESIZE - 1.  This avoids both sudden elevation changes
  560. //              and flat spots.
  561. //
  562. //----------------------------------------------------------------------------
  563. inline void Normalize(int & iTemp)
  564. {
  565.     while (iTemp < 0 || iTemp >= PALETTESIZE - 1)
  566.     {
  567.         if (iTemp < 0)
  568.         {
  569.             iTemp = 0 - iTemp;
  570.         }
  571.         else
  572.         {
  573.             iTemp = ((PALETTESIZE - 1) * 2) - (iTemp + 1);
  574.         }
  575.     }
  576. }
  577. //+---------------------------------------------------------------------------
  578. //
  579. //  Member:     CPlasma::Subdivide
  580. //
  581. //  Synopsis:   recurses into  a rectangle
  582. //
  583. //  Arguments:  [xl] - left side
  584. //              [yl] - top side
  585. //              [xh] - right side
  586. //              [yh] - bottom side
  587. //
  588. //  Returns:    nothing
  589. //
  590. //  History:    4-25-94   stevebl   Created
  591. //
  592. //  Notes:      Each ittertation is responsible for drawing the
  593. //              points marked X below if the haven't already been drawn.
  594. //              The O's are points drawn by previous ittertations.
  595. //              The .'s represent points to be drawn by future itterations.
  596. //
  597. //              O . . . . . X . . . . . O
  598. //              . . . . . . . . . . . . .
  599. //              . . . . . . . . . . . . .
  600. //              . . . . . . . . . . . . .
  601. //              . . . . . . . . . . . . .
  602. //              . . . . . . . . . . . . .
  603. //              X . . . . . X . . . . . X
  604. //              . . . . . . . . . . . . .
  605. //              . . . . . . . . . . . . .
  606. //              . . . . . . . . . . . . .
  607. //              . . . . . . . . . . . . .
  608. //              . . . . . . . . . . . . .
  609. //              O . . . . . X . . . . . O
  610. //
  611. //              Once the routine has plotted its points, it divides
  612. //              the graph into quarters and calls itself
  613. //              for each quarter.
  614. //
  615. //              Since the graph is erased to color 0 before itterations are
  616. //              begun, testing if a point has already been plotted is simple:
  617. //              if the point contians color 0 then it hasn't been plotted yet.
  618. //
  619. //----------------------------------------------------------------------------
  620. void CPlasma::Subdivide(int xl, int yl, int xh, int yh)
  621. {
  622.     if (WAIT_TIMEOUT == WaitForSingleObject(_hRestart, 0))
  623.     {
  624.         WaitForSingleObject(_hRunning, INFINITE);
  625.         // find the midpoints
  626.         int iMidX = (xh + xl) / 2;
  627.         int iMidY = (yh + yl) / 2;
  628.         // find the four corner colors
  629.         unsigned char cTL, cTR, cBL, cBR;
  630.         unsigned uTemp;
  631.         _pfh->GetPoint(&uTemp, xl, yl);
  632.         cTL = uTemp - 1;
  633.         _pfh->GetPoint(&uTemp, xh % _uWidth, yl);
  634.         cTR = uTemp - 1;
  635.         _pfh->GetPoint(&uTemp, xl, yh % _uHeight);
  636.         cBL = uTemp - 1;
  637.         _pfh->GetPoint(&uTemp, xh % _uWidth, yh % _uHeight);
  638.         cBR = uTemp - 1;
  639.         int cTM, cLM, cRM, cBM;
  640.         unsigned uSpread = (unsigned)((xh - xl) * _dRandomnessFactor);
  641.         // choose the top point
  642.         _pfh->GetPoint(&uTemp, iMidX, yl);
  643.         if (0 == uTemp)
  644.         {
  645.             cTM = (rand() % (uSpread * 2 + 1)) - uSpread;
  646.             cTM += (cTL + cTR) / 2;
  647.             Normalize(cTM);
  648.             _pfh->Point(iMidX, yl, cTM + 1);
  649.         }
  650.         // choose the bottom point
  651.         _pfh->GetPoint(&uTemp, iMidX, yh % _uHeight);
  652.         if (0 == uTemp)
  653.         {
  654.             cBM = (rand() % (uSpread * 2 + 1)) - uSpread;
  655.             cBM += (cBL + cBR) / 2;
  656.             Normalize(cBM);
  657.             // Don't need to use yh % _uHeight here because the only
  658.             // way we can get here is if yh < _uHeight.
  659.             _pfh->Point(iMidX, yh, cBM + 1);
  660.         }
  661.         uSpread = (unsigned)((yh - yl) * _dRandomnessFactor);
  662.         // choose the left point
  663.         _pfh->GetPoint(&uTemp,xl, iMidY);
  664.         if (0 == uTemp)
  665.         {
  666.             cLM = (rand() % (uSpread * 2 + 1)) - uSpread;
  667.             cLM += (cTL + cBL) / 2;
  668.             Normalize(cLM);
  669.             _pfh->Point(xl, iMidY, cLM + 1);
  670.         }
  671.         // choose the right point
  672.         _pfh->GetPoint(&uTemp, xh % _uWidth, iMidY);
  673.         if (0 == uTemp)
  674.         {
  675.             cRM = (rand() % (uSpread * 2 + 1)) - uSpread;
  676.             cRM += (cTR + cBR) / 2;
  677.             Normalize(cRM);
  678.             // Don't need to use xh % _uWidth here because the only
  679.             // way we can get here is if xh < _uWidth.
  680.             _pfh->Point(xh, iMidY, cRM + 1);
  681.         }
  682.         _pfh->GetPoint(&uTemp, iMidX, iMidY);
  683.         if (0 == uTemp)
  684.         {
  685.             // choose the center point
  686.             uSpread = (unsigned)((sqrt(((float)(xh - xl) * (xh - xl) + (yh - yl) * (yh - yl))) / 2) * _dRandomnessFactor);
  687.             int cC = (rand() % (uSpread * 2 + 1)) - uSpread;
  688.             cC += (cTL + cBR + cTR + cBL) / 4;
  689.             Normalize(cC);
  690.             _pfh->Point(iMidX, iMidY, cC + 1);
  691.         }
  692.         // now recurse
  693.         if (xh - xl > 2 || yh - yl > 2)
  694.         {
  695.             Subdivide(xl, yl, iMidX, iMidY);
  696.             Subdivide(iMidX, yl, xh, iMidY);
  697.             Subdivide(xl, iMidY, iMidX, yh);
  698.             Subdivide(iMidX, iMidY, xh, yh);
  699.         }
  700.     }
  701. }
  702. //+---------------------------------------------------------------------------
  703. //
  704. //  Member:     CPlasma::CPlasma
  705. //
  706. //  Synopsis:   constructor
  707. //
  708. //  History:    4-23-94   stevebl   Created
  709. //
  710. //----------------------------------------------------------------------------
  711. CPlasma::CPlasma()
  712. {
  713.     _uWidth = 160;
  714.     _uHeight = 120;
  715.     _dRandomnessFactor = 2.0;
  716.     _hRestart = _hRunning = _hEngine = NULL;
  717.     _dwThreadId = 0;
  718.     _cRef = 0;
  719.     _pfh = NULL;
  720.     _fDirty = TRUE;
  721. }
  722. //+---------------------------------------------------------------------------
  723. //
  724. //  Member:     CPlasma::~CPlasma
  725. //
  726. //  Synopsis:   destructor
  727. //
  728. //  History:    4-23-94   stevebl   Created
  729. //
  730. //----------------------------------------------------------------------------
  731. CPlasma::~CPlasma()
  732. {
  733.     if (_hRestart)
  734.     {
  735.         CloseHandle(_hRestart);
  736.     }
  737.     if (_hRunning)
  738.     {
  739.         CloseHandle(_hRunning);
  740.     }
  741.     if (_hEngine)
  742.     {
  743.         TerminateThread(_hEngine, 0);
  744.         CloseHandle(_hEngine);
  745.     }
  746. }
  747. #define LENGTH 50
  748. #define ABOUT_STRING_LENGTH 256
  749. //+---------------------------------------------------------------------------
  750. //
  751. //  Member:     CPlasma::DialogProc
  752. //
  753. //  Synopsis:   Dialog proc for the Properties dialog box
  754. //
  755. //  Arguments:  [hwndDlg] - the dialog's window handle
  756. //              [uMsg]    - message
  757. //              [wParam]  - first message parameter
  758. //              [lParam]  - second message parameter
  759. //
  760. //  History:    4-23-94   stevebl   Created
  761. //
  762. //----------------------------------------------------------------------------
  763. BOOL CPlasma::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  764. {
  765.     char mbs[LENGTH + 1];
  766.     switch (uMsg)
  767.     {
  768.     case WM_INITDIALOG:
  769.         sprintf(mbs, "%.13g", _dRandomnessFactor);
  770.         SetDlgItemTextA(hwndDlg, IDM_RANDOMNESS, mbs);
  771.         return(TRUE);
  772.     case WM_COMMAND:
  773.         switch (LOWORD(wParam))
  774.         {
  775.         case IDOK:
  776.             GetDlgItemTextA(hwndDlg, IDM_RANDOMNESS, mbs, LENGTH);
  777.             sscanf(mbs, "%lg", &_dRandomnessFactor);
  778.             if (_dRandomnessFactor < MIN_RANDOM)
  779.             {
  780.                 _dRandomnessFactor = MIN_RANDOM;
  781.             }
  782.             if (_dRandomnessFactor > MAX_RANDOM)
  783.             {
  784.                 _dRandomnessFactor = MAX_RANDOM;
  785.             }
  786.             _fDirty = TRUE;
  787.             SetEvent(_hRestart);
  788.             EndDialog(hwndDlg, TRUE);
  789.             return(TRUE);
  790.         case IDM_ABOUT:
  791.             {
  792.                 TCHAR szTitle[ABOUT_STRING_LENGTH];
  793.                 TCHAR szText[ABOUT_STRING_LENGTH];
  794.                 if (LoadString(ghinst, IDS_ABOUT_TITLE, szTitle, ABOUT_STRING_LENGTH))
  795.                 {
  796.                     if (LoadString(ghinst, IDS_ABOUT_TEXT, szText, ABOUT_STRING_LENGTH))
  797.                     {
  798.                         MessageBox(
  799.                             hwndDlg,
  800.                             szText,
  801.                             szTitle,
  802.                             MB_OK | MB_ICONINFORMATION);
  803.                     }
  804.                 }
  805.             }
  806.             return(TRUE);
  807.         case IDCANCEL:
  808.             EndDialog(hwndDlg, FALSE);
  809.             return(TRUE);
  810.         default:
  811.             return(FALSE);
  812.         }
  813.     }
  814.     return(FALSE);
  815. }