home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwdos / rolltype.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  32KB  |  1,045 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     rolltype.c
  4.  *
  5.  * Abstract : Implementation of the data type encapsulating an
  6.  *            inidividual rollercoaster.
  7.  *
  8.  * This file is a product of Criterion Software Ltd.
  9.  *
  10.  * This file is provided as is with no warranties of any kind and is
  11.  * provided without any obligation on Criterion Software Ltd. or
  12.  * Canon Inc. to assist in its use or modification.
  13.  *
  14.  * Criterion Software Ltd. will not, under any
  15.  * circumstances, be liable for any lost revenue or other damages arising
  16.  * from the use of this file.
  17.  *
  18.  * Copyright (c) 1994 Criterion Software Ltd.
  19.  * All Rights Reserved.
  20.  *
  21.  * RenderWare is a trademark of Canon Inc.
  22.  *
  23.  **********************************************************************/
  24.  
  25. /**********************************************************************
  26.  *
  27.  * Header files.
  28.  *
  29.  **********************************************************************/
  30.  
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <math.h>
  34. #include <string.h>
  35.  
  36. #include <rwlib.h>
  37. #include <rwdos.h>
  38.  
  39. #include "rolltype.h"
  40.  
  41. /**********************************************************************
  42.  *
  43.  * Constants.
  44.  *
  45.  **********************************************************************/
  46.  
  47. /*
  48.  * Default description of the rollercoaster.
  49.  */
  50. #define DEFAULTCOASTERDESCRIPTION "New Rollercoaster"
  51.  
  52. #define TRACKPOLYGONTAG           1
  53. #define GROUNDPOLYGONTAG          2
  54.  
  55. /**********************************************************************
  56.  *
  57.  * Type definitions.
  58.  *
  59.  **********************************************************************/
  60.  
  61. /**********************************************************************
  62.  *
  63.  * Functions.
  64.  *
  65.  **********************************************************************/
  66.  
  67. /**********************************************************************/
  68.  
  69. /*
  70.  * Create a default spline (a spline with the given number of control
  71.  * pointer arranged in a circle of the given radius).
  72.  */
  73. static RwSpline *
  74. CreateCoasterDefaultSpline(void)
  75. {
  76.     RwReal angleDelta;
  77.     int    i;
  78.     RwReal angle;
  79.     RwV3d  controlPoints[DEFAULTNUMCONTROLPOINTS];
  80.  
  81.     angleDelta = RDiv(RMul(CREAL(2.0), CREAL(M_PI)), INT2REAL(DEFAULTNUMCONTROLPOINTS));
  82.     for (i = 0; i < DEFAULTNUMCONTROLPOINTS; i++)
  83.     {
  84.         angle = RMul(INT2REAL(i), angleDelta);
  85.         controlPoints[i].x = RMul(DEFAULTSPLINERADIUS, FL2REAL(cos(REAL2FL(angle))));
  86.         controlPoints[i].y = DEFAULTMINCONTROLPOINTHEIGHT;
  87.         controlPoints[i].z = RMul(DEFAULTSPLINERADIUS, FL2REAL(sin(REAL2FL(angle))));
  88.     }
  89.  
  90.     return RwCreateSpline(DEFAULTNUMCONTROLPOINTS, rwCLOSEDLOOP, &controlPoints[0]);
  91. }
  92.  
  93. /**********************************************************************/
  94.  
  95. /*
  96.  * Rwad a spline from the given file.
  97.  */
  98. static RwSpline *
  99. ReadCoasterSpline(FILE *file)
  100. {
  101.     int       numControlPoints;
  102.     RwV3d    *controlPoints;
  103.     int       i;
  104.     double    x;
  105.     double    y;
  106.     double    z;
  107.     RwSpline *spline;
  108.  
  109.     if (fscanf(file, "%d", &numControlPoints) != 1)
  110.         return NULL;
  111.  
  112.     controlPoints = (RwV3d*)malloc(sizeof(RwV3d) * numControlPoints);
  113.     if (controlPoints == NULL)
  114.         return NULL;
  115.  
  116.     for (i = 0; i < numControlPoints; i++)
  117.     {
  118.         if (fscanf(file, "%lf %lf %lf", &x, &y, &z) != 3)
  119.         {
  120.             free(controlPoints);
  121.             return NULL;
  122.         }
  123.         controlPoints[i].x = FL2REAL(x);
  124.         controlPoints[i].y = FL2REAL(y);
  125.         controlPoints[i].z = FL2REAL(z);
  126.     }
  127.  
  128.     spline = RwCreateSpline(numControlPoints, rwCLOSEDLOOP, controlPoints);
  129.  
  130.     free(controlPoints);
  131.  
  132.     return spline;
  133. }
  134.  
  135. /**********************************************************************/
  136.  
  137. /*
  138.  * Convert the control points of the rollercoaster's spline into clumps
  139.  * in coaster's scene.
  140.  */
  141. static RwBool
  142. CreateCoasterControlPointClumps(RollerCoasterType *coaster)
  143. {
  144.     RwClump *prototypeClump;
  145.     int      numControlPoints;
  146.     int      i;
  147.     RwClump *clump;
  148.     RwV3d    point;
  149.  
  150.     RwModelBegin();
  151.         RwClumpBegin();
  152.             RwSetTag(CONTROLPOINTTAG);
  153.             RwSetSurface(CREAL(0.5), CREAL(0.4), CREAL(0.0));
  154.             RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(0.0));
  155.             RwSetSurfaceLightSampling(rwVERTEX);
  156.             RwSetSurfaceGeometrySampling(rwSOLID);
  157.             RwSetSurfaceTexture(NULL);
  158.  
  159.             RwCone(CREAL(0.1), CREAL(0.05), 6);
  160.             RwDisc(CREAL(0.0), CREAL(-0.05), 6);
  161.         RwClumpEnd(&prototypeClump);
  162.     RwModelEnd();
  163.  
  164.     numControlPoints = RwGetSplineNumPoints(coaster->spline);
  165.     for (i = 0; i < numControlPoints; i++)
  166.     {
  167.         clump = RwDuplicateClump(prototypeClump);
  168.         if (clump == NULL)
  169.         {
  170.             RwDestroyClump(prototypeClump);
  171.             return FALSE;
  172.         }
  173.         RwSetClumpData(clump, (void *)(i + 1));
  174.         RwGetSplinePoint(coaster->spline, i + 1, &point);
  175.         RwPushScratchMatrix();
  176.             RwTranslateMatrix(RwScratchMatrix(), point.x, point.y, point.z, rwREPLACE);
  177.             RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  178.         RwPopScratchMatrix();
  179.  
  180.         coaster->controlPointClumps[i] = clump;
  181.  
  182.         RwAddClumpToScene(coaster->scene, clump);
  183.     }
  184.  
  185.     RwDestroyClump(prototypeClump);
  186.  
  187.     return TRUE;
  188. }
  189.  
  190. /**********************************************************************/
  191.  
  192. /*
  193.  * Create the clump representing the roller coaster itself. Note this
  194.  * builds a clump from the given coaster's spline but does not destroy
  195.  * the coaster's existing clump (if any) or add the new clump to the
  196.  * coater's scene.
  197.  */
  198. static RwClump *
  199. CreateCoasterClump(RollerCoasterType *coaster)
  200. {
  201.     RwReal   delta;
  202.     RwV3d    vector;
  203.     RwV3d    point;
  204.     RwV3d    tangent;
  205.     RwV3d    nextPoint;
  206.     RwV3d    nextTangent;
  207.     RwV3d    right;
  208.     int      i;
  209.     int      j;
  210.     RwReal   t;
  211.     RwClump *clump;
  212.     RwUV     uv;
  213.  
  214.     delta = RDiv(CREAL(1.0), INT2REAL(DEFAULTNUMSPLINESAMPLES));
  215.  
  216.     RwModelBegin();
  217.         RwClumpBegin();
  218.             RwSetTag(TRACKTAG);
  219.             RwSetHints(rwHS | rwEDITABLE);
  220.             for (i = 0; i < DEFAULTNUMSPLINESAMPLES; i++)
  221.             {
  222.                 t = RMul(delta, INT2REAL(i + 1));
  223.                 RwSplinePoint(coaster->spline, rwSMOOTH, t, &point, &tangent);
  224.                 if (point.y < DEFAULTGROUNDLEVEL)
  225.                     point.y = DEFAULTGROUNDLEVEL;
  226.                 t = RMul(delta, INT2REAL(i + 2));
  227.                 RwSplinePoint(coaster->spline, rwSMOOTH, t, &nextPoint, &nextTangent);
  228.                 if (nextPoint.y < DEFAULTGROUNDLEVEL)
  229.                     nextPoint.y = DEFAULTGROUNDLEVEL;
  230.                 vector.x = RSub(nextPoint.x, point.x);
  231.                 vector.y = RSub(nextPoint.y, point.y);
  232.                 vector.z = RSub(nextPoint.z, point.z);
  233.                 RwNormalize(&vector);
  234.                 tangent.x = CREAL(0.0);
  235.                 tangent.y = CREAL(1.0);
  236.                 tangent.z = CREAL(0.0);
  237.                 RwCrossProduct(&vector, &tangent, &right);
  238.                 RwNormalize(&right);
  239.                 RwScaleVector(&right, CREAL(0.05), &right);
  240.  
  241.                 if (i & 1)
  242.                     uv.v = CREAL(1.0);
  243.                 else
  244.                     uv.v = CREAL(0.0);
  245.                 uv.u = CREAL(0.0);
  246.                 RwVertexExt(RSub(point.x, right.x),
  247.                             RSub(point.y, right.y),
  248.                             RSub(point.z, right.z), &uv, NULL);
  249.                 uv.u = CREAL(1.0);
  250.                 RwVertexExt(RAdd(point.x, right.x),
  251.                             RAdd(point.y, right.y),
  252.                             RAdd(point.z, right.z), &uv, NULL);
  253.                 RwVertex(RSub(point.x, right.x),
  254.                          CREAL(0.0),
  255.                          RSub(point.z, right.z));
  256.                 RwVertex(RAdd(point.x, right.x),
  257.                          CREAL(0.0),
  258.                          RAdd(point.z, right.z));
  259.             }
  260.  
  261.             for (i = 0; i < DEFAULTNUMSPLINESAMPLES; i++)
  262.             {
  263.                 j = (((i + 1) == DEFAULTNUMSPLINESAMPLES) ? 0 : i + 1);
  264.  
  265.                 /*
  266.                  * Add the polygon representing the track surface.
  267.                  */
  268.                 RwPushCurrentMaterial();
  269.                     RwSetSurfaceGeometrySampling(rwSOLID);
  270.                     RwSetSurfaceOpacity(CREAL(1.0));
  271.                     RwSetSurface(CREAL(0.5), CREAL(0.4), CREAL(0.0));
  272.                     RwSetSurfaceTextureModes(rwFORESHORTEN);
  273.                     RwSetSurfaceTexture("track1");
  274.                     RwQuadExt((i * 4) + 1, (i * 4) + 2, (j * 4) + 2, (j * 4) + 1, TRACKPOLYGONTAG);
  275.                 RwPopCurrentMaterial();
  276.  
  277.                 /*
  278.                  * Add the polygons representing the sides of the track.
  279.                  */
  280.                 RwPushCurrentMaterial();
  281.                     RwSetSurfaceGeometrySampling(rwSOLID);
  282.                     RwSetSurfaceOpacity(CREAL(1.0));
  283.                     RwSetSurface(CREAL(0.5), CREAL(0.5), CREAL(0.0));
  284.                     if (i & 1)
  285.                         RwSetSurfaceColor(CREAL(1.0), CREAL(0.0), CREAL(0.0));
  286.                     else
  287.                         RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(1.0));
  288.                     RwSetSurfaceTexture(NULL);
  289.                     RwQuad((i * 4) + 4, (j * 4) + 4, (j * 4) + 2, (i * 4) + 2);
  290.                     RwQuad((i * 4) + 3, (i * 4) + 1, (j * 4) + 1, (j * 4) + 3);
  291.                 RwPopCurrentMaterial();
  292.             }
  293.         RwClumpEnd(&clump);
  294.     RwModelEnd();
  295.  
  296.     return clump;
  297. }
  298.  
  299. /**********************************************************************/
  300.  
  301. /*
  302.  * Create the rollercoaster's ground plane.
  303.  */
  304. static RwClump *
  305. CreateCoasterGroundPlaneClump(RollerCoasterType *coaster)
  306. {
  307.     RwClump *clump;
  308.     RwUV     uv;
  309.  
  310.     /* Stop warnings */
  311.  
  312.     coaster = coaster;
  313.  
  314.     /* Continue */
  315.  
  316.     RwModelBegin();
  317.         RwClumpBegin();
  318.             RwSetTag(GROUNDPLANETAG);
  319.             RwSetHints(rwCONTAINER);
  320.             uv.u = CREAL(0.0);
  321.             uv.v = CREAL(0.0);
  322.             RwVertexExt(CREAL(-6.0), CREAL(-0.02), CREAL(6.0), &uv, NULL);
  323.             uv.u = CREAL(32.0);
  324.             uv.v = CREAL(0.0);
  325.             RwVertexExt(CREAL( 6.0), CREAL(-0.02), CREAL(6.0), &uv, NULL);
  326.             uv.u = CREAL(32.0);
  327.             uv.v = CREAL(32.0);
  328.             RwVertexExt(CREAL( 6.0), CREAL(-0.02), CREAL(-6.0), &uv, NULL);
  329.             uv.u = CREAL(0.0);
  330.             uv.v = CREAL(32.0);
  331.             RwVertexExt(CREAL(-6.0), CREAL(-0.02), CREAL(-6.0), &uv, NULL);
  332.  
  333.             RwSetSurfaceTextureModes(rwFORESHORTEN);
  334.             RwSetSurfaceTexture("rcgrass");
  335.             RwQuadExt(1, 2, 3, 4, GROUNDPOLYGONTAG);
  336.         RwClumpEnd(&clump);
  337.     RwModelEnd();
  338.  
  339.     return clump;
  340. }
  341.  
  342. /**********************************************************************/
  343.  
  344. RollerCoasterType *
  345. CreateRollerCoaster(void)
  346. {
  347.     RollerCoasterType *coaster;
  348.  
  349.     coaster = (RollerCoasterType *)malloc(sizeof(RollerCoasterType));
  350.     if (coaster != NULL)
  351.     {
  352.         /*
  353.          * Create the scene for this coaster.
  354.          */
  355.         coaster->scene = RwCreateScene();
  356.         if (coaster->scene == NULL)
  357.         {
  358.             return NULL;
  359.         }
  360.  
  361.         /*
  362.          * Create the holding scene.
  363.          */
  364.         coaster->holdingScene = RwCreateScene();
  365.         if (coaster->holdingScene == NULL)
  366.         {
  367.             RwDestroyScene(coaster->scene);
  368.             return NULL;
  369.         }
  370.  
  371.         /*
  372.          * Create the light for this coaster.
  373.          */
  374.         coaster->light = RwCreateLight(rwDIRECTIONAL,
  375.                                        CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  376.                                        CREAL(1.0));
  377.         if (coaster->light == NULL)
  378.         {
  379.             RwDestroyScene(coaster->holdingScene);
  380.             RwDestroyScene(coaster->scene);
  381.             return NULL;
  382.         }
  383.         RwAddLightToScene(coaster->scene, coaster->light);
  384.  
  385.         /*
  386.          * Create a default spline.
  387.          */
  388.         coaster->spline = CreateCoasterDefaultSpline();
  389.         if (coaster->spline == NULL)
  390.         {
  391.             RwDestroyScene(coaster->holdingScene);
  392.             RwDestroyScene(coaster->scene);
  393.             return NULL;
  394.         }
  395.  
  396.         /*
  397.          * Create the clumps representing the control points
  398.          * of the spline.
  399.          */
  400.         if (!CreateCoasterControlPointClumps(coaster))
  401.         {
  402.             RwDestroyScene(coaster->holdingScene);
  403.             RwDestroyScene(coaster->scene);
  404.             RwDestroySpline(coaster->spline);
  405.             return NULL;
  406.         }
  407.  
  408.         /*
  409.          * Convert the spline description into a coaster clump.
  410.          */
  411.         coaster->coasterClump = CreateCoasterClump(coaster);
  412.         if (coaster->coasterClump == NULL)
  413.         {
  414.             RwDestroyScene(coaster->holdingScene);
  415.             RwDestroyScene(coaster->scene);
  416.             RwDestroySpline(coaster->spline);
  417.             return NULL;
  418.         }
  419.         RwAddClumpToScene(coaster->scene, coaster->coasterClump);
  420.  
  421.         /*
  422.          * Create the coaster's ground plane.
  423.          */
  424.         coaster->groundPlaneClump = CreateCoasterGroundPlaneClump(coaster);
  425.         if (coaster->groundPlaneClump == NULL)
  426.         {
  427.             RwDestroyScene(coaster->holdingScene);
  428.             RwDestroyScene(coaster->scene);
  429.             RwDestroySpline(coaster->spline);
  430.             return NULL;
  431.         }
  432.         RwAddClumpToScene(coaster->scene, coaster->groundPlaneClump);
  433.  
  434.         /*
  435.          * Create the car clump. If it fails we just ignore it and
  436.          * continue on regardless.
  437.          */
  438.         coaster->carClump = RwReadShape("car.rwx");
  439.         if (coaster->carClump != NULL)
  440.         {
  441.             RwSetClumpTag(coaster->carClump, CARTAG);
  442.             RwSetClumpState(coaster->carClump, rwON);
  443.             RwAddClumpToScene(coaster->scene, coaster->carClump);
  444.         }
  445.  
  446.         /*
  447.          * Initialize the default elevation and plan positions.
  448.          */
  449.         coaster->elevationPosition.x = CREAL( 0.0);
  450.         coaster->elevationPosition.y = CREAL( 0.1);
  451.         coaster->elevationPosition.z = CREAL(-1.5);
  452.  
  453.         coaster->planPosition.x      = CREAL( 0.0);
  454.         coaster->planPosition.y      = CREAL( 2.0);
  455.         coaster->planPosition.z      = CREAL( 0.0);
  456.  
  457.         /*
  458.          * Initialize the spline parameter and spline parameter delta.
  459.          */
  460.         coaster->t      = CREAL(0.0);
  461.         coaster->tDelta = CREAL(0.01);
  462.  
  463.         /*
  464.          * Initialize the name and description.
  465.          */
  466.         coaster->filename[0]    = '\0';
  467.         strcpy(coaster->description, DEFAULTCOASTERDESCRIPTION);
  468.  
  469.         return coaster;
  470.     }
  471.     else
  472.     {
  473.         return NULL;
  474.     }
  475. }
  476.  
  477. /**********************************************************************/
  478.  
  479. RollerCoasterType *
  480. ReadRollerCoaster(char *filename)
  481. {
  482.     FILE *file;
  483.     int   len;
  484.  
  485.     RollerCoasterType *coaster;
  486.  
  487.     file = fopen(filename, "r");
  488.     if (file == NULL)
  489.         return NULL;
  490.  
  491.     coaster = (RollerCoasterType *)malloc(sizeof(RollerCoasterType));
  492.     if (coaster == NULL)
  493.     {
  494.         fclose(file);
  495.         return NULL;
  496.     }
  497.  
  498.     /*
  499.      * Read the description of the rollercoaster.
  500.      */
  501.     fgets(coaster->description, sizeof(coaster->description), file);
  502.     len = strlen(coaster->description);
  503.     if ((len > 0) && (coaster->description[len - 1] == '\n'))
  504.         coaster->description[len - 1] = '\0';
  505.  
  506.     /*
  507.      * Create the scene for this coaster.
  508.      */
  509.     coaster->scene = RwCreateScene();
  510.     if (coaster->scene == NULL)
  511.     {
  512.         free(coaster);
  513.         fclose(file);
  514.         return NULL;
  515.     }
  516.  
  517.     /*
  518.      * Create the holding scene for this coaster.
  519.      */
  520.     coaster->holdingScene = RwCreateScene();
  521.     if (coaster->holdingScene == NULL)
  522.     {
  523.         RwDestroyScene(coaster->scene);
  524.         free(coaster);
  525.         fclose(file);
  526.         return NULL;
  527.     }
  528.  
  529.     /*
  530.      * Create the light for this coaster.
  531.      */
  532.     coaster->light = RwCreateLight(rwDIRECTIONAL,
  533.                                    CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  534.                                    CREAL(1.0));
  535.     if (coaster->light == NULL)
  536.     {
  537.         RwDestroyScene(coaster->holdingScene);
  538.         RwDestroyScene(coaster->scene);
  539.         free(coaster);
  540.         fclose(file);
  541.         return NULL;
  542.     }
  543.     RwAddLightToScene(coaster->scene, coaster->light);
  544.  
  545.     /*
  546.      * Create a default spline.
  547.      */
  548.     coaster->spline = ReadCoasterSpline(file);
  549.     if (coaster->spline == NULL)
  550.     {
  551.         RwDestroyScene(coaster->holdingScene);
  552.         RwDestroyScene(coaster->scene);
  553.         free(coaster);
  554.         fclose(file);
  555.         return NULL;
  556.     }
  557.  
  558.     /*
  559.      * Create the clumps representing the control points
  560.      * of the spline.
  561.      */
  562.     if (!CreateCoasterControlPointClumps(coaster))
  563.     {
  564.         RwDestroyScene(coaster->holdingScene);
  565.         RwDestroySpline(coaster->spline);
  566.         RwDestroyScene(coaster->scene);
  567.         free(coaster);
  568.         fclose(file);
  569.         return NULL;
  570.     }
  571.  
  572.     /*
  573.      * Convert the spline description into a coaster clump.
  574.      */
  575.     coaster->coasterClump = CreateCoasterClump(coaster);
  576.     if (coaster->coasterClump == NULL)
  577.     {
  578.         RwDestroyScene(coaster->holdingScene);
  579.         RwDestroySpline(coaster->spline);
  580.         RwDestroyScene(coaster->scene);
  581.         free(coaster);
  582.         fclose(file);
  583.         return NULL;
  584.     }
  585.     RwAddClumpToScene(coaster->scene, coaster->coasterClump);
  586.  
  587.     /*
  588.      * Create the coaster's ground plane.
  589.      */
  590.     coaster->groundPlaneClump = CreateCoasterGroundPlaneClump(coaster);
  591.     if (coaster->groundPlaneClump == NULL)
  592.     {
  593.         RwDestroySpline(coaster->spline);
  594.         RwDestroyScene(coaster->holdingScene);
  595.         RwDestroyScene(coaster->scene);
  596.         free(coaster);
  597.         fclose(file);
  598.         return NULL;
  599.     }
  600.     RwAddClumpToScene(coaster->scene, coaster->groundPlaneClump);
  601.  
  602.     /*
  603.      * Create the car clump. If it fails we just ignore it and
  604.      * continue on regardless.
  605.      */
  606.     coaster->carClump = RwReadShape("car.rwx");
  607.     if (coaster->carClump != NULL)
  608.     {
  609.         RwSetClumpTag(coaster->carClump, CARTAG);
  610.         RwSetClumpState(coaster->carClump, rwON);
  611.         RwAddClumpToScene(coaster->scene, coaster->carClump);
  612.     }
  613.  
  614.     /*
  615.      * Initialize the default elevation and plan positions.
  616.      */
  617.     coaster->elevationPosition.x = CREAL( 0.0);
  618.     coaster->elevationPosition.y = CREAL( 0.1);
  619.     coaster->elevationPosition.z = CREAL(-1.5);
  620.  
  621.     coaster->planPosition.x      = CREAL( 0.0);
  622.     coaster->planPosition.y      = CREAL( 2.0);
  623.     coaster->planPosition.z      = CREAL( 0.0);
  624.  
  625.     /*
  626.      * Initialize the spline parameter and spline parameter delta.
  627.      */
  628.     coaster->t      = CREAL(0.0);
  629.     coaster->tDelta = DEFAULTSPLINEDELTA;
  630.  
  631.     /*
  632.      * Save the filename.
  633.      */
  634.     strcpy(coaster->filename, filename);
  635.  
  636.     fclose(file);
  637.  
  638.     return coaster;
  639. }
  640.  
  641. /**********************************************************************/
  642.  
  643. void
  644. DestroyRollerCoaster(RollerCoasterType *coaster)
  645. {
  646.     if (coaster != NULL)
  647.     {
  648.         if (coaster->scene != NULL)
  649.             RwDestroyScene(coaster->scene);
  650.         if (coaster->holdingScene != NULL)
  651.             RwDestroyScene(coaster->holdingScene);
  652.         if (coaster->spline != NULL)
  653.             RwDestroySpline(coaster->spline);
  654.         free(coaster);
  655.     }
  656. }
  657.  
  658. /**********************************************************************/
  659.  
  660. RwBool
  661. WriteRollerCoaster(RollerCoasterType *coaster, char *filename)
  662. {
  663.     int    i;
  664.     int    numControlPoints;
  665.     RwV3d  point;
  666.     FILE  *file;
  667.  
  668.     file = fopen(filename, "w");
  669.     if (file == NULL)
  670.         return FALSE;
  671.  
  672.     /*
  673.      * Write the coaster description.
  674.      */
  675.     fputs(coaster->description, file);
  676.     fputc('\n', file);
  677.  
  678.     numControlPoints = RwGetSplineNumPoints(coaster->spline);
  679.     fprintf(file, "%d\n", numControlPoints);
  680.  
  681.     for (i = 0; i < numControlPoints; i++)
  682.     {
  683.         RwGetSplinePoint(coaster->spline, i + 1, &point);
  684.         fprintf(file, "%lf %lf %lf\n", REAL2FL(point.x), REAL2FL(point.y), REAL2FL(point.z));
  685.     }
  686.  
  687.     /*
  688.      * Store the filename.
  689.      */
  690.     strcpy(coaster->filename, filename);
  691.  
  692.     fclose(file);
  693.  
  694.     return TRUE;
  695. }
  696.  
  697. /**********************************************************************/
  698.  
  699. static RwClump *
  700. ShowControlPoint(RwClump *clump, RollerCoasterType *coaster)
  701. {
  702.     if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
  703.     {
  704.         RwAddClumpToScene(coaster->scene, clump);
  705.         RwSetClumpState(clump, rwON);
  706.     }
  707.     return clump;
  708. }
  709.  
  710. /**********************************************************************/
  711.  
  712. static RwClump *
  713. HideControlPoint(RwClump *clump, RollerCoasterType *coaster)
  714. {
  715.     if (RwGetClumpTag(clump) == CONTROLPOINTTAG)
  716.     {
  717.         RwAddClumpToScene(coaster->holdingScene, clump);
  718.         RwSetClumpState(clump, rwOFF);
  719.     }
  720.     return clump;
  721. }
  722.  
  723. /**********************************************************************/
  724.  
  725. void
  726. SwitchToCoasterRideMode(RollerCoasterType *coaster)
  727. {
  728.     DisableCoasterControlPoints(coaster);
  729.  
  730.     /*
  731.      * Ensure the coaster itself is fully opaque.
  732.      */
  733.     RwForAllPolygonsInClumpReal(coaster->coasterClump,
  734.                                 RwSetPolygonOpacity, CREAL(1.0));
  735. }
  736.  
  737. /**********************************************************************/
  738.  
  739. void
  740. SwitchToCoasterEditMode(RollerCoasterType *coaster)
  741. {
  742.     EnableCoasterControlPoints(coaster);
  743.  
  744.     /*
  745.      * Make the coaster semi-transparent so we can see the control points more
  746.      * easily.
  747.      */
  748.     RwForAllPolygonsInClumpReal(coaster->coasterClump,
  749.                                 RwSetPolygonOpacity, CREAL(0.75));
  750. }
  751.  
  752. /**********************************************************************/
  753.  
  754. /*
  755.  * The function tests whether a control point has been picked or not.
  756.  * It does a conventional pick and then examines the clump picked (if
  757.  * any) to see if it is a control point clump. If it is a control
  758.  * point clump then the index of that control point is returned,
  759.  * otherwise, 0 is returned.
  760.  */
  761. int
  762. IsCoasterControlPointPicked(RollerCoasterType *coaster, RwCamera *camera, int x, int y)
  763. {
  764.     RwPickRecord pick;
  765.  
  766.     if (RwPickScene(coaster->scene, x, y, camera, &pick))
  767.     {
  768.         if (pick.type == rwPICKCLUMP)
  769.         {
  770.             if (RwGetClumpTag(pick.object.clump.clump) == CONTROLPOINTTAG)
  771.             {
  772.                 return (int)RwGetClumpData(pick.object.clump.clump);
  773.             }
  774.             else
  775.             {
  776.                 return FALSE;
  777.             }
  778.         }
  779.         else
  780.         {
  781.             return FALSE;
  782.         }
  783.     }
  784.     else
  785.     {
  786.         return FALSE;
  787.     }
  788. }
  789.  
  790. /**********************************************************************/
  791.  
  792. /*
  793.  * Transform the given spline control point of the given rollercoaster.
  794.  * Note, this function does not rebuild the coaster's clump. That is
  795.  * delayed until UpdateCoasterClump() is called.
  796.  */
  797. void
  798. TransformCoasterControlPoint(RollerCoasterType *coaster, int index, RwMatrix4d *matrix)
  799. {
  800.     RwClump *clump;
  801.     RwV3d    origin;
  802.  
  803.     clump = coaster->controlPointClumps[index - 1];
  804.  
  805.     RwTransformClump(clump, matrix, rwREPLACE);
  806.     RwGetClumpOrigin(clump, &origin);
  807.     if (origin.y < DEFAULTMINCONTROLPOINTHEIGHT)
  808.     {
  809.         RwPushScratchMatrix();
  810.             RwTranslateMatrix(RwScratchMatrix(),
  811.                               CREAL(0.0), RSub(DEFAULTMINCONTROLPOINTHEIGHT, origin.y), CREAL(0.0),
  812.                               rwREPLACE);
  813.             RwTransformClump(clump, RwScratchMatrix(), rwPOSTCONCAT);
  814.         RwPopScratchMatrix();
  815.         origin.y = DEFAULTMINCONTROLPOINTHEIGHT;
  816.     }
  817.     else if (origin.y > DEFAULTMAXCONTROLPOINTHEIGHT)
  818.     {
  819.         RwPushScratchMatrix();
  820.             RwTranslateMatrix(RwScratchMatrix(),
  821.                               CREAL(0.0), RSub(DEFAULTMAXCONTROLPOINTHEIGHT, origin.y), CREAL(0.0),
  822.                               rwREPLACE);
  823.             RwTransformClump(clump, RwScratchMatrix(), rwPOSTCONCAT);
  824.         RwPopScratchMatrix();
  825.         origin.y = DEFAULTMAXCONTROLPOINTHEIGHT;
  826.     }
  827.     RwSetSplinePoint(coaster->spline, index, &origin);
  828. }
  829.  
  830. /**********************************************************************/
  831.  
  832. /*
  833.  * Update the coaster's clump from the coaster's spline.
  834.  */
  835. RwBool
  836. UpdateCoasterClump(RollerCoasterType *coaster)
  837. {
  838.     RwClump *clump;
  839.  
  840.     clump = CreateCoasterClump(coaster);
  841.     if (clump != NULL)
  842.     {
  843.         RwDestroyClump(coaster->coasterClump);
  844.         coaster->coasterClump = clump;
  845.         RwAddClumpToScene(coaster->scene, clump);
  846.         RwForAllPolygonsInClumpReal(coaster->coasterClump, RwSetPolygonOpacity, CREAL(0.75));
  847.         return TRUE;
  848.     }
  849.     else
  850.     {
  851.         return FALSE;
  852.     }
  853. }
  854.  
  855. /**********************************************************************/
  856.  
  857. void
  858. UpdateViewParameters(RollerCoasterType *coaster)
  859. {
  860.     RwV3d  vector;
  861.     RwReal elements[4][4];
  862.  
  863.     /*
  864.      * Get the spline transform. We derive the position and
  865.      * orientation of both car and camera from the resulting
  866.      * matrix.
  867.      */
  868.     vector.x = CREAL(0.0);
  869.     vector.y = CREAL(1.0);
  870.     vector.z = CREAL(0.0);
  871.     RwPushScratchMatrix();
  872.         RwSplineTransform(coaster->spline, rwSMOOTH, coaster->t, &vector, RwScratchMatrix());
  873.         RwGetMatrixElements(RwScratchMatrix(), elements);
  874.     RwPopScratchMatrix();
  875.  
  876.     /*
  877.      * Compute the true look-up.
  878.      */
  879.     coaster->tUp.x = CREAL(0.0);
  880.     coaster->tUp.y = CREAL(1.0);
  881.     coaster->tUp.z = CREAL(0.0);
  882.     coaster->tAt.x = elements[2][0];
  883.     coaster->tAt.y = elements[2][1];
  884.     coaster->tAt.z = elements[2][2];
  885.     RwCrossProduct(&coaster->tAt, &coaster->tUp, &coaster->tRight);
  886.     RwNormalize(&coaster->tRight);
  887.     RwCrossProduct(&coaster->tRight, &coaster->tAt, &coaster->tUp);
  888.     RwNormalize(&coaster->tUp);
  889.  
  890.     /*
  891.      * Get the position.
  892.      */
  893.     coaster->tPosition.x = elements[3][0];
  894.     coaster->tPosition.y = elements[3][1];
  895.     coaster->tPosition.z = elements[3][2];
  896.     if (coaster->tPosition.y < DEFAULTGROUNDLEVEL)
  897.         coaster->tPosition.y = DEFAULTGROUNDLEVEL;
  898.  
  899.     /*
  900.      * If the coaster has a car and the car is enabled, position the
  901.      * car w.r.t. the viewing parameters.
  902.      */
  903.     if ((coaster->carClump != NULL) &&
  904.         (RwGetClumpState(coaster->carClump) == rwON))
  905.     {
  906.         RwPushScratchMatrix();
  907.             elements[0][0] = -coaster->tRight.x;
  908.             elements[0][1] = -coaster->tRight.y;
  909.             elements[0][2] = -coaster->tRight.z;
  910.             elements[0][3] = CREAL(0.0);
  911.             elements[1][0] = coaster->tUp.x;
  912.             elements[1][1] = coaster->tUp.y;
  913.             elements[1][2] = coaster->tUp.z;
  914.             elements[1][3] = CREAL(0.0);
  915.             elements[2][0] = coaster->tAt.x;
  916.             elements[2][1] = coaster->tAt.y;
  917.             elements[2][2] = coaster->tAt.z;
  918.             elements[2][3] = CREAL(0.0);
  919.             elements[3][0] = coaster->tPosition.x;
  920.             elements[3][1] = coaster->tPosition.y;
  921.             elements[3][2] = coaster->tPosition.z;
  922.             elements[3][3] = CREAL(1.0);
  923.             RwSetMatrixElements(RwScratchMatrix(), elements);
  924.             RwTransformClump(coaster->carClump, RwScratchMatrix(), rwREPLACE);
  925.         RwPopScratchMatrix();
  926.     }
  927. }
  928.  
  929. /**********************************************************************/
  930.  
  931. void
  932. TrackCameraToCoaster(RollerCoasterType *coaster, RwCamera *camera)
  933. {
  934.     RwReal x;
  935.     RwReal y;
  936.     RwReal z;
  937.  
  938.     RwSetCameraLookUp(camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  939.     RwSetCameraLookAt(camera, coaster->tAt.x, coaster->tAt.y, coaster->tAt.z);
  940.  
  941.     x = RAdd(coaster->tPosition.x, RMul(coaster->tUp.x, CREAL(0.1)));
  942.     y = RAdd(coaster->tPosition.y, RMul(coaster->tUp.y, CREAL(0.1)));
  943.     z = RAdd(coaster->tPosition.z, RMul(coaster->tUp.z, CREAL(0.1)));
  944.     RwSetCameraPosition(camera, x, y, z);
  945. }
  946.  
  947. /**********************************************************************/
  948.  
  949. void
  950. UpdateCoasterVelocity(RollerCoasterType *coaster)
  951. {
  952.     if (coaster->tAt.y < CREAL(-0.0025))
  953.     {
  954.         /*
  955.          * Falling...
  956.          */
  957.         coaster->tDelta = RAdd(coaster->tDelta, SPLINEDELTAACCELERATION);
  958.         if (coaster->tDelta > MAXSPLINEDELTA)
  959.             coaster->tDelta = MAXSPLINEDELTA;
  960.     }
  961.     else if (coaster->tAt.y > CREAL(0.0025))
  962.     {
  963.         /*
  964.          * Climbing...
  965.          */
  966.         coaster->tDelta = RSub(coaster->tDelta, SPLINEDELTADECCELERATION);
  967.         if (coaster->tDelta < MINSPLINEDELTA)
  968.             coaster->tDelta = MINSPLINEDELTA;
  969.     }
  970.     else
  971.     {
  972.         /*
  973.          * Level motion...
  974.          */
  975.         if (coaster->tDelta > DEFAULTSPLINEDELTA)
  976.         {
  977.             coaster->tDelta = RSub(coaster->tDelta, SPLINEDELTADECCELERATION);
  978.             if (coaster->tDelta < DEFAULTSPLINEDELTA)
  979.                 coaster->tDelta = DEFAULTSPLINEDELTA;
  980.         }
  981.     }
  982.  
  983.     /*
  984.      * Advance the position based on the computed delta.
  985.      */
  986.     coaster->t = RAdd(coaster->t, coaster->tDelta);
  987.  
  988.     /*
  989.      * Clump the delta to 0.0 => 1.0 (we could let the spline stuff do
  990.      * this, but eventuallywe would wrap the real rep.).
  991.      */
  992.     if (coaster->t > CREAL(1.0))
  993.            coaster->t = RSub(coaster->t, CREAL(1.0));
  994. }
  995.  
  996. /**********************************************************************/
  997.  
  998. void
  999. EnableCoasterCar(RollerCoasterType *coaster)
  1000. {
  1001.     if (coaster->carClump != NULL)
  1002.     {
  1003.         RwAddClumpToScene(coaster->scene, coaster->carClump);
  1004.         RwSetClumpState(coaster->carClump, rwON);
  1005.     }
  1006. }
  1007.  
  1008. /**********************************************************************/
  1009.  
  1010. void
  1011. DisableCoasterCar(RollerCoasterType *coaster)
  1012. {
  1013.     if (coaster->carClump != NULL)
  1014.     {
  1015.         RwAddClumpToScene(coaster->holdingScene, coaster->carClump);
  1016.         RwSetClumpState(coaster->carClump, rwOFF);
  1017.     }
  1018. }
  1019.  
  1020. /**********************************************************************/
  1021.  
  1022. void
  1023. EnableCoasterControlPoints(RollerCoasterType *coaster)
  1024. {
  1025.     RwForAllClumpsInScenePointer(coaster->scene, (RwClumpFuncPointer)ShowControlPoint, coaster);
  1026.     RwForAllClumpsInScenePointer(coaster->holdingScene, (RwClumpFuncPointer)ShowControlPoint, coaster);
  1027. }
  1028.  
  1029. /**********************************************************************/
  1030.  
  1031. void
  1032. DisableCoasterControlPoints(RollerCoasterType *coaster)
  1033. {
  1034.     RwForAllClumpsInScenePointer(coaster->holdingScene, (RwClumpFuncPointer)HideControlPoint, coaster);
  1035.     RwForAllClumpsInScenePointer(coaster->scene, (RwClumpFuncPointer)HideControlPoint, coaster);
  1036. }
  1037.  
  1038. /**********************************************************************/
  1039.  
  1040. /**********************************************************************
  1041.  *
  1042.  * End of file.
  1043.  *
  1044.  **********************************************************************/
  1045.