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