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.
Track.c
/* |
File: Track.c |
Contains: Contains code to create our rollercoaster track |
Written by: Scott Kuechle, based on original Gerbils code by Brian Greenstone |
Copyright: © 1998 by Apple Computer, Inc. All rights reserved |
Change History (most recent first) |
<2> 9/28/98 rtm made changes for Metrowerks compiler |
<1> 9/01/98 srk first file |
*/ |
/************************************************************ |
* * |
* INCLUDE FILES * |
* * |
*************************************************************/ |
#include "Track.h" |
/************************************************************ |
* * |
* FUNCTION PROTOTYPES * |
* * |
*************************************************************/ |
static float Track_AmountToRotateNubs(TrackSectionType *trackSectionList, |
long numTrackSections, |
NubEntryType *coordPtr, |
long numNubsInPart, |
long sectionNum, |
float *scale); |
static void Track_PutCameraOnTrack(TQ3CameraObject camera, |
NubEntryType *splinePtArray, |
long numSplinePoints, |
long curTrackLocation); |
#if TARGET_OS_WIN32 |
HANDLE WinIO_CreateFile(); |
BOOL WinIO_WriteToFile(HANDLE fileHndl, PartType *thisPart); |
#endif |
/************************************************************ |
* * |
* FUNCTION: Track_MakeRandomTrack * |
* * |
* PURPOSE: Generates a random series of track sections * |
* * |
*************************************************************/ |
void Track_MakeRandomTrack(TrackSectionType *trackSectionList, |
long numTrackSections) |
{ |
long i,r; |
for (i = 0; i < numTrackSections; i++) |
{ |
do |
{ |
r = Utils_MyRandomLong() & numTrackSections; |
} while(r==7); |
trackSectionList[i].partNum = i; |
trackSectionList[i].nubCoord.y = 0; |
trackSectionList[i].nubCoord.x = sin(6.24F/numTrackSections*(float)i)*(LAZY_SUSAN_RADIUS - 6.0F); |
trackSectionList[i].nubCoord.z = cos(6.24F/numTrackSections*(float)i)*(LAZY_SUSAN_RADIUS - 6.0F); |
} |
} |
/************************************************************ |
* * |
* FUNCTION: Track_CreateMasterNubList * |
* * |
* PURPOSE: creates a master list of spline nubs which * |
* contains all of the nubs within all * |
* sections of a track * |
* * |
*************************************************************/ |
void Track_CreateMasterNubList(TrackSectionType *trackSectionList, |
unsigned long numTrackSections, |
PartType *partsList, |
NubEntryType *nubList, |
long *nubTotal) |
{ |
unsigned long sectionNum,partNum,i,numNubsInPart; |
NubEntryType *coordPtr; |
TQ3Point3D sectionStartCoords,basePt,upPt; |
float rotation,scale; |
*nubTotal = 0; |
for (sectionNum=0; sectionNum < numTrackSections; sectionNum++) |
{ |
partNum = trackSectionList[sectionNum].partNum; /* get part # to add */ |
/* GET INFO FOR PART */ |
sectionStartCoords = trackSectionList[sectionNum].nubCoord; /* get coords where track section should start */ |
numNubsInPart = partsList[partNum].numNubs; /* get # nubs in part */ |
coordPtr = partsList[partNum].coordsPtr; /* get ptr to coord list */ |
rotation = Track_AmountToRotateNubs(trackSectionList, |
numTrackSections, |
coordPtr, |
numNubsInPart, |
sectionNum, |
&scale); |
/* COPY & ADJUST PART NUBS */ |
for (i=1; i < (numNubsInPart-1); i++) /* skip nub 0 & last nub */ |
{ |
basePt = coordPtr->basePt; /* get coords from part data */ |
upPt = coordPtr->upPt; |
Utils_RotatePoint(&basePt,rotation); /* rotate the points into position */ |
Utils_RotatePoint(&upPt,rotation); |
basePt.x *= scale; basePt.y *= scale; basePt.z *= scale; /* scale it */ |
upPt.x *= scale; upPt.y *= scale; upPt.z *= scale; |
nubList[*nubTotal].basePt.x = basePt.x + sectionStartCoords.x; /* tag nubs to end of previous part */ |
nubList[*nubTotal].basePt.y = basePt.y + sectionStartCoords.y; |
nubList[*nubTotal].basePt.z = basePt.z + sectionStartCoords.z; |
nubList[*nubTotal].upPt.x = upPt.x + sectionStartCoords.x; |
nubList[*nubTotal].upPt.y = upPt.y + sectionStartCoords.y; |
nubList[*nubTotal].upPt.z = upPt.z + sectionStartCoords.z; |
nubList[*nubTotal].sectionNum = sectionNum; /* remember which section this belongs to */ |
coordPtr++; |
(*nubTotal)++; |
} |
} |
/* CREATE 3 FINAL NUBS WHICH WRAP BACK TO BEGINNING TO CLOSE THE LOOP */ |
partNum = trackSectionList[0].partNum; /* get part # */ |
coordPtr = partsList[partNum].coordsPtr; /* point back to beginning */ |
sectionStartCoords = trackSectionList[0].nubCoord; /* get coords where track section should start */ |
numNubsInPart = partsList[partNum].numNubs; /* get # nubs in part */ |
rotation = Track_AmountToRotateNubs(trackSectionList, |
numTrackSections, |
coordPtr, |
numNubsInPart, |
0, |
&scale); |
for (i=0; i < 3; i++) |
{ |
basePt = coordPtr->basePt; /* get coords from part data */ |
upPt = coordPtr->upPt; |
Utils_RotatePoint(&basePt,rotation); /* rotate the points into position */ |
Utils_RotatePoint(&upPt,rotation); |
basePt.x *= scale; basePt.y *= scale; basePt.z *= scale; /* scale it */ |
upPt.x *= scale; upPt.y *= scale; upPt.z *= scale; |
nubList[*nubTotal].basePt.x = basePt.x + sectionStartCoords.x; /* tag nubs to end of previous part */ |
nubList[*nubTotal].basePt.y = basePt.y + sectionStartCoords.y; |
nubList[*nubTotal].basePt.z = basePt.z + sectionStartCoords.z; |
nubList[*nubTotal].upPt.x = upPt.x + sectionStartCoords.x; |
nubList[*nubTotal].upPt.y = upPt.y + sectionStartCoords.y; |
nubList[*nubTotal].upPt.z = upPt.z + sectionStartCoords.z; |
(*nubTotal)++; |
coordPtr++; |
} |
} |
/************************************************************ |
* * |
* FUNCTION: Track_AmountToRotateNubs * |
* * |
* PURPOSE: Calculates the amount to rotate nubs on the * |
* y axis so that the track section will go * |
* from point A to point B. It also returns a * |
* scaling value used to scale the nub based * |
* on the change in length. * |
* * |
*************************************************************/ |
static float Track_AmountToRotateNubs(TrackSectionType *trackSectionList, |
long numTrackSections, |
NubEntryType *coordPtr, |
long numNubsInPart, |
long sectionNum, |
float *scale) |
{ |
TQ3Vector3D startVec,endVec,originalVec,desiredVec; |
long i; |
float rotation,originalSize,desiredSize; |
TQ3Point3D originalPt,desiredPt,zeroPt = {0,0,0}; |
/* CALC ORIGINAL VECTOR */ |
startVec.x = coordPtr[1].basePt.x; /* use 2nd nub as start coord (remember that we skip the 1st nub in a part) */ |
startVec.y = coordPtr[1].basePt.y; |
startVec.z = coordPtr[1].basePt.z; |
endVec.x = coordPtr[numNubsInPart-1].basePt.x; /* use last nub as end coord of original data */ |
endVec.y = coordPtr[numNubsInPart-1].basePt.y; |
endVec.z = coordPtr[numNubsInPart-1].basePt.z; |
Q3Vector3D_Subtract(&endVec,&startVec,&originalVec); /* calc vector from start to end */ |
/* CALC DESIRED VECTOR */ |
i = sectionNum+1; |
if (i >= numTrackSections) |
{ |
i = 0; |
} |
startVec.x = trackSectionList[sectionNum].nubCoord.x; /* get vector of where we want it to endup */ |
startVec.y = trackSectionList[sectionNum].nubCoord.y; |
startVec.z = trackSectionList[sectionNum].nubCoord.z; |
endVec.x = trackSectionList[i].nubCoord.x; /* get vector of where we want it to endup */ |
endVec.y = trackSectionList[i].nubCoord.y; |
endVec.z = trackSectionList[i].nubCoord.z; |
Q3Vector3D_Subtract(&endVec,&startVec,&desiredVec); /* calc vector from start to desired end */ |
/* CALC ANGLE */ |
rotation = Utils_AngleBetweenVectors(originalVec,desiredVec); /* calc amount we need to rotate all nubs in part */ |
if (desiredVec.z > originalVec.z) /* see if need to negate (since we only have absolute angle between vecs) */ |
{ |
rotation = -rotation; |
} |
/* CALC SCALING TO ADJUST FOR DISTANCE CHANGE */ |
originalPt.x = originalVec.x; /* calc size of original segment */ |
originalPt.y = originalVec.y; |
originalPt.z = originalVec.z; |
originalSize = Q3Point3D_Distance(&originalPt,&zeroPt); |
desiredPt.x = desiredVec.x; /* calc size of desired seg */ |
desiredPt.y = desiredVec.y; |
desiredPt.z = desiredVec.z; |
desiredSize = Q3Point3D_Distance(&desiredPt,&zeroPt); |
*scale = desiredSize/originalSize; /* return scaling value */ |
return(rotation); |
} |
#if TARGET_OS_WIN32 |
/************************************************************ |
* * |
* FUNCTION: Track_LoadPartsFromFile * |
* * |
* PURPOSE: Loads our pre-generated track parts * |
* from a file * |
* * |
*************************************************************/ |
void Track_LoadPartsFromFile(PartType *partsList, short *partCount) |
{ |
HANDLE fileHndl; |
DWORD err; |
char partFilePath[MAX_PATH]; |
err = Utils_Win32_BuildCurDirPath((Ptr)&partFilePath, kPartDataFileName); |
fileHndl = CreateFile((char *)&partFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); |
if ((fileHndl == NULL) || (fileHndl == INVALID_HANDLE_VALUE)) |
{ |
Utils_DisplayFatalErrorMsg("Failure loading track part file TrackPartData.dat!"); |
} |
else |
{ |
Ptr currentIndex; |
HLOCAL localMem; |
DWORD numBytesRead, fileSize; |
BOOL successfull = FALSE; |
fileSize = GetFileSize(fileHndl, NULL); |
localMem = LocalAlloc(LMEM_FIXED, fileSize); |
if (localMem != NULL) |
{ |
currentIndex = localMem; |
*partCount = 0; |
successfull = FALSE; |
do |
{ |
/* get count of nubs for this part */ |
successfull = ReadFile(fileHndl, &partsList[*partCount].numNubs, sizeof(partsList->numNubs), &numBytesRead, NULL); |
if ((successfull == TRUE) && (numBytesRead != 0)) |
{ |
numBytesRead = 0; |
successfull = ReadFile(fileHndl, currentIndex, sizeof(NubEntryType) * partsList[*partCount].numNubs, &numBytesRead, NULL); |
if ((successfull == TRUE) && (numBytesRead != 0)) |
{ |
/* SAVE PART RECORD */ |
partsList[*partCount].coordsPtr = (NubEntryType *)currentIndex; |
/* move pointer to point to memory for next part */ |
currentIndex = currentIndex + sizeof(NubEntryType) * partsList[*partCount].numNubs; |
++ (*partCount); |
} |
else |
{ |
Utils_DisplayFatalErrorMsg("Error reading track part file TrackPartData.dat!"); |
} |
} |
} |
while ((successfull == TRUE) && (numBytesRead != 0)); |
} |
else |
{ |
Utils_DisplayFatalErrorMsg("Memory allocation failure!"); |
} |
} |
} |
#endif |
/************************************************************ |
* * |
* FUNCTION: Track_LoadPartsFromRez * |
* * |
* PURPOSE: Loads our pre-generated track parts * |
* from a resource file * |
* * |
*************************************************************/ |
#if TARGET_OS_MAC |
void Track_LoadPartsFromRez(PartType *partsList, short *partCount) |
{ |
OSErr err; |
short i; |
Handle partHandle; |
PartType *thisPart; |
Byte numNubs; |
Ptr nubCoordsPtr; |
*partCount = 0; |
/* get count of part resources in our resource file */ |
*partCount = Count1Resources(kPartType); |
err = ResError(); |
if (err != noErr) |
{ |
Utils_DisplayFatalErrorMsg("Error Getting Part Resource"); |
} |
else |
{ |
for (i = 1; i <= *partCount; i++) |
{ |
/* get next part resource in our file */ |
partHandle = GetIndResource(kPartType,i); |
if (partHandle == nil) |
{ |
Utils_DisplayFatalErrorMsg("Error Getting Part Resource"); |
} |
else |
{ |
DetachResource(partHandle); /* give it to me */ |
HLockHi(partHandle); |
thisPart = (PartType *)(*partHandle); |
/* get number of points in this part from the numNubs field of |
the PartType structure */ |
numNubs = thisPart->numNubs; |
/* allocate enough NubEntryType structures to hold all of the points |
in this part */ |
nubCoordsPtr = NewPtr(sizeof(NubEntryType) * numNubs);// alloc memory for nub coords |
if (nubCoordsPtr == nil) |
{ |
Utils_DisplayFatalErrorMsg("Not enough memory to load Part"); |
} |
else |
{ |
/* copy NubEntryType data to our memory block */ |
//BlockMove((Ptr)&thisPart->coordsPtr,nubCoordsPtr,sizeof(NubEntryType) * numNubs); |
BlockMove((Ptr)thisPart + sizeof(thisPart->numNubs),nubCoordsPtr,sizeof(NubEntryType) * numNubs); |
DisposeHandle(partHandle); |
/* save part record as a PartType structure */ |
partsList[i-1].numNubs = numNubs; |
partsList[i-1].coordsPtr = (NubEntryType *)nubCoordsPtr; |
} |
} |
} |
} |
} |
#endif |
/************************************************************ |
* * |
* FUNCTION: Track_PutCameraOnTrack * |
* * |
* PURPOSE: Calculates placement of the camera on the * |
* track * |
* * |
* * |
* * |
*************************************************************/ |
void Track_PutCameraOnTrack(TQ3CameraObject camera, |
NubEntryType *splinePtArray, |
long numSplinePoints, |
long curTrackLocation |
) |
{ |
TQ3Point3D cameraFrom,cameraTo; |
TQ3Vector3D cameraUp,cameraFromVect; |
long desti; |
TQ3CameraPlacement placement; |
if (numSplinePoints == 0) |
return; |
/* CALC UP VECTOR */ |
Q3Point3D_Subtract(&splinePtArray[curTrackLocation].upPt, /* calc vector from base to up point */ |
&splinePtArray[curTrackLocation].basePt, |
&cameraUp); |
Q3Vector3D_Normalize(&cameraUp,&cameraUp); |
/* USE UP VECTOR TO CALC "FROM" POSITION */ |
Q3Vector3D_Scale(&cameraUp,DISTANCE_FROM_TRACK_TO_CAMERA,&cameraFromVect); /* calc how far above track to put camera */ |
cameraFrom.x = (splinePtArray[curTrackLocation].basePt.x + |
cameraFromVect.x); |
cameraFrom.y = (splinePtArray[curTrackLocation].basePt.y + |
cameraFromVect.y); |
cameraFrom.z = (splinePtArray[curTrackLocation].basePt.z + |
cameraFromVect.z); |
/* SET "TO" PT */ |
desti = curTrackLocation + kSkipAheadPoints; |
if (desti >= (numSplinePoints-1)) |
{ |
desti -= numSplinePoints; /* loop back around */ |
} |
cameraTo = splinePtArray[desti].basePt; /* look at base spline point in distance */ |
/* UPDATE CAMERA PLACEMENT */ |
placement.cameraLocation = cameraFrom; /* set placement data */ |
placement.pointOfInterest = cameraTo; |
placement.upVector = cameraUp; |
Q3Camera_SetPlacement(camera,&placement); |
} |
/************************************************************ |
* * |
* FUNCTION: Track_BuildCoasterGeometry_Mesh_Textured * |
* * |
* PURPOSE: Build a textured track using mesh objects * |
* * |
* * |
*************************************************************/ |
void Track_BuildCoasterGeometry_Mesh(long skipValue, |
TQ3GroupObject theGroup, |
long numSplinePoints, |
NubEntryType *splinePointsPtr) |
{ |
TQ3GeometryObject myMesh = NULL; |
TQ3GroupPosition myGroupPosition; |
TQ3ColorRGB whiteColor = {1,1,1}; |
long i,faceCount,colorTick = 0; |
float x2,y2,z2; |
TQ3Vector3D tangentVector; |
TQ3MeshVertex meshVertexList[4]; |
TQ3Vertex3D vertexList[4],firstLeft,firstRight; |
TQ3AttributeSet generalAttribs = NULL,vAttrib[4] = {NULL, NULL, NULL, NULL}; |
TQ3MeshFace face; |
float ambient = 0.8F; |
float spec = 0.0F; |
TQ3Param2D corner1 = {0,1}; /* uv's for texture mapping */ |
TQ3Param2D corner2 = {1,1}; |
TQ3Param2D corner3 = {1,0}; |
TQ3Param2D corner4 = {0,0}; |
/* CREATE NEW MESH OBJECT */ |
myMesh = Q3Mesh_New(); |
if( myMesh == NULL ) |
{ |
Utils_DisplayErrorMsg("Group_AddObject failed!"); |
goto memoryError; |
} |
Q3Mesh_DelayUpdates(myMesh); |
/* SETUP GENERAL ATTRIBUTES */ |
generalAttribs = Q3AttributeSet_New(); |
if( generalAttribs == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
Q3AttributeSet_Add(generalAttribs, kQ3AttributeTypeAmbientCoefficient, &ambient); |
Q3AttributeSet_Add(generalAttribs, kQ3AttributeTypeSpecularControl, &spec); |
/* CREATE UV ATTRIBUTES FOR THE VERTICES */ |
vAttrib[0] = Q3AttributeSet_New(); |
if( vAttrib[0] == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
Q3AttributeSet_Add(vAttrib[0], kQ3AttributeTypeShadingUV, &corner1); |
vAttrib[1] = Q3AttributeSet_New(); |
if( vAttrib[1] == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
Q3AttributeSet_Add(vAttrib[1], kQ3AttributeTypeShadingUV, &corner2); |
vAttrib[2] = Q3AttributeSet_New(); |
if( vAttrib[2] == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
Q3AttributeSet_Add(vAttrib[2], kQ3AttributeTypeShadingUV, &corner3); |
vAttrib[3] = Q3AttributeSet_New(); |
if( vAttrib[3] == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
Q3AttributeSet_Add(vAttrib[3], kQ3AttributeTypeShadingUV, &corner4); |
vertexList[0].attributeSet = nil; |
vertexList[1].attributeSet = nil; |
vertexList[2].attributeSet = nil; |
vertexList[3].attributeSet = nil; |
faceCount = 0; |
for (i = 0; i < (numSplinePoints - 1 - skipValue); i += skipValue) |
{ |
/* GET SPLINE POINTS */ |
x2 = splinePointsPtr[i+skipValue].basePt.x; /* get coords of end pt #2 (far point) */ |
y2 = splinePointsPtr[i+skipValue].basePt.y; |
z2 = splinePointsPtr[i+skipValue].basePt.z; |
/* CALC TANGENT VECTOR */ |
Q3Point3D_CrossProductTri(&splinePointsPtr[i].basePt, |
&splinePointsPtr[i+skipValue].basePt, |
&splinePointsPtr[i].upPt,&tangentVector); |
Q3Vector3D_Normalize(&tangentVector,&tangentVector); |
Q3Vector3D_Scale(&tangentVector,kTrackWidth,&tangentVector); |
/* CALC NEW "UPPER" COORDS OF FACE */ |
Q3Point3D_Set(&vertexList[0].point, /* upper left */ |
x2-tangentVector.x, |
y2-tangentVector.y, |
z2-tangentVector.z); |
Q3Point3D_Set(&vertexList[1].point, /* upper right */ |
x2+tangentVector.x, |
y2+tangentVector.y, |
z2+tangentVector.z); |
meshVertexList[0] = Q3Mesh_VertexNew(myMesh, &vertexList[0]); /* get new vertex for "upper/far" */ |
meshVertexList[1] = Q3Mesh_VertexNew(myMesh, &vertexList[1]); |
/* FOR 1ST FACE, MUST RIG "BOTTOM" COORDS */ |
if (i == 0) |
{ |
Q3Point3D_Set(&vertexList[2].point, /* lower right */ |
splinePointsPtr[0].basePt.x+tangentVector.x, |
splinePointsPtr[0].basePt.y+tangentVector.y, |
splinePointsPtr[0].basePt.z+tangentVector.z); |
Q3Point3D_Set(&vertexList[3].point, /* lower left */ |
splinePointsPtr[0].basePt.x-tangentVector.x, |
splinePointsPtr[0].basePt.y-tangentVector.y, |
splinePointsPtr[0].basePt.z-tangentVector.z); |
firstRight.point = vertexList[2].point; /* remember these coords for wrap-back later */ |
firstLeft.point = vertexList[3].point; |
meshVertexList[2] = Q3Mesh_VertexNew(myMesh, &vertexList[2]); /* set vertex */ |
meshVertexList[3] = Q3Mesh_VertexNew(myMesh, &vertexList[3]); |
} |
/* CREATE FACE */ |
face = Q3Mesh_FaceNew(myMesh,4,&meshVertexList[0],generalAttribs); |
if( face == NULL ) |
{ |
Utils_DisplayErrorMsg("Q3AttributeSet_New failed!"); |
goto memoryError; |
} |
/* APPLY UV COORD ATTRIBS */ |
Q3Mesh_SetCornerAttributeSet(myMesh, meshVertexList[0], face, vAttrib[0]); |
Q3Mesh_SetCornerAttributeSet(myMesh, meshVertexList[1], face, vAttrib[1]); |
Q3Mesh_SetCornerAttributeSet(myMesh, meshVertexList[2], face, vAttrib[2]); |
Q3Mesh_SetCornerAttributeSet(myMesh, meshVertexList[3], face, vAttrib[3]); |
colorTick++; |
faceCount++; |
/* SEE IF MESH OBJECT IS LARGE ENOUGH TO USE NOW */ |
if (faceCount > kMaxFacesInMesh) |
{ |
Q3Mesh_ResumeUpdates(myMesh); |
myGroupPosition = Q3Group_AddObject(theGroup, myMesh); /* add mesh to group */ |
Q3Object_Dispose(myMesh); /* make another mesh object */ |
if ( myGroupPosition == nil ) |
{ |
Utils_DisplayErrorMsg("Q3Group_AddObject failed!"); |
goto memoryError; |
} |
myMesh = Q3Mesh_New(); |
if ( myMesh == nil ) |
{ |
Utils_DisplayErrorMsg("Q3Mesh_New failed!"); |
goto memoryError; |
} |
Q3Mesh_DelayUpdates(myMesh); |
meshVertexList[0] = Q3Mesh_VertexNew(myMesh, &vertexList[0]); /* reset these to the new mesh */ |
meshVertexList[1] = Q3Mesh_VertexNew(myMesh, &vertexList[1]); |
faceCount = 0; |
} |
/* UPPERS WILL BE LOWERS ON NEXT POLY */ |
vertexList[2] = vertexList[1]; /* this is so next poly's bottom will match last poly's top */ |
vertexList[3] = vertexList[0]; |
meshVertexList[2] = meshVertexList[1]; |
meshVertexList[3] = meshVertexList[0]; |
if (colorTick & 1) |
{ |
vertexList[0].attributeSet = vAttrib[0]; /* apply uv attribs to the vertices */ |
vertexList[1].attributeSet = vAttrib[1]; |
vertexList[2].attributeSet = vAttrib[2]; |
vertexList[3].attributeSet = vAttrib[3]; |
} |
else |
{ |
vertexList[0].attributeSet = vAttrib[3]; /* apply uv attribs to the vertices */ |
vertexList[1].attributeSet = vAttrib[2]; |
vertexList[2].attributeSet = vAttrib[1]; |
vertexList[3].attributeSet = vAttrib[0]; |
} |
} |
/* CREATE 1 FINAL FACE TO LINK BACK TO BEGINNING */ |
vertexList[0].point = firstLeft.point; |
vertexList[1].point = firstRight.point; |
meshVertexList[0] = Q3Mesh_VertexNew(myMesh, &vertexList[0]); /* create vertex based on 1st */ |
meshVertexList[1] = Q3Mesh_VertexNew(myMesh, &vertexList[1]); |
if (faceCount & 1) |
{ |
face = Q3Mesh_FaceNew(myMesh,4,&meshVertexList[0],nil); |
} |
else |
{ |
face = Q3Mesh_FaceNew(myMesh,4,&meshVertexList[0],nil); |
} |
faceCount++; |
/* APPLY ANY REMAINING MESH */ |
Q3Mesh_ResumeUpdates(myMesh); |
if (faceCount > 0) |
{ |
myGroupPosition = Q3Group_AddObject(theGroup, myMesh); |
if ( myGroupPosition == nil ) |
{ |
Utils_DisplayErrorMsg("Q3Group_AddObject failed!"); |
goto memoryError; |
} |
} |
Q3Object_Dispose(myMesh); /* kill mesh object */ |
Q3Object_Dispose(generalAttribs); |
Q3Object_Dispose(vAttrib[0]); |
Q3Object_Dispose(vAttrib[1]); |
Q3Object_Dispose(vAttrib[2]); |
Q3Object_Dispose(vAttrib[3]); |
return; |
memoryError: |
if( myMesh ) |
{ |
Q3Object_Dispose(myMesh); |
} |
if( generalAttribs ) |
{ |
Q3Object_Dispose(generalAttribs); |
} |
if( vAttrib[0] ) |
{ |
Q3Object_Dispose(vAttrib[0]); |
} |
if( vAttrib[1] ) |
{ |
Q3Object_Dispose(vAttrib[1]); |
} |
if( vAttrib[2] ) |
{ |
Q3Object_Dispose(vAttrib[2]); |
} |
if( vAttrib[3] ) |
{ |
Q3Object_Dispose(vAttrib[3]); |
} |
} |
/************************************************************ |
* * |
* FUNCTION: Track_CalcSplineCurve * |
* * |
* PURPOSE: Use our control points to construct a * |
* spline curve for each section of the * |
* track * |
* * |
* * |
*************************************************************/ |
void Track_CalcSplineCurve(NubEntryType **splinePoints, |
long maxSplinePoints, |
NubEntryType *nubPoints, |
long numSplineNubs, |
long *numSplinePoints, |
float subDivFactor) |
{ |
float t,tSquared,tCubed,a,b,c,d,incVal; |
long subCount,nubNum,numNubs,numSubDivs; |
TQ3Point3D highestPoint = {0,0,0}; |
/* ALLOC MEMORY FOR SPLINE DATA */ |
*splinePoints = (NubEntryType *)NewPtr( sizeof(NubEntryType) * maxSplinePoints ); |
if (*splinePoints == nil) |
{ |
Utils_DisplayFatalErrorMsg("Sorry, but there doesnt seem to be enough memory to allocate the track spline curve"); |
} |
else |
{ |
numNubs = numSplineNubs; /* # nubs */ |
*numSplinePoints = 0; /* # points generated */ |
/* SCAN THRU NUBS */ |
/* Note: skips 1st & last nubs (sorta) */ |
for (nubNum=1; nubNum < (numNubs-2); nubNum++) |
{ |
numSubDivs = Q3Point3D_Distance(&nubPoints[nubNum].basePt, |
&nubPoints[nubNum+1].basePt)*subDivFactor + 0.5F; /* # segments between next nubs */ |
if (numSubDivs < 1) |
numSubDivs = 1; |
incVal = 1.0F/numSubDivs; /* increment value */ |
for (t=0, subCount=0; subCount < numSubDivs; t+=incVal,subCount++) |
{ |
tSquared = t*t; |
tCubed = tSquared*t; |
a = (-0.166F * tCubed)+(0.5F * tSquared)-(0.5F * t) + 0.166F; |
b = (0.5F * tCubed) - tSquared + 0.666F; |
c = (-0.5F * tCubed) + (0.5F * tSquared) + (0.5F * t + 0.166F); |
d = 0.166F * tCubed; |
if (*numSplinePoints < maxSplinePoints) |
{ |
/* CALC SEG OF BASE */ |
(*splinePoints)[*numSplinePoints].basePt.x = |
(a * nubPoints[nubNum-1].basePt.x) + |
(b * nubPoints[nubNum].basePt.x) + |
(c * nubPoints[nubNum+1].basePt.x) + |
(d * nubPoints[nubNum+2].basePt.x); |
(*splinePoints)[*numSplinePoints].basePt.y = |
(a * nubPoints[nubNum-1].basePt.y) + |
(b * nubPoints[nubNum].basePt.y) + |
(c * nubPoints[nubNum+1].basePt.y) + |
(d * nubPoints[nubNum+2].basePt.y); |
(*splinePoints)[*numSplinePoints].basePt.z = |
(a * nubPoints[nubNum-1].basePt.z) + |
(b * nubPoints[nubNum].basePt.z) + |
(c * nubPoints[nubNum+1].basePt.z) + |
(d * nubPoints[nubNum+2].basePt.z); |
/* CALC SEG OF UP */ |
(*splinePoints)[*numSplinePoints].upPt.x = |
(a * nubPoints[nubNum-1].upPt.x) + |
(b * nubPoints[nubNum].upPt.x) + |
(c * nubPoints[nubNum+1].upPt.x) + |
(d * nubPoints[nubNum+2].upPt.x); |
(*splinePoints)[*numSplinePoints].upPt.y = |
(a * nubPoints[nubNum-1].upPt.y) + |
(b * nubPoints[nubNum].upPt.y) + |
(c * nubPoints[nubNum+1].upPt.y) + |
(d * nubPoints[nubNum+2].upPt.y); |
(*splinePoints)[*numSplinePoints].upPt.z = |
(a * nubPoints[nubNum-1].upPt.z) + |
(b * nubPoints[nubNum].upPt.z) + |
(c * nubPoints[nubNum+1].upPt.z) + |
(d * nubPoints[nubNum+2].upPt.z); |
/* REMEMBER WHAT TYPE IT IS */ |
(*splinePoints)[*numSplinePoints].sectionNum = nubPoints[nubNum].sectionNum; |
(*numSplinePoints)++; |
} |
else |
{ |
Utils_DisplayFatalErrorMsg("Too many spline points! Overflowed array!"); |
} |
} |
} |
} |
} |
/************************************************************ |
* * |
* FUNCTION: Track_MoveCamera * |
* * |
* PURPOSE: Move the camera to the next location on the * |
* track * |
* * |
* * |
*************************************************************/ |
void Track_MoveCamera(TQ3CameraObject camera, |
NubEntryType *splinePtArray, |
long numSplinePoints, |
long *curTrackLocation) |
{ |
Track_PutCameraOnTrack(camera, |
splinePtArray, |
numSplinePoints, |
*curTrackLocation); |
/* have we reached the end of the track? */ |
if ( ((*curTrackLocation) + 1) >= numSplinePoints) |
{ |
/* end-of-track, so wrap back to the beginning */ |
(*curTrackLocation) = 0; |
} |
else |
{ |
/* move to next location on track */ |
++(*curTrackLocation); |
} |
} |
/************************************************************ |
* * |
* FUNCTION: Track_GetForwardVector * |
* * |
* PURPOSE: Returns the vector representing forward at * |
* trackIndex * |
* * |
* * |
*************************************************************/ |
void Track_GetForwardVector(long trackIndex, NubEntryType *splinePointsPtr, long numSplinePoints, TQ3Vector3D *theVector) |
{ |
TQ3Vector3D forward; |
if ((trackIndex+1) == numSplinePoints) /* see if +1 will wrap it */ |
Q3Point3D_Subtract(&splinePointsPtr[0].basePt, /* calc vector from here to one in front */ |
&splinePointsPtr[trackIndex].basePt, |
&forward); |
else |
Q3Point3D_Subtract(&splinePointsPtr[trackIndex+1].basePt, /* calc vector from here to one in front */ |
&splinePointsPtr[trackIndex].basePt, |
&forward); |
Q3Vector3D_Normalize(&forward,theVector); /* normalize & return it */ |
} |
/************************************************************ |
* * |
* FUNCTION: Track_GetNormalVector * |
* * |
* PURPOSE: Returns the vector to the normal of the * |
* surface of the track at trackIndex * |
* * |
* * |
*************************************************************/ |
void Track_GetNormalVector(NubEntryType *splinePointsPtr, long trackIndex, TQ3Vector3D *theVector) |
{ |
TQ3Vector3D cameraUp; |
Q3Point3D_Subtract(&splinePointsPtr[trackIndex].upPt, /* calc vector from base to up point */ |
&splinePointsPtr[trackIndex].basePt, |
&cameraUp); |
Q3Vector3D_Normalize(&cameraUp,theVector); /* normalize & return it */ |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14