Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Sources/PickMeshShapePart.c
// PickMeshShapePart.c |
// |
// This demonstrates how to use picks to test which parts of a mesh geometry have |
// been hit. When the mesh is picked the fPickParts value set from the ShapeParts |
// menu controls the parts tested: object, face, edge, or vertex. As the returned |
// hits in the pick are processed the corresponding part of the mesh is draw in a |
// different color and the name of that part is displayed in the window's upper |
// left corner. |
// |
// The vertex and edge tolerance levels set in CreatePick() control how close the |
// window point pick must be to the given part. |
// |
// Robert Dierkes - November 11, 1995 |
// |
// ©1994-95 Apple computer Inc., All Rights Reserved |
// |
// system headers |
#include <Windows.h> |
// for QuickDraw 3D |
#include "QD3D.h" |
#include "QD3DMath.h" |
#include "QD3DDrawContext.h" |
#include "QD3DShader.h" |
#include "QD3DGroup.h" |
#include "QD3DPick.h" |
#include "PickMeshShapePart.h" |
//------------------------------------------------------------------------------------------- |
// function prototypes |
void TickDelay( |
long time); |
TQ3Status DoGroupPicking( |
TQ3ViewObject view, |
TQ3GroupObject group, |
TQ3PickObject pick); |
void GetRandomRGBColor( |
TQ3ColorRGB *pColorRGB); |
TQ3Status ChangeMeshFaceColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshFace meshFace, |
DocumentPtr theDocument); |
TQ3Status ChangeMeshEdgeColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshEdge meshEdge, |
DocumentPtr theDocument); |
TQ3Status ChangeMeshVertexColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshVertex meshVertex, |
DocumentPtr theDocument); |
TQ3Status HandleMeshShapePart( |
TQ3GeometryObject geometry, |
TQ3ShapePartObject shapePart, |
DocumentPtr theDocument); |
TQ3Status HandleMeshPickHits( |
TQ3PickObject pick, |
DocumentPtr theDocument); |
TQ3Status CreatePick( |
TQ3PickObject *pPick); |
//------------------------------------------------------------------------------------------- |
// |
#define kDelay 30 |
#define kTextLocationX 30 |
#define kTextLocationY 30 |
static TQ3PickObject gPick = NULL; |
//----------------------------------------------------------------------------- |
// |
// InitPicking |
TQ3Status InitPicking( |
void) |
{ |
return CreatePick(&gPick); |
} |
//----------------------------------------------------------------------------- |
// |
// ExitPicking |
TQ3Status ExitPicking( |
void) |
{ |
if (gPick != NULL) { |
Q3Object_Dispose(gPick); |
gPick = NULL; |
} |
return kQ3Success; |
} |
//----------------------------------------------------------------------------- |
// |
// TickDelay |
static |
void TickDelay( |
long time) |
{ |
long ticks, |
startTicks; |
startTicks = ticks = TickCount(); |
while (ticks - startTicks != time ) { |
ticks = TickCount(); |
} |
} |
//----------------------------------------------------------------------------- |
// |
// DoGroupPicking |
static |
TQ3Status DoGroupPicking( |
TQ3ViewObject view, |
TQ3GroupObject group, |
TQ3PickObject pick) |
{ |
TQ3Status status; |
TQ3ViewStatus viewStatus; |
if ((status = Q3View_StartPicking(view, pick)) == kQ3Failure) |
return status; |
do { |
status = Q3DisplayGroup_Submit(group, view); |
viewStatus = Q3View_EndPicking(view); |
} while (viewStatus == kQ3ViewStatusRetraverse); |
if (viewStatus != kQ3ViewStatusDone) { |
status = kQ3Failure; |
} |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// GetRandomRGBColor |
static |
void GetRandomRGBColor( |
TQ3ColorRGB *pColorRGB) |
{ |
unsigned long ticks; |
ticks = TickCount(); |
Q3ColorRGB_Set(pColorRGB, |
(ticks % 10) / 10.0, |
(ticks % 100) / 100.0, |
(ticks % 1000) / 1000.0); |
} |
//----------------------------------------------------------------------------- |
// |
// ChangeMeshFaceColor |
static |
TQ3Status ChangeMeshFaceColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshFace meshFace, |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3AttributeSet attributeSet; |
TQ3ColorRGB colorRGB; |
status = kQ3Failure; |
if (meshGeo == NULL || |
meshFace == NULL) { |
return status; |
} |
/* Get the face attributes */ |
if ((status = Q3Mesh_GetFaceAttributeSet(meshGeo, meshFace, &attributeSet)) == kQ3Failure) { |
return status; |
} |
/* Create an attributes if none */ |
if (attributeSet == NULL) { |
if ((attributeSet = Q3AttributeSet_New()) == NULL) { |
return kQ3Failure; |
} |
} |
GetRandomRGBColor(&colorRGB); |
if ((status = Q3AttributeSet_Add(attributeSet, kQ3AttributeTypeDiffuseColor, &colorRGB)) == kQ3Success) { |
char partTypeString[] = {"\pFace"}; |
/* Set new face color */ |
status = Q3Mesh_SetFaceAttributeSet(meshGeo, meshFace, attributeSet); |
/* Redraw the mesh */ |
DrawDocumentData(theDocument); |
MoveTo(kTextLocationX, kTextLocationY); |
DrawText((void *) partTypeString, 1, (short) partTypeString[0]); |
TickDelay(kDelay); |
/* Remove new face color */ |
status = Q3Mesh_SetFaceAttributeSet(meshGeo, meshFace, NULL); |
DrawDocumentData(theDocument); |
} |
Q3Object_Dispose(attributeSet); |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// ChangeMeshEdgeColor |
static |
TQ3Status ChangeMeshEdgeColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshEdge meshEdge, |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3AttributeSet attributeSet1, |
attributeSet2; |
TQ3MeshVertex meshVertex1, |
meshVertex2; |
TQ3ColorRGB colorRGB; |
status = kQ3Failure; |
if ((meshGeo == NULL) || |
(meshEdge == NULL) || |
(theDocument == NULL)) { |
debugstr("ChangeMeshEdgeColor: NULL parameter passed"); |
return status; |
} |
attributeSet1 = NULL; |
attributeSet2 = NULL; |
/* |
* Set color on both vertices of this edge |
* |
* We change the vertex attributes instead of the edge attributes because we can only |
* see the effects of an edge attribute when the fill style is kQ3FillStyleEdges. We |
* could use kQ3FillStyleEdges rather than the current fill of kQ3FillStyleFilled but |
* then we couldn't see the attributes on the vertex and face. |
*/ |
if ((status = Q3Mesh_GetEdgeVertices(meshGeo, meshEdge, &meshVertex1, &meshVertex2)) == kQ3Failure) { |
return status; |
} |
/* Get the vertex attributes */ |
if (((status = Q3Mesh_GetVertexAttributeSet(meshGeo, meshVertex1, &attributeSet1)) == kQ3Failure) || |
((status = Q3Mesh_GetVertexAttributeSet(meshGeo, meshVertex2, &attributeSet2)) == kQ3Failure)) { |
goto ChangeMeshEdgeColor_Exit; |
} |
/* Create an attributes if none */ |
if (attributeSet1 == NULL) { |
if ((attributeSet1 = Q3AttributeSet_New()) == NULL) { |
goto ChangeMeshEdgeColor_Exit; |
} |
} |
if (attributeSet2 == NULL) { |
if ((attributeSet2 = Q3AttributeSet_New()) == NULL) { |
goto ChangeMeshEdgeColor_Exit; |
} |
} |
GetRandomRGBColor(&colorRGB); |
if (((status = Q3AttributeSet_Add(attributeSet1, kQ3AttributeTypeDiffuseColor, &colorRGB)) == kQ3Success) && |
((status = Q3AttributeSet_Add(attributeSet2, kQ3AttributeTypeDiffuseColor, &colorRGB)) == kQ3Success)) { |
char partTypeString[] = {"\pEdge"}; |
/* Set new vertex color */ |
if (((status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex1, attributeSet1)) == kQ3Success) && |
((status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex2, attributeSet2)) == kQ3Success)) { |
/* Redraw the mesh */ |
DrawDocumentData(theDocument); |
MoveTo(kTextLocationX, kTextLocationY); |
DrawText((void *) partTypeString, 1, (short) partTypeString[0]); |
TickDelay(kDelay); |
} |
/* Remove new vertex color */ |
status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex1, NULL); |
status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex2, NULL); |
DrawDocumentData(theDocument); |
} |
ChangeMeshEdgeColor_Exit: |
if (attributeSet1 != NULL) |
Q3Object_Dispose(attributeSet1); |
if (attributeSet2 != NULL) |
Q3Object_Dispose(attributeSet2); |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// ChangeMeshVertexColor |
static |
TQ3Status ChangeMeshVertexColor( |
TQ3GeometryObject meshGeo, |
TQ3MeshVertex meshVertex, |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3AttributeSet attributeSet; |
TQ3ColorRGB colorRGB; |
status = kQ3Failure; |
if ((meshGeo == NULL) || |
(meshVertex == NULL) || |
(theDocument == NULL)) { |
debugstr("ChangeMeshVertexColor: NULL parameter passed"); |
return status; |
} |
/* Get the vertex attributes */ |
if ((status = Q3Mesh_GetVertexAttributeSet(meshGeo, meshVertex, &attributeSet)) == kQ3Failure) { |
return status; |
} |
/* Create an attributes if none */ |
if (attributeSet == NULL) { |
if ((attributeSet = Q3AttributeSet_New()) == NULL) { |
return kQ3Failure; |
} |
} |
GetRandomRGBColor(&colorRGB); |
if ((status = Q3AttributeSet_Add(attributeSet, kQ3AttributeTypeDiffuseColor, &colorRGB)) == kQ3Success) { |
char partTypeString[] = {"\pVertex"}; |
/* Set new vertex color */ |
status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex, attributeSet); |
/* Redraw the mesh */ |
DrawDocumentData(theDocument); |
MoveTo(kTextLocationX, kTextLocationY); |
DrawText((void *) partTypeString, 1, (short) partTypeString[0]); |
TickDelay(kDelay); |
/* Remove new vertex color */ |
status = Q3Mesh_SetVertexAttributeSet(meshGeo, meshVertex, NULL); |
DrawDocumentData(theDocument); |
} |
Q3Object_Dispose(attributeSet); |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// HandleMeshShapePart |
static |
TQ3Status HandleMeshShapePart( |
TQ3GeometryObject geometry, |
TQ3ShapePartObject shapePart, |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3ObjectType objectType; |
if ((geometry == NULL) || (shapePart == NULL) || (theDocument == NULL)) { |
debugstr("HandleMeshShapePart: NULL parameter passed"); |
return kQ3Failure; |
} |
/* Is object a mesh geometry? */ |
if (Q3Object_IsType (geometry, kQ3GeometryTypeMesh) == kQ3False) { |
debugstr("HandleMeshShapePart: geometry isn't a mesh"); |
return kQ3Failure; |
} |
/* Is the shapePart a mesh part? */ |
if (Q3ShapePart_GetType (shapePart) != kQ3ShapePartTypeMeshPart) { |
debugstr("HandleMeshShapePart: shape part isn't for a mesh"); |
return kQ3Failure; |
} |
status = kQ3Failure; |
/* Or use this to get the shape part hit: objectType = Q3Object_GetLeafType(shapePart); */ |
objectType = Q3MeshPart_GetType(shapePart); |
switch (objectType) { |
case kQ3MeshPartTypeMeshFacePart: |
{ |
TQ3MeshFace meshFace; |
if (Q3MeshFacePart_GetFace(shapePart, &meshFace) == kQ3Success) { |
status = ChangeMeshFaceColor(geometry, meshFace, theDocument); |
} |
} |
break; |
case kQ3MeshPartTypeMeshEdgePart: |
{ |
TQ3MeshEdge meshEdge; |
if (Q3MeshEdgePart_GetEdge(shapePart, &meshEdge) == kQ3Success) { |
status = ChangeMeshEdgeColor(geometry, meshEdge, theDocument); |
} |
} |
break; |
case kQ3MeshPartTypeMeshVertexPart: |
{ |
TQ3MeshVertex meshVertex; |
if (Q3MeshVertexPart_GetVertex(shapePart, &meshVertex) == kQ3Success) { |
status = ChangeMeshVertexColor(geometry, meshVertex, theDocument); |
} |
} |
break; |
default: |
status = kQ3Failure; |
break; |
} |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// HandleMeshPickHits |
static |
TQ3Status HandleMeshPickHits( |
TQ3PickObject pick, |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
unsigned long hitIndex, |
numHits; |
#if defined(QD3D_OBSOLETE) && QD3D_OBSOLETE |
TQ3HitData hitData; |
#else /* ! QD3D_OBSOLETE */ |
TQ3PickDetail validMask; |
TQ3Object object; |
TQ3ShapePartObject shapePart; |
object = NULL; |
shapePart = NULL; |
#endif /* ! QD3D_OBSOLETE */ |
if ((pick == NULL) || (theDocument == NULL)) { |
debugstr("HandleMeshPickHits: NULL parameter passed"); |
return kQ3Failure; |
} |
numHits = 0; |
if (Q3Pick_GetNumHits(pick, &numHits) == kQ3Failure) { |
debugstr("HandleMeshPickHits: NULL parameter passed"); |
return kQ3Failure; |
} |
/* Process each hit in the pick */ |
for (hitIndex = 0, status = kQ3Success; |
(hitIndex < numHits) && (status == kQ3Success); |
hitIndex++) { |
#if defined(QD3D_OBSOLETE) && QD3D_OBSOLETE |
if (Q3Pick_GetHitData(pick, hitIndex, &hitData) == kQ3Failure) { |
debugstr("HandleMeshPickHits: Q3Pick_GetHitData failed"); |
status = kQ3Failure; |
goto HandleMeshPickHits_Cleanup; |
} |
/* Test if hit data contains an object and shape part */ |
/* Get reference to geometry object hit */ |
if (! HitData_Has_Object(hitData)) { |
debugstr("HandleMeshPickHits: no object information returned in Q3Pick_GetHitData"); |
status = kQ3Failure; |
goto HandleMeshPickHits_Cleanup; |
} |
/* Get reference to shapePart hit */ |
if (! HitData_Has_ShapePart(hitData)) { |
debugstr("HandleMeshPickHits: no shape part information returned in Q3Pick_GetHitData"); |
status = kQ3Failure; |
goto HandleMeshPickHits_Cleanup; |
} |
/* Color the shape part(s) hit */ |
(void) HandleMeshShapePart(hitData.object, hitData.shapePart, theDocument); |
/* Dispose hitData.object and hitData.shapePart returned with Q3Pick_GetHitData */ |
HandleMeshPickHits_Cleanup: |
Q3Hit_EmptyData(&hitData); |
#else /* ! QD3D_OBSOLETE */ |
/* |
* New Picking API for QuickDraw 3D Release 1.5 |
*/ |
/* Get the TQ3PickDetail masks for this hit (hitIndex) */ |
if ((status = Q3Pick_GetPickDetailValidMask(pick, hitIndex, &validMask)) == kQ3Failure) { |
debugstr("HandleMeshPickHits: Q3Pick_GetPickDetailValidMask failed"); |
goto HandleMeshPickHits_Cleanup; |
} |
/* Quick check to see if the hit contains an object and shape part */ |
if (! (validMask & kQ3PickDetailMaskObject) || |
! (validMask & kQ3PickDetailMaskShapePart) ) { |
debugstr("HandleMeshPickHits: expected object and shapePart TQ3PickDetailMasks masks to be set"); |
status = kQ3Failure; |
goto HandleMeshPickHits_Cleanup; |
} |
/* Get reference to geometry object hit */ |
if ((status = Q3Pick_GetPickDetailData(pick, hitIndex, kQ3PickDetailMaskObject, &object)) == kQ3Failure) { |
debugstr("HandleMeshPickHits: no object returned in Q3Pick_GetPickDetailData"); |
goto HandleMeshPickHits_Cleanup; |
} |
/* Get reference to shapePart hit */ |
if ((status = Q3Pick_GetPickDetailData(pick, hitIndex, kQ3PickDetailMaskShapePart, &shapePart)) == kQ3Failure) { |
debugstr("HandleMeshPickHits: no object returned in Q3Pick_GetPickDetailData"); |
goto HandleMeshPickHits_Cleanup; |
} |
/* Color the shape part(s) hit */ |
(void) HandleMeshShapePart(object, shapePart, theDocument); |
/* Dispose object and shapePart returned with Q3Pick_GetPickDetailData */ |
HandleMeshPickHits_Cleanup: |
if (object != NULL) { |
Q3Object_Dispose(object); |
object = NULL; |
} |
if (shapePart != NULL) { |
Q3Object_Dispose(shapePart); |
shapePart = NULL; |
} |
#endif /* ! QD3D_OBSOLETE */ |
} |
/* |
* If we reuse the pick object be sure to empty the hit list. |
* If the pick object is disposed immediately after picking |
* (not the case in this sample code) the hit list is automatically disposed. |
*/ |
if (Q3Pick_EmptyHitList(pick) == kQ3Failure) { |
debugstr("HandleMeshPickHits: Q3Pick_EmptyHitList failed"); |
} |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// CreatePick |
static |
TQ3Status CreatePick( |
TQ3PickObject *pPick) |
{ |
TQ3WindowPointPickData data; |
TQ3Status status; |
status = kQ3Failure; |
if (pPick == NULL) |
return status; |
/* Create pick object */ |
data.data.sort = kQ3PickSortNearToFar; |
data.data.mask = kQ3PickDetailMaskObject | /* Request only object and shape parts */ |
kQ3PickDetailMaskShapePart; |
data.data.numHitsToReturn = kQ3ReturnAllHits; |
Q3Point2D_Set(&data.point, 0.0, 0.0); |
data.vertexTolerance = 5.0; /* Set vertex and edge tolerences */ |
data.edgeTolerance = 3.0; |
if ((*pPick = Q3WindowPointPick_New(&data)) != NULL) |
status = kQ3Success; |
return status; |
} |
//----------------------------------------------------------------------------- |
// |
// DoPicking |
TQ3Status DoPicking( |
Point *pWhere, /* local window coordinates */ |
DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3Point2D point; |
status = kQ3Failure; |
if (theDocument->fView == NULL || |
theDocument->fModel == NULL || |
theDocument->fPickPartStyle == NULL || |
gPick == NULL) { |
return kQ3Failure; |
} |
/* Set pick part style with parts selected in the menu */ |
if ((status = Q3PickPartsStyle_Set(theDocument->fPickPartStyle, theDocument->fPickParts)) == kQ3Failure) |
return kQ3Failure; |
/* Set the pick's point to mouse location */ |
Q3Point2D_Set(&point, pWhere->h, pWhere->v); |
if ((status = Q3WindowPointPick_SetPoint(gPick, &point)) == kQ3Failure) |
return kQ3Failure; |
if ((status = DoGroupPicking(theDocument->fView, theDocument->fModel, gPick)) == kQ3Failure) |
return kQ3Failure; |
/* Handle hit(s) on mesh */ |
return HandleMeshPickHits(gPick, theDocument); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14