No Title

1 Using QuickDraw3D

This section describes the most basic ways of using QuickDraw3D. In particular, it provides source code examples that show how you can

For complete details on any of these topics, you should read the corresponding chapter later in this book. For example, see the chapter "Light Objects" for complete information about the types of lights provided by QuickDraw3D.

The code samples shown in this section provide only very rudimentary error handling. You should read the chapter "Error Manager" to learn how to write and register an application-defined error-handling routine, or how to determine explicitly which errors have occurred during the execution of QuickDraw3D routines.<8bat>s

QuickDraw3D currently is supported only on PowerPC-based Macintosh computers. It exists as a shared library, in two forms. A debugging version
is available for use by developers while writing their applications or other software products. An optimized version of the QuickDraw3D shared library is available for end users of those applications and other products. The debugging version provides more extensive information than the optimized version. For instance, the debugging version of QuickDraw3D issues errors, warnings, and notices at the appropriate times; the optimized version issues only errors and warnings.

1 Compiling Your Application

In order for your application's code to work correctly with the code contained in the QuickDraw3D shared library, you need to ensure that you use the same compiler settings that were used to compile the QuickDraw3D shared library. Otherwise, it's possible for QuickDraw3D to misinterpret information you pass to it. For example, all the enumerated constants defined by QuickDraw3D are of the int data type, where an int value is 4 bytes. If your application passes a value of some other size or type for one of those constants, it's likely that QuickDraw3D will not correctly interpret that value. Accordingly, if the default setting of your compiler does not make enumerated constants to be of type int, you must override that default setting, typically by including pragma directives in your source code or by using an appropriate compiler option.

There are currently three important compiler settings:

The interface file QD3D.h contains compiler pragmas for several popular C compilers. For example, QD3D.h contains this line for the PPCC compiler, specifying field alignment on longword boundaries for pointers or data of
type long, float, or double:

#pragma options align=power
Some compilers might not provide pragmas for the three important compiler settings listed above. For example, the PPCC compiler does not currently provide a pragma for setting the size of enumerated constants. PPCC does however support the -enums compiler option, which you can use to set the size of a enumerated constants.

Consult the documentation for your compiler to determine how to specify the size of enumerated constants and to configure structure field alignment so as to conform to the settings of QuickDraw3D.<8bat>s

1 Initializing and Terminating QuickDraw3D

Before calling any QuickDraw3D routines, you need to verify that the QuickDraw3D software is available in the current operating environment. Then you need to create and initialize a connection to the QuickDraw3D software.

On the Macintosh Operating System, you can verify that QuickDraw3D is available by calling the MyEnvironmentHasQuickDraw3D function defined in Listing 1-1.

Listing 1-1 Determining whether QuickDraw3D is available

Boolean MyEnvironmentHasQuickDraw3D (void)
{
 return((Boolean) Q3Initialize != kUnresolvedSymbolAddress);
}
The MyEnvironmentHasQuickDraw3D function checks to see whether the address of the Q3Initialize function has been resolved. If it hasn't been resolved (that is, if the Code Fragment Manager couldn't find the QuickDraw3D shared library when launching your application), MyEnvironmentHasQuickDraw3D returns the value FALSE to its caller. Otherwise, if the address of the Q3Initialize function was successfully resolved, MyEnvironmentHasQuickDraw3D returns TRUE.

For the function MyEnvironmentHasQuickDraw3D to work properly, you must establish soft links (also called weak links) between your application and the QuickDraw3D shared library. For information on soft links, see the book Inside Macintosh: PowerPC System Software. For specific information on establishing soft links, see the documentation for your software development system.<8bat>u

On the Macintosh Operating System, you can verify that QuickDraw3D is available in the current operating environment by calling the Gestalt function with the gestaltQD3D selector. Gestalt returns a long word whose value indicates the availability of QuickDraw3D. Currently these values are defined:

enum {
 gestaltQD3DNotPresent           = 0,
 gestaltQD3DAvailable           = 1
}
You should ensure that the value gestaltQD3DAvailable is returned before calling any QuickDraw3D routines.

For more information on the Gestalt function, see Inside Macintosh: Operating System Utilities.<8bat>u

You create and initialize a connection to the QuickDraw3D software by calling the Q3Initialize function, as illustrated in Listing 1-2.

Listing 1-2 Initializing a connection with QuickDraw3D

OSErr MyInitialize (void)
{
 TQ3Status     myStatus;
 
 myStatus = Q3Initialize();          /*initialize QuickDraw3D*/
 if (myStatus == kQ3Failure)
  DebugStr("\pQ3Initialize returned failure.");
 
 return (noErr);
}
Once you've successfully called Q3Initialize, you can safely call other QuickDraw3D routines. If Q3Initialize returns unsuccessfully (as
indicated by the kQ3Failure result code), you shouldn't call any QuickDraw3D routines other than the error-reporting routines (such as Q3Error_Get or Q3Error_IsFatalError) or the Q3IsInitialized function. See the chapter "Error Manager" for details on QuickDraw3D's error-
handling capabilities.

When you have finished using QuickDraw3D, you should call Q3Exit to close your connection with QuickDraw3D. In most cases, you'll do this when terminating your application. Listing 1-3 illustrates how to call Q3Exit.

Listing 1-3 Terminating QuickDraw3D

void MyFinishUp (void)
{
 TQ3Status     myStatus;
 
 myStatus = Q3Exit();         /*unload QuickDraw3D*/
 if (myStatus == kQ3Failure)
  DebugStr("\pQ3Exit returned failure.");
}

1 Creating a Model

As you learned earlier (in "Modeling and Rendering" on page 1-4), creating an image of a three-dimensional model involves several steps. You must first create a model and then specify key information about the scene (such as the lighting and camera angle). This section shows how to create a simple model containing three-dimensional objects.

Objects in QuickDraw3D are defined using a Cartesian coordinate system that is right-handed (that is, if the thumb of the right hand points in the direction of the positive x axis and the index finger points in the direction of the positive y axis, then the middle finger, when made perpendicular to the other two fingers, points in the direction of the positive z axis). Figure 1-5 shows a right-handed coordinate system.

For a more complete description of the coordinate spaces used by QuickDraw3D, see the chapter "Transform Objects" later in this book.<8bat>u

Figure 1-5 A right-handed Cartesian coordinate system

The model created by the MyNewModel function defined in Listing 1-4 consists of a number of boxes that spell out the words "Hello World." The words are written in block letters, with each letter composed of a number of individual boxes. MyNewModel uses the inelegant but straightforward method of defining the 34 boxes by creating four arrays of 34 elements each. As you'll see later (in the chapter "Geometric Objects"), a box is defined by four pieces of information, an origin and three vectors that specify its sides:

typedef struct TQ3BoxData {
 TQ3Point3D         origin;
 TQ3Vector3D         orientation;
 TQ3Vector3D         majorAxis;
 TQ3Vector3D         minorAxis;
 TQ3AttributeSet         *faceAttributeSet;
 TQ3AttributeSet         boxAttributeSet;
} TQ3BoxData;
First, MyNewModel creates a new and empty ordered display group to contain all the boxes. Then the function loops through the data arrays, creating boxes and adding them to the group.

Listing 1-4 Creating a model

TQ3GroupObject MyNewModel (void)
{
 TQ3GroupObject        myModel;
 TQ3GeometryObject        myBox;
 TQ3BoxData        myBoxData;
 TQ3GroupPosition        myGroupPosition;
 
 /*Data for boxes comprising Hello and World block letters.*/
 long   i;
 float   xorigin[34] = { 
     -12.0, -9.0, -11.0, -7.0, -6.0, -6.0, -6.0, -2.0, -1.0, 
     3.0, 4.0, 8.0, 9.0, 9.0, 11.0, -13.0, -12.0, -11.0, -9.0, 
     -7.0, -6.0, -6.0, -4.0, -2.0, -1.0, -1.0,  1.0,  1.0,  3.0, 
     4.0, 8.0, 9.0, 9.0, 11.0};
 float   yorigin[34] = { 
     0.0, 0.0, 3.0, 0.0, 6.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
     6.0, 0.0, 0.0, -8.0, -8.0, -7.0, -8.0, -8.0, -8.0, -2.0,
     -8.0, -8.0, -2.0, -5.0, -4.0, -8.0, -8.0, -8.0, -8.0, -8.0, 
     -2.0, -7.0};
 float   height[34]  = { 
     7.0, 7.0, 1.0, 7.0, 1.0, 1.0, 1.0, 7.0, 1.0, 7.0, 1.0, 7.0,
     1.0, 1.0, 7.0, 7.0, 1.0, 3.0, 7.0, 7.0, 1.0, 1.0, 7.0, 7.0,
     1.0, 1.0, 2.0, 3.0, 7.0, 1.0, 7.0, 1.0, 1.0, 5.0};
 float   width[34]   = { 
     1.0, 1.0, 2.0, 1.0, 3.0, 2.0, 3.0, 1.0, 3.0, 1.0, 3.0, 1.0,
     2.0, 2.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0,
     2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 2.0, 2.0, 1.0};
 
 /*Create an ordered display group for the complete model.*/
 myModel = Q3OrderedDisplayGroup_New();
 if (myModel == NULL)
  goto bail;

 /*Add all the boxes to the model.*/
 myBoxData.faceAttributeSet = NULL;
 myBoxData.boxAttributeSet = NULL;
 for (i=0; i<34; i++) {
  Q3Point3D_Set(&myBoxData.origin, xorigin[i], yorigin[i], 1.0);
  Q3Vector3D_Set(&myBoxData.orientation, 0, height[i], 0);
  Q3Vector3D_Set(&myBoxData.minorAxis, width[i], 0, 0);
  Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 2);
  myBox = Q3Box_New(&myBoxData);
  myGroupPosition = Q3Group_AddObject(myModel, myBox);
  /*now that myBox has been added to group, dispose of our reference*/
  Q3Object_Dispose(myBox);
  if (myGroupPosition == NULL)
   goto bail;
 }

 return (myModel);         /*return the completed model*/
 
bail:
 /*If any of the above failed, then return an empty model.*/
 return (NULL);
}
The MyNewModel function can leak memory. Your application should use a different error-recovery
strategy than is used in Listing 1-4.<8bat>u

If successful, MyNewModel returns the group object containing the 34 boxes to
its caller.

1 Configuring a Window

Usually, you'll want to display the two-dimensional image of a three-
dimensional model in a window. To do this, it's useful to define a custom window information structure that holds all the information about the QuickDraw3D objects that are associated with the window. In the simplest cases, this information includes the model itself, the view, the illumination shading to be applied, and the desired styles of rendering the model. You might define a window information structure like this:

struct WindowInfo {
 TQ3ViewObject       view;
 TQ3GroupObject       model;
 TQ3ShaderObject       illumination;
 TQ3StyleObject       interpolation;
 TQ3StyleObject       backfacing;
 TQ3StyleObject       fillstyle;
};
typedef struct WindowInfo WindowInfo, *WindowInfoPtr, **WindowInfoHandle;
A standard way to attach an application-defined data structure (such as the WindowInfo structure) to a window is to set a handle to that structure as
the window's reference constant. This technique is used in Listing 1-5.

For a more complete description of using a window's reference constant to maintain window-specific information, see the discussion of document records in Inside Macintosh: Overview.<8bat>u

Listing 1-5 Creating a new window and attaching a window information structure

void MyNewWindow (void)
{
 WindowPtr        myWindow;
 Rect        myBounds = {42, 4, 442, 604};
 WindowInfoHandle        myWinfo;
 
 /*Create new window.*/
 myWindow = NewCWindow(0L, &myBounds, "\pWindow!", 1, documentProc,
          (WindowPtr) -1, true, 0L);
 if (myWindow == NULL)
  goto bail;
 SetPort(myWindow);

 /*Create storage for the new window and attach it to window.*/
 myWinfo = (WindowInfoHandle) NewHandle(sizeof(WindowInfo));
 if (myWinfo == NULL)
  goto bail;
 SetWRefCon(myWindow, (long) myWinfo);
 HLock((Handle) myWinfo);
 
 /*Create a new view.*/
 (**myWinfo).view = MyNewView(myWindow);
 if ((**myWinfo).view == NULL)
  goto bail;
 
 /*Create model to display.*/
 (**myWinfo).model = MyNewModel();           /*see Listing 1-4 on page 120*/
 if ((**myWinfo).model == NULL)
  goto bail;
 
 /*Configure an illumination shader.*/
 (**myWinfo).illumination = Q3PhongIllumination_New();
 if ((**myWinfo).illumination == NULL)
  goto bail;

 /*Configure the rendering styles.*/
 (**myWinfo).interpolation =
      Q3InterpolationStyle_New(kQ3InterpolationStyleNone);
 if ((**myWinfo).interpolation == NULL)
  goto bail;
 (**myWinfo).backfacing =
     Q3BackfacingStyle_New(kQ3BackfacingStyleRemoveBackfacing);
 if ((**myWinfo).backfacing == NULL)
  goto bail;
 (**myWinfo).fillstyle = Q3FillStyle_New(kQ3FillStyleFilled);
 if ((**myWinfo).fillstyle == NULL)
  goto bail;
 HUnlock((Handle) myWinfo);

 return;
 
bail:
 /*If failed for any reason, then close the window.*/
 if (myWinfo != NULL)
  DisposeHandle((Handle) myWinfo);
 if (myWindow != NULL)
  DisposeWindow(myWindow);
}
The MyNewWindow function creates a new window and a new window information structure, attaches the structure to the window, and then fills out several fields of that structure. In particular, MyNewWindow creates a new illumination shader that implements a Phong illumination model. You need an illumination shader for a view's lights to have any effect. (See the chapter "Shader Objects" for complete information on the available illumination shaders.) Then MyNewWindow disables interpolation between vertices of faces, removes unseen backfaces of objects in the model, and sets the renderer to render filled faces on those objects. These settings are actually passed to the renderer by submitting the styles during rendering. See "Rendering a Model," beginning on page 1-31 for details.

The MyNewWindow function can leak memory. Your application should use a different error-recovery
strategy than is used in Listing 1-5.<8bat>u

1 Creating Lights

When you use any renderer more powerful than the wireframe renderer, you'll want to create and configure a set of lights to provide illumination for the object in the model. As you've seen, QuickDraw3D provides a number of types of lights, each of which can emit light of various colors and intensities. The function MyNewLights defined in Listing 1-6 creates a group of lights. It creates an ambient light, a point light, and a directional light. See the chapter "Error Manager" for more details on creating lights.

Listing 1-6 Creating a group of lights

TQ3GroupObject MyNewLights (void)
{
 TQ3GroupPosition        myGroupPosition;
 TQ3GroupObject        myLightList;
 TQ3LightData        myLightData;
 TQ3PointLightData        myPointLightData;
 TQ3DirectionalLightData        myDirLightData;
 TQ3LightObject        myAmbientLight, myPointLight, myFillLight;
 TQ3Point3D        pointLocation = { -10.0, 0.0, 10.0 };
 TQ3Vector3D        fillDirection = { 10.0, 0.0, 10.0 };
 TQ3ColorRGB        WhiteLight = { 1.0, 1.0, 1.0 };
 
 /*Set up light data for ambient light.*/
 myLightData.isOn = kQ3True;
 myLightData.brightness = .2;
 myLightData.color = WhiteLight;
 
 /*Create ambient light.*/
 myAmbientLight = Q3AmbientLight_New(&myLightData);
 if (myAmbientLight == NULL)
  goto bail;
 
 /*Create a point light.*/
 myLightData.brightness = 1.0;
 myPointLightData.lightData = myLightData;
 myPointLightData.castsShadows = kQ3False;
 myPointLightData.attenuation = kQ3AttenuationTypeLinear;
 myPointLightData.location = pointLocation;
 myPointLight = Q3PointLight_New(&myPointLightData);
 if (myPointLight == NULL)
  goto bail;

 /*Create a directional light for fill.*/
 myLightData.brightness = .2;
 myDirLightData.lightData = myLightData;
 myDirLightData.castsShadows = kQ3False;
 myDirLightData.direction = fillDirection;
 myFillLight = Q3DirectionalLight_New(&myDirLightData);
 if (myFillLight == NULL)
  goto bail;

 /*Create light group and add each of the lights to the group.*/
 myLightList = Q3LightGroup_New();
 if (myLightList == NULL)
  goto bail;
 myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
 Q3Object_Dispose(myAmbientLight);            /*balance the reference count*/
 if (myGroupPosition == 0)
  goto bail;
 myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
 Q3Object_Dispose(myPointLight);            /*balance the reference count*/
 if (myGroupPosition == 0)
  goto bail;
 myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
 Q3Object_Dispose(myFillLight);            /*balance the reference count*/
 if (myGroupPosition == 0)
  goto bail;

 return (myLightList);
 
bail:
 /*If any of the above failed, then return nothing!*/
 return (NULL);
}
The MyNewLights function is straightforward. It fills out the fields of the relevant data structures (TQ3LightData, TQ3PointLightData, and TQ3DirectionalLightData) and calls the appropriate functions to create new light objects using the information in those structures. If successful, it adds those light objects to a group of lights. The group of lights will be added to a view, as shown in the following section.

The MyNewLights function can leak memory.<8bat>u

1 Creating a Draw Context

A draw context contains information that is specific to a particular type of window system, such as the extent of the pane to draw into and the method of clearing the window. You need to create a draw context and add it to a view in order to render a model. Listing 1-7 illustrates how to create a draw context for drawing into Macintosh windows.

Listing 1-7 Creating a Macintosh draw context

TQ3DrawContextObject MyNewDrawContext (WindowPtr theWindow)
{
 TQ3DrawContextObject        myDrawContext;
 TQ3DrawContextData        myDrawContextData;
 TQ3MacDrawContextData        myMacDrawContextData;
 TQ3ColorARGB        myClearColor;
 
 /*Set the background color.*/
 Q3ColorARGB_Set(&myClearColor, 1.0, 0.6, 0.9, 0.9);
 
 /*Fill in draw context data.*/
 myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
 myDrawContextData.clearImageColor = myClearColor;
 myDrawContextData.paneState = kQ3False;
 myDrawContextData.maskState = kQ3False;
 myDrawContextData.doubleBufferState = kQ3True;

 /*Fill in Macintosh-specific draw context data.*/
 myMacDrawContextData.drawContextData = myDrawContextData;
 myMacDrawContextData.window = (CWindowPtr) theWindow;
 myMacDrawContextData.library = kQ3Mac2DLibraryNone;
 myMacDrawContextData.viewPort = NULL;
 myMacDrawContextData.grafPort = NULL;

 /*Create draw context.*/
 myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData);
 
 return (myDrawContext);
}
Essentially, MyNewDrawContext just fills in the fields of a TQ3MacDrawContextData structure and calls Q3MacDrawContext_New to
create a new Macintosh draw context.

1 Creating a Camera

The remaining step before you can create a view is to create a camera object.
A camera object specifies a point of view and a method of projecting the three-dimensional model into two dimensions. Listing 1-8 illustrates how to create a camera. See the chapter "Camera Objects" for complete details on the routines called in MyNewCamera.

Listing 1-8 Creating a camera

TQ3CameraObject MyNewCamera (void)
{
 TQ3CameraObject         myCamera;
 TQ3CameraData         myCameraData;
 TQ3ViewAngleAspectCameraData         myViewAngleCameraData;
 TQ3Point3D         cameraFrom = { 0.0, 0.0, 15.0 };
 TQ3Point3D         cameraTo = { 0.0, 0.0, 0.0 };
 TQ3Vector3D         cameraUp = { 0.0, 1.0, 0.0 };
 
 /*Fill in camera data.*/
 myCameraData.placement.cameraLocation = cameraFrom;
 myCameraData.placement.pointOfInterest = cameraTo;
 myCameraData.placement.upVector = cameraUp;
 myCameraData.range.hither = .1;
 myCameraData.range.yon = 15.0;
 myCameraData.viewPort.origin.x = -1.0;
 myCameraData.viewPort.origin.y = 1.0;
 myCameraData.viewPort.width = 2.0;
 myCameraData.viewPort.height = 2.0;

 myViewAngleCameraData.cameraData = myCameraData;
 myViewAngleCameraData.fov = Q3Math_DegreesToRadians(100.0);
 myViewAngleCameraData.aspectRatioXToY = 1;

 myCamera = Q3ViewAngleAspectCamera_New(&myViewAngleCameraData);
 
 /*Return a camera.*/
 return (myCamera);
}
Like before, the MyNewCamera function simply fills out the fields of the appropriate data structures and calls the Q3ViewAngleAspectCamera_New function to create a new camera object.

All angles in QuickDraw3D are specified in radians. You can use the Q3Math_DegreesToRadians macro to convert degrees to radians, as illustrated in Listing 1-8, which sets the fov field to 100 degrees.<8bat>s

1 Creating a View

A view is a collection of a model, a group of lights, a camera, a renderer, and a draw context. Now that you've defined functions that create all the requisite parts of a view (except the renderer), you can create a view, as illustrated in Listing 1-9. To do this, you create a new empty view object and then explicitly add the parts to it.

To create an image in a window, a view must contain at least a camera, a renderer, and a draw context.<8bat>s

Listing 1-9 Creating a view

TQ3ViewObject MyNewView (WindowPtr theWindow)
{
 TQ3Status         myStatus;
 TQ3ViewObject         myView;
 TQ3DrawContextObject         myDrawContext;
 TQ3RendererObject         myRenderer;
 TQ3CameraObject         myCamera;
 TQ3GroupObject         myLights;
 
 myView = Q3View_New();
 if (myView == NULL)
  goto bail;
 
 /*Create and set draw context.*/
 myDrawContext = MyNewDrawContext(theWindow);
 if (myDrawContext == NULL)
  goto bail;
 myStatus = Q3View_SetDrawContext(myView, myDrawContext);
 Q3Object_Dispose(myDrawContext);
 if (myStatus == kQ3Failure)
  goto bail;
 
 /*Create and set renderer.*/
 myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
 if (myRenderer == NULL)
  goto bail;
 myStatus = Q3View_SetRenderer(myView, myRenderer);
 Q3Object_Dispose(myRenderer);
 if (myStatus == kQ3Failure)
  goto bail;

 /*Create and set camera.*/
 myCamera = MyNewCamera();
 if (myCamera == NULL)
  goto bail;
 myStatus = Q3View_SetCamera(myView, myCamera);
 Q3Object_Dispose(myCamera);
 if (myStatus == kQ3Failure)
  goto bail;

 /*Create and set lights.*/
 myLights = MyNewLights();
 if (myLights == NULL)
  goto bail;
 myStatus = Q3View_SetLightGroup(myView, myLights);
 Q3Object_Dispose(myLights);
 if (myStatus == kQ3Failure)
  goto bail;

 return (myView);
 
bail:
 /*If any of the above failed, then don't return a view.*/
 return (NULL);
}

1 Rendering a Model

To render a model using a view, you call QuickDraw3D functions that submit the various shape objects (for instance, geometric objects, groups of geometric objects, and styles) that you want to appear in the view. Because a model might be too complex to process in a single pass (and for other reasons as well), you should call the rendering routines in a rendering loop. A rendering loop begins with a call to the Q3View_StartRendering function and should end when a call to the Q3View_EndRendering function returns some value other than kQ3ViewStatusRetraverse. Within the body of the rendering loop, you should submit the shapes you want rendered. Listing 1-10 shows the general structure of a rendering loop.

Listing 1-10 A basic rendering loop

Q3View_StartRendering(myView);
do {
 /*Submit your shape objects here.*/
 Q3DisplayGroup_Submit(myGroup, myView);
} while (Q3View_EndRendering(myView) == kQ3ViewStatusRetraverse);
The Q3View_EndRendering function returns a view status value that indicates whether the renderer has finished processing the model. The available view status values are defined by these constants:

typedef enum {
 kQ3ViewStatusDone,
 kQ3ViewStatusRetraverse,
 kQ3ViewStatusError,
 kQ3ViewStatusCancelled
} TQ3ViewStatus;
Listing 1-11 illustrates how to render the model defined in Listing 1-4 (page 1-20), using the view created and configured in Listing 1-9 (page 1-30). The MyDraw function defined in Listing 1-11 retrieves the window information structure attached to a window and uses the information in it to render
the model.

Listing 1-11 Rendering a model

void MyDraw (WindowPtr theWindow)
{
 WindowInfoHandle        myWinfo;
 TQ3Status        myStat;
 TQ3DrawContextObject        myDrawContext;
 TQ3ViewStatus        myViewStatus;
 
 if (theWindow == NULL)
  return;

 myWinfo = (WindowInfoHandle) GetWRefCon(theWindow);
 HLock((Handle) myWinfo);
 
 /*Start rendering.*/
 myStat = Q3View_StartRendering((**myWinfo).view);
 if (myStat == kQ3Failure)
  goto bail;

 do {
  myStat = Q3Shader_Submit((**myWinfo).illumination, (**myWinfo).view);
  if (myStat == kQ3Failure)
   goto bail;
  myStat = Q3Style_Submit((**myWinfo).interpolation, (**myWinfo).view);
  if (myStat == kQ3Failure)
   goto bail;
  myStat = Q3Style_Submit((**myWinfo).backfacing, (**myWinfo).view);
  if (myStat == kQ3Failure)
   goto bail;
  myStat = Q3Style_Submit((**myWinfo).fillstyle, (**myWinfo).view);
  if (myStat == kQ3Failure)
   goto bail;


  myStat = Q3DisplayGroup_Submit((**myWinfo).model, (**myWinfo).view);
  if (myStat == kQ3Failure)
   goto bail;
  
  myViewStatus = Q3View_EndRendering((**myWinfo).view);
 } while (myViewStatus == kQ3ViewStatusRetraverse);
 
 HUnlock((Handle) myWinfo);
 return;

bail:
 HUnlock((Handle) myWinfo);
 SysBeep(50);
}
The rendering loop allows your application to work with any current and future renderers that require multiple passes through a model's data in order to provide features such as transparency and CSG.

For complete information about rendering loops and other kinds of submitting loops, see the chapter "View Objects" in this book.

Compiling Your Application
Initializing and Terminating QuickDraw3D
Creating a Model
Configuring a Window
Creating Lights
Creating a Draw Context
Creating a Camera
Creating a View
Rendering a Model

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

© Apple Computer, Inc.

Let us know what you think of these prototype pages.

Generated with Harlequin WebMaker