home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / tk3 / fatpel / fatpel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-20  |  64.0 KB  |  2,630 lines

  1. /************************************************************************
  2. *
  3. *   fatpel.c -- The Diamond Metric, Theory vs. Practice
  4. *
  5. *   Created by Microsoft Corporation, 1989
  6. *
  7. ************************************************************************/
  8.  
  9. #define INCL_WINFRAMEMGR
  10. #define INCL_WINWINDOWMGR
  11. #define INCL_WINMESSAGEMGR
  12. #define    INCL_WINPOINTERS
  13. #define INCL_WINSWITCHLIST
  14. #define INCL_WINTRACKRECT
  15. #define INCL_WINDIALOGS
  16. #define INCL_WINBUTTONS
  17. #define INCL_GPILOGCOLORTABLE
  18. #define INCL_GPIBITMAPS
  19. #define    INCL_GPITRANSFORMS
  20. #define INCL_DOSMEMMGR
  21. #define INCL_DOSFILEMGR
  22. #define INCL_BITMAPFILEFORMAT
  23. #define INCL_GPIPRIMITIVES
  24. #define INCL_WINMENUS
  25. #define INCL_GPIREGIONS
  26. #define INCL_WINPOINTERS
  27. #define INCL_WININPUT
  28. #include <os2.h>
  29.  
  30. #include <mt\stdio.h>
  31. #include <mt\stdlib.h>
  32. #include <mt\string.h>
  33.  
  34. #include "opendlg.h"
  35. #include "fatpel.h"
  36.  
  37.  
  38.  
  39.  
  40. /************************************************************************
  41. *
  42. *   Function declarations
  43. *
  44. ************************************************************************/
  45.  
  46. /* Private functions */
  47.  
  48. VOID  cdecl main(VOID);
  49. BOOL  FAR InitGlobals(VOID);
  50. BOOL  FAR InitApp(VOID);
  51. VOID  Close(HWND);
  52. VOID  Command(HWND, USHORT);
  53. VOID  Paint(HPS, USHORT);
  54. VOID  EraseBackground(HPS);
  55. VOID  DrawGrid(HPS);
  56. VOID  DisplayRenderedPels(HPS, USHORT);
  57. VOID  DisplayControlPoints(HPS, LONG, PPOINTL, USHORT);
  58. VOID  DisplayMathematicalObject(HPS, USHORT);
  59. VOID  DrawFatPels(HPS);
  60. VOID  DrawOneFatPel(HPS, PPOINTL, COLOR);
  61. VOID  GetFatPelFromPt(PPOINTL, PPOINTL);
  62. VOID  SetFatPel(PPOINTL, COLOR);
  63. VOID  RoundControlPoints(HPS, LONG, PPOINTL, PPOINTL, LONG, LONG);
  64. VOID  ComputeTransform(PRECTL, PRECTL);
  65. VOID  DrawPrimitive(HPS, LONG, PPOINTL);
  66. VOID  UpdateSurfaceDims(VOID);
  67. VOID  MySetWindowLong    (HWND, USHORT, LONG);
  68. VOID  MySetWindowLongHex(HWND, USHORT, LONG);
  69. LONG  MyGetWindowLong    (HWND, USHORT);
  70. VOID  MouseMove(HWND, MPARAM);
  71. VOID  ButtonUp(HWND, USHORT);
  72. VOID  ButtonDown(HWND, USHORT, MPARAM);
  73. VOID  DragPelSize(HWND, POINTS);
  74. VOID  WriteFile(HWND, HPS);
  75. BOOL  WriteBMP(HFILE, HPS, PBITMAPINFOHEADER);
  76. VOID  MyMessageBox(HWND, PSZ);
  77. VOID  SaveWindowToFile(HWND);
  78. SHORT IsPtInList(PPOINTL);
  79. SHORT AddPtToList(PPOINTL);
  80. BOOL  IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
  81. VOID  SwapLong(PLONG, PLONG);
  82.  
  83.  
  84. /* Exported functions */
  85.  
  86. ULONG CALLBACK WndProc     (HWND, USHORT, MPARAM, MPARAM);
  87. ULONG CALLBACK AboutDlg  (HWND, USHORT, MPARAM, MPARAM);
  88. ULONG CALLBACK ColorsDlg (HWND, USHORT, MPARAM, MPARAM);
  89. ULONG CALLBACK PelSizeDlg(HWND, USHORT, MPARAM, MPARAM);
  90.  
  91.  
  92.  
  93.  
  94. /************************************************************************
  95. *
  96. *   Global Variables
  97. *
  98. ************************************************************************/
  99.  
  100. /* compute absolute value for arbitrary (in my case, LONG) number */
  101. /* this is to avoid compiler warnings about data conversion */
  102. #define L_ABS(x)    (((x) > 0) ? (x) : (-(x)))
  103.  
  104. typedef struct
  105. {
  106.     HAB      hab;
  107.     HMQ      hMsgQ;
  108.     HWND     hwndFrame;
  109.     HWND     hwnd;
  110.  
  111.     BOOL     fFirstTime;   /* TRUE --> first time initialization of rcl */
  112.     RECTL    rcl;       /* dimensions of client rectangle */
  113.  
  114.     HPS      hpsFat;
  115.     HDC      hdcFat;
  116.     HBITMAP  hbmFat;
  117.     HPS      hpsFatShadow;
  118.     HDC      hdcFatShadow;
  119.     HBITMAP  hbmFatShadow;
  120.  
  121.     RECTL    rclFatBM;       /* dimensions of fatbits bitmap */
  122.     RECTL    rclFat;       /* dimensions of active fat bits grid */
  123.     LONG     cxFatPel;        /* width of fat pel */
  124.     LONG     cyFatPel;        /* height of fat pel */
  125.     LONG     cxHalfFatPel;
  126.     LONG     cyHalfFatPel;
  127.     USHORT   usPelShape;
  128.  
  129.     MATRIXLF matlf;    /* goes from window coords to fatpel coords */
  130.  
  131.     BOOL     fRGB;       /* TRUE --> color mode is RGB */
  132.     COLOR    clrMathObj;
  133.     COLOR    clrRenderedObj;
  134.     COLOR    clrField;
  135.     COLOR    clrCrossHair;
  136.     COLOR    clrInterstice;
  137.     COLOR    clrControlPoints;
  138.  
  139.     COLOR    clrBlackIndex;
  140.     COLOR    clrEditPel;
  141.  
  142.     USHORT   usControlPointSymbol;
  143.  
  144.     BOOL     fDisplayRenderedObj;
  145.     BOOL     fDisplayMathObj;
  146.     BOOL     fDisplayControlPoints;
  147.     BOOL     fDisplayCrossHairs;
  148.     BOOL     fDisplayPelBorder;
  149.     BOOL     fRoundControlPoints;
  150.     BOOL     fAutoRedraw;
  151.     USHORT   usCurPrim;
  152.     USHORT   usMix;
  153.  
  154.     LONG     cptl;
  155.     PPOINTL  pptl;
  156.     PPOINTL  pptlTmp;
  157.  
  158.     BOOL     fDraggingPelSize;
  159.     HPOINTER hptrDragSize;
  160.  
  161.     BOOL     fDraggingPelColor;
  162.     HPOINTER hptrDragColor;
  163.  
  164.     SHORT    sPtGrabbed;
  165.     BOOL     fDraggingControlPoint;
  166.     LONG     lHitPrecision;
  167.  
  168.     BOOL     fEditPelColors;
  169.  
  170. } GLOBALDATA;
  171. GLOBALDATA global;
  172.  
  173.  
  174.  
  175.  
  176. /************************************************************************
  177. *
  178. *   main
  179. *
  180. *   WinInitialize resizes our ring 2 stack, among other things, so
  181. *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
  182. *   us as a REAL PM app. (WINDOWAPI in .DEF file does also).
  183. *   Call a sub to register our window class and create a window.
  184. *   Loop over messages.  Exit cleanly.
  185. *
  186. ************************************************************************/
  187.  
  188. VOID cdecl
  189. main()
  190. {
  191.     QMSG qMsg;
  192.     int iRet = 0;
  193.  
  194.  
  195.     global.hab     = WinInitialize(NULL);
  196.     global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
  197.  
  198.     if (InitApp())
  199.     while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
  200.         WinDispatchMsg( global.hab, (PQMSG)&qMsg );
  201.     else
  202.     iRet = -1;
  203.  
  204.     WinDestroyWindow( global.hwndFrame );
  205.     WinDestroyMsgQueue( global.hMsgQ );
  206.     WinTerminate( global.hab );
  207.     DosExit(EXIT_PROCESS, iRet);
  208. }
  209.  
  210.  
  211.  
  212.  
  213. /****************************************************************************
  214. *
  215. *   InitGlobals
  216. *
  217. *   Initialize global variables.
  218. *
  219. ****************************************************************************/
  220.  
  221. BOOL FAR
  222. InitGlobals()
  223. {
  224.     global.fFirstTime         = TRUE;
  225.  
  226.     global.rcl.xLeft         = 0L;
  227.     global.rcl.yBottom         = 0L;
  228.     global.rcl.xRight         = 0L;
  229.     global.rcl.yTop         = 0L;
  230.  
  231.     global.hpsFat         = NULL;
  232.     global.hdcFat         = NULL;
  233.     global.hbmFat         = NULL;
  234.     global.hpsFatShadow      = NULL;
  235.     global.hdcFatShadow      = NULL;
  236.     global.hbmFatShadow      = NULL;
  237.     global.rclFatBM.xLeft     = 0L;
  238.     global.rclFatBM.yBottom     = 0L;
  239.     global.rclFatBM.xRight     = 0L;
  240.     global.rclFatBM.yTop     = 0L;
  241.  
  242.     global.cxFatPel         = 32L;
  243.     global.cyFatPel         = 32L;
  244.     global.cxHalfFatPel      = global.cxFatPel / 2L;
  245.     global.cyHalfFatPel      = global.cyFatPel / 2L;
  246.     global.usPelShape         = IDD_CIRCLE;
  247.  
  248.     global.fRGB          = FALSE;
  249.     global.clrMathObj         = CLR_BLUE;
  250.     global.clrRenderedObj     = CLR_NEUTRAL;
  251.     global.clrField         = CLR_CYAN;
  252.     global.clrCrossHair      = CLR_DARKCYAN;
  253.     global.clrInterstice     = CLR_BACKGROUND;
  254.     global.clrControlPoints     = CLR_YELLOW;
  255.  
  256.     global.clrBlackIndex     = CLR_ERROR;
  257.     global.clrEditPel         = CLR_ERROR;
  258.  
  259.     global.usControlPointSymbol  = MARKSYM_SOLIDDIAMOND;
  260.  
  261.     global.fDisplayRenderedObj     = TRUE;
  262.     global.fDisplayMathObj     = TRUE;
  263.     global.fDisplayControlPoints = TRUE;
  264.     global.fDisplayCrossHairs     = TRUE;
  265.     global.fDisplayPelBorder     = TRUE;
  266.     global.fRoundControlPoints     = FALSE;
  267.     global.fAutoRedraw         = TRUE;
  268.     global.usCurPrim         = IDM_POLYLINE;
  269.     global.usMix         = FM_OVERPAINT;
  270.  
  271.     global.fDraggingPelSize     = FALSE;
  272.     global.fDraggingPelColor     = FALSE;
  273.     global.fDraggingControlPoint = FALSE;
  274.     global.sPtGrabbed         = NO_POINT;
  275.     global.lHitPrecision     = 0L;
  276.  
  277.     global.fEditPelColors     = FALSE;
  278.  
  279.  
  280.     global.cptl = 0L;
  281.     global.pptl = NULL;
  282.     if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  283.            ((PUSHORT)&global.pptl)+1, 0))
  284.     return FALSE;
  285.     global.pptlTmp = NULL;
  286.     if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  287.            ((PUSHORT)&global.pptlTmp)+1, 0))
  288.     return FALSE;
  289.  
  290.     return TRUE;
  291. }
  292.  
  293.  
  294.  
  295.  
  296. /****************************************************************************
  297. *
  298. *   InitApp
  299. *
  300. *   Register application window class and creates standard window.
  301. *
  302. ****************************************************************************/
  303.  
  304. #define INIT_MENU_ITEM(val, var)     \
  305.     TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
  306.  
  307. BOOL FAR
  308. InitApp()
  309. {
  310.     char szTitle[24];
  311.     ULONG ctldata;
  312.     PID pid;
  313.     TID tid;
  314.     HSWITCH hsw;
  315.     static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
  316.                  SWL_JUMPABLE, "FatPels", 0 };
  317.  
  318.     if (!InitGlobals())
  319.     return FALSE;
  320.  
  321.  
  322.     /*  Register Application Window Class  */
  323.  
  324.     WinLoadString( global.hab, NULL, IDS_TITLE, sizeof(szTitle), (PCH)szTitle );
  325.     if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
  326.         CS_SIZEREDRAW, 0 ))
  327.     return FALSE;
  328.  
  329.  
  330.     /* Load the pointer to use when dragging pel size. */
  331.     if (!(global.hptrDragSize = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGSIZEPTR )))
  332.     return FALSE;
  333.  
  334.     /* Load the pointer to use when dragging pel color. */
  335.     if (!(global.hptrDragColor = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGCOLORPTR )))
  336.     return FALSE;
  337.  
  338.  
  339.     /* Create a window instance of class "FatPel" */
  340.  
  341.     ctldata = FCF_STANDARD &
  342.      ~(ULONG)(FCF_ICON | FCF_ACCELTABLE | FCF_TASKLIST);
  343.  
  344.     if (global.hwndFrame = WinCreateStdWindow(
  345.     HWND_DESKTOP,           /* specify desktop as parent window        */
  346.     WS_VISIBLE,           /* window styles                */
  347.     &ctldata,           /* frame creation flags            */
  348.     (PCH)szTitle,           /* window class name             */
  349.     (PCH)szTitle,           /* name appearing in window caption        */
  350.     0L,               /*                        */
  351.     (HMODULE)NULL,           /* use current executable module id        */
  352.     IDR_FATPEL,           /* menu id                    */
  353.     (HWND FAR *)&global.hwnd   /* window handle                */
  354.     ))
  355.     {
  356.     INIT_MENU_ITEM(IDM_RENDEREDOBJ,     global.fDisplayRenderedObj);
  357.     INIT_MENU_ITEM(IDM_MATHOBJ,     global.fDisplayMathObj);
  358.     INIT_MENU_ITEM(IDM_CTLPOINTS,     global.fDisplayControlPoints);
  359.     INIT_MENU_ITEM(IDM_CROSSHAIRS,     global.fDisplayCrossHairs);
  360.     INIT_MENU_ITEM(IDM_PELBORDER,     global.fDisplayPelBorder);
  361.     INIT_MENU_ITEM(IDM_ROUNDPOINTS,     global.fRoundControlPoints);
  362.     INIT_MENU_ITEM(IDM_AUTOREDRAW,     global.fAutoRedraw);
  363.     INIT_MENU_ITEM(IDM_EDITPELCOLORS, global.fEditPelColors);
  364.  
  365.     CHECK_MENU_ITEM(global.hwndFrame, global.usCurPrim);
  366.  
  367.  
  368.     /* Add ourselves to the switch list. */
  369.  
  370.     WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
  371.     swctl.hwnd    = global.hwndFrame;
  372.     swctl.idProcess = pid;
  373.     hsw = WinAddSwitchEntry(&swctl);
  374.  
  375.     return TRUE;
  376.     }
  377.     return FALSE;
  378. }
  379.  
  380.  
  381.  
  382.  
  383. /*************************************************************************
  384. *
  385. *   WndProc
  386. *
  387. *   Process messages for the window class.
  388. *
  389. ************************************************************************/
  390.  
  391. ULONG CALLBACK
  392. WndProc( hwnd, usMsg, mp1, mp2 )
  393. HWND    hwnd;
  394. USHORT    usMsg;
  395. MPARAM  mp1;
  396. MPARAM  mp2;
  397. {
  398.     switch (usMsg)
  399.     {
  400.     case WM_CLOSE:
  401.     Close(hwnd);
  402.     break;
  403.  
  404.     case WM_COMMAND:
  405.     Command(hwnd, LOUSHORT(mp1));
  406.     break;
  407.  
  408.     case WM_PAINT:
  409.     {
  410.         HPS   hps;
  411.  
  412.         if (global.fFirstTime)
  413.         {
  414.         SIZEF sizfx;
  415.  
  416.         hps = WinGetPS(hwnd);
  417.         GpiQueryMarkerBox(hps, &sizfx);
  418.         global.lHitPrecision = sizfx.cx / 0x20000L + 1L;
  419.         WinReleasePS(hps);
  420.  
  421.         UpdateSurfaceDims();
  422.         global.fFirstTime = FALSE;
  423.         }
  424.  
  425.         /* The small bitmap may have been resized since we last
  426.          * painted, in which case it will have been initialized to
  427.          * the field color.  Therefore, we will render the mathematical
  428.          * object to make sure the right fatpels are there.
  429.          */
  430.         global.usMix = FM_OVERPAINT;
  431.         hps = WinBeginPaint(global.hwnd, NULL, NULL);
  432.         Paint(hps, CLEAR_BACKGROUND|RENDER_MATH_OBJ);
  433.         WinEndPaint(hps);
  434.     }
  435.     break;
  436.  
  437.     case WM_BUTTON1DOWN:
  438.     case WM_BUTTON2DOWN:
  439.     ButtonDown(hwnd, usMsg, mp1);
  440.     break;
  441.  
  442.     case WM_BUTTON1UP:
  443.     case WM_BUTTON2UP:
  444.     ButtonUp(hwnd, usMsg);
  445.     break;
  446.  
  447.     case WM_MOUSEMOVE:
  448.     MouseMove(hwnd, mp1);
  449.     break;
  450.  
  451.     case WM_SIZE:
  452.     UpdateSurfaceDims();
  453.     return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  454.     break;
  455.  
  456.     default:
  457.     return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  458.     break;
  459.     }
  460.  
  461.     return FALSE;
  462. }
  463.  
  464.  
  465.  
  466.  
  467. /************************************************************************
  468. *
  469. *   MouseMove
  470. *
  471. ************************************************************************/
  472.  
  473. VOID
  474. MouseMove(hwnd, mp1)
  475. HWND hwnd;
  476. MPARAM mp1;
  477. {
  478.     POINTL ptl;
  479.     HPS hps;
  480.  
  481.  
  482.     /* make sure we still have our pointer */
  483.     /* notice the hierarchy of pointer modes */
  484.  
  485.     if (global.fDraggingPelSize)
  486.     {
  487.     if (global.hptrDragSize)
  488.         WinSetPointer(HWND_DESKTOP,global.hptrDragSize);
  489.     }
  490.     else if (global.fEditPelColors)
  491.     {
  492.     if (global.hptrDragColor)
  493.         WinSetPointer(HWND_DESKTOP,global.hptrDragColor);
  494.     }
  495.     else
  496.     WinSetPointer(HWND_DESKTOP,
  497.           WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
  498.  
  499.  
  500.     if (global.fDraggingPelColor)
  501.     {
  502.     POINTL ptl, ptlFat;
  503.     HPS hps;
  504.  
  505.  
  506.     ptl.x = (LONG) LOUSHORT(mp1);
  507.     ptl.y = (LONG) HIUSHORT(mp1);
  508.  
  509.     /* letting the point go negative causes overflow errors */
  510.     if (ptl.x < 0)
  511.         ptl.x = 0;
  512.     if (ptl.y < 0)
  513.         ptl.y = 0;
  514.  
  515.     GetFatPelFromPt(&ptl, &ptlFat);
  516.     SetFatPel(&ptlFat, global.clrEditPel);
  517.  
  518.     hps = WinGetPS(hwnd);
  519.     Paint(hps, OVERRIDE_RENDERED_OBJ);
  520.     Paint(hps, IGNORED);    /* this call just copies fatpels to the screen */
  521.     WinReleasePS(hps);
  522.     }
  523.     else if (global.fDraggingControlPoint)
  524.     {
  525.     ptl.x = (LONG) LOUSHORT(mp1);
  526.     ptl.y = (LONG) HIUSHORT(mp1);
  527.  
  528.     /* letting the point go negative causes overflow errors */
  529.     if (ptl.x < 0)
  530.         ptl.x = 0;
  531.     if (ptl.y < 0)
  532.         ptl.y = 0;
  533.  
  534.     if (global.sPtGrabbed != NO_POINT)
  535.     {
  536.         hps = WinGetPS(hwnd);
  537.         Paint(hps, OVERRIDE_RENDERED_OBJ);
  538.  
  539.         global.pptl[global.sPtGrabbed] = ptl;
  540.  
  541.         Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  542.         WinReleasePS(hps);
  543.     }
  544.     }
  545. }
  546.  
  547.  
  548.  
  549.  
  550. /************************************************************************
  551. *
  552. *   ButtonUp
  553. *
  554. ************************************************************************/
  555.  
  556. VOID
  557. ButtonUp(hwnd, usMsg)
  558. HWND hwnd;
  559. USHORT usMsg;
  560. {
  561.     SHORT i;
  562.     HPS hps;
  563.  
  564.  
  565.     if (global.fDraggingPelColor)
  566.     {
  567.     global.fDraggingPelColor = FALSE;
  568.     WinSetCapture(HWND_DESKTOP, NULL);
  569.     }
  570.     else if (global.fDraggingControlPoint)
  571.     {
  572.     global.fDraggingControlPoint = FALSE;
  573.     WinSetCapture(HWND_DESKTOP, NULL);
  574.     if (global.sPtGrabbed != NO_POINT)
  575.     {
  576.         if (usMsg == WM_BUTTON2UP)    /* remove point? */
  577.         {
  578.         hps = WinGetPS(hwnd);
  579.         Paint(hps, OVERRIDE_RENDERED_OBJ);
  580.  
  581.         /* squeeze out selected point */
  582.         if ((i = global.sPtGrabbed) < (SHORT)(global.cptl-1))
  583.             while (i < (SHORT)(global.cptl-1))
  584.             {
  585.             global.pptl[i] = global.pptl[i+1];
  586.             ++i;
  587.             }
  588.  
  589.         --global.cptl;
  590.         global.sPtGrabbed = NO_POINT;
  591.  
  592.         Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  593.         WinReleasePS(hps);
  594.         }
  595.         else    /* WM_BUTTON1UP */
  596.         global.sPtGrabbed = NO_POINT;
  597.     }
  598.     }
  599. }
  600.  
  601.  
  602.  
  603.  
  604. /************************************************************************
  605. *
  606. *   ButtonDown
  607. *
  608. ************************************************************************/
  609.  
  610. VOID
  611. ButtonDown(hwnd, usMsg, mp1)
  612. HWND hwnd;
  613. USHORT usMsg;
  614. MPARAM mp1;
  615. {
  616.     if (global.fDraggingPelSize)
  617.     {
  618.     POINTS pt;
  619.     HPS hps;
  620.  
  621.     pt.x = LOUSHORT(mp1);
  622.     pt.y = HIUSHORT(mp1);
  623.     DragPelSize(hwnd, pt);
  624.     global.fDraggingPelSize = FALSE;
  625.  
  626.     WinSetPointer(HWND_DESKTOP,
  627.               WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
  628.  
  629.     hps = WinGetPS(hwnd);
  630.     global.usMix = FM_OVERPAINT;
  631.     Paint(hps, CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  632.     WinReleasePS(hps);
  633.     }
  634.     else if (global.fEditPelColors)
  635.     {
  636.     POINTL ptl, ptlFat;
  637.     HPS hps;
  638.  
  639.     global.fDraggingPelColor = TRUE;
  640.     WinSetCapture(HWND_DESKTOP, hwnd);
  641.  
  642.     ptl.x = (LONG) LOUSHORT(mp1);
  643.     ptl.y = (LONG) HIUSHORT(mp1);
  644.  
  645.     if (global.usMix != FM_XOR)
  646.     {
  647.         hps = WinGetPS(hwnd);
  648.         global.usMix = FM_XOR;
  649.         Paint(hps, CLEAR_BACKGROUND);
  650.         WinReleasePS(hps);
  651.     }
  652.  
  653.     if (usMsg == WM_BUTTON1DOWN)
  654.         global.clrEditPel = global.clrRenderedObj;
  655.     else
  656.         global.clrEditPel = global.clrField;
  657.  
  658.     GetFatPelFromPt(&ptl, &ptlFat);
  659.     SetFatPel(&ptlFat, global.clrEditPel);
  660.  
  661.     hps = WinGetPS(hwnd);
  662.     Paint(hps, OVERRIDE_RENDERED_OBJ);
  663.     Paint(hps, IGNORED);    /* this call just copies fatpels to the screen */
  664.     WinReleasePS(hps);
  665.     }
  666.     else if (!global.fDraggingControlPoint)
  667.     {
  668.     POINTL ptl;
  669.     SHORT sNewPtGrabbed;
  670.     HPS hps;
  671.  
  672.     global.fDraggingControlPoint = TRUE;
  673.     WinSetCapture(HWND_DESKTOP, hwnd);
  674.  
  675.     ptl.x = (LONG) LOUSHORT(mp1);
  676.     ptl.y = (LONG) HIUSHORT(mp1);
  677.  
  678.     sNewPtGrabbed = IsPtInList(&ptl);
  679.  
  680.     if (global.usMix != FM_XOR)
  681.     {
  682.         hps = WinGetPS(hwnd);
  683.         global.usMix = FM_XOR;
  684.         Paint(hps, CLEAR_BACKGROUND);
  685.         WinReleasePS(hps);
  686.     }
  687.  
  688.     if (usMsg == WM_BUTTON1DOWN)    /* add/move point? */
  689.     {
  690.         hps = WinGetPS(hwnd);
  691.  
  692.         if (sNewPtGrabbed != NO_POINT)
  693.         global.sPtGrabbed = sNewPtGrabbed;
  694.         Paint(hps, OVERRIDE_RENDERED_OBJ);
  695.  
  696.         if (sNewPtGrabbed == NO_POINT)
  697.         global.sPtGrabbed = AddPtToList(&ptl);
  698.         else
  699.         global.sPtGrabbed = sNewPtGrabbed;
  700.  
  701.         Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  702.         WinReleasePS(hps);
  703.  
  704.         if (global.sPtGrabbed == NO_POINT)
  705.         MyMessageBox(global.hwnd, "Cannot add any more points.");
  706.     }
  707.     else if (sNewPtGrabbed != NO_POINT)
  708.         global.sPtGrabbed = sNewPtGrabbed;
  709.     }
  710. }
  711.  
  712.  
  713.  
  714.  
  715. /************************************************************************
  716. *
  717. *   GetFatPelFromPt
  718. *
  719. ************************************************************************/
  720.  
  721. VOID
  722. GetFatPelFromPt(pptl, pptlFat)
  723. PPOINTL pptl;
  724. PPOINTL pptlFat;
  725. {
  726.     pptlFat->x = pptl->x / global.cxFatPel;
  727.     pptlFat->y = pptl->y / global.cyFatPel;
  728. }
  729.  
  730.  
  731.  
  732.  
  733. /************************************************************************
  734. *
  735. *   SetFatPel
  736. *
  737. ************************************************************************/
  738.  
  739. VOID
  740. SetFatPel(pptl, clr)
  741. PPOINTL pptl;
  742. COLOR clr;
  743. {
  744.     LINEBUNDLE lb;
  745.  
  746.     if (global.hpsFat)
  747.     {
  748.     lb.lColor = clr;
  749.     GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
  750.     GpiSetPel(global.hpsFat, pptl);
  751.     }
  752. }
  753.  
  754.  
  755.  
  756.  
  757. /************************************************************************
  758. *
  759. *   IsPtInList
  760. *
  761. ************************************************************************/
  762.  
  763. SHORT
  764. IsPtInList(pptl)
  765. PPOINTL pptl;
  766. {
  767.     SHORT i;
  768.  
  769.  
  770.     /* try to find pptl in the points we already have */
  771.     for (i = 0; i < (SHORT)global.cptl; ++i)
  772.     if (((L_ABS(pptl->x - global.pptl[i].x)) <= global.lHitPrecision) &&
  773.         ((L_ABS(pptl->y - global.pptl[i].y)) <= global.lHitPrecision))
  774.         return i;
  775.  
  776.     /* couldn't find it */
  777.     return NO_POINT;
  778. }
  779.  
  780.  
  781.  
  782.  
  783. /************************************************************************
  784. *
  785. *   AddPtToList
  786. *
  787. ************************************************************************/
  788.  
  789. SHORT
  790. AddPtToList(pptl)
  791. PPOINTL pptl;
  792. {
  793.     SHORT i, j;
  794.  
  795.     if (global.cptl < CPTLMAX)
  796.     {
  797.     /* check for new points lying on a line segment */
  798.     for (i = 0; i < (SHORT)(global.cptl-1L); ++i)
  799.         if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
  800.         {
  801.         /* insert point between endpoints of nearest line segment */
  802.         for (j = (SHORT)global.cptl; j > i+1; --j)
  803.             global.pptl[j] = global.pptl[j - 1];
  804.         global.pptl[i+1] = *pptl;
  805.         ++global.cptl;
  806.         return i+1;
  807.         }
  808.  
  809.     /* append the point */
  810.  
  811.     i = (SHORT) global.cptl;
  812.     global.pptl[i] = *pptl;
  813.     ++global.cptl;
  814.     return i;
  815.     }
  816.  
  817.     return NO_POINT;
  818. }
  819.  
  820.  
  821.  
  822.  
  823. /************************************************************************
  824. *
  825. *   IsPtCloseToLine
  826. *
  827. ************************************************************************/
  828.  
  829. BOOL
  830. IsPtCloseToLine(pptl1, pptl2, pptlTest)
  831. PPOINTL pptl1;
  832. PPOINTL pptl2;
  833. PPOINTL pptlTest;
  834. {
  835.     POINTL ptlLL, ptlUR;
  836.     LONG dx, dy, yIntercept, error;
  837.     LONG lBoxAdjustment;
  838.  
  839.  
  840.     /* find the bounding box of the line segment */
  841.  
  842.     ptlLL = *pptl1;    /* assume line goes lower left to upper right */
  843.     ptlUR = *pptl2;
  844.     if (pptl1->x > pptl2->x)
  845.     SwapLong(&ptlLL.x, &ptlUR.x);
  846.     if (pptl1->y > pptl2->y)
  847.     SwapLong(&ptlLL.y, &ptlUR.y);
  848.  
  849.  
  850.     /* adjust the bounding box if it's too narrow */
  851.  
  852.     lBoxAdjustment = global.lHitPrecision/2L;
  853.  
  854.     dx = pptl2->x - pptl1->x;
  855.     if (L_ABS(dx) <= global.lHitPrecision)
  856.     {
  857.     ptlLL.x -= lBoxAdjustment;
  858.     ptlUR.x += lBoxAdjustment;
  859.     }
  860.     dy = pptl2->y - pptl1->y;
  861.     if (L_ABS(dy) <= global.lHitPrecision)
  862.     {
  863.     ptlLL.y -= lBoxAdjustment;
  864.     ptlUR.y += lBoxAdjustment;
  865.     }
  866.  
  867.  
  868.     /* see if the test point is in the bounding box of the line segment */
  869.  
  870.     if ((pptlTest->x >= ptlLL.x) &&
  871.     (pptlTest->x <= ptlUR.x) &&
  872.     (pptlTest->y >= ptlLL.y) &&
  873.     (pptlTest->y <= ptlUR.y))
  874.     {
  875.     /* test for special cases */
  876.  
  877.     if (dx == 0)    /* vertical line */
  878.     {
  879.         return (L_ABS(pptlTest->x - pptl1->x) <= global.lHitPrecision);
  880.     }
  881.  
  882.     if (dy == 0)    /* horizontal line */
  883.     {
  884.         return (L_ABS(pptlTest->y - pptl1->y) <= global.lHitPrecision);
  885.     }
  886.  
  887.  
  888.     /* test for general case */
  889.  
  890.     yIntercept = pptl1->y - (pptl1->x * dy) / dx;
  891.  
  892.     error = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
  893.     if (L_ABS(error) <= global.lHitPrecision)
  894.         return TRUE;
  895.     }
  896.  
  897.     return FALSE;
  898. }
  899.  
  900.  
  901.  
  902.  
  903. /************************************************************************
  904. *
  905. *   SwapLong
  906. *
  907. ************************************************************************/
  908.  
  909. VOID
  910. SwapLong(pl1, pl2)
  911. PLONG pl1, pl2;
  912. {
  913.     LONG lTmp;
  914.  
  915.     lTmp = *pl1;
  916.     *pl1 = *pl2;
  917.     *pl2 = lTmp;
  918. }
  919.  
  920.  
  921.  
  922.  
  923. /************************************************************************
  924. *
  925. *   DragPelSize
  926. *
  927. *   Set the dimensions of a fat pel by dragging a rectangle
  928. *   on the screen.
  929. *
  930. ************************************************************************/
  931.  
  932. VOID
  933. DragPelSize(hwnd, pt)
  934. HWND hwnd;
  935. POINTS pt;
  936. {
  937.     TRACKINFO ti;
  938.  
  939.     WinSendMsg(global.hwndFrame, WM_QUERYTRACKINFO, (MPARAM)TF_MOVE, (MPARAM)&ti);
  940.  
  941.     ti.cxBorder   = 1;
  942.     ti.cyBorder   = 1;
  943.     ti.rclTrack.xLeft    = (LONG)pt.x;
  944.     ti.rclTrack.yBottom = (LONG)pt.y;
  945.     ti.rclTrack.xRight    = (LONG)pt.x;
  946.     ti.rclTrack.yTop    = (LONG)pt.y;
  947.     ti.fs = TF_RIGHT | TF_TOP;
  948.     ti.ptlMinTrackSize.x = 1L;
  949.     ti.ptlMinTrackSize.y = 1L;
  950.  
  951.     if (WinTrackRect(hwnd, NULL, &ti))
  952.     {
  953.     global.cxFatPel = (ti.rclTrack.xRight - ti.rclTrack.xLeft)  ;
  954.     global.cyFatPel = (ti.rclTrack.yTop   - ti.rclTrack.yBottom);
  955.  
  956.     if (global.cxFatPel < 1L)
  957.         global.cxFatPel = 1L;
  958.  
  959.     if (global.cyFatPel < 1L)
  960.         global.cyFatPel = 1L;
  961.  
  962.     global.cxHalfFatPel = global.cxFatPel / 2L;
  963.     global.cyHalfFatPel = global.cyFatPel / 2L;
  964.  
  965.     UpdateSurfaceDims();
  966.     }
  967. }
  968.  
  969.  
  970.  
  971.  
  972. /************************************************************************
  973. *
  974. *   Close
  975. *
  976. ************************************************************************/
  977.  
  978. VOID
  979. Close(hwnd)
  980. HWND hwnd;
  981. {
  982.     if (global.hptrDragSize)
  983.     WinDestroyPointer(global.hptrDragSize);
  984.     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  985. }
  986.  
  987.  
  988.  
  989.  
  990. /************************************************************************
  991. *
  992. *   Command
  993. *
  994. *   Dispatches menu commands to the proper handlers.
  995. *
  996. ************************************************************************/
  997.  
  998. #define UPDATE_MENU_BOOL(var, val)                \
  999.     {                            \
  1000.         TOGGLE_BOOL((var));                 \
  1001.         TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));    \
  1002.     }
  1003.  
  1004. #define UPDATE_MENU_LIST(var, val)                \
  1005.     {                            \
  1006.         UNCHECK_MENU_ITEM(global.hwndFrame, (var));     \
  1007.         (var) = (val);                    \
  1008.         CHECK_MENU_ITEM(global.hwndFrame, (var));        \
  1009.     }
  1010.  
  1011. VOID
  1012. Command(hwnd, id)
  1013. HWND hwnd;
  1014. USHORT id;
  1015. {
  1016.     BOOL fRedraw = FALSE;
  1017.     USHORT fsCmd = IGNORED;
  1018.  
  1019.  
  1020.     switch (id)
  1021.     {
  1022.     case IDM_SAVE:
  1023.     SaveWindowToFile(hwnd);
  1024.     break;
  1025.  
  1026.     case IDM_ABOUT:
  1027.     WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)AboutDlg, NULL,
  1028.                IDR_ABOUTDLG, NULL );
  1029.     break;
  1030.  
  1031.     case IDM_REDRAW:
  1032.     fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  1033.     break;
  1034.  
  1035.     case IDM_SETPELSIZE:
  1036.     {
  1037.         LONG cxFatPel, cyFatPel;
  1038.  
  1039.         cxFatPel = global.cxFatPel;
  1040.         cyFatPel = global.cyFatPel;
  1041.  
  1042.         if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)PelSizeDlg, NULL,
  1043.                IDR_PELSIZEDLG, NULL ))
  1044.         {
  1045.         if ((cxFatPel == global.cxFatPel) &&
  1046.             (cyFatPel == global.cyFatPel))
  1047.             fsCmd = CLEAR_BACKGROUND;
  1048.         else
  1049.             fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  1050.         fRedraw = TRUE;
  1051.         }
  1052.     }
  1053.     break;
  1054.  
  1055.     case IDM_DRAGPELSIZE:
  1056.     global.fDraggingPelSize = TRUE;
  1057.     break;
  1058.  
  1059.     case IDM_RENDEREDOBJ:
  1060.     UPDATE_MENU_BOOL(global.fDisplayRenderedObj, IDM_RENDEREDOBJ);
  1061.     fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  1062.     fRedraw = TRUE;
  1063.     break;
  1064.  
  1065.     case IDM_MATHOBJ:
  1066.     UPDATE_MENU_BOOL(global.fDisplayMathObj, IDM_MATHOBJ);
  1067.     fsCmd = CLEAR_BACKGROUND;
  1068.     fRedraw = TRUE;
  1069.     break;
  1070.  
  1071.     case IDM_CTLPOINTS:
  1072.     UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
  1073.     fsCmd = CLEAR_BACKGROUND;
  1074.     fRedraw = TRUE;
  1075.     break;
  1076.  
  1077.     case IDM_CROSSHAIRS:
  1078.     UPDATE_MENU_BOOL(global.fDisplayCrossHairs, IDM_CROSSHAIRS);
  1079.     fsCmd = CLEAR_BACKGROUND;
  1080.     fRedraw = TRUE;
  1081.     break;
  1082.  
  1083.     case IDM_PELBORDER:
  1084.     UPDATE_MENU_BOOL(global.fDisplayPelBorder, IDM_PELBORDER);
  1085.     fsCmd = CLEAR_BACKGROUND;
  1086.     fRedraw = TRUE;
  1087.     break;
  1088.  
  1089.     case IDM_ROUNDPOINTS:
  1090.     UPDATE_MENU_BOOL(global.fRoundControlPoints, IDM_ROUNDPOINTS);
  1091.     fsCmd = CLEAR_BACKGROUND;
  1092.     fRedraw = TRUE;
  1093.     break;
  1094.  
  1095.     case IDM_AUTOREDRAW:
  1096.     UPDATE_MENU_BOOL(global.fAutoRedraw, IDM_AUTOREDRAW);
  1097.     break;
  1098.  
  1099.     case IDM_NOPRIM:
  1100.     case IDM_POLYLINE:
  1101.     case IDM_POLYFILLET:
  1102.     case IDM_POLYSPLINE:
  1103.     case IDM_POINTARC:
  1104.     UPDATE_MENU_LIST(global.usCurPrim, id);
  1105.     fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  1106.     fRedraw = TRUE;
  1107.     break;
  1108.  
  1109.     case IDM_SETCOLORS:
  1110.     if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)ColorsDlg, NULL,
  1111.                IDR_COLORSDLG, NULL ))
  1112.     {
  1113.         fsCmd = CLEAR_BACKGROUND|RENDER_MATH_OBJ;
  1114.         fRedraw = TRUE;
  1115.     }
  1116.     break;
  1117.  
  1118.     case IDM_EDITPELCOLORS:
  1119.     UPDATE_MENU_BOOL(global.fEditPelColors, IDM_EDITPELCOLORS);
  1120.     break;
  1121.  
  1122.     case IDM_CLEARALL:
  1123.     global.cptl = 0L;
  1124.     fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  1125.     fRedraw = TRUE;
  1126.     break;
  1127.     }
  1128.  
  1129.     if ((global.fAutoRedraw && fRedraw) || (id == IDM_REDRAW))
  1130.     {
  1131.     HPS hps;
  1132.  
  1133.     hps = WinGetPS(hwnd);
  1134.     global.usMix = FM_OVERPAINT;
  1135.     Paint(hps, fsCmd);
  1136.     WinReleasePS(hps);
  1137.     }
  1138. }
  1139.  
  1140.  
  1141.  
  1142.  
  1143. /************************************************************************
  1144. *
  1145. *   Paint
  1146. *
  1147. ************************************************************************/
  1148.  
  1149. VOID
  1150. Paint(hps, fsCmd)
  1151. HPS  hps;
  1152. USHORT fsCmd;
  1153. {
  1154.     HRGN hrgn, hrgnClipOld, hrgnT;
  1155.  
  1156.  
  1157.     /* Clear the unused part of the client rectangle to a hatch pattern. */
  1158.     if (fsCmd & CLEAR_BACKGROUND)
  1159.     EraseBackground(hps);
  1160.  
  1161.  
  1162.     /* Set up the color mode as the user has requested */
  1163.  
  1164.     if (global.fRGB)
  1165.     {
  1166.     GpiCreateLogColorTable(hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
  1167.     if (global.hpsFat)
  1168.     {
  1169.         GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
  1170.         GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
  1171.     }
  1172.     }
  1173.     else
  1174.     if (global.hpsFat)
  1175.     {
  1176.         GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
  1177.         GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
  1178.         global.clrBlackIndex = GpiQueryColorIndex(hps, 0L, 0x000000L);
  1179.     }
  1180.  
  1181.  
  1182.     if (global.usPelShape == IDD_CIRCLE)
  1183.     {
  1184.     ARCPARAMS arcp;
  1185.  
  1186.     arcp.lP = global.cxFatPel / 2L;
  1187.     arcp.lQ = global.cyFatPel / 2L;
  1188.     arcp.lR = 0L;
  1189.     arcp.lS = 0L;
  1190.  
  1191.     GpiSetArcParams(hps, &arcp);
  1192.     }
  1193.  
  1194.  
  1195.     /* set clipping rectangle to the fatbit surface */
  1196.  
  1197.     if ((hrgn = GpiCreateRegion(hps, 1L, &global.rcl)) != HRGN_ERROR)
  1198.     GpiSetClipRegion(hps, hrgn, &hrgnClipOld);
  1199.  
  1200.  
  1201.     if (fsCmd & CLEAR_BACKGROUND)
  1202.     {
  1203.     DrawGrid(hps);
  1204.  
  1205.     if (global.hpsFatShadow)
  1206.     {
  1207.         AREABUNDLE ab;
  1208.  
  1209.         /* clear shadow fatpel surface to background color */
  1210.         ab.lColor = global.clrField;
  1211.         GpiSetAttrs(global.hpsFatShadow, PRIM_AREA, ABB_COLOR, 0L, &ab);
  1212.         GpiBitBlt(global.hpsFatShadow, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
  1213.     }
  1214.     }
  1215.  
  1216.     if (global.fDisplayRenderedObj && !(fsCmd & OVERRIDE_RENDERED_OBJ))
  1217.     DisplayRenderedPels(hps, fsCmd);
  1218.  
  1219.     if (global.fDisplayControlPoints)
  1220.     {
  1221.     /* when rubberbanding with the rendered obj, newly drawn fatpels
  1222.      * can wipe out stationary control point markers, so we have to
  1223.      * redraw them all each time
  1224.      */
  1225.  
  1226.     if (global.fDisplayRenderedObj || (fsCmd & CLEAR_BACKGROUND))
  1227.         DisplayControlPoints(hps, global.cptl, global.pptl, global.usMix);
  1228.     else if (global.sPtGrabbed != NO_POINT)
  1229.         /* draw just the control point that moved */
  1230.         DisplayControlPoints(hps, 1L, global.pptl+global.sPtGrabbed, global.usMix);
  1231.     }
  1232.  
  1233.     if (global.fDisplayMathObj)
  1234.     DisplayMathematicalObject(hps, global.usMix);
  1235.  
  1236.     /* delete the clip region we set up */
  1237.  
  1238.     if (hrgnClipOld != HRGN_ERROR)
  1239.     GpiSetClipRegion(hps, hrgnClipOld, &hrgnT);
  1240.     if (hrgn != HRGN_ERROR)
  1241.     GpiDestroyRegion(hps, hrgn);
  1242. }
  1243.  
  1244.  
  1245.  
  1246.  
  1247. /************************************************************************
  1248. *
  1249. *   DisplayMathematicalObject
  1250. *
  1251. ************************************************************************/
  1252.  
  1253. VOID
  1254. DisplayMathematicalObject(hps, usMix)
  1255. HPS hps;
  1256. USHORT usMix;
  1257. {
  1258.     PPOINTL pptl;
  1259.     LINEBUNDLE lb;
  1260.  
  1261.     if (global.cptl > 0)
  1262.     {
  1263.     if (global.fRoundControlPoints)
  1264.     {
  1265.         RoundControlPoints(hps, global.cptl, global.pptl, global.pptlTmp,
  1266.                    global.cxFatPel, global.cyFatPel);
  1267.         pptl = global.pptlTmp;
  1268.     }
  1269.     else
  1270.         pptl = global.pptl;
  1271.  
  1272.     /* draw line */
  1273.     lb.lColor    = global.clrMathObj;
  1274.     lb.usMixMode = usMix;
  1275.     GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE, 0L, &lb);
  1276.     DrawPrimitive(hps, global.cptl, pptl);
  1277.     }
  1278. }
  1279.  
  1280.  
  1281.  
  1282.  
  1283. /************************************************************************
  1284. *
  1285. *   DisplayControlPoints
  1286. *
  1287. ************************************************************************/
  1288.  
  1289. VOID
  1290. DisplayControlPoints(hps, cptl, pptl, usMix)
  1291. HPS hps;
  1292. LONG cptl;
  1293. PPOINTL pptl;
  1294. USHORT usMix;
  1295. {
  1296.     PPOINTL pptlT;
  1297.     MARKERBUNDLE mb;
  1298.  
  1299.     if (cptl > 0)
  1300.     {
  1301.     if (global.fRoundControlPoints)
  1302.     {
  1303.         RoundControlPoints(hps, cptl, pptl, global.pptlTmp,
  1304.                    global.cxFatPel, global.cyFatPel);
  1305.         pptlT = global.pptlTmp;
  1306.     }
  1307.     else
  1308.         pptlT = pptl;
  1309.  
  1310.  
  1311.     mb.lColor    = global.clrControlPoints;
  1312.     mb.usMixMode = usMix;
  1313.     mb.usSymbol  = global.usControlPointSymbol;
  1314.     GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR|MBB_MIX_MODE|MBB_SYMBOL, 0L, &mb);
  1315.  
  1316.     GpiPolyMarker(hps, cptl, pptlT);
  1317.     }
  1318. }
  1319.  
  1320.  
  1321.  
  1322.  
  1323. /************************************************************************
  1324. *
  1325. *   EraseBackground
  1326. *
  1327. *   Erase the unused part of the window to a hatch pattern.
  1328. *
  1329. ************************************************************************/
  1330.  
  1331. VOID
  1332. EraseBackground(hps)
  1333. HPS hps;
  1334. {
  1335.     RECTL rclClient, rclT;
  1336.     AREABUNDLE ab;
  1337.  
  1338.  
  1339.     WinQueryWindowRect(global.hwnd, &rclClient);
  1340.  
  1341.     ab.lColor      = CLR_BLACK;
  1342.     ab.lBackColor = CLR_WHITE;
  1343.     ab.usSymbol   = PATSYM_DIAG1;
  1344.     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR|ABB_BACK_COLOR|ABB_SYMBOL,
  1345.         0L, (PBUNDLE)&ab);
  1346.  
  1347.     if (global.rcl.yTop < rclClient.yTop)
  1348.     {
  1349.     rclT.xLeft   = rclClient.xLeft;
  1350.     rclT.yBottom = global.rcl.yBottom;
  1351.     rclT.xRight  = rclClient.xRight;
  1352.     rclT.yTop    = rclClient.yTop;
  1353.     GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
  1354.     }
  1355.  
  1356.     if (global.rcl.xRight < rclClient.xRight)
  1357.     {
  1358.     rclT.xLeft   = global.rcl.xRight;
  1359.     rclT.yBottom = rclClient.yBottom;
  1360.     rclT.xRight  = rclClient.xRight;
  1361.     rclT.yTop    = global.rcl.yTop;
  1362.     GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
  1363.     }
  1364.  
  1365.     ab.usSymbol   = PATSYM_SOLID;
  1366.     GpiSetAttrs(hps, PRIM_AREA, ABB_SYMBOL, 0L, (PBUNDLE)&ab);
  1367. }
  1368.  
  1369.  
  1370.  
  1371.  
  1372. /************************************************************************
  1373. *
  1374. *   DrawGrid
  1375. *
  1376. ************************************************************************/
  1377.  
  1378. VOID
  1379. DrawGrid(hps)
  1380. HPS  hps;
  1381. {
  1382.     AREABUNDLE ab;
  1383.     POINTL ptl;
  1384.     POINTL aptl[3];
  1385.  
  1386.  
  1387.     /* clear fatpel surface to background color */
  1388.     ab.lColor = global.clrInterstice;
  1389.     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
  1390.     GpiBitBlt(hps, NULL, 2L, (PPOINTL)&global.rcl, ROP_PATCOPY, NULL);
  1391.  
  1392.  
  1393.     /* draw one pel in lower left corner */
  1394.  
  1395.     ptl.x = global.cxFatPel / 2L;
  1396.     ptl.y = global.cyFatPel / 2L;
  1397.     DrawOneFatPel(hps, &ptl, global.clrField);
  1398.  
  1399.  
  1400.     /* blt up first column then across -- we don't have to worry
  1401.      * about the edges because a clip region has been setup to do that.
  1402.      */
  1403.  
  1404.     aptl[0].x = 0L;
  1405.     aptl[0].y = global.cyFatPel;
  1406.     aptl[1].x = global.cxFatPel;
  1407.     aptl[2].x = 0L;
  1408.     aptl[2].y = 0L;
  1409.  
  1410.     while (aptl[0].y <= global.rcl.yTop)
  1411.     {
  1412.     aptl[1].y  = aptl[0].y + aptl[0].y;
  1413.     GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
  1414.     aptl[0].y += aptl[1].y - aptl[0].y;
  1415.     }
  1416.  
  1417.     aptl[0].x = global.cxFatPel;
  1418.     aptl[0].y = 0L;
  1419.     aptl[1].y = global.rcl.yTop;
  1420.     aptl[2].x = 0L;
  1421.     aptl[2].y = 0L;
  1422.  
  1423.     while (aptl[0].x <= global.rcl.xRight)
  1424.     {
  1425.     aptl[1].x  = aptl[0].x + aptl[0].x;
  1426.     GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
  1427.     aptl[0].x += aptl[1].x - aptl[0].x;
  1428.     }
  1429. }
  1430.  
  1431.  
  1432.  
  1433.  
  1434. /************************************************************************
  1435. *
  1436. *   DisplayRenderedPels
  1437. *
  1438. ************************************************************************/
  1439.  
  1440. VOID
  1441. DisplayRenderedPels(hps, fsCmd)
  1442. HPS hps;
  1443. USHORT fsCmd;
  1444. {
  1445.     LINEBUNDLE lb;
  1446.     AREABUNDLE ab;
  1447.     POINTL aptl[3];
  1448.  
  1449.     /*    Call GPI to draw the current primitive into the small bitmap,
  1450.      *    then fatbit it to the display.
  1451.      */
  1452.  
  1453.     if (global.hbmFat)
  1454.     {
  1455.     if (fsCmd & CLEAR_FAT_BITMAP)
  1456.     {
  1457.         /* clear fatpel surface to background color */
  1458.         ab.lColor = global.clrField;
  1459.         GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
  1460.         GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
  1461.     }
  1462.  
  1463.     if (fsCmd & RENDER_MATH_OBJ)
  1464.     {
  1465.         if (global.cptl > 0)
  1466.         {
  1467.         /* draw line */
  1468.         lb.lColor = global.clrRenderedObj;
  1469.         GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
  1470.         GpiSetModelTransformMatrix(global.hpsFat, 9L,
  1471.                       &global.matlf, TRANSFORM_REPLACE);
  1472.         DrawPrimitive(global.hpsFat, global.cptl, global.pptl);
  1473.         GpiSetModelTransformMatrix(global.hpsFat, 0L, NULL, TRANSFORM_REPLACE);
  1474.         }
  1475.     }
  1476.  
  1477.     /* xor the new rendered bitmap into the shadow bitmap */
  1478.     *((PRECTL)&aptl[0]) = global.rclFat;
  1479.     aptl[2].x = 0L;
  1480.     aptl[2].y = 0L;
  1481.     GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCINVERT, NULL);
  1482.  
  1483.     /* fatbit object to the display */
  1484.     DrawFatPels(hps);
  1485.  
  1486.     /* get the new shadow bitmap */
  1487.     GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCCOPY, NULL);
  1488.     }
  1489. }
  1490.  
  1491.  
  1492.  
  1493.  
  1494. /************************************************************************
  1495. *
  1496. *   DrawFatPels
  1497. *
  1498. ************************************************************************/
  1499.  
  1500. VOID
  1501. DrawFatPels(hps)
  1502. HPS hps;
  1503. {
  1504.     POINTL ptl, ptlCenter;
  1505.     LONG i, j;
  1506.     COLOR clr;
  1507.  
  1508.  
  1509.     /* if the pel size is 1,1, then just blt the small bitmap to the
  1510.      * display.
  1511.      */
  1512.  
  1513.     if ((global.cxFatPel == 1L) && (global.cyFatPel == 1L))
  1514.     {
  1515.     POINTL aptl[3];
  1516.  
  1517.     *((PRECTL)&aptl[0]) = global.rcl;
  1518.     aptl[2].x = 0L;
  1519.     aptl[2].y = 0L;
  1520.     GpiBitBlt(hps, global.hpsFat, 3L, aptl, ROP_SRCCOPY, 0L);
  1521.  
  1522.     return;
  1523.     }
  1524.  
  1525.     for (i = 0; i < global.rclFat.xRight; ++i)
  1526.     for (j = 0; j < global.rclFat.yTop; ++j)
  1527.     {
  1528.         ptl.x = i;
  1529.         ptl.y = j;
  1530.  
  1531.         clr = GpiQueryPel(global.hpsFatShadow, &ptl);
  1532.         if ((global.fRGB && (clr != 0x000000L)) ||
  1533.            (!global.fRGB && (clr != global.clrBlackIndex)))
  1534.         {
  1535.         clr = GpiQueryPel(global.hpsFat, &ptl);
  1536.         ptlCenter.x = (i * global.cxFatPel) + global.cxHalfFatPel;
  1537.         ptlCenter.y = (j * global.cyFatPel) + global.cyHalfFatPel;
  1538.         DrawOneFatPel(hps, &ptlCenter, clr);
  1539.         }
  1540.     }
  1541. }
  1542.  
  1543.  
  1544.  
  1545.  
  1546. /************************************************************************
  1547. *
  1548. *   DrawOneFatPel
  1549. *
  1550. ************************************************************************/
  1551.  
  1552. VOID
  1553. DrawOneFatPel(hps, pptl, clr)
  1554. HPS hps;
  1555. PPOINTL pptl;
  1556. COLOR clr;
  1557. {
  1558.     POINTL ptl;
  1559.     LINEBUNDLE lb;
  1560.     AREABUNDLE ab;
  1561.  
  1562.  
  1563.     if (global.fDisplayPelBorder || global.fDisplayCrossHairs)
  1564.     {
  1565.     lb.lColor = global.clrCrossHair;
  1566.     GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  1567.     }
  1568.  
  1569.     ab.lColor = clr;
  1570.     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
  1571.  
  1572.  
  1573.     switch (global.usPelShape)
  1574.     {
  1575.     case IDD_SQUARE:
  1576.     {
  1577.         POINTL ptlT;
  1578.         ULONG flCmd;
  1579.  
  1580.         if (global.fDisplayPelBorder)
  1581.         flCmd = DRO_OUTLINEFILL;
  1582.         else
  1583.         flCmd = DRO_FILL;
  1584.  
  1585.         ptlT.x = pptl->x - global.cxHalfFatPel;
  1586.         ptlT.y = pptl->y - global.cyHalfFatPel;
  1587.         GpiSetCurrentPosition(hps, &ptlT);
  1588.         ptlT.x = pptl->x + global.cxHalfFatPel;
  1589.         ptlT.y = pptl->y + global.cyHalfFatPel;
  1590.         GpiBox(hps, flCmd, &ptlT, 0L, 0L);
  1591.     }
  1592.     break;
  1593.  
  1594.     case IDD_DIAMOND:
  1595.     {
  1596.         POINTL aptlT[4];
  1597.         ULONG flCmd;
  1598.  
  1599.         if (global.fDisplayPelBorder)
  1600.         flCmd = BA_BOUNDARY;
  1601.         else
  1602.         flCmd = 0L;
  1603.  
  1604.         aptlT[0].x = pptl->x;
  1605.         aptlT[0].y = pptl->y - global.cyHalfFatPel;
  1606.         aptlT[1].x = pptl->x - global.cxHalfFatPel;
  1607.         aptlT[1].y = pptl->y;
  1608.         aptlT[2].x = pptl->x;
  1609.         aptlT[2].y = pptl->y + global.cyHalfFatPel;
  1610.         aptlT[3].x = pptl->x + global.cxHalfFatPel;
  1611.         aptlT[3].y = pptl->y;
  1612.  
  1613.         GpiSetCurrentPosition(hps, &aptlT[3]);
  1614.         GpiBeginArea(hps, flCmd);
  1615.         GpiPolyLine(hps, 4L, aptlT);
  1616.         GpiEndArea(hps);
  1617.     }
  1618.  
  1619.     break;
  1620.  
  1621.     case IDD_CIRCLE:
  1622.     {
  1623.         ULONG flCmd;
  1624.  
  1625.         if (global.fDisplayPelBorder)
  1626.         flCmd = DRO_OUTLINEFILL;
  1627.         else
  1628.         flCmd = DRO_FILL;
  1629.  
  1630.         GpiSetCurrentPosition(hps, pptl);
  1631.         GpiFullArc(hps, flCmd, 0x10000L);
  1632.     }
  1633.     break;
  1634.     }
  1635.  
  1636.  
  1637.     if (global.fDisplayCrossHairs)
  1638.     {
  1639.     /* draw cross in center of pel */
  1640.  
  1641.     ptl.x = pptl->x - global.cxHalfFatPel;
  1642.     ptl.y = pptl->y;
  1643.     GpiSetCurrentPosition(hps, &ptl);
  1644.     ptl.x = pptl->x + global.cxHalfFatPel;
  1645.     GpiPolyLine(hps, 1L, &ptl);
  1646.  
  1647.     ptl.x = pptl->x;
  1648.     ptl.y = pptl->y - global.cyHalfFatPel;
  1649.     GpiSetCurrentPosition(hps, &ptl);
  1650.     ptl.y = pptl->y + global.cyHalfFatPel;
  1651.     GpiPolyLine(hps, 1L, &ptl);
  1652.     }
  1653. }
  1654.  
  1655.  
  1656.  
  1657.  
  1658. /************************************************************************
  1659. *
  1660. *   RoundControlPoints
  1661. *
  1662. ************************************************************************/
  1663.  
  1664. VOID
  1665. RoundControlPoints(hps, cptl, pptl1, pptl2, cx, cy)
  1666. HPS hps;
  1667. LONG cptl;
  1668. PPOINTL pptl1;
  1669. PPOINTL pptl2;
  1670. LONG cx;
  1671. LONG cy;
  1672. {
  1673.     LONG cx2, cy2;
  1674.     LONG i;
  1675.     MATRIXLF matlf;
  1676.  
  1677.  
  1678.     /* copy the input buffer to the output/scratch buffer */
  1679.     for (i = 0; i < cptl; ++i)
  1680.     pptl2[i] = pptl1[i];
  1681.  
  1682.  
  1683.     /* set the transform, transform the points to device space (i.e. to
  1684.      * hpsFat dimensions), then restore the original transform
  1685.      */
  1686.     GpiQueryModelTransformMatrix(hps, 9L, &matlf);
  1687.     GpiSetModelTransformMatrix(hps, 9L, &global.matlf, TRANSFORM_REPLACE);
  1688.     GpiConvert(hps, CVTC_WORLD, CVTC_DEVICE, cptl, pptl2);
  1689.     GpiSetModelTransformMatrix(hps, 9L, &matlf, TRANSFORM_REPLACE);
  1690.  
  1691.  
  1692.     /* position each point in the center of its fatpel */
  1693.  
  1694.     cx2 = cx / 2L;
  1695.     cy2 = cy / 2L;
  1696.  
  1697.     for (i = 0; i < cptl; ++i, ++pptl2)
  1698.     {
  1699.     pptl2->x = pptl2->x * cx + cx2;
  1700.     pptl2->y = pptl2->y * cy + cy2;
  1701.     }
  1702. }
  1703.  
  1704.  
  1705.  
  1706.  
  1707. /************************************************************************
  1708. *
  1709. *   ComputeTransform
  1710. *
  1711. ************************************************************************/
  1712.  
  1713. VOID
  1714. ComputeTransform(prcl1, prcl2)
  1715. PRECTL prcl1;
  1716. PRECTL prcl2;
  1717. {
  1718.     LONG xExt1, yExt1;
  1719.     LONG xExt2, yExt2;
  1720.     FIXED xScale, yScale;
  1721.  
  1722.  
  1723.     xExt1 = prcl1->xRight - prcl1->xLeft;
  1724.     yExt1 = prcl1->yTop   - prcl1->yBottom;
  1725.     xExt2 = prcl2->xRight - prcl2->xLeft;
  1726.     yExt2 = prcl2->yTop   - prcl2->yBottom;
  1727.  
  1728.  
  1729.     /* If the rectangles are of exactly the same dimensions, then
  1730.      * set the unity transform.  If not, compute the x and y scale
  1731.      * factors.  Note that in world coordinates rectangles are
  1732.      * inclusive-inclusive, whereas in device coordinates they are
  1733.      * inclusive-exclusive.  The extents of the destination are
  1734.      * therefore one pel too large as computed, so we subtract one
  1735.      * in the scale factor computation.
  1736.      */
  1737.  
  1738.     if (xExt1 == xExt2)
  1739.     xScale = 0x10000L;
  1740.     else
  1741.     xScale = ((xExt2-1L) * 0x10000L) / xExt1;
  1742.  
  1743.     if (yExt1 == yExt2)
  1744.     yScale = 0x10000L;
  1745.     else
  1746.     yScale = ((yExt2-1L) * 0x10000L) / yExt1;
  1747.  
  1748.  
  1749.     /* store the transform matrix for easy access */
  1750.  
  1751.     global.matlf.fxM11 = xScale;
  1752.     global.matlf.fxM12 = 0L;
  1753.     global.matlf. lM13 = 0L;
  1754.     global.matlf.fxM21 = 0L;
  1755.     global.matlf.fxM22 = yScale;
  1756.     global.matlf. lM23 = 0L;
  1757.     global.matlf. lM31 = 0L;
  1758.     global.matlf. lM32 = 0L;
  1759.     global.matlf. lM33 = 1L;
  1760. }
  1761.  
  1762.  
  1763.  
  1764.  
  1765. /************************************************************************
  1766. *
  1767. *   DrawPrimitive
  1768. *
  1769. ************************************************************************/
  1770.  
  1771. VOID
  1772. DrawPrimitive(hps, cptl, pptl)
  1773. HPS hps;
  1774. LONG cptl;
  1775. PPOINTL pptl;
  1776. {
  1777.     switch (global.usCurPrim)
  1778.     {
  1779.     case IDM_NOPRIM:
  1780.     break;
  1781.  
  1782.     case IDM_POLYLINE:
  1783.     GpiSetCurrentPosition(hps, pptl);
  1784.     GpiPolyLine(hps, cptl-1L, pptl + 1);
  1785.     break;
  1786.  
  1787.     case IDM_POLYFILLET:
  1788.     if (cptl >= 3L)
  1789.     {
  1790.         GpiSetCurrentPosition(hps, pptl);
  1791.         GpiPolyFillet(hps, cptl-1L, pptl + 1);
  1792.     }
  1793.     break;
  1794.  
  1795.     case IDM_POLYSPLINE:
  1796.     if (cptl >= 4L)
  1797.     {
  1798.         LONG cptSlack;    /* # points in pptl not usable by PolySpline */
  1799.  
  1800.         cptSlack = ((cptl-1L) % 3) + 1;
  1801.         GpiSetCurrentPosition( hps, pptl );
  1802.         GpiPolySpline( hps, cptl-cptSlack, pptl+1 );
  1803.     }
  1804.     break;
  1805.  
  1806.     case IDM_POINTARC:
  1807.     if (cptl >= 3L)
  1808.     {
  1809.         GpiSetCurrentPosition( hps, pptl );
  1810.         GpiPointArc( hps, pptl+1 );
  1811.     }
  1812.     break;
  1813.     }
  1814. }
  1815.  
  1816.  
  1817.  
  1818.  
  1819. /************************************************************************
  1820. *
  1821. *   UpdateSurfaceDims
  1822. *
  1823. ************************************************************************/
  1824.  
  1825. VOID
  1826. UpdateSurfaceDims()
  1827. {
  1828.     SIZEL size;
  1829.     BITMAPINFOHEADER bminfo;
  1830.     AREABUNDLE ab;
  1831.  
  1832.  
  1833.     WinQueryWindowRect(global.hwnd, &global.rcl);
  1834.  
  1835.     /* compute size of small surface */
  1836.     global.rclFat.xLeft   = 0L;
  1837.     global.rclFat.yBottom = 0L;
  1838.     global.rclFat.xRight  = global.rcl.xRight / global.cxFatPel;
  1839.     global.rclFat.yTop      = global.rcl.yTop   / global.cyFatPel;
  1840.  
  1841.     /* compute size of fatpel version of small surface */
  1842.     global.rcl.xLeft   = 0L;
  1843.     global.rcl.yBottom = 0L;
  1844.     global.rcl.xRight  = global.rclFat.xRight * global.cxFatPel;
  1845.     global.rcl.yTop    = global.rclFat.yTop   * global.cyFatPel;
  1846.  
  1847.     ComputeTransform(&global.rcl, &global.rclFat);
  1848.  
  1849.     if ((global.rclFat.xRight <= global.rclFatBM.xRight) &&
  1850.     (global.rclFat.yTop   <= global.rclFatBM.yTop))
  1851.     return;
  1852.  
  1853.  
  1854.  
  1855.     /* The new fatbits surface doesn't fit in the bitmap, so we
  1856.      * have to make a new one.    If we don't have a DC or PS, make
  1857.      * those before making the bitmap.    If we do have a bitmap,
  1858.      * delete it before making the new one.
  1859.      */
  1860.  
  1861.     global.rclFatBM = global.rclFat;
  1862.  
  1863.     if (global.hbmFat)
  1864.     {
  1865.     GpiSetBitmap(global.hpsFat, NULL);
  1866.     GpiDeleteBitmap(global.hbmFat);
  1867.     GpiSetBitmap(global.hpsFatShadow, NULL);
  1868.     GpiDeleteBitmap(global.hbmFatShadow);
  1869.     }
  1870.  
  1871.     if (!global.hdcFat)
  1872.     {
  1873.     global.hdcFat = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
  1874.     if (!global.hdcFat)
  1875.         goto usd_error;
  1876.  
  1877.     global.hdcFatShadow = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
  1878.     if (!global.hdcFatShadow)
  1879.         goto usd_error;
  1880.     }
  1881.  
  1882.     if (!global.hpsFat)
  1883.     {
  1884.     size.cx = 0L;
  1885.     size.cy = 0L;
  1886.     global.hpsFat = GpiCreatePS(global.hab, global.hdcFat, &size,
  1887.                  PU_PELS|GPIT_MICRO|GPIA_ASSOC);
  1888.     if (!global.hpsFat)
  1889.         goto usd_error;
  1890.  
  1891.     global.hpsFatShadow = GpiCreatePS(global.hab, global.hdcFatShadow, &size,
  1892.                  PU_PELS|GPIT_MICRO|GPIA_ASSOC);
  1893.     if (!global.hpsFatShadow)
  1894.         goto usd_error;
  1895.     }
  1896.  
  1897.     /* create bitmap with maximum color resolution (24-bit color) */
  1898.     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  1899.     bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
  1900.     bminfo.cy = (USHORT) (global.rclFatBM.yTop     - global.rclFatBM.yBottom);
  1901.     bminfo.cPlanes   = 1L;
  1902.     bminfo.cBitCount = 24L;
  1903.     global.hbmFat = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L);
  1904.     if (!global.hbmFat)
  1905.     goto usd_error;
  1906.     GpiSetBitmap(global.hpsFat, global.hbmFat);
  1907.  
  1908.     /* create a shadow bitmap of the one we just created */
  1909.     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  1910.     bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
  1911.     bminfo.cy = (USHORT) (global.rclFatBM.yTop     - global.rclFatBM.yBottom);
  1912.     bminfo.cPlanes   = 1L;
  1913.     bminfo.cBitCount = 24L;
  1914.     global.hbmFatShadow = GpiCreateBitmap(global.hpsFatShadow, &bminfo, 0L, 0L, 0L);
  1915.     if (!global.hbmFat)
  1916.     goto usd_error;
  1917.     GpiSetBitmap(global.hpsFatShadow, global.hbmFatShadow);
  1918.  
  1919.     /* clear bitmap surface to field color */
  1920.     ab.lColor = global.clrField;
  1921.     GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
  1922.     GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
  1923.  
  1924.     return;
  1925.  
  1926.  
  1927. /* error exit point */
  1928.  
  1929. usd_error:
  1930.     if (global.hpsFat)
  1931.     GpiDestroyPS(global.hpsFat);
  1932.     if (global.hpsFatShadow)
  1933.     GpiDestroyPS(global.hpsFatShadow);
  1934.     if (global.hdcFat)
  1935.     DevCloseDC(global.hdcFat);
  1936.     if (global.hdcFatShadow)
  1937.     DevCloseDC(global.hdcFatShadow);
  1938.  
  1939.     global.hpsFat    = NULL;
  1940.     global.hdcFat    = NULL;
  1941.     global.hpsFatShadow = NULL;
  1942.     global.hdcFatShadow = NULL;
  1943. }
  1944.  
  1945.  
  1946.  
  1947.  
  1948. /************************************************************************
  1949. *
  1950. *   AboutDlg
  1951. *
  1952. *   Process messages for the About box.
  1953. *
  1954. ************************************************************************/
  1955.  
  1956. ULONG CALLBACK
  1957. AboutDlg(hwnd, usMsg, mp1, mp2)
  1958. HWND   hwnd;
  1959. USHORT usMsg;
  1960. MPARAM mp1;
  1961. MPARAM mp2;
  1962. {
  1963.     switch (usMsg)
  1964.     {
  1965.     case WM_COMMAND:
  1966.     if (SHORT1FROMMP(mp1) == DID_OK)
  1967.         WinDismissDlg(hwnd, TRUE);
  1968.     else
  1969.         return FALSE;
  1970.     break;
  1971.  
  1972.     default:
  1973.     return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  1974.     }
  1975.     return FALSE;
  1976. }
  1977.  
  1978.  
  1979.  
  1980.  
  1981. /************************************************************************
  1982. *
  1983. *   PelSizeDlg
  1984. *
  1985. *   Process messages for the Pel Size dialog box.
  1986. *
  1987. ************************************************************************/
  1988.  
  1989. ULONG CALLBACK
  1990. PelSizeDlg(hwnd, usMsg, mp1, mp2)
  1991. HWND   hwnd;
  1992. USHORT usMsg;
  1993. MPARAM mp1;
  1994. MPARAM mp2;
  1995. {
  1996.     BOOL fRet = FALSE;
  1997.  
  1998.     switch (usMsg)
  1999.     {
  2000.     case WM_INITDLG:
  2001.     MySetWindowLong(hwnd, IDD_PELWIDTH,  global.cxFatPel);
  2002.     MySetWindowLong(hwnd, IDD_PELHEIGHT, global.cyFatPel);
  2003.     WinSendDlgItemMsg(hwnd, global.usPelShape,
  2004.               BM_SETCHECK, (MPARAM)TRUE, 0L);
  2005.     return FALSE;
  2006.     break;
  2007.  
  2008.     case WM_COMMAND:
  2009.     switch (SHORT1FROMMP(mp1))
  2010.     {
  2011.     case IDD_OK:
  2012.         global.cxFatPel = MyGetWindowLong(hwnd, IDD_PELWIDTH);
  2013.         global.cyFatPel = MyGetWindowLong(hwnd, IDD_PELHEIGHT);
  2014.  
  2015.         if (global.cxFatPel < 1L)
  2016.         global.cxFatPel = 1L;
  2017.  
  2018.         if (global.cyFatPel < 1L)
  2019.         global.cyFatPel = 1L;
  2020.  
  2021.         global.cxHalfFatPel = global.cxFatPel / 2L;
  2022.         global.cyHalfFatPel = global.cyFatPel / 2L;
  2023.  
  2024.         global.usPelShape = (USHORT) WinSendDlgItemMsg(hwnd, IDD_SQUARE,
  2025.                    BM_QUERYCHECKINDEX, 0L, 0L) + IDD_SQUARE;
  2026.  
  2027.  
  2028.         UpdateSurfaceDims();
  2029.  
  2030.         fRet = TRUE;
  2031.  
  2032.         /* fall through to some common code */
  2033.  
  2034.     case IDD_CANCEL:
  2035.         WinDismissDlg(hwnd, fRet);
  2036.         break;
  2037.  
  2038.     default:
  2039.         return FALSE;
  2040.     }
  2041.     break;
  2042.  
  2043.     default:
  2044.     return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  2045.     }
  2046.     return FALSE;
  2047. }
  2048.  
  2049.  
  2050.  
  2051.  
  2052. /************************************************************************
  2053. *
  2054. *   ColorsDlg
  2055. *
  2056. *   Process messages for the Set Colors dialog box.
  2057. *
  2058. ************************************************************************/
  2059.  
  2060. ULONG CALLBACK
  2061. ColorsDlg(hwnd, usMsg, mp1, mp2)
  2062. HWND   hwnd;
  2063. USHORT usMsg;
  2064. MPARAM mp1;
  2065. MPARAM mp2;
  2066. {
  2067.     BOOL fRet = FALSE;
  2068.     BOOL fRGB;
  2069.     COLOR clrMathObj;
  2070.     COLOR clrRenderedObj;
  2071.     COLOR clrField;
  2072.     COLOR clrCrossHair;
  2073.     COLOR clrInterstice;
  2074.     COLOR clrControlPoints;
  2075.  
  2076.     switch (usMsg)
  2077.     {
  2078.     case WM_INITDLG:
  2079.     if (global.fRGB)
  2080.     {
  2081.         MySetWindowLongHex(hwnd, IDD_MATHOBJ,     global.clrMathObj);
  2082.         MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
  2083.         MySetWindowLongHex(hwnd, IDD_FIELD,         global.clrField);
  2084.         MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
  2085.         MySetWindowLongHex(hwnd, IDD_INTERSTICE,  global.clrInterstice);
  2086.         MySetWindowLongHex(hwnd, IDD_CTLPOINTS,   global.clrControlPoints);
  2087.     }
  2088.     else
  2089.     {
  2090.         MySetWindowLong   (hwnd, IDD_MATHOBJ,     global.clrMathObj);
  2091.         MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
  2092.         MySetWindowLong   (hwnd, IDD_FIELD,         global.clrField);
  2093.         MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
  2094.         MySetWindowLong   (hwnd, IDD_INTERSTICE,  global.clrInterstice);
  2095.         MySetWindowLong   (hwnd, IDD_CTLPOINTS,   global.clrControlPoints);
  2096.     }
  2097.     WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(global.fRGB,0), 0L);
  2098.     return FALSE;
  2099.     break;
  2100.  
  2101.     case WM_CONTROL:
  2102.     if ((SHORT1FROMMP(mp1) == IDD_RGB) && (SHORT2FROMMP(mp1)== BN_CLICKED))
  2103.     {
  2104.         fRGB = !(SHORT)WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QUERYCHECK, 0L, 0L);
  2105.         WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(fRGB,0), 0L);
  2106.  
  2107.         clrMathObj         = MyGetWindowLong(hwnd, IDD_MATHOBJ);
  2108.         clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
  2109.         clrField         = MyGetWindowLong(hwnd, IDD_FIELD);
  2110.         clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
  2111.         clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
  2112.         clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
  2113.  
  2114.         if (fRGB)
  2115.         {
  2116.         HPS hps;
  2117.  
  2118.         /* for each color, get rgb value from index */
  2119.  
  2120.         hps = WinGetPS(hwnd);
  2121.  
  2122.         clrMathObj     = GpiQueryRGBColor(hps, 0L, clrMathObj);
  2123.         clrRenderedObj     = GpiQueryRGBColor(hps, 0L, clrRenderedObj);
  2124.         clrField     = GpiQueryRGBColor(hps, 0L, clrField);
  2125.         clrCrossHair     = GpiQueryRGBColor(hps, 0L, clrCrossHair);
  2126.         clrInterstice     = GpiQueryRGBColor(hps, 0L, clrInterstice);
  2127.         clrControlPoints = GpiQueryRGBColor(hps, 0L, clrControlPoints);
  2128.  
  2129.         WinReleasePS(hps);
  2130.  
  2131.         MySetWindowLongHex(hwnd, IDD_MATHOBJ,     clrMathObj);
  2132.         MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
  2133.         MySetWindowLongHex(hwnd, IDD_FIELD,     clrField);
  2134.         MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  clrCrossHair);
  2135.         MySetWindowLongHex(hwnd, IDD_INTERSTICE,  clrInterstice);
  2136.         MySetWindowLongHex(hwnd, IDD_CTLPOINTS,     clrControlPoints);
  2137.         }
  2138.         else
  2139.         {
  2140.         HPS hps;
  2141.  
  2142.         /* for each color, get nearest index value from rgb */
  2143.  
  2144.         hps = WinGetPS(hwnd);
  2145.  
  2146.         clrMathObj     = GpiQueryColorIndex(hps, 0L, clrMathObj);
  2147.         clrRenderedObj     = GpiQueryColorIndex(hps, 0L, clrRenderedObj);
  2148.         clrField     = GpiQueryColorIndex(hps, 0L, clrField);
  2149.         clrCrossHair     = GpiQueryColorIndex(hps, 0L, clrCrossHair);
  2150.         clrInterstice     = GpiQueryColorIndex(hps, 0L, clrInterstice);
  2151.         clrControlPoints = GpiQueryColorIndex(hps, 0L, clrControlPoints);
  2152.  
  2153.         WinReleasePS(hps);
  2154.  
  2155.         MySetWindowLong   (hwnd, IDD_MATHOBJ,     clrMathObj);
  2156.         MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
  2157.         MySetWindowLong   (hwnd, IDD_FIELD,     clrField);
  2158.         MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  clrCrossHair);
  2159.         MySetWindowLong   (hwnd, IDD_INTERSTICE,  clrInterstice);
  2160.         MySetWindowLong   (hwnd, IDD_CTLPOINTS,     clrControlPoints);
  2161.         }
  2162.     }
  2163.     return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  2164.     break;
  2165.  
  2166.     case WM_COMMAND:
  2167.     switch (SHORT1FROMMP(mp1))
  2168.     {
  2169.     case IDD_OK:
  2170.         global.clrMathObj        = MyGetWindowLong(hwnd, IDD_MATHOBJ);
  2171.         global.clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
  2172.         global.clrField        = MyGetWindowLong(hwnd, IDD_FIELD);
  2173.         global.clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
  2174.         global.clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
  2175.         global.clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
  2176.  
  2177.         global.fRGB = (SHORT)WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QUERYCHECK, 0L, 0L);
  2178.  
  2179.         fRet = TRUE;
  2180.  
  2181.         /* fall through to some common code */
  2182.  
  2183.     case IDD_CANCEL:
  2184.         WinDismissDlg(hwnd, fRet);
  2185.         break;
  2186.  
  2187.     default:
  2188.         return FALSE;
  2189.     }
  2190.     break;
  2191.  
  2192.     default:
  2193.     return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  2194.     }
  2195.     return FALSE;
  2196. }
  2197.  
  2198.  
  2199.  
  2200.  
  2201. /************************************************************************
  2202. *
  2203. *   MySetWindowLong
  2204. *
  2205. *   Sets the given control id to the value specified.
  2206. *
  2207. ************************************************************************/
  2208.  
  2209. VOID
  2210. MySetWindowLong(hWnd, id, num)
  2211. HWND hWnd;
  2212. USHORT id;
  2213. LONG num;
  2214. {
  2215.     char szStr[CCHSTR];
  2216.  
  2217.     sprintf((NPCH)szStr, "%ld", num);
  2218.     WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
  2219. }
  2220.  
  2221.  
  2222.  
  2223.  
  2224. /************************************************************************
  2225. *
  2226. *   MySetWindowLongHex
  2227. *
  2228. *   Sets the given control id to the value specified, in hexadecimal
  2229. *   notation.
  2230. *
  2231. ************************************************************************/
  2232.  
  2233. VOID
  2234. MySetWindowLongHex(hWnd, id, num)
  2235. HWND hWnd;
  2236. USHORT id;
  2237. LONG num;
  2238. {
  2239.     char szStr[CCHSTR];
  2240.  
  2241.     sprintf((NPCH)szStr, "0x%06lX", num);
  2242.     WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
  2243. }
  2244.  
  2245.  
  2246.  
  2247.  
  2248. /************************************************************************
  2249. *
  2250. *   MyGetWindowLong
  2251. *
  2252. *   Returns the value from the given control id.
  2253. *
  2254. ************************************************************************/
  2255.  
  2256. LONG
  2257. MyGetWindowLong(hWnd, id)
  2258. HWND hWnd;
  2259. USHORT id;
  2260. {
  2261.     char szStr[CCHSTR];
  2262.     LONG num;
  2263.  
  2264.     WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
  2265.  
  2266.     if (strchr(szStr, 'x'))
  2267.     sscanf((NPCH)szStr, "0x%lx", &num);
  2268.     else if (strchr(szStr, 'X'))
  2269.     sscanf((NPCH)szStr, "0X%lx", &num);
  2270.     else
  2271.     sscanf((NPCH)szStr, "%ld", &num);
  2272.  
  2273.     return num;
  2274. }
  2275.  
  2276.  
  2277.  
  2278.  
  2279. /************************************************************************
  2280. *
  2281. *   SaveWindowToFile
  2282. *
  2283. *   Copy the bits from the client rectangle (actually, just the fatpel
  2284. *   area) into a bitmap, then save that bitmap.
  2285. *
  2286. ************************************************************************/
  2287.  
  2288. VOID
  2289. SaveWindowToFile(hwnd)
  2290. HWND hwnd;
  2291. {
  2292.     BITMAPINFOHEADER bminfo;
  2293.     HBITMAP hbm;
  2294.     HPS hps;
  2295.     POINTL aptl[3];
  2296.  
  2297.     /* create bitmap in display's favorite format */
  2298.     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  2299.     bminfo.cx = (USHORT) (global.rcl.xRight - global.rcl.xLeft);
  2300.     bminfo.cy = (USHORT) (global.rcl.yTop   - global.rcl.yBottom);
  2301.     bminfo.cPlanes   = 0L;
  2302.     bminfo.cBitCount = 0L;
  2303.     if (hbm = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L))
  2304.     {
  2305.     /* select it into the small bitmap's PS */
  2306.     GpiSetBitmap(global.hpsFat, hbm);
  2307.  
  2308.     /* GpiBitBlt from the window to the bitmap */
  2309.     hps = WinGetPS(hwnd);
  2310.  
  2311.     *((PRECTL)&aptl[0]) = global.rcl;
  2312.     aptl[2].x = 0L;
  2313.     aptl[2].y = 0L;
  2314.     GpiBitBlt(global.hpsFat, hps, 3L, aptl, ROP_SRCCOPY, 0L);
  2315.  
  2316.     WinReleasePS(hps);
  2317.  
  2318.     /* save the bitmap */
  2319.     WriteFile(hwnd, global.hpsFat);
  2320.     }
  2321.  
  2322.     /* deselect the bitmap and delete it */
  2323.     GpiSetBitmap(global.hpsFat, global.hbmFat);
  2324.     if (hbm)
  2325.     GpiDeleteBitmap(hbm);
  2326. }
  2327.  
  2328.  
  2329.  
  2330.  
  2331. /************************************************************************
  2332. *
  2333. *   WriteFile
  2334. *
  2335. *   Calls the OpenDlg's DlgFile function to ask the user what file name to
  2336. *   save under.
  2337. *
  2338. ************************************************************************/
  2339.  
  2340. VOID
  2341. WriteFile(hwnd, hps)
  2342. HWND hwnd;
  2343. HPS hps;
  2344. {
  2345.     HFILE hfile;
  2346.     DLF dlf;
  2347.     BITMAPINFOHEADER bmih;
  2348.  
  2349.     dlf.rgbAction    = DLG_SAVEDLG;
  2350.     dlf.rgbFlags    = 0;
  2351.     dlf.phFile        = &hfile;
  2352.     dlf.pszExt        = "";
  2353.     dlf.pszAppName    = "FatPel";
  2354.     dlf.pszInstructions = NULL;
  2355.     dlf.szFileName[0]    = '\0';
  2356.     dlf.szOpenFile[0]    = '\0';
  2357.     dlf.pszTitle    = "Save Bitmap";
  2358.  
  2359.  
  2360.     switch (DlgFile(hwnd,&dlf))
  2361.     {
  2362.     case TDF_ERRMEM:
  2363.     case TDF_INVALID:
  2364.     MyMessageBox(hwnd, "Error opening file.");
  2365.     break;
  2366.  
  2367.     case TDF_NOSAVE:
  2368.     break;
  2369.  
  2370.     default:
  2371.     bmih.cbFix     = sizeof(BITMAPINFOHEADER);
  2372.     bmih.cx        = (USHORT) global.rcl.xRight;
  2373.     bmih.cy        = (USHORT) global.rcl.yTop;
  2374.     bmih.cPlanes   = 0L;
  2375.     bmih.cBitCount = 0L;
  2376.  
  2377.     if (!WriteBMP(hfile, hps, &bmih))
  2378.         MyMessageBox(hwnd, "Error writing file.");
  2379.     }
  2380. }
  2381.  
  2382.  
  2383.  
  2384.  
  2385. /************************************************************************
  2386. *
  2387. *   WriteBMP
  2388. *
  2389. *   Write the bitmap out to a BMP format file.    Write the file
  2390. *   header first, then the bitmap bits.  Space for the header
  2391. *   and the bits is allocated.    Huge bitmaps are supported.
  2392. *   Free up memory and close the file before leaving.  The file
  2393. *   will have been opened by the time this function is called,
  2394. *   and the file handle will be in the *pdlf structure.
  2395. *
  2396. ************************************************************************/
  2397.  
  2398. BOOL
  2399. WriteBMP(hfile, hps, pbmih)
  2400. HFILE hfile;
  2401. HPS hps;         /* hps from which to get bitmap bits.       */
  2402. PBITMAPINFOHEADER pbmih; /* Bitmap information.            */
  2403. {
  2404.     ULONG cScans;
  2405.     ULONG ulSize;     /* Number of bytes occupied by bitmap bits.         */
  2406.     USHORT cSegs;     /* Number of 64K segments in ulSize.             */
  2407.     USHORT cbExtra;     /* Bytes in last segment of ulSize.             */
  2408.     SEL selBits;     /* Base selector to bitmap bits.             */
  2409.     USHORT hugeshift;     /* Segment index shift value.                 */
  2410.     USHORT cbBMHdr;     /* Size of bitmap header.                 */
  2411.     PBITMAPFILEHEADER pbfh; /* Pointer to private copy of bitmap info data.    */
  2412.     USHORT cbWrite1;     /* Number of bytes to write first call to DosWrite  */
  2413.     USHORT cbWrite2;     /* Number of bytes to write second call to DosWrite */
  2414.     USHORT cbWritten;     /* Number of bytes written by DosWrite.         */
  2415.     BOOL fRet = FALSE;     /* Function return code.                 */
  2416.     int i;         /* Generic loop index.                  */
  2417.     struct
  2418.     {
  2419.     LONG cPlanes;
  2420.     LONG cBitCount;
  2421.     } bmFmt;
  2422.  
  2423.  
  2424.     /*******************************************************************
  2425.     * If the bitmap was created with either 0 planes or 0 bits per
  2426.     * pixel, then query the format to write with.  By asking for just
  2427.     * one format (two LONGs, or one instance of structure of bmFmt),
  2428.     * we'll get the device's favored format.
  2429.     *******************************************************************/
  2430.  
  2431.     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount == 0))
  2432.     {
  2433.     if (!GpiQueryDeviceBitmapFormats(hps, 2L, (PLONG)&bmFmt))
  2434.         goto lfwrite_error_close_file;
  2435.     }
  2436.     else
  2437.     {
  2438.     bmFmt.cPlanes    = pbmih->cPlanes;
  2439.     bmFmt.cBitCount = pbmih->cBitCount;
  2440.     }
  2441.  
  2442.  
  2443.     /*******************************************************************
  2444.     * Determine size of bitmap header.    The header consists of a
  2445.     * a fixed-size part and a variable-length color table.  The
  2446.     * latter has  2^cBitCount  entries, each of which is sizeof(RGB)
  2447.     * bytes long.  The exception is when cBitCount is 24, in which
  2448.     * case the color table is omitted because the pixels are direct
  2449.     * rgb values.
  2450.     *******************************************************************/
  2451.  
  2452.     i = (int) bmFmt.cBitCount;
  2453.     if (i == 24)
  2454.     cbBMHdr = 0;
  2455.     else
  2456.     for (cbBMHdr = sizeof(RGB); i > 0; --i)
  2457.         cbBMHdr *= 2;
  2458.     cbBMHdr += sizeof(BITMAPFILEHEADER);
  2459.  
  2460.  
  2461.     /*******************************************************************
  2462.     * Copy structure from input to work buffer.  The call to
  2463.     * GpiQueryBitmapBits will have write-access to this, so we won't
  2464.     * let it have the user's data.
  2465.     *******************************************************************/
  2466.  
  2467.     pbfh = 0;
  2468.     if (DosAllocSeg(cbBMHdr, ((PUSHORT)&pbfh)+1, 0))
  2469.     goto lfwrite_error_close_file;
  2470.     pbfh->bmp = *pbmih;
  2471.     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
  2472.     {
  2473.     pbfh->bmp.cPlanes   = (USHORT) bmFmt.cPlanes;
  2474.     pbfh->bmp.cBitCount = (USHORT) bmFmt.cBitCount;
  2475.     }
  2476.  
  2477.  
  2478.     /*******************************************************************
  2479.     * Allocate space for the bitmap bits -- all of them at once.
  2480.     * The extra ULONG casts are there to force all the arithmetic
  2481.     * to be done in 32 bits.
  2482.     *******************************************************************/
  2483.  
  2484.     ulSize = (
  2485.            (
  2486.          (
  2487.            (ULONG)pbfh->bmp.cBitCount
  2488.            * (ULONG)pbfh->bmp.cx
  2489.            + 31L
  2490.          ) / 32L
  2491.            ) * (ULONG)pbfh->bmp.cPlanes * 4L
  2492.          ) * (ULONG)pbfh->bmp.cy;
  2493.  
  2494.     cSegs   = (USHORT)(ulSize/0x10000L);
  2495.     cbExtra = (USHORT)(ulSize%0x10000L);
  2496.     if (DosAllocHuge(cSegs, cbExtra, (PSEL)&selBits, 0, 0))
  2497.     goto lfwrite_error_free_header;
  2498.     if (DosGetHugeShift(&hugeshift))
  2499.     goto lfwrite_error_free_bits;
  2500.  
  2501.  
  2502.     /*******************************************************************
  2503.     * Tell GPI to give us the bits. The function returns the number
  2504.     * of scan lines of the bitmap that were copied.  We want all of
  2505.     * them at once.
  2506.     *******************************************************************/
  2507.  
  2508.     cScans = GpiQueryBitmapBits( hps
  2509.                    , 0L
  2510.                    , (ULONG)pbfh->bmp.cy
  2511.                    , (PBYTE)MAKEP(selBits, 0)
  2512.                    , (PBITMAPINFO)&pbfh->bmp);
  2513.     if (cScans != pbfh->bmp.cy)  /* compare with original number of scans */
  2514.     goto lfwrite_error_free_bits;
  2515.  
  2516.  
  2517.     /*******************************************************************
  2518.     * Fill in the extra header fields and write the header out to
  2519.     * the file.
  2520.     *******************************************************************/
  2521.  
  2522.     pbfh->usType    = 0x4D42;          /* 'MB' */
  2523.     pbfh->cbSize    = ulSize + cbBMHdr;
  2524.     pbfh->xHotspot  = pbfh->bmp.cx / 2;
  2525.     pbfh->yHotspot  = pbfh->bmp.cy / 2;
  2526.     pbfh->offBits   = cbBMHdr;
  2527.  
  2528.     if (DosWrite( hfile
  2529.         , (PVOID)pbfh
  2530.         , cbBMHdr
  2531.         , &cbWritten))
  2532.     goto lfwrite_error_free_bits;
  2533.     if (cbWritten != cbBMHdr)
  2534.     goto lfwrite_error_free_bits;
  2535.  
  2536.  
  2537.     /*******************************************************************
  2538.     * Write the bits out to the file. The DosWrite function allows a
  2539.     * maximum of 64K-1 bytes written at a time.  We get around this
  2540.     * by writing two 32K chunks for each 64K segment, and writing the
  2541.     * last segment in one piece.
  2542.     *******************************************************************/
  2543.  
  2544.     for (i = 0; i <= cSegs; ++i)
  2545.     {
  2546.     if (i < cSegs)
  2547.     {
  2548.         /* This segment is 64K bytes long, so split it up. */
  2549.         cbWrite1 = 0x8000;
  2550.         cbWrite2 = 0x8000;
  2551.     }
  2552.     else
  2553.     {
  2554.         /* This segment is less than 64K bytes long, so write it all. */
  2555.         cbWrite1 = cbExtra;
  2556.         cbWrite2 = 0;
  2557.     }
  2558.  
  2559.     /* There's a possibility that cbExtra will be 0, so check
  2560.      * to avoid an unnecessary system call.
  2561.      */
  2562.     if (cbWrite1 > 0)
  2563.     {
  2564.         if (DosWrite( hfile
  2565.             , (PVOID)MAKEP(selBits+(i<<hugeshift), 0)
  2566.             , cbWrite1
  2567.             , &cbWritten))
  2568.         goto lfwrite_error_free_bits;
  2569.         if (cbWrite1 != cbWritten)
  2570.         goto lfwrite_error_free_bits;
  2571.     }
  2572.  
  2573.     /* This will always be skipped on the last partial segment. */
  2574.     if (cbWrite2 > 0)
  2575.     {
  2576.         if (DosWrite( hfile
  2577.             , (PVOID)MAKEP(selBits+(i<<hugeshift), cbWrite1)
  2578.             , cbWrite2
  2579.             , &cbWritten))
  2580.         goto lfwrite_error_free_bits;
  2581.         if (cbWrite2 != cbWritten)
  2582.         goto lfwrite_error_free_bits;
  2583.     }
  2584.     }
  2585.  
  2586.     fRet = TRUE;     /* The bits are on the disk. */
  2587.  
  2588.  
  2589.     /*******************************************************************
  2590.     * Close the file, free the buffer space and leave.    This is a
  2591.     * common exit point from the function.  Since the same cleanup
  2592.     * operations need to be performed for such a large number of
  2593.     * possible error conditions, this is concise way to do the right
  2594.     * thing.
  2595.     *******************************************************************/
  2596.  
  2597. lfwrite_error_free_bits:
  2598.     DosFreeSeg(selBits);
  2599. lfwrite_error_free_header:
  2600.     DosFreeSeg(*((PUSHORT)&pbfh+1));
  2601. lfwrite_error_close_file:
  2602.     DosClose(hfile);
  2603.     return fRet;
  2604. }
  2605.  
  2606.  
  2607.  
  2608.  
  2609. /************************************************************************
  2610. *
  2611. *   MyMessageBox
  2612. *
  2613. *   Displays a message box with the given string.  To simplify matters,
  2614. *   the box will always have the same title ("FatPel"), will always
  2615. *   have a single button ("Ok"), will always have an exclamation point
  2616. *   icon, and will always be application modal.
  2617. *
  2618. ************************************************************************/
  2619.  
  2620. VOID
  2621. MyMessageBox(hWnd, sz)
  2622. HWND hWnd;
  2623. PSZ sz;
  2624. {
  2625.     static char *szTitle = "FatPel Application";
  2626.  
  2627.     WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, NULL,
  2628.           MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
  2629. }
  2630.