]> git.tdb.fi Git - r2c2.git/blob - source/3d/tracktype.cpp
Make use of the geometry part of libmspmath
[r2c2.git] / source / 3d / tracktype.cpp
1 #include <algorithm>
2 #include <cmath>
3 #include <msp/gl/technique.h>
4 #include "catalogue.h"
5 #include "tracktype.h"
6
7 using namespace std;
8 using namespace Msp;
9
10 namespace R2C2 {
11
12 TrackType3D::TrackType3D(Catalogue3D &cat3d, const TrackType &tt):
13         catalogue(cat3d),
14         mesh(0),
15         object(0)
16 {
17         const Catalogue &cat = cat3d.get_catalogue();
18         const vector<TrackPart> &parts = tt.get_parts();
19
20         const Profile &ballast_profile = cat.get_ballast_profile();
21         const Vector &ballast_min = ballast_profile.get_min_coords();
22         const Vector &ballast_max = ballast_profile.get_max_coords();
23         float ballast_h = ballast_max.y-ballast_min.y;
24
25         const Profile &rail_profile = cat.get_rail_profile();
26         const Vector &rail_min = rail_profile.get_min_coords();
27         const Vector &rail_max = rail_profile.get_max_coords();
28         float rail_h = rail_max.y-rail_min.y;
29
30         float gauge = cat.get_gauge();
31
32         string obj_name = tt.get_object();
33         if(!obj_name.empty())
34                 object = &catalogue.get<GL::Object>(obj_name);
35         else
36         {
37                 mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
38                 mesh->set_winding(&GL::WindingTest::counterclockwise());
39                 GL::MeshBuilder bld(*mesh);
40
41                 unsigned index = 0;
42                 bld.texcoord(0.25, 0.5);
43                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
44                         build_part(*i, ballast_profile, Vector(0, -ballast_min.y, 0), false, bld, index);
45
46                 bld.texcoord(0.75, 0.5);
47                 float y = ballast_h-rail_min.y;
48                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
49                         build_part(*i, rail_profile, Vector(0, gauge/2, y), true, bld, index);
50                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
51                         build_part(*i, rail_profile, Vector(0, -gauge/2, y), false, bld, index);
52
53                 object = new GL::Object;
54                 object->set_mesh(mesh);
55                 object->set_technique(&catalogue.get<GL::Technique>(cat.get_track_technique()));
56         }
57  
58         unsigned paths = tt.get_paths();
59         for(unsigned i=0; paths; ++i, paths>>=1)
60         {
61                 GL::Mesh *m = 0;
62                 if(paths&1)
63                 {
64                         m = new GL::Mesh(GL::VERTEX3);
65                         GL::MeshBuilder bld(*m);
66                         unsigned index = 0;
67                         for(vector<TrackPart>::const_iterator j=parts.begin(); j!=parts.end(); ++j)
68                                 if(j->get_path()==i)
69                                         build_part(*j, cat.get_path_profile(), Vector(0, 0, ballast_h+1.5*rail_h), false, bld, index);
70                 }
71                 path_meshes.push_back(m);
72         }
73 }
74
75 TrackType3D::~TrackType3D()
76 {
77         for(vector<GL::Mesh *>::iterator i=path_meshes.begin(); i!=path_meshes.end(); ++i)
78                 delete *i;
79 }
80
81 const GL::Mesh &TrackType3D::get_path_mesh(unsigned p) const
82 {
83         if(p>=path_meshes.size())
84                 throw out_of_range("TrackType3D::get_path_mesh");
85         if(!path_meshes[p])
86                 throw invalid_argument("TrackType3D::get_path_mesh");
87         return *path_meshes[p];
88 }
89
90 void TrackType3D::build_part(const TrackPart &part, const Profile &profile, const Vector &offset, bool mirror, GL::MeshBuilder &bld, unsigned &base_index)
91 {
92         float plen = part.get_length();
93         unsigned nsegs = (part.is_curved() ? static_cast<unsigned>(plen*32)+1 : 1);
94
95         unsigned n_vertices = profile.get_n_vertices();
96         for(unsigned i=0; i<=nsegs; ++i)
97         {
98                 TrackPoint basep = part.get_point(i*plen/nsegs);
99                 Transform trans = Transform::rotation(basep.dir, Vector(0, 0, 1));
100
101                 for(unsigned j=0; j<n_vertices; ++j)
102                 {
103                         const Profile::Vertex &v = profile.get_vertex(mirror ? n_vertices-1-j : j);
104                         Vector p(0, -v.pos.x, v.pos.y);
105                         if(mirror)
106                                 p.y = -p.y;
107                         p = basep.pos+trans.transform(offset+p);
108
109                         Vector n(0, -v.normal.x, v.normal.y);
110                         if(mirror)
111                                 n.y = -n.y;
112                         n = trans.transform(n);
113
114                         bld.normal(n.x, n.y, n.z);
115                         bld.vertex(p.x, p.y, p.z);
116                 }
117         }
118
119         for(unsigned i=0; i+1<n_vertices; )
120         {
121                 bld.begin(GL::TRIANGLE_STRIP);
122                 for(unsigned j=0; j<=nsegs; ++j)
123                 {
124                         unsigned k = j*n_vertices+i;
125                         bld.element(base_index+k+1);
126                         bld.element(base_index+k);
127                 }
128                 bld.end();
129
130                 ++i;
131                 if(!profile.get_vertex(i).smooth)
132                         ++i;
133         }
134
135         base_index += (nsegs+1)*n_vertices;
136 }
137
138 } // namespace R2C2