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