]> git.tdb.fi Git - r2c2.git/commitdiff
Add framework for generating simple meshes for vehicles
authorMikko Rasa <tdb@tdb.fi>
Sun, 7 Nov 2010 14:27:40 +0000 (14:27 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 7 Nov 2010 14:27:40 +0000 (14:27 +0000)
source/3d/vehicletype.cpp
source/3d/vehicletype.h

index be6b985be828df81ed6bdf8a1288af638686dc81..b283eddebe896b1307881fef7b96098117dd64b1 100644 (file)
@@ -6,6 +6,8 @@ Distributed under the GPL
 */
 
 #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"
@@ -13,19 +15,35 @@ Distributed under the GPL
 using namespace std;
 using namespace Msp;
 
+namespace {
+
+template<typename T>
+T get(const map<string, string> &params, 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));
@@ -72,10 +90,256 @@ 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<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> &params)
+{
+       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> &params)
+{
+       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> &params)
+{
+       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> &params)
+{
+       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
index faa34aca4e8e5a936273b5207399ba2246ef47cd..f38f02d92ea43dab2651d8019884dccf1438e851 100644 (file)
@@ -19,13 +19,15 @@ class Catalogue3D;
 class VehicleType3D
 {
 private:
+       const Catalogue3D &catalogue;
+       const VehicleType &type;
        std::map<std::string, Msp::GL::Object *> objects;
        Msp::GL::Object *body_object;
        std::vector<Msp::GL::Object *> bogie_objects;
        std::vector<std::vector<Msp::GL::Object *> > axle_objects;
 
 public:
-       VehicleType3D(Catalogue3D &, const VehicleType &);
+       VehicleType3D(const Catalogue3D &, const VehicleType &);
        ~VehicleType3D();
 
        const Msp::GL::Object *get_body_object() const { return body_object; }
@@ -34,6 +36,10 @@ public:
        const Msp::GL::Object *get_bogie_axle_object(unsigned, unsigned) const;
 private:
        Msp::GL::Object *get_object(const std::string &);
+       Msp::GL::Technique *create_technique(const std::map<std::string, std::string> &);
+       Msp::GL::Mesh *create_open_wagon(const std::map<std::string, std::string> &);
+       Msp::GL::Mesh *create_covered_wagon(const std::map<std::string, std::string> &);
+       Msp::GL::Mesh *create_flat_wagon(const std::map<std::string, std::string> &);
 };
 
 } // namespace Marklin