*/
#include <msp/gl/meshbuilder.h>
+#include <msp/gl/technique.h>
+#include <msp/gl/texture2d.h>
#include <msp/gl/vector.h>
#include "catalogue.h"
#include "vehicletype.h"
using namespace std;
using namespace Msp;
+namespace {
+
+template<typename T>
+T get(const map<string, string> ¶ms, const string &key, T def = T())
+{
+ map<string, string>::const_iterator i = params.find(key);
+ if(i==params.end())
+ return def;
+
+ return lexical_cast<T>(i->second);
+}
+
+}
+
namespace Marklin {
-VehicleType3D::VehicleType3D(Catalogue3D &, const VehicleType &vt):
+VehicleType3D::VehicleType3D(const Catalogue3D &c, const VehicleType &t):
+ catalogue(c),
+ type(t),
body_object(0),
axle_objects(1)
{
- body_object = get_object(vt.get_object());
+ body_object = get_object(type.get_object());
- const vector<VehicleType::Axle> &axles = vt.get_axles();
+ const vector<VehicleType::Axle> &axles = type.get_axles();
for(vector<VehicleType::Axle>::const_iterator i=axles.begin(); i!=axles.end(); ++i)
axle_objects[0].push_back(get_object(i->object));
- const vector<VehicleType::Bogie> &bogies = vt.get_bogies();
+ const vector<VehicleType::Bogie> &bogies = type.get_bogies();
for(vector<VehicleType::Bogie>::const_iterator i=bogies.begin(); i!=bogies.end(); ++i)
{
bogie_objects.push_back(get_object(i->object));
GL::Object *&ptr = objects[name];
if(!ptr)
{
- ptr = new GL::Object;
- DataFile::load(*ptr, name);
+ if(name[0]==':')
+ {
+ string::size_type colon = name.find(':', 1);
+ string kind = name.substr(1, colon-1);
+
+ map<string, string> params;
+ params["length"] = lexical_cast(type.get_length()*1000);
+ params["width"] = lexical_cast(type.get_width()*1000);
+ params["height"] = lexical_cast(type.get_height()*1000);
+ if(colon!=string::npos)
+ {
+ string::size_type start = colon+1;
+ while(1)
+ {
+ string::size_type equals = name.find('=', start);
+ string::size_type comma = name.find(',', start);
+ if(equals<comma)
+ params[name.substr(start, equals-start)] = name.substr(equals+1, comma-equals-1);
+ else
+ params[name.substr(start, comma-start)] = string();
+
+ if(comma==string::npos)
+ break;
+ start = comma+1;
+ }
+ }
+
+ GL::Mesh *mesh = 0;
+ if(kind=="openwagon")
+ mesh = create_open_wagon(params);
+ else if(kind=="coveredwagon")
+ mesh = create_covered_wagon(params);
+ else if(kind=="flatwagon")
+ mesh = create_flat_wagon(params);
+
+ if(mesh)
+ {
+ ptr = new GL::Object;
+ ptr->set_mesh(mesh);
+ ptr->set_technique(create_technique(params));
+ }
+ }
+ else
+ {
+ ptr = new GL::Object;
+ DataFile::load(*ptr, name);
+ }
}
return ptr;
}
+GL::Technique *VehicleType3D::create_technique(const map<string, string> ¶ms)
+{
+ string color_str = get<string>(params, "color", "808080");
+ unsigned color = lexical_cast<unsigned>(color_str, "x");
+ string color2_str = get<string>(params, "color2", color_str);
+ unsigned color2 = lexical_cast<unsigned>(color2_str, "x");
+
+ GL::Technique *tech = new GL::Technique;
+ GL::RenderPass &pass = tech->add_pass(GL::Tag());
+ GL::Material *mat = new GL::Material;
+ mat->set_diffuse(GL::Color(1));
+ pass.set_material(mat);
+ GL::Texture2D *tex = new GL::Texture2D;
+ tex->storage(GL::RGB, 2, 1, 0);
+ tex->set_min_filter(GL::NEAREST);
+ tex->set_mag_filter(GL::NEAREST);
+ unsigned char data[6] = { color>>16, color>>8, color, color2>>16, color2>>8, color2 };
+ tex->image(0, GL::RGB, GL::UNSIGNED_BYTE, data);
+ pass.set_texture(0, tex);
+
+ return tech;
+}
+
+GL::Mesh *VehicleType3D::create_open_wagon(const map<string, string> ¶ms)
+{
+ float length = get<float>(params, "length")/1000;
+ float width = get<float>(params, "width")/1000;
+ float height = get<float>(params, "height")/1000;
+ float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
+ float border = get<float>(params, "border", 40*catalogue.get_catalogue().get_scale())/1000;
+
+ GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
+ GL::MeshBuilder bld(*mesh);
+
+ for(unsigned i=0; i<16; ++i)
+ {
+ float x = length/2;
+ float y = width/2;
+ if(i>=8)
+ {
+ x -= border;
+ y -= border;
+ }
+ if((i+1)%4<2)
+ x = -x;
+ if(i%4<2)
+ y = -y;
+
+ float z = height;
+ if(i<4)
+ z = clearance;
+ else if(i>=12)
+ z = clearance+0.1*catalogue.get_catalogue().get_scale();
+
+ bld.texcoord((i>=12 ? 0.75 : 0.25), 0.5);
+ bld.normal(0, 0, (i<4 ? -1 : 1));
+ bld.vertex(x, y, z);
+ bld.texcoord((i>=8 ? 0.75 : 0.25), 0.5);
+ bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
+ bld.vertex(x, y, z);
+ bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
+ bld.vertex(x, y, z);
+ }
+
+ bld.begin(GL::QUADS);
+ for(unsigned i=0; i<3; ++i)
+ for(unsigned j=0; j<4; ++j)
+ {
+ unsigned k = (i==1 ? 0 : 2-j%2);
+ bld.element((i*4+j)*3+k);
+ bld.element((i*4+(j+1)%4)*3+k);
+ bld.element(((i+1)*4+(j+1)%4)*3+k);
+ bld.element(((i+1)*4+j)*3+k);
+ }
+ for(unsigned i=4; i--;)
+ bld.element(i*3);
+ for(unsigned i=0; i<4; ++i)
+ bld.element((12+i)*3);
+ bld.end();
+
+ return mesh;
+}
+
+GL::Mesh *VehicleType3D::create_covered_wagon(const map<string, string> ¶ms)
+{
+ float length = get<float>(params, "length")/1000;
+ float width = get<float>(params, "width")/1000;
+ float height = get<float>(params, "height")/1000;
+ float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
+ float roof = get<float>(params, "roof", width*250)/1000;
+
+ GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
+ GL::MeshBuilder bld(*mesh);
+
+ for(unsigned i=0; i<12; ++i)
+ {
+ float x = length/2;
+ float y = width/2;
+ if(i>=8)
+ y /= 3;
+ if((i+1)%4<2)
+ x = -x;
+ if(i%4<2)
+ y = -y;
+
+ float z = height;
+ if(i<4)
+ z = clearance;
+ else if(i<8)
+ z -= roof;
+
+ if(i<4)
+ {
+ bld.normal(0, 0, -1);
+ bld.texcoord(0.25, 0.5);
+ }
+ else
+ {
+ float a = atan2(roof/(i>=8 ? 3 : 1), width/2);
+ if(y<0)
+ a = -a;
+ bld.normal(0, sin(a), cos(a));
+ bld.texcoord(0.75, 0.5);
+ }
+ bld.vertex(x, y, z);
+
+ bld.texcoord(0.25, 0.5);
+ bld.normal((x<0 ? -1 : 1), 0, 0);
+ bld.vertex(x, y, z);
+ bld.normal(0, (y<0 ? -1 : 1), 0);
+ bld.vertex(x, y, z);
+ }
+
+ bld.begin(GL::QUADS);
+ for(unsigned i=0; i<2; ++i)
+ for(unsigned j=0; j<4; ++j)
+ {
+ unsigned k = ((i==1 && j%2==0) ? 0 : 2-j%2);
+ bld.element((i*4+j)*3+k);
+ bld.element((i*4+(j+1)%4)*3+k);
+ bld.element(((i+1)*4+(j+1)%4)*3+k);
+ bld.element(((i+1)*4+j)*3+k);
+ }
+ for(unsigned i=4; i--;)
+ bld.element(i*3);
+ for(unsigned i=0; i<4; ++i)
+ bld.element((8+i)*3);
+ bld.end();
+
+ return mesh;
+}
+
+GL::Mesh *VehicleType3D::create_flat_wagon(const map<string, string> ¶ms)
+{
+ float length = get<float>(params, "length")/1000;
+ float width = get<float>(params, "width")/1000;
+ float height = get<float>(params, "height")/1000;
+ float clearance = get<float>(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000;
+
+ GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
+ GL::MeshBuilder bld(*mesh);
+
+ for(unsigned i=0; i<8; ++i)
+ {
+ float x = length/2;
+ float y = width/2;
+ if((i+1)%4<2)
+ x = -x;
+ if(i%4<2)
+ y = -y;
+
+ float z = (i<4 ? clearance : height);
+
+ bld.texcoord((i>=4 ? 0.75 : 0.25), 0.5);
+ bld.normal(0, 0, (i<4 ? -1 : 1));
+ bld.vertex(x, y, z);
+ bld.texcoord(0.25, 0.5);
+ bld.normal(((x<0)==(i<8) ? -1 : 1), 0, 0);
+ bld.vertex(x, y, z);
+ bld.normal(0, ((y<0)==(i<8) ? -1 : 1), 0);
+ bld.vertex(x, y, z);
+ }
+
+ bld.begin(GL::QUADS);
+ for(unsigned i=0; i<4; ++i)
+ {
+ unsigned j = 2-i%2;
+ bld.element(i*3+j);
+ bld.element(((i+1)%4)*3+j);
+ bld.element((4+(i+1)%4)*3+j);
+ bld.element((4+i)*3+j);
+ }
+ for(unsigned i=4; i--;)
+ bld.element(i*3);
+ for(unsigned i=0; i<4; ++i)
+ bld.element((4+i)*3);
+ bld.end();
+
+ return mesh;
+}
+
} // namespace Marklin