Sources/PickMeshShapePartShell.c

// PickMeshShapePartShell.c
//
// This is MeshShapePartPick, an adaptation of box, the QuickDraw 3D starter program,
// written by Nick Thompson.
// modifed by Robert Dierkes for an example of mesh shape part picking.
// 
// ©1994-95 Apple computer Inc., All Rights Reserved
//
 
// system headers
#include <Fonts.h>
#include <Menus.h>
#include <DiskInit.h>
#include <ToolUtils.h>
 
 
#include "PickMeshShapePart.h"
#include "PickMeshShapePartSupport.h"
 
 
//-------------------------------------------------------------------------------------------
// function prototypes
 
void InitDocumentData(
    DocumentPtr theDocument);
 
void DisposeDocumentData(
    DocumentPtr theDocument);
 
void InitToolbox(
    void);
 
void InitMenuItems(
    DocumentPtr theDocument);
 
void MainEventLoop(
    void);
 
void HandleKeyPress(
    EventRecord *event);
 
void HandleMenuCommand(
    long    result);
 
 
//-------------------------------------------------------------------------------------------
//
 
Boolean         gQuitFlag   = false;
WindowPtr       gMainWindow = nil;
DocumentRec     gDocument;
 
 
//-------------------------------------------------------------------------------------------
// main()
// entry point for the application, initialize the toolbox, initialize QuickDraw 3D
// and enter the main event loop.  On exit from the main event loop, we want to call
// the QuickDraw 3D exit function to clean up QuickDraw 3d.
 
void main(
    void)
{
    Rect    windowBounds = { 50, 50, 350, 350 };
    Str255  title = "\pMesh ShapePart Picking";
 
    InitToolbox();
 
    //  Initialize QuickDraw 3D, open a connection to the QuickDraw 3D library
    if(Q3Initialize() == kQ3Failure) {
        debugstr("Q3Initialize returned failure.");
        return;
    }
 
    // set up our globals
    gQuitFlag  = false;
    gMainWindow = NewCWindow(nil, &windowBounds, title, true, noGrowDocProc, (WindowPtr)-1, true, 0);
    InitDocumentData(&gDocument);
    InitMenuItems(&gDocument);
    InitPicking();
 
    MainEventLoop();
    
    ExitPicking();
    DisposeDocumentData(&gDocument);
    
    //  Close our connection to the QuickDraw 3D library
    if(Q3Exit() == kQ3Failure)
        debugstr("Q3Exit returned failure.");
}
 
//-------------------------------------------------------------------------------------------
//
 
static
void InitDocumentData(
    DocumentPtr theDocument) 
{
    // sets up the 3d data for the scene
    // Create view for QuickDraw 3D.
    theDocument->fView = MyNewView((WindowPtr)gMainWindow);
 
    // the main display group:
    theDocument->fModel = MyNewModel();
 
    // the drawing styles:
    theDocument->fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleVertex);
    theDocument->fBackFacing    = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth);
    theDocument->fFillStyle     = Q3FillStyle_New(kQ3FillStyleFilled);
    theDocument->fPickPartStyle = Q3PickPartsStyle_New(theDocument->fPickParts);
 
    theDocument->fPickParts = kQ3PickPartsObject;
 
    // Add fPickPartStyle to the model as the first object before the geometry
    if (theDocument->fPickPartStyle != NULL) {
        TQ3GroupPosition    firstPosition;
 
        if (Q3Group_GetFirstPosition(theDocument->fModel, &firstPosition) == kQ3Success  &&
            firstPosition != NULL) {
 
            // Add the fPickPartStyle to the beginning of the fModel group
            Q3Group_AddObjectBefore(theDocument->fModel, firstPosition, theDocument->fPickPartStyle);
 
            // Dispose our 2nd reference to the style now that it's added
            // to the group but this reference can still be used when the
            // application wants to set pick parts style other part values.
            Q3Object_Dispose(theDocument->fPickPartStyle);
        }
    }
}
 
 
static
void DisposeDocumentData(
    DocumentPtr theDocument)
{
    Q3Object_Dispose(theDocument->fView);           // the view for the scene
    Q3Object_Dispose(theDocument->fModel);          // object in the scene being modelled
    Q3Object_Dispose(theDocument->fInterpolation);  // interpolation style used when rendering
    Q3Object_Dispose(theDocument->fBackFacing);     // whether to draw shapes that face away from the camera
    Q3Object_Dispose(theDocument->fFillStyle);      // whether drawn as solid filled object or decomposed to components
    // No need to delete fPickPartStyle; its only reference is in the fModel
}
 
//-----------------------------------------------------------------------------
// 
 
TQ3Status DrawDocumentData(
    DocumentPtr theDocument)
{   
    Q3View_StartRendering(theDocument->fView);
    do {
        Q3Style_Submit(theDocument->fInterpolation, theDocument->fView);
        Q3Style_Submit(theDocument->fBackFacing,    theDocument->fView);
        Q3Style_Submit(theDocument->fFillStyle,     theDocument->fView);
        Q3DisplayGroup_Submit(theDocument->fModel,  theDocument->fView);
    } while(Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse);
    return kQ3Success;
}
 
//-------------------------------------------------------------------------------------------
//
 
static
void InitToolbox(
    void)
{
    MaxApplZone();
    MoreMasters(); MoreMasters(); MoreMasters(); 
    
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitCursor();
    InitMenus();
 
    FlushEvents(everyEvent, 0);
    // initialize application globals
    
    gQuitFlag = false;
}
 
 
static
void InitMenuItems(
    DocumentPtr theDocument)
{
    MenuHandle  hMenu;
 
    /* Set up menus */
    hMenu = NewMenu(mApple, "\p\024");
    AppendMenu(hMenu, "\pAbout Mesh ShapePart PickingÉ");
    AppendMenu(hMenu, "\p(-");
    AddResMenu(hMenu, 'DRVR');
    InsertMenu(hMenu, 0);
 
    hMenu = NewMenu(mFile, "\pFile");
    AppendMenu(hMenu, "\pQuit/Q");
    InsertMenu(hMenu, 0);
 
    hMenu = NewMenu(mParts, "\pShapeParts");
    AppendMenu(hMenu, "\pObject/O;Face/F;Edge/E;Vertex/V");
    InsertMenu(hMenu, 0);
 
    DrawMenuBar();
 
    /* Initialize shape part menu */
    CheckItem(hMenu, iObject,   (Boolean)  (theDocument->fPickParts == kQ3PickPartsObject));
    CheckItem(hMenu, iFace,     (Boolean) ((theDocument->fPickParts & kQ3PickPartsMaskFace)   != 0));
    CheckItem(hMenu, iEdge,     (Boolean) ((theDocument->fPickParts & kQ3PickPartsMaskEdge)   != 0));
    CheckItem(hMenu, iVertex,   (Boolean) ((theDocument->fPickParts & kQ3PickPartsMaskVertex) != 0));
}
 
 
//-------------------------------------------------------------------------------------------
//
static
void MainEventLoop(
    void)
{
    EventRecord     event;
    WindowPtr       window;
    short           thePart;
    Rect            screenRect, updateRect;
    Point           aPoint = {100, 100};
    
    while(!gQuitFlag)
    {
        if(WaitNextEvent(everyEvent, &event, 0, nil))
        {
 
            switch (event.what) {
                case mouseDown:
                
                    thePart = FindWindow(event.where, &window);
                    
                    switch (thePart) {
                        case inMenuBar:
                            HandleMenuCommand(MenuSelect(event.where));
                            break;
 
                        case inDrag:
                            screenRect =(**GetGrayRgn()).rgnBBox;
                            DragWindow(window, event.where, &screenRect);
                            break;
                    
                        case inContent:
                            if(window != FrontWindow())
                                SelectWindow(window);
                            else {
                                CGrafPtr    savedPort;
                                Point       clickPoint;
 
                                GetPort((GrafPtr*)&savedPort);
                                SetPort(window);
                                clickPoint = event.where;
                                GlobalToLocal(&clickPoint);
                                SetPort((GrafPtr)savedPort);
 
                                DoPicking(&clickPoint, &gDocument);
                            }
                            break;
                    
                        case inGoAway:
                            if(TrackGoAway(window, event.where)) {
                                DisposeWindow(window);
                                gQuitFlag = true;
 
                            }
                            break;
 
                        default:
                            break;
                    }
                    break;
 
 
                case updateEvt:
                    window =(WindowPtr)event.message;
                    updateRect =(**(window->visRgn)).rgnBBox;
                    SetPort(window);
                    BeginUpdate(window);
                    DrawDocumentData(&gDocument);
                    EndUpdate(window);
                    break;
                    
                case keyDown:
                case autoKey:
                    HandleKeyPress(&event);
                    break;
                    
                case diskEvt:
                    if(HiWord(event.message) != noErr) 
                        (void) DIBadMount(aPoint, event.message);
                    break;
                    
                case osEvt:
                case activateEvt:
                    break;
            }
        }
    }
}
 
 
//-------------------------------------------------------------------------------------------
//
static
void HandleKeyPress(
    EventRecord *event)
{
    char    charCode;
 
    charCode = event->message & charCodeMask;
 
    if(event->modifiers & cmdKey)
        HandleMenuCommand(MenuKey(charCode));
}
 
 
//-------------------------------------------------------------------------------------------
//
static
void HandleMenuCommand(
    long menuResult)
{
    short   menuID,
            itemNumber;
 
    if(menuResult == 0)
        return;
 
    menuID     = HiWord(menuResult);
    itemNumber = LoWord(menuResult);
 
    switch (menuID) {
        case mApple:
            switch (itemNumber) {
                case iAbout:
                    SysBeep(1);
                    break;
 
                default:
                    break;
            }
            break;
 
        case mFile:
            switch (itemNumber) {
                case iQuit:
                    gQuitFlag = true;
                    break;
 
                default:
                    break;
            }
            break;
 
        case mParts:
            {
                MenuHandle  hMenu;
 
                hMenu = GetMenuHandle(menuID);
 
                switch (itemNumber) {
                    case iObject:
                        gDocument.fPickParts = kQ3PickPartsObject;
                        CheckItem(hMenu, iFace,   false);
                        CheckItem(hMenu, iEdge,   false);
                        CheckItem(hMenu, iVertex, false);
                        break;
    
                    case iFace:
                        if(gDocument.fPickParts & kQ3PickPartsMaskFace) {
                            gDocument.fPickParts &= ~kQ3PickPartsMaskFace;
                            CheckItem(hMenu, itemNumber, false);
                        }
                        else {
                            gDocument.fPickParts |= kQ3PickPartsMaskFace;
                            CheckItem(hMenu, itemNumber, true);
                        }
                        break;
    
                    case iEdge:
                        if(gDocument.fPickParts & kQ3PickPartsMaskEdge) {
                            gDocument.fPickParts &= ~kQ3PickPartsMaskEdge;
                            CheckItem(hMenu, itemNumber, false);
                        }
                        else {
                            gDocument.fPickParts |= kQ3PickPartsMaskEdge;
                            CheckItem(hMenu, itemNumber, true);
                        }
                        break;
    
                    case iVertex:
                        if(gDocument.fPickParts & kQ3PickPartsMaskVertex) {
                            gDocument.fPickParts &= ~kQ3PickPartsMaskVertex;
                            CheckItem(hMenu, itemNumber, false);
                        }
                        else {
                            gDocument.fPickParts |= kQ3PickPartsMaskVertex;
                            CheckItem(hMenu, itemNumber, true);
                        }
                        break;
    
                    default:
                        break;
                }
    
                /* Un/check "object" item after other part menu items are selected */
                CheckItem(hMenu, iObject, (Boolean) (gDocument.fPickParts == kQ3PickPartsObject));
            }
            break;
 
        default:
            break;
    }
 
    HiliteMenu(0);
}