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.
472 lines
13 KiB
472 lines
13 KiB
#include <crtdbg.h>
|
|
|
|
#include <stdio.h>
|
|
#include <objbase.h>
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
#include <commdlg.h>
|
|
#include <gdiplus.h>
|
|
using namespace Gdiplus;
|
|
|
|
#include "wndstuff.h"
|
|
|
|
GraphicsPath gppath;
|
|
GraphicsPath widepath;
|
|
GraphicsPath clippath;
|
|
TextureBrush *texturebrush = NULL;
|
|
PointF lastpoint(-1,-1);
|
|
Bitmap *offscreenbitmap = NULL;
|
|
int subpathlength = 0;
|
|
int ScaleColorMode = 0;
|
|
WCHAR savedFilename[255];
|
|
|
|
void
|
|
RemakePath(GraphicsPath *linepath, GraphicsPath *bezpath, BOOL bezmode)
|
|
{
|
|
GraphicsPath *temppath = linepath->Clone();
|
|
temppath->CloseFigure();
|
|
bezpath->Reset();
|
|
PointF *points = new PointF[temppath->GetPointCount()];
|
|
BYTE *types = new BYTE[temppath->GetPointCount()];
|
|
temppath->GetPathPoints(points, temppath->GetPointCount());
|
|
temppath->GetPathTypes(types, temppath->GetPointCount());
|
|
int last = 0;
|
|
for (int i=0; i<temppath->GetPointCount(); i++)
|
|
{
|
|
if (types[i] & PathPointTypeCloseSubpath)
|
|
{
|
|
if (i-last+1 > 2)
|
|
{
|
|
if (!bezmode)
|
|
{
|
|
bezpath->AddPolygon(points+last, i-last+1);
|
|
}
|
|
else
|
|
{
|
|
bezpath->AddClosedCurve(points+last, i-last+1);
|
|
}
|
|
last = i+1;
|
|
}
|
|
}
|
|
}
|
|
delete points;
|
|
delete types;
|
|
delete temppath;
|
|
}
|
|
|
|
void
|
|
SplitPath(BOOL bezmode, BOOL before, BOOL after, float flatness)
|
|
{
|
|
if (gppath.GetPointCount() < 3)
|
|
return;
|
|
|
|
RemakePath(&gppath, &widepath, bezmode);
|
|
|
|
if (widepath.GetPointCount() > 2)
|
|
{
|
|
Pen pen(Color(0xff000000), 20);
|
|
pen.SetLineJoin(LineJoinMiter);
|
|
pen.SetMiterLimit(5);
|
|
Matrix matrix;
|
|
if (before)
|
|
widepath.Outline(NULL, flatness);
|
|
widepath.Widen(&pen, NULL, flatness);
|
|
if (after)
|
|
widepath.Outline(NULL, flatness);
|
|
}
|
|
}
|
|
|
|
void
|
|
ClosePath()
|
|
{
|
|
if (gppath.GetPointCount() < 1)
|
|
return;
|
|
gppath.CloseFigure();
|
|
lastpoint = PointF(-1,-1);
|
|
}
|
|
|
|
void
|
|
ClearPath()
|
|
{
|
|
lastpoint = PointF(-1,-1);
|
|
gppath.Reset();
|
|
widepath.Reset();
|
|
}
|
|
|
|
void
|
|
ClipPath(BOOL bezmode)
|
|
{
|
|
clippath.Reset();
|
|
GraphicsPath remadepath;
|
|
RemakePath(&gppath, &remadepath, bezmode);
|
|
clippath.AddPath(&remadepath, FALSE);
|
|
ClearPath();
|
|
}
|
|
|
|
void
|
|
ClearClipPath()
|
|
{
|
|
clippath.Reset();
|
|
}
|
|
|
|
void
|
|
AddPoint(INT x, INT y)
|
|
{
|
|
if (!(lastpoint.X == -1 && lastpoint.Y == -1))
|
|
{
|
|
gppath.AddLine(lastpoint, PointF((float)x, (float)y));
|
|
}
|
|
lastpoint = PointF((float)x, (float)y);
|
|
}
|
|
|
|
void
|
|
OpenPath(char *filename)
|
|
{
|
|
FILE *f = fopen(filename, "rt");
|
|
INT count;
|
|
|
|
fscanf(f, "%i", &count);
|
|
for (INT i=0; i<count; i++)
|
|
{
|
|
INT type;
|
|
REAL x, y;
|
|
fscanf(f, "%i %f %f\n", &type, &x, &y);
|
|
|
|
if (((type & 7) == 0) && i == 0)
|
|
{
|
|
gppath.Reset();
|
|
PointF lastpoint; lastpoint.X = -1; lastpoint.Y = -1;
|
|
}
|
|
|
|
if ((type & 7) == 0)
|
|
{
|
|
lastpoint = PointF((float)x, (float)y);
|
|
}
|
|
else if ((type & 7) == 1)
|
|
{
|
|
gppath.AddLine(lastpoint, PointF((float)x, (float)y));
|
|
lastpoint = PointF((float)x, (float)y);
|
|
}
|
|
|
|
if (type & 128)
|
|
{
|
|
//gppath.AddLine(firstpoint, lastpoint);
|
|
ClosePath();
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void
|
|
SavePath(char *filename)
|
|
{
|
|
FILE *f = fopen(filename, "wt");
|
|
|
|
int count = gppath.GetPointCount();
|
|
|
|
Point *pathpoints = new Point[count];
|
|
BYTE *pathtypes = new BYTE[count];
|
|
gppath.GetPathPoints(pathpoints, count);
|
|
gppath.GetPathTypes(pathtypes, count);
|
|
|
|
fprintf(f, "%d\n", count);
|
|
for (int i=0; i<count; i++)
|
|
{
|
|
fprintf(f, "%i %d %d\n", pathtypes[i], pathpoints[i].X, pathpoints[i].Y);
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
delete pathpoints;
|
|
delete pathtypes;
|
|
}
|
|
|
|
void
|
|
SetColorMode(INT colorMode)
|
|
{
|
|
ScaleColorMode = colorMode;
|
|
ChangeTexture(savedFilename);
|
|
}
|
|
|
|
Color
|
|
ScaleColor(Color color, INT x, INT width)
|
|
{
|
|
REAL alphaScale = 1, redScale = 1, greenScale = 1, blueScale = 1;
|
|
switch (ScaleColorMode)
|
|
{
|
|
case 1:
|
|
alphaScale = 0.5;
|
|
break;
|
|
case 2:
|
|
alphaScale = (REAL)x / width;
|
|
break;
|
|
}
|
|
|
|
REAL alpha = ((REAL)color.GetAlpha())*alphaScale;
|
|
REAL red = ((REAL)color.GetRed())*redScale;
|
|
REAL green = ((REAL)color.GetGreen())*greenScale;
|
|
REAL blue = ((REAL)color.GetBlue())*blueScale;
|
|
return Color((BYTE)alpha, (BYTE)red, (BYTE)green, (BYTE)blue);
|
|
}
|
|
|
|
void
|
|
ScaleColors(Bitmap* destBitmap, Bitmap *bitmap)
|
|
{
|
|
BitmapData bmpData;
|
|
Rect rect = Rect(0, 0, bitmap->GetWidth(), bitmap->GetHeight());
|
|
if (bitmap->LockBits(&rect, ImageLockModeRead, PixelFormat32bppARGB, &bmpData) == Ok)
|
|
{
|
|
ARGB *data;
|
|
for (UINT y=0; y<bitmap->GetHeight(); y++)
|
|
{
|
|
data = (ARGB*)((BYTE*)bmpData.Scan0+(y*bmpData.Stride));
|
|
for (UINT x=0; x<bitmap->GetWidth(); x++)
|
|
{
|
|
*data = ScaleColor(Color(*data), x, bitmap->GetWidth()).GetValue();
|
|
data++;
|
|
}
|
|
}
|
|
BitmapData bmpDataDest;
|
|
if (destBitmap->LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bmpDataDest) == Ok)
|
|
{
|
|
memcpy(bmpDataDest.Scan0, bmpData.Scan0, bitmap->GetWidth() * bitmap->GetHeight() * sizeof(ARGB));
|
|
destBitmap->UnlockBits(&bmpDataDest);
|
|
}
|
|
bitmap->UnlockBits(&bmpData);
|
|
}
|
|
}
|
|
|
|
void
|
|
ChangeTexture(const WCHAR *filename)
|
|
{
|
|
wcsncpy(savedFilename, filename, 255);
|
|
delete texturebrush;
|
|
Bitmap image(filename);
|
|
Bitmap image2(image.GetWidth(), image.GetHeight(), PixelFormat32bppARGB);
|
|
ScaleColors(&image2, &image);
|
|
texturebrush = new TextureBrush(&image2);
|
|
}
|
|
|
|
void
|
|
Resize(INT x, INT y)
|
|
{
|
|
delete offscreenbitmap;
|
|
offscreenbitmap = new Bitmap(x, y, PixelFormat32bppPARGB);
|
|
}
|
|
|
|
void
|
|
CleanUp()
|
|
{
|
|
delete offscreenbitmap;
|
|
delete texturebrush;
|
|
}
|
|
|
|
VOID
|
|
Print(HWND hwnd, float flatness, PtFlag flags)
|
|
{
|
|
PRINTDLG printdlg;
|
|
memset(&printdlg, 0, sizeof(PRINTDLG));
|
|
printdlg.lStructSize = sizeof(PRINTDLG);
|
|
printdlg.hwndOwner = hwnd;
|
|
printdlg.hDevMode = NULL;
|
|
printdlg.hDevNames = NULL;
|
|
printdlg.hDC = NULL;
|
|
printdlg.Flags = PD_RETURNDC;
|
|
if (PrintDlg(&printdlg))
|
|
{
|
|
DOCINFO di;
|
|
memset(&di, 0, sizeof(DOCINFO));
|
|
di.cbSize = sizeof(DOCINFO);
|
|
di.lpszDocName = "Path Printing Test";
|
|
di.lpszOutput = (LPTSTR)NULL;
|
|
di.lpszDatatype = (LPTSTR)NULL;
|
|
di.fwType = 0;
|
|
DEVMODE *devmode = (DEVMODE*)GlobalLock(printdlg.hDevMode);
|
|
if (devmode == NULL)
|
|
return;
|
|
HANDLE hprinter;
|
|
OpenPrinter((LPSTR)devmode->dmDeviceName, &hprinter, NULL);
|
|
GlobalUnlock(printdlg.hDevMode);
|
|
|
|
StartDoc(printdlg.hDC, &di);
|
|
StartPage(printdlg.hDC);
|
|
|
|
DrawPath(hwnd, &printdlg.hDC, &hprinter, flatness, flags);
|
|
|
|
EndPage(printdlg.hDC);
|
|
EndDoc(printdlg.hDC);
|
|
}
|
|
else
|
|
{
|
|
DWORD error = CommDlgExtendedError();
|
|
if (error)
|
|
{
|
|
char errormessage[100];
|
|
sprintf(errormessage, "PrintDlg error: %d", error);
|
|
MessageBox(hwnd, errormessage, "PrintDlg error", MB_OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawPath(HWND hwnd, HDC *phdc, HANDLE *hprinter, float flatness, PtFlag flags)
|
|
{
|
|
if (!offscreenbitmap)
|
|
return;
|
|
|
|
Graphics *renderinggraphics;
|
|
if (phdc)
|
|
{
|
|
renderinggraphics = new Graphics(*phdc, *hprinter);
|
|
}
|
|
else
|
|
{
|
|
renderinggraphics = new Graphics(offscreenbitmap);
|
|
}
|
|
|
|
RECT rect;
|
|
GetClientRect(hwnd, &rect);
|
|
|
|
Brush *background;
|
|
if (flags & PTBackgroundGradFillFlag)
|
|
{
|
|
background = new LinearGradientBrush(Point(0, 0), Point((rect.right-rect.left)/4, 0), Color(0xffffffff), Color(0xff0000ff));
|
|
((LinearGradientBrush*)background)->SetWrapMode(WrapModeTileFlipX);
|
|
}
|
|
else
|
|
{
|
|
background = new SolidBrush(Color(0xffffffff));
|
|
}
|
|
renderinggraphics->FillRectangle(background, Rect(rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top));
|
|
delete background;
|
|
|
|
renderinggraphics->SetSmoothingMode(SmoothingModeAntiAlias);
|
|
|
|
if (gppath.GetPointCount() > 0)
|
|
{
|
|
SplitPath(flags & PtBezierFlag, flags & PtOutlineBeforeFlag, flags & PtOutlineAfterFlag, flatness);
|
|
if (clippath.GetPointCount() > 2)
|
|
{
|
|
renderinggraphics->SetClip(&clippath);
|
|
}
|
|
|
|
if (flags & PtTextureFillFlag)
|
|
{
|
|
if (!texturebrush)
|
|
ChangeTexture(L"mycomputer.jpg");
|
|
|
|
GraphicsPath bezpath;
|
|
RemakePath(&gppath, &bezpath, flags & PtBezierFlag);
|
|
if (flags & PtOutlineBeforeFlag)
|
|
bezpath.Outline();
|
|
bezpath.SetFillMode(FillModeWinding);
|
|
renderinggraphics->FillPath(texturebrush, &bezpath);
|
|
}
|
|
|
|
if (flags & PtTransSolidFillFlag)
|
|
{
|
|
SolidBrush transsolidbrush(Color(0x80ffff00));
|
|
GraphicsPath bezpath;
|
|
RemakePath(&gppath, &bezpath, flags & PtBezierFlag);
|
|
if (flags & PtOutlineBeforeFlag)
|
|
bezpath.Outline();
|
|
bezpath.SetFillMode(FillModeAlternate);
|
|
renderinggraphics->FillPath(&transsolidbrush, &bezpath);
|
|
}
|
|
|
|
if (flags & PtTransGradFillFlag)
|
|
{
|
|
GraphicsPath bezpath;
|
|
RemakePath(&gppath, &bezpath, flags & PtBezierFlag);
|
|
Matrix m;
|
|
bezpath.Flatten(&m, flatness);
|
|
INT count = bezpath.GetPointCount();
|
|
if (flags & PtOutlineBeforeFlag)
|
|
bezpath.Outline();
|
|
bezpath.SetFillMode(FillModeAlternate);
|
|
PathGradientBrush pathgradientbrush(&bezpath);
|
|
Color *colors = new Color[count];
|
|
for (int i=0; i<count; i++)
|
|
colors[i] = (i/2 == (float)i/2) ? 0xffff0000 : 0x80000000;
|
|
pathgradientbrush.SetCenterColor(0x00000000);
|
|
pathgradientbrush.SetSurroundColors(colors, &count);
|
|
renderinggraphics->FillPath(&pathgradientbrush, &bezpath);
|
|
delete colors;
|
|
}
|
|
|
|
if (!(flags & PtHatchBrushFlag))
|
|
{
|
|
SolidBrush pathbrush(Color(0xffc0c0ff));
|
|
renderinggraphics->FillPath(&pathbrush, &widepath);
|
|
}
|
|
else
|
|
{
|
|
HatchBrush pathbrush(HatchStyleDiagonalBrick, Color(0xff000000), Color(0xffc0c0ff));
|
|
renderinggraphics->FillPath(&pathbrush, &widepath);
|
|
}
|
|
|
|
Pen blackpen(Color(0xff000000), 2);
|
|
blackpen.SetLineJoin(LineJoinMiter);
|
|
renderinggraphics->DrawPath(&blackpen, &widepath);
|
|
|
|
renderinggraphics->ResetClip();
|
|
|
|
SolidBrush solidbrush(0xff0000ff);
|
|
Pen pathpen(&solidbrush);
|
|
pathpen.SetLineJoin(LineJoinRound);
|
|
if (!(flags & PtDashPatternFlag))
|
|
{
|
|
pathpen.SetWidth(6);
|
|
}
|
|
else
|
|
{
|
|
pathpen.SetWidth(8);
|
|
pathpen.SetDashStyle(DashStyleDot);
|
|
pathpen.SetDashCap(DashCapRound);
|
|
REAL distances[6] = {1.0f, 1.0f, 3.0f, 3.5f, 7.0f, 9.0f};
|
|
pathpen.SetDashPattern(distances,6);
|
|
}
|
|
renderinggraphics->DrawPath(&pathpen, &gppath);
|
|
|
|
PointF *points = new PointF[gppath.GetPointCount()];
|
|
gppath.GetPathPoints(points, gppath.GetPointCount());
|
|
for (INT i=0; i<gppath.GetPointCount(); i++)
|
|
{
|
|
SolidBrush bluebrush(Color(0xff0000ff));
|
|
RectF rect((float)points[i].X-4, (float)points[i].Y-4, 8, 8);
|
|
renderinggraphics->FillEllipse(&bluebrush, rect);
|
|
}
|
|
delete points;
|
|
}
|
|
|
|
if (clippath.GetPointCount() > 2)
|
|
{
|
|
Pen clippen(Color(0xffff0000), 4);
|
|
clippen.SetDashStyle(DashStyleDot);
|
|
clippen.SetLineJoin(LineJoinRound);
|
|
renderinggraphics->DrawPath(&clippen, &clippath);
|
|
}
|
|
|
|
SolidBrush darkbluebrush(Color(0xff0000c0));
|
|
if (lastpoint.X != -1 && lastpoint.Y != -1)
|
|
{
|
|
RectF rect(lastpoint.X-6, lastpoint.Y-6, 12, 12);
|
|
renderinggraphics->FillEllipse(&darkbluebrush, rect);
|
|
}
|
|
|
|
delete renderinggraphics;
|
|
|
|
if (phdc == NULL)
|
|
{
|
|
HDC hdc = GetDC(hwnd);
|
|
Graphics *g = new Graphics(hdc);
|
|
PAINTSTRUCT paintstruct;
|
|
BeginPaint(hwnd, &paintstruct);
|
|
g->DrawImage(offscreenbitmap, 0, 0);
|
|
EndPaint(hwnd, &paintstruct);
|
|
ReleaseDC(hwnd, hdc);
|
|
delete g;
|
|
}
|
|
}
|
|
|