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