3D Graphics Programming with QuickDraw 3D

4 Using Geometric Objects

QuickDraw3D provides routines that you can use to create and edit geometric objects, get and set attributes for those objects, and perform other geometric operations. This section illustrates how to create and delete some geometric objects and how to traverse the parts of a mesh.

4 Creating and Deleting Geometric Objects

As you saw briefly in the chapter "Introduction to QuickDraw 3D," QuickDraw3D supports both immediate and retained modes of defining and rendering a model. Which mode you employ in any particular instance depends on the needs of your application. As suggested earlier, if much of the model remains unchanged from frame to frame, you should use retained mode imaging to create and draw the model. If, however, many parts of the model do change from frame to frame, you should use immediate mode imaging, creating and rendering a model on a shape-by-shape basis.

Listing 4-1 illustrates how to create a retained box.

Listing 4-1 Creating a retained box

TQ3GeometryObject        myBox;
TQ3BoxData        myBoxData;

Q3Point3D_Set(&myBoxData.origin, 1.0, 1.0, 1.0);
Q3Vector3D_Set(&myBoxData.orientation, 0, 2.0, 0);
Q3Vector3D_Set(&myBoxData.minorAxis, 2.0, 0, 0);
Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 2.0);
myBox = Q3Box_New(&myBoxData);
Once the code in Listing 4-1 has been executed, the variable myBox contains a reference to the new box. You can then reuse or dispose of the myBoxData structure, because all subsequent operations on the retained box are performed using myBox. For example, to submit the box for drawing, picking, bounding, or writing, you can execute the following line of code inside a rendering, picking, bounding, or writing loop:

myStatus = Q3Object_Submit(myBox, myView);
To dispose of the retained box, you can call the Q3Object_Dispose function,
as follows:

myStatus = Q3Object_Dispose(myBox);
Listing 4-2 illustrates how to create an immediate box.

Listing 4-2 Creating an immediate box

TQ3BoxData        myBoxData;

Q3Point3D_Set(&myBoxData.origin, 1.0, 1.0, 1.0);
Q3Vector3D_Set(&myBoxData.orientation, 0, 2.0, 0);
Q3Vector3D_Set(&myBoxData.minorAxis, 2.0, 0, 0);
Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 2.0);
As you can see, you do not have to call any QuickDraw3D routine to create an immediate box; instead, you simply define the box data in a structure of type TQ3BoxData. To draw an immediate box, you call the Q3Box_Submit function (inside a rendering loop), as follows:

myStatus = Q3Box_Submit(myBox, myView);
Because you didn't create any retained entity, you do not need to dispose of the immediate box.

4 Creating a Mesh

As you saw earlier (in "Meshes," beginning on page 4-6), you create a mesh
by calling Q3Mesh_New to create a new empty mesh and then by calling Q3Mesh_VertexNew and Q3Mesh_FaceNew to explicitly add vertices and faces
to the mesh. Listing 4-3 illustrates how to create a simple mesh using these functions. It also shows how to attach a custom surface parameterization to
a mesh face, so that a texture can be mapped onto the face.

Listing 4-3 Creating a simple mesh

TQ3GroupObject MyBuildMesh (void)
{
 TQ3ColorRGB         myMeshColor;
 TQ3GroupObject         myModel;
 static TQ3Vertex3D         vertices[9] = {
  { { -0.5,  0.5, 0.0 }, NULL },
  { { -0.5, -0.5, 0.0 }, NULL },
  { {  0.0, -0.5, 0.3 }, NULL },
  { {  0.5, -0.5, 0.0 }, NULL },
  { {  0.5,  0.5, 0.0 }, NULL },
  { {  0.0,  0.5, 0.3 }, NULL },
  { { -0.4,  0.2, 0.0 }, NULL },
  { {  0.0,  0.0, 0.0 }, NULL },
  { { -0.4, -0.2, 0.0 }, NULL }};
 static TQ3Param2D         verticesUV[9] = {
  {0.0, 1.0}, {0.0, 0.0}, {0.5, 0.0}, {1.0, 0.0},
  {1.0, 1.0}, {0.5, 1.0}, {0.1, 0.8}, {0.5, 0.5},
  {0.1, 0.4}};
 
 TQ3MeshVertex         myMeshVertices[9];
 TQ3GeometryObject         myMesh;
 TQ3MeshFace         myMeshFace;
 TQ3AttributeSet         myFaceAttrs;
 unsigned long         i;

 myMesh = Q3Mesh_New();         /*create new empty mesh*/

 Q3Mesh_DelayUpdates(myMesh);         /*turn off mesh updating*/

 /*Add vertices and surface parameterization to mesh.*/
 for (i = 0; i < 9; i++) 
 {
  TQ3AttributeSet        myVertAttrs;
  
  myMeshVertices[i] = Q3Mesh_VertexNew(myMesh, &vertices[i]);
  myVertAttrs = Q3AttributeSet_New();
  Q3AttributeSet_Add
     (myVertAttrs, kQ3AttributeTypeSurfaceUV, &verticesUV[i]);
  Q3Mesh_SetVertexAttributeSet(myMesh, myMeshVertices[i], myVertAttrs);
  Q3Object_Dispose(myVertAttrs);
 }

 myFaceAttrs = Q3AttributeSet_New();
 myMeshColor.r = 0.3;
 myMeshColor.g = 0.9;
 myMeshColor.b = 0.5;
 Q3AttributeSet_Add
     (myFaceAttrs, kQ3AttributeTypeDiffuseColor, &myMeshColor);

 myMeshFace = Q3Mesh_FaceNew(myMesh, 6, myMeshVertices, myFaceAttrs);

 Q3Mesh_FaceToContour(myMesh, myMeshFace, 
      Q3Mesh_FaceNew(myMesh, 3, &myMeshVertices[6], NULL));

 Q3Mesh_ResumeUpdates(myMesh);

 myModel = Q3OrderedDisplayGroup_New();
 Q3Group_AddObject(myModel, myMesh);
 Q3Object_Dispose(myFaceAttrs);
 Q3Object_Dispose(myMesh);
 return (myModel);
}
The new mesh created by MyBuildMesh is a retained object. Note that you need to call Q3Mesh_New before you call Q3Mesh_VertexNew and Q3Mesh_FaceNew. Also, the call to Q3Mesh_FaceToContour destroys any attributes associated with the mesh face that is turned into a contour.

4 Traversing a Mesh

QuickDraw3D supplies a large number of functions that you can use to traverse a mesh by iterating through the various distinguishable parts of the mesh (that is, through the faces, vertices, edges, contours, or components in the mesh). For example, you can operate on each face of a mesh by calling the Q3Mesh_FirstMeshFace function to get the first face in the mesh and then by calling Q3Mesh_NextMeshFace to get each successive face in the mesh. When you call Q3Mesh_FirstMeshFace, you specify a mesh and a mesh iterator structure, which QuickDraw3D fills in with information about its current position while traversing a mesh. You must pass that same mesh iterator structure to Q3Mesh_NextMeshFace when you get successive faces in the mesh. Listing 4-4 illustrates how to use these routines to operate on all faces in a mesh.

Listing 4-4 Iterating through all faces in a mesh

TQ3Status MySetMeshFacesDiffuseColor (TQ3GeometryObject myMesh, 
                TQ3ColorRGB color) 
{
 TQ3MeshFace       myFace;
 TQ3MeshIterator       myIter;
 TQ3Status       myErr;
 TQ3AttributeSet       mySet;

 for (myFace = Q3Mesh_FirstMeshFace(myMesh, &myIter); 
    myFace;
    myFace = Q3Mesh_NextMeshFace(&myIter)) {

  /*Get the current attribute set of the current face.*/
  myErr = Q3Mesh_GetFaceAttributeSet(myMesh, myFace, &mySet);
  if (myErr == kQ3Failure) return (kQ3Failure);
  
  /*Add the color attribute to the face attribute set.*/
  myErr = Q3AttributeSet_Add((TQ3AttributeSet)mySet, 
        kQ3AttributeTypeDiffuseColor, &color);
  if (myErr == kQ3Failure) return (kQ3Failure);

  /*Set the attribute set of the current face.*/
  myErr = Q3Mesh_SetFaceAttributeSet(myMesh, myFace, mySet);
  if (myErr == kQ3Failure) return (kQ3Failure);
 }
 return (kQ3Success);
}
QuickDraw3D also supplies a number of C language macros that you can use to simplify your source code. For example, you can use the Q3ForEachMeshFace macro, defined like this:

#define Q3ForEachMeshFace(m,f,i)                   \
 for ( (f) = Q3Mesh_FirstMeshFace((m),(i));                  \
  (f);                 \
  (f) = Q3Mesh_NextMeshFace((i)) )
Listing 4-5 shows how to use two of these macros to attach a corner to each vertex or each face of a mesh.

Listing 4-5 Attaching corners to all vertices in all faces of a mesh

TQ3Status MyAddCornersToMesh (TQ3GeometryObject myMesh, 
               TQ3AttributeSet mySet)
{
 TQ3MeshFace       myFace;
 TQ3MeshVertex       myVertex;
 TQ3MeshIterator       myIter1;
 TQ3MeshIterator       myIter2;
 TQ3Status       myErr;


 Q3ForEachMeshFace(myMesh, myFace, &myIter1) {
  Q3ForEachFaceVertex(myFace, myVertex, &myIter2) {
   myErr = Q3Mesh_SetCornerAttributeSet
      (myMesh, myFace, myVertex, mySet);
   if (myErr == kQ3Failure) return (kQ3Failure);
  }
 }
 return (kQ3Success);
}
4 - Creating and Deleting Geometric Objects
4 - Creating a Mesh
4 - Traversing a Mesh

3D Graphics Programming with QuickDraw 3D - 21 OCT 1995

© Apple Computer, Inc.

Let us know what you think of these prototype pages.

Generated with Harlequin WebMaker