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.
Box3DSupport.c
// My3dSupport.c - QuickDraw 3d routines |
// |
// This file contains utility routines for QuickDraw 3d sample code. |
// This is a simple QuickDraw 3d application to draw a cube in the center |
// of the main application window. The routines in here handle setting up |
// the main display group, the view, the Macintosh 3D draw context, and the |
// camera and lighting. |
// |
// This code is the basis of the introductory article in d e v e l o p issue 22 |
// |
// Nick Thompson - January 6th 1995 |
// |
// ©1994-95 Apple computer Inc., All Rights Reserved |
// |
#include <QuickDraw.h> |
#include <QDOffScreen.h> |
#include "Box3DSupport.h" |
#include "QD3DDrawContext.h" |
#include "QD3DRenderer.h" |
#include "QD3DShader.h" |
#include "QD3DCamera.h" |
#include "QD3DLight.h" |
#include "QD3DGeometry.h" |
#include "QD3DGroup.h" |
#include "QD3DMath.h" |
#include "QD3DSet.h" |
#include "QD3DTransform.h" |
#include "QD3DAcceleration.h" |
static TQ3Point3D documentGroupCenter; |
static float documentGroupScale; |
TQ3ViewObject MyNewView(WindowPtr theWindow) |
{ |
TQ3Status myStatus; |
TQ3ViewObject myView; |
TQ3DrawContextObject myDrawContext; |
TQ3RendererObject myRenderer; |
TQ3CameraObject myCamera; |
TQ3GroupObject myLights; |
myView = Q3View_New(); |
// Create and set draw context. |
if ((myDrawContext = MyNewDrawContext(theWindow)) == nil ) |
goto bail; |
if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure ) |
goto bail; |
Q3Object_Dispose( myDrawContext ) ; |
// Create and set renderer. |
// this would use the wireframe renderer |
#if 0 |
myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame); |
if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) { |
goto bail; |
} |
#else |
// this would use the interactive software renderer |
if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != nil ) { |
if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) { |
goto bail; |
} |
// these two lines set us up to use the best possible renderer, |
// including hardware if it is installed. |
Q3InteractiveRenderer_SetDoubleBufferBypass (myRenderer, kQ3True); |
Q3InteractiveRenderer_SetPreferences(myRenderer, kQAVendor_BestChoice, 0); |
/* |
* the line below would force the use of the software rasterizer |
* |
* Q3InteractiveRenderer_SetPreferences(myRenderer, kQAVendor_Apple, kQAEngine_AppleSW); |
* |
*/ |
} |
else { |
goto bail; |
} |
#endif |
Q3Object_Dispose( myRenderer ) ; |
// Create and set camera. |
if ( (myCamera = MyNewCamera(theWindow)) == nil ) |
goto bail; |
if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure ) |
goto bail; |
Q3Object_Dispose( myCamera ) ; |
// Create and set lights. |
if ((myLights = MyNewLights()) == nil ) |
goto bail; |
if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure ) |
goto bail; |
Q3Object_Dispose(myLights); |
// Done!!! |
return ( myView ); |
bail: |
// If any of the above failed, then don't return a view. |
return ( nil ); |
} |
//---------------------------------------------------------------------------------- |
TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow) |
{ |
TQ3DrawContextData myDrawContextData; |
TQ3MacDrawContextData myMacDrawContextData; |
TQ3ColorARGB ClearColor; |
TQ3DrawContextObject myDrawContext ; |
// Set the background color. |
ClearColor.a = 1.0; |
ClearColor.r = 1.0; |
ClearColor.g = 1.0; |
ClearColor.b = 1.0; |
// Fill in draw context data. |
myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor; |
myDrawContextData.clearImageColor = ClearColor; |
myDrawContextData.paneState = kQ3False; |
myDrawContextData.maskState = kQ3False; |
myDrawContextData.doubleBufferState = kQ3True; |
myMacDrawContextData.drawContextData = myDrawContextData; |
myMacDrawContextData.window = (CGrafPtr) theWindow; // this is the window associated with the view |
myMacDrawContextData.library = kQ3Mac2DLibraryNone; |
myMacDrawContextData.viewPort = nil; |
myMacDrawContextData.grafPort = nil; |
// Create draw context and return it, if itÕs nil the caller must handle |
myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData) ; |
return myDrawContext ; |
} |
//---------------------------------------------------------------------------------- |
TQ3CameraObject MyNewCamera(WindowPtr theWindow) |
{ |
TQ3ViewAngleAspectCameraData perspectiveData; |
TQ3CameraObject camera; |
TQ3Point3D from = { 0.0, 0.0, 7.0 }; |
TQ3Point3D to = { 0.0, 0.0, 0.0 }; |
TQ3Vector3D up = { 0.0, 1.0, 0.0 }; |
float fieldOfView = 1.0; |
float hither = 1.0; |
float yon = 1000; |
TQ3Status returnVal = kQ3Failure ; |
perspectiveData.cameraData.placement.cameraLocation = from; |
perspectiveData.cameraData.placement.pointOfInterest = to; |
perspectiveData.cameraData.placement.upVector = up; |
perspectiveData.cameraData.range.hither = hither; |
perspectiveData.cameraData.range.yon = yon; |
perspectiveData.cameraData.viewPort.origin.x = -1.0; |
perspectiveData.cameraData.viewPort.origin.y = 1.0; |
perspectiveData.cameraData.viewPort.width = 2.0; |
perspectiveData.cameraData.viewPort.height = 2.0; |
perspectiveData.fov = fieldOfView; |
perspectiveData.aspectRatioXToY = |
(float) (theWindow->portRect.right - theWindow->portRect.left) / |
(float) (theWindow->portRect.bottom - theWindow->portRect.top); |
camera = Q3ViewAngleAspectCamera_New(&perspectiveData); |
return camera ; |
} |
//---------------------------------------------------------------------------------- |
TQ3GroupObject MyNewLights() |
{ |
TQ3GroupPosition myGroupPosition; |
TQ3GroupObject myLightList; |
TQ3LightData myLightData; |
TQ3PointLightData myPointLightData; |
TQ3DirectionalLightData myDirectionalLightData; |
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. This light data will be used for point and fill |
// light also. |
myLightData.isOn = kQ3True; |
myLightData.color = WhiteLight; |
// Create ambient light. |
myLightData.brightness = .2; |
myAmbientLight = Q3AmbientLight_New(&myLightData); |
if ( myAmbientLight == nil ) |
goto bail; |
// Create point light. |
myLightData.brightness = 1.0; |
myPointLightData.lightData = myLightData; |
myPointLightData.castsShadows = kQ3False; |
myPointLightData.attenuation = kQ3AttenuationTypeNone; |
myPointLightData.location = pointLocation; |
myPointLight = Q3PointLight_New(&myPointLightData); |
if ( myPointLight == nil ) |
goto bail; |
// Create fill light. |
myLightData.brightness = .2; |
myDirectionalLightData.lightData = myLightData; |
myDirectionalLightData.castsShadows = kQ3False; |
myDirectionalLightData.direction = fillDirection; |
myFillLight = Q3DirectionalLight_New(&myDirectionalLightData); |
if ( myFillLight == nil ) |
goto bail; |
// Create light group and add each of the lights into the group. |
myLightList = Q3LightGroup_New(); |
if ( myLightList == nil ) |
goto bail; |
myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight); |
if ( myGroupPosition == 0 ) |
goto bail; |
myGroupPosition = Q3Group_AddObject(myLightList, myPointLight); |
if ( myGroupPosition == 0 ) |
goto bail; |
myGroupPosition = Q3Group_AddObject(myLightList, myFillLight); |
if ( myGroupPosition == 0 ) |
goto bail; |
Q3Object_Dispose( myAmbientLight ) ; |
Q3Object_Dispose( myPointLight ) ; |
Q3Object_Dispose( myFillLight ) ; |
// Done! |
return ( myLightList ); |
bail: |
// If any of the above failed, then return nothing! |
return ( nil ); |
} |
static void MyColorBoxFaces( TQ3BoxData *myBoxData ) |
{ |
TQ3ColorRGB faceColor ; |
short face ; |
// sanity check - you need to have set up |
// the face attribute set for the box data |
// before calling this. |
if( myBoxData->faceAttributeSet == NULL ) |
return ; |
// make each face of a box a different color |
for( face = 0; face < 6; face++) { |
myBoxData->faceAttributeSet[face] = Q3AttributeSet_New(); |
switch( face ) { |
case 0: |
faceColor.r = 1.0; |
faceColor.g = 0.0; |
faceColor.b = 0.0; |
break; |
case 1: |
faceColor.r = 0.0; |
faceColor.g = 1.0; |
faceColor.b = 0.0; |
break; |
case 2: |
faceColor.r = 0.0; |
faceColor.g = 0.0; |
faceColor.b = 1.0; |
break; |
case 3: |
faceColor.r = 1.0; |
faceColor.g = 1.0; |
faceColor.b = 0.0; |
break; |
case 4: |
faceColor.r = 1.0; |
faceColor.g = 0.0; |
faceColor.b = 1.0; |
break; |
case 5: |
faceColor.r = 0.0; |
faceColor.g = 1.0; |
faceColor.b = 1.0; |
break; |
} |
Q3AttributeSet_Add(myBoxData->faceAttributeSet[face], kQ3AttributeTypeDiffuseColor, &faceColor); |
} |
} |
static TQ3GroupPosition MyAddTransformedObjectToGroup( TQ3GroupObject theGroup, TQ3Object theObject, TQ3Vector3D *translation ) |
{ |
TQ3TransformObject transform; |
transform = Q3TranslateTransform_New(translation); |
Q3Group_AddObject(theGroup, transform); |
Q3Object_Dispose(transform); |
return Q3Group_AddObject(theGroup, theObject); |
} |
TQ3GroupObject MyNewModel() |
{ |
TQ3GroupObject myGroup = NULL; |
TQ3GeometryObject myBox; |
TQ3BoxData myBoxData; |
TQ3ShaderObject myIlluminationShader ; |
TQ3Vector3D translation; |
TQ3SetObject faces[6] ; |
short face ; |
// Create a group for the complete model. |
// do not use Q3OrderedDisplayGroup_New since in this |
// type of group all of the translations are applied before |
// the objects in the group are drawn, in this instance we |
// dont want this. |
if ((myGroup = Q3DisplayGroup_New()) != NULL ) { |
// Define a shading type for the group |
// and add the shader to the group |
myIlluminationShader = Q3PhongIllumination_New(); |
Q3Group_AddObject(myGroup, myIlluminationShader); |
// set up the colored faces for the box data |
myBoxData.faceAttributeSet = faces; |
myBoxData.boxAttributeSet = nil; |
MyColorBoxFaces( &myBoxData ) ; |
// create the box itself |
Q3Point3D_Set(&myBoxData.origin, 0, 0, 0); |
Q3Vector3D_Set(&myBoxData.orientation, 0, 1, 0); |
Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 1); |
Q3Vector3D_Set(&myBoxData.minorAxis, 1, 0, 0); |
myBox = Q3Box_New(&myBoxData); |
// put four copies of the box into the group, each one with its own translation |
translation.x = 0;translation.y = 0;translation.z = 0; |
MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ; |
translation.x = 2;translation.y = 0;translation.z = 0; |
MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ; |
translation.x = 0;translation.y = 0;translation.z = -2; |
MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ; |
translation.x = -2;translation.y = 0;translation.z = 0; |
MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ; |
} |
// dispose of the objects we created here |
if( myIlluminationShader ) |
Q3Object_Dispose(myIlluminationShader); |
for( face = 0; face < 6; face++) { |
if( myBoxData.faceAttributeSet[face] != NULL ) |
Q3Object_Dispose(myBoxData.faceAttributeSet[face]); |
} |
if( myBox ) |
Q3Object_Dispose( myBox ); |
// Done! |
return ( myGroup ); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14