|
|
/**************************************************************************\
* * Copyright (c) 1999 Microsoft Corporation * * Module Name: * * QuadTest.cpp * * Abstract: * * Test app for quad transform * * Usage: * QuadTest * * * Revision History: * * 03/18/1999 ikkof * Created it. * \**************************************************************************/
#include "precomp.hpp"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <windows.h>
#include <objbase.h>
#include <gdiplus.h>
// Use the given namespace
using namespace Gdiplus;
CHAR* programName; // program name
HINSTANCE appInstance; // handle to the application instance
HWND hwndMain; // handle to application's main window
SIZE srcSize; // source bitmap size
SIZE dstSize; // destination bitmap size
SIZE wndSizeExtra; // extra pixels for window decorations
BOOL isDragging = FALSE; // used to handle mouse dragging
INT knobSize = 6; // mesh control point knob size
BOOL showMesh = TRUE;
POINT pts[5]; INT index = -1; Rect srcRect; Point ptsF[5]; Point pt00, pt10, pt20, pt30; Point bPts[4];
class QuadGraphics : public Graphics { public:
QuadGraphics(HDC hdc) : Graphics(hdc) { }
QuadGraphics(HWND hwnd) : Graphics(hwnd) { }
Status DrawWarpedLine( const Pen* pen, Point& pt1, Point& pt2, Point* points, INT count, Rect srcRect ) { return SetStatus(DllExports::GdipDrawWarpedLine( GetNativeGraphics(), GetNativePen(pen), pt1.X, pt1.Y, pt2.X, pt2.Y, points, count, &srcRect ) ); } Status DrawWarpedBezier( const Pen* pen, Point& pt1, Point& pt2, Point& pt3, Point& pt4, Point* points, INT count, Rect srcRect ) { return SetStatus(DllExports::GdipDrawWarpedBezier( GetNativeGraphics(), GetNativePen(pen), pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y, points, count, &srcRect ) ); } };
//
// Display an error message dialog and quit
//
VOID Error( const CHAR* fmt, ... )
{ va_list arglist;
va_start(arglist, fmt); vfprintf(stderr, fmt, arglist); va_end(arglist);
exit(-1); }
//
// Create a new mesh object
//
VOID CreateMesh() { srcSize.cx = 300; srcSize.cy = 300;
dstSize = srcSize; INT offset = 10; pts[0].x = offset; pts[0].y = offset; pts[1].x = srcSize.cx - offset; pts[1].y = offset; pts[2].x = srcSize.cx - offset; pts[2].y = srcSize.cy - offset; pts[3].x = offset; pts[3].y = srcSize.cy - offset; pts[4] = pts[0];
srcRect.X = (REAL) pts[0].x; srcRect.Y = (REAL) pts[0].y; srcRect.Width = (REAL) pts[2].x - pts[0].x; srcRect.Height = (REAL) pts[2].y - pts[0].y;
ptsF[0].X = (REAL) pts[0].x; ptsF[0].Y = (REAL) pts[0].y; ptsF[1].X = (REAL) pts[1].x; ptsF[1].Y = (REAL) pts[1].y; ptsF[2].X = (REAL) pts[3].x; ptsF[2].Y = (REAL) pts[3].y; ptsF[3].X = (REAL) pts[2].x; ptsF[3].Y = (REAL) pts[2].y;
pt00 = ptsF[0]; pt10 = ptsF[1]; pt20 = ptsF[2]; pt30 = ptsF[3];
bPts[0].X = (REAL) 2*offset; bPts[0].Y = (REAL) srcSize.cy/2; bPts[1].X = (REAL) srcSize.cx/2; bPts[1].Y = 0; bPts[2].X = (REAL) srcSize.cx; bPts[2].Y = (REAL) srcSize.cy/2; bPts[3].X = (REAL) 3*srcSize.cx/4; bPts[3].Y = (REAL) 3*srcSize.cy/4; }
//
// Draw mesh
//
#define MESHCOLOR RGB(255, 0, 0)
VOID DrawMesh( HDC hdc ) { static HPEN meshPen = NULL; static HBRUSH meshBrush = NULL;
if (meshPen == NULL) meshPen = CreatePen(PS_SOLID, 1, MESHCOLOR);
SelectObject(hdc, meshPen);
// Draw horizontal meshes
INT i, j, rows, cols, pointCount; POINT* points;
// Draw knobs
// Create the brush to draw the mesh if necessary
if (meshBrush == NULL) meshBrush = CreateSolidBrush(MESHCOLOR);
Polyline(hdc, pts, 5); for (j=0; j < 4; j++) { RECT rect;
rect.left = pts[j].x - knobSize/2; rect.top = pts[j].y - knobSize/2; rect.right = rect.left + knobSize; rect.bottom = rect.top + knobSize;
FillRect(hdc, &rect, meshBrush);
} }
VOID DoGDIPlusDrawing( HWND hwnd, HDC hdc ) {
// QuadGraphics *g = Graphics::GetFromHwnd(hwnd);
QuadGraphics *g = new QuadGraphics(hwnd);
REAL width = 1; Color color(0, 0, 0); SolidBrush brush(color); Pen pen(&brush, width);
ptsF[0].X = (REAL) pts[0].x; ptsF[0].Y = (REAL) pts[0].y; ptsF[1].X = (REAL) pts[1].x; ptsF[1].Y = (REAL) pts[1].y; ptsF[2].X = (REAL) pts[3].x; ptsF[2].Y = (REAL) pts[3].y; ptsF[3].X = (REAL) pts[2].x; ptsF[3].Y = (REAL) pts[2].y;
g->DrawWarpedLine(&pen, pt00, pt30, ptsF, 4, srcRect); g->DrawWarpedLine(&pen, pt10, pt20, ptsF, 4, srcRect); g->DrawWarpedBezier(&pen, bPts[0], bPts[1], bPts[2], bPts[3], ptsF, 4, srcRect); delete g; }
//
// Handle window repaint event
//
VOID DoPaint( HWND hwnd )
{ HDC hdc; PAINTSTRUCT ps; RECT rect; INT width, height;
// Determine if we need to perform warping operation
GetClientRect(hwnd, &rect); width = rect.right; height = rect.bottom;
hdc = BeginPaint(hwnd, &ps);
HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255)); HBRUSH savedBrush = (HBRUSH) SelectObject(hdc, brush); Rectangle(hdc, 0, 0, width, height);
DoGDIPlusDrawing(hwnd, hdc);
// Draw to offscreen DC to reduce flashing
DrawMesh(hdc); SelectObject(hdc, savedBrush); DeleteObject(brush);
EndPaint(hwnd, &ps); }
//
// Handle WM_SIZING message
//
BOOL DoWindowSizing( HWND hwnd, RECT* rect, INT side )
{ INT w = rect->right - rect->left - wndSizeExtra.cx; INT h = rect->bottom - rect->top - wndSizeExtra.cy;
if (w >= srcSize.cx && h >= srcSize.cy) return FALSE;
// Window width is too small
if (w < srcSize.cx) { INT dx = srcSize.cx + wndSizeExtra.cx;
switch (side) { case WMSZ_LEFT: case WMSZ_TOPLEFT: case WMSZ_BOTTOMLEFT: rect->left = rect->right - dx; break; default: rect->right = rect->left + dx; break; } }
// Window height is too small
if (h < srcSize.cy) { INT dy = srcSize.cy + wndSizeExtra.cy;
switch (side) { case WMSZ_TOP: case WMSZ_TOPLEFT: case WMSZ_TOPRIGHT: rect->top = rect->bottom - dy; break; default: rect->bottom = rect->top + dy; break; } }
return TRUE; }
//
// Handle left mouse-down event
//
VOID DoMouseDown( HWND hwnd, INT x, INT y )
{ // Figure out if the click happened in a mesh control knob
INT i, j, rows, cols; POINT pt; RECT rect;
GetClientRect(hwnd, &rect);
for(i = 0; i < 4; i++) { pt = pts[i]; pt.x -= knobSize/2; pt.y -= knobSize/2;
if (x >= pt.x && x < pt.x+knobSize && y >= pt.y && y < pt.y+knobSize) { index = i; SetCapture(hwnd); isDragging = TRUE; return; } }
index = -1;
}
//
// Handle mouse-move event
//
VOID DoMouseMove( HWND hwnd, INT x, INT y )
{ // We assume isDragging is true here.
RECT rect; INT w, h;
GetClientRect(hwnd, &rect); w = rect.right; h = rect.bottom;
if (x < 0 || x >= w || y < 0 || y >= h) return;
pts[index].x = x; pts[index].y = y;
if(index == 0) pts[4] = pts[0];
InvalidateRect(hwnd, NULL, FALSE); }
//
// Handle menu command
//
VOID DoCommand( HWND hwnd, INT command ) { InvalidateRect(hwnd, NULL, FALSE); }
//
// Handle popup menu
//
VOID DoPopupMenu( HWND hwnd, INT x, INT y ) { HMENU menu; DWORD result; POINT pt;
GetCursorPos(&pt); menu = LoadMenu(appInstance, MAKEINTRESOURCE(IDM_MAINMENU));
result = TrackPopupMenu( GetSubMenu(menu, 0), TPM_CENTERALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
if (result == 0) return;
DoCommand(hwnd, LOWORD(result)); }
//
// Window callback procedure
//
LRESULT CALLBACK MyWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{ INT x, y;
switch (uMsg) { case WM_PAINT:
DoPaint(hwnd); break;
case WM_LBUTTONDOWN:
if (showMesh) { x = (SHORT) LOWORD(lParam); y = (SHORT) HIWORD(lParam); DoMouseDown(hwnd, x, y); } break;
case WM_LBUTTONUP:
if (isDragging) { ReleaseCapture(); isDragging = FALSE; InvalidateRect(hwnd, NULL, FALSE); } break;
case WM_MOUSEMOVE:
if (isDragging) { x = (SHORT) LOWORD(lParam); y = (SHORT) HIWORD(lParam); DoMouseMove(hwnd, x, y); } break;
case WM_SIZING:
if (DoWindowSizing(hwnd, (RECT*) lParam, wParam)) return TRUE; else return DefWindowProc(hwnd, uMsg, wParam, lParam);
case WM_SIZE:
InvalidateRect(hwnd, NULL, FALSE); break;
case WM_CHAR:
switch ((CHAR) wParam) { case 'r': // reset
DoCommand(hwnd, IDC_RESETMESH); break;
case ' ': // show/hide mesh
DoCommand(hwnd, IDC_TOGGLEMESH); break;
case '1': // restore 1-to-1 scale
DoCommand(hwnd, IDC_SHRINKTOFIT); break; case '<': // decrease mesh density
DoCommand(hwnd, IDC_SPARSEMESH); break;
case '>': // increase mesh density
DoCommand(hwnd, IDC_DENSEMESH); break;
case 'f': // toggle live feedback
DoCommand(hwnd, IDC_LIVEFEEDBACK); break; }
break;
case WM_RBUTTONDOWN:
x = (SHORT) LOWORD(lParam); y = (SHORT) HIWORD(lParam); DoPopupMenu(hwnd, x, y); break;
case WM_DESTROY:
PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }
return 0; }
//
// Create main application window
//
VOID CreateMainWindow( VOID )
#define MYWNDCLASSNAME L"QuadTest"
{ //
// Register window class if necessary
//
static BOOL wndclassRegistered = FALSE;
if (!wndclassRegistered) { WNDCLASS wndClass = { 0, MyWindowProc, 0, 0, appInstance, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), NULL, NULL, MYWNDCLASSNAME };
RegisterClass(&wndClass); wndclassRegistered = TRUE; } wndSizeExtra.cx = 2*GetSystemMetrics(SM_CXSIZEFRAME); wndSizeExtra.cy = 2*GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
hwndMain = CreateWindow( MYWNDCLASSNAME, MYWNDCLASSNAME, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, srcSize.cx + wndSizeExtra.cx, srcSize.cy + wndSizeExtra.cy, NULL, NULL, appInstance, NULL); }
//
// Main program entrypoint
//
INT _cdecl main( INT argc, CHAR **argv )
{ programName = *argv++; argc--; appInstance = GetModuleHandle(NULL);
// Initialize mesh configuration
CreateMesh();
// Create the main application window
CreateMainWindow();
// Main message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam; }
|