home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwwin
/
spline.c_
/
spline.bin
Wrap
Text File
|
1995-11-14
|
16KB
|
540 lines
/*********************************************************************
*
* File: spline.c
*
* Abstract: Spline related functions mostly taken from rwRoller. Some
* changes were made relating to shape of control point geometry
* and coaster clump.
*
* Author: Colin McCartney
*
* Date: 02/03/95
*
*********************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <rwlib.h>
#include <rwwin.h>
#include "rfview.h"
/**********************************************************************
*
* Constants.
*
**********************************************************************/
/*
* Default description of the rollercoaster.
*/
#define TRACKPOLYGONTAG 1
#define GROUNDPOLYGONTAG 2
#define rfOPAQUE 0.50
#define CONTROLPOINTTAG 1
#define GROUNDPLANETAG 2
#define TRACKTAG 3
#define CARTAG 4
/**********************************************************************/
/*
* Read a spline from the given file.
*/
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.
*/
BOOL
CreateCoasterControlPointClumps(RollerCoasterType *coaster)
{
RwClump *prototypeClump;
int numControlPoints;
int i;
RwClump *clump;
RwV3d point;
ClumpUserData *userData;
/* Allocate the user data for the new clump. */
userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
if (userData == (ClumpUserData *)NULL) return FALSE;
RwModelBegin();
RwClumpBegin();
RwSetTag(CONTROLPOINTTAG);
RwSetSurface(CREAL(0.75), CREAL(0.4), CREAL(0.2));
RwSetSurfaceColor(CREAL(0.0), CREAL(0.0), CREAL(1.0));
RwSetSurfaceLightSampling(rwVERTEX);
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetSurfaceTexture(NULL);
RwSphere(CREAL(0.02), 6);
RwClumpEnd(&prototypeClump);
userData->light = NULL;
userData->datatype = rfIsSpline;
RwSetClumpData(prototypeClump, (void *)userData);
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)); // RF NO USER DATA SET ON SPLINE CONTROL POINTS
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(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.
*/
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;
RwSplinePath path;
ClumpUserData *userData;
if(UseSmoothEnd) path=rwNICEENDS; else path=rwSMOOTH;
/* Allocate the user data for the new clump. */
userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
if (userData == NULL) return NULL;
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, path, t, &point, &tangent);
t = RMul(delta, INT2REAL(i + 2));
RwSplinePoint(coaster->spline, path, t, &nextPoint, &nextTangent);
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.03), &right); // used to be 0.05
RwVertex(RSub(point.x, right.x),
RSub(point.y, right.y),RSub(point.z, right.z));
RwVertex(RAdd(point.x, right.x),
RAdd(point.y, right.y),RAdd(point.z, right.z));
}
RwPushCurrentMaterial();
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetSurfaceOpacity(CREAL(1.0));
RwSetSurface(CREAL(0.5), CREAL(0.4), CREAL(0.0));
RwSetSurfaceTextureModes(rwFORESHORTEN);
RwSetSurfaceColor(CREAL(0.0),CREAL(0.0),CREAL(0.0));
RwSetSurfaceTextureModes((RwTextureModes)NULL);
for (i = 0; i < DEFAULTNUMSPLINESAMPLES; i++)
{
j = (((i + 1) == DEFAULTNUMSPLINESAMPLES) ? 0 : i + 1);
/*
* Add the polygon representing the track surface.
*/
RwQuadExt((i * 2) + 1, (i * 2) + 2, (j * 2) + 2, (j * 2) + 1, TRACKPOLYGONTAG); // A B C D
RwQuadExt((i * 2) + 1, (j * 2) + 1, (j * 2) + 2, (i * 2) + 2, TRACKPOLYGONTAG); // try backside A D C B
}
RwPopCurrentMaterial();
RwClumpEnd(&clump);
userData->light = NULL;
userData->datatype = rfIsSpline;
RwSetClumpData(clump, (void *)userData);
RwModelEnd();
return clump;
}
/**********************************************************************/
// read a spline from disk based on input filename
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 a default spline.
*/
coaster->spline = ReadCoasterSpline(file);
if (coaster->spline == NULL)
{
free(coaster);
fclose(file);
return NULL;
}
/*
* Create the clumps representing the control points
* of the spline.
*/
if (!CreateCoasterControlPointClumps(coaster))
{
RwDestroySpline(coaster->spline);
free(coaster);
fclose(file);
return NULL;
}
/*
* Convert the spline description into a coaster clump.
*/
coaster->coasterClump = CreateCoasterClump(coaster);
if (coaster->coasterClump == NULL)
{
RwDestroySpline(coaster->spline);
free(coaster);
fclose(file);
return NULL;
}
RwAddClumpToScene(Scene, coaster->coasterClump);
/*
* 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;
}
/**********************************************************************/
// if there is a spline, destroy the spline
void
DestroyRollerCoaster(RollerCoasterType *coaster)
{
if (coaster != NULL)
{
if (coaster->spline != NULL)
RwDestroySpline(coaster->spline);
free(coaster);
}
}
/**********************************************************************/
// show the control points
static RwClump *
ShowControlPoint(RwClump *clump)
{
if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
{
RwSetClumpState(clump, rwON);
}
return clump;
}
/**********************************************************************/
// hide the control points
static RwClump *
HideControlPoint(RwClump *clump)
{
if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
{
RwSetClumpState(clump, rwOFF);
}
return clump;
}
/**********************************************************************/
// delete the spline track and control points
static RwClump *
DeleteCoasterAll(RwClump *clump)
{
RwInt32 tag;
tag = RwGetClumpTag(clump);
if ((tag == CONTROLPOINTTAG) || (tag == TRACKTAG) )
{
RwRemoveClumpFromScene(clump);
}
return clump;
}
/**********************************************************************/
// show the track
static RwClump *
ShowTrack(RwClump *clump)
{
if (RwGetClumpTag(clump) == TRACKTAG)
{
RwSetClumpState(clump, rwON);
}
return clump;
}
/**********************************************************************/
// hide the track
static RwClump *
HideTrack(RwClump *clump)
{
if (RwGetClumpTag(clump) == TRACKTAG)
{
RwSetClumpState(clump, rwOFF);
}
return clump;
}
/**********************************************************************/
// position the selected object onto the spline at 0.0
void
PositionObjectOnSpline(RollerCoasterType *coaster,RwClump *object)
{
RwV3d vector;
RwSplinePath path;
#ifdef XXX
RwReal elements[4][4];
#endif
if(UseSmoothEnd) path=rwNICEENDS; else path=rwSMOOTH;
/*
* 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);
#ifdef XXX // use if necessary to align Y
RwPushScratchMatrix();
RwSplineTransform(coaster->spline, path, 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];
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(object, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
#endif
#define YYY
#ifdef YYY // use if not necessary to align Y
RwPushScratchMatrix();
RwSplineTransform(coaster->spline, path, coaster->t, &vector, RwScratchMatrix());
RwTransformClump(object, RwScratchMatrix(), rwREPLACE); // used instead
RwPopScratchMatrix();
#endif
}
/**********************************************************************/
// track the camera to the coaster
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);
}
/**********************************************************************/
// show all coaster control points
void
EnableCoasterControlPoints(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(Scene, (RwClumpFuncPointer)ShowControlPoint, coaster);
}
/**********************************************************************/
// hide all coaster control points
void
DisableCoasterControlPoints(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(Scene, (RwClumpFuncPointer)HideControlPoint, coaster);
}
/**********************************************************************/
// delete all coaster control points and track
void
DeleteCoaster(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(Scene, (RwClumpFuncPointer)DeleteCoasterAll, coaster);
}
/**********************************************************************/
// display all spine path
void
EnableCoasterTrack(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(Scene, (RwClumpFuncPointer)ShowTrack, coaster);
}
/**********************************************************************/
// disable all spline path
void
DisableCoasterTrack(RollerCoasterType *coaster)
{
RwForAllClumpsInScenePointer(Scene, (RwClumpFuncPointer)HideTrack, coaster);
}