X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2F3d%2Fvehicletype.cpp;h=34f2be630a9bc587680aaf2b4691888b6941eaf0;hb=3dd660ffad729fbd6e75e6401f5c7f27b9013faf;hp=be6b985be828df81ed6bdf8a1288af638686dc81;hpb=97443d96ff3ce51388d2edd1e0dca8f2cd231346;p=r2c2.git diff --git a/source/3d/vehicletype.cpp b/source/3d/vehicletype.cpp index be6b985..34f2be6 100644 --- a/source/3d/vehicletype.cpp +++ b/source/3d/vehicletype.cpp @@ -1,11 +1,7 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - +#include #include +#include +#include #include #include "catalogue.h" #include "vehicletype.h" @@ -13,26 +9,40 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace { -VehicleType3D::VehicleType3D(Catalogue3D &, const VehicleType &vt): - body_object(0), - axle_objects(1) +template +T get(const map ¶ms, const string &key, T def = T()) { - body_object = get_object(vt.get_object()); + map::const_iterator i = params.find(key); + if(i==params.end()) + return def; + + return lexical_cast(i->second); +} - const vector &axles = vt.get_axles(); +} + +namespace R2C2 { + +VehicleType3D::VehicleType3D(Catalogue3D &c, const VehicleType &t): + ObjectType3D(c), + type(t), + body_object(0) +{ + body_object = get_object(type.get_object()); + + const vector &axles = type.get_axles(); for(vector::const_iterator i=axles.begin(); i!=axles.end(); ++i) - axle_objects[0].push_back(get_object(i->object)); + axle_objects.push_back(get_object(i->object)); - const vector &bogies = vt.get_bogies(); + const vector &bogies = type.get_bogies(); for(vector::const_iterator i=bogies.begin(); i!=bogies.end(); ++i) - { bogie_objects.push_back(get_object(i->object)); - axle_objects.push_back(vector()); - for(vector::const_iterator j=i->axles.begin(); j!=i->axles.end(); ++j) - axle_objects.back().push_back(get_object(j->object)); - } + + const vector &rods = type.get_rods(); + for(vector::const_iterator i=rods.begin(); i!=rods.end(); ++i) + rod_objects.push_back(get_object(i->object)); } VehicleType3D::~VehicleType3D() @@ -43,25 +53,23 @@ VehicleType3D::~VehicleType3D() const GL::Object *VehicleType3D::get_axle_object(unsigned i) const { - if(i>=axle_objects[0].size()) - throw InvalidParameterValue("Axle index out of range"); - return axle_objects[0][i]; + if(i>=axle_objects.size()) + throw out_of_range("VehicleType3D::get_fixed_axle_object"); + return axle_objects[i]; } const GL::Object *VehicleType3D::get_bogie_object(unsigned i) const { if(i>=bogie_objects.size()) - throw InvalidParameterValue("Bogie index out of range"); + throw out_of_range("VehicleType3D::get_bogie_object"); return bogie_objects[i]; } -const GL::Object *VehicleType3D::get_bogie_axle_object(unsigned i, unsigned j) const +const GL::Object *VehicleType3D::get_rod_object(unsigned i) const { - if(i>=bogie_objects.size()) - throw InvalidParameterValue("Bogie index out of range"); - if(j>=axle_objects[i+1].size()) - throw InvalidParameterValue("Axle index out of range"); - return axle_objects[i+1][j]; + if(i>=rod_objects.size()) + throw out_of_range("VehicleType3D::get_rod_object"); + return rod_objects[i]; } GL::Object *VehicleType3D::get_object(const string &name) @@ -72,10 +80,255 @@ GL::Object *VehicleType3D::get_object(const string &name) 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 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(equalsset_mesh(mesh); + ptr->set_technique(create_technique(params)); + } + } + else + return &catalogue.get(name); } return ptr; } -} // namespace Marklin +GL::Technique *VehicleType3D::create_technique(const map ¶ms) +{ + string color_str = get(params, "color", "808080"); + unsigned color = lexical_cast(color_str, "x"); + string color2_str = get(params, "color2", color_str); + unsigned color2 = lexical_cast(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); + tex->set_min_filter(GL::NEAREST); + tex->set_mag_filter(GL::NEAREST); + unsigned char data[6]; + data[0] = color>>16; data[1] = color>>8; data[2] = color; + data[3] = color2>>16; data[4] = color2>>8; data[5] = 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 ¶ms) +{ + float length = get(params, "length")/1000; + float width = get(params, "width")/1000; + float height = get(params, "height")/1000; + float clearance = get(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000; + float border = get(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 ¶ms) +{ + float length = get(params, "length")/1000; + float width = get(params, "width")/1000; + float height = get(params, "height")/1000; + float clearance = get(params, "clearance", 900*catalogue.get_catalogue().get_scale())/1000; + float roof = get(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 ¶ms) +{ + float length = get(params, "length")/1000; + float width = get(params, "width")/1000; + float height = get(params, "height")/1000; + float clearance = get(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 R2C2