Annotation of pmsdk/samples/fatpel/fatpel.c, revision 1.1.1.1

1.1       root        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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.