/******************************Module*Header*******************************\ * Module Name: wndstuff.cpp * * This file contains all the code necessary for a simple GDI+ primitive * test. * * Author: J. Andrew Goossen [andrewgo] * * Copyright (c) 1991-2000 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include #include #include #include using namespace Gdiplus; #include "wndstuff.h" #include "../gpinit.inc" #define HIT_DISTANCE 16 #define ABS(x) (((x) >= 0) ? (x) : -(x)) #define ROUND(x) ((INT) floor(x + 0.5f)) // We set the GDI transform to a 16x scaling transform, and the mode to // GM_ADVANCED, so that we can get full fractional accuracy on the points // that we feed to GDI: #define GDI_FIXEDPOINT_SCALE 16 // State for tracking the primitive vertices and transform: const INT PrimitivePointsMax = 64; INT PrimitivePointsCount = 4; PointF PrimitivePoints[PrimitivePointsMax] = { PointF(100, 100), PointF(100, 400), PointF(400, 400), PointF(400, 100) }; Matrix *PrimitiveTransform; Matrix *PrimitiveInverseTransform; INT PrimitiveDragVertex = -1; BOOL IsAddingPoints = FALSE; // State for tracking the location of the transform overlay: const REAL OverlayDimension = 100; PointF OverlayPoints[3]; // 3 device-space representing overlay, // where [1] is the elbow PointF OverlayOffset; // World-space coordinate of overlay elbow INT OverlayDragVertex = -1; // Miscellaneous state: INT WindowWidth; INT WindowHeight; // Settings: BOOL DoFill = FALSE; BOOL DoDraw = TRUE; BOOL DoAntialias = FALSE; BOOL DoGammaCorrect = FALSE; BOOL DoGdi = FALSE; BOOL DoClipGrid = FALSE; BOOL DoRandomTest = FALSE; BOOL DoWindingFill = FALSE; BOOL DoAnchors = TRUE; BOOL DoSpine = FALSE; BOOL DoWiden = FALSE; BOOL DoCompound = FALSE; BOOL DoTransformOverlay = FALSE; BOOL DoScalingOnly = FALSE; BOOL DoShape = FALSE; BOOL DoBrushRect = FALSE; REAL RenderMiterLimit = 10; INT RenderWidth = 1; INT RenderAlpha = 255; LinearGradientBrush *LinearBrush; GraphicsPath *PathGradientPath; Brush *RenderBrush; Pen *RenderPen; Region *RenderRegion; HRGN RenderHrgn; HBRUSH RenderHbrush; HPEN RenderHpen; WORD MmWrapMode = MM_WRAP_TILE; WORD MmBrushType = MM_BRUSH_SOLID; WORD MmEndCap = MM_CAP_FLAT; WORD MmJoin = MM_JOIN_MITER; WORD MmDashStyle = MM_STYLE_SOLID; WORD MmAlignment = MM_ALIGNMENT_CENTER; WORD MmPrimitive = MM_POLYGON; // Other useful globals: HINSTANCE ghInstance; HWND ghwndMain; HBRUSH ghbrWhite; //FARPROC glpfnEnterWidth; //FARPROC glpfnEnterAlpha; //FARPROC glpfnEnterPoints; //FARPROC glpfnEnterTransform; /***************************************************************************\ * Creates the GDI+ brush to be used. * \***************************************************************************/ VOID CreateBrush_Gdiplus() { WrapMode wrapMode; INT i; // Delete the old brush: delete RenderBrush; LinearBrush = NULL; RenderBrush = NULL; // Create the new one: Bitmap bitmap(L"winnt256.bmp"); switch (MmWrapMode) { case MM_WRAP_TILE: wrapMode = WrapModeTile; break; case MM_WRAP_CLAMP: wrapMode = WrapModeClamp; break; case MM_WRAP_FLIPX: wrapMode = WrapModeTileFlipX; break; case MM_WRAP_FLIPY: wrapMode = WrapModeTileFlipY; break; case MM_WRAP_FLIPXY: wrapMode = WrapModeTileFlipXY; break; } switch (MmBrushType) { case MM_BRUSH_SOLID: RenderBrush = new SolidBrush(Color(128, 128, 128)); break; case MM_BRUSH_TEXTURE: RenderBrush = new TextureBrush(&bitmap, wrapMode); break; case MM_BRUSH_TEXTURE_32x32: { Bitmap texture(32, 32, PixelFormat32bppARGB); Graphics g(&texture); g.DrawImage(&bitmap, Rect(0, 0, 32, 32)); TextureBrush *brush = new TextureBrush(&texture, wrapMode); // Set a translate: Matrix matrix(1, 0, 0, 1, 100, 100); brush->SetTransform(&matrix); RenderBrush = brush; } break; case MM_BRUSH_TEXTURE_1x1: { SolidBrush solidBrush(Color::Green); Bitmap texture(1, 1, PixelFormat32bppARGB); Graphics g(&texture); g.FillRectangle(&solidBrush, 0, 0, 1, 1); TextureBrush *brush = new TextureBrush(&texture, wrapMode); // Set a translate: Matrix matrix(1, 0, 0, 1, 100, 100); brush->SetTransform(&matrix); RenderBrush = brush; } break; case MM_BRUSH_LINEAR: { LinearGradientBrush *brush = new LinearGradientBrush( Point(100, 100), Point(100, 300), Color::Red, Color::Black ); brush->SetWrapMode(wrapMode); RenderBrush = brush; LinearBrush = brush; } break; case MM_BRUSH_PATHGRADIENT: { PathGradientBrush *brush; INT count; if (PathGradientPath != NULL) { brush = new PathGradientBrush(PathGradientPath); count = PathGradientPath->GetPointCount(); } else { // Substitute a default path for now: PointF points[] = { PointF(100, 100), PointF(100, 300), PointF(300, 300), PointF(30, 100) }; brush = new PathGradientBrush(points, 4); count = 4; } Color *colors = new Color[count]; for (i = 0; i < count; i += 2) { colors[i] = Color::Green; colors[i+1] = Color::Red; } brush->SetSurroundColors(colors, &count); delete [] colors; brush->SetCenterPoint(OverlayOffset); brush->SetCenterColor(Color::Black); RenderBrush = brush; } break; } } /***************************************************************************\ * Creates the GDI brush to be used. * \***************************************************************************/ VOID CreateBrush_Gdi() { DeleteObject(RenderHbrush); RenderHbrush = CreateSolidBrush(RGB(128, 128, 128)); } /***************************************************************************\ * Creates the GDI and GDI+ brushes to be used. * \***************************************************************************/ VOID CreateBrushes() { CreateBrush_Gdiplus(); CreateBrush_Gdi(); } /***************************************************************************\ * Creates the GDI+ pen to be used. * \***************************************************************************/ VOID CreatePen_Gdiplus() { DashCap dashCap; LineCap lineCap; LineJoin lineJoin; DashStyle dashStyle; PenAlignment alignment; delete RenderPen; RenderPen = new Pen(Color((BYTE) RenderAlpha, 255, 0, 0), (REAL) RenderWidth); switch (MmEndCap) { case MM_CAP_ROUND: lineCap = LineCapRound; dashCap = DashCapRound; break; case MM_CAP_SQUARE: lineCap = LineCapSquare; dashCap = DashCapFlat; break; case MM_CAP_FLAT: lineCap = LineCapFlat; dashCap = DashCapFlat; break; case MM_CAP_TRIANGLE: lineCap = LineCapTriangle; dashCap = DashCapTriangle; break; } RenderPen->SetEndCap(lineCap); RenderPen->SetStartCap(lineCap); RenderPen->SetDashCap(dashCap); switch (MmJoin) { case MM_JOIN_ROUND: lineJoin = LineJoinRound; break; case MM_JOIN_BEVEL: lineJoin = LineJoinBevel; break; case MM_JOIN_MITER: lineJoin = LineJoinMiter; break; } RenderPen->SetLineJoin(lineJoin); switch (MmDashStyle) { case MM_STYLE_SOLID: dashStyle = DashStyleSolid; break; case MM_STYLE_DASH: dashStyle = DashStyleDash; break; case MM_STYLE_DOT: dashStyle = DashStyleDot; break; case MM_STYLE_DASHDOT: dashStyle = DashStyleDashDot; break; case MM_STYLE_DASHDOTDOT: dashStyle = DashStyleDashDotDot; break; } RenderPen->SetDashStyle(dashStyle); switch (MmAlignment) { case MM_ALIGNMENT_CENTER: alignment = PenAlignmentCenter; break; case MM_ALIGNMENT_INSET: alignment = PenAlignmentInset; break; } RenderPen->SetAlignment(alignment); RenderPen->SetMiterLimit(RenderMiterLimit); // We should add a 'compound array' UI to make this more flexible. // But for now, we only ever create one type of compound line: if (DoCompound) { REAL compoundArray[] = { 0.0f, 0.2f, 0.8f, 1.0f }; RenderPen->SetCompoundArray(compoundArray, 4); } } /***************************************************************************\ * Creates the GDI pen to be used. * \***************************************************************************/ VOID CreatePen_Gdi() { DWORD lineCap; DWORD lineJoin; DWORD dashStyle; LOGBRUSH logBrush; DeleteObject(RenderHpen); switch (MmEndCap) { case MM_CAP_ROUND: lineCap = PS_ENDCAP_ROUND; break; case MM_CAP_SQUARE: lineCap = PS_ENDCAP_SQUARE; break; case MM_CAP_FLAT: lineCap = PS_ENDCAP_FLAT; break; case MM_CAP_TRIANGLE: lineCap = PS_ENDCAP_SQUARE; break; // No equivalent } switch (MmJoin) { case MM_JOIN_ROUND: lineJoin = PS_JOIN_ROUND; break; case MM_JOIN_BEVEL: lineJoin = PS_JOIN_BEVEL; break; case MM_JOIN_MITER: lineJoin = PS_JOIN_MITER; break; } switch (MmDashStyle) { case MM_STYLE_SOLID: dashStyle = PS_SOLID; break; case MM_STYLE_DASH: dashStyle = PS_DASH; break; case MM_STYLE_DOT: dashStyle = PS_DOT; break; case MM_STYLE_DASHDOT: dashStyle = PS_DASHDOT; break; case MM_STYLE_DASHDOTDOT: dashStyle = PS_DASHDOTDOT; break; } logBrush.lbStyle = BS_SOLID; logBrush.lbColor = RGB(255, 0, 0); logBrush.lbHatch = 0; RenderHpen = ExtCreatePen(lineCap | lineJoin | dashStyle | PS_GEOMETRIC, GDI_FIXEDPOINT_SCALE * RenderWidth, &logBrush, 0, NULL); } /***************************************************************************\ * Creates the GDI+ and GDI pens to be used. * \***************************************************************************/ VOID CreatePens() { CreatePen_Gdiplus(); CreatePen_Gdi(); } /***************************************************************************\ * Creates the GDI+ clip region to be used. * \***************************************************************************/ VOID CreateRegion_Gdiplus() { INT x; INT y; delete RenderRegion; RenderRegion = new Region(); for (x = 0; x < WindowWidth; x += 128) { for (y = 0; y < WindowHeight; y += 128) { RenderRegion->Exclude(Rect(x + 64, y, 64, 64)); RenderRegion->Exclude(Rect(x, y + 64, 64, 64)); } } } /***************************************************************************\ * Creates the GDI clip region to be used. * \***************************************************************************/ VOID CreateRegion_Gdi() { INT x; INT y; HRGN hrgn; DeleteObject(RenderHrgn); RenderHrgn = CreateRectRgn(0, 0, WindowWidth, WindowHeight); hrgn = CreateRectRgn(0, 0, 0, 0); for (x = 0; x < WindowWidth; x += 128) { for (y = 0; y < WindowHeight; y += 128) { SetRectRgn(hrgn, x + 64, y, x + 128, y + 64); CombineRgn(RenderHrgn, RenderHrgn, hrgn, RGN_DIFF); SetRectRgn(hrgn, x, y + 64, x + 64, y + 128); CombineRgn(RenderHrgn, RenderHrgn, hrgn, RGN_DIFF); } } DeleteObject(hrgn); } /***************************************************************************\ * Free all our global objects. * \***************************************************************************/ VOID DeleteObjects_Gdiplus() { delete RenderRegion; delete RenderBrush; delete RenderPen; delete PrimitiveTransform; delete PrimitiveInverseTransform; } /***************************************************************************\ * Free all our global objects. * \***************************************************************************/ VOID DeleteObjects_Gdi() { DeleteObject(RenderHrgn); DeleteObject(RenderHbrush); DeleteObject(RenderHpen); } /***************************************************************************\ * Draw the control points * \***************************************************************************/ VOID DrawAnchors( Graphics *g, PointF* points, INT count ) { SolidBrush blueBrush(Color(150, 128, 128, 128)); for (; count != 0; count--, points++) { PointF point(*points); PrimitiveTransform->TransformPoints(&point, 1); g->FillRectangle(&blueBrush, RectF(point.X - 2, point.Y - 2, 5, 5)); } } /***************************************************************************\ * DrawTransformOverlay * \***************************************************************************/ VOID DrawTransformOverlay( Graphics *g ) { Pen pen(Color::Purple, 1); SolidBrush brush(Color::Purple); g->DrawLine(&pen, OverlayPoints[1].X, OverlayPoints[1].Y, OverlayPoints[0].X, OverlayPoints[0].Y); g->DrawLine(&pen, OverlayPoints[1].X, OverlayPoints[1].Y, OverlayPoints[2].X, OverlayPoints[2].Y); g->FillRectangle(&brush, RectF(OverlayPoints[0].X - 2, OverlayPoints[0].Y - 2, 5, 5)); g->FillRectangle(&brush, RectF(OverlayPoints[2].X - 2, OverlayPoints[2].Y - 2, 5, 5)); } /***************************************************************************\ * Render_Gdiplus * \***************************************************************************/ INT Render_Gdiplus( Graphics *g, PointF *points, INT count ) { INT i; INT pointsUsed; // if (DoBrushRect) // { // LinearBrush->SetLinearPoints(points[0], points[1]); // } RectF rect(points[0].X, points[0].Y, points[1].X - points[0].X, points[1].Y - points[0].Y); Pen spinePen(Color(0, 128, 0), 0); GraphicsPath shapePath; switch (MmPrimitive) { case MM_POLYGON: { shapePath.AddPolygon(points, count); if (!DoShape) { if (DoFill) g->FillPolygon(RenderBrush, points, count, (DoWindingFill) ? FillModeWinding : FillModeAlternate); if (DoDraw) g->DrawPolygon(RenderPen, points, count); if (DoSpine) g->DrawPolygon(&spinePen, points, count); } pointsUsed = count; break; } case MM_LINES: { shapePath.AddLines(points, count); if (!DoShape) { if (DoDraw) g->DrawLines(RenderPen, points, count); if (DoSpine) g->DrawLines(&spinePen, points, count); } pointsUsed = count; break; } case MM_BEZIER: { GraphicsPath path; path.AddBeziers(points, count); shapePath.AddPath(&path, FALSE); if (!DoShape) { if (DoFill) g->FillPath(RenderBrush, &path); if (DoDraw) g->DrawPath(RenderPen, &path); if (DoSpine) g->DrawPath(&spinePen, &path); } pointsUsed = count; break; } case MM_RECTANGLE: { shapePath.AddRectangle(rect); if (!DoShape) { if (DoFill) g->FillRectangle(RenderBrush, rect); if (DoDraw) g->DrawRectangle(RenderPen, rect); if (DoSpine) g->DrawRectangle(&spinePen, rect); } pointsUsed = 2; break; } case MM_ELLIPSE: { shapePath.AddEllipse(rect); if (!DoShape) { if (DoFill) g->FillEllipse(RenderBrush, rect); if (DoDraw) g->DrawEllipse(RenderPen, rect); if (DoSpine) g->DrawEllipse(&spinePen, rect); } pointsUsed = 2; break; } case MM_TEXTPATH: { WCHAR string[] = L"GDI+ Rules!"; GraphicsPath path((DoWindingFill) ? FillModeWinding : FillModeAlternate); FontFamily family(L"Times New Roman"); PointF origin(points[0].X, points[0].Y); path.AddString( string, wcslen(string), &family, 0, 200, origin, NULL ); shapePath.AddPath(&path, FALSE); if (!DoShape) { if (DoFill) g->FillPath(RenderBrush, &path); if (DoDraw) g->DrawPath(RenderPen, &path); if (DoSpine) g->DrawPath(&spinePen, &path); } pointsUsed = 1; break; } } if (DoShape) { // Recreate the path to be use for the path-gradient brush, // using the new shape data: delete PathGradientPath; PathGradientPath = shapePath.Clone(); // Recreate the brush and do a complete fill of the window using // the specified brush: CreateBrushes(); if (DoFill) g->FillRectangle(RenderBrush, -262144, -262144, 524288, 524288); if (DoDraw) g->DrawPath(RenderPen, &shapePath); if (DoSpine) g->DrawPath(&spinePen, &shapePath); } if (DoWiden) { Pen widenPen(Color::Black, 0); shapePath.Widen(RenderPen, NULL); g->DrawPath(&widenPen, &shapePath); } return(pointsUsed); } /***************************************************************************\ * Render_Gdi * \***************************************************************************/ INT Render_Gdi( HDC hdc, PointF *primitivePoints, INT count ) { BOOL drawSpine; HGDIOBJ oldPen; HGDIOBJ oldBrush; HPEN hpenSpine; INT pointsUsed; POINT points[PrimitivePointsMax]; INT i; // Convert to integer, the preferred GDI format. Remember that we've // set the transform to scale down by 16, so we have to multiply by // 16 here. We've done this so that we can specify 28.4 directly to // GDI: for (i = 0; i < count; i++) { points[i].x = ROUND(GDI_FIXEDPOINT_SCALE * primitivePoints[i].X); points[i].y = ROUND(GDI_FIXEDPOINT_SCALE * primitivePoints[i].Y); } hpenSpine = CreatePen(PS_SOLID, 0, RGB(0, 128, 0)); for (drawSpine = FALSE; drawSpine != TRUE; drawSpine = TRUE) { if (drawSpine) { oldPen = SelectObject(hdc, hpenSpine); oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); } else { oldPen = SelectObject(hdc, (DoDraw) ? RenderHpen : GetStockObject(NULL_PEN)); oldBrush = SelectObject(hdc, (DoFill) ? RenderHbrush : GetStockObject(NULL_BRUSH)); } switch (MmPrimitive) { case MM_POLYGON: { Polygon(hdc, points, count); pointsUsed = count; break; } case MM_LINES: { Polyline(hdc, points, count); pointsUsed = count; break; } case MM_BEZIER: { // Don't use StrokeAndFillPath because GDI would close the // stroke: BeginPath(hdc); PolyBezier(hdc, points, count); EndPath(hdc); FillPath(hdc); BeginPath(hdc); PolyBezier(hdc, points, count); EndPath(hdc); StrokePath(hdc); pointsUsed = count; break; } case MM_RECTANGLE: { Rectangle(hdc, points[0].x, points[0].y, points[1].x, points[1].y); pointsUsed = 2; break; } case MM_ELLIPSE: { Ellipse(hdc, points[0].x, points[0].y, points[1].x, points[1].y); pointsUsed = 2; break; } case MM_TEXTPATH: { LOGFONT logFont; memset(&logFont, 0, sizeof(logFont)); // Don't forget to multiply the height by 16, because // we're using a scaling transform with GDI so that we // can spit out 28.4 coordinates: logFont.lfHeight = - GDI_FIXEDPOINT_SCALE * 200; strcpy(logFont.lfFaceName, "Times New Roman"); SetBkMode(hdc, TRANSPARENT); HFONT font = CreateFontIndirect(&logFont); HGDIOBJ oldFont = SelectObject(hdc, font); WCHAR string[] = L"GDI+ Rules!"; BeginPath(hdc); ExtTextOutW(hdc, points[0].x, points[0].y, 0, NULL, string, wcslen(string), NULL); EndPath(hdc); StrokeAndFillPath(hdc); SelectObject(hdc, oldFont); DeleteObject(font); pointsUsed = 1; } } SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); } DeleteObject(hpenSpine); return(pointsUsed); } /***************************************************************************\ * PrepareContext_Gdiplus * \***************************************************************************/ VOID PrepareContext_Gdiplus( Graphics *g ) { g->SetSmoothingMode((DoAntialias) ? SmoothingModeAntiAlias : SmoothingModeNone); g->SetCompositingQuality((DoGammaCorrect) ? CompositingQualityGammaCorrected : CompositingQualityAssumeLinear); if (DoClipGrid) { g->SetClip(RenderRegion); } g->SetTransform(PrimitiveTransform); } /***************************************************************************\ * PrepareContext_Gdi * \***************************************************************************/ VOID PrepareContext_Gdi( HDC hdc ) { REAL m[6]; XFORM xform; SetMiterLimit(hdc, RenderMiterLimit, NULL); SetPolyFillMode(hdc, (DoWindingFill) ? WINDING : ALTERNATE); if (DoClipGrid) { SelectClipRgn(hdc, RenderHrgn); } // Setup the transform: PrimitiveTransform->GetElements(m); // Scale the transform down by 16 so that we can give GDI 28.4 // coordinates directly as integers: xform.eM11 = m[0] / GDI_FIXEDPOINT_SCALE; xform.eM12 = m[1] / GDI_FIXEDPOINT_SCALE; xform.eM21 = m[2] / GDI_FIXEDPOINT_SCALE; xform.eM22 = m[3] / GDI_FIXEDPOINT_SCALE; xform.eDx = m[4]; xform.eDy = m[5]; SetGraphicsMode(hdc, GM_ADVANCED); SetWorldTransform(hdc, &xform); } /***************************************************************************\ * GenerateRandomPoints * \***************************************************************************/ INT GenerateRandomPoints( PointF *randomPoints, INT maxPoints ) { INT randomPointsCount; INT i; // Make 1 in 32 have lotsa randomPoints: if ((rand() & 31) == 0) { randomPointsCount = rand() & 511; } else { randomPointsCount = (rand() & 7) + 1; } randomPointsCount = min(randomPointsCount, maxPoints); // !!! Need to randomize switch (rand() & 3) { case 0: // Trivially clipped for (i = 0; i < randomPointsCount; i++) { randomPoints[i].X = (rand() % (16 * WindowWidth * 16)) / 16.0f; randomPoints[i].Y = (rand() % (16 * WindowHeight)) / 16.0f; } break; case 1: // Really small for (i = 0; i < randomPointsCount; i++) { randomPoints[i].X = (rand() & 127) / 16.0f + 32; randomPoints[i].Y = (rand() & 127) / 16.0f + 32; } break; default: // Big space, with at least one point inside window: randomPoints[0].X = (rand() % (16 * WindowWidth)) / 16.0f; randomPoints[0].Y = (rand() % (16 * WindowHeight)) / 16.0f; if (0) { for (i = 1; i < randomPointsCount; i++) { // Once in a while, make the points REALLY REALLY big: randomPoints[i].X = (REAL) (rand() * rand() * rand()); randomPoints[i].Y = (REAL) (rand() * rand() * rand()); } } else { for (i = 1; i < randomPointsCount; i++) { randomPoints[i].X = (rand() % 1000000 - 500000) / 16.0f; randomPoints[i].Y = (rand() % 1000000 - 500000) / 16.0f; } } break; } return(randomPointsCount); } /***************************************************************************\ * Draw * \***************************************************************************/ VOID Draw( HDC hdc, BOOL doTime = FALSE ) { CHAR stringBuffer[200]; LONGLONG startCounter; LONGLONG endCounter; LONGLONG counterFrequency; INT pointsUsed; INT repetitions = (doTime) ? 10 : 1; INT i; // Clear the window: HGDIOBJ hbrush = GetStockObject(WHITE_BRUSH); HGDIOBJ holdBrush = SelectObject(hdc, hbrush); PatBlt(hdc, -10000, -10000, 20000, 20000, PATCOPY); SelectObject(hdc, holdBrush); DeleteObject(hbrush); QueryPerformanceCounter((LARGE_INTEGER*) &startCounter); // Draw the stuff: if (DoGdi) { SaveDC(hdc); PrepareContext_Gdi(hdc); for (i = 0; i < repetitions; i++) { pointsUsed = Render_Gdi(hdc, PrimitivePoints, PrimitivePointsCount); } RestoreDC(hdc, -1); } else { Graphics g(hdc); PrepareContext_Gdiplus(&g); if (!DoRandomTest) { for (i = 0; i < repetitions; i++) { pointsUsed = Render_Gdiplus(&g, PrimitivePoints, PrimitivePointsCount); } } else { PointF points[512]; INT count; // To get faster 'test' rendering (by avoiding clears between // successive tests), always draw in a batch of '20': for (i = 0; i < 20; i++) { count = GenerateRandomPoints(points, 512); pointsUsed = Render_Gdiplus(&g, points, count); } } } // Display the time: QueryPerformanceCounter((LARGE_INTEGER*) &endCounter); QueryPerformanceFrequency((LARGE_INTEGER*) &counterFrequency); float seconds = (float)(endCounter - startCounter) / counterFrequency; INT milliseconds = (INT) (seconds * 1000 + 0.5f); if (doTime) { sprintf(stringBuffer, "%li repetitions: %li ms", repetitions, milliseconds); } else { sprintf(stringBuffer, "Rasterization time: %li ms", milliseconds); } SetBkMode(hdc, TRANSPARENT); ExtTextOut(hdc, 0, 0, 0, NULL, stringBuffer, strlen(stringBuffer), NULL); if (!DoRandomTest) { // Now that we're out of the timing loop, draw our control points: Graphics g(hdc); if (DoAnchors) { DrawAnchors(&g, PrimitivePoints, pointsUsed); } if (DoTransformOverlay) { DrawTransformOverlay(&g); } } } /***************************************************************************\ * EnterWidth * * Dialog for entering pen width. \***************************************************************************/ INT_PTR EnterWidth( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bTrans; switch (message) { case WM_INITDIALOG: SetDlgItemInt(hDlg, IDD_WIDTH, RenderWidth, TRUE); return(TRUE); case WM_COMMAND: if (wParam == IDD_OK) { RenderWidth = GetDlgItemInt(hDlg, IDD_WIDTH, &bTrans, TRUE); EndDialog(hDlg, wParam); InvalidateRect(ghwndMain, NULL, TRUE); } break; case WM_SETFOCUS: SetFocus(GetDlgItem(hDlg, IDD_WIDTH)); return(FALSE); default: return(FALSE); } return(TRUE); } /***************************************************************************\ * EnterAlpha * * Dialog for entering pen alpha. \***************************************************************************/ INT_PTR EnterAlpha( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bTrans; switch (message) { case WM_INITDIALOG: SetDlgItemInt(hDlg, IDD_ALPHA, RenderAlpha, TRUE); return(TRUE); case WM_COMMAND: if (wParam == IDD_OK) { RenderAlpha = GetDlgItemInt(hDlg, IDD_ALPHA, &bTrans, TRUE); EndDialog(hDlg, wParam); InvalidateRect(ghwndMain, NULL, TRUE); } break; case WM_SETFOCUS: SetFocus(GetDlgItem(hDlg, IDD_ALPHA)); return(FALSE); default: return(FALSE); } return(TRUE); } /***************************************************************************\ * EnterPoints * * Dialog for entering points. \***************************************************************************/ INT_PTR EnterPoints( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { BOOL bTrans; INT i; switch (message) { case WM_INITDIALOG: SetDlgItemInt(hDlg, IDD_POINT1X, ROUND(PrimitivePoints[0].X), TRUE); SetDlgItemInt(hDlg, IDD_POINT1Y, ROUND(PrimitivePoints[0].Y), TRUE); SetDlgItemInt(hDlg, IDD_POINT2X, ROUND(PrimitivePoints[1].X), TRUE); SetDlgItemInt(hDlg, IDD_POINT2Y, ROUND(PrimitivePoints[1].Y), TRUE); SetDlgItemInt(hDlg, IDD_POINT3X, ROUND(PrimitivePoints[2].X), TRUE); SetDlgItemInt(hDlg, IDD_POINT3Y, ROUND(PrimitivePoints[2].Y), TRUE); SetDlgItemInt(hDlg, IDD_POINT4X, ROUND(PrimitivePoints[3].X), TRUE); SetDlgItemInt(hDlg, IDD_POINT4Y, ROUND(PrimitivePoints[3].Y), TRUE); return(TRUE); case WM_COMMAND: if (wParam == IDD_OK) { PrimitivePoints[0].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT1X, &bTrans, TRUE); PrimitivePoints[0].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT1Y, &bTrans, TRUE); PrimitivePoints[1].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT2X, &bTrans, TRUE); PrimitivePoints[1].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT2Y, &bTrans, TRUE); PrimitivePoints[2].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT3X, &bTrans, TRUE); PrimitivePoints[2].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT3Y, &bTrans, TRUE); PrimitivePoints[3].X = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT4X, &bTrans, TRUE); PrimitivePoints[3].Y = (REAL) (INT) GetDlgItemInt(hDlg, IDD_POINT4Y, &bTrans, TRUE); EndDialog(hDlg, wParam); InvalidateRect(ghwndMain, NULL, TRUE); } break; case WM_SETFOCUS: SetFocus(GetDlgItem(hDlg, IDD_POINT1X)); return(FALSE); default: return(FALSE); } return(TRUE); } /***************************************************************************\ * EnterTransform * * Dialog for entering arbitrary transforms. \***************************************************************************/ INT_PTR EnterTransform( HWND hDlg, WORD message, WPARAM wParam, LONG lParam) { BOOL bTrans; REAL m[6]; PrimitiveTransform->GetElements(m); switch (message) { case WM_INITDIALOG: SetDlgItemInt(hDlg, IDD_M11, ROUND(m[0] * 1000.0f), TRUE); SetDlgItemInt(hDlg, IDD_M12, ROUND(m[1] * 1000.0f), TRUE); SetDlgItemInt(hDlg, IDD_M21, ROUND(m[2] * 1000.0f), TRUE); SetDlgItemInt(hDlg, IDD_M22, ROUND(m[3] * 1000.0f), TRUE); SetDlgItemInt(hDlg, IDD_M31, ROUND(m[4] * 1000.0f), TRUE); SetDlgItemInt(hDlg, IDD_M32, ROUND(m[5] * 1000.0f), TRUE); return(TRUE); case WM_COMMAND: if (wParam == IDD_OK) { m[0] = ((INT) GetDlgItemInt(hDlg, IDD_M11, &bTrans, TRUE)) / 1000.0f; m[1] = ((INT) GetDlgItemInt(hDlg, IDD_M12, &bTrans, TRUE)) / 1000.0f; m[2] = ((INT) GetDlgItemInt(hDlg, IDD_M21, &bTrans, TRUE)) / 1000.0f; m[3] = ((INT) GetDlgItemInt(hDlg, IDD_M22, &bTrans, TRUE)) / 1000.0f; m[4] = ((INT) GetDlgItemInt(hDlg, IDD_M31, &bTrans, TRUE)) / 1000.0f; m[5] = ((INT) GetDlgItemInt(hDlg, IDD_M32, &bTrans, TRUE)) / 1000.0f; PrimitiveTransform->SetElements(m[0], m[1], m[2], m[3], m[4], m[5]); PrimitiveInverseTransform->SetElements(m[0], m[1], m[2], m[3], m[4], m[5]); PrimitiveInverseTransform->Invert(); // Calculate the new world-space elbow location: OverlayOffset.X = OverlayPoints[1].X; OverlayOffset.Y = OverlayPoints[1].Y; PrimitiveInverseTransform->TransformPoints(&OverlayOffset); // Now calculate the new device-space end-points, by initializing // in world-space and then converting back to device-space: OverlayPoints[0].X = OverlayOffset.X + OverlayDimension; OverlayPoints[0].Y = OverlayOffset.Y; OverlayPoints[2].X = OverlayOffset.X; OverlayPoints[2].Y = OverlayOffset.Y - OverlayDimension; PrimitiveTransform->TransformPoints(&OverlayPoints[0]); PrimitiveTransform->TransformPoints(&OverlayPoints[2]); // We're done; force a redraw: EndDialog(hDlg, wParam); InvalidateRect(ghwndMain, NULL, TRUE); } break; case WM_SETFOCUS: SetFocus(GetDlgItem(hDlg, IDD_OK)); return(FALSE); default: return(FALSE); } return(TRUE); } /***************************************************************************\ * ComputeOverlayTransformFromPoints * \***************************************************************************/ VOID ComputeOverlayTransformFromPoints() { REAL dx1 = OverlayPoints[0].X - OverlayPoints[1].X; REAL dy1 = OverlayPoints[0].Y - OverlayPoints[1].Y; REAL dx2 = OverlayPoints[1].X - OverlayPoints[2].X; REAL dy2 = OverlayPoints[1].Y - OverlayPoints[2].Y; REAL xMid = (REAL) (WindowWidth >> 1); REAL yMid = (REAL) (WindowHeight >> 1); RectF srcRect(OverlayOffset.X, OverlayOffset.Y, OverlayDimension, OverlayDimension); // The order is upper-left, upper-right, lower-left corner: PointF dstPoints[] = { PointF(xMid, yMid), PointF(xMid + dx1, yMid + dy1), PointF(xMid + dx2, yMid + dy2) }; delete PrimitiveTransform; PrimitiveTransform = new Matrix(srcRect, dstPoints); delete PrimitiveInverseTransform; PrimitiveInverseTransform = PrimitiveTransform->Clone(); PrimitiveInverseTransform->Invert(); } /***************************************************************************\ * CreateOverlayTransform * \***************************************************************************/ VOID CreateOverlayTransform() { REAL xMid = (REAL) (WindowWidth >> 1); REAL yMid = (REAL) (WindowHeight >> 1); OverlayPoints[0].X = xMid + OverlayDimension; OverlayPoints[0].Y = yMid; OverlayPoints[1].X = xMid; OverlayPoints[1].Y = yMid; OverlayPoints[2].X = xMid; OverlayPoints[2].Y = yMid - OverlayDimension; OverlayOffset.X = xMid; OverlayOffset.Y = yMid; ComputeOverlayTransformFromPoints(); } /***************************************************************************\ * UpdateOverlay * \***************************************************************************/ VOID UpdateOverlay( REAL x, REAL y ) { if (OverlayDragVertex == 1) { // The root of the overlay is being moved, so we move the overlay // as a whole: REAL dx = x - OverlayPoints[1].X; REAL dy = y - OverlayPoints[1].Y; OverlayPoints[0].X += dx; OverlayPoints[0].Y += dy; OverlayPoints[1].X = x; OverlayPoints[1].Y = y; OverlayPoints[2].X += dx; OverlayPoints[2].Y += dy; } else { OverlayPoints[OverlayDragVertex].X = x; OverlayPoints[OverlayDragVertex].Y = y; ComputeOverlayTransformFromPoints(); } } /***************************************************************************\ * RecenterOverlay * \***************************************************************************/ VOID RecenterOverlay() { REAL xMid = (REAL) (WindowWidth >> 1); REAL yMid = (REAL) (WindowHeight >> 1); REAL dx = xMid - OverlayPoints[1].X; REAL dy = yMid - OverlayPoints[1].Y; // Center the transform around the new world-space focus point: OverlayOffset.X = OverlayPoints[1].X; OverlayOffset.Y = OverlayPoints[1].Y; if (PrimitiveInverseTransform != NULL) { PrimitiveInverseTransform->TransformPoints(&OverlayOffset, 1); } // Bring the overlay control back to the middle of the screen: OverlayPoints[0].X += dx; OverlayPoints[0].Y += dy; OverlayPoints[1].X = xMid; OverlayPoints[1].Y = yMid; OverlayPoints[2].X += dx; OverlayPoints[2].Y += dy; ComputeOverlayTransformFromPoints(); } /***************************************************************************\ * FindNearest * \***************************************************************************/ INT FindNearest( REAL x, // Device space REAL y, const PointF *points, // World space INT count, const Matrix *matrix = NULL // World-to-device transform ) { INT i; REAL d; REAL minDistance; INT vertex; PointF inputPoint(x, y); // Find the nearest vertex, using a simple Manhattan metric. minDistance = 100000; for (i = 0; i < count; i++) { PointF point(points[i]); // For the distance metric, we want to be doing our calculations // in device space: if (matrix) { matrix->TransformPoints(&point, 1); } d = ABS(x - point.X) + ABS(y - point.Y); if (d < minDistance) { minDistance = d; vertex = i; } } return((minDistance < HIT_DISTANCE) ? vertex : -1); } /***************************************************************************\ * MainWindowProc(hwnd, message, wParam, lParam) * * Processes all messages for the main window. * * History: * 04-07-91 -by- KentD * Wrote it. \***************************************************************************/ LRESULT MainWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { PointF point; LONG i; LONG d; LONG minDistance; LONG vertex; HDC hdc; PAINTSTRUCT ps; HMENU hmenu = GetMenu(hwnd); WORD mmCommand = LOWORD(wParam); switch (message) { case WM_CREATE: // NOTICE-DavePr@2002/05/28 // Missing FreeProcInstance for these anyway. //glpfnEnterWidth = (FARPROC) MakeProcInstance(EnterWidth, ghwndMain); //glpfnEnterAlpha = (FARPROC) MakeProcInstance(EnterAlpha, ghwndMain); //glpfnEnterPoints = (FARPROC) MakeProcInstance(EnterPoints, ghwndMain); //glpfnEnterTransform = (FARPROC) MakeProcInstance(EnterTransform, ghwndMain); SetTimer(hwnd, 1, 80, NULL); break; case WM_COMMAND: switch(mmCommand) { case MM_RANDOMTEST: DoRandomTest = !DoRandomTest; if (!DoRandomTest) InvalidateRect(hwnd, NULL, TRUE); break; case MM_WIDTH: //DialogBox(ghInstance, "Width", ghwndMain, glpfnEnterWidth); DialogBox(ghInstance, "Width", ghwndMain, EnterWidth); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_ALPHA: //DialogBox(ghInstance, "Alpha", ghwndMain, glpfnEnterAlpha); DialogBox(ghInstance, "Alpha", ghwndMain, EnterAlpha); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_POINTS: //DialogBox(ghInstance, "Points", ghwndMain, glpfnEnterPoints); DialogBox(ghInstance, "Points", ghwndMain, EnterPoints); InvalidateRect(hwnd, NULL, TRUE); break; case MM_EDITTRANSFORM: //DialogBox(ghInstance, "Transform", ghwndMain, glpfnEnterTransform); DialogBox(ghInstance, "Transform", ghwndMain, EnterTransform); InvalidateRect(hwnd, NULL, TRUE); break; case MM_REDRAW: hdc = GetDC(hwnd); Draw(hdc); ReleaseDC(hwnd, hdc); break; case MM_TIME: hdc = GetDC(hwnd); Draw(hdc, TRUE); ReleaseDC(hwnd, hdc); break; case MM_CLIPGRID: DoClipGrid = !DoClipGrid; CheckMenuItem(hmenu, mmCommand, DoClipGrid ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_ANTIALIAS: DoAntialias = !DoAntialias; CheckMenuItem(hmenu, mmCommand, DoAntialias ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_GAMMACORRECT: DoGammaCorrect = !DoGammaCorrect; CheckMenuItem(hmenu, mmCommand, DoGammaCorrect ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_WINDING: DoWindingFill = !DoWindingFill; CheckMenuItem(hmenu, mmCommand, DoWindingFill ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_SPINE: DoSpine = !DoSpine; CheckMenuItem(hmenu, mmCommand, DoSpine ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_WIDENPATH: DoWiden = !DoWiden; CheckMenuItem(hmenu, mmCommand, DoWiden ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_ANCHORS: DoAnchors = !DoAnchors; CheckMenuItem(hmenu, mmCommand, DoAnchors ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_TRANSFORMOVERLAY: DoTransformOverlay = !DoTransformOverlay; CheckMenuItem(hmenu, mmCommand, DoTransformOverlay ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_SCALINGONLY: DoScalingOnly = !DoScalingOnly; CheckMenuItem(hmenu, mmCommand, DoScalingOnly ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_RESETTRANSFORM: CreateOverlayTransform(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_FILL: DoFill = !DoFill; CheckMenuItem(hmenu, mmCommand, DoFill ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_DRAW: DoDraw = !DoDraw; CheckMenuItem(hmenu, mmCommand, DoDraw ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_POLYGON: case MM_LINES: case MM_BEZIER: case MM_RECTANGLE: case MM_ELLIPSE: case MM_TEXTPATH: CheckMenuItem(hmenu, MmPrimitive, MF_UNCHECKED); MmPrimitive = mmCommand; CheckMenuItem(hmenu, MmPrimitive, MF_CHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_COMPOUND: DoCompound = !DoCompound; CheckMenuItem(hmenu, mmCommand, DoCompound ? MF_CHECKED : MF_UNCHECKED); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_STYLE_SOLID: case MM_STYLE_DASH: case MM_STYLE_DOT: case MM_STYLE_DASHDOT: case MM_STYLE_DASHDOTDOT: CheckMenuItem(hmenu, MmDashStyle, MF_UNCHECKED); MmDashStyle = mmCommand; CheckMenuItem(hmenu, MmDashStyle, MF_CHECKED); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_CAP_FLAT: case MM_CAP_SQUARE: case MM_CAP_ROUND: case MM_CAP_TRIANGLE: CheckMenuItem(hmenu, MmEndCap, MF_UNCHECKED); MmEndCap = mmCommand; CheckMenuItem(hmenu, MmEndCap, MF_CHECKED); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_JOIN_ROUND: case MM_JOIN_MITER: case MM_JOIN_BEVEL: CheckMenuItem(hmenu, MmJoin, MF_UNCHECKED); MmJoin = mmCommand; CheckMenuItem(hmenu, MmJoin, MF_CHECKED); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_ALIGNMENT_CENTER: case MM_ALIGNMENT_INSET: CheckMenuItem(hmenu, MmAlignment, MF_UNCHECKED); MmAlignment = mmCommand; CheckMenuItem(hmenu, MmAlignment, MF_CHECKED); CreatePens(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_WRAP_TILE: case MM_WRAP_CLAMP: case MM_WRAP_FLIPX: case MM_WRAP_FLIPY: case MM_WRAP_FLIPXY: CheckMenuItem(hmenu, MmWrapMode, MF_UNCHECKED); MmWrapMode = mmCommand; CheckMenuItem(hmenu, MmWrapMode, MF_CHECKED); CreateBrushes(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_BRUSH_SOLID: case MM_BRUSH_TEXTURE: case MM_BRUSH_TEXTURE_32x32: case MM_BRUSH_TEXTURE_1x1: case MM_BRUSH_LINEAR: case MM_BRUSH_PATHGRADIENT: CheckMenuItem(hmenu, MmBrushType, MF_UNCHECKED); MmBrushType = mmCommand; CheckMenuItem(hmenu, MmBrushType, MF_CHECKED); CreateBrushes(); InvalidateRect(hwnd, NULL, TRUE); break; case MM_DYNAMICBRUSHRECTANGLE: DoBrushRect = !DoBrushRect; CheckMenuItem(hmenu, mmCommand, DoBrushRect ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_EDITBRUSHSHAPE: DoShape = !DoShape; CheckMenuItem(hmenu, mmCommand, DoShape ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; case MM_GDI: DoGdi = !DoGdi; CheckMenuItem(hmenu, mmCommand, DoGdi ? MF_CHECKED : MF_UNCHECKED); InvalidateRect(hwnd, NULL, TRUE); break; default: break; } break; case WM_SIZE: WindowWidth = (short)LOWORD(lParam); WindowHeight = (short)HIWORD(lParam); CreateRegion_Gdiplus(); CreateRegion_Gdi(); RecenterOverlay(); InvalidateRect(hwnd, NULL, TRUE); break; case WM_LBUTTONDOWN: point.X = (REAL)(short)LOWORD(lParam); point.Y = (REAL)(short)HIWORD(lParam); // First, try to find a hit with the overlay. Then try a hit with // the primitive points, in world space: OverlayDragVertex = -1; PrimitiveDragVertex = -1; if (DoTransformOverlay) { OverlayDragVertex = FindNearest(point.X, point.Y, OverlayPoints, 3); } if (OverlayDragVertex == -1) { PrimitiveDragVertex = FindNearest(point.X, point.Y, PrimitivePoints, PrimitivePointsCount, PrimitiveTransform); } // The first left-click disables 'adding points' mode: IsAddingPoints = FALSE; break; case WM_RBUTTONDOWN: point.X = (REAL)(short)LOWORD(lParam); point.Y = (REAL)(short)HIWORD(lParam); PrimitiveInverseTransform->TransformPoints(&point, 1); // If we were in 'adding points' mode (which occurs when we're // right-clicking in succession), simply add the point to the // list. // // If we're not in 'adding points' mode, reset the point list // and switch us to 'adding points' mode: if (!IsAddingPoints) { IsAddingPoints = TRUE; PrimitivePointsCount = 0; } // Add this point to the list: if (PrimitivePointsCount < PrimitivePointsMax) { PrimitivePoints[PrimitivePointsCount] = point; PrimitivePointsCount++; // If this was the first point, make all the points the same // (in part to make 'ellipse' and 'rectangle' properly empty): if (PrimitivePointsCount == 1) { for (i = 1; i < PrimitivePointsMax; i++) { PrimitivePoints[i] = PrimitivePoints[0]; } } hdc = GetDC(hwnd); Draw(hdc); ReleaseDC(hwnd, hdc); } break; case WM_MOUSEMOVE: point.X = (REAL)(short)LOWORD(lParam); point.Y = (REAL)(short)HIWORD(lParam); // Overlay hit-testing works in screen space: if (OverlayDragVertex != -1) { // To prevent extraneous redraws, redraw only if the new point // is different: if ((OverlayPoints[OverlayDragVertex].X != point.X) || (OverlayPoints[OverlayDragVertex].Y != point.Y)) { UpdateOverlay(point.X, point.Y); hdc = GetDC(hwnd); Draw(hdc); ReleaseDC(hwnd, hdc); } } // Primitive hit-testing works in world space: PrimitiveInverseTransform->TransformPoints(&point, 1); if (PrimitiveDragVertex != -1) { // To prevent extraneous redraws, redraw only if the new point // is different: if ((PrimitivePoints[PrimitiveDragVertex].X != point.X) || (PrimitivePoints[PrimitiveDragVertex].Y != point.Y)) { PrimitivePoints[PrimitiveDragVertex] = point; hdc = GetDC(hwnd); Draw(hdc); ReleaseDC(hwnd, hdc); } } break; case WM_LBUTTONUP: PrimitiveDragVertex = -1; OverlayDragVertex = -1; RecenterOverlay(); InvalidateRect(hwnd, NULL, TRUE); break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); Draw(hdc); ReleaseDC(hwnd, hdc); break; case WM_TIMER: if (DoRandomTest) { hdc = GetDC(hwnd); Draw(hdc); ReleaseDC(hwnd, hdc); } break; case WM_DESTROY: DeleteObjects_Gdiplus(); DeleteObjects_Gdi(); DeleteObject(ghbrWhite); PostQuitMessage(0); return(DefWindowProc(hwnd, message, wParam, lParam)); default: return(DefWindowProc(hwnd, message, wParam, lParam)); } return(0); } /***************************************************************************\ * InitializeApplication() * * Initializes app. * * History: * 04-07-91 -by- KentD * Wrote it. \***************************************************************************/ BOOL InitializeApplication(VOID) { WNDCLASS wc; ghbrWhite = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.style = 0; wc.lpfnWndProc = MainWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInstance; wc.hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(POLYTESTICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = ghbrWhite; wc.lpszMenuName = "MainMenu"; wc.lpszClassName = "TestClass"; if (!RegisterClass(&wc)) { return(FALSE); } ghwndMain = CreateWindowEx( 0, "TestClass", "PolyTest", ( WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_VISIBLE | WS_SYSMENU ), 80, 70, 500, 500, NULL, NULL, ghInstance, NULL ); if (ghwndMain == NULL) { return(FALSE); } SetFocus(ghwndMain); // Create our initialize stuff: CreateBrushes(); CreatePens(); CreateOverlayTransform(); return(TRUE); } /***************************************************************************\ * main(argc, argv[]) * * Sets up the message loop. * * History: * 04-07-91 -by- KentD * Wrote it. \***************************************************************************/ _cdecl main( INT argc, PCHAR argv[]) { MSG msg; HACCEL haccel; CHAR* pSrc; CHAR* pDst; if (!gGdiplusInitHelper.IsValid()) { return 0; } ghInstance = GetModuleHandle(NULL); if (!InitializeApplication()) { return(0); } haccel = LoadAccelerators(ghInstance, MAKEINTRESOURCE(ACCELS)); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, haccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return(1); }