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

unix.superglobalmegacorp.com

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