|
|
/******************************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 <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <windows.h>
#include <objbase.h>
#include <mmsystem.h>
#include <gdiplus.h>
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); }
|