X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2F3d%2Ftracktype.cpp;h=a1ffc361f4e29aef712678228504109c1f11bf01;hb=508ee4bfcc0f8fb1373fb7af251c59c873ef896f;hp=a5e06665b3d589a5116a72d693beca5851beee0d;hpb=a277834b140eb5987419e2c335032c534a7184cd;p=r2c2.git diff --git a/source/3d/tracktype.cpp b/source/3d/tracktype.cpp index a5e0666..a1ffc36 100644 --- a/source/3d/tracktype.cpp +++ b/source/3d/tracktype.cpp @@ -1,233 +1,248 @@ -/* $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 "libr2c2/trackappearance.h" #include "catalogue.h" #include "tracktype.h" using namespace std; using namespace Msp; -namespace { - -bool compare_z(const Marklin::Point &p1, const Marklin::Point &p2) -{ - return p1.z -Iter graham_scan(Iter begin, Iter end) +TrackType3D::TrackType3D(Catalogue3D &c, const TrackType &tt): + ObjectType3D(c), + mesh(0), + object(0), + own_data(false) { - // http://en.wikipedia.org/wiki/Graham_scan - - // Find point with lowest X coordinate - Marklin::Point lowest = *begin; - for(Iter i=begin; i!=end; ++i) - if(i->xx==lowest.x && i->y>lowest.y)) - lowest = *i; - - // Compute tangents and sort points - for(Iter i=begin; i!=end; ++i) - i->z = (i->x==lowest.x ? 1e5/(i->y-lowest.y-1) : (i->y-lowest.y)/(i->x-lowest.x)); - sort(begin, end, compare_z); - - for(Iter k=begin, i=k++, j=k++;; ) - { - // Compute winding by cross product - float turn = (j->x-i->x)*(k->y-j->y) - (k->x-j->x)*(j->y-i->y); - - if(turn<1e-5) - { - // Right turn - throw the middle point away - // Special case for collinear vertices in the beginning - if(i==begin) - j = k++; - else - j = i--; - } - else - { - // Left turn - store the middle point and advance - if(++i!=j) - *i = *j; - j = k++; - } - - // Cycle back to beginning and terminate after checking the last point - if(k==end) - k = begin; - else if(j==begin) - return ++i; - } -} - -} - -namespace Marklin { - -TrackType3D::TrackType3D(const Catalogue3D &cat3d, const TrackType &tt): - catalogue(cat3d), - ballast_mesh((GL::NORMAL3, GL::COLOR4_UBYTE, GL::VERTEX3)), - rail_mesh((GL::NORMAL3, GL::COLOR4_UBYTE, GL::VERTEX3)) -{ - const Catalogue &cat = cat3d.get_catalogue(); + const TrackAppearance &appearance = tt.get_appearance(); const vector &parts = tt.get_parts(); - const Profile &ballast_profile = cat.get_ballast_profile(); - const Point &ballast_min = ballast_profile.get_min_coords(); - const Point &ballast_max = ballast_profile.get_max_coords(); + const Profile &ballast_profile = appearance.get_ballast_profile(); + const Vector &ballast_min = ballast_profile.get_min_coords(); + const Vector &ballast_max = ballast_profile.get_max_coords(); float ballast_h = ballast_max.y-ballast_min.y; - const Profile &rail_profile = cat.get_rail_profile(); - const Point &rail_min = rail_profile.get_min_coords(); - const Point &rail_max = rail_profile.get_max_coords(); + const Profile &rail_profile = appearance.get_rail_profile(); + const Vector &rail_min = rail_profile.get_min_coords(); + const Vector &rail_max = rail_profile.get_max_coords(); float rail_h = rail_max.y-rail_min.y; - float gauge = cat.get_gauge(); + const Profile &tie_profile = appearance.get_tie_profile(); + const Vector &tie_min = tie_profile.get_min_coords(); + const Vector &tie_max = tie_profile.get_max_coords(); + float tie_h = tie_max.y-tie_min.y; + + float gauge = appearance.get_gauge(); + string obj_name = tt.get_object(); + if(!obj_name.empty()) + object = &catalogue.get(obj_name); + else { + mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3)); + mesh->set_winding(&GL::WindingTest::counterclockwise()); + GL::MeshBuilder bld(*mesh); + unsigned index = 0; - GL::MeshBuilder bld(ballast_mesh); - bld.color(0.25f, 0.25f, 0.25f); + bld.texcoord(0.17, 0.5); for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - build_part(*i, ballast_profile, Point(0, -ballast_min.y), bld, index); - } + build_part(*i, ballast_profile, Vector(0, 0, -ballast_min.y), false, bld, index); - { - unsigned index = 0; - GL::MeshBuilder bld(rail_mesh); - bld.color(0.85f, 0.85f, 0.85f); - float y = ballast_h-rail_min.y; + float y = ballast_h-tie_min.y; + bld.texcoord(0.83, 0.5); for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - build_part(*i, rail_profile, Point(-gauge/2-rail_max.x, y), bld, index); + build_ties(*i, tie_profile, appearance.get_tie_length(), appearance.get_tie_spacing(), Vector(0, 0, y), bld, index); + + bld.texcoord(0.5, 0.5); + y = ballast_h+tie_h-rail_min.y; + for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) + build_part(*i, rail_profile, Vector(0, gauge/2, y), true, bld, index); for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - build_part(*i, rail_profile, Point(gauge/2-rail_min.x, y), bld, index); + build_part(*i, rail_profile, Vector(0, -gauge/2, y), false, bld, index); + + object = new GL::Object; + object->set_mesh(mesh); + object->set_technique(&catalogue.get(appearance.get_technique())); + + own_data = true; } - + unsigned paths = tt.get_paths(); - for(unsigned i=0; paths; ++i, paths>>=1) + for(int i=-1; i<=1; ++i) { - GL::Mesh *mesh = 0; - if(paths&1) + // TODO Make profile width configurable + Profile profile; + if(i==0) { - mesh = new GL::Mesh(GL::VERTEX3); - GL::MeshBuilder bld(*mesh); + float rail_w = (rail_max.x-rail_min.x)*2; + profile.append_vertex(Vector(rail_w*-0.5, 0, 0), false); + profile.append_vertex(Vector(rail_w*0.5, 0, 0), false); + } + else + { + profile.append_vertex(Vector(i*(gauge*0.5+rail_min.x*2), 0, 0), false); + profile.append_vertex(Vector(i*(gauge*0.5+rail_max.x*2), 0, 0), false); + } + + // TODO Avoid generating redundant meshes for single-path tracks + for(int j=-1; j<=4; ++j) + { + if(j>=0 && !((paths>>j)&1)) + continue; + + GL::Mesh *m = new GL::Mesh(GL::VERTEX3); + GL::MeshBuilder bld(*m); unsigned index = 0; - for(vector::const_iterator j=parts.begin(); j!=parts.end(); ++j) - if(j->get_path()==i) - build_part(*j, cat.get_path_profile(), Point(0, ballast_h+1.5*rail_h), bld, index); + for(vector::const_iterator k=parts.begin(); k!=parts.end(); ++k) + if(j<0 || k->get_path()==static_cast(j)) + build_part(*k, profile, Vector(0, 0, ballast_h+1.5*rail_h), false, bld, index); + path_meshes[(j&0xFF)|((i&3)<<8)] = m; } - path_meshes.push_back(mesh); } +} - min_z = max_z = border.front().z; - for(vector::iterator i=border.begin(); i!=border.end(); ++i) +TrackType3D::~TrackType3D() +{ + for(map::iterator i=path_meshes.begin(); i!=path_meshes.end(); ++i) + delete i->second; + if(own_data) { - min_z = min(min_z, i->z); - max_z = max(max_z, i->z); + delete object; + delete mesh; } - border.erase(graham_scan(border.begin(), border.end()), border.end()); } -TrackType3D::~TrackType3D() +const GL::Mesh &TrackType3D::get_path_mesh(int p, int s) const { - for(vector::iterator i=path_meshes.begin(); i!=path_meshes.end(); ++i) - delete *i; + unsigned key = (p<0 ? 0xFF : p) | ((s&3)<<8); + return *get_item(path_meshes, key); } -void TrackType3D::get_bounds(float angle, Point &minp, Point &maxp) const +void TrackType3D::build_part(const TrackPart &part, const Profile &profile, const Vector &offset, bool mirror, GL::MeshBuilder &bld, unsigned &base_index) { - float c = cos(-angle); - float s = sin(-angle); - - minp = maxp = Point(); - minp.z = min_z; - maxp.z = max_z; + float plen = part.get_length(); + unsigned nsegs = (part.is_curved() ? static_cast(plen*32)+1 : 1); - for(vector::const_iterator i=border.begin(); i!=border.end(); ++i) + unsigned n_vertices = profile.get_n_vertices(); + for(unsigned i=0; i<=nsegs; ++i) { - float x = c*i->x-s*i->y; - float y = s*i->x+c*i->y; + OrientedPoint basep = part.get_point(i*plen/nsegs); + Transform trans = Transform::rotation(basep.rotation, Vector(0, 0, 1)); - minp.x = min(minp.x, x); - minp.y = min(minp.y, y); - maxp.x = max(maxp.x, x); - maxp.y = max(maxp.y, y); + for(unsigned j=0; j=path_meshes.size() || !path_meshes[p]) - throw InvalidParameterValue("Invalid path"); - return *path_meshes[p]; -} - -void TrackType3D::render(const GL::Tag &tag) const -{ - if(tag==0) + for(unsigned i=0; i+1(plen*16)+1 : 1); + unsigned count = plen/spacing+0.5; - unsigned n_points = profile.get_n_points(); - for(unsigned i=0; i<=nsegs; ++i) + unsigned n_vertices = profile.get_n_vertices(); + float min_y = profile.get_min_coords().y; + vector cap_vertices; + for(unsigned i=0; i+1=2) + { + if(i+20) - bld.vertex(p.x, p.y, p.z); + Vector n = trans.transform(Vector(0, -v.normal.x, v.normal.y)); + bld.normal(n.x, n.y, n.z); - if(j+1=2 && !profile.get_vertex(j).smooth) + { + bld.end(); + strip = 0; + } } - } + if(strip) + bld.end(); - for(unsigned i=0; i+1