]> git.tdb.fi Git - r2c2.git/blob - source/3d/tracktype.cpp
Get rid of some obsolete #includes
[r2c2.git] / source / 3d / tracktype.cpp
1 #include <algorithm>
2 #include <cmath>
3 #include <msp/gl/technique.h>
4 #include "libr2c2/trackappearance.h"
5 #include "catalogue.h"
6 #include "tracktype.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace R2C2 {
12
13 TrackType3D::TrackType3D(Catalogue3D &c, const TrackType &tt):
14         ObjectType3D(c),
15         mesh(0),
16         object(0),
17         own_data(false)
18 {
19         const TrackAppearance &appearance = tt.get_appearance();
20         const vector<TrackPart> &parts = tt.get_parts();
21
22         const Profile &ballast_profile = appearance.get_ballast_profile();
23         const Vector &ballast_min = ballast_profile.get_min_coords();
24         const Vector &ballast_max = ballast_profile.get_max_coords();
25         float ballast_h = ballast_max.y-ballast_min.y;
26
27         const Profile &rail_profile = appearance.get_rail_profile();
28         const Vector &rail_min = rail_profile.get_min_coords();
29         const Vector &rail_max = rail_profile.get_max_coords();
30         float rail_h = rail_max.y-rail_min.y;
31
32         const Profile &tie_profile = appearance.get_tie_profile();
33         const Vector &tie_min = tie_profile.get_min_coords();
34         const Vector &tie_max = tie_profile.get_max_coords();
35         float tie_h = tie_max.y-tie_min.y;
36
37         float gauge = appearance.get_gauge();
38
39         string obj_name = tt.get_object();
40         if(!obj_name.empty())
41                 object = &catalogue.get<GL::Object>(obj_name);
42         else
43         {
44                 mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
45                 mesh->set_winding(&GL::WindingTest::counterclockwise());
46                 GL::MeshBuilder bld(*mesh);
47
48                 unsigned index = 0;
49                 bld.texcoord(0.17, 0.5);
50                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
51                         build_part(*i, ballast_profile, Vector(0, 0, -ballast_min.y), false, bld, index);
52
53                 float y = ballast_h-tie_min.y;
54                 bld.texcoord(0.83, 0.5);
55                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
56                         build_ties(*i, tie_profile, appearance.get_tie_length(), appearance.get_tie_spacing(), Vector(0, 0, y), bld, index);
57
58                 bld.texcoord(0.5, 0.5);
59                 y = ballast_h+tie_h-rail_min.y;
60                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
61                         build_part(*i, rail_profile, Vector(0, gauge/2, y), true, bld, index);
62                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
63                         build_part(*i, rail_profile, Vector(0, -gauge/2, y), false, bld, index);
64
65                 object = new GL::Object;
66                 object->set_mesh(mesh);
67                 object->set_technique(&catalogue.get<GL::Technique>(appearance.get_technique()));
68
69                 own_data = true;
70         }
71
72         unsigned paths = tt.get_paths();
73         for(int i=-1; i<=1; ++i)
74         {
75                 // TODO Make profile width configurable
76                 Profile profile;
77                 if(i==0)
78                 {
79                         float rail_w = (rail_max.x-rail_min.x)*2;
80                         profile.append_vertex(Vector(rail_w*-0.5, 0, 0), false);
81                         profile.append_vertex(Vector(rail_w*0.5, 0, 0), false);
82                 }
83                 else
84                 {
85                         profile.append_vertex(Vector(i*(gauge*0.5+rail_min.x*2), 0, 0), false);
86                         profile.append_vertex(Vector(i*(gauge*0.5+rail_max.x*2), 0, 0), false);
87                 }
88
89                 // TODO Avoid generating redundant meshes for single-path tracks
90                 for(int j=-1; j<=4; ++j)
91                 {
92                         if(j>=0 && !((paths>>j)&1))
93                                 continue;
94
95                         GL::Mesh *m = new GL::Mesh(GL::VERTEX3);
96                         GL::MeshBuilder bld(*m);
97                         unsigned index = 0;
98                         for(vector<TrackPart>::const_iterator k=parts.begin(); k!=parts.end(); ++k)
99                                 if(j<0 || k->get_path()==static_cast<unsigned>(j))
100                                         build_part(*k, profile, Vector(0, 0, ballast_h+1.5*rail_h), false, bld, index);
101                         path_meshes[(j&0xFF)|((i&3)<<8)] = m;
102                 }
103         }
104 }
105
106 TrackType3D::~TrackType3D()
107 {
108         for(map<unsigned, GL::Mesh *>::iterator i=path_meshes.begin(); i!=path_meshes.end(); ++i)
109                 delete i->second;
110         if(own_data)
111         {
112                 delete object;
113                 delete mesh;
114         }
115 }
116
117 const GL::Mesh &TrackType3D::get_path_mesh(int p, int s) const
118 {
119         unsigned key = (p<0 ? 0xFF : p) | ((s&3)<<8);
120         return *get_item(path_meshes, key);
121 }
122
123 void TrackType3D::build_part(const TrackPart &part, const Profile &profile, const Vector &offset, bool mirror, GL::MeshBuilder &bld, unsigned &base_index)
124 {
125         float plen = part.get_length();
126         unsigned nsegs = (part.is_curved() ? static_cast<unsigned>(plen*32)+1 : 1);
127
128         unsigned n_vertices = profile.get_n_vertices();
129         for(unsigned i=0; i<=nsegs; ++i)
130         {
131                 OrientedPoint basep = part.get_point(i*plen/nsegs);
132                 Transform trans = Transform::rotation(basep.rotation, Vector(0, 0, 1));
133
134                 for(unsigned j=0; j<n_vertices; ++j)
135                 {
136                         const Profile::Vertex &v = profile.get_vertex(mirror ? n_vertices-1-j : j);
137                         Vector p(0, -v.pos.x, v.pos.y);
138                         if(mirror)
139                                 p.y = -p.y;
140                         p = basep.position+trans.transform(offset+p);
141
142                         Vector n(0, -v.normal.x, v.normal.y);
143                         if(mirror)
144                                 n.y = -n.y;
145                         n = trans.transform(n);
146
147                         bld.normal(n.x, n.y, n.z);
148                         bld.vertex(p.x, p.y, p.z);
149                 }
150         }
151
152         for(unsigned i=0; i+1<n_vertices; )
153         {
154                 bld.begin(GL::TRIANGLE_STRIP);
155                 for(unsigned j=0; j<=nsegs; ++j)
156                 {
157                         unsigned k = j*n_vertices+i;
158                         bld.element(base_index+k+1);
159                         bld.element(base_index+k);
160                 }
161                 bld.end();
162
163                 ++i;
164                 if(!profile.get_vertex(i).smooth)
165                         ++i;
166         }
167
168         base_index += (nsegs+1)*n_vertices;
169 }
170
171 void TrackType3D::build_ties(const TrackPart &part, const Profile &profile, float length, float spacing, const Vector &offset, GL::MeshBuilder &bld, unsigned &base_index)
172 {
173         float plen = part.get_length();
174         unsigned count = plen/spacing+0.5;
175
176         unsigned n_vertices = profile.get_n_vertices();
177         float min_y = profile.get_min_coords().y;
178         vector<Vector> cap_vertices;
179         for(unsigned i=0; i+1<n_vertices; )
180         {
181                 const Profile::Vertex &v = profile.get_vertex(i);
182                 if(cap_vertices.size()>=2)
183                 {
184                         if(i+2<n_vertices)
185                                 cap_vertices.push_back(Vector(v.pos.x, min_y, 0));
186                         else
187                                 cap_vertices.push_back(profile.get_vertex(n_vertices-1).pos);
188                 }
189                 cap_vertices.push_back(v.pos);
190
191                 ++i;
192                 if(!profile.get_vertex(i).smooth)
193                         ++i;
194         }
195
196         for(unsigned i=0; i<count; ++i)
197         {
198                 OrientedPoint basep = part.get_point((i+0.5)*plen/count);
199                 Transform trans = Transform::rotation(basep.rotation, Vector(0, 0, 1));
200
201                 unsigned strip = 0;
202                 for(unsigned j=0; j<n_vertices; ++j)
203                 {
204                         const Profile::Vertex &v = profile.get_vertex(j);
205
206                         Vector n = trans.transform(Vector(0, -v.normal.x, v.normal.y));
207                         bld.normal(n.x, n.y, n.z);
208
209                         if(!strip)
210                                 bld.begin(GL::TRIANGLE_STRIP);
211
212                         for(unsigned k=0; k<2; ++k)
213                         {
214                                 Vector p((k-0.5)*length, -v.pos.x, v.pos.y);
215                                 p = basep.position+trans.transform(offset+p);
216                                 bld.vertex(p.x, p.y, p.z);
217                         }
218
219                         if(++strip>=2 && !profile.get_vertex(j).smooth)
220                         {
221                                 bld.end();
222                                 strip = 0;
223                         }
224                 }
225                 if(strip)
226                         bld.end();
227
228                 for(unsigned j=0; j<2; ++j)
229                 {
230                         Vector n = trans.transform(Vector(j*2.0-1, 0, 0));
231                         bld.normal(n.x, n.y, n.z);
232
233                         bld.begin(GL::TRIANGLE_STRIP);
234                         for(unsigned k=0; k<cap_vertices.size(); ++k)
235                         {
236                                 const Vector &v = cap_vertices[k^j];
237                                 Vector p((j-0.5)*length, -v.x, v.y);
238                                 p = basep.position+trans.transform(offset+p);
239                                 bld.vertex(p.x, p.y, p.z);
240                         }
241                         bld.end();
242                 }
243
244                 base_index += 2*(n_vertices+cap_vertices.size());
245         }
246 }
247
248 } // namespace R2C2