Leaked source code of windows server 2003
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.

1895 lines
53 KiB

  1. // SimpView.cpp : implementation of the CSimpsonsView class
  2. //
  3. #define DISABLE_CROSSDOT
  4. #include "stdafx.h"
  5. #include "simpsons.h"
  6. #include "SimpDoc.h"
  7. #include "SimpView.h"
  8. #include "dxtrans.h"
  9. #include "dxhelper.h"
  10. #include <mmsystem.h>
  11. #define fZOOMFACTOR 0.03f
  12. #define fSCALEMIN 0.4f
  13. #define fSCALEMAX 2.5f
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. // Flatten to an error of 2/3. During initial phase, use 18.14 format.
  20. #define TEST_MAGNITUDE_INITIAL (6 * 0x00002aa0L)
  21. // Error of 2/3. During normal phase, use 15.17 format.
  22. #define TEST_MAGNITUDE_NORMAL (TEST_MAGNITUDE_INITIAL << 3)
  23. // 'FIX' is a 28.4 fixed point type:
  24. #define FIX_SCALE 16
  25. typedef LONG FIX;
  26. typedef POINT POINTFIX;
  27. typedef struct _RECTFX
  28. {
  29. FIX xLeft;
  30. FIX yTop;
  31. FIX xRight;
  32. FIX yBottom;
  33. } RECTFX, *PRECTFX;
  34. #define MIN(A,B) ((A) < (B) ? (A) : (B))
  35. #define MAX(A,B) ((A) > (B) ? (A) : (B))
  36. #define ABS(A) ((A) < 0 ? -(A) : (A))
  37. // Hacky macro which returns the current test case's attribute array
  38. #define ThisTestCase (TC::testCases[m_testCaseNumber])
  39. // Test case combinations
  40. //
  41. // We enumerate every test case in a table so that we can cycle through
  42. // all of them.
  43. namespace TC {
  44. // Names for each test case attribute
  45. enum {At_Library, At_Source, At_Destination, At_Aliasing};
  46. const char *AttributeStr[] = {
  47. "Library", "Source", "Dest", "Aliasing"
  48. };
  49. const int NumAttributes = (sizeof(AttributeStr)/sizeof(AttributeStr[0]));
  50. typedef int TestCase[NumAttributes];
  51. // For each attribute, names for each option:
  52. enum {Meta, GDIP, GDI}; // At_Library
  53. enum {Native, FromMetafile, CreatePoly, PathAPI}; // At_Source
  54. enum {Memory, Screen, ToMetafile}; // At_Destination
  55. enum {Aliased, Antialiased}; // At_Aliasing
  56. const char *OptionStr[NumAttributes][4] = {
  57. "Meta", "GDI+", "GDI", "",
  58. "Native", "Metafile", "CreatePoly", "PathAPI",
  59. "Memory", "Screen", "Metafile", "",
  60. "Aliased", "AA", "", ""
  61. };
  62. // Supported options for each library:
  63. //
  64. // GDI+: At_Source - Native, FromMetafile, PathAPI
  65. // At_Destination - Memory, Screen, ToMetafile
  66. // At_Aliasing - Aliased, Antialiased
  67. //
  68. // Meta: At_Source - Native
  69. // At_Destination - Memory, Screen
  70. // At_Aliasing - Antialiased
  71. //
  72. // GDI: At_Source - PathAPI, CreatePoly, FromMetafile
  73. // At_Destination - Memory, Screen, ToMetafile
  74. // At_Aliasing - Aliased
  75. const TestCase testCases[] = {
  76. // Library Source Destination Aliasing
  77. GDIP, Native, Memory, Antialiased,
  78. GDIP, Native, Screen, Antialiased,
  79. GDIP, Native, Memory, Aliased,
  80. GDIP, Native, Screen, Aliased,
  81. GDIP, Native, ToMetafile, Antialiased,
  82. GDIP, FromMetafile, Memory, Antialiased,
  83. GDIP, PathAPI, Memory, Antialiased,
  84. Meta, Native, Memory, Antialiased,
  85. Meta, Native, Screen, Antialiased,
  86. GDI, CreatePoly, Memory, Aliased,
  87. GDI, CreatePoly, Screen, Aliased,
  88. GDI, CreatePoly, ToMetafile, Aliased,
  89. GDI, FromMetafile, Memory, Aliased,
  90. GDI, PathAPI, Memory, Aliased,
  91. };
  92. const int numTestCases = (sizeof(testCases)/(sizeof(testCases[0])));
  93. };
  94. // Test results, used when we cycle automatically through all test combinations
  95. // Hack: This should be a member of CSimpsonView, but I kept it here to reduce
  96. // compile time when we add a test case.
  97. DWORD timingResults[TC::numTestCases];
  98. // IncrementAttribute(int): Changes the rendering attributes
  99. // Advances to the next test case which is different in the given
  100. // attribute. Unless the attribute is TC::At_Library, will only advance to a
  101. // case which is identical in all other attributes.
  102. //
  103. // If there is none, doesn't do anything.
  104. //
  105. // Returns: false if the test case didn't change
  106. bool CSimpsonsView::IncrementAttribute(int attribute) {
  107. int startValue=m_testCaseNumber;
  108. int i;
  109. while (1) {
  110. // Increment the test case number, with wraparound
  111. m_testCaseNumber++;
  112. if (m_testCaseNumber >= TC::numTestCases) m_testCaseNumber = 0;
  113. // If we've returned to the case we started on, no suitable
  114. // case was found
  115. if (m_testCaseNumber == startValue) return false;
  116. // Continue searching if the attribute for this case is the same
  117. if (TC::testCases[startValue][attribute] ==
  118. TC::testCases[m_testCaseNumber][attribute]) continue;
  119. // If we're incrementing the library attribute, we've found what
  120. // we need.
  121. if (attribute == TC::At_Library) break;
  122. // Otherwise, we need to continue if this case isn't identical
  123. // in the other attributes
  124. for (i=0; i<TC::NumAttributes; i++) {
  125. if (i==attribute) continue;
  126. if (TC::testCases[startValue][i] !=
  127. TC::testCases[m_testCaseNumber][i]) break;
  128. }
  129. // If all other attributes were identical, end the search
  130. if (i==TC::NumAttributes) break;
  131. }
  132. return true;
  133. }
  134. // IncrementTest(): Cycles through the possible combinations of attributes
  135. // Each call changes one of the test attributes.
  136. // Returns true when the cycle is done.
  137. bool CSimpsonsView::IncrementTest() {
  138. UpdateStatusMessage();
  139. // Store the timing for the current test.
  140. timingResults[m_testCaseNumber] = m_dwRenderTime;
  141. m_testCaseNumber++;
  142. if (m_testCaseNumber == TC::numTestCases) m_testCaseNumber = 0;
  143. return m_testCaseNumber==0;
  144. }
  145. void CSimpsonsView::PrintTestResults() {
  146. int i,j;
  147. printf("\n");
  148. for (i=0;i<TC::NumAttributes;i++) {
  149. printf("%-11s", TC::AttributeStr[i]);
  150. }
  151. printf(" Time\n\n");
  152. for (i=0;i<TC::numTestCases;i++) {
  153. for (j=0;j<TC::NumAttributes;j++) {
  154. printf("%-11s", TC::OptionStr[j][TC::testCases[i][j]]);
  155. }
  156. printf(" %dms\n", timingResults[i]);
  157. }
  158. printf("\n");
  159. };
  160. DWORD g_aColors[] =
  161. {
  162. 0xFF000000,
  163. 0xFF0000FF,
  164. 0xFF00FF00,
  165. 0xFF00FFFF,
  166. 0xFFFF0000,
  167. 0xFFFF00FF,
  168. 0xFFFFFF00,
  169. 0xFFFFFFFF,
  170. 0xFFAAAAAA,
  171. 0xFF444444
  172. };
  173. const ULONG NumColors = sizeof(g_aColors) / sizeof(g_aColors[0]);
  174. ULONG g_ulColorIndex = 8;
  175. /**********************************Class***********************************\
  176. * class HFDBASIS32
  177. *
  178. * Class for HFD vector objects.
  179. *
  180. * Public Interface:
  181. *
  182. * vInit(p1, p2, p3, p4) - Re-parameterizes the given control points
  183. * to our initial HFD error basis.
  184. * vLazyHalveStepSize(cShift) - Does a lazy shift. Caller has to remember
  185. * it changes 'cShift' by 2.
  186. * vSteadyState(cShift) - Re-parameterizes to our working normal
  187. * error basis.
  188. *
  189. * vTakeStep() - Forward steps to next sub-curve
  190. * vHalveStepSize() - Adjusts down (subdivides) the sub-curve
  191. * vDoubleStepSize() - Adjusts up the sub-curve
  192. * lError() - Returns error if current sub-curve were
  193. * to be approximated using a straight line
  194. * (value is actually multiplied by 6)
  195. * fxValue() - Returns rounded coordinate of first point in
  196. * current sub-curve. Must be in steady
  197. * state.
  198. *
  199. * History:
  200. * 10-Nov-1990 -by- J. Andrew Goossen [andrewgo]
  201. * Wrote it.
  202. \**************************************************************************/
  203. class HFDBASIS32
  204. {
  205. private:
  206. LONG e0;
  207. LONG e1;
  208. LONG e2;
  209. LONG e3;
  210. public:
  211. VOID vInit(FIX p1, FIX p2, FIX p3, FIX p4);
  212. VOID vLazyHalveStepSize(LONG cShift);
  213. VOID vSteadyState(LONG cShift);
  214. VOID vHalveStepSize();
  215. VOID vDoubleStepSize();
  216. VOID vTakeStep();
  217. LONG lParentErrorDividedBy4() { return(MAX(ABS(e3), ABS(e2 + e2 - e3))); }
  218. LONG lError() { return(MAX(ABS(e2), ABS(e3))); }
  219. FIX fxValue() { return((e0 + (1L << 12)) >> 13); }
  220. };
  221. /**********************************Class***********************************\
  222. * class BEZIER32
  223. *
  224. * Bezier cracker.
  225. *
  226. * A hybrid cubic Bezier curve flattener based on KirkO's error factor.
  227. * Generates line segments fast without using the stack. Used to flatten
  228. * a path.
  229. *
  230. * For an understanding of the methods used, see:
  231. *
  232. * Kirk Olynyk, "..."
  233. * Goossen and Olynyk, "System and Method of Hybrid Forward
  234. * Differencing to Render Bezier Splines"
  235. * Lien, Shantz and Vaughan Pratt, "Adaptive Forward Differencing for
  236. * Rendering Curves and Surfaces", Computer Graphics, July 1987
  237. * Chang and Shantz, "Rendering Trimmed NURBS with Adaptive Forward
  238. * Differencing", Computer Graphics, August 1988
  239. * Foley and Van Dam, "Fundamentals of Interactive Computer Graphics"
  240. *
  241. * This algorithm is protected by U.S. patents 5,363,479 and 5,367,617.
  242. *
  243. * Public Interface:
  244. *
  245. * vInit(pptfx) - pptfx points to 4 control points of
  246. * Bezier. Current point is set to the first
  247. * point after the start-point.
  248. * BEZIER32(pptfx) - Constructor with initialization.
  249. * vGetCurrent(pptfx) - Returns current polyline point.
  250. * bCurrentIsEndPoint() - TRUE if current point is end-point.
  251. * vNext() - Moves to next polyline point.
  252. *
  253. * History:
  254. * 1-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  255. * Wrote it.
  256. \**************************************************************************/
  257. class BEZIER32
  258. {
  259. public:
  260. LONG cSteps;
  261. HFDBASIS32 x;
  262. HFDBASIS32 y;
  263. RECTFX rcfxBound;
  264. BOOL bInit(POINTFIX* aptfx, RECTFX*);
  265. BOOL bNext(POINTFIX* pptfx);
  266. };
  267. #define INLINE inline
  268. INLINE BOOL bIntersect(RECTFX* prcfx1, RECTFX* prcfx2)
  269. {
  270. BOOL bRet = (prcfx1->yTop <= prcfx2->yBottom &&
  271. prcfx1->yBottom >= prcfx2->yTop &&
  272. prcfx1->xLeft <= prcfx2->xRight &&
  273. prcfx1->xRight >= prcfx2->xLeft);
  274. return(bRet);
  275. }
  276. INLINE VOID vBoundBox(POINTFIX* aptfx, RECTFX* prcfx)
  277. {
  278. if (aptfx[0].x >= aptfx[1].x)
  279. if (aptfx[2].x >= aptfx[3].x)
  280. {
  281. prcfx->xLeft = MIN(aptfx[1].x, aptfx[3].x);
  282. prcfx->xRight = MAX(aptfx[0].x, aptfx[2].x);
  283. }
  284. else
  285. {
  286. prcfx->xLeft = MIN(aptfx[1].x, aptfx[2].x);
  287. prcfx->xRight = MAX(aptfx[0].x, aptfx[3].x);
  288. }
  289. else
  290. if (aptfx[2].x <= aptfx[3].x)
  291. {
  292. prcfx->xLeft = MIN(aptfx[0].x, aptfx[2].x);
  293. prcfx->xRight = MAX(aptfx[1].x, aptfx[3].x);
  294. }
  295. else
  296. {
  297. prcfx->xLeft = MIN(aptfx[0].x, aptfx[3].x);
  298. prcfx->xRight = MAX(aptfx[1].x, aptfx[2].x);
  299. }
  300. if (aptfx[0].y >= aptfx[1].y)
  301. if (aptfx[2].y >= aptfx[3].y)
  302. {
  303. prcfx->yTop = MIN(aptfx[1].y, aptfx[3].y);
  304. prcfx->yBottom = MAX(aptfx[0].y, aptfx[2].y);
  305. }
  306. else
  307. {
  308. prcfx->yTop = MIN(aptfx[1].y, aptfx[2].y);
  309. prcfx->yBottom = MAX(aptfx[0].y, aptfx[3].y);
  310. }
  311. else
  312. if (aptfx[2].y <= aptfx[3].y)
  313. {
  314. prcfx->yTop = MIN(aptfx[0].y, aptfx[2].y);
  315. prcfx->yBottom = MAX(aptfx[1].y, aptfx[3].y);
  316. }
  317. else
  318. {
  319. prcfx->yTop = MIN(aptfx[0].y, aptfx[3].y);
  320. prcfx->yBottom = MAX(aptfx[1].y, aptfx[2].y);
  321. }
  322. }
  323. INLINE VOID HFDBASIS32::vInit(FIX p1, FIX p2, FIX p3, FIX p4)
  324. {
  325. // Change basis and convert from 28.4 to 18.14 format:
  326. e0 = (p1 ) << 10;
  327. e1 = (p4 - p1 ) << 10;
  328. e2 = (3 * (p2 - p3 - p3 + p4)) << 11;
  329. e3 = (3 * (p1 - p2 - p2 + p3)) << 11;
  330. }
  331. INLINE VOID HFDBASIS32::vLazyHalveStepSize(LONG cShift)
  332. {
  333. e2 = (e2 + e3) >> 1;
  334. e1 = (e1 - (e2 >> cShift)) >> 1;
  335. }
  336. INLINE VOID HFDBASIS32::vSteadyState(LONG cShift)
  337. {
  338. // We now convert from 18.14 fixed format to 15.17:
  339. e0 <<= 3;
  340. e1 <<= 3;
  341. register LONG lShift = cShift - 3;
  342. if (lShift < 0)
  343. {
  344. lShift = -lShift;
  345. e2 <<= lShift;
  346. e3 <<= lShift;
  347. }
  348. else
  349. {
  350. e2 >>= lShift;
  351. e3 >>= lShift;
  352. }
  353. }
  354. INLINE VOID HFDBASIS32::vHalveStepSize()
  355. {
  356. e2 = (e2 + e3) >> 3;
  357. e1 = (e1 - e2) >> 1;
  358. e3 >>= 2;
  359. }
  360. INLINE VOID HFDBASIS32::vDoubleStepSize()
  361. {
  362. e1 += e1 + e2;
  363. e3 <<= 2;
  364. e2 = (e2 << 3) - e3;
  365. }
  366. INLINE VOID HFDBASIS32::vTakeStep()
  367. {
  368. e0 += e1;
  369. register LONG lTemp = e2;
  370. e1 += lTemp;
  371. e2 += lTemp - e3;
  372. e3 = lTemp;
  373. }
  374. typedef struct _BEZIERCONTROLS {
  375. POINTFIX ptfx[4];
  376. } BEZIERCONTROLS;
  377. BOOL BEZIER32::bInit(
  378. POINTFIX* aptfxBez, // Pointer to 4 control points
  379. RECTFX* prcfxClip) // Bound box of visible region (optional)
  380. {
  381. POINTFIX aptfx[4];
  382. LONG cShift = 0; // Keeps track of 'lazy' shifts
  383. cSteps = 1; // Number of steps to do before reach end of curve
  384. vBoundBox(aptfxBez, &rcfxBound);
  385. *((BEZIERCONTROLS*) aptfx) = *((BEZIERCONTROLS*) aptfxBez);
  386. {
  387. register FIX fxOr;
  388. register FIX fxOffset;
  389. fxOffset = rcfxBound.xLeft;
  390. fxOr = (aptfx[0].x -= fxOffset);
  391. fxOr |= (aptfx[1].x -= fxOffset);
  392. fxOr |= (aptfx[2].x -= fxOffset);
  393. fxOr |= (aptfx[3].x -= fxOffset);
  394. fxOffset = rcfxBound.yTop;
  395. fxOr |= (aptfx[0].y -= fxOffset);
  396. fxOr |= (aptfx[1].y -= fxOffset);
  397. fxOr |= (aptfx[2].y -= fxOffset);
  398. fxOr |= (aptfx[3].y -= fxOffset);
  399. // This 32 bit cracker can only handle points in a 10 bit space:
  400. if ((fxOr & 0xffffc000) != 0)
  401. return(FALSE);
  402. }
  403. x.vInit(aptfx[0].x, aptfx[1].x, aptfx[2].x, aptfx[3].x);
  404. y.vInit(aptfx[0].y, aptfx[1].y, aptfx[2].y, aptfx[3].y);
  405. if (prcfxClip == (RECTFX*) NULL || bIntersect(&rcfxBound, prcfxClip))
  406. {
  407. while (TRUE)
  408. {
  409. register LONG lTestMagnitude = TEST_MAGNITUDE_INITIAL << cShift;
  410. if (x.lError() <= lTestMagnitude && y.lError() <= lTestMagnitude)
  411. break;
  412. cShift += 2;
  413. x.vLazyHalveStepSize(cShift);
  414. y.vLazyHalveStepSize(cShift);
  415. cSteps <<= 1;
  416. }
  417. }
  418. x.vSteadyState(cShift);
  419. y.vSteadyState(cShift);
  420. // Note that this handles the case where the initial error for
  421. // the Bezier is already less than TEST_MAGNITUDE_NORMAL:
  422. x.vTakeStep();
  423. y.vTakeStep();
  424. cSteps--;
  425. return(TRUE);
  426. }
  427. BOOL BEZIER32::bNext(POINTFIX* pptfx)
  428. {
  429. // Return current point:
  430. pptfx->x = x.fxValue() + rcfxBound.xLeft;
  431. pptfx->y = y.fxValue() + rcfxBound.yTop;
  432. // If cSteps == 0, that was the end point in the curve!
  433. if (cSteps == 0)
  434. return(FALSE);
  435. // Okay, we have to step:
  436. if (MAX(x.lError(), y.lError()) > TEST_MAGNITUDE_NORMAL)
  437. {
  438. x.vHalveStepSize();
  439. y.vHalveStepSize();
  440. cSteps <<= 1;
  441. }
  442. while (!(cSteps & 1) &&
  443. x.lParentErrorDividedBy4() <= (TEST_MAGNITUDE_NORMAL >> 2) &&
  444. y.lParentErrorDividedBy4() <= (TEST_MAGNITUDE_NORMAL >> 2))
  445. {
  446. x.vDoubleStepSize();
  447. y.vDoubleStepSize();
  448. cSteps >>= 1;
  449. }
  450. cSteps--;
  451. x.vTakeStep();
  452. y.vTakeStep();
  453. return(TRUE);
  454. }
  455. /////////////////////////////////////////////////////////////////////////////
  456. // CSimpsonsView
  457. IMPLEMENT_DYNCREATE(CSimpsonsView, CView)
  458. BEGIN_MESSAGE_MAP(CSimpsonsView, CView)
  459. //{{AFX_MSG_MAP(CSimpsonsView)
  460. ON_WM_SIZE()
  461. ON_WM_LBUTTONUP()
  462. ON_WM_LBUTTONDOWN()
  463. ON_WM_KEYDOWN()
  464. ON_WM_RBUTTONDOWN()
  465. ON_WM_MOUSEMOVE()
  466. ON_WM_MOUSEWHEEL()
  467. //}}AFX_MSG_MAP
  468. END_MESSAGE_MAP()
  469. /////////////////////////////////////////////////////////////////////////////
  470. // CSimpsonsView construction/destruction
  471. CSimpsonsView::CSimpsonsView()
  472. : m_sizWin(0, 0)
  473. {
  474. m_pDD = NULL;
  475. m_pddsScreen = NULL;
  476. m_pSurfFactory = NULL;
  477. m_pDX2D = NULL;
  478. m_pDX2DScreen = NULL;
  479. m_pDX2DDebug = NULL;
  480. m_CycleTests = false;
  481. m_testCaseNumber = 0;
  482. m_bIgnoreStroke = m_bIgnoreFill = false;
  483. m_dwRenderTime = 0;
  484. m_gpPathArray = NULL;
  485. m_XForm.SetIdentity();
  486. m_centerPoint.x = m_centerPoint.y = 0;
  487. m_lastPoint.x = m_lastPoint.y = 0;
  488. m_tracking = m_scaling = false;
  489. m_bLButton = false;
  490. }
  491. CSimpsonsView::~CSimpsonsView()
  492. {
  493. if (m_gpPathArray) delete [] m_gpPathArray;
  494. MMRELEASE(m_pDD);
  495. MMRELEASE(m_pddsScreen);
  496. MMRELEASE(m_pSurfFactory);
  497. MMRELEASE(m_pDX2D);
  498. MMRELEASE(m_pDX2DScreen);
  499. MMRELEASE(m_pDX2DDebug);
  500. CoUninitialize();
  501. }
  502. BOOL
  503. CSimpsonsView::PreCreateWindow(CREATESTRUCT &cs)
  504. {
  505. HRESULT hr = S_OK;
  506. IDXTransformFactory *pTranFact = NULL;
  507. IDirectDrawFactory *pDDrawFact = NULL;
  508. IDirectDraw *pDD = NULL;
  509. if (CView::PreCreateWindow(cs) == false)
  510. return false;
  511. CHECK_HR(hr = CoInitialize(NULL));
  512. //--- Create the transform factory
  513. CHECK_HR(hr = ::CoCreateInstance(CLSID_DXTransformFactory, NULL, CLSCTX_INPROC,
  514. IID_IDXTransformFactory, (void **) &pTranFact));
  515. CHECK_HR(hr = ::CoCreateInstance(CLSID_DX2D, NULL, CLSCTX_INPROC,
  516. IID_IDX2D, (void **) &m_pDX2D));
  517. CHECK_HR(hr = ::CoCreateInstance(CLSID_DX2D, NULL, CLSCTX_INPROC,
  518. IID_IDX2D, (void **) &m_pDX2DScreen));
  519. /* m_pDX2D->QueryInterface(IID_IDX2DDebug, (void **) &m_pDX2DDebug);*/
  520. CHECK_HR(hr = m_pDX2D->SetTransformFactory(pTranFact));
  521. CHECK_HR(hr = m_pDX2DScreen->SetTransformFactory(pTranFact));
  522. CHECK_HR(hr = pTranFact->QueryInterface(IID_IDXSurfaceFactory, (void **) &m_pSurfFactory));
  523. //--- Create the direct draw object
  524. CHECK_HR(hr = ::CoCreateInstance(CLSID_DirectDrawFactory, NULL, CLSCTX_INPROC,
  525. IID_IDirectDrawFactory, (void **) &pDDrawFact));
  526. CHECK_HR(hr = pDDrawFact->CreateDirectDraw( NULL, m_hWnd, DDSCL_NORMAL, 0, NULL, &pDD));
  527. CHECK_HR(hr = pDD->QueryInterface( IID_IDirectDraw3, (void **) &m_pDD));
  528. // Create the primary ddraw surface (m_pddsScreen)
  529. DDSURFACEDESC ddsd;
  530. ZeroMemory(&ddsd, sizeof(ddsd));
  531. ddsd.dwSize = sizeof(ddsd);
  532. ddsd.dwFlags = DDSD_CAPS;
  533. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  534. CHECK_HR(hr = m_pDD->CreateSurface(&ddsd, &m_pddsScreen, NULL));
  535. CHECK_HR(hr = m_pDX2DScreen->SetSurface(m_pddsScreen));
  536. e_Exit:
  537. MMRELEASE(pTranFact);
  538. MMRELEASE(pDDrawFact);
  539. MMRELEASE(pDD);
  540. return (hr == S_OK);
  541. }
  542. /////////////////////////////////////////////////////////////////////////////
  543. // CSimpsonsView drawing
  544. void
  545. CSimpsonsView::OnSize(UINT nType, int cx, int cy)
  546. {
  547. // MMTRACE("OnSize\n");
  548. m_centerPoint.x = cx / 2;
  549. m_centerPoint.y = cy / 2;
  550. CView::OnSize(nType, cx, cy);
  551. }
  552. HRESULT
  553. CSimpsonsView::Resize(DWORD nX, DWORD nY)
  554. {
  555. // MMTRACE("Resize\n");
  556. HRESULT hr;
  557. IDirectDrawSurface *pdds = NULL;
  558. CDXDBnds Bnds;
  559. MMASSERT(nX && nY);
  560. // store the new size
  561. m_sizWin.cx = nX;
  562. m_sizWin.cy = nY;
  563. Bnds.SetXYSize(m_sizWin);
  564. CHECK_HR(hr = m_pSurfFactory->CreateSurface(m_pDD, NULL, &DDPF_PMARGB32, &Bnds, 0,
  565. NULL, IID_IDXSurface, (void **) &pdds));
  566. CHECK_HR(hr = m_pDX2D->SetSurface(pdds));
  567. // render the image to the backbuffer
  568. CHECK_HR(hr = Render(true));
  569. // Hack: Get the client rect in screen coordinates. My hacky way of doing
  570. // this is to get the window rect and adjust it.
  571. GetWindowRect(&m_clientRectHack);
  572. m_clientRectHack.left += 2; m_clientRectHack.top += 2;
  573. m_clientRectHack.right -= 2; m_clientRectHack.bottom -= 2;
  574. CHECK_HR(hr = m_pDX2DScreen->SetClipRect(&m_clientRectHack));
  575. e_Exit:
  576. MMRELEASE(pdds);
  577. return hr;
  578. }
  579. void
  580. CSimpsonsView::OnDraw(CDC *pDC)
  581. {
  582. // MMTRACE("OnDraw\n");
  583. HRESULT hr;
  584. HDC hdcSurf = NULL;
  585. IDirectDrawSurface *pdds = NULL;
  586. DDSURFACEDESC ddsd;
  587. RECT rDim;
  588. UpdateStatusMessage();
  589. // get the size of the invalid area
  590. GetClientRect(&rDim);
  591. if ((rDim.left == rDim.right) || (rDim.top == rDim.bottom))
  592. return;
  593. CSimpsonsDoc *pDoc = GetDocument();
  594. // if this is a new document, build the GDI+ path list
  595. if (pDoc->HasNeverRendered()) BuildGDIPList();
  596. // check if the back buffer has changed size
  597. if (pDoc->HasNeverRendered() || (rDim.right != m_sizWin.cx) || (rDim.bottom != m_sizWin.cy)) {
  598. ResetTransform();
  599. CHECK_HR(hr = Resize(rDim.right, rDim.bottom));
  600. pDoc->MarkRendered();
  601. }
  602. ddsd.dwSize = sizeof(ddsd);
  603. CHECK_HR(hr = m_pDX2D->GetSurface(IID_IDirectDrawSurface, (void **) &pdds));
  604. CHECK_HR(hr = pdds->GetSurfaceDesc(&ddsd));
  605. CHECK_HR(hr = pdds->GetDC(&hdcSurf));
  606. ::BitBlt(pDC->m_hDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcSurf, 0, 0, SRCCOPY);
  607. e_Exit:
  608. if (hdcSurf) {
  609. pdds->ReleaseDC( hdcSurf );
  610. }
  611. MMRELEASE(pdds);
  612. }
  613. /////////////////////////////////////////////////////////////////////////////
  614. // CSimpsonsView diagnostics
  615. #ifdef _DEBUG
  616. void CSimpsonsView::AssertValid() const
  617. {
  618. CView::AssertValid();
  619. }
  620. void CSimpsonsView::Dump(CDumpContext& dc) const
  621. {
  622. CView::Dump(dc);
  623. }
  624. CSimpsonsDoc* CSimpsonsView::GetDocument() // non-debug version is inline
  625. {
  626. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSimpsonsDoc)));
  627. return (CSimpsonsDoc*)m_pDocument;
  628. }
  629. #endif //_DEBUG
  630. /////////////////////////////////////////////////////////////////////////////
  631. // CSimpsonsView message handlers
  632. #include "ddhelper.h"
  633. typedef DWORD FP;
  634. #define nEXPBIAS 127
  635. #define nEXPSHIFTS 23
  636. #define nEXPLSB (1 << nEXPSHIFTS)
  637. #define maskMANT (nEXPLSB - 1)
  638. #define FloatToFixedNoScale(nDst, fSrc) MACSTART \
  639. float fTmp = fSrc; \
  640. DWORD nRaw = *((FP *) &(fTmp)); \
  641. if (nRaw < (nEXPBIAS << nEXPSHIFTS)) \
  642. nDst = 0; \
  643. else \
  644. nDst = ((nRaw | nEXPLSB) << 8) >> ((nEXPBIAS + 31) - (nRaw >> nEXPSHIFTS)); \
  645. MACEND
  646. // This routine converts a 'float' to 28.4 fixed point format.
  647. inline FIX
  648. FloatToFix(float f)
  649. {
  650. FIX i;
  651. FloatToFixedNoScale(i, f*FIX_SCALE);
  652. return(i);
  653. }
  654. /*
  655. Draw a polygon with GDI. This version flattens beziers and packages
  656. the polygon up into a single polypoly call. (Compare to DrawGDIPolyPathAPI)
  657. */
  658. void
  659. CSimpsonsView::DrawGDIPoly(HDC hDC, PolyInfo *pPoly)
  660. {
  661. POINT rgpt[1024];
  662. DWORD rgcpt[30];
  663. DWORD cPoints = pPoly->cPoints;
  664. BEZIER32 bez;
  665. POINTFIX aptfxBez[4];
  666. MMASSERT(cPoints);
  667. DWORD *pcptBuffer;
  668. POINT *pptBuffer;
  669. POINT *pptFigure;
  670. DXFPOINT *pCurPoint = pPoly->pPoints;
  671. DXFPOINT *pCurPointLimit = pPoly->pPoints + cPoints;
  672. BYTE *pCurCode = pPoly->pCodes;
  673. pptBuffer = rgpt;
  674. pptFigure = rgpt;
  675. pcptBuffer = rgcpt;
  676. // In an effort to reduce our per-call overhead, we try to avoid
  677. // calling GDI's BeginPath/EndPath/FillPath routines, because they
  678. // just add significant time when the drawing is small. Instead,
  679. // we package everything up into PolyPoly calls that will draw
  680. // immediately.
  681. while (TRUE)
  682. {
  683. if (*pCurCode == PT_BEZIERTO)
  684. {
  685. aptfxBez[0].x = FloatToFix((pCurPoint-1)->x);
  686. aptfxBez[0].y = FloatToFix((pCurPoint-1)->y);
  687. aptfxBez[1].x = FloatToFix((pCurPoint)->x);
  688. aptfxBez[1].y = FloatToFix((pCurPoint)->y);
  689. aptfxBez[2].x = FloatToFix((pCurPoint+1)->x);
  690. aptfxBez[2].y = FloatToFix((pCurPoint+1)->y);
  691. aptfxBez[3].x = FloatToFix((pCurPoint+2)->x);
  692. aptfxBez[3].y = FloatToFix((pCurPoint+2)->y);
  693. if (bez.bInit(aptfxBez, NULL))
  694. {
  695. while (bez.bNext(pptBuffer++))
  696. ;
  697. }
  698. pCurPoint += 3;
  699. pCurCode += 3;
  700. }
  701. else
  702. {
  703. pptBuffer->x = FloatToFix(pCurPoint->x);
  704. pptBuffer->y = FloatToFix(pCurPoint->y);
  705. pptBuffer++;
  706. pCurPoint++;
  707. pCurCode++;
  708. }
  709. if (pCurPoint == pCurPointLimit)
  710. {
  711. *pcptBuffer++ = (DWORD)(pptBuffer - pptFigure);
  712. break;
  713. }
  714. if (*pCurCode == PT_MOVETO)
  715. {
  716. *pcptBuffer++ = (DWORD)(pptBuffer - pptFigure);
  717. pptFigure = pptBuffer;
  718. }
  719. }
  720. if (pPoly->dwFlags & DX2D_FILL)
  721. {
  722. if (!m_bNullPenSelected)
  723. {
  724. SelectObject(hDC, m_hNullPen);
  725. m_bNullPenSelected = TRUE;
  726. }
  727. PolyPolygon(hDC, rgpt, (INT*) rgcpt, (int) (pcptBuffer - rgcpt));
  728. }
  729. else
  730. {
  731. if (m_bNullPenSelected)
  732. {
  733. SelectObject(hDC, m_hStrokePen);
  734. m_bNullPenSelected = FALSE;
  735. }
  736. PolyPolyline(hDC, rgpt, rgcpt, (DWORD) (pcptBuffer - rgcpt));
  737. }
  738. }
  739. /*
  740. Same as DrawGDIPoly, but uses the slow GDI path functions.
  741. */
  742. void
  743. CSimpsonsView::DrawGDIPolyPathAPI(HDC hDC, PolyInfo *pPoly)
  744. {
  745. POINTFIX aptfxBez[3];
  746. POINTFIX pt;
  747. DXFPOINT *pCurPoint = pPoly->pPoints;
  748. DXFPOINT *pCurPointLimit = pPoly->pPoints + pPoly->cPoints;
  749. BYTE *pCurCode = pPoly->pCodes;
  750. BeginPath(hDC);
  751. while (pCurPoint < pCurPointLimit) {
  752. switch (*pCurCode) {
  753. case PT_BEZIERTO:
  754. aptfxBez[0].x = FloatToFix((pCurPoint)->x);
  755. aptfxBez[0].y = FloatToFix((pCurPoint)->y);
  756. aptfxBez[1].x = FloatToFix((pCurPoint+1)->x);
  757. aptfxBez[1].y = FloatToFix((pCurPoint+1)->y);
  758. aptfxBez[2].x = FloatToFix((pCurPoint+2)->x);
  759. aptfxBez[2].y = FloatToFix((pCurPoint+2)->y);
  760. PolyBezierTo(hDC, aptfxBez, 3);
  761. pCurPoint += 3;
  762. pCurCode += 3;
  763. break;
  764. case PT_LINETO:
  765. pt.x = FloatToFix(pCurPoint->x);
  766. pt.y = FloatToFix(pCurPoint->y);
  767. PolylineTo(hDC, &pt, 1);
  768. pCurPoint++;
  769. pCurCode++;
  770. break;
  771. case PT_MOVETO:
  772. MoveToEx(hDC,
  773. FloatToFix(pCurPoint->x),
  774. FloatToFix(pCurPoint->y),
  775. NULL);
  776. pCurPoint++;
  777. pCurCode++;
  778. break;
  779. }
  780. }
  781. EndPath(hDC);
  782. if (pPoly->dwFlags & DX2D_FILL)
  783. {
  784. if (!m_bNullPenSelected)
  785. {
  786. SelectObject(hDC, m_hNullPen);
  787. m_bNullPenSelected = TRUE;
  788. }
  789. FillPath(hDC);
  790. }
  791. else
  792. {
  793. if (m_bNullPenSelected)
  794. {
  795. SelectObject(hDC, m_hStrokePen);
  796. m_bNullPenSelected = FALSE;
  797. }
  798. StrokePath(hDC);
  799. }
  800. }
  801. /*
  802. Draw the scene using GDI.
  803. */
  804. void
  805. CSimpsonsView::DrawAllGDI(HDC hDC)
  806. {
  807. DWORD nStart, nEnd;
  808. int dataSource = ThisTestCase[TC::At_Source];
  809. nStart = timeGetTime();
  810. HPEN hpenOld;
  811. HBRUSH hbrushOld;
  812. HGDIOBJ hBrush;
  813. HDC hdcOutput;
  814. const RenderCmd *pCurCmd = GetDocument()->GetRenderCommands();
  815. if (pCurCmd == NULL)
  816. return;
  817. PolyInfo *pPoly;
  818. BrushInfo *pBrush;
  819. PenInfo *pPen;
  820. m_hNullPen = (HPEN) GetStockObject(NULL_PEN);
  821. m_bNullPenSelected = TRUE;
  822. if (ThisTestCase[TC::At_Destination]==TC::ToMetafile) {
  823. // Determine the picture frame dimensions.
  824. // iWidthMM is the display width in millimeters.
  825. // iHeightMM is the display height in millimeters.
  826. // iWidthPels is the display width in pixels.
  827. // iHeightPels is the display height in pixels
  828. LONG iWidthMM = GetDeviceCaps(hDC, HORZSIZE);
  829. LONG iHeightMM = GetDeviceCaps(hDC, VERTSIZE);
  830. LONG iWidthPels = GetDeviceCaps(hDC, HORZRES);
  831. LONG iHeightPels = GetDeviceCaps(hDC, VERTRES);
  832. // Hack the client rect
  833. RECT rect={0, 0, 500, 500};
  834. // Convert client coordinates to .01-mm units.
  835. // Use iWidthMM, iWidthPels, iHeightMM, and
  836. // iHeightPels to determine the number of
  837. // .01-millimeter units per pixel in the x-
  838. // and y-directions.
  839. rect.left = (rect.left * iWidthMM * 100)/iWidthPels;
  840. rect.top = (rect.top * iHeightMM * 100)/iHeightPels;
  841. rect.right = (rect.right * iWidthMM * 100)/iWidthPels;
  842. rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels;
  843. hdcOutput = CreateEnhMetaFile(hDC, "simpgdi.emf", &rect, NULL);
  844. if (!hdcOutput) { return; }
  845. } else {
  846. hdcOutput = hDC;
  847. }
  848. if (dataSource==TC::FromMetafile) {
  849. HENHMETAFILE hemf = GetEnhMetaFile("simpgdi.emf");
  850. if (hemf) {
  851. RECT rect = {0, 0, 500, 500};
  852. PlayEnhMetaFile(hdcOutput, hemf, &rect);
  853. DeleteEnhMetaFile(hemf);
  854. } else {
  855. printf("Metafile didn't load!\n");
  856. }
  857. } else {
  858. HGDIOBJ hOldBrush = SelectObject(hdcOutput, GetStockObject(WHITE_BRUSH));
  859. HGDIOBJ hOldPen = SelectObject(hdcOutput, m_hNullPen);
  860. // Here we set a 1/16th shrinking transform. We will have to
  861. // scale up all the points we give GDI by a factor of 16.
  862. //
  863. // We do this because when set in advanced mode, NT's GDI can
  864. // rasterize with 28.4 precision, and since we have factional
  865. // coordinates, this will make the result look better on NT.
  866. //
  867. // (There will be no difference on Win9x.)
  868. SetGraphicsMode(hdcOutput, GM_ADVANCED);
  869. SetMapMode(hdcOutput, MM_ANISOTROPIC);
  870. SetWindowExtEx(hdcOutput, FIX_SCALE, FIX_SCALE, NULL);
  871. for (;pCurCmd->nType != typeSTOP; pCurCmd++) {
  872. switch (pCurCmd->nType) {
  873. case typePOLY:
  874. // draw the polygon
  875. pPoly = (PolyInfo *) pCurCmd->pvData;
  876. if (!((m_bIgnoreStroke && (pPoly->dwFlags & DX2D_STROKE)) ||
  877. (m_bIgnoreFill && (pPoly->dwFlags & DX2D_FILL))))
  878. {
  879. if (dataSource == TC::PathAPI) {
  880. DrawGDIPolyPathAPI(hdcOutput, (PolyInfo *) pCurCmd->pvData);
  881. } else {
  882. ASSERT(dataSource == TC::CreatePoly);
  883. DrawGDIPoly(hdcOutput, (PolyInfo *) pCurCmd->pvData);
  884. }
  885. }
  886. break;
  887. case typeBRUSH:
  888. // select a new brush
  889. {
  890. pBrush = (BrushInfo *) pCurCmd->pvData;
  891. DWORD dwColor = pBrush->Color;
  892. BYTE r = BYTE(dwColor >> 16);
  893. BYTE g = BYTE(dwColor >> 8);
  894. BYTE b = BYTE(dwColor);
  895. hBrush = CreateSolidBrush(RGB(r,g,b));
  896. hbrushOld = (HBRUSH) SelectObject(hdcOutput, hBrush);
  897. DeleteObject(hbrushOld);
  898. }
  899. break;
  900. case typePEN:
  901. // select a new pen
  902. {
  903. pPen = (PenInfo *) pCurCmd->pvData;
  904. DWORD dwColor = pPen->Color;
  905. BYTE r = BYTE(dwColor >> 16);
  906. BYTE g = BYTE(dwColor >> 8);
  907. BYTE b = BYTE(dwColor);
  908. hpenOld = m_hStrokePen;
  909. m_hStrokePen = CreatePen(PS_SOLID,
  910. DWORD(pPen->fWidth * FIX_SCALE),
  911. RGB(r, g, b));
  912. if (!m_bNullPenSelected)
  913. {
  914. SelectObject(hdcOutput, m_hStrokePen);
  915. }
  916. DeleteObject(hpenOld);
  917. }
  918. break;
  919. }
  920. }
  921. SetMapMode(hdcOutput, MM_TEXT);
  922. SetGraphicsMode(hdcOutput, GM_COMPATIBLE);
  923. hbrushOld = (HBRUSH) SelectObject(hdcOutput, hOldBrush);
  924. hpenOld = (HPEN) SelectObject(hdcOutput, hOldPen);
  925. DeleteObject(hbrushOld);
  926. DeleteObject(hpenOld);
  927. DeleteObject(m_hStrokePen);
  928. }
  929. nEnd = timeGetTime();
  930. m_dwRenderTime = nEnd-nStart;
  931. if (ThisTestCase[TC::At_Destination]==TC::ToMetafile) {
  932. DeleteEnhMetaFile(CloseEnhMetaFile(hdcOutput));
  933. }
  934. }
  935. void
  936. CSimpsonsView::DrawGDIPPoly(Graphics *g, PolyInfo *pPoly, Pen *pen, Brush *brush)
  937. {
  938. GraphicsPath path(FillModeAlternate);
  939. DXFPOINT *pCurPoint = pPoly->pPoints;
  940. DXFPOINT *pCurPointLimit = pPoly->pPoints + pPoly->cPoints;
  941. BYTE *pCurCode = pPoly->pCodes;
  942. DXFPOINT currentPosition;
  943. while (pCurPoint < pCurPointLimit)
  944. {
  945. switch (*pCurCode)
  946. {
  947. case PT_BEZIERTO:
  948. path.AddBezier(
  949. (pCurPoint-1)->x, (pCurPoint-1)->y,
  950. (pCurPoint) ->x, (pCurPoint) ->y,
  951. (pCurPoint+1)->x, (pCurPoint+1)->y,
  952. (pCurPoint+2)->x, (pCurPoint+2)->y);
  953. pCurPoint += 3;
  954. pCurCode += 3;
  955. break;
  956. case PT_MOVETO:
  957. path.StartFigure();
  958. pCurPoint++;
  959. pCurCode++;
  960. break;
  961. case PT_LINETO:
  962. path.AddLine(
  963. (pCurPoint-1)->x,
  964. (pCurPoint-1)->y,
  965. (pCurPoint)->x,
  966. (pCurPoint)->y);
  967. pCurPoint++;
  968. pCurCode++;
  969. break;
  970. }
  971. }
  972. if (pPoly->dwFlags & DX2D_FILL)
  973. {
  974. g->FillPath(brush, &path);
  975. }
  976. else
  977. {
  978. g->DrawPath(pen, &path);
  979. }
  980. }
  981. struct BitmapInfo
  982. {
  983. BITMAPINFOHEADER bmiHeader;
  984. RGBQUAD bmiColors[256]; // 256 is the maximum palette size
  985. };
  986. /*
  987. Build an array of GDI+ paths for the current document.
  988. This is used as a 'native' data source - so that we don't time path
  989. creation when rendering. Even in this mode, DrawAllGDIP() still uses the
  990. RenderCmd buffer to read pen and brush data.
  991. */
  992. void
  993. CSimpsonsView::BuildGDIPList()
  994. {
  995. // Free the old path array, if any
  996. if (m_gpPathArray) {
  997. delete [] m_gpPathArray;
  998. m_gpPathArray = NULL;
  999. }
  1000. const RenderCmd *pCmd = GetDocument()->GetRenderCommands();
  1001. const RenderCmd *pCurCmd;
  1002. if (!pCmd) return;
  1003. // Count the number of polygons
  1004. int count=0;
  1005. for (pCurCmd=pCmd; pCurCmd->nType != typeSTOP; pCurCmd++) {
  1006. if (pCurCmd->nType == typePOLY) count++;
  1007. }
  1008. m_gpPathArray = new GraphicsPath [count];
  1009. if (!m_gpPathArray) return;
  1010. GraphicsPath *pPath=m_gpPathArray;
  1011. PolyInfo *pPoly;
  1012. // Add each polygon to the path array
  1013. for (pCurCmd=pCmd; pCurCmd->nType != typeSTOP; pCurCmd++) {
  1014. if (pCurCmd->nType==typePOLY) {
  1015. pPoly = (PolyInfo *) pCurCmd->pvData;
  1016. DXFPOINT *pCurPoint = pPoly->pPoints;
  1017. DXFPOINT *pCurPointLimit = pPoly->pPoints + pPoly->cPoints;
  1018. BYTE *pCurCode = pPoly->pCodes;
  1019. DXFPOINT currentPosition;
  1020. while (pCurPoint < pCurPointLimit)
  1021. {
  1022. switch (*pCurCode) {
  1023. case PT_BEZIERTO:
  1024. pPath->AddBezier(
  1025. (pCurPoint-1)->x, (pCurPoint-1)->y,
  1026. (pCurPoint) ->x, (pCurPoint) ->y,
  1027. (pCurPoint+1)->x, (pCurPoint+1)->y,
  1028. (pCurPoint+2)->x, (pCurPoint+2)->y);
  1029. pCurPoint += 3;
  1030. pCurCode += 3;
  1031. break;
  1032. case PT_MOVETO:
  1033. pPath->StartFigure();
  1034. pCurPoint++;
  1035. pCurCode++;
  1036. break;
  1037. case PT_LINETO:
  1038. pPath->AddLine(
  1039. (pCurPoint-1)->x,
  1040. (pCurPoint-1)->y,
  1041. (pCurPoint)->x,
  1042. (pCurPoint)->y);
  1043. pCurPoint++;
  1044. pCurCode++;
  1045. break;
  1046. }
  1047. }
  1048. pPath++;
  1049. }
  1050. }
  1051. printf ("BuildGDIPList successful\n");
  1052. }
  1053. void
  1054. CSimpsonsView::DrawAllGDIP(HDC hDC)
  1055. {
  1056. DWORD nStart, nEnd;
  1057. //
  1058. // START TIMING
  1059. //
  1060. nStart = timeGetTime();
  1061. int dataSource = ThisTestCase[TC::At_Source];
  1062. const RenderCmd *pCurCmd = GetDocument()->GetRenderCommands();
  1063. if (pCurCmd == NULL)
  1064. return;
  1065. PolyInfo *pPoly;
  1066. BrushInfo *pBrush;
  1067. PenInfo *pPen;
  1068. GraphicsPath *pPath = NULL;
  1069. if (dataSource==TC::Native) {
  1070. pPath = m_gpPathArray;
  1071. if (!pPath) {
  1072. printf("GDI+ Native data is invalid\n");
  1073. return;
  1074. }
  1075. }
  1076. Graphics *gOutput, *g;
  1077. Metafile *recMetafile, *playMetafile;
  1078. g = Graphics::FromHDC(hDC);
  1079. if (ThisTestCase[TC::At_Destination]==TC::ToMetafile) {
  1080. recMetafile = new Metafile(L"simpsons.emf", hDC);
  1081. if (!recMetafile) { delete g; return; }
  1082. gOutput = Graphics::FromImage(recMetafile);
  1083. } else {
  1084. gOutput = g;
  1085. }
  1086. if (ThisTestCase[TC::At_Aliasing]==TC::Antialiased) {
  1087. gOutput->SetSmoothingMode(SmoothingModeAntiAlias);
  1088. } else {
  1089. gOutput->SetSmoothingMode(SmoothingModeNone);
  1090. }
  1091. if (dataSource==TC::FromMetafile) {
  1092. playMetafile = new Metafile(L"simpsons.emf");
  1093. if (playMetafile) {
  1094. GpRectF playbackRect;
  1095. gOutput->GetVisibleClipBounds(&playbackRect);
  1096. gOutput->DrawImage(playMetafile, 0, 0);
  1097. } else {
  1098. printf("Metafile didn't load!\n");
  1099. }
  1100. } else {
  1101. Color black(0,0,0);
  1102. Pen currentPen(black, 1);
  1103. SolidBrush currentBrush(black);
  1104. for (;pCurCmd->nType != typeSTOP; pCurCmd++) {
  1105. switch (pCurCmd->nType) {
  1106. case typePOLY:
  1107. // convert points to fixed point
  1108. pPoly = (PolyInfo *) pCurCmd->pvData;
  1109. if (!((m_bIgnoreStroke && (pPoly->dwFlags & DX2D_STROKE)) ||
  1110. (m_bIgnoreFill && (pPoly->dwFlags & DX2D_FILL))))
  1111. {
  1112. if (pPath) {
  1113. // Draw from the pre-created path list
  1114. if (pPoly->dwFlags & DX2D_FILL)
  1115. {
  1116. gOutput->FillPath(&currentBrush, pPath);
  1117. }
  1118. else
  1119. {
  1120. gOutput->DrawPath(&currentPen, pPath);
  1121. }
  1122. } else {
  1123. ASSERT(dataSource == TC::PathAPI);
  1124. // Create the path and draw it
  1125. DrawGDIPPoly(gOutput, (PolyInfo *) pCurCmd->pvData, &currentPen, &currentBrush);
  1126. }
  1127. }
  1128. if(pPath != NULL) pPath++;
  1129. break;
  1130. case typeBRUSH:
  1131. {
  1132. // change brush color
  1133. pBrush = (BrushInfo *) pCurCmd->pvData;
  1134. DWORD dwColor = pBrush->Color;
  1135. BYTE r = BYTE(dwColor >> 16);
  1136. BYTE g = BYTE(dwColor >> 8);
  1137. BYTE b = BYTE(dwColor);
  1138. Color c(r,g,b);
  1139. currentBrush.SetColor(c);
  1140. }
  1141. break;
  1142. case typePEN:
  1143. #if 0
  1144. {
  1145. // select a new pen
  1146. pPen = (PenInfo *) pCurCmd->pvData;
  1147. DWORD dwColor = pPen->Color;
  1148. BYTE r = BYTE(dwColor >> 16);
  1149. BYTE g = BYTE(dwColor >> 8);
  1150. BYTE b = BYTE(dwColor);
  1151. currentPen.SetPenColor(Color(r,g,b));
  1152. }
  1153. #endif
  1154. break;
  1155. }
  1156. }
  1157. }
  1158. gOutput->Flush();
  1159. if (ThisTestCase[TC::At_Source]==TC::FromMetafile) {
  1160. delete playMetafile;
  1161. }
  1162. if (ThisTestCase[TC::At_Destination]==TC::ToMetafile) {
  1163. delete gOutput;
  1164. delete recMetafile;
  1165. }
  1166. delete g;
  1167. //
  1168. // STOP TIMING
  1169. //
  1170. nEnd = timeGetTime();
  1171. m_dwRenderTime = nEnd-nStart;
  1172. }
  1173. void
  1174. CSimpsonsView::UpdateStatusMessage()
  1175. {
  1176. using namespace TC;
  1177. sprintf(g_rgchTmpBuf, "Time: %dms %s Src: %s Dst: %s, %s",
  1178. // GetDocument()->GetFileName(),
  1179. m_dwRenderTime,
  1180. OptionStr[At_Library][ThisTestCase[At_Library]],
  1181. OptionStr[At_Source][ThisTestCase[At_Source]],
  1182. OptionStr[At_Destination][ThisTestCase[At_Destination]],
  1183. OptionStr[At_Aliasing][ThisTestCase[At_Aliasing]]
  1184. );
  1185. // OutputDebugString(g_rgchTmpBuf);
  1186. // OutputDebugString("\n");
  1187. CFrameWnd *pFrame = GetParentFrame();
  1188. if (pFrame)
  1189. pFrame->SetMessageText(g_rgchTmpBuf);
  1190. }
  1191. void
  1192. CSimpsonsView::DrawAll(IDX2D *pDX2D)
  1193. {
  1194. DWORD nStart, nEnd;
  1195. nStart = timeGetTime();
  1196. const RenderCmd *pCurCmd = GetDocument()->GetRenderCommands();
  1197. DXBRUSH Brush;
  1198. DXPEN Pen;
  1199. // intialize Pen and Brush
  1200. Pen.pTexture = NULL;
  1201. Pen.TexturePos.x = 0.f;
  1202. Pen.TexturePos.y = 0.f;
  1203. Brush.pTexture = NULL;
  1204. Brush.TexturePos.x = 0.f;
  1205. Brush.TexturePos.y = 0.f;
  1206. PolyInfo *pPoly;
  1207. BrushInfo *pBrush;
  1208. PenInfo *pPen;
  1209. bool bBrush = false, bPen = false;
  1210. for (;pCurCmd->nType != typeSTOP; pCurCmd++) {
  1211. switch (pCurCmd->nType) {
  1212. case typePOLY:
  1213. pPoly = (PolyInfo *) pCurCmd->pvData;
  1214. if (!((m_bIgnoreStroke && (pPoly->dwFlags & DX2D_STROKE)) ||
  1215. (m_bIgnoreFill && (pPoly->dwFlags & DX2D_FILL))))
  1216. {
  1217. pDX2D->AAPolyDraw(pPoly->pPoints, pPoly->pCodes, pPoly->cPoints, 4, pPoly->dwFlags);
  1218. }
  1219. break;
  1220. case typeBRUSH:
  1221. // select a new brush
  1222. pBrush = (BrushInfo *) pCurCmd->pvData;
  1223. Brush.Color = pBrush->Color;
  1224. pDX2D->SetBrush(&Brush);
  1225. bBrush = true;
  1226. break;
  1227. case typePEN:
  1228. // select a new pen
  1229. pPen = (PenInfo *) pCurCmd->pvData;
  1230. Pen.Color = pPen->Color;
  1231. Pen.Width = pPen->fWidth;
  1232. Pen.Style = pPen->dwStyle;
  1233. pDX2D->SetPen(&Pen);
  1234. bPen = true;
  1235. break;
  1236. }
  1237. }
  1238. nEnd = timeGetTime();
  1239. m_dwRenderTime = nEnd-nStart;
  1240. }
  1241. HRESULT CSimpsonsView::Render(bool bInvalidate)
  1242. {
  1243. // MMTRACE("Render\n");
  1244. RECT rc = {0, 0, 500, 400};
  1245. HRESULT hr = S_OK;
  1246. IDirectDrawSurface *pdds = NULL;
  1247. IDXSurface *pDXSurf = NULL;
  1248. HDC screenDC = NULL, drawDC = NULL, memDC = NULL;
  1249. BOOL bFinished = false;
  1250. DWORD executionTime;
  1251. sprintf(g_rgchTmpBuf, "Rendering with %s...", TC::OptionStr[TC::At_Library][ThisTestCase[TC::At_Library]]);
  1252. CFrameWnd *pFrame = GetParentFrame();
  1253. if (pFrame) {
  1254. pFrame->SetMessageText(g_rgchTmpBuf);
  1255. }
  1256. CHECK_HR(hr = m_pDX2D->GetSurface(IID_IDXSurface, (void **) &pDXSurf));
  1257. CHECK_HR(hr = pDXSurf->GetDirectDrawSurface(IID_IDirectDrawSurface, (void **) &pdds));
  1258. while (!bFinished) {
  1259. DXFillSurface(pDXSurf, g_aColors[g_ulColorIndex]);
  1260. //--- Set alias mode
  1261. // CHECK_HR(hr = m_pDX2D->_SetDelegateToGDI(m_bAliased));
  1262. //--- Set global opacity
  1263. // CHECK_HR(hr = m_pDX2D->SetGlobalOpacity(1.f));
  1264. CHECK_HR(hr = m_pDX2D->SetWorldTransform(&m_XForm));
  1265. CDX2DXForm xform;
  1266. xform = m_XForm;
  1267. xform.Translate((REAL)m_clientRectHack.left, (REAL)m_clientRectHack.top);
  1268. CHECK_HR(hr = m_pDX2DScreen->SetWorldTransform(&xform));
  1269. //--- Get the DC of the DD surface.
  1270. CHECK_HR(hr = pdds->GetDC(&memDC));
  1271. // render the scene and compute timing
  1272. // Set the timer resolution to 1ms
  1273. if (timeBeginPeriod(1)==TIMERR_NOCANDO) {
  1274. hr = ERROR_INVALID_FUNCTION;
  1275. goto e_Exit;
  1276. }
  1277. /*
  1278. For the direct-to-screen cases, we bypass the ddraw surface.
  1279. For repaints to look pretty, though, we copy the result to the ddraw
  1280. surface (after the timer has been turned off.)
  1281. */
  1282. drawDC = memDC;
  1283. HBRUSH backgroundBrush;
  1284. if (ThisTestCase[TC::At_Destination]==TC::Screen) {
  1285. screenDC = ::GetDC(m_hWnd);
  1286. backgroundBrush = CreateSolidBrush(g_aColors[g_ulColorIndex] & 0xffffff);
  1287. FillRect(screenDC, &rc, backgroundBrush);
  1288. DeleteObject(backgroundBrush);
  1289. drawDC = screenDC;
  1290. }
  1291. // The 'DrawAll' routine will actually do the timeGetTime() and store the
  1292. // result in m_dwRenderTime.
  1293. switch (ThisTestCase[TC::At_Library]) {
  1294. case TC::GDI:
  1295. DrawAllGDI(drawDC);
  1296. break;
  1297. case TC::Meta:
  1298. if (ThisTestCase[TC::At_Destination]==TC::Screen) {
  1299. DrawAll(m_pDX2DScreen);
  1300. } else {
  1301. DrawAll(m_pDX2D);
  1302. }
  1303. break;
  1304. case TC::GDIP:
  1305. DrawAllGDIP(drawDC);
  1306. break;
  1307. }
  1308. // !!! Release and re-acquire the DDraw surface DC to work-around
  1309. // a current limitation in GDI+ where Graphics(hdc) nukes the
  1310. // hdc of a DDraw surface
  1311. pdds->ReleaseDC(memDC); memDC = NULL;
  1312. CHECK_HR(hr = pdds->GetDC(&memDC));
  1313. if (ThisTestCase[TC::At_Destination]==TC::Screen) {
  1314. bInvalidate = false;
  1315. UpdateStatusMessage();
  1316. // Copy to from the screen to the ddraw surface,
  1317. // so that repaints work.
  1318. ::BitBlt(memDC, 0, 0, 500, 400, screenDC, 0, 0, SRCCOPY);
  1319. }
  1320. timeEndPeriod(1); // Reset the multimedia timer to default resolution
  1321. pdds->ReleaseDC(memDC); memDC = NULL;
  1322. if (screenDC) {
  1323. ::ReleaseDC(m_hWnd, screenDC);
  1324. screenDC = NULL;
  1325. }
  1326. if (m_CycleTests) {
  1327. bFinished = IncrementTest();
  1328. } else {
  1329. bFinished = true;
  1330. }
  1331. }
  1332. e_Exit:
  1333. //--- Clean-up
  1334. if (pdds) {
  1335. if (memDC)
  1336. pdds->ReleaseDC(memDC);
  1337. MMRELEASE(pdds);
  1338. }
  1339. if (screenDC) {
  1340. ::ReleaseDC(m_hWnd, screenDC);
  1341. }
  1342. MMRELEASE(pDXSurf);
  1343. //--- draw
  1344. if (bInvalidate)
  1345. Invalidate();
  1346. return hr;
  1347. }
  1348. void CSimpsonsView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  1349. {
  1350. bool bNothing = false;
  1351. float fTheta = 1.f;
  1352. if (nChar == 'G') {
  1353. ToggleGDI();
  1354. } else if (nChar == 'A') {
  1355. bNothing = !IncrementAttribute(TC::At_Aliasing);
  1356. } else if (nChar == 'D') {
  1357. bNothing = !IncrementAttribute(TC::At_Destination);
  1358. } else if (nChar == 'I') {
  1359. IncrementTest();
  1360. } else if ((nChar >= '0') && (nChar <= '9')) {
  1361. g_ulColorIndex = (nChar - '0');
  1362. } else if (nChar == ' ') {
  1363. // Redraw
  1364. } else if (nChar == 'R') {
  1365. ResetTransform();
  1366. } else if (nChar == 'F') {
  1367. ToggleFill();
  1368. } else if (nChar == 'S') {
  1369. ToggleStroke();
  1370. } else if (nChar == 'C') {
  1371. m_CycleTests = true;
  1372. m_testCaseNumber = 0;
  1373. if (m_pDX2DDebug) m_pDX2DDebug->SetDC(NULL);
  1374. } else if (nChar == VK_LEFT) {
  1375. AddRotation(fTheta);
  1376. } else if (nChar == VK_RIGHT) {
  1377. AddRotation(-fTheta);
  1378. } else {
  1379. bNothing = true;
  1380. }
  1381. if (!bNothing)
  1382. Render(true);
  1383. if (m_CycleTests) {
  1384. PrintTestResults();
  1385. m_CycleTests = false;
  1386. }
  1387. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  1388. }
  1389. void
  1390. CSimpsonsView::ToggleStroke()
  1391. {
  1392. m_bIgnoreStroke ^= 1;
  1393. }
  1394. void
  1395. CSimpsonsView::ToggleFill()
  1396. {
  1397. m_bIgnoreFill ^= 1;
  1398. }
  1399. void
  1400. CSimpsonsView::ResetTransform()
  1401. {
  1402. m_XForm.SetIdentity();
  1403. }
  1404. void
  1405. CSimpsonsView::AddRotation(float fTheta)
  1406. {
  1407. m_XForm.Rotate(fTheta);
  1408. }
  1409. void
  1410. CSimpsonsView::ToggleGDI()
  1411. {
  1412. HRESULT hr = S_OK;
  1413. IDXSurface *pdxsRender = NULL;
  1414. IDirectDrawSurface *pddsRender = NULL;
  1415. HDC hDC = NULL;
  1416. IncrementAttribute(TC::At_Library);
  1417. if (m_pDX2DDebug) {
  1418. switch (ThisTestCase[TC::At_Library]) {
  1419. case TC::GDI:
  1420. case TC::GDIP:
  1421. CHECK_HR(hr = m_pDX2D->GetSurface(IID_IDXSurface, (void**) &pdxsRender));
  1422. CHECK_HR(hr = pdxsRender->QueryInterface(IID_IDirectDrawSurface, (void **) &pddsRender));
  1423. CHECK_HR(hr = pddsRender->GetDC(&hDC));
  1424. m_pDX2DDebug->SetDC(hDC);
  1425. break;
  1426. case TC::Meta:
  1427. m_pDX2DDebug->SetDC(NULL);
  1428. break;
  1429. }
  1430. }
  1431. e_Exit:
  1432. if (pddsRender && hDC)
  1433. pddsRender->ReleaseDC(hDC);
  1434. MMRELEASE(pddsRender);
  1435. MMRELEASE(pdxsRender);
  1436. }
  1437. void
  1438. CSimpsonsView::OnLButtonDown(UINT nFlags, CPoint pt)
  1439. {
  1440. CView::OnLButtonDown(nFlags, pt);
  1441. }
  1442. void
  1443. CSimpsonsView::OnRButtonDown(UINT nFlags, CPoint point)
  1444. {
  1445. CView::OnRButtonDown(nFlags, point);
  1446. }
  1447. void
  1448. CSimpsonsView::ForceUpdate()
  1449. {
  1450. HRESULT hr;
  1451. Render(false);
  1452. HDC hdcSurf = NULL;
  1453. IDirectDrawSurface *pdds = NULL;
  1454. DDSURFACEDESC ddsd;
  1455. CDC *pDC = GetDC();
  1456. ddsd.dwSize = sizeof(ddsd);
  1457. CHECK_HR(hr = m_pDX2D->GetSurface(IID_IDirectDrawSurface, (void **) &pdds));
  1458. CHECK_HR(hr = pdds->GetSurfaceDesc(&ddsd));
  1459. CHECK_HR(hr = pdds->GetDC(&hdcSurf));
  1460. ::BitBlt(pDC->m_hDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcSurf, 0, 0, SRCCOPY);
  1461. UpdateStatusMessage();
  1462. e_Exit:
  1463. if (pdds && hdcSurf)
  1464. pdds->ReleaseDC(hdcSurf);
  1465. MMRELEASE(pdds);
  1466. }
  1467. void
  1468. CSimpsonsView::DoMove(POINT &pt)
  1469. {
  1470. if ((m_lastPoint.x != pt.x) && (m_lastPoint.y != pt.y)) {
  1471. float dx = float(pt.x - m_lastPoint.x);
  1472. float dy = float(pt.y - m_lastPoint.y);
  1473. if (m_scaling) {
  1474. float scale = 1.f + dx * fZOOMFACTOR;
  1475. CLAMP(scale, fSCALEMIN, fSCALEMAX);
  1476. m_XForm.Translate(float(-m_centerPoint.x), float(-m_centerPoint.y));
  1477. m_XForm.Scale(scale, scale);
  1478. m_XForm.Translate(float(m_centerPoint.x), float(m_centerPoint.y));
  1479. } else {
  1480. // panning
  1481. m_XForm.Translate(dx, dy);
  1482. }
  1483. ForceUpdate();
  1484. m_lastPoint = pt;
  1485. }
  1486. }
  1487. void
  1488. CSimpsonsView::OnLButtonUp(UINT nFlags, CPoint ptPassed)
  1489. {
  1490. POINT pt;
  1491. GetCursorPos(&pt);
  1492. ScreenToClient(&pt);
  1493. DoMove(pt);
  1494. CView::OnLButtonUp(nFlags, pt);
  1495. }
  1496. void
  1497. CSimpsonsView::OnMouseMove(UINT nFlagsPassed, CPoint ptPassed)
  1498. {
  1499. // get current mouse position
  1500. POINT pt;
  1501. GetCursorPos(&pt);
  1502. ScreenToClient(&pt);
  1503. // check if left mouse button is down
  1504. m_tracking = (GetAsyncKeyState(VK_LBUTTON) && (m_bLButton || IsInside(pt.x, pt.y, m_sizWin)));
  1505. if (m_tracking) {
  1506. if (m_bLButton) {
  1507. DoMove(pt);
  1508. } else {
  1509. m_scaling = ((GetAsyncKeyState(VK_CONTROL) & ~0x1) != 0);
  1510. m_bLButton = true;
  1511. m_centerPoint = pt;
  1512. m_lastPoint = pt;
  1513. }
  1514. }
  1515. m_bLButton = m_tracking;
  1516. CView::OnMouseMove(nFlagsPassed, ptPassed);
  1517. }
  1518. BOOL
  1519. CSimpsonsView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  1520. {
  1521. float fDelta = float (zDelta / 1200.f);
  1522. float fScale = 1.f - fDelta;
  1523. CLAMP(fScale, fSCALEMIN, fSCALEMAX);
  1524. m_XForm.Translate(float(-m_centerPoint.x), float(-m_centerPoint.y));
  1525. m_XForm.Scale(fScale, fScale);
  1526. m_XForm.Translate(float(m_centerPoint.x), float(m_centerPoint.y));
  1527. ForceUpdate();
  1528. return CView::OnMouseWheel(nFlags, zDelta, pt);
  1529. }
  1530. _cdecl
  1531. main(INT argc, PCHAR argb[])
  1532. {
  1533. return(1);
  1534. }