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.
Source/Objects.c
/*********************************/ |
/* OBJECT MANAGER */ |
/* By Brian Greenstone */ |
/*********************************/ |
/***************/ |
/* EXTERNALS */ |
/***************/ |
#include <QD3D.h> |
#include <QD3DGeometry.h> |
#include <QD3DGroup.h> |
#include <QD3DMath.h> |
#include <QD3DTransform.h> |
#include "myglobals.h" |
#include "objects.h" |
#include "misc.h" |
#include "qd3d_support.h" |
/****************************/ |
/* CONSTANTS */ |
/****************************/ |
#define INVALID_NODE_FLAG 0xffffffffL // put into CType when node is deleted |
/**********************/ |
/* VARIABLES */ |
/**********************/ |
// OBJECT LIST |
ObjNode *gFirstNodePtr; |
ObjNode *gCurrentNode,*gMostRecentlyAddedNode; |
NewObjectDefinitionType gNewObjectDefinition; |
TQ3Point3D gCoord; |
/************************ INIT OBJECT MANAGER **********************/ |
void InitObjectManager(void) |
{ |
gCurrentNode = nil; |
gFirstNodePtr = nil; // no node yet |
} |
/*********************** MAKE NEW OBJECT ******************/ |
// |
// MAKE NEW OBJECT & RETURN PTR TO IT |
// |
// The linked list is sorted from LARGEST z to smallest! |
// |
ObjNode *MakeNewObject(NewObjectDefinitionType *newObjDef) |
{ |
ObjNode *newNodePtr,*scanNodePtr,*reNodePtr; |
long slot; |
slot = newObjDef->slot; |
/* INITIALIZE NEW NODE */ |
newNodePtr = (ObjNode *)AllocPtr(sizeof(ObjNode)); |
if (newNodePtr == nil) |
DoFatalAlert("\pMakeNewObject: Alloc Ptr failed!"); |
newNodePtr->SortSlot = slot; |
newNodePtr->Type = newObjDef->type; |
newNodePtr->MoveCall = newObjDef->moveCall; // save move routine |
newNodePtr->Genre = newObjDef->genre; |
newNodePtr->Coord = newObjDef->coord; |
newNodePtr->ModeFlags = newObjDef->flags|OBJ_MODE_MOVE; |
newNodePtr->RotX = |
newNodePtr->RotY = |
newNodePtr->RotZ = 0; |
newNodePtr->ScaleX = |
newNodePtr->ScaleY = |
newNodePtr->ScaleZ = 1.0; |
newNodePtr->BaseGroup = nil; |
/* FIND INSERTION PLACE FOR NODE */ |
if (gFirstNodePtr == nil) // special case only entry |
{ |
gFirstNodePtr = newNodePtr; |
newNodePtr->PrevNode = nil; |
newNodePtr->NextNode = nil; |
} |
else |
if (slot < gFirstNodePtr->SortSlot) // INSERT AS FIRST NODE |
{ |
newNodePtr->PrevNode = nil; // no prev |
newNodePtr->NextNode = gFirstNodePtr; // next pts to old 1st |
gFirstNodePtr->PrevNode = newNodePtr; // old pts to new 1st |
gFirstNodePtr = newNodePtr; |
} |
else |
{ |
reNodePtr = gFirstNodePtr; |
scanNodePtr = gFirstNodePtr; |
while (scanNodePtr != nil) |
{ |
if (slot < scanNodePtr->SortSlot) // INSERT IN MIDDLE HERE |
{ |
newNodePtr->NextNode = scanNodePtr; |
newNodePtr->PrevNode = reNodePtr; |
reNodePtr->NextNode = newNodePtr; |
scanNodePtr->PrevNode = newNodePtr; |
goto out; |
} |
reNodePtr = scanNodePtr; |
scanNodePtr=(ObjNode *)scanNodePtr->NextNode; // try next node |
} |
newNodePtr->NextNode = nil; // TAG TO END |
newNodePtr->PrevNode = reNodePtr; |
reNodePtr->NextNode = newNodePtr; |
} |
out: |
gMostRecentlyAddedNode = newNodePtr; // remember this |
return(newNodePtr); |
} |
/******************************* MOVE OBJECTS **************************/ |
void MoveObjects(void) |
{ |
ObjNode *thisNodePtr; |
if (gFirstNodePtr == nil) // see if there are any objects |
return; |
thisNodePtr = gFirstNodePtr; |
do |
{ |
/* NEXT TRY TO MOVE IT */ |
if ((thisNodePtr->ModeFlags & OBJ_MODE_MOVE) && (thisNodePtr->MoveCall != nil)) |
{ |
gCurrentNode = thisNodePtr; // set current object node |
thisNodePtr->MoveCall(); // call object's move routine |
} |
thisNodePtr = (ObjNode *)thisNodePtr->NextNode; // next node |
} |
while (thisNodePtr != nil); |
} |
/**************************** DRAW OBJECTS ***************************/ |
void DrawObjects(QD3DSetupOutputType *viewInfo) |
{ |
ObjNode *theNode; |
TQ3Status myStatus; |
if (gFirstNodePtr == nil) // see if there are any objects |
return; |
theNode = gFirstNodePtr; |
/* MAIN NODE TASK LOOP */ |
do |
{ |
if (theNode->BaseGroup) // see if group exists |
{ |
myStatus = Q3Object_Submit(theNode->BaseGroup,viewInfo->viewObject); |
if ( myStatus == kQ3Failure ) |
DoFatalAlert("\p Drawing Q3Object_Submit Failed!"); |
} |
theNode = (ObjNode *)theNode->NextNode; |
}while (theNode != nil); |
} |
/******************** DELETE ALL OBJECTS ********************/ |
void DeleteAllObjects(void) |
{ |
while (gFirstNodePtr != nil) |
DeleteObject(gFirstNodePtr); |
} |
/************************ DELETE OBJECT ****************/ |
void DeleteObject(ObjNode *theNode) |
{ |
ObjNode *tempNode; |
if (theNode == nil) // see if passed a bogus node |
return; |
/* PURGE SPECIAL DATA */ |
if(theNode->BaseGroup) |
{ |
Q3Object_Dispose(theNode->BaseGroup); |
theNode->BaseGroup = nil; |
} |
/* DO NODE SWITCHING */ |
if (theNode->PrevNode == nil) // special case 1st node |
{ |
gFirstNodePtr = (ObjNode *)theNode->NextNode; |
tempNode = (ObjNode *)theNode->NextNode; |
tempNode->PrevNode = nil; |
} |
else if (theNode->NextNode == nil) // special case last node |
{ |
tempNode = (ObjNode *)theNode->PrevNode; |
tempNode->NextNode = nil; |
} |
else // generic middle deletion |
{ |
tempNode = (ObjNode *)theNode->PrevNode; |
tempNode->NextNode = theNode->NextNode; |
tempNode = (ObjNode *)theNode->NextNode; |
tempNode->PrevNode = theNode->PrevNode; |
} |
DisposePtr((Ptr)theNode); |
} |
/********************** GET OBJECT INFO *********************/ |
void GetObjectInfo(ObjNode *theNode) |
{ |
gCoord = theNode->Coord; |
} |
/********************** UPDATE OBJECT *********************/ |
void UpdateObject(ObjNode *theNode) |
{ |
theNode->Coord = gCoord; |
} |
/************* MAKE NEW DISPLAY GROUP OBJECT *************/ |
ObjNode *MakeNewDisplayGroupObject(NewObjectDefinitionType *newObjDef) |
{ |
ObjNode *newObj; |
newObjDef->genre = DISPLAY_GROUP_GENRE; |
newObj = MakeNewObject(newObjDef); |
if (newObj == nil) |
return(nil); |
CreateBaseGroup(newObj); |
return(newObj); |
} |
/************************* ADD GEOMETRY TO DISPLAY GROUP OBJECT ***********************/ |
// |
// Attaches a geometry object to the BaseGroup object. MakeNewDisplayGroupObject must have already been |
// called which made the group & transforms. |
// |
void AttachGeometryToDisplayGroupObject(ObjNode *theNode, TQ3GeometryObject geometry) |
{ |
TQ3GroupPosition groupPosition; |
groupPosition = Q3Group_AddObject(theNode->BaseGroup,geometry); |
if (groupPosition == nil) |
DoFatalAlert("\pError: AttachGeometryToDisplayGroupObject"); |
} |
/***************** CREATE BASE GROUP **********************/ |
// |
// the base group contains the base translation/rotation transforms |
// plus the link to the heirarchial chain of joint objects if its a skeleton object. |
// |
// NOTE: this is not only used for skeleton objects, but also for display group objects!!! |
// |
void CreateBaseGroup(ObjNode *theNode) |
{ |
TQ3GroupPosition myGroupPosition; |
TQ3Matrix4x4 transMatrix,scaleMatrix; |
TQ3TransformObject transObject; |
if (theNode->BaseGroup) // nuke old one |
Q3Object_Dispose(theNode->BaseGroup); |
/* CREATE THE GROUP OBJECT */ |
theNode->BaseGroup = Q3DisplayGroup_New(); |
if (theNode->BaseGroup == nil) |
DoFatalAlert("\p Couldnt allocate BaseGroup!"); |
/* SETUP BASE MATRIX */ |
Q3Matrix4x4_SetRotate_XYZ(&theNode->BaseTransformMatrix, // init rotation matrix |
theNode->RotX, theNode->RotY, |
theNode->RotZ); |
Q3Matrix4x4_SetTranslate(&transMatrix, theNode->Coord.x, theNode->Coord.y, // make translate matrix |
theNode->Coord.z); |
Q3Matrix4x4_Multiply(&theNode->BaseTransformMatrix, // mult rot & trans matrices |
&transMatrix, |
&theNode->BaseTransformMatrix); |
Q3Matrix4x4_SetScale(&scaleMatrix, theNode->ScaleX, |
theNode->ScaleY, |
theNode->ScaleZ); |
Q3Matrix4x4_Multiply(&theNode->BaseTransformMatrix, // mult rot & trans matrices |
&scaleMatrix, |
&theNode->BaseTransformMatrix); |
/* CREATE A MATRIX XFORM */ |
transObject = Q3MatrixTransform_New(&theNode->BaseTransformMatrix); |
myGroupPosition = Q3Group_AddObject(theNode->BaseGroup, transObject); // add to base group |
if (myGroupPosition == 0) |
DoFatalAlert("\pQ3Group_AddObject Failed!"); |
theNode->BaseTransformObject = transObject; // keep illegal ref |
Q3Object_Dispose(transObject); |
} |
/****************** UPDATE OBJECT TRANSFORMS *****************/ |
// |
// This updates the skeleton object's base translate & rotate transforms |
// |
void UpdateObjectTransforms(ObjNode *theNode) |
{ |
TQ3Matrix4x4 scaleMatrix; |
/* RESET BASE MATRIX */ |
Q3Matrix4x4_SetRotate_XYZ(&theNode->BaseTransformMatrix, // init rotation matrix |
theNode->RotX, theNode->RotY, |
theNode->RotZ); |
TranslateObjectBaseMatrixByXYZ(theNode); |
Q3Matrix4x4_SetScale(&scaleMatrix, theNode->ScaleX, // do scale |
theNode->ScaleY, |
theNode->ScaleZ); |
TransformObjectBaseMatrix(theNode,&scaleMatrix); |
SetObjectTransformMatrix(theNode); |
} |
/***************** SET OBJECT TRANSFORM MATRIX *******************/ |
// |
// This call simply resets the base transform object so that it uses the latest |
// base transform matrix |
// |
void SetObjectTransformMatrix(ObjNode *theNode) |
{ |
TQ3Status error; |
error = Q3MatrixTransform_Set(theNode->BaseTransformObject,&theNode->BaseTransformMatrix); |
if (error != kQ3Success) |
DoFatalAlert("\pQ3MatrixTransform_Set Failed!"); |
} |
/******************** TRANSLATE OBJECT BASE MATRIX BY X/Y/Z *******************/ |
void TranslateObjectBaseMatrixByXYZ(ObjNode *theNode) |
{ |
TQ3Matrix4x4 transMatrix; |
Q3Matrix4x4_SetTranslate(&transMatrix, theNode->Coord.x, theNode->Coord.y, // make translate matrix |
theNode->Coord.z); |
TransformObjectBaseMatrix(theNode,&transMatrix); |
} |
/***************** TRANSFORM OBJECT BASE MATRIX ******************/ |
// |
// This multiplies the current BaseTransformMatrix by the input transform matrix. |
// |
void TransformObjectBaseMatrix(ObjNode *theNode, TQ3Matrix4x4 *inMatrix) |
{ |
Q3Matrix4x4_Multiply(&theNode->BaseTransformMatrix, |
inMatrix, |
&theNode->BaseTransformMatrix); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14