3D Graphics Programming with QuickDraw 3D
MyHandleClickInWindow
, that takes a window pointer and an event record and handles mouse clicks in that window.
TQ3Status MyHandleClickInWindow (CGrafPtr myWindow, EventRec myEvent) { TQ3WindowPointPickData myWPPickData; TQ3PickObject myPickObject; TQ3HitData myHitData; unsigned long myNumHits; unsigned long myIndex; Point myPoint; TQ3Point2D my2DPoint; TQ3ViewObject myView; /*Get the window coordinates of a mouse click.*/ SetPort(myWindow); myPoint = myEvent.where; /*get location of mouse click*/ GlobalToLocal(&myPoint); /*convert to window coordinates*/ my2DPoint.x = myPoint.h; /*configure a 2D point*/ my2DPoint.y = myPoint.v; /*Set up picking data structures.*/ /*Set sorting type: objects nearer to pick origin are returned first.*/ myWPPickData.data.sort = kQ3PickSortNearToFar; myWPPickData.data.mask = kQ3PickDetailMaskPickID | kQ3PickDetailMaskXYZ | kQ3PickDetailMaskObject; myWPPickData.data.numHitsToReturn = kQ3ReturnAllHits; myWPPickData.point = my2DPoint; myWPPickData.vertexTolerance = 2.0; myWPPickData.edgeTolerance = 2.0; /*Create a new window-point pick object.*/ myPickObject = Q3WindowPointPick_New(&myWPPickData); myView = MyGetViewFromWindow(myWindow); /*increments reference count*/ /*Pick a group object.*/ Q3View_StartPicking(myView, myPickObject); do { Q3DisplayGroup_Submit(gGroup, myPickObject, myView); } while (Q3View_EndPicking(myView) == kQ3ViewStatusRetraverse); /*See whether any hits occurred.*/ if (!Q3Pick_GetNumHits(myPickObject, &myNumHits) || !(myNumHits == 0)) { Q3Object_Dispose(myPickObject); return; } /*Process each hit.*/ for (myIndex = 0; myIndex < myNumHits; myIndex++) { Q3Pick_GetHitData(myPickObject, myIndex, &myHitData); /*operate on myHitData, then...*/ ... Q3Hit_EmptyData(&myHitData); /*dispose of hit data*/ } /*Dispose of all hits in the hit list.*/ Q3Pick_EmptyHitList(myPickObject); /*Dispose of the pick object.*/ Q3Object_Dispose(myPickObject); /*Dispose of the view object.*/ Q3Object_Dispose(myView); }Note that the call to
Q3Pick_EmptyHitList
is redundant, because disposing Q3Object_Dispose
) also disposes of its associated hit list. The call is included in Listing 15-1 simply to illustrate how to Q3Pick_EmptyHitList
. You would, however, need to call to Q3Pick_EmptyHitList
if you wanted to reuse the associated pick object in another pick operation.
myPickData.mask = kQ3PickDetailMaskShapePart | kQ3PickDetailMaskObject | kQ3PickDetailMaskDistance;This line of code indicates that you want QuickDraw3D to return information about objects and any distinguishable parts of objects, as well as the distances from the objects to the pick origin. (To prevent mesh parts from being selected, you simply omit adding in the
kQ3PickDetailMaskShapePart
mask.)
You can determine whether a hit data structure returned by Q3Pick_GetHitData
applies to a shape part by inspecting the shapePart
field of that structure. If the value in the field is non-NULL
, the structure contains information about a shape part. Currently the only available shape parts are mesh parts. Listing 15-2 illustrates how to use the shapePart
field to determine the type of mesh part selected and to perform some operation on the selected mesh part.
Listing 15-2 Picking mesh parts
Q3Pick_GetHitData(myPickObject, myIndex, &myHitData); if (myHitData.shapePart != NULL) { switch(Q3Object_GetLeafType(myHitData.shapePart)) { case kQ3MeshPartTypeMeshFacePart: Q3MeshFacePart_GetFace(myHitData.shapePart, &myFace); MyDoPickFace(myHitData.object, myFace); break; case kQ3MeshPartTypeMeshEdgePart: Q3MeshEdgePart_GetEdge(myHitData.shapePart, &myEdge); MyDoPickEdge(myHitData.object, myEdge); break; case kQ3MeshPartTypeMeshVertexPart: Q3MeshVertexPart_GetVertex(myHitData.shapePart, &myVertex); MyDoPickVertex(myHitData.object, myVertex); break; } }This code branches on the type of the mesh part indicated by the
shapePart
field. For each defined type of mesh part, the code calls a QuickDraw3D routine to retrieve the corresponding mesh face, edge, or vertex. Then it calls an application-defined routine (for example, MyDoPickFace
) to handle the mesh part selection.Listing 15-3 Picking in immediate mode
void MyImmediateModePickID (TQ3ViewObject view, WindowPtr window) { TQ3WindowRectPickData myPickData; TQ3TriangleData myTriangleData; TQ3PickObject myPick; TQ3ViewStatus myViewStatus; TQ3HitData myHitData; Rect myPortRect; Point myCenter; unsigned long myNumHits; /*Set up a triangle.*/ Q3Point3D_Set(&myTriangleData.vertices[0].point, -1.0, -0.5, 0.0); Q3Point3D_Set(&myTriangleData.vertices[1].point, 1.0, 0.0, 0.0); Q3Point3D_Set(&myTriangleData.vertices[2].point, -0.5, 1.5, 0.0); myTriangleData.vertices[0].attributeSet = NULL; myTriangleData.vertices[1].attributeSet = NULL; myTriangleData.vertices[2].attributeSet = NULL; myTriangleData.triangleAttributeSet = NULL; /*Set up TQ3WindowPointPickData structure.*/ myPickData.data.sort = kQ3PickSortNone; myPickData.data.mask = kQ3PickDetailMaskPickID | kQ3PickDetailMaskObject; myPickData.data.numHitsToReturn = kQ3ReturnAllHits; myPortRect = ((GrafPtr) window)->myPortRect; myCenter.h = (myPortRect.right - myPortRect.left)/2.0; myCenter.v = (myPortRect.bottom - myPortRect.top) /2.0; Q3Point2D_Set(&myPickData.rect.min, myCenter.h - 5, myCenter.v - 5); Q3Point2D_Set(&myPickData.rect.max, myCenter.h + 5, myCenter.v + 5); /*Create the window rectangle window pick.*/ myPick = Q3WindowRectPick_New(&myPickData); /*Submit the pick ID and triangle in immediate mode.*/ Q3View_StartPicking(view, myPick); do { Q3PickIDStyle_Submit(kPickID, view); Q3Triangle_Submit(&myTriangleData, view); myViewStatus = Q3View_EndPicking(view); } while (myViewStatus == kQ3ViewStatusRetraverse); Q3Pick_GetNumHits(myPick, &myNumHits); if (numHits == 1) { /*Get the hit data and check its pick ID.*/ Q3Pick_GetHitData(myPick, 0, &myHitData); if (myHitData.pickID == kPickID) { /*picked on triangle with pick ID*/ } } Q3Object_Dispose(myPick); }
Let us know what you think of these prototype pages.
Generated with Harlequin WebMaker