]> git.tdb.fi Git - r2c2.git/blob - source/3d/vehicletype.cpp
Miscellaneous compilation fixes
[r2c2.git] / source / 3d / vehicletype.cpp
1 #include <msp/gl/meshbuilder.h>
2 #include <msp/gl/technique.h>
3 #include <msp/gl/texture2d.h>
4 #include <msp/gl/vector.h>
5 #include "catalogue.h"
6 #include "vehicletype.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace {
12
13 template<typename T>
14 T get(const map<string, string> &params, const string &key, T def = T())
15 {
16         map<string, string>::const_iterator i = params.find(key);
17         if(i==params.end())
18                 return def;
19
20         return lexical_cast<T>(i->second);
21 }
22
23 }
24
25 namespace R2C2 {
26
27 VehicleType3D::VehicleType3D(Catalogue3D &c, const VehicleType &t):
28         catalogue(c),
29         type(t),
30         body_object(0),
31         axle_objects(1)
32 {
33         body_object = get_object(type.get_object());
34
35         const vector<VehicleType::Axle> &axles = type.get_fixed_axles();
36         for(vector<VehicleType::Axle>::const_iterator i=axles.begin(); i!=axles.end(); ++i)
37                 axle_objects[0].push_back(get_object(i->object));
38
39         const vector<VehicleType::Bogie> &bogies = type.get_bogies();
40         for(vector<VehicleType::Bogie>::const_iterator i=bogies.begin(); i!=bogies.end(); ++i)
41         {
42                 bogie_objects.push_back(get_object(i->object));
43                 axle_objects.push_back(vector<GL::Object *>());
44                 for(vector<VehicleType::Axle>::const_iterator j=i->axles.begin(); j!=i->axles.end(); ++j)
45                         axle_objects.back().push_back(get_object(j->object));
46         }
47
48         const vector<VehicleType::Rod> &rods = type.get_rods();
49         for(vector<VehicleType::Rod>::const_iterator i=rods.begin(); i!=rods.end(); ++i)
50                 rod_objects.push_back(get_object(i->object));
51 }
52
53 VehicleType3D::~VehicleType3D()
54 {
55         for(map<string, GL::Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
56                 delete i->second;
57 }
58
59 const GL::Object *VehicleType3D::get_fixed_axle_object(unsigned i) const
60 {
61         if(i>=axle_objects[0].size())
62                 throw out_of_range("VehicleType3D::get_fixed_axle_object");
63         return axle_objects[0][i];
64 }
65
66 const GL::Object *VehicleType3D::get_bogie_object(unsigned i) const
67 {
68         if(i>=bogie_objects.size())
69                 throw out_of_range("VehicleType3D::get_bogie_object");
70         return bogie_objects[i];
71 }
72
73 const GL::Object *VehicleType3D::get_bogie_axle_object(unsigned i, unsigned j) const
74 {
75         if(i>=bogie_objects.size())
76                 throw out_of_range("VehicleType3D::get_bogie_axle_object");
77         if(j>=axle_objects[i+1].size())
78                 throw out_of_range("VehicleType3D::get_bogie_axle_object");
79         return axle_objects[i+1][j];
80 }
81
82 const GL::Object *VehicleType3D::get_rod_object(unsigned i) const
83 {
84         if(i>=rod_objects.size())
85                 throw out_of_range("VehicleType3D::get_rod_object");
86         return rod_objects[i];
87 }
88
89 GL::Object *VehicleType3D::get_object(const string &name)
90 {
91         if(name.empty())
92                 return 0;
93
94         GL::Object *&ptr = objects[name];
95         if(!ptr)
96         {
97                 if(name[0]==':')
98                 {
99                         string::size_type colon = name.find(':', 1);
100                         string kind = name.substr(1, colon-1);
101
102                         map<string, string> params;
103                         params["length"] = lexical_cast<string>(type.get_length()*1000);
104                         params["width"] = lexical_cast<string>(type.get_width()*1000);
105                         params["height"] = lexical_cast<string>(type.get_height()*1000);
106                         if(colon!=string::npos)
107                         {
108                                 string::size_type start = colon+1;
109                                 while(1)
110                                 {
111                                         string::size_type equals = name.find('=', start);
112                                         string::size_type comma = name.find(',', start);
113                                         if(equals<comma)
114                                                 params[name.substr(start, equals-start)] = name.substr(equals+1, comma-equals-1);
115                                         else
116                                                 params[name.substr(start, comma-start)] = string();
117
118                                         if(comma==string::npos)
119                                                 break;
120                                         start = comma+1;
121                                 }
122                         }
123
124                         GL::Mesh *mesh = 0;
125                         if(kind=="openwagon")
126                                 mesh = create_open_wagon(params);
127                         else if(kind=="coveredwagon")
128                                 mesh = create_covered_wagon(params);
129                         else if(kind=="flatwagon")
130                                 mesh = create_flat_wagon(params);
131
132                         if(mesh)
133                         {
134                                 ptr = new GL::Object;
135                                 ptr->set_mesh(mesh);
136                                 ptr->set_technique(create_technique(params));
137                         }
138                 }
139                 else
140                         return &catalogue.get<GL::Object>(name);
141         }
142         return ptr;
143 }
144
145 GL::Technique *VehicleType3D::create_technique(const map<string, string> &params)
146 {
147         string color_str = get<string>(params, "color", "808080");
148         unsigned color = lexical_cast<unsigned>(color_str, "x");
149         string color2_str = get<string>(params, "color2", color_str);
150         unsigned color2 = lexical_cast<unsigned>(color2_str, "x");
151
152         GL::Technique *tech = new GL::Technique;
153         GL::RenderPass &pass = tech->add_pass(GL::Tag());
154         GL::Material *mat = new GL::Material;
155         mat->set_diffuse(GL::Color(1));
156         pass.set_material(mat);
157         GL::Texture2D *tex = new GL::Texture2D;
158         tex->storage(GL::RGB, 2, 1);
159         tex->set_min_filter(GL::NEAREST);
160         tex->set_mag_filter(GL::NEAREST);
161         unsigned char data[6];
162         data[0] = color>>16;  data[1] = color>>8;  data[2] = color;
163         data[3] = color2>>16; data[4] = color2>>8; data[5] = color2;
164         tex->image(0, GL::RGB, GL::UNSIGNED_BYTE, data);
165         pass.set_texture(0, tex);
166
167         return tech;
168 }
169
170 GL::Mesh *VehicleType3D::create_open_wagon(const map<string, string> &params)
171 {
172         float length = get<float>(params, "length")/1000;
173         float width = get<float>(params, "width")/1000;
174         float height = get<float>(params, "height")/1000;
175         float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
176         float border = get<float>(params, "border", 40*catalogue.get_catalogue().get_scale())/1000;
177
178         GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
179         GL::MeshBuilder bld(*mesh);
180
181         for(unsigned i=0; i<16; ++i)
182         {
183                 float x = length/2;
184                 float y = width/2;
185                 if(i>=8)
186                 {
187                         x -= border;
188                         y -= border;
189                 }
190                 if((i+1)%4<2)
191                         x = -x;
192                 if(i%4<2)
193                         y = -y;
194
195                 float z = height;
196                 if(i<4)
197                         z = clearance;
198                 else if(i>=12)
199                         z = clearance+0.1*catalogue.get_catalogue().get_scale();
200
201                 bld.texcoord((i>=12 ? 0.75 : 0.25), 0.5);
202                 bld.normal(0, 0, (i<4 ? -1 : 1));
203                 bld.vertex(x, y, z);
204                 bld.texcoord((i>=8 ? 0.75 : 0.25), 0.5);
205                 bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
206                 bld.vertex(x, y, z);
207                 bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
208                 bld.vertex(x, y, z);
209         }
210
211         bld.begin(GL::QUADS);
212         for(unsigned i=0; i<3; ++i)
213                 for(unsigned j=0; j<4; ++j)
214                 {
215                         unsigned k = (i==1 ? 0 : 2-j%2);
216                         bld.element((i*4+j)*3+k);
217                         bld.element((i*4+(j+1)%4)*3+k);
218                         bld.element(((i+1)*4+(j+1)%4)*3+k);
219                         bld.element(((i+1)*4+j)*3+k);
220                 }
221         for(unsigned i=4; i--;)
222                 bld.element(i*3);
223         for(unsigned i=0; i<4; ++i)
224                 bld.element((12+i)*3);
225         bld.end();
226
227         return mesh;
228 }
229
230 GL::Mesh *VehicleType3D::create_covered_wagon(const map<string, string> &params)
231 {
232         float length = get<float>(params, "length")/1000;
233         float width = get<float>(params, "width")/1000;
234         float height = get<float>(params, "height")/1000;
235         float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
236         float roof = get<float>(params, "roof", width*250)/1000;
237
238         GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
239         GL::MeshBuilder bld(*mesh);
240
241         for(unsigned i=0; i<12; ++i)
242         {
243                 float x = length/2;
244                 float y = width/2;
245                 if(i>=8)
246                         y /= 3;
247                 if((i+1)%4<2)
248                         x = -x;
249                 if(i%4<2)
250                         y = -y;
251
252                 float z = height;
253                 if(i<4)
254                         z = clearance;
255                 else if(i<8)
256                         z -= roof;
257
258                 if(i<4)
259                 {
260                         bld.normal(0, 0, -1);
261                         bld.texcoord(0.25, 0.5);
262                 }
263                 else
264                 {
265                         float a = atan2(roof/(i>=8 ? 3 : 1), width/2);
266                         if(y<0)
267                                 a = -a;
268                         bld.normal(0, sin(a), cos(a));
269                         bld.texcoord(0.75, 0.5);
270                 }
271                 bld.vertex(x, y, z);
272
273                 bld.texcoord(0.25, 0.5);
274                 bld.normal((x<0 ? -1 : 1), 0, 0);
275                 bld.vertex(x, y, z);
276                 bld.normal(0, (y<0 ? -1 : 1), 0);
277                 bld.vertex(x, y, z);
278         }
279
280         bld.begin(GL::QUADS);
281         for(unsigned i=0; i<2; ++i)
282                 for(unsigned j=0; j<4; ++j)
283                 {
284                         unsigned k = ((i==1 && j%2==0) ? 0 : 2-j%2);
285                         bld.element((i*4+j)*3+k);
286                         bld.element((i*4+(j+1)%4)*3+k);
287                         bld.element(((i+1)*4+(j+1)%4)*3+k);
288                         bld.element(((i+1)*4+j)*3+k);
289                 }
290         for(unsigned i=4; i--;)
291                 bld.element(i*3);
292         for(unsigned i=0; i<4; ++i)
293                 bld.element((8+i)*3);
294         bld.end();
295
296         return mesh;
297 }
298
299 GL::Mesh *VehicleType3D::create_flat_wagon(const map<string, string> &params)
300 {
301         float length = get<float>(params, "length")/1000;
302         float width = get<float>(params, "width")/1000;
303         float height = get<float>(params, "height")/1000;
304         float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
305
306         GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
307         GL::MeshBuilder bld(*mesh);
308
309         for(unsigned i=0; i<8; ++i)
310         {
311                 float x = length/2;
312                 float y = width/2;
313                 if((i+1)%4<2)
314                         x = -x;
315                 if(i%4<2)
316                         y = -y;
317
318                 float z = (i<4 ? clearance : height);
319
320                 bld.texcoord((i>=4 ? 0.75 : 0.25), 0.5);
321                 bld.normal(0, 0, (i<4 ? -1 : 1));
322                 bld.vertex(x, y, z);
323                 bld.texcoord(0.25, 0.5);
324                 bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
325                 bld.vertex(x, y, z);
326                 bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
327                 bld.vertex(x, y, z);
328         }
329
330         bld.begin(GL::QUADS);
331         for(unsigned i=0; i<4; ++i)
332         {
333                 unsigned j = 2-i%2;
334                 bld.element(i*3+j);
335                 bld.element(((i+1)%4)*3+j);
336                 bld.element((4+(i+1)%4)*3+j);
337                 bld.element((4+i)*3+j);
338         }
339         for(unsigned i=4; i--;)
340                 bld.element(i*3);
341         for(unsigned i=0; i<4; ++i)
342                 bld.element((4+i)*3);
343         bld.end();
344
345         return mesh;
346 }
347
348 } // namespace R2C2