]> git.tdb.fi Git - r2c2.git/blob - source/3d/tracktype.cpp
Use generic ObjectTypes in Catalogue
[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 &c, const TrackType &tt):
13         ObjectType3D(c),
14         mesh(0),
15         object(0),
16         own_data(false)
17 {
18         const Catalogue &cat = catalogue.get_catalogue();
19         const vector<TrackPart> &parts = tt.get_parts();
20
21         const Profile &ballast_profile = cat.get_ballast_profile();
22         const Vector &ballast_min = ballast_profile.get_min_coords();
23         const Vector &ballast_max = ballast_profile.get_max_coords();
24         float ballast_h = ballast_max.y-ballast_min.y;
25
26         const Profile &rail_profile = cat.get_rail_profile();
27         const Vector &rail_min = rail_profile.get_min_coords();
28         const Vector &rail_max = rail_profile.get_max_coords();
29         float rail_h = rail_max.y-rail_min.y;
30
31         float gauge = cat.get_gauge();
32
33         string obj_name = tt.get_object();
34         if(!obj_name.empty())
35                 object = &catalogue.get<GL::Object>(obj_name);
36         else
37         {
38                 mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
39                 mesh->set_winding(&GL::WindingTest::counterclockwise());
40                 GL::MeshBuilder bld(*mesh);
41
42                 unsigned index = 0;
43                 bld.texcoord(0.25, 0.5);
44                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
45                         build_part(*i, ballast_profile, Vector(0, -ballast_min.y, 0), false, bld, index);
46
47                 bld.texcoord(0.75, 0.5);
48                 float y = ballast_h-rail_min.y;
49                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
50                         build_part(*i, rail_profile, Vector(0, gauge/2, y), true, bld, index);
51                 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
52                         build_part(*i, rail_profile, Vector(0, -gauge/2, y), false, bld, index);
53
54                 object = new GL::Object;
55                 object->set_mesh(mesh);
56                 object->set_technique(&catalogue.get<GL::Technique>(cat.get_track_technique()));
57
58                 own_data = true;
59         }
60
61         unsigned paths = tt.get_paths();
62         for(int i=-1; i<=1; ++i)
63         {
64                 // TODO Make profile width configurable
65                 Profile profile;
66                 if(i==0)
67                 {
68                         float rail_w = (rail_max.x-rail_min.x)*2;
69                         profile.append_vertex(Vector(rail_w*-0.5, 0, 0), false);
70                         profile.append_vertex(Vector(rail_w*0.5, 0, 0), false);
71                 }
72                 else
73                 {
74                         profile.append_vertex(Vector(i*(gauge*0.5+rail_min.x*2), 0, 0), false);
75                         profile.append_vertex(Vector(i*(gauge*0.5+rail_max.x*2), 0, 0), false);
76                 }
77
78                 // TODO Avoid generating redundant meshes for single-path tracks
79                 for(int j=-1; j<=4; ++j)
80                 {
81                         if(j>=0 && !((paths>>j)&1))
82                                 continue;
83
84                         GL::Mesh *m = new GL::Mesh(GL::VERTEX3);
85                         GL::MeshBuilder bld(*m);
86                         unsigned index = 0;
87                         for(vector<TrackPart>::const_iterator k=parts.begin(); k!=parts.end(); ++k)
88                                 if(j<0 || k->get_path()==static_cast<unsigned>(j))
89                                         build_part(*k, profile, Vector(0, 0, ballast_h+1.5*rail_h), false, bld, index);
90                         path_meshes[(j&0xFF)|((i&3)<<8)] = m;
91                 }
92         }
93 }
94
95 TrackType3D::~TrackType3D()
96 {
97         for(map<unsigned, GL::Mesh *>::iterator i=path_meshes.begin(); i!=path_meshes.end(); ++i)
98                 delete i->second;
99         if(own_data)
100         {
101                 delete object;
102                 delete mesh;
103         }
104 }
105
106 const GL::Mesh &TrackType3D::get_path_mesh(int p, int s) const
107 {
108         unsigned key = (p<0 ? 0xFF : p) | ((s&3)<<8);
109         return *get_item(path_meshes, key);
110 }
111
112 void TrackType3D::build_part(const TrackPart &part, const Profile &profile, const Vector &offset, bool mirror, GL::MeshBuilder &bld, unsigned &base_index)
113 {
114         float plen = part.get_length();
115         unsigned nsegs = (part.is_curved() ? static_cast<unsigned>(plen*32)+1 : 1);
116
117         unsigned n_vertices = profile.get_n_vertices();
118         for(unsigned i=0; i<=nsegs; ++i)
119         {
120                 OrientedPoint basep = part.get_point(i*plen/nsegs);
121                 Transform trans = Transform::rotation(basep.rotation, Vector(0, 0, 1));
122
123                 for(unsigned j=0; j<n_vertices; ++j)
124                 {
125                         const Profile::Vertex &v = profile.get_vertex(mirror ? n_vertices-1-j : j);
126                         Vector p(0, -v.pos.x, v.pos.y);
127                         if(mirror)
128                                 p.y = -p.y;
129                         p = basep.position+trans.transform(offset+p);
130
131                         Vector n(0, -v.normal.x, v.normal.y);
132                         if(mirror)
133                                 n.y = -n.y;
134                         n = trans.transform(n);
135
136                         bld.normal(n.x, n.y, n.z);
137                         bld.vertex(p.x, p.y, p.z);
138                 }
139         }
140
141         for(unsigned i=0; i+1<n_vertices; )
142         {
143                 bld.begin(GL::TRIANGLE_STRIP);
144                 for(unsigned j=0; j<=nsegs; ++j)
145                 {
146                         unsigned k = j*n_vertices+i;
147                         bld.element(base_index+k+1);
148                         bld.element(base_index+k);
149                 }
150                 bld.end();
151
152                 ++i;
153                 if(!profile.get_vertex(i).smooth)
154                         ++i;
155         }
156
157         base_index += (nsegs+1)*n_vertices;
158 }
159
160 } // namespace R2C2