home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 February / Chip_2001-02_cd1.bin / bonus / demos / CS / exp / SOURCES / DEMO / vlacik2.h < prev    next >
C/C++ Source or Header  |  2000-08-11  |  24KB  |  824 lines

  1. #ifndef _vlacik2_H
  2. #define _vlacik2_H
  3.  
  4. #define unit_length 100.0
  5. #define straight_line_max (unit_length/5.0)
  6. #define rail_spacing 10.0
  7. #define rail_size 1.4
  8. #define tube_sides 9
  9. #define tube_radius (rail_spacing/2.0+12.0)
  10. #define rail_tube_spacing 6.0
  11.  
  12. //  Sorts of tracks
  13.  
  14. #define STRAIGHT                1
  15. #define HALFTURN_RIGHT          2
  16. #define QUARTERTURN_RIGHT       3
  17. #define UTURN_RIGHT             4
  18. #define HALFTURN_LEFT           5
  19. #define QUARTERTURN_LEFT        6
  20. #define UTURN_LEFT              7
  21. #define HALFTURN_UP             8
  22. #define QUARTERTURN_UP            9
  23. #define UTURN_UP                10
  24. #define HALFTURN_DOWN           11
  25. #define QUARTERTURN_DOWN        12
  26. #define UTURN_DOWN              13
  27. #define ASCEND                  14
  28. #define DESCEND                 15
  29. #define ASCEND_LOW              16
  30. #define DESCEND_LOW             17
  31. #define ASCEND_HIGH             18
  32. #define DESCEND_HIGH            19
  33. #define FULLWHIRL               20
  34. #define FULLWHIRL_CLOCKWISE     21
  35. #define HALFWHIRL               22
  36. #define HALFWHIRL_CLOCKWISE     23
  37. #define DOUBLEWHIRL             24
  38. #define DOUBLEWHIRL_CLOCKWISE   25
  39. #define LOOPING                 26
  40.  
  41. //  Construction style flags
  42.  
  43. #define HAS_TUBE    1
  44.  
  45.  
  46. struct track_base
  47. {
  48.   static Material3DS* rail_material;
  49.   static Material3DS* tube_material;
  50.   unsigned long flag;
  51.  
  52.   GLmatrix_double cs;
  53.   quaternion<double> qcs;
  54.  
  55.   track_base() {
  56.     cs.Identity();
  57.     qcs = quaternion<double> (1.0, 0.0, 0.0, 0.0);
  58.     flag = 0;
  59.   }
  60.   void CS(const GLmatrix_double& m) {
  61.     cs=m;
  62.   };
  63.   void QCS(const quaternion<double>& q) {
  64.     qcs = q;
  65.   };
  66.  
  67.   virtual double length() = 0;
  68.   virtual Vector3d position(double t) = 0;
  69.   virtual Vector3d direction(double t) = 0;
  70.   virtual Vector3d udirection(double t) = 0;
  71.   virtual double roll(double t) = 0;
  72.   virtual quaternion<double> local_orientation(double t) = 0;
  73.   virtual RenderableEntityA* rails() = 0;
  74.  
  75.   void normalize(Vector3d &u) {
  76.     double l = 1.0/sqrt(u.x*u.x + u.y*u.y + u.z+u.z);
  77.     u.x*=l; u.y*=l; u.z*=l;
  78.   }
  79.   GLmatrix_double answer_cs(const Vector3d &p, const Vector3d &d, const Vector3d &ud, double r) {
  80.     Vector3d n, u, v, a,b;
  81.     n=d;
  82.     u=ud;
  83.     v.x=-(u.y*n.z-u.z*n.y);
  84.     v.y=-(u.z*n.x-u.x*n.z);
  85.     v.z=-(u.x*n.y-u.y*n.x);
  86.     double s = sin(r);
  87.     double c = cos(r);
  88.     a = c*u + s*v;
  89.     b = -s*u + c*v;
  90.     GLmatrix_double m;
  91.     m[0]=a.x; m[4]=b.x; m[8]= n.x; m[12]=p.x;
  92.     m[1]=a.y; m[5]=b.y; m[9]= n.y; m[13]=p.y;
  93.     m[2]=a.z; m[6]=b.z; m[10]=n.z; m[14]=p.z;
  94.     m[3]=0.0; m[7]=0.0; m[11]=0.0; m[15]=1.0;
  95.     return m;
  96.   }
  97.   virtual GLmatrix_double coordinate_system(double t) {
  98.     return cs*answer_cs(position(t), direction(t), udirection(t), roll(t));
  99.   }
  100.   virtual quaternion<double> orientation(double t) {
  101.     return qcs*local_orientation(t);
  102.   }
  103.  
  104.   virtual RenderableEntityA* tube() {
  105.     if(!(flag&HAS_TUBE))
  106.       return 0;
  107.     GLmatrix_double m;
  108.     double d = rail_spacing/2.0;
  109.     int parts = (int)(length()/straight_line_max)+1;
  110.     Vector3d P, X, Y, V, H, N;
  111.     Vertex3DS* v = new Vertex3DS[tube_sides*(parts+1)];
  112.  
  113.     GLuint i = 0;
  114.  
  115.     for(int q=0; q<=parts; q++) {
  116.       m = coordinate_system((double)q/(double)parts);
  117.       P.x = m[12]; P.y = m[13]; P.z = m[14];
  118.       X.x = m[0]; X.y = m[1]; X.z = m[2];
  119.       Y.x = m[4]; Y.y = m[5]; Y.z = m[6];
  120.       H = Y*sqrt(tube_radius*tube_radius - (d+rail_tube_spacing)*(d+rail_tube_spacing));
  121.  
  122.       for(int k=0; k<tube_sides; k++) {
  123.         double a = ((2*PI)/(double)tube_sides)*k;
  124.         N = X*cos(a) + Y*sin(a);
  125.         V = P + H + tube_radius*N;
  126.         v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  127.         v[i].i = N.x; v[i].j = N.y; v[i].k = N.z;
  128.         v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  129.         v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  130.         i++;
  131.       }
  132.     }
  133.  
  134.     RenderableEntityA* obj = new RenderableEntityA;
  135.     obj->SetMaterial(tube_material);
  136.     obj->Vertices(tube_sides*(parts+1), v);
  137.  
  138.     int isize = (parts+1)<<1;
  139.     GLuint* ind[tube_sides];
  140.     for(int k=0; k<tube_sides; k++)
  141.       ind[k] = new GLuint[isize];
  142.  
  143.     i = 0; int j = 0;
  144.     for(int q=0; q<=parts; q++, i+=tube_sides, j+=2) {
  145.       for(int k=0; k<tube_sides; k++) {
  146.         *(ind[k]+j) = i+k;
  147.         *(ind[k]+j+1) = i+((k+1)%tube_sides);
  148.       }
  149.     }
  150.  
  151.     for(int k=0; k<tube_sides; k++)
  152.       obj->AddElement(GL_TRIANGLE_STRIP, isize, ind[k]);
  153.  
  154.     return obj;
  155.   }
  156. };
  157.  
  158. // initialization of static data
  159.  
  160. Material3DS* track_base::rail_material = 0;
  161. Material3DS* track_base::tube_material = 0;
  162.  
  163. // STRAIGHT
  164.  
  165. struct straight_track : public track_base
  166. {
  167.   double len;
  168.   void Length(double f) { len=f; }
  169.   virtual double length() { return len; }
  170.  
  171.   virtual Vector3d position(double t) {
  172.     return Vector3d(0.0, 0.0, t*len);
  173.   }
  174.   virtual Vector3d direction(double t) {
  175.     return Vector3d(0.0, 0.0, 1.0);
  176.   }
  177.   virtual Vector3d udirection(double t) {
  178.     return Vector3d(1.0, 0.0, 0.0);
  179.   }
  180.   virtual double roll(double t) {
  181.     return 0;
  182.   }
  183.   virtual quaternion<double> local_orientation(double t) {
  184.     return quaternion<double> (1.0, 0.0, 0.0, 0.0);
  185.   }
  186.   virtual RenderableEntityA* rails() {
  187.     GLmatrix_double m;
  188.     double d = rail_spacing/2.0;
  189.     int parts = 1;
  190.     Vector3d P, X, Y, V;
  191.     Vertex3DS* v = new Vertex3DS[6*(parts+1)];
  192.  
  193.     GLuint i = 0;
  194.  
  195.     for(int q=0; q<=parts; q++) {
  196.       m = coordinate_system((double)q/(double)parts);
  197.       P.x = m[12]; P.y = m[13]; P.z = m[14];
  198.       X.x = m[0]; X.y = m[1]; X.z = m[2];
  199.       Y.x = m[4]; Y.y = m[5]; Y.z = m[6];
  200.  
  201.       V = P - X*(d + rail_size*0.5);
  202.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  203.       v[i].i = -X.x; v[i].j = -X.y; v[i].k = -X.z;
  204.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  205.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  206.       i++;
  207.       V = P - X*(d - rail_size*0.5);
  208.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  209.       v[i].i = X.x; v[i].j = X.y; v[i].k = X.z;
  210.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  211.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  212.       i++;
  213.       V = P - X*d + Y*rail_size;
  214.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  215.       v[i].i = Y.x; v[i].j = Y.y; v[i].k = Y.z;
  216.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  217.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  218.       i++;
  219.  
  220.       V = P + X*(d - rail_size*0.5);
  221.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  222.       v[i].i = -X.x; v[i].j = -X.y; v[i].k = -X.z;
  223.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  224.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  225.       i++;
  226.       V = P + X*(d + rail_size*0.5);
  227.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  228.       v[i].i = X.x; v[i].j = X.y; v[i].k = X.z;
  229.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  230.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  231.       i++;
  232.       V = P + X*d + Y*rail_size;
  233.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  234.       v[i].i = Y.x; v[i].j = Y.y; v[i].k = Y.z;
  235.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  236.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  237.       i++;
  238.     }
  239.  
  240.     RenderableEntityA* obj = new RenderableEntityA;
  241.     obj->SetMaterial(rail_material);
  242.     obj->Vertices(6*(parts+1), v);
  243.     int isize = (parts+1)<<1;
  244.     GLuint* ind1 = new GLuint[isize];
  245.     GLuint* ind2 = new GLuint[isize];
  246.     GLuint* ind3 = new GLuint[isize];
  247.     GLuint* ind4 = new GLuint[isize];
  248.     GLuint* ind5 = new GLuint[isize];
  249.     GLuint* ind6 = new GLuint[isize];
  250.  
  251.     i = 0; int j = 0;
  252.     for(int q=0; q<=parts; q++, i+=6, j+=2) {
  253.       ind1[j] = i;
  254.       ind1[j+1] = i+1;
  255.  
  256.       ind2[j] = i+1;
  257.       ind2[j+1] = i+2;
  258.  
  259.       ind3[j] = i+2;
  260.       ind3[j+1] = i;
  261.  
  262.       ind4[j] = i+3;
  263.       ind4[j+1] = i+4;
  264.  
  265.       ind5[j] = i+4;
  266.       ind5[j+1] = i+5;
  267.  
  268.       ind6[j] = i+5;
  269.       ind6[j+1] = i+3;
  270.     }
  271.  
  272.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind1);
  273.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind2);
  274.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind3);
  275.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind4);
  276.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind5);
  277.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind6);
  278.  
  279.     return obj;
  280.   }
  281.   
  282. };
  283.  
  284. // curved base
  285.  
  286. struct track_base_curved : public track_base
  287. {
  288.   virtual RenderableEntityA* rails() {
  289.     GLmatrix_double m;
  290.     double d = rail_spacing/2.0;
  291.     int parts = (int)(length()/straight_line_max)+1;
  292.     Vector3d P, X, Y, V;
  293.     Vertex3DS* v = new Vertex3DS[6*(parts+1)];
  294.  
  295.     GLuint i = 0;
  296.  
  297.     for(int q=0; q<=parts; q++) {
  298.       m = coordinate_system((double)q/(double)parts);
  299.       P.x = m[12]; P.y = m[13]; P.z = m[14];
  300.       X.x = m[0]; X.y = m[1]; X.z = m[2];
  301.       Y.x = m[4]; Y.y = m[5]; Y.z = m[6];
  302.  
  303.       V = P - X*(d + rail_size*0.5);
  304.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  305.       v[i].i = -X.x; v[i].j = -X.y; v[i].k = -X.z;
  306.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  307.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  308.       i++;
  309.       V = P - X*(d - rail_size*0.5);
  310.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  311.       v[i].i = X.x; v[i].j = X.y; v[i].k = X.z;
  312.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  313.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  314.       i++;
  315.       V = P - X*d + Y*rail_size;
  316.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  317.       v[i].i = Y.x; v[i].j = Y.y; v[i].k = Y.z;
  318.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  319.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  320.       i++;
  321.   
  322.       V = P + X*(d - rail_size*0.5);
  323.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  324.       v[i].i = -X.x; v[i].j = -X.y; v[i].k = -X.z;
  325.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  326.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  327.       i++;
  328.       V = P + X*(d + rail_size*0.5);
  329.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  330.       v[i].i = X.x; v[i].j = X.y; v[i].k = X.z;
  331.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  332.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  333.       i++;
  334.       V = P + X*d + Y*rail_size;
  335.       v[i].x = V.x; v[i].y = V.y; v[i].z = V.z; v[i].w = 1.0F;
  336.       v[i].i = Y.x; v[i].j = Y.y; v[i].k = Y.z;
  337.       v[i].R = v[i].G = v[i].B = v[i].A = 1.0F;
  338.       v[i].s = v[i].t = v[i].r = 0.0F; v[i].q = 1.0F;
  339.       i++;
  340.     }
  341.  
  342.     RenderableEntityA* obj = new RenderableEntityA;
  343.     obj->SetMaterial(rail_material);
  344.     obj->Vertices(6*(parts+1), v);
  345.     int isize = (parts+1)<<1;
  346.     GLuint* ind1 = new GLuint[isize];
  347.     GLuint* ind2 = new GLuint[isize];
  348.     GLuint* ind3 = new GLuint[isize];
  349.     GLuint* ind4 = new GLuint[isize];
  350.     GLuint* ind5 = new GLuint[isize];
  351.     GLuint* ind6 = new GLuint[isize];
  352.  
  353.     i = 0; int j = 0;
  354.     for(int q=0; q<=parts; q++, i+=6, j+=2) {
  355.       ind1[j] = i;
  356.       ind1[j+1] = i+1;
  357.  
  358.       ind2[j] = i+1;
  359.       ind2[j+1] = i+2;
  360.  
  361.       ind3[j] = i+2;
  362.       ind3[j+1] = i;
  363.  
  364.       ind4[j] = i+3;
  365.       ind4[j+1] = i+4;
  366.  
  367.       ind5[j] = i+4;
  368.       ind5[j+1] = i+5;
  369.  
  370.       ind6[j] = i+5;
  371.       ind6[j+1] = i+3;
  372.     }
  373.  
  374.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind1);
  375.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind2);
  376.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind3);
  377.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind4);
  378.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind5);
  379.     obj->AddElement(GL_TRIANGLE_STRIP, isize, ind6);
  380.  
  381.     return obj;
  382.   }
  383. };
  384.  
  385. // circular base
  386.  
  387. struct circular_track : public track_base_curved
  388. {
  389.   double a, b;
  390.   double radius;
  391.   double clk;
  392.   circular_track() : a(0), b(0), radius(0), clk(1) {}
  393.   void A(double f) { a=f; }
  394.   void B(double f) { b=f; }
  395.   void Radius(double f) { radius=f; }
  396.   void Clk(double f) { clk=f; }
  397.   virtual double length() { return radius*fabs(a-b); }
  398. };
  399.  
  400. // HORIZONTAL
  401.  
  402. struct turn_track_horizontal : public circular_track
  403. {
  404.   virtual Vector3d position(double t) {
  405.     double tt = a + t*(b-a);
  406.     return Vector3d(radius*(cos(tt)-cos(a)),
  407.                     0.0,
  408.                     radius*(sin(tt)-sin(a)));
  409.   }
  410.   virtual Vector3d direction(double t) {
  411.     double tt = a + t*(b-a);
  412.     return Vector3d(-sin(tt)*clk, 0.0, cos(tt)*clk);
  413.   }
  414.   virtual Vector3d udirection(double t) {
  415.     double tt = a + t*(b-a);
  416.     return Vector3d(cos(tt)*clk, 0.0, sin(tt)*clk);
  417.   }
  418.   virtual quaternion<double> local_orientation(double t) {
  419.     return AngleAxis2Quaternion(-t*(b-a), 0.0, 1.0, 0.0);
  420.   }
  421.   virtual double roll(double t) {
  422.     return 0;
  423.   }
  424. };
  425.  
  426. struct halfturn_left : public turn_track_horizontal {
  427.   halfturn_left() { a=PI; b=PI/2.0; clk=-1.0; }
  428. };
  429. struct quarterturn_left : public turn_track_horizontal {
  430.   quarterturn_left() { a=PI; b=(3*PI)/4.0; clk=-1.0; }
  431. };
  432. struct uturn_left : public turn_track_horizontal {
  433.   uturn_left() { a=PI; b=0.0; clk=-1.0; }
  434. };
  435.  
  436. struct halfturn_right : public turn_track_horizontal {
  437.   halfturn_right() { a=0.0; b=PI/2.0; clk=1.0; }
  438. };
  439. struct quarterturn_right : public turn_track_horizontal {
  440.   quarterturn_right() { a=0.0; b=PI/4.0; clk=1.0; } 
  441. };
  442. struct uturn_right : public turn_track_horizontal {
  443.   uturn_right() { a=0.0; b=PI; clk=1.0; }
  444. };
  445.  
  446. // VERTICAL
  447.  
  448. struct turn_track_vertical : public circular_track
  449. {
  450.   virtual Vector3d position(double t) {
  451.     double tt = a + t*(b-a);
  452.     return Vector3d(0.0,
  453.                     radius*(sin(tt)-sin(a)),
  454.                     radius*(cos(tt)-cos(a)));
  455.   }
  456.   virtual Vector3d direction(double t) {
  457.     double tt = a + t*(b-a);
  458.     return Vector3d(0.0, cos(tt)*clk, -sin(tt)*clk);
  459.   }
  460.   virtual Vector3d udirection(double t) {
  461.     double tt = a + t*(b-a);
  462.     return Vector3d(1.0, 0.0, 0.0);
  463.   }
  464.   virtual double roll(double t) {
  465.     return 0;
  466.   }
  467.   virtual quaternion<double> local_orientation(double t) {
  468.     return AngleAxis2Quaternion(-t*(b-a), 1.0, 0.0, 0.0);
  469.   }
  470. };
  471.  
  472. struct ascend : public turn_track_vertical {
  473.   ascend() { a=(3*PI)/2.0; b=(7*PI)/4.0; clk=1.0; } 
  474. };
  475. struct descend : public turn_track_vertical {
  476.   descend() { a=PI/2.0; b=PI/4.0; clk=-1.0; }
  477. };
  478. struct ascend_low : public turn_track_vertical {
  479.   ascend_low() { a=(3*PI)/2.0; b=(5*PI)/3.0; clk=1.0; } 
  480. };
  481. struct descend_low : public turn_track_vertical {
  482.   descend_low() { a=PI/2.0; b=PI/3.0; clk=-1.0; }
  483. };
  484. struct ascend_high : public turn_track_vertical {
  485.   ascend_high() { a=(3*PI)/2.0; b=(11*PI)/6.0; clk=1.0; } 
  486. };
  487. struct descend_high : public turn_track_vertical {
  488.   descend_high() { a=PI/2.0; b=PI/6.0; clk=-1.0; }
  489. };
  490.  
  491. struct halfturn_down : public turn_track_vertical {
  492.   halfturn_down() { a=PI/2.0; b=0.0; clk=-1.0; }
  493. };
  494. struct quarterturn_down : public turn_track_vertical {
  495.   quarterturn_down() { a=PI/2.0; b=PI/4.0; clk=-1.0; }
  496. };
  497. struct uturn_down : public turn_track_vertical {
  498.   uturn_down() { a=PI/2.0; b=-PI/2.0; clk=-1.0; }
  499. };
  500.  
  501. struct halfturn_up : public turn_track_vertical {
  502.   halfturn_up() { a=(3*PI)/2.0; b=2*PI; clk=1.0; }
  503. };
  504. struct quarterturn_up : public turn_track_vertical {
  505.   quarterturn_up() { a=(3*PI)/2.0; b=(7*PI)/4.0; clk=1.0; } 
  506. };
  507. struct uturn_up : public turn_track_vertical {
  508.   uturn_up() { a=(3*PI)/2.0; b=(5*PI)/2; clk=1.0; }
  509. };
  510.  
  511. // LOOPINGS
  512.  
  513. struct loopings : public circular_track
  514. {
  515.   virtual Vector3d position(double t) {
  516.     Vector3d v;
  517.     double tt = a + t*(b-a);
  518.     v.x = (rail_spacing)*sin(t*PI/2.0)*sin(t*PI/2.0);
  519.     v.y = radius*(sin(tt)-sin(a));
  520.     v.z = radius*(cos(tt)-cos(a));
  521.     return v;
  522.   }
  523.   virtual Vector3d direction(double t) {
  524.     double tt = a + t*(b-a);
  525.     return Vector3d(0.0, cos(tt)*clk, -sin(tt)*clk);
  526.   }
  527.   virtual Vector3d udirection(double t) {
  528.     return Vector3d(1.0, 0.0, 0.0);
  529.   }
  530.   virtual double roll(double t) {
  531.     return 0;
  532.   }
  533.   virtual quaternion<double> local_orientation(double t) {
  534.     return AngleAxis2Quaternion(-t*(b-a), 1.0, 0.0, 0.0);
  535.   }
  536. };
  537.  
  538. struct looping : public loopings {
  539.   looping() { a=(3*PI)/2.0; b=(7*PI)/2.0; clk=1.0; }
  540. };
  541.  
  542.  
  543. // WHIRL
  544.  
  545. struct whirl_track : public track_base_curved
  546. {
  547.   double len;
  548.   double a;
  549.   double clk;
  550.   whirl_track() : a(0), len(0), clk(1) {}
  551.   void Degree(double f) { a=f; }
  552.   void Length(double f) { len=f; }
  553.   void Clk(double f) { clk=f; }
  554.   virtual double length() { return len; }
  555.   virtual Vector3d position(double t) {
  556.     return Vector3d(0.0, 0.0, t*len);
  557.   }
  558.   virtual Vector3d direction(double t) {
  559.     return Vector3d(0.0, 0.0, 1.0);
  560.   }
  561.   virtual Vector3d udirection(double t) {
  562.     return Vector3d(1.0, 0.0, 0.0);
  563.   }
  564.   virtual double roll(double t) {
  565.     return clk*sin(t*PI/2.0)*sin(t*PI/2.0)*a;
  566.   }
  567.   virtual quaternion<double> local_orientation(double t) {
  568.     return AngleAxis2Quaternion(roll(t), 0.0, 0.0, 1.0);
  569.   }
  570.  
  571. };
  572.  
  573. struct fullwhirl : public whirl_track {
  574.   fullwhirl() { a=2*PI; clk=1.0; }
  575. };
  576. struct fullwhirl_clockwise : public whirl_track {
  577.   fullwhirl_clockwise() { a=2*PI; clk=-1.0; }
  578. };
  579. struct halfwhirl : public whirl_track {
  580.   halfwhirl() { a=PI; clk=1.0; }
  581. };  
  582. struct halfwhirl_clockwise : public whirl_track {
  583.   halfwhirl_clockwise() { a=PI; clk=-1.0; }
  584. };  
  585. struct doublewhirl : public whirl_track {
  586.   doublewhirl() { a=4*PI; clk=1.0; }
  587. };
  588. struct doublewhirl_clockwise : public whirl_track {
  589.   doublewhirl_clockwise() { a=4*PI; clk=-1.0; }
  590. };
  591.  
  592. struct train_track_desc
  593. {
  594.   int type;
  595.   double arg1;
  596.   double arg2;
  597.   unsigned long f;
  598. };
  599.  
  600. class train_track
  601.   List<track_base *> parts;
  602.   RenderableEntities *construction;
  603.  
  604.   struct track_info
  605.   {
  606.     double length;
  607.     double before;
  608.     track_base *track;
  609.   };
  610.  
  611.   int n_tracks;
  612.   int tid;
  613.   double track_length;
  614.   track_info *info;
  615.  
  616.   void join_tracks() {
  617.     track_base *ptrack;
  618.     GLmatrix_double m;
  619.     m.Identity();
  620.     quaternion<double> q(1.0, 0.0, 0.0, 0.0);
  621.     parts.rewind();
  622.     for(int i=parts.size(); i; i--) {
  623.       ptrack = *parts;
  624.       ptrack->CS(m);
  625.       ptrack->QCS(q);
  626.       m = ptrack->coordinate_system(1.0);
  627.       q = ptrack->orientation(1.0);
  628.       ++parts;
  629.     }
  630.   }
  631. public:
  632.   train_track() : construction(0) {}
  633.  
  634.   double length() { return track_length; }
  635.  
  636.   void AddTrack(track_base *p) {
  637.     if(p) parts.push_back(p);
  638.   }
  639.   void operator +=(track_base *p) {
  640.     if(p) parts.push_back(p);
  641.   }
  642.  
  643.   void AddTrack(int type, double arg1, double arg2, unsigned long flag) {
  644.     track_base *p = 0;
  645.     switch(type) {
  646.       case STRAIGHT:
  647.         p = new straight_track;
  648.         (*(straight_track *)p).Length(arg1);
  649.         break;
  650.       case HALFTURN_RIGHT:
  651.         p = new halfturn_right;
  652.         (*(halfturn_right *)p).Radius(arg1);
  653.         break;
  654.       case QUARTERTURN_RIGHT:
  655.         p = new quarterturn_right;
  656.         (*(quarterturn_right *)p).Radius(arg1);
  657.         break;
  658.       case UTURN_RIGHT:
  659.         p = new uturn_right;
  660.         (*(uturn_right *)p).Radius(arg1);
  661.         break;
  662.       case HALFTURN_LEFT:
  663.         p = new halfturn_left;
  664.         (*(halfturn_left *)p).Radius(arg1);
  665.         break;
  666.       case QUARTERTURN_LEFT:
  667.         p = new quarterturn_left;
  668.         (*(quarterturn_left *)p).Radius(arg1);
  669.         break;
  670.       case UTURN_LEFT:
  671.         p = new uturn_left;
  672.         (*(uturn_left *)p).Radius(arg1);
  673.         break;
  674.       case HALFTURN_UP:
  675.         p = new halfturn_up;
  676.         (*(halfturn_up *)p).Radius(arg1);
  677.         break;
  678.       case QUARTERTURN_UP:
  679.         p = new quarterturn_up;
  680.         (*(quarterturn_up *)p).Radius(arg1);
  681.         break;
  682.       case UTURN_UP:
  683.         p = new uturn_up;
  684.         (*(uturn_up *)p).Radius(arg1);
  685.         break;
  686.       case HALFTURN_DOWN:
  687.         p = new halfturn_down;
  688.         (*(halfturn_down *)p).Radius(arg1);
  689.         break;
  690.       case QUARTERTURN_DOWN:
  691.         p = new quarterturn_down;
  692.         (*(quarterturn_down *)p).Radius(arg1);
  693.         break;
  694.       case UTURN_DOWN:
  695.         p = new uturn_down;
  696.         (*(uturn_down *)p).Radius(arg1);
  697.         break;
  698.       case ASCEND:
  699.         p = new ascend;
  700.         (*(ascend *)p).Radius(arg1);
  701.         break;
  702.       case DESCEND:
  703.         p = new descend;
  704.         (*(descend *)p).Radius(arg1);
  705.         break;
  706.       case ASCEND_HIGH:
  707.         p = new ascend_high;
  708.         (*(ascend_high *)p).Radius(arg1);
  709.         break;
  710.       case DESCEND_HIGH:
  711.         p = new descend_high;
  712.         (*(descend_high *)p).Radius(arg1);
  713.         break;
  714.       case ASCEND_LOW:
  715.         p = new ascend_low;
  716.         (*(ascend_low *)p).Radius(arg1);
  717.         break;
  718.       case DESCEND_LOW:
  719.         p = new descend_low;
  720.         (*(descend_low *)p).Radius(arg1);
  721.         break;
  722.       case FULLWHIRL:
  723.         p = new fullwhirl;
  724.         (*(fullwhirl *)p).Length(arg1);
  725.         break;
  726.       case FULLWHIRL_CLOCKWISE:
  727.         p = new fullwhirl_clockwise;
  728.         (*(fullwhirl_clockwise *)p).Length(arg1);
  729.         break;
  730.       case HALFWHIRL:
  731.         p = new halfwhirl;
  732.         (*(halfwhirl *)p).Length(arg1);
  733.         break;
  734.       case HALFWHIRL_CLOCKWISE:
  735.         p = new halfwhirl_clockwise;
  736.         (*(halfwhirl_clockwise *)p).Length(arg1);
  737.         break;
  738.       case DOUBLEWHIRL:
  739.         p = new doublewhirl;
  740.         (*(doublewhirl *)p).Length(arg1);
  741.         break;
  742.       case DOUBLEWHIRL_CLOCKWISE:
  743.         p = new doublewhirl_clockwise;
  744.         (*(doublewhirl_clockwise *)p).Length(arg1);
  745.         break;
  746.       case LOOPING:
  747.         p = new looping;
  748.         (*(looping *)p).Radius(arg1);
  749.         break;
  750.       default:
  751.         return;
  752.     }
  753.     p->flag = flag;
  754.     AddTrack(p);
  755.   }
  756.  
  757.   RenderableEntities* Construct() {
  758.     if(construction)
  759.       return construction;
  760.     construction = new RenderableEntities;
  761.     if(parts.size()==0)
  762.       return construction;
  763.  
  764.     RenderableEntities tubes;
  765.     join_tracks();
  766.     info = new track_info[parts.size()];
  767.     n_tracks = parts.size();
  768.     tid = 0;
  769.     track_length = 0;
  770.     track_base *ptrack;
  771.     double l = 0;
  772.     parts.rewind();
  773.     for(int i=0; i<parts.size(); i++) {
  774.       ptrack = *parts;
  775.       construction->Add(ptrack->rails());
  776.       tubes.Add(ptrack->tube());
  777.       info[i].track = ptrack;
  778.       info[i].length = ptrack->length();
  779.       info[i].before = track_length;
  780.       track_length+=ptrack->length();
  781.       ++parts;
  782.     }
  783.     construction->Add(tubes);
  784.     return construction;
  785.   }
  786.  
  787.   RenderableEntities* Construct(int n, train_track_desc *desc) {
  788.     for(int i=n; i; i--, desc++)
  789.       AddTrack(desc->type, desc->arg1, desc->arg2, desc->f);
  790.     return Construct();
  791.   }
  792.  
  793.   GLmatrix coordinate_system(double len) {
  794.     double l = len - floor(len/track_length)*track_length;
  795.     while(l<info[tid].before||l>(info[tid].before+info[tid].length)) 
  796.       if(l<info[tid].before) tid--;
  797.       else tid++;
  798.     l = (l-info[tid].before)/info[tid].length; // scale to <0,1>
  799.     GLmatrix_double q = (info[tid].track)->coordinate_system(l);
  800.     GLmatrix m;
  801.     for(int i=0; i<16; i++)
  802.       m[i] = (GLfloat)q[i];
  803.     return m;
  804.   }
  805.   quaternion<float> orientation(double len) {
  806.     double l = len - floor(len/track_length)*track_length;
  807.     while(l<info[tid].before||l>(info[tid].before+info[tid].length)) 
  808.       if(l<info[tid].before) tid--;
  809.       else tid++;
  810.     l = (l-info[tid].before)/info[tid].length; // scale to <0,1>
  811.     quaternion<double> q = (info[tid].track)->orientation(l);
  812.     return quaternion<float> ((float)re(q), (float)im1(q), (float)im2(q), (float)im3(q));
  813.   }
  814.  
  815.   void Render() {
  816.     if(construction)
  817.       construction->Render();
  818.   }
  819.  
  820. };
  821.  
  822.  
  823. #endif