home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwwin
/
rolltype.c_
/
rolltype.bin
Wrap
Text File
|
1995-11-14
|
32KB
|
1,041 lines
/**********************************************************************
*
* File : rolltype.c
*
* Abstract : Implementation of the data type encapsulating an
* inidividual rollercoaster.
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1994 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
**********************************************************************/
/**********************************************************************
*
* Header files.
*
**********************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <rwlib.h>
#include <rwwin31.h>
#include "rolltype.h"
/**********************************************************************
*
* Constants.
*
**********************************************************************/
/*
* Default description of the rollercoaster.
*/
#define DEFAULTCOASTERDESCRIPTION "New Rollercoaster"
#define TRACKPOLYGONTAG 1
#define GROUNDPOLYGONTAG 2
/**********************************************************************
*
* Type definitions.
*
**********************************************************************/
/**********************************************************************
*
* Functions.
*
**********************************************************************/
/**********************************************************************/
/*
* Create a default spline (a spline with the given number of control
* pointer arranged in a circle of the given radius).
*/
static RwSpline *
CreateCoasterDefaultSpline(void)
{
RwReal angleDelta;
int i;
RwReal angle;
RwV3d controlPoints[DEFAULTNUMCONTROLPOINTS];
angleDelta = RDiv(RMul(CREAL(2.0), CREAL(M_PI)), INT2REAL(DEFAULTNUMCONTROLPOINTS));
for (i = 0; i < DEFAULTNUMCONTROLPOINTS; i++)
{
angle = RMul(INT2REAL(i), angleDelta);
controlPoints[i].x = RMul(DEFAULTSPLINERADIUS, FL2REAL(cos(REAL2FL(angle))));
controlPoints[i].y = DEFAULTMINCONTROLPOINTHEIGHT;
controlPoints[i].z = RMul(DEFAULTSPLINERADIUS, FL2REAL(sin(REAL2FL(angle))));
}
return RwCreateSpline(DEFAULTNUMCONTROLPOINTS, rwCLOSEDLOOP, &controlPoints[0]);
}
/**********************************************************************/
/*
* Rwad a spline from the given file.
*/
static RwSpline *
ReadCoasterSpline(FILE *file)
{
int numControlPoints;
RwV3d *controlPoints;
int i;
double x;
double y;
double z;
RwSpline *spline;
if (fscanf(file, "%d", &numControlPoints) != 1)
return NULL;
controlPoints = (RwV3d*)malloc(sizeof(RwV3d) * numControlPoints);
if (controlPoints == NULL)
return NULL;
for (i = 0; i < numControlPoints; i++)
{
if (fscanf(file, "%lf %lf %lf", &x, &y, &z) != 3)
{
free(controlPoints);
return NULL;
}
controlPoints[i].x = FL2REAL(x);
controlPoints[i].y = FL2REAL(y);
controlPoints[i].z = FL2REAL(z);
}
spline = RwCreateSpline(numControlPoints, rwCLOSEDLOOP, controlPoints);
free(controlPoints);
return spline;
}
/**********************************************************************/
/*
* Convert the control points of the rollercoaster's spline into clumps
* in coaster's scene.
*/
static BOOL
CreateCoasterControlPointClumps(RollerCoasterType *coaster)
{
RwClump *prototypeClump;
int numControlPoints;
int i;
RwClump *clump;
RwV3d point;
RwModelBegin();
RwClumpBegin();
RwSetTag(CONTROLPOINTTAG);
RwSetSurface(CREAL(0.75), CREAL(0.4), CREAL(0.0));
RwSetSurfaceColor(CREAL(0.0), CREAL(0.0), CREAL(1.0));
RwSetSurfaceLightSampling(rwVERTEX);
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetSurfaceTexture(NULL);
RwCone(CREAL(0.1), CREAL(0.05), 6);
RwDisc(CREAL(0.0), CREAL(-0.05), 6);
RwClumpEnd(&prototypeClump);
RwModelEnd();
numControlPoints = (int)RwGetSplineNumPoints(coaster->spline);
for (i = 0; i < numControlPoints; i++)
{
clump = RwDuplicateClump(prototypeClump);
if (clump == NULL)
{
RwDestroyClump(prototypeClump);
return FALSE;
}
RwSetClumpData(clump, (void *)(i + 1));
RwGetSplinePoint(coaster->spline, i + 1, &point);
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(), point.x, point.y, point.z, rwREPLACE);
RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
coaster->controlPointClumps[i] = clump;
RwAddClumpToScene(coaster->scene, clump);
}
RwDestroyClump(prototypeClump);
return TRUE;
}
/**********************************************************************/
/*
* Create the clump representing the roller coaster itself. Note this
* builds a clump from the given coaster's spline but does not destroy
* the coaster's existing clump (if any) or add the new clump to the
* coater's scene.
*/
static RwClump *
CreateCoasterClump(RollerCoasterType *coaster)
{
RwReal delta;
RwV3d vector;
RwV3d point;
RwV3d tangent;
RwV3d nextPoint;
RwV3d nextTangent;
RwV3d right;
int i;
int j;
RwReal t;
RwClump *clump;
RwUV uv;
delta = RDiv(CREAL(1.0), INT2REAL(DEFAULTNUMSPLINESAMPLES));
RwModelBegin();
RwClumpBegin();
RwSetTag(TRACKTAG);
RwSetHints(rwHS | rwEDITABLE);
for (i = 0; i < DEFAULTNUMSPLINESAMPLES; i++)
{
t = RMul(delta, INT2REAL(i + 1));
RwSplinePoint(coaster->spline, rwSMOOTH, t, &point, &tangent);
if (point.y < DEFAULTGROUNDLEVEL)
point.y = DEFAULTGROUNDLEVEL;
t = RMul(delta, INT2REAL(i + 2));
RwSplinePoint(coaster->spline, rwSMOOTH, t, &nextPoint, &nextTangent);
if (nextPoint.y < DEFAULTGROUNDLEVEL)
nextPoint.y = DEFAULTGROUNDLEVEL;
vector.x = RSub(nextPoint.x, point.x);
vector.y = RSub(nextPoint.y, point.y);
vector.z = RSub(nextPoint.z, point.z);
RwNormalize(&vector);
tangent.x = CREAL(0.0);
tangent.y = CREAL(1.0);
tangent.z = CREAL(0.0);
RwCrossProduct(&vector, &tangent, &right);
RwNormalize(&right);
RwScaleVector(&right, CREAL(0.05), &right);
if (i & 1)
uv.v = CREAL(1.0);
else
uv.v = CREAL(0.0);
uv.u = CREAL(0.0);
RwVertexExt(RSub(point.x, right.x),
RSub(point.y, right.y),
RSub(point.z, right.z), &uv, NULL);
uv.u = CREAL(1.0);
RwVertexExt(RAdd(point.x, right.x),
RAdd(point.y, right.y),
RAdd(point.z, right.z), &uv, NULL);
RwVertex(RSub(point.x, right.x),
CREAL(0.0),
RSub(point.z, right.z));
RwVertex(RAdd(point.x, right.x),
CREAL(0.0),
RAdd(point.z, right.z));
}
for (i = 0; i < DEFAULTNUMSPLINESAMPLES; i++)
{
j = (((i + 1) == DEFAULTNUMSPLINESAMPLES) ? 0 : i + 1);
/*
* Add the polygon representing the track surface.
*/
RwPushCurrentMaterial();
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetSurfaceOpacity(CREAL(1.0));
RwSetSurface(CREAL(0.5), CREAL(0.4), CREAL(0.0));
RwSetSurfaceTextureModes(rwFORESHORTEN);
RwSetSurfaceTexture("track1");
RwQuadExt((i * 4) + 1, (i * 4) + 2, (j * 4) + 2, (j * 4) + 1, TRACKPOLYGONTAG);
RwPopCurrentMaterial();
/*
* Add the polygons representing the sides of the track.
*/
RwPushCurrentMaterial();
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetSurfaceOpacity(CREAL(1.0));
RwSetSurface(CREAL(0.5), CREAL(0.5), CREAL(0.0));
if (i & 1)
RwSetSurfaceColor(CREAL(1.0), CREAL(0.0), CREAL(0.0));
else
RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(1.0));
RwSetSurfaceTexture(NULL);
RwQuad((i * 4) + 4, (j * 4) + 4, (j * 4) + 2, (i * 4) + 2);
RwQuad((i * 4) + 3, (i * 4) + 1, (j * 4) + 1, (j * 4) + 3);
RwPopCurrentMaterial();
}
RwClumpEnd(&clump);
RwModelEnd();
return clump;
}
/**********************************************************************/
/*
* Create the rollercoaster's ground plane.
*/
static RwClump *
CreateCoasterGroundPlaneClump(RollerCoasterType *coaster)
{
RwClump *clump;
RwUV uv;
RwModelBegin();
RwClumpBegin();
RwSetTag(GROUNDPLANETAG);
RwSetHints(rwCONTAINER);
uv.u = CREAL(0.0);
uv.v = CREAL(0.0);
RwVertexExt(CREAL(-6.0), CREAL(-0.02), CREAL(6.0), &uv, NULL);
uv.u = CREAL(32.0);
uv.v = CREAL(0.0);
RwVertexExt(CREAL( 6.0), CREAL(-0.02), CREAL(6.0), &uv, NULL);
uv.u = CREAL(32.0);
uv.v = CREAL(32.0);
RwVertexExt(CREAL( 6.0), CREAL(-0.02), CREAL(-6.0), &uv, NULL);
uv.u = CREAL(0.0);
uv.v = CREAL(32.0);
RwVertexExt(CREAL(-6.0), CREAL(-0.02), CREAL(-6.0), &uv, NULL);
RwSetSurfaceTextureModes(rwFORESHORTEN);
RwSetSurfaceTexture("rcgrass");
RwQuadExt(1, 2, 3, 4, GROUNDPOLYGONTAG);
RwClumpEnd(&clump);
RwModelEnd();
return clump;
}
/**********************************************************************/
RollerCoasterType *
CreateRollerCoaster(void)
{
RollerCoasterType *coaster;
coaster = (RollerCoasterType *)malloc(sizeof(RollerCoasterType));
if (coaster != NULL)
{
/*
* Create the scene for this coaster.
*/
coaster->scene = RwCreateScene();
if (coaster->scene == NULL)
{
return NULL;
}
/*
* Create the holding scene.
*/
coaster->holdingScene = RwCreateScene();
if (coaster->holdingScene == NULL)
{
RwDestroyScene(coaster->scene);
return NULL;
}
/*
* Create the light for this coaster.
*/
coaster->light = RwCreateLight(rwDIRECTIONAL,
CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
CREAL(1.0));
if (coaster->light == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
return NULL;
}
RwAddLightToScene(coaster->scene, coaster->light);
/*
* Create a default spline.
*/
coaster->spline = CreateCoasterDefaultSpline();
if (coaster->spline == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
return NULL;
}
/*
* Create the clumps representing the control points
* of the spline.
*/
if (!CreateCoasterControlPointClumps(coaster))
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
RwDestroySpline(coaster->spline);
return NULL;
}
/*
* Convert the spline description into a coaster clump.
*/
coaster->coasterClump = CreateCoasterClump(coaster);
if (coaster->coasterClump == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
RwDestroySpline(coaster->spline);
return NULL;
}
RwAddClumpToScene(coaster->scene, coaster->coasterClump);
/*
* Create the coaster's ground plane.
*/
coaster->groundPlaneClump = CreateCoasterGroundPlaneClump(coaster);
if (coaster->groundPlaneClump == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
RwDestroySpline(coaster->spline);
return NULL;
}
RwAddClumpToScene(coaster->scene, coaster->groundPlaneClump);
/*
* Create the car clump. If it fails we just ignore it and
* continue on regardless.
*/
coaster->carClump = RwReadShape("car.rwx");
if (coaster->carClump != NULL)
{
RwSetClumpTag(coaster->carClump, CARTAG);
RwSetClumpState(coaster->carClump, rwON);
RwAddClumpToScene(coaster->scene, coaster->carClump);
}
/*
* Initialize the default elevation and plan positions.
*/
coaster->elevationPosition.x = CREAL( 0.0);
coaster->elevationPosition.y = CREAL( 0.1);
coaster->elevationPosition.z = CREAL(-1.5);
coaster->planPosition.x = CREAL( 0.0);
coaster->planPosition.y = CREAL( 2.0);
coaster->planPosition.z = CREAL( 0.0);
/*
* Initialize the spline parameter and spline parameter delta.
*/
coaster->t = CREAL(0.0);
coaster->tDelta = CREAL(0.01);
/*
* Initialize the name and description.
*/
coaster->filename[0] = '\0';
strcpy(coaster->description, DEFAULTCOASTERDESCRIPTION);
return coaster;
}
else
{
return NULL;
}
}
/**********************************************************************/
RollerCoasterType *
ReadRollerCoaster(char *filename)
{
FILE *file;
int len;
RollerCoasterType *coaster;
file = fopen(filename, "r");
if (file == NULL)
return NULL;
coaster = (RollerCoasterType *)malloc(sizeof(RollerCoasterType));
if (coaster == NULL)
{
fclose(file);
return NULL;
}
/*
* Read the description of the rollercoaster.
*/
fgets(coaster->description, sizeof(coaster->description), file);
len = strlen(coaster->description);
if ((len > 0) && (coaster->description[len - 1] == '\n'))
coaster->description[len - 1] = '\0';
/*
* Create the scene for this coaster.
*/
coaster->scene = RwCreateScene();
if (coaster->scene == NULL)
{
free(coaster);
fclose(file);
return NULL;
}
/*
* Create the holding scene for this coaster.
*/
coaster->holdingScene = RwCreateScene();
if (coaster->holdingScene == NULL)
{
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
/*
* Create the light for this coaster.
*/
coaster->light = RwCreateLight(rwDIRECTIONAL,
CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
CREAL(1.0));
if (coaster->light == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
RwAddLightToScene(coaster->scene, coaster->light);
/*
* Create a default spline.
*/
coaster->spline = ReadCoasterSpline(file);
if (coaster->spline == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
/*
* Create the clumps representing the control points
* of the spline.
*/
if (!CreateCoasterControlPointClumps(coaster))
{
RwDestroyScene(coaster->holdingScene);
RwDestroySpline(coaster->spline);
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
/*
* Convert the spline description into a coaster clump.
*/
coaster->coasterClump = CreateCoasterClump(coaster);
if (coaster->coasterClump == NULL)
{
RwDestroyScene(coaster->holdingScene);
RwDestroySpline(coaster->spline);
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
RwAddClumpToScene(coaster->scene, coaster->coasterClump);
/*
* Create the coaster's ground plane.
*/
coaster->groundPlaneClump = CreateCoasterGroundPlaneClump(coaster);
if (coaster->groundPlaneClump == NULL)
{
RwDestroySpline(coaster->spline);
RwDestroyScene(coaster->holdingScene);
RwDestroyScene(coaster->scene);
free(coaster);
fclose(file);
return NULL;
}
RwAddClumpToScene(coaster->scene, coaster->groundPlaneClump);
/*
* Create the car clump. If it fails we just ignore it and
* continue on regardless.
*/
coaster->carClump = RwReadShape("car.rwx");
if (coaster->carClump != NULL)
{
RwSetClumpTag(coaster->carClump, CARTAG);
RwSetClumpState(coaster->carClump, rwON);
RwAddClumpToScene(coaster->scene, coaster->carClump);
}
/*
* Initialize the default elevation and plan positions.
*/
coaster->elevationPosition.x = CREAL( 0.0);
coaster->elevationPosition.y = CREAL( 0.1);
coaster->elevationPosition.z = CREAL(-1.5);
coaster->planPosition.x = CREAL( 0.0);
coaster->planPosition.y = CREAL( 2.0);
coaster->planPosition.z = CREAL( 0.0);
/*
* Initialize the spline parameter and spline parameter delta.
*/
coaster->t = CREAL(0.0);
coaster->tDelta = DEFAULTSPLINEDELTA;
/*
* Save the filename.
*/
strcpy(coaster->filename, filename);
fclose(file);
return coaster;
}
/**********************************************************************/
void
DestroyRollerCoaster(RollerCoasterType *coaster)
{
if (coaster != NULL)
{
if (coaster->scene != NULL)
RwDestroyScene(coaster->scene);
if (coaster->holdingScene != NULL)
RwDestroyScene(coaster->holdingScene);
if (coaster->spline != NULL)
RwDestroySpline(coaster->spline);
free(coaster);
}
}
/**********************************************************************/
BOOL
WriteRollerCoaster(RollerCoasterType *coaster, char *filename)
{
int i;
int numControlPoints;
RwV3d point;
FILE *file;
file = fopen(filename, "w");
if (file == NULL)
return FALSE;
/*
* Write the coaster description.
*/
fputs(coaster->description, file);
fputc('\n', file);
numControlPoints = (int)RwGetSplineNumPoints(coaster->spline);
fprintf(file, "%d\n", numControlPoints);
for (i = 0; i < numControlPoints; i++)
{
RwGetSplinePoint(coaster->spline, i + 1, &point);
fprintf(file, "%lf %lf %lf\n", REAL2FL(point.x), REAL2FL(point.y), REAL2FL(point.z));
}
/*
* Store the filename.
*/
strcpy(coaster->filename, filename);
fclose(file);
return TRUE;
}
/**********************************************************************/
static RwClump *
ShowControlPoint(RwClump *clump, RollerCoasterType *coaster)
{
if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
{
RwAddClumpToScene(coaster->scene, clump);
RwSetClumpState(clump, rwON);
}
return clump;
}
/**********************************************************************/
static RwClump *
HideControlPoint(RwClump *clump, RollerCoasterType *coaster)
{
if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
{
RwAddClumpToScene(coaster->holdingScene, clump);
RwSetClumpState(clump, rwOFF);
}
return clump;
}
/**********************************************************************/
void
SwitchToCoasterRideMode(RollerCoasterType *coaster)
{
DisableCoasterControlPoints(coaster);
/*
* Ensure the coaster itself is fully opaque.
*/
RwForAllPolygonsInClumpReal(coaster->coasterClump,
RwSetPolygonOpacity, CREAL(1.0));
}
/**********************************************************************/
void
SwitchToCoasterEditMode(RollerCoasterType *coaster)
{
EnableCoasterControlPoints(coaster);
/*
* Make the coaster semi-transparent so we can see the control points more
* easily.
*/
RwForAllPolygonsInClumpReal(coaster->coasterClump,
RwSetPolygonOpacity, CREAL(0.75));
}
/**********************************************************************/
/*
* The function tests whether a control point has been picked or not.
* It does a conventional pick and then examines the clump picked (if
* any) to see if it is a control point clump. If it is a control
* point clump then the index of that control point is returned,
* otherwise, 0 is returned.
*/
int
IsCoasterControlPointPicked(RollerCoasterType *coaster, RwCamera *camera, int x, int y)
{
RwPickRecord pick;
if (RwPickScene(coaster->scene, x, y, camera, &pick))
{
if (pick.type == rwPICKCLUMP)
{
if (RwGetClumpTag(pick.object.clump.clump) == CONTROLPOINTTAG)
{
return (int)RwGetClumpData(pick.object.clump.clump);
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
/**********************************************************************/
/*
* Transform the given spline control point of the given rollercoaster.
* Note, this function does not rebuild the coaster's clump. That is
* delayed until UpdateCoasterClump() is called.
*/
void
TransformCoasterControlPoint(RollerCoasterType *coaster, int index, RwMatrix4d *matrix)
{
RwClump *clump;
RwV3d origin;
clump = coaster->controlPointClumps[index - 1];
RwTransformClump(clump, matrix, rwREPLACE);
RwGetClumpOrigin(clump, &origin);
if (origin.y < DEFAULTMINCONTROLPOINTHEIGHT)
{
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(),
CREAL(0.0), RSub(DEFAULTMINCONTROLPOINTHEIGHT, origin.y), CREAL(0.0),
rwREPLACE);
RwTransformClump(clump, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
origin.y = DEFAULTMINCONTROLPOINTHEIGHT;
}
else if (origin.y > DEFAULTMAXCONTROLPOINTHEIGHT)
{
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(),
CREAL(0.0), RSub(DEFAULTMAXCONTROLPOINTHEIGHT, origin.y), CREAL(0.0),
rwREPLACE);
RwTransformClump(clump, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
origin.y = DEFAULTMAXCONTROLPOINTHEIGHT;
}
RwSetSplinePoint(coaster->spline, index, &origin);
}
/**********************************************************************/
/*
* Update the coaster's clump from the coaster's spline.
*/
BOOL
UpdateCoasterClump(RollerCoasterType *coaster)
{
RwClump *clump;
clump = CreateCoasterClump(coaster);
if (clump != NULL)
{
RwDestroyClump(coaster->coasterClump);
coaster->coasterClump = clump;
RwAddClumpToScene(coaster->scene, clump);
RwForAllPolygonsInClumpReal(coaster->coasterClump, RwSetPolygonOpacity, CREAL(0.75));
return TRUE;
}
else
{
return FALSE;
}
}
/**********************************************************************/
void
UpdateViewParameters(RollerCoasterType *coaster)
{
RwV3d vector;
RwReal elements[4][4];
/*
* Get the spline transform. We derive the position and
* orientation of both car and camera from the resulting
* matrix.
*/
vector.x = CREAL(0.0);
vector.y = CREAL(1.0);
vector.z = CREAL(0.0);
RwPushScratchMatrix();
RwSplineTransform(coaster->spline, rwSMOOTH, coaster->t, &vector, RwScratchMatrix());
RwGetMatrixElements(RwScratchMatrix(), elements);
RwPopScratchMatrix();
/*
* Compute the true look-up.
*/
coaster->tUp.x = CREAL(0.0);
coaster->tUp.y = CREAL(1.0);
coaster->tUp.z = CREAL(0.0);
coaster->tAt.x = elements[2][0];
coaster->tAt.y = elements[2][1];
coaster->tAt.z = elements[2][2];
RwCrossProduct(&coaster->tAt, &coaster->tUp, &coaster->tRight);
RwNormalize(&coaster->tRight);
RwCrossProduct(&coaster->tRight, &coaster->tAt, &coaster->tUp);
RwNormalize(&coaster->tUp);
/*
* Get the position.
*/
coaster->tPosition.x = elements[3][0];
coaster->tPosition.y = elements[3][1];
coaster->tPosition.z = elements[3][2];
if (coaster->tPosition.y < DEFAULTGROUNDLEVEL)
coaster->tPosition.y = DEFAULTGROUNDLEVEL;
/*
* If the coaster has a car and the car is enabled, position the
* car w.r.t. the viewing parameters.
*/
if ((coaster->carClump != NULL) &&
(RwGetClumpState(coaster->carClump) == rwON))
{
RwPushScratchMatrix();
elements[0][0] = -coaster->tRight.x;
elements[0][1] = -coaster->tRight.y;
elements[0][2] = -coaster->tRight.z;
elements[0][3] = CREAL(0.0);
elements[1][0] = coaster->tUp.x;
elements[1][1] = coaster->tUp.y;
elements[1][2] = coaster->tUp.z;
elements[1][3] = CREAL(0.0);
elements[2][0] = coaster->tAt.x;
elements[2][1] = coaster->tAt.y;
elements[2][2] = coaster->tAt.z;
elements[2][3] = CREAL(0.0);
elements[3][0] = coaster->tPosition.x;
elements[3][1] = coaster->tPosition.y;
elements[3][2] = coaster->tPosition.z;
elements[3][3] = CREAL(1.0);
RwSetMatrixElements(RwScratchMatrix(), elements);
RwTransformClump(coaster->carClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
}
}
/**********************************************************************/
void
TrackCameraToCoaster(RollerCoasterType *coaster, RwCamera *camera)
{
RwReal x;
RwReal y;
RwReal z;
RwSetCameraLookUp(camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwSetCameraLookAt(camera, coaster->tAt.x, coaster->tAt.y, coaster->tAt.z);
x = RAdd(coaster->tPosition.x, RMul(coaster->tUp.x, CREAL(0.1)));
y = RAdd(coaster->tPosition.y, RMul(coaster->tUp.y, CREAL(0.1)));
z = RAdd(coaster->tPosition.z, RMul(coaster->tUp.z, CREAL(0.1)));
RwSetCameraPosition(camera, x, y, z);
}
/**********************************************************************/
void
UpdateCoasterVelocity(RollerCoasterType *coaster)
{
if (coaster->tAt.y < CREAL(-0.0025))
{
/*
* Falling...
*/
coaster->tDelta = RAdd(coaster->tDelta, SPLINEDELTAACCELERATION);
if (coaster->tDelta > MAXSPLINEDELTA)
coaster->tDelta = MAXSPLINEDELTA;
}
else if (coaster->tAt.y > CREAL(0.0025))
{
/*
* Climbing...
*/
coaster->tDelta = RSub(coaster->tDelta, SPLINEDELTADECCELERATION);
if (coaster->tDelta < MINSPLINEDELTA)
coaster->tDelta = MINSPLINEDELTA;
}
else
{
/*
* Level motion...
*/
if (coaster->tDelta > DEFAULTSPLINEDELTA)
{
coaster->tDelta = RSub(coaster->tDelta, SPLINEDELTADECCELERATION);
if (coaster->tDelta < DEFAULTSPLINEDELTA)
coaster->tDelta = DEFAULTSPLINEDELTA;
}
}
/*
* Advance the position based on the computed delta.
*/
coaster->t = RAdd(coaster->t, coaster->tDelta);
/*
* Clump the delta to 0.0 => 1.0 (we could let the spline stuff do
* this, but eventuallywe would wrap the real rep.).
*/
if (coaster->t > CREAL(1.0))
coaster->t = RSub(coaster->t, CREAL(1.0));
}
/**********************************************************************/
void
EnableCoasterCar(RollerCoasterType *coaster)
{
if (coaster->carClump != NULL)
{
RwAddClumpToScene(coaster->scene, coaster->carClump);
RwSetClumpState(coaster->carClump, rwON);
}
}
/**********************************************************************/
void
DisableCoasterCar(RollerCoasterType *coaster)
{
if (coaster->carClump != NULL)
{
RwAddClumpToScene(coaster->holdingScene, coaster->carClump);
RwSetClumpState(coaster->carClump, rwOFF);
}
}
/**********************************************************************/
void
EnableCoasterControlPoints(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(coaster->scene, (RwClumpFuncPointer)ShowControlPoint, coaster);
RwForAllClumpsInScenePointer(coaster->holdingScene, (RwClumpFuncPointer)ShowControlPoint, coaster);
}
/**********************************************************************/
void
DisableCoasterControlPoints(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(coaster->holdingScene, (RwClumpFuncPointer)HideControlPoint, coaster);
RwForAllClumpsInScenePointer(coaster->scene, (RwClumpFuncPointer)HideControlPoint, coaster);
}
/**********************************************************************/
/**********************************************************************
*
* End of file.
*
**********************************************************************/