home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / winnt / plgblt / plgblt.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  46KB  |  1,332 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1992-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /**************************************************************************\
  13. *  plgblt.c -- sample program demonstrating the new PlgBlt() API.
  14. *
  15. *  design:  There is one main window with one dialog box stretched to fill
  16. *   the top of it.  The parameters for the plgblt painted into the main
  17. *   window are stored in the entry fields of this dialog box.  The user
  18. *   may change these values and see the effect on the blt.
  19. \**************************************************************************/
  20.  
  21. #include <windows.h>
  22. #include <commdlg.h>
  23. #include <math.h>
  24. #include <stdio.h>
  25. #include "plgblt.h"
  26. #include "track.h"
  27. #include "bitmap.h"
  28.  
  29.  
  30.  
  31. /* global variables. */
  32. PTrackObject ptoDest, ptoSrc, ptoMask = NULL;
  33. HDC          hdcDest, hdcSrc, hdcMask;
  34. HBITMAP               hbmSrc, hbmMask = NULL;
  35.  
  36. HANDLE hInst;
  37. HWND   hwndMain, hwndDlg;
  38.  
  39. int nSpin;
  40.  
  41.  
  42. #define  BACKGROUNDBRUSH GetStockObject(LTGRAY_BRUSH)
  43.  
  44.  
  45.  
  46. /**************************************************************************\
  47. *
  48. *  function:  WinMain()
  49. *
  50. *  input parameters:  c.f. generic sample
  51. *
  52. \**************************************************************************/
  53. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  54.                      LPSTR lpCmdLine, int nCmdShow)
  55. {
  56.     MSG   msg;
  57.     RECT rect;
  58.     HANDLE haccel;
  59.  
  60.     UNREFERENCED_PARAMETER( lpCmdLine );
  61.  
  62.  
  63.     //
  64.     // Detect platform and exit gracefully if not Windows NT.
  65.     //
  66.  
  67.     {
  68.       OSVERSIONINFO osvi;
  69.       osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  70.  
  71.       GetVersionEx (&osvi);
  72.       if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  73.         MessageBox (NULL,
  74.           GetStringRes (IDS_NTONLY),
  75.           "PlgBlt", MB_OK | MB_ICONSTOP);
  76.         return 0;
  77.       }
  78.     }
  79.  
  80.  
  81.     /* Check for previous instance.  If none, then register class. */
  82.     if (!hPrevInstance) {
  83.         WNDCLASS  wc;
  84.  
  85.         wc.style = 0;
  86.         wc.lpfnWndProc = (WNDPROC)MainWndProc;
  87.  
  88.         wc.cbClsExtra = 0;
  89.         wc.cbWndExtra = 0;
  90.         wc.hInstance = hInstance;
  91.         wc.hIcon = LoadIcon(hInstance, "plgbltIcon");
  92.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  93.         wc.hbrBackground = BACKGROUNDBRUSH;
  94.         wc.lpszMenuName =  "plgbltMenu";
  95.         wc.lpszClassName = "plgblt";
  96.  
  97.         if (!RegisterClass(&wc)) return (FALSE);
  98.     }  /* class registered o.k. */
  99.  
  100.  
  101.     /* Create the main window.  Return false if CreateWindow() fails */
  102.     hInst = hInstance;
  103.  
  104.     hwndMain = CreateWindow(
  105.         "plgblt",
  106.         GetStringRes (IDS_WINDOWTITLE),
  107.         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  108.         CW_USEDEFAULT,
  109.         CW_USEDEFAULT,
  110.         CW_USEDEFAULT,
  111.         CW_USEDEFAULT,
  112.         NULL,
  113.         NULL,
  114.         hInstance,
  115.         NULL);
  116.  
  117.     if (!hwndMain) return (FALSE);
  118.  
  119.  
  120.     /* create the top dialog as a child of the main window. */
  121.     hwndDlg = CreateDialog (hInst, "plgbltDlg", hwndMain, (DLGPROC)DlgProc);
  122.  
  123.     /* Send main window a WM_SIZE message so that it will size the top
  124.      *  dialog correctly.
  125.      */
  126.     GetClientRect (hwndMain, &rect);
  127.     SendMessage (hwndMain, WM_SIZE, 0, (rect.right - rect.left));
  128.     ShowWindow (hwndDlg, SW_SHOW);
  129.     ShowWindow(hwndMain, nCmdShow);
  130.  
  131.  
  132.     /* get global handle to the menu */
  133.  
  134.     /* Load the accelerator table that provides clipboard support. */
  135.     haccel = LoadAccelerators (hInst, "bltAccel");
  136.  
  137.  
  138.  
  139.     /* Loop getting messages and dispatching them. */
  140.     while (GetMessage(&msg,NULL, 0,0)) {
  141.       if (!TranslateAccelerator(hwndMain, haccel, &msg))
  142.       if (!IsDialogMessage (hwndDlg, &msg)){
  143.         DispatchMessage(&msg);
  144.       }
  145.  
  146.       /* if no messages, and we are spinning, then post spin message. */
  147.       if (!PeekMessage (&msg, hwndMain, 0,0, PM_NOREMOVE) && nSpin)
  148.         PostMessage (hwndMain, WM_SPIN, 0,0);
  149.     }
  150.  
  151.     /* Return the value from PostQuitMessage */
  152.     return (msg.wParam);
  153. }
  154.  
  155.  
  156.  
  157.  
  158. /**************************************************************************\
  159. *
  160. *  function:  MainWndProc()
  161. *
  162. *  input parameters:  normal window procedure parameters.
  163. *
  164. *  There are 6 different HDCs used for the main window (in addition to the
  165. *   temporary one returned from BeginPaint).  There are two for each of the
  166. *   three thirds of the window.  The first one contains the bitmap.  The
  167. *   second one is for the track object and is stored in the TRACKOBJECT
  168. *   structure.
  169. *
  170. *  global variables:
  171. *   hwndDlg - dialog with entry fields containing parameters.
  172. *   ptoDest, ptoSrc, ptoMask - pointers to the direct manipulation objects
  173. *   hdcDest, hdcSrc, hdcMask - HDCs for the 3 sub regions of the window.
  174. *   hbmSrc, hbmMask          - bitmap handles for source and mask.
  175. \**************************************************************************/
  176. LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  177. {
  178. static int miniWidth;
  179. static RECT rect;
  180. static HANDLE hPenGrid, hPenSeparator;
  181.  
  182.   switch (message) {
  183.  
  184.     /**********************************************************************\
  185.     *  WM_CREATE
  186.     *
  187.     * Get three new HDCs, then create three new track objects.
  188.     *  Each track object has different allowed tracking modes.
  189.     *  Finally create two pens for drawing later on.
  190.     \**********************************************************************/
  191.     case WM_CREATE:
  192.         hdcSrc  = GetDC (hwnd);
  193.         hdcDest = GetDC (hwnd);
  194.         hdcMask = GetDC (hwnd);
  195.  
  196.         ptoDest = doTrackObject (NULL, TROB_NEW, hwnd,0);
  197.         ptoDest->allowedModes = TMALL;
  198.         ptoSrc  = doTrackObject (NULL, TROB_NEW, hwnd,0);
  199.         ptoSrc->allowedModes = TMMOVE | TMSIZEXY;
  200.         ptoMask = doTrackObject (NULL, TROB_NEW, hwnd,0);
  201.         ptoMask->allowedModes = TMMOVE;
  202.  
  203.         hPenGrid      = CreatePen (PS_SOLID, 1, GRIDCOLOR);
  204.         hPenSeparator = CreatePen (PS_SOLID, 2*SEPARATORWIDTH, (COLORREF) 0x01000000);
  205.  
  206.         { HMENU hMenu;
  207.         hMenu = GetMenu (hwnd);
  208.         CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_CHECKED);
  209.         CheckMenuItem(hMenu, IDM_SPINOFF    , MF_CHECKED);
  210.         nSpin = FALSE;
  211.         }
  212.  
  213.     break;
  214.  
  215.  
  216.     /**********************************************************************\
  217.     *  WM_DESTROY
  218.     *
  219.     * Complement of WM_CREATE.  Free up all of the HDCs, send all of the
  220.     *  track objects their delete messages, delete the pens,
  221.     *  then call PostQuitMessage.
  222.     \**********************************************************************/
  223.     case WM_DESTROY:
  224.         ReleaseDC (hwnd, hdcSrc );
  225.         ReleaseDC (hwnd, hdcDest);
  226.         ReleaseDC (hwnd, hdcMask);
  227.         doTrackObject (ptoDest, TROB_DELETE, hwnd,0);
  228.         doTrackObject (ptoSrc , TROB_DELETE, hwnd,0);
  229.         doTrackObject (ptoMask, TROB_DELETE, hwnd,0);
  230.  
  231.         DeleteObject(hPenGrid);
  232.         DeleteObject(hPenSeparator);
  233.  
  234.         PostQuitMessage(0);
  235.     break;
  236.  
  237.  
  238.  
  239.     /**********************************************************************\
  240.     *  WM_SIZE
  241.     *
  242.     * Stretch the top dialog to fill the width of the main window.
  243.     * Adjust the viewport origins of the 6 HDCs.
  244.     * Set the clip regions of the 6 HDCs.
  245.     \**********************************************************************/
  246.     case WM_SIZE: {
  247.         HRGN hrgn;
  248.  
  249.         SetWindowPos (hwndDlg, NULL, 0,0, LOWORD(lParam), DIALOGHEIGHT, 0);
  250.  
  251.         GetClientRect (hwndMain, &rect);
  252.         miniWidth = rect.right/3;
  253.  
  254.         SetViewportOrgEx (hdcDest,      0,           DIALOGHEIGHT, NULL);
  255.         SetViewportOrgEx (ptoDest->hdc, 0,           DIALOGHEIGHT, NULL);
  256.         SetViewportOrgEx (hdcSrc,       miniWidth,   DIALOGHEIGHT, NULL);
  257.         SetViewportOrgEx (ptoSrc->hdc,  miniWidth,   DIALOGHEIGHT, NULL);
  258.         SetViewportOrgEx (hdcMask,      2*miniWidth, DIALOGHEIGHT, NULL);
  259.         SetViewportOrgEx (ptoMask->hdc, 2*miniWidth, DIALOGHEIGHT, NULL);
  260.  
  261.         ptoDest->rectClip.left    = 0;
  262.         ptoDest->rectClip.top     = DIALOGHEIGHT;
  263.         ptoDest->rectClip.right   = miniWidth-2*SEPARATORWIDTH;
  264.         ptoDest->rectClip.bottom  = rect.bottom;
  265.         hrgn = CreateRectRgnIndirect (&ptoDest->rectClip);
  266.         SelectClipRgn (hdcDest,      hrgn);
  267.         SelectClipRgn (ptoDest->hdc, hrgn);
  268.         DeleteObject (hrgn);
  269.  
  270.         ptoSrc->rectClip.left    = miniWidth;
  271.         ptoSrc->rectClip.top     = DIALOGHEIGHT;
  272.         ptoSrc->rectClip.right   = 2*miniWidth-2*SEPARATORWIDTH;
  273.         ptoSrc->rectClip.bottom  = rect.bottom;
  274.         hrgn = CreateRectRgnIndirect (&ptoSrc->rectClip);
  275.         SelectClipRgn (hdcSrc,       hrgn);
  276.         SelectClipRgn (ptoSrc->hdc,  hrgn);
  277.         DeleteObject (hrgn);
  278.  
  279.         ptoMask->rectClip.left    = 2*miniWidth;
  280.         ptoMask->rectClip.top     = DIALOGHEIGHT;
  281.         ptoMask->rectClip.right   = 3*miniWidth;
  282.         ptoMask->rectClip.bottom  = rect.bottom;
  283.         hrgn = CreateRectRgnIndirect (&ptoMask->rectClip);
  284.         SelectClipRgn (hdcMask,      hrgn);
  285.         SelectClipRgn (ptoMask->hdc, hrgn);
  286.         DeleteObject (hrgn);
  287.  
  288.         SendMessage (hwndDlg, WM_PUTUPLPOINTS, (DWORD)hdcDest, (LONG)ptoDest);
  289.         SendMessage (hwndDlg, WM_PUTUPSRCRECT, (DWORD)hdcSrc,  (LONG)ptoSrc);
  290.         SendMessage (hwndDlg, WM_PUTUPMASKPT,  (DWORD)hdcMask, (LONG)ptoMask);
  291.  
  292.         /* repaint the whole window. */
  293.         InvalidateRect (hwnd, NULL, TRUE);
  294.     } break;
  295.  
  296.  
  297.  
  298.     /**********************************************************************\
  299.     *  WM_PAINT
  300.     *
  301.     * miniWidth, rect -- set by WM_SIZE message.
  302.     *
  303.     * First shift the viewport origin down so that 0,0 is the top left
  304.     *  most visible point (out from underneath the top dialog).  Second,
  305.     *  draw the grid with wider lines on the axes.  Finally, read the
  306.     *  values out of the top dialog, do elementary validation, and then
  307.     *  try to call plgblt() with the values.
  308.     \**********************************************************************/
  309.      case WM_PAINT: {
  310.         HDC hdc;
  311.         PAINTSTRUCT ps;
  312.  
  313.         hdc = BeginPaint(hwnd, &ps);
  314.  
  315.         /* Draw Separator lines for the three miniareas */
  316.         SelectObject(hdc, hPenSeparator);
  317.         MoveToEx (hdc,   miniWidth-SEPARATORWIDTH,0, NULL);
  318.         LineTo   (hdc,   miniWidth-SEPARATORWIDTH, rect.bottom);
  319.         MoveToEx (hdc, 2*miniWidth-SEPARATORWIDTH,0, NULL);
  320.         LineTo   (hdc, 2*miniWidth-SEPARATORWIDTH, rect.bottom);
  321.  
  322.         /* Grid the HDCs */
  323.         SelectObject(hdcSrc, hPenGrid);
  324.         DrawGrids (hdcSrc, miniWidth, rect.bottom);
  325.         SelectObject(hdcMask, hPenGrid);
  326.         DrawGrids (hdcMask, miniWidth, rect.bottom);
  327.  
  328.         /* Draw bitmaps if any, then draw track objects over them. */
  329.         if (hbmSrc)  DrawBitmap (hdcSrc, hbmSrc);
  330.         if (hbmMask) DrawBitmap (hdcMask, hbmMask);
  331.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  332.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  333.  
  334.         /* paint the left third of the window. */
  335.         SendMessage (hwnd, WM_PLGBLT, 0,0);
  336.  
  337.         EndPaint (hwnd, &ps);
  338.     } return FALSE;
  339.  
  340.  
  341.  
  342.     /**********************************************************************\
  343.     *  WM_PLGBLT
  344.     *
  345.     * WM_USER message.  This paints the left third of the window.  It
  346.     *  is called on the WM_PAINT message.  It is separated out here because
  347.     *  it is common for just the plgblt() to need to be called and not the
  348.     *  whole window painted.
  349.     \**********************************************************************/
  350.     case WM_PLGBLT: {
  351.         POINT lpPoint[3];
  352.         int XSrc, YSrc, nWidth, nHeight, XMask, YMask;
  353.         BOOL success;
  354.         RECT cliprect;
  355.  
  356.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  357.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  358.  
  359.         GetClipBox (hdcDest, &cliprect);
  360.         FillRect (hdcDest, &cliprect,
  361.                   (HBRUSH) GetClassLong (hwnd, GCL_HBRBACKGROUND));
  362.         SelectObject(hdcDest, hPenGrid);
  363.  
  364.         DrawGrids (hdcDest, miniWidth, rect.bottom);
  365.         if (IsWindow(hwndDlg)) {
  366.  
  367.           /* Grab points out of the dialog entry fields. */
  368.           lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  369.           lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  370.           lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  371.           lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  372.           lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  373.           lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  374.           XSrc = GetDlgItemInt(hwndDlg, DID_XSRC, &success, TRUE);
  375.           YSrc = GetDlgItemInt(hwndDlg, DID_YSRC, &success, TRUE);
  376.           nWidth = GetDlgItemInt(hwndDlg, DID_WIDTH, &success, TRUE);
  377.           nHeight = GetDlgItemInt(hwndDlg, DID_HEIGHT, &success, TRUE);
  378.           XMask = GetDlgItemInt(hwndDlg, DID_XMASK, &success, TRUE);
  379.           YMask = GetDlgItemInt(hwndDlg, DID_YMASK, &success, TRUE);
  380.  
  381.  
  382.           /**********************************************************/
  383.           /**********************************************************/
  384.           PlgBlt (hdcDest, lpPoint,
  385.                   hdcSrc, XSrc, YSrc, nWidth, nHeight,
  386.                   hbmMask, XMask, YMask);
  387.           /**********************************************************/
  388.           /**********************************************************/
  389.         }
  390.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  391.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  392.     } break;
  393.  
  394.  
  395.  
  396.     /**********************************************************************\
  397.     *  WM_LBUTTONDOWN & WM_RBUTTONDOWN
  398.     * On button down messages, hittest on the track object, and if
  399.     *  it returns true, then send these messages to the track object.
  400.     \**********************************************************************/
  401.     case WM_RBUTTONDOWN:
  402.     case WM_LBUTTONDOWN:
  403.       if (doTrackObject(ptoDest, TROB_HITTEST, hwnd, lParam))
  404.          doTrackObject(ptoDest, message, hwnd, lParam);
  405.       else if (doTrackObject(ptoSrc, TROB_HITTEST, hwnd, lParam))
  406.          doTrackObject(ptoSrc, message, hwnd, lParam);
  407.       else if (doTrackObject(ptoMask, TROB_HITTEST, hwnd, lParam))
  408.          doTrackObject(ptoMask, message, hwnd, lParam);
  409.     break;
  410.  
  411.  
  412.  
  413.     /**********************************************************************\
  414.     *  WM_LBUTTONUP & WM_RBUTTONDOWN & MW_MOUSEMOVE
  415.     * If the track object is in a "tracking mode" then send it these messages.
  416.     *  If the transform dialog is not minimized, fill it with numbers.
  417.     *  If the mouse dialog is not minimized, fill it with numbers.
  418.     \**********************************************************************/
  419.     case WM_RBUTTONUP:
  420.     case WM_LBUTTONUP:
  421.       /* user action complete.  Force plgblt() update. */
  422.       PostMessage (hwndMain, WM_PLGBLT, 0,0);
  423.     case WM_MOUSEMOVE:
  424.       if (ptoDest->Mode) {
  425.         doTrackObject(ptoDest, message, hwnd, lParam);
  426.         SendMessage (hwndDlg, WM_PUTUPLPOINTS, (DWORD) hdcDest, (LONG) ptoDest);
  427.       }
  428.       if (ptoSrc->Mode) {
  429.         doTrackObject(ptoSrc, message, hwnd, lParam);
  430.         SendMessage (hwndDlg, WM_PUTUPSRCRECT, (DWORD) hdcSrc, (LONG) ptoSrc);
  431.       }
  432.  
  433.       if (ptoMask->Mode) {
  434.         doTrackObject(ptoMask, message, hwnd, lParam);
  435.         SendMessage (hwndDlg, WM_PUTUPMASKPT, (DWORD) hdcMask, (LONG) ptoMask);
  436.       }
  437.  
  438.     break;
  439.  
  440.  
  441.  
  442.     /**********************************************************************\
  443.     *  WM_SETFOCUS
  444.     *
  445.     * The main window should never have the focus.  Set it back
  446.     *  to the top dialog.
  447.     \**********************************************************************/
  448.     case WM_SETFOCUS: SetFocus (hwndDlg);
  449.         return 0;
  450.  
  451.  
  452.  
  453.     /**********************************************************************\
  454.     *  Menu item support.
  455.     *
  456.     \**********************************************************************/
  457.     case WM_COMMAND:
  458.       switch (LOWORD(wParam)) {
  459.         HBITMAP hbmCompat, hbmOld;
  460.         HDC hdcCompat;
  461.  
  462.         /******************************************************************\
  463.         *  WM_COMMAND, IDM_COPY
  464.         *
  465.         * Create a new bitmap, copy the destination HDC bits into it,
  466.         *  and send the new bitmap to the clipboard.
  467.         \******************************************************************/
  468.         case IDM_COPY: {
  469.           int X[4],Y[4];
  470.           int nWidth, nHeight;
  471.           int Xmin, Ymin, Xmax, Ymax;
  472.           BOOL success;
  473.           int i;
  474.  
  475.           for (i = 0; i<3 ; i++) {
  476.             X[i] = GetDlgItemInt(hwndDlg, DID_P1X + 2*i, &success, TRUE);
  477.             Y[i] = GetDlgItemInt(hwndDlg, DID_P1Y + 2*i, &success, TRUE);
  478.           }
  479.  
  480.           X[3] = (X[1] - X[0]) + X[2];
  481.           Y[3] = (Y[2] - Y[0]) + Y[1];
  482.  
  483.           Xmin = Xmax = X[0];
  484.           Ymin = Ymax = Y[0];
  485.  
  486.           for (i = 1; i<4 ; i++) {
  487.             Xmin = (X[i] < Xmin) ? X[i] : Xmin;
  488.             Ymin = (Y[i] < Ymin) ? Y[i] : Ymin;
  489.             Xmax = (X[i] > Xmax) ? X[i] : Xmax;
  490.             Ymax = (Y[i] > Ymax) ? Y[i] : Ymax;
  491.           }
  492.  
  493.           nWidth = Xmax - Xmin;
  494.           nHeight = Ymax - Ymin;
  495.  
  496.           hdcCompat = CreateCompatibleDC(hdcDest);
  497.           hbmCompat = CreateCompatibleBitmap (hdcDest, nWidth, nHeight);
  498.           hbmOld = SelectObject(hdcCompat,hbmCompat);
  499.  
  500.           BitBlt (hdcCompat, 0,0,nWidth, nHeight, hdcDest, Xmin,Ymin, SRCCOPY );
  501.  
  502.           SelectObject(hdcCompat,hbmOld);
  503.           DeleteDC(hdcCompat);
  504.  
  505.           OpenClipboard (hwnd);
  506.           SetClipboardData (CF_BITMAP,hbmCompat);
  507.           CloseClipboard ();
  508.  
  509.           DeleteObject (hbmCompat);
  510.  
  511.         } break;
  512.  
  513.  
  514.         /******************************************************************\
  515.         *  WM_COMMAND, IDM_PASTE
  516.         *
  517.         * Get bitmap handle from clipboard, create a new bitmap, draw
  518.         *  the clipboard bitmap into the new one, and store the new
  519.         *  handle in the global hbmSrc.
  520.         \******************************************************************/
  521.         case IDM_PASTE: {
  522.           HBITMAP hbm;
  523.           BITMAP bm;
  524.  
  525.           OpenClipboard (hwnd);
  526.           if ( hbm = GetClipboardData (CF_BITMAP)) {
  527.             DeleteObject (hbmSrc);
  528.  
  529.             GetObject (hbm, sizeof(BITMAP), &bm);
  530.  
  531.             hdcCompat = CreateCompatibleDC(hdcDest);
  532.             hbmCompat = CreateCompatibleBitmap (hdcDest, bm.bmWidth, bm.bmHeight);
  533.             hbmOld = SelectObject(hdcCompat,hbmCompat);
  534.  
  535.             DrawBitmap (hdcCompat, hbm);
  536.  
  537.             SelectObject(hdcCompat,hbmOld);
  538.             DeleteDC(hdcCompat);
  539.  
  540.             hbmSrc = hbmCompat;
  541.  
  542.             InvalidateRect (hwnd, &ptoSrc->rectClip, TRUE);
  543.             InvalidateRect (hwnd, &ptoDest->rectClip, TRUE);
  544.           }
  545.           CloseClipboard ();
  546.         } break;
  547.  
  548.         /******************************************************************\
  549.         *  WM_COMMAND, IDM_BOTH
  550.         *
  551.         * Post a COPY and PASTE command message to this window so that with
  552.         *  one key stroke the user can copy the DEST image into the clipboard,
  553.         *  paste it down into the SRC hdc and cause the blt.
  554.         \******************************************************************/
  555.         case IDM_BOTH:
  556.  
  557.           PostMessage (hwnd, WM_COMMAND, MAKELONG (IDM_COPY , 1), 0);
  558.           PostMessage (hwnd, WM_COMMAND, MAKELONG (IDM_PASTE, 1), 0);
  559.  
  560.         break;
  561.  
  562.  
  563.  
  564.         /******************************************************************\
  565.         *  WM_COMMAND, IDM_MODE_*
  566.         *
  567.         * manage mutually exclusive menu.
  568.         *  call SetStretchBltMode() for the global destination hdc.
  569.         \******************************************************************/
  570.         case IDM_MODE_BLACKONWHITE:
  571.           { HMENU hMenu;
  572.           hMenu = GetMenu (hwnd);
  573.  
  574.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_CHECKED);
  575.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  576.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  577.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  578.  
  579.           SetStretchBltMode (hdcDest,BLACKONWHITE);
  580.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  581.  
  582.           } return 0;
  583.  
  584.         case IDM_MODE_COLORONCOLOR:
  585.           { HMENU hMenu;
  586.           hMenu = GetMenu (hwnd);
  587.  
  588.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  589.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_CHECKED);
  590.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  591.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  592.  
  593.           SetStretchBltMode (hdcDest,COLORONCOLOR);
  594.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  595.  
  596.           } return 0;
  597.  
  598.         case IDM_MODE_WHITEONBLACK:
  599.           { HMENU hMenu;
  600.           hMenu = GetMenu (hwnd);
  601.  
  602.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  603.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  604.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_CHECKED);
  605.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  606.  
  607.           SetStretchBltMode (hdcDest,WHITEONBLACK);
  608.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  609.  
  610.           } return 0;
  611.  
  612.         case IDM_MODE_HALFTONE    :
  613.           { HMENU hMenu;
  614.           hMenu = GetMenu (hwnd);
  615.  
  616.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  617.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  618.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  619.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_CHECKED);
  620.  
  621.           SetStretchBltMode (hdcDest,HALFTONE);
  622.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  623.  
  624.           } return 0;
  625.  
  626.  
  627.  
  628.  
  629.  
  630.         /******************************************************************\
  631.         *  WM_COMMAND, IDM_SPIN*
  632.         *
  633.         * manage mutually exclusive menu.
  634.         *
  635.         \******************************************************************/
  636.         case IDM_SPINOFF:
  637.           { HMENU hMenu;
  638.           hMenu = GetMenu (hwnd);
  639.  
  640.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_CHECKED);
  641.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  642.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  643.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  644.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  645.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  646.  
  647.           nSpin = FALSE;
  648.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  649.  
  650.           } return 0;
  651.  
  652.         case IDM_SPIN5 :
  653.           { HMENU hMenu;
  654.           hMenu = GetMenu (hwnd);
  655.  
  656.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  657.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_CHECKED);
  658.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  659.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  660.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  661.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  662.  
  663.           nSpin = 5;
  664.  
  665.           } return 0;
  666.  
  667.         case IDM_SPIN10:
  668.           { HMENU hMenu;
  669.           hMenu = GetMenu (hwnd);
  670.  
  671.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  672.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  673.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_CHECKED);
  674.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  675.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  676.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  677.  
  678.           nSpin = 10;
  679.  
  680.           } return 0;
  681.  
  682.         case IDM_SPIN30:
  683.           { HMENU hMenu;
  684.           hMenu = GetMenu (hwnd);
  685.  
  686.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  687.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  688.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  689.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_CHECKED);
  690.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  691.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  692.  
  693.           nSpin = 30;
  694.  
  695.           } return 0;
  696.  
  697.         case IDM_SPIN60:
  698.           { HMENU hMenu;
  699.           hMenu = GetMenu (hwnd);
  700.  
  701.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  702.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  703.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  704.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  705.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_CHECKED);
  706.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  707.  
  708.           nSpin = 60;
  709.  
  710.           } return 0;
  711.  
  712.         case IDM_SPIN90:
  713.           { HMENU hMenu;
  714.           hMenu = GetMenu (hwnd);
  715.  
  716.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  717.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  718.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  719.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  720.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  721.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_CHECKED);
  722.  
  723.           nSpin = 90;
  724.  
  725.           } return 0;
  726.  
  727.  
  728.         case IDM_FLIPONCE:
  729.           nSpin = 90;
  730.           SendMessage (hwndMain, WM_SPIN, 0,0);
  731.           nSpin = FALSE;
  732.           return 0;
  733.  
  734.  
  735.  
  736.         case IDM_SPINTOPLEFT:
  737.           { HMENU hMenu;
  738.           hMenu = GetMenu (hwnd);
  739.  
  740.           CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_CHECKED);
  741.           CheckMenuItem(hMenu, IDM_SPINCENTER , MF_UNCHECKED);
  742.  
  743.           } return 0;
  744.  
  745.         case IDM_SPINCENTER:
  746.           { HMENU hMenu;
  747.           hMenu = GetMenu (hwnd);
  748.  
  749.           CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_UNCHECKED);
  750.           CheckMenuItem(hMenu, IDM_SPINCENTER , MF_CHECKED);
  751.  
  752.           } return 0;
  753.  
  754.  
  755.         /******************************************************************\
  756.         *  WM_COMMAND, DID_NEW*
  757.         *
  758.         * menu equivalents for buttons on top dialog.  Just pass along
  759.         *  WM_COMMAND messages to the dialog.
  760.         *
  761.         \******************************************************************/
  762.         case DID_NEWSRC:
  763.         case DID_NEWMASK:
  764.           SendMessage (hwndDlg, message, wParam, lParam);
  765.         return 0;
  766.  
  767.  
  768.         /******************************************************************\
  769.         *  WM_COMMAND, IDM_ABOUT
  770.         *
  771.         \******************************************************************/
  772.         case IDM_ABOUT:
  773.           DialogBox (hInst, "aboutBox", hwnd, (DLGPROC)About);
  774.         return 0;
  775.  
  776.  
  777.  
  778.  
  779.       }  /* end switch */
  780.  
  781.     break;  /* end wm_command */
  782.  
  783.  
  784.  
  785.     /******************************************************************\
  786.     *  WM_SPIN
  787.     *
  788.     * Set up a transform to modify the destination points.
  789.     *  (Note that the transform in hdcDest remains the identity.)
  790.     *  Loop through, reblitting to the transformed points.
  791.     *  Erase behind the old bitmap by keeping track of the region uncovered.
  792.     *
  793.     \******************************************************************/
  794.     case WM_SPIN: {
  795.  
  796.       XFORM  x;
  797.       HDC hdc;
  798.       float M11, M12, M21, M22;
  799.       int nSteps, i;
  800.  
  801.       POINT pivot;
  802.       POINT lpPoint[3];
  803.       POINT lpRgnErase[4], lpRgnBmp[4];
  804.       HRGN hrgnErase, hrgnBmp;
  805.       HMENU hMenu;
  806.       int XSrc, YSrc, nWidth, nHeight, XMask, YMask;
  807.       BOOL success;
  808.  
  809.       /* validate the dialog on top with the parameters in it. */
  810.       if (!IsWindow(hwndDlg)) return 0;
  811.  
  812.       /* Grab points out of the dialog entry fields. */
  813.       lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  814.       lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  815.       lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  816.       lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  817.       lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  818.       lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  819.       XSrc = GetDlgItemInt(hwndDlg, DID_XSRC, &success, TRUE);
  820.       YSrc = GetDlgItemInt(hwndDlg, DID_YSRC, &success, TRUE);
  821.       nWidth = GetDlgItemInt(hwndDlg, DID_WIDTH, &success, TRUE);
  822.       nHeight = GetDlgItemInt(hwndDlg, DID_HEIGHT, &success, TRUE);
  823.       XMask = GetDlgItemInt(hwndDlg, DID_XMASK, &success, TRUE);
  824.       YMask = GetDlgItemInt(hwndDlg, DID_YMASK, &success, TRUE);
  825.  
  826.  
  827.       /* get an HDC we can use to play with transforms. */
  828.       hdc = GetDC (hwnd);
  829.       SetGraphicsMode (hdc, GM_ADVANCED);
  830.  
  831.  
  832.  
  833.       /* check menu check to pivot on top-left corner, or pivot on center. */
  834.       hMenu = GetMenu (hwnd);
  835.  
  836.       if (GetMenuState(hMenu, IDM_SPINCENTER, MF_BYCOMMAND) & MF_CHECKED) {
  837.         pivot.x = (lpPoint[1].x +lpPoint[2].x)/2;
  838.         pivot.y = (lpPoint[1].y +lpPoint[2].y)/2;
  839.       } else {
  840.         pivot.x = lpPoint[0].x;
  841.         pivot.y = lpPoint[0].y;
  842.       }
  843.  
  844.       /* nSpin contains values reflecting the number of degrees per step.
  845.        *  fill in the number of steps required (360 / nSpin), and fill in
  846.        *  the precomputed transformation matrices.
  847.        */
  848.       switch (nSpin) {
  849.  
  850.         case 5:
  851.           nSteps = 72;
  852.           M11 =                   M22 = (float)0.9961946980917;
  853.           M12 = (float)-0.08715574274766; M21 = (float)0.08715574274766;
  854.           break;
  855.         case 10:
  856.           nSteps = 36;
  857.           M11 =                   M22 = (float)0.984808;
  858.           M12 = (float)-0.173648; M21 = (float)0.173648;
  859.           break;
  860.         case 30:
  861.           nSteps = 12;
  862.           M11 =                   M22 = (float)0.866025;
  863.           M12 = (float)-0.5     ; M21 = (float)0.5;
  864.           break;
  865.         case 60:
  866.           nSteps = 6;
  867.           M11 =                   M22 = (float)0.5     ;
  868.           M12 = (float)-0.866025; M21 = (float)0.866025;
  869.           break;
  870.         case 90:
  871.           nSteps = 4;
  872.           M11 =                   M22 = (float)0.0;
  873.           M12 = (float)-1.0     ; M21 = (float)1.0;
  874.           break;
  875.         default:
  876.           MessageBox (hwnd,
  877.                       GetStringRes (IDS_INVALID),
  878.                       NULL, MB_ICONHAND);
  879.           return 0;
  880.  
  881.       } /* end switch nSpin */
  882.  
  883.  
  884.  
  885.  
  886.       /* translate objects from pivot point to origin. */
  887.       x.eM11 = (float)1.0;
  888.       x.eM12 = (float)0.0;
  889.       x.eM21 = (float)0.0;
  890.       x.eM22 = (float)1.0;
  891.       x.eDx = (float)-pivot.x;
  892.       x.eDy = (float)-pivot.y;
  893.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  894.  
  895.       /* rotate object about origin. */
  896.       x.eM11 = M11;
  897.       x.eM12 = M12;
  898.       x.eM21 = M21;
  899.       x.eM22 = M22;
  900.       x.eDx = (float)0.0;
  901.       x.eDy = (float)0.0;
  902.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  903.  
  904.       /* translate objects back to pivot point. */
  905.       x.eM11 = (float)1.0;
  906.       x.eM12 = (float)0.0;
  907.       x.eM21 = (float)0.0;
  908.       x.eM22 = (float)1.0;
  909.       x.eDx = (float)pivot.x;
  910.       x.eDy = (float)pivot.y;
  911.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  912.  
  913.  
  914.  
  915.       /* fill in initial region for erasure... the region containing bmp */
  916.       lpRgnErase[0] = lpPoint[0];
  917.       lpRgnErase[1] = lpPoint[1];
  918.       lpRgnErase[3] = lpPoint[2];
  919.       lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  920.       lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  921.       lpRgnErase[2].x += lpPoint[0].x;
  922.       lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  923.       lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  924.       lpRgnErase[2].y += lpPoint[0].y;
  925.  
  926.  
  927.  
  928.       /* loop through transforming the points on each step. */
  929.       for (i= 0; i<nSteps; i++) {
  930.  
  931.  
  932.         hrgnErase = CreatePolygonRgn (lpRgnErase, 4, ALTERNATE);
  933.  
  934.         /* TRANSFORM the lpPoint[] destination extent points */
  935.         LPtoDP (hdc, lpPoint, 3);
  936.  
  937.         /* create a region containing the new bitmap extents */
  938.         lpRgnBmp[0] = lpPoint[0];
  939.         lpRgnBmp[1] = lpPoint[1];
  940.         lpRgnBmp[3] = lpPoint[2];
  941.         lpRgnBmp[2].x =  lpPoint[1].x - lpPoint[0].x;
  942.         lpRgnBmp[2].x += lpPoint[2].x - lpPoint[0].x;
  943.         lpRgnBmp[2].x += lpPoint[0].x;
  944.         lpRgnBmp[2].y =  lpPoint[1].y - lpPoint[0].y;
  945.         lpRgnBmp[2].y += lpPoint[2].y - lpPoint[0].y;
  946.         lpRgnBmp[2].y += lpPoint[0].y;
  947.         hrgnBmp = CreatePolygonRgn (lpRgnBmp, 4, ALTERNATE);
  948.  
  949.         /* subtract the new bitmap extents region from the erasure region. */
  950.         CombineRgn (hrgnErase, hrgnErase, hrgnBmp, RGN_DIFF);
  951.  
  952.  
  953.  
  954.         /* while we are here, get points ready for the next loop erasure */
  955.         lpRgnErase[0] = lpPoint[0];
  956.         lpRgnErase[1] = lpPoint[1];
  957.         lpRgnErase[3] = lpPoint[2];
  958.         lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  959.         lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  960.         lpRgnErase[2].x += lpPoint[0].x;
  961.         lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  962.         lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  963.         lpRgnErase[2].y += lpPoint[0].y;
  964.  
  965.  
  966.  
  967.         /**********************************************************/
  968.         PlgBlt (hdcDest, lpPoint,
  969.                 hdcSrc, XSrc, YSrc, nWidth, nHeight,
  970.                 hbmMask, XMask, YMask);
  971.         /**********************************************************/
  972.  
  973.         /* need to flush graphics buffer, or regions are erased
  974.          *  before the bitmap is drawn.
  975.          */
  976.         GdiFlush();
  977.  
  978.         /* erase the newly uncovered region. */
  979.         FillRgn (hdcDest, hrgnErase, BACKGROUNDBRUSH );
  980.         DeleteObject (hrgnErase);
  981.         DeleteObject (hrgnBmp);
  982.       } /* end for loop */
  983.  
  984.  
  985.       /* because of roundoff error, the 'nSteps'th rotation will not
  986.        *  always bring the parallelogram around to the 0th position.
  987.        *  So we special case the last position, and do one more erase.
  988.        *  Try commenting this out, and see the little glitches left
  989.        *  on the screen if this comment is unclear.
  990.        */
  991.       lpRgnErase[0] = lpPoint[0];
  992.       lpRgnErase[1] = lpPoint[1];
  993.       lpRgnErase[3] = lpPoint[2];
  994.       lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  995.       lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  996.       lpRgnErase[2].x += lpPoint[0].x;
  997.       lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  998.       lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  999.       lpRgnErase[2].y += lpPoint[0].y;
  1000.       hrgnErase = CreatePolygonRgn (lpRgnErase, 4, ALTERNATE);
  1001.       lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  1002.       lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  1003.       lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  1004.       lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  1005.       lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  1006.       lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  1007.       lpRgnBmp[0] = lpPoint[0];
  1008.       lpRgnBmp[1] = lpPoint[1];
  1009.       lpRgnBmp[3] = lpPoint[2];
  1010.       lpRgnBmp[2].x =  lpPoint[1].x - lpPoint[0].x;
  1011.       lpRgnBmp[2].x += lpPoint[2].x - lpPoint[0].x;
  1012.       lpRgnBmp[2].x += lpPoint[0].x;
  1013.       lpRgnBmp[2].y =  lpPoint[1].y - lpPoint[0].y;
  1014.       lpRgnBmp[2].y += lpPoint[2].y - lpPoint[0].y;
  1015.       lpRgnBmp[2].y += lpPoint[0].y;
  1016.       hrgnBmp = CreatePolygonRgn (lpRgnBmp, 4, ALTERNATE);
  1017.       CombineRgn (hrgnErase, hrgnErase, hrgnBmp, RGN_DIFF);
  1018.       FillRgn (hdcDest, hrgnErase, BACKGROUNDBRUSH );
  1019.       DeleteObject (hrgnErase);
  1020.       DeleteObject (hrgnBmp);
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.       ReleaseDC (hwnd, hdc);
  1029.  
  1030.  
  1031.     } return 0; /* end WM_SPIN message */
  1032.  
  1033.  
  1034.   } /* end switch */
  1035.   return (DefWindowProc(hwnd, message, wParam, lParam));
  1036. }
  1037.  
  1038.  
  1039.  
  1040.  
  1041. /**************************************************************************\
  1042. *
  1043. *  function:  DlgProc()
  1044. *
  1045. *  input parameters:  normal window procedure parameters.
  1046. *
  1047. *  Respond to user button presses by getting new bitmaps or by sending
  1048. *   the main window a WM_PLGBLT message.  Also handle special user messages
  1049. *   for updating the entry fields with the contents of the direct manipulation
  1050. *   objects.
  1051. *
  1052. *  global variables:
  1053. *   hwndMain - the main window.  also the parent of this dialog
  1054. *   ptoDest, ptoSrc, ptoMask - pointers to the direct manipulation objects
  1055. *   hdcDest, hdcSrc, hdcMask - HDCs for the 3 sub regions of the window.
  1056. *   hbmSrc, hbmMask          - bitmap handles for source and mask.
  1057. \**************************************************************************/
  1058. LRESULT CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1059. {
  1060.  
  1061.   switch (message) {
  1062.     /**********************************************************************\
  1063.     *  WM_INITDIALOG
  1064.     *
  1065.     * Fill the entry fields with sensible original values.
  1066.     \**********************************************************************/
  1067.     case WM_INITDIALOG:
  1068.         SetDlgItemText(hwnd, DID_P1X     , "0");
  1069.         SetDlgItemText(hwnd, DID_P1Y     , "0");
  1070.         SetDlgItemText(hwnd, DID_P2X     , "0");
  1071.         SetDlgItemText(hwnd, DID_P2Y     , "0");
  1072.         SetDlgItemText(hwnd, DID_P3X     , "0");
  1073.         SetDlgItemText(hwnd, DID_P3Y     , "0");
  1074.         SetDlgItemText(hwnd, DID_XSRC    , "0");
  1075.         SetDlgItemText(hwnd, DID_YSRC    , "0");
  1076.         SetDlgItemText(hwnd, DID_WIDTH   , "0");
  1077.         SetDlgItemText(hwnd, DID_HEIGHT  , "0");
  1078.         SetDlgItemText(hwnd, DID_XMASK   , "0");
  1079.         SetDlgItemText(hwnd, DID_YMASK   , "0");
  1080.     return TRUE;
  1081.  
  1082.  
  1083.  
  1084.     /**********************************************************************\
  1085.     *  WM_PUTUPLPOINTS
  1086.     *
  1087.     * wParam -  HDC with the needed world transform.
  1088.     * lParam -  Pointer to the track object.
  1089.     *
  1090.     * Fill the entry fields for the array of 3 dest parallelogram points.
  1091.     *  Conditionally change the first point depending on tracking mode.
  1092.     \**********************************************************************/
  1093.     case WM_PUTUPLPOINTS: {
  1094.         POINT p, origin;
  1095.         PTrackObject pto;
  1096.         HDC hdc;
  1097.  
  1098.         hdc = (HDC) wParam;
  1099.         pto = (PTrackObject) lParam;
  1100.         GetViewportOrgEx (hdc, &origin);
  1101.  
  1102.         if (pto->Mode & TMMOVE) {
  1103.           p.x = pto->rect.left;
  1104.           p.y = pto->rect.top;
  1105.           LPtoDP (pto->hdc, &p, 1);
  1106.           p.x -= origin.x; p.y -= origin.y;
  1107.  
  1108.           SetDlgItemInt(hwnd, DID_P1X, p.x, TRUE);
  1109.           SetDlgItemInt(hwnd, DID_P1Y, p.y, TRUE);
  1110.  
  1111.         }
  1112.  
  1113.         p.x = pto->rect.right;
  1114.         p.y = pto->rect.top;
  1115.         LPtoDP (pto->hdc, &p, 1);
  1116.         p.x -= origin.x; p.y -= origin.y;
  1117.  
  1118.         SetDlgItemInt(hwnd, DID_P2X, p.x, TRUE);
  1119.         SetDlgItemInt(hwnd, DID_P2Y, p.y, TRUE);
  1120.  
  1121.         p.x = pto->rect.left;
  1122.         p.y = pto->rect.bottom;
  1123.         LPtoDP (pto->hdc, &p, 1);
  1124.         p.x -= origin.x; p.y -= origin.y;
  1125.         SetDlgItemInt(hwnd, DID_P3X, p.x, TRUE);
  1126.         SetDlgItemInt(hwnd, DID_P3Y, p.y, TRUE);
  1127.  
  1128.     } return FALSE;
  1129.  
  1130.  
  1131.  
  1132.  
  1133.     /**********************************************************************\
  1134.     *  WM_PUTUPSRCRECT
  1135.     *
  1136.     * wParam -  HDC with the needed world transform.
  1137.     * lParam -  Pointer to the track object.
  1138.     *
  1139.     * Fill the entry fields for the source rectangle points.
  1140.     *  Conditionally change <x,y> or <width,height> depending on tracking mode.
  1141.     \**********************************************************************/
  1142.     case WM_PUTUPSRCRECT: {
  1143.         POINT p1,p2, origin;
  1144.         PTrackObject pto;
  1145.         HDC hdc;
  1146.  
  1147.         hdc = (HDC) wParam;
  1148.         pto = (PTrackObject) lParam;
  1149.         GetViewportOrgEx (hdc, &origin);
  1150.  
  1151.         p1.x = pto->rect.left;
  1152.         p1.y = pto->rect.top;
  1153.         LPtoDP (pto->hdc, &p1, 1);
  1154.  
  1155.         p2.x = pto->rect.right;
  1156.         p2.y = pto->rect.bottom;
  1157.         LPtoDP (pto->hdc, &p2, 1);
  1158.         p2.x -= p1.x; p2.y -= p1.y;
  1159.  
  1160.         p1.x -= origin.x; p1.y -= origin.y;
  1161.  
  1162.         if (!(pto->Mode & TMSIZEXY)) {
  1163.           SetDlgItemInt(hwnd, DID_XSRC, p1.x, TRUE);
  1164.           SetDlgItemInt(hwnd, DID_YSRC, p1.y, TRUE);
  1165.         }
  1166.  
  1167.         if (!(pto->Mode & TMMOVE)) {
  1168.           SetDlgItemInt(hwnd, DID_WIDTH,  p2.x, TRUE);
  1169.           SetDlgItemInt(hwnd, DID_HEIGHT, p2.y, TRUE);
  1170.         }
  1171.     } return FALSE;
  1172.  
  1173.  
  1174.  
  1175.     /**********************************************************************\
  1176.     *  WM_PUTUPMASKPT
  1177.     *
  1178.     * wParam -  HDC with the needed world transform.
  1179.     * lParam -  Pointer to the track object.
  1180.     *
  1181.     * Fill the entry fields for the mask location point.
  1182.     \**********************************************************************/
  1183.     case WM_PUTUPMASKPT: {
  1184.         POINT p1, origin;
  1185.         PTrackObject pto;
  1186.         HDC hdc;
  1187.  
  1188.         hdc = (HDC) wParam;
  1189.         pto = (PTrackObject) lParam;
  1190.         GetViewportOrgEx (hdc, &origin);
  1191.  
  1192.         p1.x = pto->rect.left;
  1193.         p1.y = pto->rect.top;
  1194.         LPtoDP (pto->hdc, &p1, 1);
  1195.         p1.x -= origin.x; p1.y -= origin.y;
  1196.  
  1197.         SetDlgItemInt(hwnd, DID_XMASK, p1.x, TRUE);
  1198.         SetDlgItemInt(hwnd, DID_YMASK, p1.y, TRUE);
  1199.  
  1200.     } return FALSE;
  1201.  
  1202.  
  1203.  
  1204.  
  1205.     /**********************************************************************\
  1206.     *  WM_COMMAND, DID_DRAW
  1207.     *
  1208.     * Draw button hit - send main window message to call PlgBlt().
  1209.     \**********************************************************************/
  1210.     case WM_COMMAND: {
  1211.       HBITMAP hbm;
  1212.  
  1213.       if (LOWORD(wParam) == DID_DRAW) {
  1214.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  1215.  
  1216.  
  1217.     /**********************************************************************\
  1218.     *  WM_COMMAND, DID_NEWSRC
  1219.     *
  1220.     * Try to get a new source bitmap.  Then
  1221.     *  invalidate two sub windows so that we force a repaint.
  1222.     \**********************************************************************/
  1223.       } else if (LOWORD(wParam) == DID_NEWSRC) {
  1224.         if ( hbm = GetBitmap (hdcSrc, hInst, FALSE)) {
  1225.           DeleteObject (hbmSrc);
  1226.           hbmSrc = hbm;
  1227.           InvalidateRect (hwndMain, &ptoSrc->rectClip, TRUE);
  1228.           InvalidateRect (hwndMain, &ptoDest->rectClip, TRUE);
  1229.         }
  1230.  
  1231.     /**********************************************************************\
  1232.     *  WM_COMMAND, DID_Mask
  1233.     *
  1234.     * Try to get a new mask bitmap.  Then
  1235.     *  invalidate two sub windows so that we force a repaint.
  1236.     \**********************************************************************/
  1237.       } else if (LOWORD(wParam) == DID_NEWMASK) {
  1238.         if ( hbm = GetBitmap (hdcMask,  hInst, TRUE)) {
  1239.           DeleteObject (hbmMask);
  1240.           hbmMask = hbm;
  1241.           InvalidateRect (hwndMain, &ptoMask->rectClip, TRUE);
  1242.           InvalidateRect (hwndMain, &ptoDest->rectClip, TRUE);
  1243.         }
  1244.       }
  1245.  
  1246.     } return FALSE; /* end WM_COMMAND */
  1247.  
  1248.  
  1249.   } /* end switch */
  1250.   return 0;
  1251. }
  1252.  
  1253.  
  1254.  
  1255. #define TICKSPACE     20
  1256.  
  1257. /**************************************************************************\
  1258. *
  1259. *  function:  DrawGrids()
  1260. *
  1261. *  input parameters:
  1262. *   hdc - Device context to draw into.
  1263. *   width, height - size of the rectangle to fill with grids.
  1264. *
  1265. *  global variables:  none.
  1266. *
  1267. \**************************************************************************/
  1268. VOID DrawGrids (HDC hdc, int width, int height)
  1269. {
  1270. int i;
  1271.  
  1272.     /* Draw vertical lines. Double at the axis */
  1273.     for (i = 0; i<= width; i+=TICKSPACE){
  1274.       MoveToEx (hdc, i, 0, NULL);
  1275.       LineTo (hdc, i, height);
  1276.     }
  1277.     MoveToEx (hdc, 1, 0, NULL);
  1278.     LineTo (hdc, 1, height);
  1279.  
  1280.     /* Draw horizontal lines. Double at the axis */
  1281.     for (i = 0; i<= height; i+=TICKSPACE){
  1282.       MoveToEx (hdc, 0,i, NULL);
  1283.       LineTo (hdc, width,i);
  1284.     }
  1285.     MoveToEx (hdc, 0, 1, NULL);
  1286.     LineTo (hdc, width,1);
  1287.  
  1288.   return;
  1289. }
  1290.  
  1291.  
  1292.  
  1293.  
  1294. /****************************************************************************
  1295.     FUNCTION: About
  1296. ****************************************************************************/
  1297. LRESULT CALLBACK About(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1298. {
  1299.   if ((message == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
  1300.     EndDialog (hwnd, TRUE);
  1301.     return TRUE;
  1302.   }
  1303.   if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE)) {
  1304.     EndDialog (hwnd, TRUE);
  1305.     return TRUE;
  1306.   }
  1307.   return FALSE;
  1308. }
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314. /******************************************************************************\
  1315. *
  1316. *  FUNCTION:    GetStringRes (int id INPUT ONLY)
  1317. *
  1318. *  COMMENTS:    Load the resource string with the ID given, and return a
  1319. *               pointer to it.  Notice that the buffer is common memory so
  1320. *               the string must be used before this call is made a second time.
  1321. *
  1322. \******************************************************************************/
  1323.  
  1324. LPTSTR   GetStringRes (int id)
  1325. {
  1326.   static TCHAR buffer[MAX_PATH];
  1327.  
  1328.   buffer[0]=0;
  1329.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  1330.   return buffer;
  1331. }
  1332.