3 This file is part of R²C²
4 Copyright © 2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
8 #include <msp/gl/meshbuilder.h>
9 #include <msp/gl/technique.h>
10 #include <msp/gl/texture2d.h>
11 #include <msp/gl/vector.h>
12 #include "catalogue.h"
13 #include "vehicletype.h"
21 T get(const map<string, string> ¶ms, const string &key, T def = T())
23 map<string, string>::const_iterator i = params.find(key);
27 return lexical_cast<T>(i->second);
34 VehicleType3D::VehicleType3D(const Catalogue3D &c, const VehicleType &t):
40 body_object = get_object(type.get_object());
42 const vector<VehicleType::Axle> &axles = type.get_axles();
43 for(vector<VehicleType::Axle>::const_iterator i=axles.begin(); i!=axles.end(); ++i)
44 axle_objects[0].push_back(get_object(i->object));
46 const vector<VehicleType::Bogie> &bogies = type.get_bogies();
47 for(vector<VehicleType::Bogie>::const_iterator i=bogies.begin(); i!=bogies.end(); ++i)
49 bogie_objects.push_back(get_object(i->object));
50 axle_objects.push_back(vector<GL::Object *>());
51 for(vector<VehicleType::Axle>::const_iterator j=i->axles.begin(); j!=i->axles.end(); ++j)
52 axle_objects.back().push_back(get_object(j->object));
55 const vector<VehicleType::Rod> &rods = type.get_rods();
56 for(vector<VehicleType::Rod>::const_iterator i=rods.begin(); i!=rods.end(); ++i)
57 rod_objects.push_back(get_object(i->object));
60 VehicleType3D::~VehicleType3D()
62 for(map<string, GL::Object *>::iterator i=objects.begin(); i!=objects.end(); ++i)
66 const GL::Object *VehicleType3D::get_axle_object(unsigned i) const
68 if(i>=axle_objects[0].size())
69 throw InvalidParameterValue("Axle index out of range");
70 return axle_objects[0][i];
73 const GL::Object *VehicleType3D::get_bogie_object(unsigned i) const
75 if(i>=bogie_objects.size())
76 throw InvalidParameterValue("Bogie index out of range");
77 return bogie_objects[i];
80 const GL::Object *VehicleType3D::get_bogie_axle_object(unsigned i, unsigned j) const
82 if(i>=bogie_objects.size())
83 throw InvalidParameterValue("Bogie index out of range");
84 if(j>=axle_objects[i+1].size())
85 throw InvalidParameterValue("Axle index out of range");
86 return axle_objects[i+1][j];
89 const GL::Object *VehicleType3D::get_rod_object(unsigned i) const
91 if(i>=rod_objects.size())
92 throw InvalidParameterValue("Rod index out of range");
93 return rod_objects[i];
96 GL::Object *VehicleType3D::get_object(const string &name)
101 GL::Object *&ptr = objects[name];
106 string::size_type colon = name.find(':', 1);
107 string kind = name.substr(1, colon-1);
109 map<string, string> params;
110 params["length"] = lexical_cast(type.get_length()*1000);
111 params["width"] = lexical_cast(type.get_width()*1000);
112 params["height"] = lexical_cast(type.get_height()*1000);
113 if(colon!=string::npos)
115 string::size_type start = colon+1;
118 string::size_type equals = name.find('=', start);
119 string::size_type comma = name.find(',', start);
121 params[name.substr(start, equals-start)] = name.substr(equals+1, comma-equals-1);
123 params[name.substr(start, comma-start)] = string();
125 if(comma==string::npos)
132 if(kind=="openwagon")
133 mesh = create_open_wagon(params);
134 else if(kind=="coveredwagon")
135 mesh = create_covered_wagon(params);
136 else if(kind=="flatwagon")
137 mesh = create_flat_wagon(params);
141 ptr = new GL::Object;
143 ptr->set_technique(create_technique(params));
148 ptr = new GL::Object;
149 DataFile::load(*ptr, name);
155 GL::Technique *VehicleType3D::create_technique(const map<string, string> ¶ms)
157 string color_str = get<string>(params, "color", "808080");
158 unsigned color = lexical_cast<unsigned>(color_str, "x");
159 string color2_str = get<string>(params, "color2", color_str);
160 unsigned color2 = lexical_cast<unsigned>(color2_str, "x");
162 GL::Technique *tech = new GL::Technique;
163 GL::RenderPass &pass = tech->add_pass(GL::Tag());
164 GL::Material *mat = new GL::Material;
165 mat->set_diffuse(GL::Color(1));
166 pass.set_material(mat);
167 GL::Texture2D *tex = new GL::Texture2D;
168 tex->storage(GL::RGB, 2, 1);
169 tex->set_min_filter(GL::NEAREST);
170 tex->set_mag_filter(GL::NEAREST);
171 unsigned char data[6] = { color>>16, color>>8, color, color2>>16, color2>>8, color2 };
172 tex->image(0, GL::RGB, GL::UNSIGNED_BYTE, data);
173 pass.set_texture(0, tex);
178 GL::Mesh *VehicleType3D::create_open_wagon(const map<string, string> ¶ms)
180 float length = get<float>(params, "length")/1000;
181 float width = get<float>(params, "width")/1000;
182 float height = get<float>(params, "height")/1000;
183 float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
184 float border = get<float>(params, "border", 40*catalogue.get_catalogue().get_scale())/1000;
186 GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
187 GL::MeshBuilder bld(*mesh);
189 for(unsigned i=0; i<16; ++i)
207 z = clearance+0.1*catalogue.get_catalogue().get_scale();
209 bld.texcoord((i>=12 ? 0.75 : 0.25), 0.5);
210 bld.normal(0, 0, (i<4 ? -1 : 1));
212 bld.texcoord((i>=8 ? 0.75 : 0.25), 0.5);
213 bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
215 bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
219 bld.begin(GL::QUADS);
220 for(unsigned i=0; i<3; ++i)
221 for(unsigned j=0; j<4; ++j)
223 unsigned k = (i==1 ? 0 : 2-j%2);
224 bld.element((i*4+j)*3+k);
225 bld.element((i*4+(j+1)%4)*3+k);
226 bld.element(((i+1)*4+(j+1)%4)*3+k);
227 bld.element(((i+1)*4+j)*3+k);
229 for(unsigned i=4; i--;)
231 for(unsigned i=0; i<4; ++i)
232 bld.element((12+i)*3);
238 GL::Mesh *VehicleType3D::create_covered_wagon(const map<string, string> ¶ms)
240 float length = get<float>(params, "length")/1000;
241 float width = get<float>(params, "width")/1000;
242 float height = get<float>(params, "height")/1000;
243 float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
244 float roof = get<float>(params, "roof", width*250)/1000;
246 GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
247 GL::MeshBuilder bld(*mesh);
249 for(unsigned i=0; i<12; ++i)
268 bld.normal(0, 0, -1);
269 bld.texcoord(0.25, 0.5);
273 float a = atan2(roof/(i>=8 ? 3 : 1), width/2);
276 bld.normal(0, sin(a), cos(a));
277 bld.texcoord(0.75, 0.5);
281 bld.texcoord(0.25, 0.5);
282 bld.normal((x<0 ? -1 : 1), 0, 0);
284 bld.normal(0, (y<0 ? -1 : 1), 0);
288 bld.begin(GL::QUADS);
289 for(unsigned i=0; i<2; ++i)
290 for(unsigned j=0; j<4; ++j)
292 unsigned k = ((i==1 && j%2==0) ? 0 : 2-j%2);
293 bld.element((i*4+j)*3+k);
294 bld.element((i*4+(j+1)%4)*3+k);
295 bld.element(((i+1)*4+(j+1)%4)*3+k);
296 bld.element(((i+1)*4+j)*3+k);
298 for(unsigned i=4; i--;)
300 for(unsigned i=0; i<4; ++i)
301 bld.element((8+i)*3);
307 GL::Mesh *VehicleType3D::create_flat_wagon(const map<string, string> ¶ms)
309 float length = get<float>(params, "length")/1000;
310 float width = get<float>(params, "width")/1000;
311 float height = get<float>(params, "height")/1000;
312 float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
314 GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
315 GL::MeshBuilder bld(*mesh);
317 for(unsigned i=0; i<8; ++i)
326 float z = (i<4 ? clearance : height);
328 bld.texcoord((i>=4 ? 0.75 : 0.25), 0.5);
329 bld.normal(0, 0, (i<4 ? -1 : 1));
331 bld.texcoord(0.25, 0.5);
332 bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
334 bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
338 bld.begin(GL::QUADS);
339 for(unsigned i=0; i<4; ++i)
343 bld.element(((i+1)%4)*3+j);
344 bld.element((4+(i+1)%4)*3+j);
345 bld.element((4+i)*3+j);
347 for(unsigned i=4; i--;)
349 for(unsigned i=0; i<4; ++i)
350 bld.element((4+i)*3);