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/TriGridShell.c
// |
// This is box, the QuickDraw 3D starter program. Written for the |
// Getting started with QuickDraw 3D Develop article. This app does not have |
// graceful error handling - it's purpose is to illustrate a very basic QuickDraw |
// 3D program. |
// |
// Nick Thompson - January 6th 1994 |
// |
// Modification History: |
// |
// 1/6/95 nick initial version based on cube |
// 12/31/94 nick cube modifications for QuickDraw 3d sample code |
// 03/22/95 rdd adapted from BoxShell.c: added simple picking |
// and trigrid selection via number keys |
// 04/12/95 rdd added SetCameraLocation. |
// 04/14/95 rdd added menu support. |
// |
// system headers |
#include <Dialogs.h> |
#include <Devices.h> |
#include <DiskInit.h> |
#include <Fonts.h> |
#include <Menus.h> |
#include <QDOffScreen.h> |
#include <QuickDraw.h> |
#include <Resources.h> |
#include <SegLoad.h> |
#include <StandardFile.h> |
#include <TextEdit.h> |
#include <ToolUtils.h> |
// for QuickDraw 3D |
#include "QD3D.h" |
#include "QD3DMath.h" |
#include "QD3DCamera.h" |
#include "QD3DDrawContext.h" |
#include "QD3DShader.h" |
#include "QD3DTransform.h" |
#include "QD3DGroup.h" |
#include "QD3DPick.h" |
#include "TriGridShell.h" |
#include "TriGrid3DSupport.h" |
#include "GeometrySample.h" |
#include "Textures2.h" |
//------------------------------------------------------------------------------------------- |
struct _documentRecord { |
TQ3ViewObject fView ; // the view for the scene |
TQ3GroupObject fModel ; // object in the scene being modelled |
TQ3StyleObject fInterpolation ; // interpolation style used when rendering |
TQ3StyleObject fBackFacing ; // whether to draw shapes that face away from the camera |
TQ3StyleObject fFillStyle ; // whether drawn as solid filled object or decomposed to components |
TQ3Matrix4x4 fRotation ; // the transform for the model |
unsigned short fGeometryNum ; // triGrid geometry 1-9 (menu item number) |
unsigned short fTextureType ; // method of uv parameterization for texture (menu item number) |
unsigned short fPictureNum ; // PICT (menu item number) |
}; |
typedef struct _documentRecord DocumentRec, *DocumentPtr, **DocumentHdl ; |
//------------------------------------------------------------------------------------------- |
// function prototypes |
static void InitToolbox( void ) ; |
static Boolean SetUpMenus (void) ; |
static void IntializeMenuItems (DocumentPtr theDocument) ; |
static void MainEventLoop( void ) ; |
static void HandleKeyPress(EventRecord *pEvent) ; |
static void DoAboutBox (void); |
static void DoMenuCommand (long menuResult) ; |
static void HandleOSEvent(EventRecord *event) ; |
static void InitDocumentData( DocumentPtr theDocument ) ; |
static TQ3Status DocumentDraw3DData( DocumentPtr theDocument ) ; |
static void DisposeDocumentData( DocumentPtr theDocument) ; |
static void SetCameraLocation (TQ3ViewObject view, float x, float y, float z); |
static void ChangeGeometry (DocumentPtr theDocument) ; |
static void DoPicking(EventRecord *event) ; |
//------------------------------------------------------------------------------------------- |
// |
Boolean gQuitFlag = false ; |
WindowPtr gMainWindow = nil ; |
DocumentRec gDocument ; |
Handle ghMenuBar ; |
short gNumPictures ; |
//------------------------------------------------------------------------------------------- |
// main() |
// entry point for the application, initialize the toolbox, initialize QuickDraw 3D |
// and enter the main event loop. On exit from the main event loop, we want to call |
// the QuickDraw 3D exit function to clean up QuickDraw 3d. |
void main(void) |
{ |
TQ3Status myStatus; |
InitToolbox() ; |
SetUpMenus () ; |
// Initialize QuickDraw 3D, open a connection to the QuickDraw 3D library |
myStatus = Q3Initialize(); |
if ( myStatus == kQ3Failure ) |
DebugStr("\pErInitialize returned failure."); |
// set up our globals |
gQuitFlag = false ; |
gMainWindow = GetNewCWindow(kWindowRsrcID, nil, (WindowPtr)-1); |
InitDocumentData( &gDocument ) ; |
IntializeMenuItems ( &gDocument ) ; |
MainEventLoop(); |
DisposeDocumentData( &gDocument ) ; |
// Close our connection to the QuickDraw 3D library |
myStatus = Q3Exit(); |
if ( myStatus == kQ3Failure ) |
DebugStr("\pErExit returned failure."); |
} |
//------------------------------------------------------------------------------------------- |
// |
void InitDocumentData( DocumentPtr theDocument ) |
{ |
// sets up the 3d data for the scene |
// Create view for QuickDraw 3D. |
theDocument->fView = MyNewView( (WindowPtr)gMainWindow ) ; |
// the drawing styles: |
theDocument->fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleNone) ; |
theDocument->fBackFacing = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth ) ; |
theDocument->fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled ) ; |
// set the rotation matrix the identity matrix |
Q3Matrix4x4_SetIdentity(&theDocument->fRotation); |
theDocument->fGeometryNum = iFlat ; |
theDocument->fTextureType = iNoTexture ; |
theDocument->fPictureNum = iPictureFirst ; |
// the main display group: |
theDocument->fModel = MyNewModel() ; |
ChangeGeometry (theDocument); |
} |
void DisposeDocumentData( DocumentPtr theDocument) |
{ |
if(theDocument->fView) |
Q3Object_Dispose(theDocument->fView) ; // the view for the scene |
if(theDocument->fModel) |
Q3Object_Dispose(theDocument->fModel) ; // object in the scene being modelled |
if(theDocument->fInterpolation) |
Q3Object_Dispose(theDocument->fInterpolation) ; // interpolation style used when rendering |
if(theDocument->fBackFacing) |
Q3Object_Dispose(theDocument->fBackFacing) ; // whether to draw shapes that face away from the camera |
if(theDocument->fFillStyle) |
Q3Object_Dispose(theDocument->fFillStyle) ; // whether drawn as solid filled object or decomposed to components |
} |
//----------------------------------------------------------------------------- |
// |
TQ3Status DocumentDraw3DData( DocumentPtr theDocument ) |
{ |
Q3View_StartRendering(theDocument->fView ); |
do { |
Q3Style_Submit( theDocument->fInterpolation, theDocument->fView ); |
Q3Style_Submit( theDocument->fBackFacing, theDocument->fView ); |
Q3Style_Submit( theDocument->fFillStyle, theDocument->fView ); |
Q3MatrixTransform_Submit( &theDocument->fRotation, theDocument->fView ); |
Q3DisplayGroup_Submit( theDocument->fModel, theDocument->fView ); |
} while (Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse ); |
return kQ3Success ; |
} |
//---------------------------------------------------------------------------------- |
// |
void InitToolbox() |
{ |
Handle menuBar = nil; |
MaxApplZone() ; |
MoreMasters() ; MoreMasters() ; MoreMasters() ; |
InitGraf( &qd.thePort ); |
InitFonts(); |
InitWindows(); |
InitCursor(); |
FlushEvents( everyEvent, 0 ) ; |
// initialize application globals |
gQuitFlag = false; |
} |
//------------------------------------------------------------------------------------------- |
// |
Boolean SetUpMenus (void) |
{ |
Boolean goodMenus; |
goodMenus = true; |
ghMenuBar = GetNewMBar (kMenuBarRsrc); |
if (ghMenuBar != nil) |
{ |
SetMenuBar (ghMenuBar); |
AppendResMenu (GetMenuHandle (mApple), (ResType) 'DRVR'); |
DrawMenuBar (); |
} |
else |
{ |
DebugStr ("\pSetUpMenus: Couldn't find menu bar."); |
ghMenuBar = nil; |
goodMenus = false; |
} |
return (goodMenus); |
} |
//------------------------------------------------------------------------------------------- |
// |
void IntializeMenuItems (DocumentPtr theDocument) |
{ |
MenuHandle hMenu; |
Str255 menuPrefix = {"\pPicture "}, |
itemText, |
numString; |
long item; |
short rsrcID; |
ResType rsrcType; |
Handle hPict; |
hMenu = GetMenuHandle(mTexture); |
gNumPictures = Count1Resources ('PICT'); |
/* PICT resources to be used as textures must be numbered starting with kFirstPICTRsrcID */ |
SetResLoad (false); |
for (item = 0; item < gNumPictures; item++) |
{ |
itemText[0] = 0; |
hPict = GetResource ('PICT', kFirstPICTRsrcID + item); |
if (hPict != NULL) |
GetResInfo (hPict, &rsrcID, &rsrcType, itemText); |
else |
break; |
if (itemText[0] == 0) |
{ |
BlockMove ((Ptr) menuPrefix, (Ptr) itemText, (Size) menuPrefix[0]+1); |
NumToString (item+1, numString); |
itemText[0] += numString[0]; |
BlockMove ((Ptr) &numString[1], (Ptr) itemText[itemText[0]+1], (Size) numString[0]); |
} |
AppendMenu (hMenu, itemText); |
} |
SetResLoad (true); |
gNumPictures = item; |
if (theDocument->fTextureType == iNoTexture) |
{ |
for (item = iPictureFirst; item < iPictureFirst + gNumPictures; item++) |
DisableItem(hMenu, item); |
} |
CheckItem (GetMenuHandle (mGeometry), theDocument->fGeometryNum, true); |
CheckItem (hMenu, theDocument->fTextureType, true); |
CheckItem (hMenu, theDocument->fPictureNum, true); |
} |
//------------------------------------------------------------------------------------------- |
// |
void MainEventLoop() |
{ |
EventRecord event; |
WindowPtr window; |
short thePart; |
Rect screenRect, updateRect; |
Point aPoint = {100, 100}; |
while( !gQuitFlag ) |
{ |
if (WaitNextEvent( everyEvent, &event, 0, nil )) |
{ |
switch (event.what) { |
case mouseDown: |
thePart = FindWindow( event.where, &window ); |
switch( thePart ) { |
case inMenuBar: |
DoMenuCommand (MenuSelect (event.where)); |
break; |
case inSysWindow: |
SystemClick (&event, window); |
break; |
case inDrag: |
screenRect = (**GetGrayRgn()).rgnBBox; |
DragWindow( window, event.where, &screenRect ); |
break ; |
case inContent: |
if (window != FrontWindow()) |
SelectWindow( window ); |
DoPicking(&event); |
break ; |
case inGoAway: |
if (TrackGoAway( window, event.where )) { |
DisposeWindow ( window ); |
gQuitFlag = true; |
} |
break ; |
default: |
case inGrow: |
case inZoomIn: |
case inZoomOut: |
break ; |
} |
break ; |
case updateEvt: |
window = (WindowPtr)event.message; |
updateRect = (**(window->visRgn)).rgnBBox; |
SetPort( window ) ; |
BeginUpdate( window ); |
DocumentDraw3DData( &gDocument ) ; |
EndUpdate( window ); |
break ; |
case keyDown: |
case autoKey: |
HandleKeyPress(&event); |
break; |
case diskEvt: |
if ( HiWord(event.message) != noErr ) |
(void) DIBadMount(aPoint, event.message); |
break; |
case osEvt: |
case activateEvt: |
break; |
} |
} |
else { |
// we received a null event, rotate the cube |
TQ3Matrix4x4 tmp; |
Rect theRect = ((GrafPtr)gMainWindow)->portRect ; |
SetPort((GrafPtr)gMainWindow) ; |
Q3Matrix4x4_SetRotate_XYZ(&tmp, 0.1, 0.12, 0.08); |
Q3Matrix4x4_Multiply(&gDocument.fRotation, &tmp, &gDocument.fRotation); |
InvalRect( &theRect ) ; |
} |
} |
} |
//------------------------------------------------------------------------------------------- |
// |
void HandleKeyPress(EventRecord *pEvent) |
{ |
char charCode; |
charCode = pEvent->message & charCodeMask; |
if (pEvent->modifiers & btnState) |
{ |
/* Button is UP with a key */ |
if (pEvent->modifiers & cmdKey) |
{ |
DoMenuCommand (MenuKey (charCode)); |
} |
} |
else |
{ |
/* Button is DOWN with a key */ |
} |
} |
//------------------------------------------------------------------------------------------- |
// |
void DoAboutBox (void) |
{ |
DialogPtr theDialog; |
short itemHit; |
theDialog = GetNewDialog(kDialogRsrcID, nil, (WindowPtr)-1); |
if (theDialog == nil) |
return; |
do |
{ |
ModalDialog (nil, &itemHit); |
} |
while (itemHit != ok); |
DisposeDialog (theDialog); |
} |
//------------------------------------------------------------------------------------------- |
// |
void DoMenuCommand (long menuResult) |
{ |
short menuID, |
itemNumber; |
if (! menuResult) |
return; |
menuID = HiWord (menuResult); |
itemNumber = LoWord (menuResult); |
switch (menuID) |
{ |
case mApple: |
switch (itemNumber) |
{ |
case iAbout: |
DoAboutBox(); |
break; |
default: |
{ |
MenuHandle hMenu; |
Str255 deskAccName; |
GrafPtr oldPort; |
hMenu = GetMenuHandle (menuID); |
if (hMenu != nil) |
{ |
GetPort (&oldPort); |
GetMenuItemText (hMenu, itemNumber, deskAccName); |
(void) OpenDeskAcc (deskAccName); |
SetPort (oldPort); |
} |
} |
break; |
} |
break; |
case mFile: |
switch (itemNumber) |
{ |
case iNew: break; |
case iOpen: break; |
case iClose: break; |
case iQuit: |
gQuitFlag = true;break; |
default: SysBeep(1);break; |
} |
break; |
case mEdit: |
if (! SystemEdit (itemNumber - 1)) |
switch (itemNumber) |
{ |
case iUndo: break; |
case iCut: break; |
case iCopy: break; |
case iPaste: break; |
case iClear: break; |
} |
break; |
case mGeometry: |
if (itemNumber != gDocument.fGeometryNum) |
{ |
CheckItem (GetMenuHandle (mGeometry), gDocument.fGeometryNum, false); |
gDocument.fGeometryNum = itemNumber; |
CheckItem (GetMenuHandle (mGeometry), gDocument.fGeometryNum, true); |
ChangeGeometry (&gDocument); |
} |
break; |
case mTexture: |
if (itemNumber >= iNoTexture && itemNumber <= iFaceTexture) |
{ |
if (itemNumber != gDocument.fTextureType) |
{ |
long item; |
if (gDocument.fTextureType == iNoTexture) |
{ |
for (item = iPictureFirst; item < iPictureFirst + gNumPictures; item++) |
EnableItem(GetMenuHandle (menuID), item); |
} |
else |
if (itemNumber == iNoTexture) |
{ |
for (item = iPictureFirst; item < iPictureFirst + gNumPictures; item++) |
DisableItem(GetMenuHandle (menuID), item); |
} |
CheckItem (GetMenuHandle (mTexture), gDocument.fTextureType, false); |
gDocument.fTextureType = itemNumber; |
CheckItem (GetMenuHandle (mTexture), gDocument.fTextureType, true); |
ChangeGeometry (&gDocument); |
} |
} |
else |
if (itemNumber >= iPictureFirst && itemNumber <= iPictureFirst + gNumPictures - 1) |
{ |
if (itemNumber != gDocument.fPictureNum) |
{ |
CheckItem (GetMenuHandle (mTexture), gDocument.fPictureNum, false); |
gDocument.fPictureNum = itemNumber; |
CheckItem (GetMenuHandle (mTexture), gDocument.fPictureNum, true); |
ChangeGeometry (&gDocument); |
} |
} |
break; |
default: |
break; |
} /* switch (menuID) */ |
HiliteMenu (0); |
} |
//------------------------------------------------------------------------------------------- |
// |
void SetCameraLocation (TQ3ViewObject view, float x, float y, float z) |
{ |
TQ3CameraObject camera; |
TQ3CameraData cameraData; |
Q3View_GetCamera(view, &camera); |
if (camera != nil) |
{ |
Q3Camera_GetData(camera, &cameraData); |
Q3Point3D_Set(&cameraData.placement.cameraLocation, x, y, z); |
Q3Camera_SetData(camera, &cameraData); |
Q3Object_Dispose(camera); |
} |
} |
//------------------------------------------------------------------------------------------- |
// |
void ChangeGeometry (DocumentPtr theDocument) |
{ |
TQ3Status status; |
TQ3Object object; |
TQ3GroupPosition position; |
unsigned long triGridLibNum; |
if (theDocument->fModel == nil) |
return; |
status = Q3Group_GetFirstPositionOfType(theDocument->fModel, kQ3ShapeTypeGeometry, &position); |
if (status == kQ3Success && position != nil) |
{ |
object = Q3Group_RemovePosition(theDocument->fModel, position); |
Q3Object_Dispose(object); |
object = NULL; |
} |
switch (theDocument->fTextureType) |
{ |
case iNoTexture: triGridLibNum = (theDocument->fGeometryNum-1) + kGeometryLibraryRange_Simple; break; |
case iGeometryTexture: triGridLibNum = (theDocument->fGeometryNum-1) + kGeometryLibraryRange_UVGeoAttributes; break; |
case iFaceTexture: triGridLibNum = (theDocument->fGeometryNum-1) + kGeometryLibraryRange_UVFaceAttributes;break; |
} |
object = NewLibraryTriGrid(triGridLibNum); |
if (object == NULL) |
return; |
Q3Group_AddObject (theDocument->fModel, object); |
/* Add diffuse color if no texture */ |
if (theDocument->fTextureType == iNoTexture) |
{ |
TQ3AttributeSet attrSet; |
TQ3ColorRGB rgbColor; |
attrSet = Q3AttributeSet_New(); |
if (attrSet != NULL) |
{ |
Q3ColorRGB_Set(&rgbColor, 0.0, 0.75, 0.75); |
status = Q3AttributeSet_Add(attrSet, kQ3AttributeTypeDiffuseColor, &rgbColor); |
if (status == kQ3Success) |
{ |
Q3Geometry_SetAttributeSet(object, attrSet); |
Q3Object_Dispose(attrSet); |
} |
} |
} |
else |
/* Add texture shader */ |
AddResourceTextureToGroup(theDocument->fPictureNum - iPictureFirst + kFirstPICTRsrcID, theDocument->fModel); |
Q3Object_Dispose(object); |
/* (These cameral locations could be calculated) */ |
switch (theDocument->fGeometryNum) |
{ |
case iFlat: SetCameraLocation (theDocument->fView, 0.0, 0.0, 4.0); break; |
case iTorus: SetCameraLocation (theDocument->fView, 0.0, 0.0, 10.0); break; |
case iWaveyTorus: SetCameraLocation (theDocument->fView, 0.0, 0.0, 10.0); break; |
case iSplash: SetCameraLocation (theDocument->fView, 0.0, 0.0, 25.0); break; |
case iSphere: SetCameraLocation (theDocument->fView, 0.0, 0.0, 7.0); break; |
case iCone: SetCameraLocation (theDocument->fView, 0.0, 0.0, 9.0); break; |
case iPipe: SetCameraLocation (theDocument->fView, 0.0, 0.0, 10.0); break; |
case iSteps: SetCameraLocation (theDocument->fView, 0.0, 0.0, 30.0); break; |
case iSpring: SetCameraLocation (theDocument->fView, 0.0, 0.0, 11.0); break; |
} |
} |
//------------------------------------------------------------------------------------------- |
// |
void DoPicking(EventRecord *event) |
{ |
Point screenPoint; |
TQ3WindowPointPickData withData; |
unsigned long numPicked; |
TQ3PickObject pickObject; |
TQ3Status status; |
TQ3ViewStatus viewStatus; |
withData.data.sort = kQ3PickSortNone; |
withData.data.numHitsToReturn= kQ3ReturnAllHits; |
withData.data.mask = kQ3PickDetailMaskObject; |
screenPoint = event->where; |
GlobalToLocal (&screenPoint); |
withData.point.x = screenPoint.h; |
withData.point.y = screenPoint.v; |
withData.vertexTolerance = withData.edgeTolerance = 2.0; |
pickObject = Q3WindowPointPick_New(&withData); |
status = Q3View_StartPicking(gDocument.fView, pickObject); |
if (status == kQ3Failure) |
debugstr ("DoPicking: Q3View_StartPicking failed."); |
do { |
status = Q3DisplayGroup_Submit(gDocument.fModel, gDocument.fView); |
if (status == kQ3Failure) |
debugstr ("DoPicking: Q3View_StartPicking failed."); |
viewStatus = Q3View_EndPicking(gDocument.fView); |
} while (viewStatus == kQ3ViewStatusRetraverse); |
if (viewStatus != kQ3ViewStatusDone) |
debugstr ("DoPicking: Q3View_EndPicking failed."); |
if (Q3Pick_GetNumHits(pickObject, &numPicked) && (numPicked != 0)) { |
SetCursor(*GetCursor(plusCursor)); |
SysBeep(1); |
} else { |
SetCursor(&qd.arrow); |
} |
Q3Object_Dispose(pickObject); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14