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.

2065 lines
57 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: wndstuff.cpp
  3. *
  4. * This file contains all the code necessary for a simple GDI+ primitive
  5. * test.
  6. *
  7. * Author: J. Andrew Goossen [andrewgo]
  8. *
  9. * Copyright (c) 1991-2000 Microsoft Corporation
  10. *
  11. \**************************************************************************/
  12. #include <stddef.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <math.h>
  16. #include <float.h>
  17. #include <windows.h>
  18. #include <objbase.h>
  19. #include <mmsystem.h>
  20. #include <gdiplus.h>
  21. using namespace Gdiplus;
  22. #include "wndstuff.h"
  23. #include "../gpinit.inc"
  24. #define HIT_DISTANCE 16
  25. #define ABS(x) (((x) >= 0) ? (x) : -(x))
  26. #define ROUND(x) ((INT) floor(x + 0.5f))
  27. // We set the GDI transform to a 16x scaling transform, and the mode to
  28. // GM_ADVANCED, so that we can get full fractional accuracy on the points
  29. // that we feed to GDI:
  30. #define GDI_FIXEDPOINT_SCALE 16
  31. // State for tracking the primitive vertices and transform:
  32. const INT PrimitivePointsMax = 64;
  33. INT PrimitivePointsCount = 4;
  34. PointF PrimitivePoints[PrimitivePointsMax] = { PointF(100, 100),
  35. PointF(100, 400),
  36. PointF(400, 400),
  37. PointF(400, 100) };
  38. Matrix *PrimitiveTransform;
  39. Matrix *PrimitiveInverseTransform;
  40. INT PrimitiveDragVertex = -1;
  41. BOOL IsAddingPoints = FALSE;
  42. // State for tracking the location of the transform overlay:
  43. const REAL OverlayDimension = 100;
  44. PointF OverlayPoints[3]; // 3 device-space representing overlay,
  45. // where [1] is the elbow
  46. PointF OverlayOffset; // World-space coordinate of overlay elbow
  47. INT OverlayDragVertex = -1;
  48. // Miscellaneous state:
  49. INT WindowWidth;
  50. INT WindowHeight;
  51. // Settings:
  52. BOOL DoFill = FALSE;
  53. BOOL DoDraw = TRUE;
  54. BOOL DoAntialias = FALSE;
  55. BOOL DoGammaCorrect = FALSE;
  56. BOOL DoGdi = FALSE;
  57. BOOL DoClipGrid = FALSE;
  58. BOOL DoRandomTest = FALSE;
  59. BOOL DoWindingFill = FALSE;
  60. BOOL DoAnchors = TRUE;
  61. BOOL DoSpine = FALSE;
  62. BOOL DoWiden = FALSE;
  63. BOOL DoCompound = FALSE;
  64. BOOL DoTransformOverlay = FALSE;
  65. BOOL DoScalingOnly = FALSE;
  66. BOOL DoShape = FALSE;
  67. BOOL DoBrushRect = FALSE;
  68. REAL RenderMiterLimit = 10;
  69. INT RenderWidth = 1;
  70. INT RenderAlpha = 255;
  71. LinearGradientBrush *LinearBrush;
  72. GraphicsPath *PathGradientPath;
  73. Brush *RenderBrush;
  74. Pen *RenderPen;
  75. Region *RenderRegion;
  76. HRGN RenderHrgn;
  77. HBRUSH RenderHbrush;
  78. HPEN RenderHpen;
  79. WORD MmWrapMode = MM_WRAP_TILE;
  80. WORD MmBrushType = MM_BRUSH_SOLID;
  81. WORD MmEndCap = MM_CAP_FLAT;
  82. WORD MmJoin = MM_JOIN_MITER;
  83. WORD MmDashStyle = MM_STYLE_SOLID;
  84. WORD MmAlignment = MM_ALIGNMENT_CENTER;
  85. WORD MmPrimitive = MM_POLYGON;
  86. // Other useful globals:
  87. HINSTANCE ghInstance;
  88. HWND ghwndMain;
  89. HBRUSH ghbrWhite;
  90. //FARPROC glpfnEnterWidth;
  91. //FARPROC glpfnEnterAlpha;
  92. //FARPROC glpfnEnterPoints;
  93. //FARPROC glpfnEnterTransform;
  94. /***************************************************************************\
  95. * Creates the GDI+ brush to be used.
  96. *
  97. \***************************************************************************/
  98. VOID
  99. CreateBrush_Gdiplus()
  100. {
  101. WrapMode wrapMode;
  102. INT i;
  103. // Delete the old brush:
  104. delete RenderBrush;
  105. LinearBrush = NULL;
  106. RenderBrush = NULL;
  107. // Create the new one:
  108. Bitmap bitmap(L"winnt256.bmp");
  109. switch (MmWrapMode)
  110. {
  111. case MM_WRAP_TILE: wrapMode = WrapModeTile; break;
  112. case MM_WRAP_CLAMP: wrapMode = WrapModeClamp; break;
  113. case MM_WRAP_FLIPX: wrapMode = WrapModeTileFlipX; break;
  114. case MM_WRAP_FLIPY: wrapMode = WrapModeTileFlipY; break;
  115. case MM_WRAP_FLIPXY: wrapMode = WrapModeTileFlipXY; break;
  116. }
  117. switch (MmBrushType)
  118. {
  119. case MM_BRUSH_SOLID:
  120. RenderBrush = new SolidBrush(Color(128, 128, 128));
  121. break;
  122. case MM_BRUSH_TEXTURE:
  123. RenderBrush = new TextureBrush(&bitmap, wrapMode);
  124. break;
  125. case MM_BRUSH_TEXTURE_32x32:
  126. {
  127. Bitmap texture(32, 32, PixelFormat32bppARGB);
  128. Graphics g(&texture);
  129. g.DrawImage(&bitmap, Rect(0, 0, 32, 32));
  130. TextureBrush *brush = new TextureBrush(&texture, wrapMode);
  131. // Set a translate:
  132. Matrix matrix(1, 0, 0, 1, 100, 100);
  133. brush->SetTransform(&matrix);
  134. RenderBrush = brush;
  135. }
  136. break;
  137. case MM_BRUSH_TEXTURE_1x1:
  138. {
  139. SolidBrush solidBrush(Color::Green);
  140. Bitmap texture(1, 1, PixelFormat32bppARGB);
  141. Graphics g(&texture);
  142. g.FillRectangle(&solidBrush, 0, 0, 1, 1);
  143. TextureBrush *brush = new TextureBrush(&texture, wrapMode);
  144. // Set a translate:
  145. Matrix matrix(1, 0, 0, 1, 100, 100);
  146. brush->SetTransform(&matrix);
  147. RenderBrush = brush;
  148. }
  149. break;
  150. case MM_BRUSH_LINEAR:
  151. {
  152. LinearGradientBrush *brush = new LinearGradientBrush(
  153. Point(100, 100),
  154. Point(100, 300),
  155. Color::Red,
  156. Color::Black
  157. );
  158. brush->SetWrapMode(wrapMode);
  159. RenderBrush = brush;
  160. LinearBrush = brush;
  161. }
  162. break;
  163. case MM_BRUSH_PATHGRADIENT:
  164. {
  165. PathGradientBrush *brush;
  166. INT count;
  167. if (PathGradientPath != NULL)
  168. {
  169. brush = new PathGradientBrush(PathGradientPath);
  170. count = PathGradientPath->GetPointCount();
  171. }
  172. else
  173. {
  174. // Substitute a default path for now:
  175. PointF points[] = { PointF(100, 100), PointF(100, 300),
  176. PointF(300, 300), PointF(30, 100) };
  177. brush = new PathGradientBrush(points, 4);
  178. count = 4;
  179. }
  180. Color *colors = new Color[count];
  181. for (i = 0; i < count; i += 2)
  182. {
  183. colors[i] = Color::Green;
  184. colors[i+1] = Color::Red;
  185. }
  186. brush->SetSurroundColors(colors, &count);
  187. delete [] colors;
  188. brush->SetCenterPoint(OverlayOffset);
  189. brush->SetCenterColor(Color::Black);
  190. RenderBrush = brush;
  191. }
  192. break;
  193. }
  194. }
  195. /***************************************************************************\
  196. * Creates the GDI brush to be used.
  197. *
  198. \***************************************************************************/
  199. VOID
  200. CreateBrush_Gdi()
  201. {
  202. DeleteObject(RenderHbrush);
  203. RenderHbrush = CreateSolidBrush(RGB(128, 128, 128));
  204. }
  205. /***************************************************************************\
  206. * Creates the GDI and GDI+ brushes to be used.
  207. *
  208. \***************************************************************************/
  209. VOID
  210. CreateBrushes()
  211. {
  212. CreateBrush_Gdiplus();
  213. CreateBrush_Gdi();
  214. }
  215. /***************************************************************************\
  216. * Creates the GDI+ pen to be used.
  217. *
  218. \***************************************************************************/
  219. VOID
  220. CreatePen_Gdiplus()
  221. {
  222. DashCap dashCap;
  223. LineCap lineCap;
  224. LineJoin lineJoin;
  225. DashStyle dashStyle;
  226. PenAlignment alignment;
  227. delete RenderPen;
  228. RenderPen = new Pen(Color((BYTE) RenderAlpha, 255, 0, 0), (REAL) RenderWidth);
  229. switch (MmEndCap)
  230. {
  231. case MM_CAP_ROUND: lineCap = LineCapRound; dashCap = DashCapRound; break;
  232. case MM_CAP_SQUARE: lineCap = LineCapSquare; dashCap = DashCapFlat; break;
  233. case MM_CAP_FLAT: lineCap = LineCapFlat; dashCap = DashCapFlat; break;
  234. case MM_CAP_TRIANGLE: lineCap = LineCapTriangle; dashCap = DashCapTriangle; break;
  235. }
  236. RenderPen->SetEndCap(lineCap);
  237. RenderPen->SetStartCap(lineCap);
  238. RenderPen->SetDashCap(dashCap);
  239. switch (MmJoin)
  240. {
  241. case MM_JOIN_ROUND: lineJoin = LineJoinRound; break;
  242. case MM_JOIN_BEVEL: lineJoin = LineJoinBevel; break;
  243. case MM_JOIN_MITER: lineJoin = LineJoinMiter; break;
  244. }
  245. RenderPen->SetLineJoin(lineJoin);
  246. switch (MmDashStyle)
  247. {
  248. case MM_STYLE_SOLID: dashStyle = DashStyleSolid; break;
  249. case MM_STYLE_DASH: dashStyle = DashStyleDash; break;
  250. case MM_STYLE_DOT: dashStyle = DashStyleDot; break;
  251. case MM_STYLE_DASHDOT: dashStyle = DashStyleDashDot; break;
  252. case MM_STYLE_DASHDOTDOT: dashStyle = DashStyleDashDotDot; break;
  253. }
  254. RenderPen->SetDashStyle(dashStyle);
  255. switch (MmAlignment)
  256. {
  257. case MM_ALIGNMENT_CENTER: alignment = PenAlignmentCenter; break;
  258. case MM_ALIGNMENT_INSET: alignment = PenAlignmentInset; break;
  259. }
  260. RenderPen->SetAlignment(alignment);
  261. RenderPen->SetMiterLimit(RenderMiterLimit);
  262. // We should add a 'compound array' UI to make this more flexible.
  263. // But for now, we only ever create one type of compound line:
  264. if (DoCompound)
  265. {
  266. REAL compoundArray[] = { 0.0f, 0.2f, 0.8f, 1.0f };
  267. RenderPen->SetCompoundArray(compoundArray, 4);
  268. }
  269. }
  270. /***************************************************************************\
  271. * Creates the GDI pen to be used.
  272. *
  273. \***************************************************************************/
  274. VOID
  275. CreatePen_Gdi()
  276. {
  277. DWORD lineCap;
  278. DWORD lineJoin;
  279. DWORD dashStyle;
  280. LOGBRUSH logBrush;
  281. DeleteObject(RenderHpen);
  282. switch (MmEndCap)
  283. {
  284. case MM_CAP_ROUND: lineCap = PS_ENDCAP_ROUND; break;
  285. case MM_CAP_SQUARE: lineCap = PS_ENDCAP_SQUARE; break;
  286. case MM_CAP_FLAT: lineCap = PS_ENDCAP_FLAT; break;
  287. case MM_CAP_TRIANGLE: lineCap = PS_ENDCAP_SQUARE; break; // No equivalent
  288. }
  289. switch (MmJoin)
  290. {
  291. case MM_JOIN_ROUND: lineJoin = PS_JOIN_ROUND; break;
  292. case MM_JOIN_BEVEL: lineJoin = PS_JOIN_BEVEL; break;
  293. case MM_JOIN_MITER: lineJoin = PS_JOIN_MITER; break;
  294. }
  295. switch (MmDashStyle)
  296. {
  297. case MM_STYLE_SOLID: dashStyle = PS_SOLID; break;
  298. case MM_STYLE_DASH: dashStyle = PS_DASH; break;
  299. case MM_STYLE_DOT: dashStyle = PS_DOT; break;
  300. case MM_STYLE_DASHDOT: dashStyle = PS_DASHDOT; break;
  301. case MM_STYLE_DASHDOTDOT: dashStyle = PS_DASHDOTDOT; break;
  302. }
  303. logBrush.lbStyle = BS_SOLID;
  304. logBrush.lbColor = RGB(255, 0, 0);
  305. logBrush.lbHatch = 0;
  306. RenderHpen = ExtCreatePen(lineCap | lineJoin | dashStyle | PS_GEOMETRIC,
  307. GDI_FIXEDPOINT_SCALE * RenderWidth,
  308. &logBrush,
  309. 0,
  310. NULL);
  311. }
  312. /***************************************************************************\
  313. * Creates the GDI+ and GDI pens to be used.
  314. *
  315. \***************************************************************************/
  316. VOID
  317. CreatePens()
  318. {
  319. CreatePen_Gdiplus();
  320. CreatePen_Gdi();
  321. }
  322. /***************************************************************************\
  323. * Creates the GDI+ clip region to be used.
  324. *
  325. \***************************************************************************/
  326. VOID
  327. CreateRegion_Gdiplus()
  328. {
  329. INT x;
  330. INT y;
  331. delete RenderRegion;
  332. RenderRegion = new Region();
  333. for (x = 0; x < WindowWidth; x += 128)
  334. {
  335. for (y = 0; y < WindowHeight; y += 128)
  336. {
  337. RenderRegion->Exclude(Rect(x + 64, y, 64, 64));
  338. RenderRegion->Exclude(Rect(x, y + 64, 64, 64));
  339. }
  340. }
  341. }
  342. /***************************************************************************\
  343. * Creates the GDI clip region to be used.
  344. *
  345. \***************************************************************************/
  346. VOID
  347. CreateRegion_Gdi()
  348. {
  349. INT x;
  350. INT y;
  351. HRGN hrgn;
  352. DeleteObject(RenderHrgn);
  353. RenderHrgn = CreateRectRgn(0, 0, WindowWidth, WindowHeight);
  354. hrgn = CreateRectRgn(0, 0, 0, 0);
  355. for (x = 0; x < WindowWidth; x += 128)
  356. {
  357. for (y = 0; y < WindowHeight; y += 128)
  358. {
  359. SetRectRgn(hrgn, x + 64, y, x + 128, y + 64);
  360. CombineRgn(RenderHrgn, RenderHrgn, hrgn, RGN_DIFF);
  361. SetRectRgn(hrgn, x, y + 64, x + 64, y + 128);
  362. CombineRgn(RenderHrgn, RenderHrgn, hrgn, RGN_DIFF);
  363. }
  364. }
  365. DeleteObject(hrgn);
  366. }
  367. /***************************************************************************\
  368. * Free all our global objects.
  369. *
  370. \***************************************************************************/
  371. VOID
  372. DeleteObjects_Gdiplus()
  373. {
  374. delete RenderRegion;
  375. delete RenderBrush;
  376. delete RenderPen;
  377. delete PrimitiveTransform;
  378. delete PrimitiveInverseTransform;
  379. }
  380. /***************************************************************************\
  381. * Free all our global objects.
  382. *
  383. \***************************************************************************/
  384. VOID
  385. DeleteObjects_Gdi()
  386. {
  387. DeleteObject(RenderHrgn);
  388. DeleteObject(RenderHbrush);
  389. DeleteObject(RenderHpen);
  390. }
  391. /***************************************************************************\
  392. * Draw the control points
  393. *
  394. \***************************************************************************/
  395. VOID
  396. DrawAnchors(
  397. Graphics *g,
  398. PointF* points,
  399. INT count
  400. )
  401. {
  402. SolidBrush blueBrush(Color(150, 128, 128, 128));
  403. for (; count != 0; count--, points++)
  404. {
  405. PointF point(*points);
  406. PrimitiveTransform->TransformPoints(&point, 1);
  407. g->FillRectangle(&blueBrush, RectF(point.X - 2, point.Y - 2, 5, 5));
  408. }
  409. }
  410. /***************************************************************************\
  411. * DrawTransformOverlay
  412. *
  413. \***************************************************************************/
  414. VOID
  415. DrawTransformOverlay(
  416. Graphics *g
  417. )
  418. {
  419. Pen pen(Color::Purple, 1);
  420. SolidBrush brush(Color::Purple);
  421. g->DrawLine(&pen, OverlayPoints[1].X, OverlayPoints[1].Y,
  422. OverlayPoints[0].X, OverlayPoints[0].Y);
  423. g->DrawLine(&pen, OverlayPoints[1].X, OverlayPoints[1].Y,
  424. OverlayPoints[2].X, OverlayPoints[2].Y);
  425. g->FillRectangle(&brush, RectF(OverlayPoints[0].X - 2,
  426. OverlayPoints[0].Y - 2,
  427. 5,
  428. 5));
  429. g->FillRectangle(&brush, RectF(OverlayPoints[2].X - 2,
  430. OverlayPoints[2].Y - 2,
  431. 5,
  432. 5));
  433. }
  434. /***************************************************************************\
  435. * Render_Gdiplus
  436. *
  437. \***************************************************************************/
  438. INT
  439. Render_Gdiplus(
  440. Graphics *g,
  441. PointF *points,
  442. INT count
  443. )
  444. {
  445. INT i;
  446. INT pointsUsed;
  447. // if (DoBrushRect)
  448. // {
  449. // LinearBrush->SetLinearPoints(points[0], points[1]);
  450. // }
  451. RectF rect(points[0].X, points[0].Y,
  452. points[1].X - points[0].X, points[1].Y - points[0].Y);
  453. Pen spinePen(Color(0, 128, 0), 0);
  454. GraphicsPath shapePath;
  455. switch (MmPrimitive)
  456. {
  457. case MM_POLYGON:
  458. {
  459. shapePath.AddPolygon(points, count);
  460. if (!DoShape)
  461. {
  462. if (DoFill)
  463. g->FillPolygon(RenderBrush, points, count, (DoWindingFill)
  464. ? FillModeWinding
  465. : FillModeAlternate);
  466. if (DoDraw)
  467. g->DrawPolygon(RenderPen, points, count);
  468. if (DoSpine)
  469. g->DrawPolygon(&spinePen, points, count);
  470. }
  471. pointsUsed = count;
  472. break;
  473. }
  474. case MM_LINES:
  475. {
  476. shapePath.AddLines(points, count);
  477. if (!DoShape)
  478. {
  479. if (DoDraw)
  480. g->DrawLines(RenderPen, points, count);
  481. if (DoSpine)
  482. g->DrawLines(&spinePen, points, count);
  483. }
  484. pointsUsed = count;
  485. break;
  486. }
  487. case MM_BEZIER:
  488. {
  489. GraphicsPath path;
  490. path.AddBeziers(points, count);
  491. shapePath.AddPath(&path, FALSE);
  492. if (!DoShape)
  493. {
  494. if (DoFill)
  495. g->FillPath(RenderBrush, &path);
  496. if (DoDraw)
  497. g->DrawPath(RenderPen, &path);
  498. if (DoSpine)
  499. g->DrawPath(&spinePen, &path);
  500. }
  501. pointsUsed = count;
  502. break;
  503. }
  504. case MM_RECTANGLE:
  505. {
  506. shapePath.AddRectangle(rect);
  507. if (!DoShape)
  508. {
  509. if (DoFill)
  510. g->FillRectangle(RenderBrush, rect);
  511. if (DoDraw)
  512. g->DrawRectangle(RenderPen, rect);
  513. if (DoSpine)
  514. g->DrawRectangle(&spinePen, rect);
  515. }
  516. pointsUsed = 2;
  517. break;
  518. }
  519. case MM_ELLIPSE:
  520. {
  521. shapePath.AddEllipse(rect);
  522. if (!DoShape)
  523. {
  524. if (DoFill)
  525. g->FillEllipse(RenderBrush, rect);
  526. if (DoDraw)
  527. g->DrawEllipse(RenderPen, rect);
  528. if (DoSpine)
  529. g->DrawEllipse(&spinePen, rect);
  530. }
  531. pointsUsed = 2;
  532. break;
  533. }
  534. case MM_TEXTPATH:
  535. {
  536. WCHAR string[] = L"GDI+ Rules!";
  537. GraphicsPath path((DoWindingFill) ? FillModeWinding
  538. : FillModeAlternate);
  539. FontFamily family(L"Times New Roman");
  540. PointF origin(points[0].X, points[0].Y);
  541. path.AddString(
  542. string,
  543. wcslen(string),
  544. &family,
  545. 0,
  546. 200,
  547. origin,
  548. NULL
  549. );
  550. shapePath.AddPath(&path, FALSE);
  551. if (!DoShape)
  552. {
  553. if (DoFill)
  554. g->FillPath(RenderBrush, &path);
  555. if (DoDraw)
  556. g->DrawPath(RenderPen, &path);
  557. if (DoSpine)
  558. g->DrawPath(&spinePen, &path);
  559. }
  560. pointsUsed = 1;
  561. break;
  562. }
  563. }
  564. if (DoShape)
  565. {
  566. // Recreate the path to be use for the path-gradient brush,
  567. // using the new shape data:
  568. delete PathGradientPath;
  569. PathGradientPath = shapePath.Clone();
  570. // Recreate the brush and do a complete fill of the window using
  571. // the specified brush:
  572. CreateBrushes();
  573. if (DoFill)
  574. g->FillRectangle(RenderBrush, -262144, -262144, 524288, 524288);
  575. if (DoDraw)
  576. g->DrawPath(RenderPen, &shapePath);
  577. if (DoSpine)
  578. g->DrawPath(&spinePen, &shapePath);
  579. }
  580. if (DoWiden)
  581. {
  582. Pen widenPen(Color::Black, 0);
  583. shapePath.Widen(RenderPen, NULL);
  584. g->DrawPath(&widenPen, &shapePath);
  585. }
  586. return(pointsUsed);
  587. }
  588. /***************************************************************************\
  589. * Render_Gdi
  590. *
  591. \***************************************************************************/
  592. INT
  593. Render_Gdi(
  594. HDC hdc,
  595. PointF *primitivePoints,
  596. INT count
  597. )
  598. {
  599. BOOL drawSpine;
  600. HGDIOBJ oldPen;
  601. HGDIOBJ oldBrush;
  602. HPEN hpenSpine;
  603. INT pointsUsed;
  604. POINT points[PrimitivePointsMax];
  605. INT i;
  606. // Convert to integer, the preferred GDI format. Remember that we've
  607. // set the transform to scale down by 16, so we have to multiply by
  608. // 16 here. We've done this so that we can specify 28.4 directly to
  609. // GDI:
  610. for (i = 0; i < count; i++)
  611. {
  612. points[i].x = ROUND(GDI_FIXEDPOINT_SCALE * primitivePoints[i].X);
  613. points[i].y = ROUND(GDI_FIXEDPOINT_SCALE * primitivePoints[i].Y);
  614. }
  615. hpenSpine = CreatePen(PS_SOLID, 0, RGB(0, 128, 0));
  616. for (drawSpine = FALSE; drawSpine != TRUE; drawSpine = TRUE)
  617. {
  618. if (drawSpine)
  619. {
  620. oldPen = SelectObject(hdc, hpenSpine);
  621. oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
  622. }
  623. else
  624. {
  625. oldPen = SelectObject(hdc,
  626. (DoDraw) ? RenderHpen : GetStockObject(NULL_PEN));
  627. oldBrush = SelectObject(hdc,
  628. (DoFill) ? RenderHbrush : GetStockObject(NULL_BRUSH));
  629. }
  630. switch (MmPrimitive)
  631. {
  632. case MM_POLYGON:
  633. {
  634. Polygon(hdc, points, count);
  635. pointsUsed = count;
  636. break;
  637. }
  638. case MM_LINES:
  639. {
  640. Polyline(hdc, points, count);
  641. pointsUsed = count;
  642. break;
  643. }
  644. case MM_BEZIER:
  645. {
  646. // Don't use StrokeAndFillPath because GDI would close the
  647. // stroke:
  648. BeginPath(hdc);
  649. PolyBezier(hdc, points, count);
  650. EndPath(hdc);
  651. FillPath(hdc);
  652. BeginPath(hdc);
  653. PolyBezier(hdc, points, count);
  654. EndPath(hdc);
  655. StrokePath(hdc);
  656. pointsUsed = count;
  657. break;
  658. }
  659. case MM_RECTANGLE:
  660. {
  661. Rectangle(hdc, points[0].x, points[0].y, points[1].x, points[1].y);
  662. pointsUsed = 2;
  663. break;
  664. }
  665. case MM_ELLIPSE:
  666. {
  667. Ellipse(hdc, points[0].x, points[0].y, points[1].x, points[1].y);
  668. pointsUsed = 2;
  669. break;
  670. }
  671. case MM_TEXTPATH:
  672. {
  673. LOGFONT logFont;
  674. memset(&logFont, 0, sizeof(logFont));
  675. // Don't forget to multiply the height by 16, because
  676. // we're using a scaling transform with GDI so that we
  677. // can spit out 28.4 coordinates:
  678. logFont.lfHeight = - GDI_FIXEDPOINT_SCALE * 200;
  679. strcpy(logFont.lfFaceName, "Times New Roman");
  680. SetBkMode(hdc, TRANSPARENT);
  681. HFONT font = CreateFontIndirect(&logFont);
  682. HGDIOBJ oldFont = SelectObject(hdc, font);
  683. WCHAR string[] = L"GDI+ Rules!";
  684. BeginPath(hdc);
  685. ExtTextOutW(hdc, points[0].x, points[0].y, 0, NULL, string,
  686. wcslen(string), NULL);
  687. EndPath(hdc);
  688. StrokeAndFillPath(hdc);
  689. SelectObject(hdc, oldFont);
  690. DeleteObject(font);
  691. pointsUsed = 1;
  692. }
  693. }
  694. SelectObject(hdc, oldBrush);
  695. SelectObject(hdc, oldPen);
  696. }
  697. DeleteObject(hpenSpine);
  698. return(pointsUsed);
  699. }
  700. /***************************************************************************\
  701. * PrepareContext_Gdiplus
  702. *
  703. \***************************************************************************/
  704. VOID
  705. PrepareContext_Gdiplus(
  706. Graphics *g
  707. )
  708. {
  709. g->SetSmoothingMode((DoAntialias) ? SmoothingModeAntiAlias
  710. : SmoothingModeNone);
  711. g->SetCompositingQuality((DoGammaCorrect) ?
  712. CompositingQualityGammaCorrected : CompositingQualityAssumeLinear);
  713. if (DoClipGrid)
  714. {
  715. g->SetClip(RenderRegion);
  716. }
  717. g->SetTransform(PrimitiveTransform);
  718. }
  719. /***************************************************************************\
  720. * PrepareContext_Gdi
  721. *
  722. \***************************************************************************/
  723. VOID
  724. PrepareContext_Gdi(
  725. HDC hdc
  726. )
  727. {
  728. REAL m[6];
  729. XFORM xform;
  730. SetMiterLimit(hdc, RenderMiterLimit, NULL);
  731. SetPolyFillMode(hdc, (DoWindingFill) ? WINDING : ALTERNATE);
  732. if (DoClipGrid)
  733. {
  734. SelectClipRgn(hdc, RenderHrgn);
  735. }
  736. // Setup the transform:
  737. PrimitiveTransform->GetElements(m);
  738. // Scale the transform down by 16 so that we can give GDI 28.4
  739. // coordinates directly as integers:
  740. xform.eM11 = m[0] / GDI_FIXEDPOINT_SCALE;
  741. xform.eM12 = m[1] / GDI_FIXEDPOINT_SCALE;
  742. xform.eM21 = m[2] / GDI_FIXEDPOINT_SCALE;
  743. xform.eM22 = m[3] / GDI_FIXEDPOINT_SCALE;
  744. xform.eDx = m[4];
  745. xform.eDy = m[5];
  746. SetGraphicsMode(hdc, GM_ADVANCED);
  747. SetWorldTransform(hdc, &xform);
  748. }
  749. /***************************************************************************\
  750. * GenerateRandomPoints
  751. *
  752. \***************************************************************************/
  753. INT
  754. GenerateRandomPoints(
  755. PointF *randomPoints,
  756. INT maxPoints
  757. )
  758. {
  759. INT randomPointsCount;
  760. INT i;
  761. // Make 1 in 32 have lotsa randomPoints:
  762. if ((rand() & 31) == 0)
  763. {
  764. randomPointsCount = rand() & 511;
  765. }
  766. else
  767. {
  768. randomPointsCount = (rand() & 7) + 1;
  769. }
  770. randomPointsCount = min(randomPointsCount, maxPoints);
  771. // !!! Need to randomize
  772. switch (rand() & 3)
  773. {
  774. case 0: // Trivially clipped
  775. for (i = 0; i < randomPointsCount; i++)
  776. {
  777. randomPoints[i].X = (rand() % (16 * WindowWidth * 16)) / 16.0f;
  778. randomPoints[i].Y = (rand() % (16 * WindowHeight)) / 16.0f;
  779. }
  780. break;
  781. case 1: // Really small
  782. for (i = 0; i < randomPointsCount; i++)
  783. {
  784. randomPoints[i].X = (rand() & 127) / 16.0f + 32;
  785. randomPoints[i].Y = (rand() & 127) / 16.0f + 32;
  786. }
  787. break;
  788. default: // Big space, with at least one point inside window:
  789. randomPoints[0].X = (rand() % (16 * WindowWidth)) / 16.0f;
  790. randomPoints[0].Y = (rand() % (16 * WindowHeight)) / 16.0f;
  791. if (0)
  792. {
  793. for (i = 1; i < randomPointsCount; i++)
  794. {
  795. // Once in a while, make the points REALLY REALLY big:
  796. randomPoints[i].X = (REAL) (rand() * rand() * rand());
  797. randomPoints[i].Y = (REAL) (rand() * rand() * rand());
  798. }
  799. }
  800. else
  801. {
  802. for (i = 1; i < randomPointsCount; i++)
  803. {
  804. randomPoints[i].X = (rand() % 1000000 - 500000) / 16.0f;
  805. randomPoints[i].Y = (rand() % 1000000 - 500000) / 16.0f;
  806. }
  807. }
  808. break;
  809. }
  810. return(randomPointsCount);
  811. }
  812. /***************************************************************************\
  813. * Draw
  814. *
  815. \***************************************************************************/
  816. VOID
  817. Draw(
  818. HDC hdc,
  819. BOOL doTime = FALSE
  820. )
  821. {
  822. CHAR stringBuffer[200];
  823. LONGLONG startCounter;
  824. LONGLONG endCounter;
  825. LONGLONG counterFrequency;
  826. INT pointsUsed;
  827. INT repetitions = (doTime) ? 10 : 1;
  828. INT i;
  829. // Clear the window:
  830. HGDIOBJ hbrush = GetStockObject(WHITE_BRUSH);
  831. HGDIOBJ holdBrush = SelectObject(hdc, hbrush);
  832. PatBlt(hdc, -10000, -10000, 20000, 20000, PATCOPY);
  833. SelectObject(hdc, holdBrush);
  834. DeleteObject(hbrush);
  835. QueryPerformanceCounter((LARGE_INTEGER*) &startCounter);
  836. // Draw the stuff:
  837. if (DoGdi)
  838. {
  839. SaveDC(hdc);
  840. PrepareContext_Gdi(hdc);
  841. for (i = 0; i < repetitions; i++)
  842. {
  843. pointsUsed = Render_Gdi(hdc, PrimitivePoints, PrimitivePointsCount);
  844. }
  845. RestoreDC(hdc, -1);
  846. }
  847. else
  848. {
  849. Graphics g(hdc);
  850. PrepareContext_Gdiplus(&g);
  851. if (!DoRandomTest)
  852. {
  853. for (i = 0; i < repetitions; i++)
  854. {
  855. pointsUsed = Render_Gdiplus(&g, PrimitivePoints, PrimitivePointsCount);
  856. }
  857. }
  858. else
  859. {
  860. PointF points[512];
  861. INT count;
  862. // To get faster 'test' rendering (by avoiding clears between
  863. // successive tests), always draw in a batch of '20':
  864. for (i = 0; i < 20; i++)
  865. {
  866. count = GenerateRandomPoints(points, 512);
  867. pointsUsed = Render_Gdiplus(&g, points, count);
  868. }
  869. }
  870. }
  871. // Display the time:
  872. QueryPerformanceCounter((LARGE_INTEGER*) &endCounter);
  873. QueryPerformanceFrequency((LARGE_INTEGER*) &counterFrequency);
  874. float seconds = (float)(endCounter - startCounter) / counterFrequency;
  875. INT milliseconds = (INT) (seconds * 1000 + 0.5f);
  876. if (doTime)
  877. {
  878. sprintf(stringBuffer, "%li repetitions: %li ms", repetitions, milliseconds);
  879. }
  880. else
  881. {
  882. sprintf(stringBuffer, "Rasterization time: %li ms", milliseconds);
  883. }
  884. SetBkMode(hdc, TRANSPARENT);
  885. ExtTextOut(hdc, 0, 0, 0, NULL, stringBuffer, strlen(stringBuffer), NULL);
  886. if (!DoRandomTest)
  887. {
  888. // Now that we're out of the timing loop, draw our control points:
  889. Graphics g(hdc);
  890. if (DoAnchors)
  891. {
  892. DrawAnchors(&g, PrimitivePoints, pointsUsed);
  893. }
  894. if (DoTransformOverlay)
  895. {
  896. DrawTransformOverlay(&g);
  897. }
  898. }
  899. }
  900. /***************************************************************************\
  901. * EnterWidth
  902. *
  903. * Dialog for entering pen width.
  904. \***************************************************************************/
  905. INT_PTR EnterWidth(
  906. HWND hDlg,
  907. UINT message,
  908. WPARAM wParam,
  909. LPARAM lParam)
  910. {
  911. BOOL bTrans;
  912. switch (message)
  913. {
  914. case WM_INITDIALOG:
  915. SetDlgItemInt(hDlg, IDD_WIDTH, RenderWidth, TRUE);
  916. return(TRUE);
  917. case WM_COMMAND:
  918. if (wParam == IDD_OK)
  919. {
  920. RenderWidth = GetDlgItemInt(hDlg, IDD_WIDTH, &bTrans, TRUE);
  921. EndDialog(hDlg, wParam);
  922. InvalidateRect(ghwndMain, NULL, TRUE);
  923. }
  924. break;
  925. case WM_SETFOCUS:
  926. SetFocus(GetDlgItem(hDlg, IDD_WIDTH));
  927. return(FALSE);
  928. default:
  929. return(FALSE);
  930. }
  931. return(TRUE);
  932. }
  933. /***************************************************************************\
  934. * EnterAlpha
  935. *
  936. * Dialog for entering pen alpha.
  937. \***************************************************************************/
  938. INT_PTR EnterAlpha(
  939. HWND hDlg,
  940. UINT message,
  941. WPARAM wParam,
  942. LPARAM lParam)
  943. {
  944. BOOL bTrans;
  945. switch (message)
  946. {
  947. case WM_INITDIALOG:
  948. SetDlgItemInt(hDlg, IDD_ALPHA, RenderAlpha, TRUE);
  949. return(TRUE);
  950. case WM_COMMAND:
  951. if (wParam == IDD_OK)
  952. {
  953. RenderAlpha = GetDlgItemInt(hDlg, IDD_ALPHA, &bTrans, TRUE);
  954. EndDialog(hDlg, wParam);
  955. InvalidateRect(ghwndMain, NULL, TRUE);
  956. }
  957. break;
  958. case WM_SETFOCUS:
  959. SetFocus(GetDlgItem(hDlg, IDD_ALPHA));
  960. return(FALSE);
  961. default:
  962. return(FALSE);
  963. }
  964. return(TRUE);
  965. }
  966. /***************************************************************************\
  967. * EnterPoints
  968. *
  969. * Dialog for entering points.
  970. \***************************************************************************/
  971. INT_PTR EnterPoints(
  972. HWND hDlg,
  973. UINT message,
  974. WPARAM wParam,
  975. LPARAM lParam
  976. )
  977. {
  978. BOOL bTrans;
  979. INT i;
  980. switch (message)
  981. {
  982. case WM_INITDIALOG:
  983. SetDlgItemInt(hDlg, IDD_POINT1X, ROUND(PrimitivePoints[0].X), TRUE);
  984. SetDlgItemInt(hDlg, IDD_POINT1Y, ROUND(PrimitivePoints[0].Y), TRUE);
  985. SetDlgItemInt(hDlg, IDD_POINT2X, ROUND(PrimitivePoints[1].X), TRUE);
  986. SetDlgItemInt(hDlg, IDD_POINT2Y, ROUND(PrimitivePoints[1].Y), TRUE);
  987. SetDlgItemInt(hDlg, IDD_POINT3X, ROUND(PrimitivePoints[2].X), TRUE);
  988. SetDlgItemInt(hDlg, IDD_POINT3Y, ROUND(PrimitivePoints[2].Y), TRUE);
  989. SetDlgItemInt(hDlg, IDD_POINT4X, ROUND(PrimitivePoints[3].X), TRUE);
  990. SetDlgItemInt(hDlg, IDD_POINT4Y, ROUND(PrimitivePoints[3].Y), TRUE);
  991. return(TRUE);
  992. case WM_COMMAND:
  993. if (wParam == IDD_OK)
  994. {
  995. PrimitivePoints[0].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT1X, &bTrans, TRUE);
  996. PrimitivePoints[0].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT1Y, &bTrans, TRUE);
  997. PrimitivePoints[1].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT2X, &bTrans, TRUE);
  998. PrimitivePoints[1].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT2Y, &bTrans, TRUE);
  999. PrimitivePoints[2].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT3X, &bTrans, TRUE);
  1000. PrimitivePoints[2].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT3Y, &bTrans, TRUE);
  1001. PrimitivePoints[3].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT4X, &bTrans, TRUE);
  1002. PrimitivePoints[3].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT4Y, &bTrans, TRUE);
  1003. EndDialog(hDlg, wParam);
  1004. InvalidateRect(ghwndMain, NULL, TRUE);
  1005. }
  1006. break;
  1007. case WM_SETFOCUS:
  1008. SetFocus(GetDlgItem(hDlg, IDD_POINT1X));
  1009. return(FALSE);
  1010. default:
  1011. return(FALSE);
  1012. }
  1013. return(TRUE);
  1014. }
  1015. /***************************************************************************\
  1016. * EnterTransform
  1017. *
  1018. * Dialog for entering arbitrary transforms.
  1019. \***************************************************************************/
  1020. INT_PTR EnterTransform(
  1021. HWND hDlg,
  1022. WORD message,
  1023. WPARAM wParam,
  1024. LONG lParam)
  1025. {
  1026. BOOL bTrans;
  1027. REAL m[6];
  1028. PrimitiveTransform->GetElements(m);
  1029. switch (message)
  1030. {
  1031. case WM_INITDIALOG:
  1032. SetDlgItemInt(hDlg, IDD_M11, ROUND(m[0] * 1000.0f), TRUE);
  1033. SetDlgItemInt(hDlg, IDD_M12, ROUND(m[1] * 1000.0f), TRUE);
  1034. SetDlgItemInt(hDlg, IDD_M21, ROUND(m[2] * 1000.0f), TRUE);
  1035. SetDlgItemInt(hDlg, IDD_M22, ROUND(m[3] * 1000.0f), TRUE);
  1036. SetDlgItemInt(hDlg, IDD_M31, ROUND(m[4] * 1000.0f), TRUE);
  1037. SetDlgItemInt(hDlg, IDD_M32, ROUND(m[5] * 1000.0f), TRUE);
  1038. return(TRUE);
  1039. case WM_COMMAND:
  1040. if (wParam == IDD_OK)
  1041. {
  1042. m[0] = ((INT) GetDlgItemInt(hDlg, IDD_M11, &bTrans, TRUE)) / 1000.0f;
  1043. m[1] = ((INT) GetDlgItemInt(hDlg, IDD_M12, &bTrans, TRUE)) / 1000.0f;
  1044. m[2] = ((INT) GetDlgItemInt(hDlg, IDD_M21, &bTrans, TRUE)) / 1000.0f;
  1045. m[3] = ((INT) GetDlgItemInt(hDlg, IDD_M22, &bTrans, TRUE)) / 1000.0f;
  1046. m[4] = ((INT) GetDlgItemInt(hDlg, IDD_M31, &bTrans, TRUE)) / 1000.0f;
  1047. m[5] = ((INT) GetDlgItemInt(hDlg, IDD_M32, &bTrans, TRUE)) / 1000.0f;
  1048. PrimitiveTransform->SetElements(m[0], m[1], m[2], m[3], m[4], m[5]);
  1049. PrimitiveInverseTransform->SetElements(m[0], m[1], m[2], m[3], m[4], m[5]);
  1050. PrimitiveInverseTransform->Invert();
  1051. // Calculate the new world-space elbow location:
  1052. OverlayOffset.X = OverlayPoints[1].X;
  1053. OverlayOffset.Y = OverlayPoints[1].Y;
  1054. PrimitiveInverseTransform->TransformPoints(&OverlayOffset);
  1055. // Now calculate the new device-space end-points, by initializing
  1056. // in world-space and then converting back to device-space:
  1057. OverlayPoints[0].X = OverlayOffset.X + OverlayDimension;
  1058. OverlayPoints[0].Y = OverlayOffset.Y;
  1059. OverlayPoints[2].X = OverlayOffset.X;
  1060. OverlayPoints[2].Y = OverlayOffset.Y - OverlayDimension;
  1061. PrimitiveTransform->TransformPoints(&OverlayPoints[0]);
  1062. PrimitiveTransform->TransformPoints(&OverlayPoints[2]);
  1063. // We're done; force a redraw:
  1064. EndDialog(hDlg, wParam);
  1065. InvalidateRect(ghwndMain, NULL, TRUE);
  1066. }
  1067. break;
  1068. case WM_SETFOCUS:
  1069. SetFocus(GetDlgItem(hDlg, IDD_OK));
  1070. return(FALSE);
  1071. default:
  1072. return(FALSE);
  1073. }
  1074. return(TRUE);
  1075. }
  1076. /***************************************************************************\
  1077. * ComputeOverlayTransformFromPoints
  1078. *
  1079. \***************************************************************************/
  1080. VOID
  1081. ComputeOverlayTransformFromPoints()
  1082. {
  1083. REAL dx1 = OverlayPoints[0].X - OverlayPoints[1].X;
  1084. REAL dy1 = OverlayPoints[0].Y - OverlayPoints[1].Y;
  1085. REAL dx2 = OverlayPoints[1].X - OverlayPoints[2].X;
  1086. REAL dy2 = OverlayPoints[1].Y - OverlayPoints[2].Y;
  1087. REAL xMid = (REAL) (WindowWidth >> 1);
  1088. REAL yMid = (REAL) (WindowHeight >> 1);
  1089. RectF srcRect(OverlayOffset.X, OverlayOffset.Y, OverlayDimension, OverlayDimension);
  1090. // The order is upper-left, upper-right, lower-left corner:
  1091. PointF dstPoints[] = { PointF(xMid, yMid),
  1092. PointF(xMid + dx1, yMid + dy1),
  1093. PointF(xMid + dx2, yMid + dy2) };
  1094. delete PrimitiveTransform;
  1095. PrimitiveTransform = new Matrix(srcRect, dstPoints);
  1096. delete PrimitiveInverseTransform;
  1097. PrimitiveInverseTransform = PrimitiveTransform->Clone();
  1098. PrimitiveInverseTransform->Invert();
  1099. }
  1100. /***************************************************************************\
  1101. * CreateOverlayTransform
  1102. *
  1103. \***************************************************************************/
  1104. VOID
  1105. CreateOverlayTransform()
  1106. {
  1107. REAL xMid = (REAL) (WindowWidth >> 1);
  1108. REAL yMid = (REAL) (WindowHeight >> 1);
  1109. OverlayPoints[0].X = xMid + OverlayDimension;
  1110. OverlayPoints[0].Y = yMid;
  1111. OverlayPoints[1].X = xMid;
  1112. OverlayPoints[1].Y = yMid;
  1113. OverlayPoints[2].X = xMid;
  1114. OverlayPoints[2].Y = yMid - OverlayDimension;
  1115. OverlayOffset.X = xMid;
  1116. OverlayOffset.Y = yMid;
  1117. ComputeOverlayTransformFromPoints();
  1118. }
  1119. /***************************************************************************\
  1120. * UpdateOverlay
  1121. *
  1122. \***************************************************************************/
  1123. VOID
  1124. UpdateOverlay(
  1125. REAL x,
  1126. REAL y
  1127. )
  1128. {
  1129. if (OverlayDragVertex == 1)
  1130. {
  1131. // The root of the overlay is being moved, so we move the overlay
  1132. // as a whole:
  1133. REAL dx = x - OverlayPoints[1].X;
  1134. REAL dy = y - OverlayPoints[1].Y;
  1135. OverlayPoints[0].X += dx;
  1136. OverlayPoints[0].Y += dy;
  1137. OverlayPoints[1].X = x;
  1138. OverlayPoints[1].Y = y;
  1139. OverlayPoints[2].X += dx;
  1140. OverlayPoints[2].Y += dy;
  1141. }
  1142. else
  1143. {
  1144. OverlayPoints[OverlayDragVertex].X = x;
  1145. OverlayPoints[OverlayDragVertex].Y = y;
  1146. ComputeOverlayTransformFromPoints();
  1147. }
  1148. }
  1149. /***************************************************************************\
  1150. * RecenterOverlay
  1151. *
  1152. \***************************************************************************/
  1153. VOID
  1154. RecenterOverlay()
  1155. {
  1156. REAL xMid = (REAL) (WindowWidth >> 1);
  1157. REAL yMid = (REAL) (WindowHeight >> 1);
  1158. REAL dx = xMid - OverlayPoints[1].X;
  1159. REAL dy = yMid - OverlayPoints[1].Y;
  1160. // Center the transform around the new world-space focus point:
  1161. OverlayOffset.X = OverlayPoints[1].X;
  1162. OverlayOffset.Y = OverlayPoints[1].Y;
  1163. if (PrimitiveInverseTransform != NULL)
  1164. {
  1165. PrimitiveInverseTransform->TransformPoints(&OverlayOffset, 1);
  1166. }
  1167. // Bring the overlay control back to the middle of the screen:
  1168. OverlayPoints[0].X += dx;
  1169. OverlayPoints[0].Y += dy;
  1170. OverlayPoints[1].X = xMid;
  1171. OverlayPoints[1].Y = yMid;
  1172. OverlayPoints[2].X += dx;
  1173. OverlayPoints[2].Y += dy;
  1174. ComputeOverlayTransformFromPoints();
  1175. }
  1176. /***************************************************************************\
  1177. * FindNearest
  1178. *
  1179. \***************************************************************************/
  1180. INT
  1181. FindNearest(
  1182. REAL x, // Device space
  1183. REAL y,
  1184. const PointF *points, // World space
  1185. INT count,
  1186. const Matrix *matrix = NULL // World-to-device transform
  1187. )
  1188. {
  1189. INT i;
  1190. REAL d;
  1191. REAL minDistance;
  1192. INT vertex;
  1193. PointF inputPoint(x, y);
  1194. // Find the nearest vertex, using a simple Manhattan metric.
  1195. minDistance = 100000;
  1196. for (i = 0; i < count; i++)
  1197. {
  1198. PointF point(points[i]);
  1199. // For the distance metric, we want to be doing our calculations
  1200. // in device space:
  1201. if (matrix)
  1202. {
  1203. matrix->TransformPoints(&point, 1);
  1204. }
  1205. d = ABS(x - point.X) + ABS(y - point.Y);
  1206. if (d < minDistance)
  1207. {
  1208. minDistance = d;
  1209. vertex = i;
  1210. }
  1211. }
  1212. return((minDistance < HIT_DISTANCE) ? vertex : -1);
  1213. }
  1214. /***************************************************************************\
  1215. * MainWindowProc(hwnd, message, wParam, lParam)
  1216. *
  1217. * Processes all messages for the main window.
  1218. *
  1219. * History:
  1220. * 04-07-91 -by- KentD
  1221. * Wrote it.
  1222. \***************************************************************************/
  1223. LRESULT
  1224. MainWindowProc(
  1225. HWND hwnd,
  1226. UINT message,
  1227. WPARAM wParam,
  1228. LPARAM lParam
  1229. )
  1230. {
  1231. PointF point;
  1232. LONG i;
  1233. LONG d;
  1234. LONG minDistance;
  1235. LONG vertex;
  1236. HDC hdc;
  1237. PAINTSTRUCT ps;
  1238. HMENU hmenu = GetMenu(hwnd);
  1239. WORD mmCommand = LOWORD(wParam);
  1240. switch (message)
  1241. {
  1242. case WM_CREATE:
  1243. // NOTICE-DavePr@2002/05/28
  1244. // Missing FreeProcInstance for these anyway.
  1245. //glpfnEnterWidth = (FARPROC) MakeProcInstance(EnterWidth, ghwndMain);
  1246. //glpfnEnterAlpha = (FARPROC) MakeProcInstance(EnterAlpha, ghwndMain);
  1247. //glpfnEnterPoints = (FARPROC) MakeProcInstance(EnterPoints, ghwndMain);
  1248. //glpfnEnterTransform = (FARPROC) MakeProcInstance(EnterTransform, ghwndMain);
  1249. SetTimer(hwnd, 1, 80, NULL);
  1250. break;
  1251. case WM_COMMAND:
  1252. switch(mmCommand)
  1253. {
  1254. case MM_RANDOMTEST:
  1255. DoRandomTest = !DoRandomTest;
  1256. if (!DoRandomTest)
  1257. InvalidateRect(hwnd, NULL, TRUE);
  1258. break;
  1259. case MM_WIDTH:
  1260. //DialogBox(ghInstance, "Width", ghwndMain, glpfnEnterWidth);
  1261. DialogBox(ghInstance, "Width", ghwndMain, EnterWidth);
  1262. CreatePens();
  1263. InvalidateRect(hwnd, NULL, TRUE);
  1264. break;
  1265. case MM_ALPHA:
  1266. //DialogBox(ghInstance, "Alpha", ghwndMain, glpfnEnterAlpha);
  1267. DialogBox(ghInstance, "Alpha", ghwndMain, EnterAlpha);
  1268. CreatePens();
  1269. InvalidateRect(hwnd, NULL, TRUE);
  1270. break;
  1271. case MM_POINTS:
  1272. //DialogBox(ghInstance, "Points", ghwndMain, glpfnEnterPoints);
  1273. DialogBox(ghInstance, "Points", ghwndMain, EnterPoints);
  1274. InvalidateRect(hwnd, NULL, TRUE);
  1275. break;
  1276. case MM_EDITTRANSFORM:
  1277. //DialogBox(ghInstance, "Transform", ghwndMain, glpfnEnterTransform);
  1278. DialogBox(ghInstance, "Transform", ghwndMain, EnterTransform);
  1279. InvalidateRect(hwnd, NULL, TRUE);
  1280. break;
  1281. case MM_REDRAW:
  1282. hdc = GetDC(hwnd);
  1283. Draw(hdc);
  1284. ReleaseDC(hwnd, hdc);
  1285. break;
  1286. case MM_TIME:
  1287. hdc = GetDC(hwnd);
  1288. Draw(hdc, TRUE);
  1289. ReleaseDC(hwnd, hdc);
  1290. break;
  1291. case MM_CLIPGRID:
  1292. DoClipGrid = !DoClipGrid;
  1293. CheckMenuItem(hmenu, mmCommand, DoClipGrid ? MF_CHECKED : MF_UNCHECKED);
  1294. InvalidateRect(hwnd, NULL, TRUE);
  1295. break;
  1296. case MM_ANTIALIAS:
  1297. DoAntialias = !DoAntialias;
  1298. CheckMenuItem(hmenu, mmCommand, DoAntialias ? MF_CHECKED : MF_UNCHECKED);
  1299. InvalidateRect(hwnd, NULL, TRUE);
  1300. break;
  1301. case MM_GAMMACORRECT:
  1302. DoGammaCorrect = !DoGammaCorrect;
  1303. CheckMenuItem(hmenu, mmCommand, DoGammaCorrect ? MF_CHECKED : MF_UNCHECKED);
  1304. InvalidateRect(hwnd, NULL, TRUE);
  1305. break;
  1306. case MM_WINDING:
  1307. DoWindingFill = !DoWindingFill;
  1308. CheckMenuItem(hmenu, mmCommand, DoWindingFill ? MF_CHECKED : MF_UNCHECKED);
  1309. InvalidateRect(hwnd, NULL, TRUE);
  1310. break;
  1311. case MM_SPINE:
  1312. DoSpine = !DoSpine;
  1313. CheckMenuItem(hmenu, mmCommand, DoSpine ? MF_CHECKED : MF_UNCHECKED);
  1314. InvalidateRect(hwnd, NULL, TRUE);
  1315. break;
  1316. case MM_WIDENPATH:
  1317. DoWiden = !DoWiden;
  1318. CheckMenuItem(hmenu, mmCommand, DoWiden ? MF_CHECKED : MF_UNCHECKED);
  1319. InvalidateRect(hwnd, NULL, TRUE);
  1320. break;
  1321. case MM_ANCHORS:
  1322. DoAnchors = !DoAnchors;
  1323. CheckMenuItem(hmenu, mmCommand, DoAnchors ? MF_CHECKED : MF_UNCHECKED);
  1324. InvalidateRect(hwnd, NULL, TRUE);
  1325. break;
  1326. case MM_TRANSFORMOVERLAY:
  1327. DoTransformOverlay = !DoTransformOverlay;
  1328. CheckMenuItem(hmenu, mmCommand, DoTransformOverlay ? MF_CHECKED : MF_UNCHECKED);
  1329. InvalidateRect(hwnd, NULL, TRUE);
  1330. break;
  1331. case MM_SCALINGONLY:
  1332. DoScalingOnly = !DoScalingOnly;
  1333. CheckMenuItem(hmenu, mmCommand, DoScalingOnly ? MF_CHECKED : MF_UNCHECKED);
  1334. InvalidateRect(hwnd, NULL, TRUE);
  1335. break;
  1336. case MM_RESETTRANSFORM:
  1337. CreateOverlayTransform();
  1338. InvalidateRect(hwnd, NULL, TRUE);
  1339. break;
  1340. case MM_FILL:
  1341. DoFill = !DoFill;
  1342. CheckMenuItem(hmenu, mmCommand, DoFill ? MF_CHECKED : MF_UNCHECKED);
  1343. InvalidateRect(hwnd, NULL, TRUE);
  1344. break;
  1345. case MM_DRAW:
  1346. DoDraw = !DoDraw;
  1347. CheckMenuItem(hmenu, mmCommand, DoDraw ? MF_CHECKED : MF_UNCHECKED);
  1348. InvalidateRect(hwnd, NULL, TRUE);
  1349. break;
  1350. case MM_POLYGON:
  1351. case MM_LINES:
  1352. case MM_BEZIER:
  1353. case MM_RECTANGLE:
  1354. case MM_ELLIPSE:
  1355. case MM_TEXTPATH:
  1356. CheckMenuItem(hmenu, MmPrimitive, MF_UNCHECKED);
  1357. MmPrimitive = mmCommand;
  1358. CheckMenuItem(hmenu, MmPrimitive, MF_CHECKED);
  1359. InvalidateRect(hwnd, NULL, TRUE);
  1360. break;
  1361. case MM_COMPOUND:
  1362. DoCompound = !DoCompound;
  1363. CheckMenuItem(hmenu, mmCommand, DoCompound ? MF_CHECKED : MF_UNCHECKED);
  1364. CreatePens();
  1365. InvalidateRect(hwnd, NULL, TRUE);
  1366. break;
  1367. case MM_STYLE_SOLID:
  1368. case MM_STYLE_DASH:
  1369. case MM_STYLE_DOT:
  1370. case MM_STYLE_DASHDOT:
  1371. case MM_STYLE_DASHDOTDOT:
  1372. CheckMenuItem(hmenu, MmDashStyle, MF_UNCHECKED);
  1373. MmDashStyle = mmCommand;
  1374. CheckMenuItem(hmenu, MmDashStyle, MF_CHECKED);
  1375. CreatePens();
  1376. InvalidateRect(hwnd, NULL, TRUE);
  1377. break;
  1378. case MM_CAP_FLAT:
  1379. case MM_CAP_SQUARE:
  1380. case MM_CAP_ROUND:
  1381. case MM_CAP_TRIANGLE:
  1382. CheckMenuItem(hmenu, MmEndCap, MF_UNCHECKED);
  1383. MmEndCap = mmCommand;
  1384. CheckMenuItem(hmenu, MmEndCap, MF_CHECKED);
  1385. CreatePens();
  1386. InvalidateRect(hwnd, NULL, TRUE);
  1387. break;
  1388. case MM_JOIN_ROUND:
  1389. case MM_JOIN_MITER:
  1390. case MM_JOIN_BEVEL:
  1391. CheckMenuItem(hmenu, MmJoin, MF_UNCHECKED);
  1392. MmJoin = mmCommand;
  1393. CheckMenuItem(hmenu, MmJoin, MF_CHECKED);
  1394. CreatePens();
  1395. InvalidateRect(hwnd, NULL, TRUE);
  1396. break;
  1397. case MM_ALIGNMENT_CENTER:
  1398. case MM_ALIGNMENT_INSET:
  1399. CheckMenuItem(hmenu, MmAlignment, MF_UNCHECKED);
  1400. MmAlignment = mmCommand;
  1401. CheckMenuItem(hmenu, MmAlignment, MF_CHECKED);
  1402. CreatePens();
  1403. InvalidateRect(hwnd, NULL, TRUE);
  1404. break;
  1405. case MM_WRAP_TILE:
  1406. case MM_WRAP_CLAMP:
  1407. case MM_WRAP_FLIPX:
  1408. case MM_WRAP_FLIPY:
  1409. case MM_WRAP_FLIPXY:
  1410. CheckMenuItem(hmenu, MmWrapMode, MF_UNCHECKED);
  1411. MmWrapMode = mmCommand;
  1412. CheckMenuItem(hmenu, MmWrapMode, MF_CHECKED);
  1413. CreateBrushes();
  1414. InvalidateRect(hwnd, NULL, TRUE);
  1415. break;
  1416. case MM_BRUSH_SOLID:
  1417. case MM_BRUSH_TEXTURE:
  1418. case MM_BRUSH_TEXTURE_32x32:
  1419. case MM_BRUSH_TEXTURE_1x1:
  1420. case MM_BRUSH_LINEAR:
  1421. case MM_BRUSH_PATHGRADIENT:
  1422. CheckMenuItem(hmenu, MmBrushType, MF_UNCHECKED);
  1423. MmBrushType = mmCommand;
  1424. CheckMenuItem(hmenu, MmBrushType, MF_CHECKED);
  1425. CreateBrushes();
  1426. InvalidateRect(hwnd, NULL, TRUE);
  1427. break;
  1428. case MM_DYNAMICBRUSHRECTANGLE:
  1429. DoBrushRect = !DoBrushRect;
  1430. CheckMenuItem(hmenu, mmCommand, DoBrushRect ? MF_CHECKED : MF_UNCHECKED);
  1431. InvalidateRect(hwnd, NULL, TRUE);
  1432. break;
  1433. case MM_EDITBRUSHSHAPE:
  1434. DoShape = !DoShape;
  1435. CheckMenuItem(hmenu, mmCommand, DoShape ? MF_CHECKED : MF_UNCHECKED);
  1436. InvalidateRect(hwnd, NULL, TRUE);
  1437. break;
  1438. case MM_GDI:
  1439. DoGdi = !DoGdi;
  1440. CheckMenuItem(hmenu, mmCommand, DoGdi ? MF_CHECKED : MF_UNCHECKED);
  1441. InvalidateRect(hwnd, NULL, TRUE);
  1442. break;
  1443. default:
  1444. break;
  1445. }
  1446. break;
  1447. case WM_SIZE:
  1448. WindowWidth = (short)LOWORD(lParam);
  1449. WindowHeight = (short)HIWORD(lParam);
  1450. CreateRegion_Gdiplus();
  1451. CreateRegion_Gdi();
  1452. RecenterOverlay();
  1453. InvalidateRect(hwnd, NULL, TRUE);
  1454. break;
  1455. case WM_LBUTTONDOWN:
  1456. point.X = (REAL)(short)LOWORD(lParam);
  1457. point.Y = (REAL)(short)HIWORD(lParam);
  1458. // First, try to find a hit with the overlay. Then try a hit with
  1459. // the primitive points, in world space:
  1460. OverlayDragVertex = -1;
  1461. PrimitiveDragVertex = -1;
  1462. if (DoTransformOverlay)
  1463. {
  1464. OverlayDragVertex = FindNearest(point.X, point.Y, OverlayPoints, 3);
  1465. }
  1466. if (OverlayDragVertex == -1)
  1467. {
  1468. PrimitiveDragVertex = FindNearest(point.X, point.Y, PrimitivePoints,
  1469. PrimitivePointsCount, PrimitiveTransform);
  1470. }
  1471. // The first left-click disables 'adding points' mode:
  1472. IsAddingPoints = FALSE;
  1473. break;
  1474. case WM_RBUTTONDOWN:
  1475. point.X = (REAL)(short)LOWORD(lParam);
  1476. point.Y = (REAL)(short)HIWORD(lParam);
  1477. PrimitiveInverseTransform->TransformPoints(&point, 1);
  1478. // If we were in 'adding points' mode (which occurs when we're
  1479. // right-clicking in succession), simply add the point to the
  1480. // list.
  1481. //
  1482. // If we're not in 'adding points' mode, reset the point list
  1483. // and switch us to 'adding points' mode:
  1484. if (!IsAddingPoints)
  1485. {
  1486. IsAddingPoints = TRUE;
  1487. PrimitivePointsCount = 0;
  1488. }
  1489. // Add this point to the list:
  1490. if (PrimitivePointsCount < PrimitivePointsMax)
  1491. {
  1492. PrimitivePoints[PrimitivePointsCount] = point;
  1493. PrimitivePointsCount++;
  1494. // If this was the first point, make all the points the same
  1495. // (in part to make 'ellipse' and 'rectangle' properly empty):
  1496. if (PrimitivePointsCount == 1)
  1497. {
  1498. for (i = 1; i < PrimitivePointsMax; i++)
  1499. {
  1500. PrimitivePoints[i] = PrimitivePoints[0];
  1501. }
  1502. }
  1503. hdc = GetDC(hwnd);
  1504. Draw(hdc);
  1505. ReleaseDC(hwnd, hdc);
  1506. }
  1507. break;
  1508. case WM_MOUSEMOVE:
  1509. point.X = (REAL)(short)LOWORD(lParam);
  1510. point.Y = (REAL)(short)HIWORD(lParam);
  1511. // Overlay hit-testing works in screen space:
  1512. if (OverlayDragVertex != -1)
  1513. {
  1514. // To prevent extraneous redraws, redraw only if the new point
  1515. // is different:
  1516. if ((OverlayPoints[OverlayDragVertex].X != point.X) ||
  1517. (OverlayPoints[OverlayDragVertex].Y != point.Y))
  1518. {
  1519. UpdateOverlay(point.X, point.Y);
  1520. hdc = GetDC(hwnd);
  1521. Draw(hdc);
  1522. ReleaseDC(hwnd, hdc);
  1523. }
  1524. }
  1525. // Primitive hit-testing works in world space:
  1526. PrimitiveInverseTransform->TransformPoints(&point, 1);
  1527. if (PrimitiveDragVertex != -1)
  1528. {
  1529. // To prevent extraneous redraws, redraw only if the new point
  1530. // is different:
  1531. if ((PrimitivePoints[PrimitiveDragVertex].X != point.X) ||
  1532. (PrimitivePoints[PrimitiveDragVertex].Y != point.Y))
  1533. {
  1534. PrimitivePoints[PrimitiveDragVertex] = point;
  1535. hdc = GetDC(hwnd);
  1536. Draw(hdc);
  1537. ReleaseDC(hwnd, hdc);
  1538. }
  1539. }
  1540. break;
  1541. case WM_LBUTTONUP:
  1542. PrimitiveDragVertex = -1;
  1543. OverlayDragVertex = -1;
  1544. RecenterOverlay();
  1545. InvalidateRect(hwnd, NULL, TRUE);
  1546. break;
  1547. case WM_PAINT:
  1548. hdc = BeginPaint(hwnd, &ps);
  1549. Draw(hdc);
  1550. ReleaseDC(hwnd, hdc);
  1551. break;
  1552. case WM_TIMER:
  1553. if (DoRandomTest)
  1554. {
  1555. hdc = GetDC(hwnd);
  1556. Draw(hdc);
  1557. ReleaseDC(hwnd, hdc);
  1558. }
  1559. break;
  1560. case WM_DESTROY:
  1561. DeleteObjects_Gdiplus();
  1562. DeleteObjects_Gdi();
  1563. DeleteObject(ghbrWhite);
  1564. PostQuitMessage(0);
  1565. return(DefWindowProc(hwnd, message, wParam, lParam));
  1566. default:
  1567. return(DefWindowProc(hwnd, message, wParam, lParam));
  1568. }
  1569. return(0);
  1570. }
  1571. /***************************************************************************\
  1572. * InitializeApplication()
  1573. *
  1574. * Initializes app.
  1575. *
  1576. * History:
  1577. * 04-07-91 -by- KentD
  1578. * Wrote it.
  1579. \***************************************************************************/
  1580. BOOL InitializeApplication(VOID)
  1581. {
  1582. WNDCLASS wc;
  1583. ghbrWhite = (HBRUSH) GetStockObject(WHITE_BRUSH);
  1584. wc.style = 0;
  1585. wc.lpfnWndProc = MainWindowProc;
  1586. wc.cbClsExtra = 0;
  1587. wc.cbWndExtra = 0;
  1588. wc.hInstance = ghInstance;
  1589. wc.hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(POLYTESTICON));
  1590. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  1591. wc.hbrBackground = ghbrWhite;
  1592. wc.lpszMenuName = "MainMenu";
  1593. wc.lpszClassName = "TestClass";
  1594. if (!RegisterClass(&wc))
  1595. {
  1596. return(FALSE);
  1597. }
  1598. ghwndMain =
  1599. CreateWindowEx(
  1600. 0,
  1601. "TestClass",
  1602. "PolyTest",
  1603. (
  1604. WS_OVERLAPPED |
  1605. WS_CAPTION |
  1606. WS_BORDER |
  1607. WS_THICKFRAME |
  1608. WS_MAXIMIZEBOX |
  1609. WS_MINIMIZEBOX |
  1610. WS_CLIPCHILDREN |
  1611. WS_VISIBLE |
  1612. WS_SYSMENU
  1613. ),
  1614. 80,
  1615. 70,
  1616. 500,
  1617. 500,
  1618. NULL,
  1619. NULL,
  1620. ghInstance,
  1621. NULL
  1622. );
  1623. if (ghwndMain == NULL)
  1624. {
  1625. return(FALSE);
  1626. }
  1627. SetFocus(ghwndMain);
  1628. // Create our initialize stuff:
  1629. CreateBrushes();
  1630. CreatePens();
  1631. CreateOverlayTransform();
  1632. return(TRUE);
  1633. }
  1634. /***************************************************************************\
  1635. * main(argc, argv[])
  1636. *
  1637. * Sets up the message loop.
  1638. *
  1639. * History:
  1640. * 04-07-91 -by- KentD
  1641. * Wrote it.
  1642. \***************************************************************************/
  1643. _cdecl
  1644. main(
  1645. INT argc,
  1646. PCHAR argv[])
  1647. {
  1648. MSG msg;
  1649. HACCEL haccel;
  1650. CHAR* pSrc;
  1651. CHAR* pDst;
  1652. if (!gGdiplusInitHelper.IsValid())
  1653. {
  1654. return 0;
  1655. }
  1656. ghInstance = GetModuleHandle(NULL);
  1657. if (!InitializeApplication())
  1658. {
  1659. return(0);
  1660. }
  1661. haccel = LoadAccelerators(ghInstance, MAKEINTRESOURCE(ACCELS));
  1662. while (GetMessage(&msg, NULL, 0, 0))
  1663. {
  1664. if (!TranslateAccelerator(msg.hwnd, haccel, &msg))
  1665. {
  1666. TranslateMessage(&msg);
  1667. DispatchMessage(&msg);
  1668. }
  1669. }
  1670. return(1);
  1671. }