From 346d933cb7d5d2e016ce235fb4336e202ca7708e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 21 Nov 2013 13:42:37 +0200 Subject: [PATCH 01/16] Avoid crash if an object does not have a shape --- source/3d/layout.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/3d/layout.cpp b/source/3d/layout.cpp index 59a23c9..be19b00 100644 --- a/source/3d/layout.cpp +++ b/source/3d/layout.cpp @@ -41,7 +41,11 @@ void Layout3D::get_bounds(Vector &minp, Vector &maxp) const Geometry::BoundingBox bbox; for(ObjectMap::const_iterator i=objects.begin(); i!=objects.end(); ++i) - bbox = bbox|i->second->get_object().get_type().get_shape()->get_axis_aligned_bounding_box(); + { + const Shape *shape = i->second->get_object().get_shape(); + if(shape) + bbox = bbox|shape->get_axis_aligned_bounding_box(); + } minp = bbox.get_minimum_point(); maxp = bbox.get_maximum_point(); -- 2.43.0 From e37f7bfbbee86eef3b1f6e338a21239905911608 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 21 Nov 2013 17:04:25 +0200 Subject: [PATCH 02/16] Add button_release handler to Tool --- source/designer/tool.cpp | 1 + source/designer/tool.h | 1 + 2 files changed, 2 insertions(+) diff --git a/source/designer/tool.cpp b/source/designer/tool.cpp index 83ac15d..249259e 100644 --- a/source/designer/tool.cpp +++ b/source/designer/tool.cpp @@ -15,6 +15,7 @@ Tool::Tool(Designer &d, Input::Keyboard &keyboard, Input::Mouse &mouse): keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Tool::key_press), false)); keyboard.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Tool::key_release), false)); mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Tool::button_press), false)); + mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Tool::button_release), false)); mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Tool::axis_motion), false)); pointer.x = mouse.get_axis_value(0); diff --git a/source/designer/tool.h b/source/designer/tool.h index 3119bc0..48780ec 100644 --- a/source/designer/tool.h +++ b/source/designer/tool.h @@ -42,6 +42,7 @@ protected: virtual void key_press(unsigned); virtual void key_release(unsigned); virtual void button_press(unsigned); + virtual void button_release(unsigned) { } virtual void axis_motion(unsigned, float, float); virtual void pointer_motion() { } virtual void finish() { } -- 2.43.0 From 2220ba2f11705ea9a4e480603d43ab7ed4cf5a89 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 21 Nov 2013 17:12:12 +0200 Subject: [PATCH 03/16] Add editable terrain objects These will soon replace the base object in layout. It's still a bit rough along the edges, especially the editing tool. References to surface materials are also just a hint of things to come. --- data/terrain.tech | 7 + source/3d/layout.cpp | 3 + source/3d/terrain.cpp | 190 +++++++++++++++++++ source/3d/terrain.h | 45 +++++ source/designer/designer.cpp | 9 + source/designer/terraintool.cpp | 90 +++++++++ source/designer/terraintool.h | 32 ++++ source/engineer/engineer.cpp | 1 + source/libr2c2/catalogue.cpp | 12 ++ source/libr2c2/catalogue.h | 1 + source/libr2c2/layout.cpp | 23 +++ source/libr2c2/layout.h | 1 + source/libr2c2/terrain.cpp | 317 ++++++++++++++++++++++++++++++++ source/libr2c2/terrain.h | 118 ++++++++++++ source/libr2c2/terraintype.cpp | 51 +++++ source/libr2c2/terraintype.h | 50 +++++ terrain.dat | 9 + 17 files changed, 959 insertions(+) create mode 100644 data/terrain.tech create mode 100644 source/3d/terrain.cpp create mode 100644 source/3d/terrain.h create mode 100644 source/designer/terraintool.cpp create mode 100644 source/designer/terraintool.h create mode 100644 source/libr2c2/terrain.cpp create mode 100644 source/libr2c2/terrain.h create mode 100644 source/libr2c2/terraintype.cpp create mode 100644 source/libr2c2/terraintype.h create mode 100644 terrain.dat diff --git a/data/terrain.tech b/data/terrain.tech new file mode 100644 index 0000000..35fb0e0 --- /dev/null +++ b/data/terrain.tech @@ -0,0 +1,7 @@ +pass "" +{ + material + { + diffuse 0.88 0.9 0.6 1.0; + }; +}; diff --git a/source/3d/layout.cpp b/source/3d/layout.cpp index be19b00..fdb4dfc 100644 --- a/source/3d/layout.cpp +++ b/source/3d/layout.cpp @@ -1,6 +1,7 @@ #include "beamgate.h" #include "layout.h" #include "signal.h" +#include "terrain.h" #include "track.h" #include "utility.h" #include "vehicle.h" @@ -86,6 +87,8 @@ void Layout3D::object_added(Object &o) new Vehicle3D(*this, *v); else if(BeamGate *g = dynamic_cast(&o)) new BeamGate3D(*this, *g); + else if(Terrain *r = dynamic_cast(&o)) + new Terrain3D(*this, *r); } void Layout3D::object_removed(Object &o) diff --git a/source/3d/terrain.cpp b/source/3d/terrain.cpp new file mode 100644 index 0000000..8fbaa98 --- /dev/null +++ b/source/3d/terrain.cpp @@ -0,0 +1,190 @@ +#include +#include "libr2c2/terraintype.h" +#include "layout.h" +#include "terrain.h" + +using namespace Msp; + +namespace R2C2 { + +unsigned Terrain3D::surface_indices[] = +{ + 0, 1, 3, 0, 3, 2, + 1, 3, 2, 1, 2, 0 +}; + +unsigned Terrain3D::wall_indices[] = +{ + 1, 4, 5, 1, 5, 3, + 3, 7, 6, 3, 6, 2 +}; + +Terrain3D::Terrain3D(Layout3D &l, Terrain &t): + Object3D(l, t), + terrain(t), + mesh((GL::VERTEX3, GL::NORMAL3)), + tech(layout.get_catalogue().get("terrain.tech")) +{ + terrain.signal_size_changed.connect(sigc::mem_fun(this, &Terrain3D::size_changed)); + terrain.signal_tile_changed.connect(sigc::bind<2>(sigc::mem_fun(this, &Terrain3D::tile_changed), true)); + + create_mesh(); + + layout.get_scene().add(*this); +} + +Terrain3D::~Terrain3D() +{ + layout.get_scene().remove(*this); +} + +Vector Terrain3D::get_node() const +{ + float ts = terrain.get_type().get_tile_size(); + return terrain.get_position()+Vector(terrain.get_width()*ts/2, terrain.get_height()*ts/2, 0); +} + +void Terrain3D::create_mesh() +{ + mesh.clear(); + + GL::MeshBuilder bld(mesh); + unsigned width = terrain.get_width(); + unsigned height = terrain.get_height(); + bld.begin(GL::TRIANGLES); + for(unsigned y=0; y0) + tile_changed(x-1, y, false); + if(y>0) + tile_changed(x, y-1, false); + } +} + +void Terrain3D::render(GL::Renderer &renderer, const GL::Tag &tag) const +{ + if(!tech.has_pass(tag)) + return; + + GL::Renderer::Push push(renderer); + + renderer.matrix_stack() *= matrix; + + const GL::RenderPass &pass = tech.get_pass(tag); + renderer.set_material(pass.get_material()); + renderer.set_texturing(pass.get_texturing()); + renderer.set_shader_program(pass.get_shader_program(), pass.get_shader_data()); + + mesh.draw(renderer); +} + +} // namespace R2C2 diff --git a/source/3d/terrain.h b/source/3d/terrain.h new file mode 100644 index 0000000..2cd9854 --- /dev/null +++ b/source/3d/terrain.h @@ -0,0 +1,45 @@ +#ifndef R2C2_3D_TERRAIN_H_ +#define R2C2_3D_TERRAIN_H_ + +#include +#include +#include +#include +#include "libr2c2/terrain.h" +#include "object.h" + +namespace R2C2 { + +class Terrain3D: public Object3D, public Msp::GL::Renderable +{ +private: + Terrain &terrain; + Msp::GL::Mesh mesh; + const Msp::GL::Technique &tech; + + static unsigned surface_indices[]; + static unsigned wall_indices[]; + +public: + Terrain3D(Layout3D &, Terrain &); + virtual ~Terrain3D(); + + virtual Vector get_node() const; + virtual bool is_visible() const { return true; } + +private: + void create_mesh(); + void gather_nodes(unsigned, unsigned, Vector *); + void build_triangle(Msp::GL::PrimitiveBuilder &, const Vector *, const unsigned *); + void update_triangle(unsigned, const Vector *, const unsigned *); + + void size_changed(unsigned, unsigned); + void tile_changed(unsigned, unsigned, bool); + +public: + virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 6ae9c07..32fe423 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -17,6 +17,7 @@ #include #include #include "libr2c2/route.h" +#include "libr2c2/terrain.h" #include "libr2c2/tracktype.h" #include "libr2c2/zone.h" #include "3d/path.h" @@ -35,6 +36,7 @@ #include "selection.h" #include "slopetool.h" #include "svgexporter.h" +#include "terraintool.h" #include "trackbar.h" #include "zonebar.h" #include "zoneproperties.h" @@ -61,6 +63,7 @@ Designer::Designer(int argc, char **argv): // Setup catalogue and layout DataFile::load(catalogue, "tracks.dat"); + DataFile::load(catalogue, "terrain.dat"); cat_layout_3d = new Layout3D(catalogue.get_layout()); @@ -428,6 +431,12 @@ void Designer::key_press(unsigned key) svg_export(); else if(key==Msp::Input::KEY_P) object_properties(); + else if(key==Msp::Input::KEY_TAB) + { + Object *obj = selection.get_object(); + if(Terrain *terrain = dynamic_cast(obj)) + use_tool(new TerrainTool(*this, keyboard, mouse, *terrain)); + } } template diff --git a/source/designer/terraintool.cpp b/source/designer/terraintool.cpp new file mode 100644 index 0000000..46076ec --- /dev/null +++ b/source/designer/terraintool.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include "designer.h" +#include "terraintool.h" + +using namespace std; +using namespace Msp; +using namespace R2C2; + +TerrainTool::TerrainTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, Terrain &t): + Tool(d, k, m), + terrain(t), + marker((GL::VERTEX3, GL::COLOR4_UBYTE)), + dragging(false), + drag_start(0) +{ + designer.get_layout_3d().get_scene().add(*this); + + float ts = terrain.get_type().get_tile_size(); + GL::MeshBuilder bld(marker); + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(-ts/2, 0, -ts/4); + bld.vertex(ts/2, 0, -ts/4); + bld.vertex(-ts/2, 0, ts/4); + bld.vertex(ts/2, 0, ts/4); + bld.end(); + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(0, -ts/2, -ts/4); + bld.vertex(0, ts/2, -ts/4); + bld.vertex(0, -ts/2, ts/4); + bld.vertex(0, ts/2, ts/4); + bld.end(); +} + +TerrainTool::~TerrainTool() +{ + designer.get_layout_3d().get_scene().remove(*this); +} + +void TerrainTool::button_press(unsigned btn) +{ + if(btn==1) + { + dragging = true; + drag_start = pointer.y; + } +} + +void TerrainTool::button_release(unsigned btn) +{ + if(btn==1) + dragging = false; +} + +void TerrainTool::pointer_motion() +{ + if(dragging) + { + float d = (pointer.y-drag_start)*20; + + if(abs(d)>1) + { + float elev = terrain.get_node_elevation(highlight_node); + float eg = terrain.get_type().get_elevation_granularity(); + elev += eg*d; + terrain.set_node_elevation(highlight_node, elev, true); + marker_position = terrain.get_node_position(highlight_node); + + drag_start = pointer.y; + } + } + else + { + Ray ray = designer.get_view().create_ray(pointer.x, pointer.y); + highlight_node = terrain.get_closest_node(ray); + marker_position = terrain.get_node_position(highlight_node); + } +} + +void TerrainTool::render(GL::Renderer &renderer, const GL::Tag &tag) const +{ + if(tag.id) + return; + + GL::Renderer::Push push(renderer); + + renderer.matrix_stack() *= GL::Matrix::translation(marker_position); + marker.draw(renderer); +} diff --git a/source/designer/terraintool.h b/source/designer/terraintool.h new file mode 100644 index 0000000..f5f8354 --- /dev/null +++ b/source/designer/terraintool.h @@ -0,0 +1,32 @@ +#ifndef TERRAINTOOL_H_ +#define TERRAINTOOL_H_ + +#include +#include +#include "libr2c2/terrain.h" +#include "tool.h" + +class TerrainTool: public Tool, public Msp::GL::Renderable +{ +private: + R2C2::Terrain &terrain; + Msp::GL::Mesh marker; + R2C2::Terrain::NodeCoordinates highlight_node; + R2C2::Vector marker_position; + bool dragging; + float drag_start; + +public: + TerrainTool(Designer &, Msp::Input::Keyboard &, Msp::Input::Mouse &, R2C2::Terrain &); + virtual ~TerrainTool(); + +private: + virtual void button_press(unsigned); + virtual void button_release(unsigned); + virtual void pointer_motion(); + +public: + virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; +}; + +#endif diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index d0c879c..49edd48 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -71,6 +71,7 @@ Engineer::Engineer(int argc, char **argv): DataFile::load(catalogue, "tracks.dat"); DataFile::load(catalogue, "locos.dat"); DataFile::load(catalogue, "wagons.dat"); + DataFile::load(catalogue, "terrain.dat"); DataFile::load(layout, options.layout_fn); if(layout.has_driver()) diff --git a/source/libr2c2/catalogue.cpp b/source/libr2c2/catalogue.cpp index 221a6f0..779e210 100644 --- a/source/libr2c2/catalogue.cpp +++ b/source/libr2c2/catalogue.cpp @@ -3,6 +3,7 @@ #include #include "catalogue.h" #include "signaltype.h" +#include "terraintype.h" #include "tracktype.h" #include "vehicletype.h" @@ -49,6 +50,7 @@ Catalogue::Loader::Loader(Catalogue &c): add("rail_profile", &Loader::rail_profile); add("scale", &Loader::scale); add("signal", &Loader::signal); + add("terrain", &Loader::terrain); add("track", &Loader::track); add("track_technique", &Catalogue::track_technique); add("vehicle", &Loader::vehicle); @@ -89,6 +91,16 @@ void Catalogue::Loader::signal(ArticleNumber art_nr) obj.add(*sig.release()); } +void Catalogue::Loader::terrain(ArticleNumber art_nr) +{ + if(obj.objects.count(art_nr)) + throw key_error(art_nr); + + RefPtr ter = new TerrainType(art_nr); + load_sub(*ter); + obj.add(*ter.release()); +} + void Catalogue::Loader::track(ArticleNumber art_nr) { if(obj.objects.count(art_nr)) diff --git a/source/libr2c2/catalogue.h b/source/libr2c2/catalogue.h index dcde9f3..5a91560 100644 --- a/source/libr2c2/catalogue.h +++ b/source/libr2c2/catalogue.h @@ -25,6 +25,7 @@ public: void rail_profile(); void scale(float, float); void signal(ArticleNumber); + void terrain(ArticleNumber); void track(ArticleNumber); void vehicle(ArticleNumber); }; diff --git a/source/libr2c2/layout.cpp b/source/libr2c2/layout.cpp index c23ad38..0025ec3 100644 --- a/source/libr2c2/layout.cpp +++ b/source/libr2c2/layout.cpp @@ -13,6 +13,7 @@ #include "route.h" #include "signal.h" #include "signaltype.h" +#include "terrain.h" #include "track.h" #include "trackcircuit.h" #include "tracktype.h" @@ -135,6 +136,12 @@ const set &Layout::get_all() const return objects.get(); } +template<> +const set &Layout::get_all() const +{ + return objects.get(); +} + template<> const set &Layout::get_all() const { @@ -414,6 +421,15 @@ void Layout::save(const string &fn) const writer.write(st); } + const set &terrains = objects.get(); + for(set::const_iterator i=terrains.begin(); i!=terrains.end(); ++i) + { + DataFile::Statement st("terrain"); + st.append((*i)->get_type().get_article_number()); + (*i)->save(st.sub); + writer.write(st); + } + const set &gates = objects.get(); for(set::const_iterator i=gates.begin(); i!=gates.end(); ++i) { @@ -534,6 +550,7 @@ Layout::Loader::Loader(Layout &l): add("beamgate", &Loader::beamgate); add("route", &Loader::route); add("signal", &Loader::signal); + add("terrain", &Loader::terrain); add("track", &Loader::track); add("train", &Loader::train); add("turnout", &Loader::turnout); @@ -558,6 +575,12 @@ void Layout::Loader::signal(ArticleNumber art_nr) load_sub(*sig); } +void Layout::Loader::terrain(ArticleNumber art_nr) +{ + Terrain *ter = new Terrain(obj, obj.catalogue.get(art_nr)); + load_sub(*ter); +} + void Layout::Loader::track(ArticleNumber art_nr) { Track *trk = new Track(obj, obj.catalogue.get(art_nr)); diff --git a/source/libr2c2/layout.h b/source/libr2c2/layout.h index d1428cf..498a45a 100644 --- a/source/libr2c2/layout.h +++ b/source/libr2c2/layout.h @@ -36,6 +36,7 @@ public: void beamgate(); void route(); void signal(ArticleNumber); + void terrain(ArticleNumber); void track(ArticleNumber); void train(ArticleNumber, unsigned, const std::string &); void turnout(unsigned, unsigned); diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp new file mode 100644 index 0000000..e84c7cd --- /dev/null +++ b/source/libr2c2/terrain.cpp @@ -0,0 +1,317 @@ +#include +#include +#include "layout.h" +#include "terrain.h" +#include "terraintype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Terrain::Terrain(Layout &l, const TerrainType &t): + Object(l), + type(t), + width(0), + height(0) +{ + set_size(1, 1); + + layout.add(*this); +} + +Terrain::~Terrain() +{ + layout.remove(*this); +} + +Terrain *Terrain::clone(Layout *to_layout) const +{ + Terrain *terrain = new Terrain((to_layout ? *to_layout : layout), type); + terrain->set_size(width, height); + for(unsigned i=0; itiles[i] = tiles[i]; + return terrain; +} + +void Terrain::set_position(const Vector &p) +{ + position = p; + signal_moved.emit(); +} + +void Terrain::set_rotation(const Angle &r) +{ + rotation = r; + signal_moved.emit(); +} + +void Terrain::set_size(unsigned w, unsigned h) +{ + if(!w || !h) + throw invalid_argument("Terrain::set_size"); + + vector new_tiles(w*h); + for(unsigned y=0; (y( + Geometry::Box(dim), + Transform::translation(dim/2.0f)); + + signal_size_changed.emit(width, height); +} + +const Terrain::Tile &Terrain::get_tile(unsigned x, unsigned y) const +{ + if(x>=width || y>=height) + throw out_of_range("Terrain::get_tile"); + return tiles[x+y*width]; +} + +void Terrain::set_node_elevation(const NodeCoordinates &c, float elev, bool joined) +{ + if(c.x>=width || c.y>=height || c.i>=4) + throw out_of_range("Terrain::set_node_elevation"); + + float eg = type.get_elevation_granularity(); + elev = int(elev/eg+0.5)*eg; + + if(joined) + { + float ref = tiles[c.x+c.y*width].nodes[c.i].elevation; + for(unsigned i=0; i<4; ++i) + { + unsigned x = c.x+c.i%2-i%2; + unsigned y = c.y+c.i/2-i/2; + if(x=width || c.y>=height || c.i>=4) + throw out_of_range("Terrain::get_node_elevation"); + + return tiles[c.x+c.y*width].nodes[c.i].elevation; +} + +Vector Terrain::get_node_position(const NodeCoordinates &c) const +{ + if(c.x>=width || c.y>=height || c.i>=4) + throw out_of_range("Terrain::get_node_position"); + + const Tile &tile = tiles[c.x+c.y*width]; + float tile_size = type.get_tile_size(); + Transform trans = Transform::translation(position)* + Transform::rotation(rotation, Vector(0, 0, 1)); + return trans.transform(Vector((c.x+c.i%2)*tile_size, (c.y+c.i/2)*tile_size, tile.nodes[c.i].elevation)); +} + +Terrain::NodeCoordinates Terrain::get_closest_node(const Ray &ray) const +{ + NodeCoordinates coords; + float closest_dist = -1; + for(unsigned y=0; y &st) const +{ + st.push_back((DataFile::Statement("size"), width, height)); + for(vector::const_iterator i=tiles.begin(); i!=tiles.end(); ++i) + { + DataFile::Statement ss("tile"); + i->save(ss.sub); + st.push_back(ss); + } +} + + +Terrain::Node::Node(): + elevation(0), + ground(0), + wall(0) +{ } + +void Terrain::Node::save(list &st) const +{ + st.push_back((DataFile::Statement("elevation"), elevation)); + st.push_back((DataFile::Statement("ground"), ground)); +} + + +Terrain::Tile::Tile(): + secondary_axis(false) +{ } + +void Terrain::Tile::save(list &st) const +{ + bool flat = true; + for(unsigned i=1; (flat && i<4); ++i) + flat = (nodes[i].elevation==nodes[0].elevation && nodes[i].ground==nodes[0].ground && nodes[i].wall==nodes[0].wall); + if(flat) + { + st.push_back((DataFile::Statement("elevation"), nodes[0].elevation)); + st.push_back((DataFile::Statement("ground"), nodes[0].ground)); + } + else + { + for(unsigned i=0; i<4; ++i) + { + DataFile::Statement ss("node"); + ss.append(i); + nodes[i].save(ss.sub); + st.push_back(ss); + } + } +} + + +Terrain::NodeCoordinates::NodeCoordinates(): + x(0), + y(0), + i(0) +{ } + +Terrain::NodeCoordinates::NodeCoordinates(unsigned x_, unsigned y_, unsigned i_): + x(x_), + y(y_), + i(i_) +{ } + + +Terrain::Loader::Loader(Terrain &t): + DataFile::ObjectLoader(t), + next_tile(0) +{ + add("position", &Loader::position); + add("rotation", &Loader::rotation); + add("size", &Loader::size); + add("tile", &Loader::tile); + add("tile", &Loader::tile_coords); +} + +void Terrain::Loader::position(float x, float y, float z) +{ + obj.set_position(Vector(x, y, z)); +} + +void Terrain::Loader::rotation(float a) +{ + obj.set_rotation(Angle::from_radians(a)); +} + +void Terrain::Loader::size(unsigned w, unsigned h) +{ + obj.set_size(w, h); +} + +void Terrain::Loader::tile() +{ + if(next_tile>=obj.tiles.size()) + throw runtime_error("Terrain::Loader::tile"); + + Tile &t = obj.tiles[next_tile]; + Tile::Loader ldr(obj, t); + load_sub_with(ldr); + unsigned x = next_tile%obj.width; + unsigned y = next_tile/obj.width; + ++next_tile; + obj.signal_tile_changed.emit(x, y); +} + +void Terrain::Loader::tile_coords(unsigned x, unsigned y) +{ + if(x>=obj.width || y>=obj.height) + throw out_of_range("Terrain::Loader::tile"); + next_tile = x+y*obj.width; + tile(); +} + + +Terrain::Node::Loader::Loader(Terrain &t, Node &n): + DataFile::ObjectLoader(n), + terrain(t) +{ + add("ground", &Loader::ground); + add("elevation", &Node::elevation); +} + +void Terrain::Node::Loader::ground(unsigned g) +{ + if(g>=terrain.type.get_n_surface_types()) + throw out_of_range("Tile::Loader::surface"); + obj.ground = g; +} + + +Terrain::Tile::Loader::Loader(Terrain &t, Tile &l): + DataFile::ObjectLoader(l), + terrain(t) +{ + add("ground", &Loader::ground); + add("elevation", &Loader::elevation); + add("node", &Loader::node); +} + +void Terrain::Tile::Loader::ground(unsigned g) +{ + if(g>=terrain.type.get_n_surface_types()) + throw out_of_range("Tile::Loader::surface"); + for(unsigned i=0; i<4; ++i) + obj.nodes[i].ground = g; +} + +void Terrain::Tile::Loader::elevation(float h) +{ + for(unsigned i=0; i<4; ++i) + obj.nodes[i].elevation = h; +} + +void Terrain::Tile::Loader::node(unsigned i) +{ + if(i>=4) + throw out_of_range("Tile::Loader::node"); + Node::Loader ldr(terrain, obj.nodes[i]); + load_sub_with(ldr); +} + +} // namespace R2C2 diff --git a/source/libr2c2/terrain.h b/source/libr2c2/terrain.h new file mode 100644 index 0000000..837119e --- /dev/null +++ b/source/libr2c2/terrain.h @@ -0,0 +1,118 @@ +#ifndef LIBR2C2_TERRAIN_H_ +#define LIBR2C2_TERRAIN_H_ + +#include "object.h" +#include "terraintype.h" + +namespace R2C2 { + +class Terrain: public Object +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + private: + unsigned next_tile; + + public: + Loader(Terrain &); + + private: + void position(float, float, float); + void rotation(float); + void size(unsigned, unsigned); + void tile(); + void tile_coords(unsigned, unsigned); + }; + + struct Node + { + class Loader: public Msp::DataFile::ObjectLoader + { + private: + Terrain &terrain; + + public: + Loader(Terrain &, Node &); + + private: + void ground(unsigned); + }; + + float elevation; + unsigned ground; + unsigned wall; + + Node(); + + void save(std::list &) const; + }; + + struct Tile + { + class Loader: public Msp::DataFile::ObjectLoader + { + private: + Terrain &terrain; + + public: + Loader(Terrain &, Tile &); + + private: + void ground(unsigned); + void elevation(float); + void node(unsigned); + }; + + Node nodes[4]; + bool secondary_axis; + + Tile(); + + void save(std::list &) const; + }; + + struct NodeCoordinates + { + unsigned x, y; + unsigned i; + + NodeCoordinates(); + NodeCoordinates(unsigned, unsigned, unsigned); + }; + + sigc::signal signal_size_changed; + sigc::signal signal_tile_changed; + +private: + const TerrainType &type; + unsigned width; + unsigned height; + std::vector tiles; + +public: + Terrain(Layout &, const TerrainType &); + virtual ~Terrain(); + + virtual Terrain *clone(Layout *) const; + + virtual const TerrainType &get_type() const { return type; } + virtual void set_position(const Vector &); + virtual void set_rotation(const Angle &); + virtual void set_tilt(const Angle &) { } + + void set_size(unsigned, unsigned); + unsigned get_width() const { return width; } + unsigned get_height() const { return height; } + const Tile &get_tile(unsigned, unsigned) const; + void set_node_elevation(const NodeCoordinates &, float, bool = false); + float get_node_elevation(const NodeCoordinates &) const; + Vector get_node_position(const NodeCoordinates &) const; + NodeCoordinates get_closest_node(const Ray &) const; + + void save(std::list &) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/terraintype.cpp b/source/libr2c2/terraintype.cpp new file mode 100644 index 0000000..ce9551f --- /dev/null +++ b/source/libr2c2/terraintype.cpp @@ -0,0 +1,51 @@ +#include +#include "terraintype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +TerrainType::TerrainType(const ArticleNumber &an): + ObjectType(an), + tile_size(1), + elevation_granularity(0.1) +{ } + +const TerrainType::SurfaceType &TerrainType::get_surface_type(unsigned i) const +{ + if(i>=surface_types.size()) + throw out_of_range("TerrainType::get_surface_type"); + return surface_types[i]; +} + + +TerrainType::SurfaceType::SurfaceType(): + r(0.8), + g(0.8), + b(0.8) +{ } + + +TerrainType::Loader::Loader(TerrainType &tt): + DataFile::ObjectLoader(tt) +{ + add("elevation_granularity", &TerrainType::elevation_granularity); + add("surface", &Loader::surface); + add("tile_size", &TerrainType::tile_size); +} + +void TerrainType::Loader::surface() +{ + SurfaceType srf; + load_sub(srf); + obj.surface_types.push_back(srf); +} + + +TerrainType::SurfaceType::Loader::Loader(SurfaceType &st): + DataFile::ObjectLoader(st) +{ +} + +} // namespace R2C2 diff --git a/source/libr2c2/terraintype.h b/source/libr2c2/terraintype.h new file mode 100644 index 0000000..f0013ad --- /dev/null +++ b/source/libr2c2/terraintype.h @@ -0,0 +1,50 @@ +#ifndef LIBR2C2_TERRAINTYPE_H_ +#define LIBR2C2_TERRAINTYPE_H_ + +#include +#include "objecttype.h" + +namespace R2C2 { + +class TerrainType: public ObjectType +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(TerrainType &); + + private: + void surface(); + }; + + struct SurfaceType + { + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(SurfaceType &); + }; + + float r, g, b; + + SurfaceType(); + }; + +private: + std::vector surface_types; + float tile_size; + float elevation_granularity; + +public: + TerrainType(const ArticleNumber &); + + unsigned get_n_surface_types() const { return surface_types.size(); } + const SurfaceType &get_surface_type(unsigned) const; + float get_tile_size() const { return tile_size; } + float get_elevation_granularity() const { return elevation_granularity; } +}; + +} // namespace R2C2 + +#endif diff --git a/terrain.dat b/terrain.dat new file mode 100644 index 0000000..df47ef5 --- /dev/null +++ b/terrain.dat @@ -0,0 +1,9 @@ +terrain \100001 +{ + surface + { + }; + + tile_size 0.05; + elevation_granularity 0.0125; +}; -- 2.43.0 From 6b90a1c8bb9efff7f660e352bf69a02992d620cc Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 21 Nov 2013 19:41:15 +0200 Subject: [PATCH 04/16] More efficient picking of terrain nodes --- source/libr2c2/terrain.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index e84c7cd..d4f3e41 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -132,6 +132,11 @@ Vector Terrain::get_node_position(const NodeCoordinates &c) const Terrain::NodeCoordinates Terrain::get_closest_node(const Ray &ray) const { + Transform reverse_trans = Transform::rotation(rotation, Vector(0, 0, -1))* + Transform::translation(-position); + Ray local_ray = reverse_trans.transform(ray); + + float ts = type.get_tile_size(); NodeCoordinates coords; float closest_dist = -1; for(unsigned y=0; y Date: Thu, 21 Nov 2013 19:48:50 +0200 Subject: [PATCH 05/16] Edit a single terrain node at a time if shift is held --- source/designer/terraintool.cpp | 70 ++++++++++++++++++++++++++------- source/designer/terraintool.h | 5 +++ source/libr2c2/terrain.cpp | 2 +- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/source/designer/terraintool.cpp b/source/designer/terraintool.cpp index 46076ec..5dddb82 100644 --- a/source/designer/terraintool.cpp +++ b/source/designer/terraintool.cpp @@ -12,25 +12,13 @@ TerrainTool::TerrainTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, Terra Tool(d, k, m), terrain(t), marker((GL::VERTEX3, GL::COLOR4_UBYTE)), + marker_orientation(0), dragging(false), drag_start(0) { designer.get_layout_3d().get_scene().add(*this); - float ts = terrain.get_type().get_tile_size(); - GL::MeshBuilder bld(marker); - bld.begin(GL::TRIANGLE_STRIP); - bld.vertex(-ts/2, 0, -ts/4); - bld.vertex(ts/2, 0, -ts/4); - bld.vertex(-ts/2, 0, ts/4); - bld.vertex(ts/2, 0, ts/4); - bld.end(); - bld.begin(GL::TRIANGLE_STRIP); - bld.vertex(0, -ts/2, -ts/4); - bld.vertex(0, ts/2, -ts/4); - bld.vertex(0, -ts/2, ts/4); - bld.vertex(0, ts/2, ts/4); - bld.end(); + update_marker(); } TerrainTool::~TerrainTool() @@ -38,6 +26,56 @@ TerrainTool::~TerrainTool() designer.get_layout_3d().get_scene().remove(*this); } +void TerrainTool::update_marker() +{ + marker.clear(); + GL::MeshBuilder bld(marker); + + float ts = terrain.get_type().get_tile_size(); + if(shift_held) + { + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(0, ts/2, ts/4); + bld.vertex(0, ts/2, -ts/4); + bld.vertex(0, 0, ts/4); + bld.vertex(0, 0, -ts/4); + bld.vertex(ts/2, 0, ts/4); + bld.vertex(ts/2, 0, -ts/4); + bld.end(); + } + else + { + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(-ts/2, 0, ts/4); + bld.vertex(-ts/2, 0, -ts/4); + bld.vertex((edit_size+0.5)*ts, 0, ts/4); + bld.vertex((edit_size+0.5)*ts, 0, -ts/4); + bld.end(); + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(0, -ts/2, ts/4); + bld.vertex(0, -ts/2, -ts/4); + bld.vertex(0, (edit_size+0.5)*ts, ts/4); + bld.vertex(0, (edit_size+0.5)*ts, -ts/4); + bld.end(); + } +} + +void TerrainTool::key_press(unsigned key) +{ + bool shift_was_held = shift_held; + Tool::key_press(key); + if(shift_held!=shift_was_held) + update_marker(); +} + +void TerrainTool::key_release(unsigned key) +{ + bool shift_was_held = shift_held; + Tool::key_release(key); + if(shift_held!=shift_was_held) + update_marker(); +} + void TerrainTool::button_press(unsigned btn) { if(btn==1) @@ -64,7 +102,7 @@ void TerrainTool::pointer_motion() float elev = terrain.get_node_elevation(highlight_node); float eg = terrain.get_type().get_elevation_granularity(); elev += eg*d; - terrain.set_node_elevation(highlight_node, elev, true); + terrain.set_node_elevation(highlight_node, elev, !shift_held); marker_position = terrain.get_node_position(highlight_node); drag_start = pointer.y; @@ -75,6 +113,7 @@ void TerrainTool::pointer_motion() Ray ray = designer.get_view().create_ray(pointer.x, pointer.y); highlight_node = terrain.get_closest_node(ray); marker_position = terrain.get_node_position(highlight_node); + marker_orientation = highlight_node.i^(highlight_node.i>>1); } } @@ -86,5 +125,6 @@ void TerrainTool::render(GL::Renderer &renderer, const GL::Tag &tag) const GL::Renderer::Push push(renderer); renderer.matrix_stack() *= GL::Matrix::translation(marker_position); + renderer.matrix_stack() *= GL::Matrix::rotation(Angle::from_turns(marker_orientation*0.25), 0, 0, 1); marker.draw(renderer); } diff --git a/source/designer/terraintool.h b/source/designer/terraintool.h index f5f8354..e844ba2 100644 --- a/source/designer/terraintool.h +++ b/source/designer/terraintool.h @@ -13,6 +13,7 @@ private: Msp::GL::Mesh marker; R2C2::Terrain::NodeCoordinates highlight_node; R2C2::Vector marker_position; + unsigned marker_orientation; bool dragging; float drag_start; @@ -21,6 +22,10 @@ public: virtual ~TerrainTool(); private: + void update_marker(); + + virtual void key_press(unsigned); + virtual void key_release(unsigned); virtual void button_press(unsigned); virtual void button_release(unsigned); virtual void pointer_motion(); diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index d4f3e41..5a31774 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -144,7 +144,7 @@ Terrain::NodeCoordinates Terrain::get_closest_node(const Ray &ray) const for(unsigned i=0; i<4; ++i) { NodeCoordinates c(x, y, i); - Vector node_pos((x+i%2)*ts, (y+i/2)*ts, get_node_elevation(c)); + Vector node_pos((x+0.25+(i%2)*0.5)*ts, (y+0.25+(i/2)*0.5)*ts, get_node_elevation(c)); Vector v = node_pos-local_ray.get_start(); float dist = (v-local_ray.get_direction()*dot(local_ray.get_direction(), v)).norm(); if(closest_dist<0 || dist Date: Fri, 22 Nov 2013 01:33:30 +0200 Subject: [PATCH 06/16] Automatically adjust the secondary_axis flag when elevations are changed --- source/libr2c2/terrain.cpp | 10 ++++++++-- source/libr2c2/terrain.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index 5a31774..072a6e5 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -97,7 +97,7 @@ void Terrain::set_node_elevation(const NodeCoordinates &c, float elev, bool join Tile &tile = tiles[x+y*width]; if(tile.nodes[i].elevation==ref) { - tile.nodes[i].elevation = elev; + tile.set_node_elevation(i, elev); signal_tile_changed.emit(x, y); } } @@ -105,7 +105,7 @@ void Terrain::set_node_elevation(const NodeCoordinates &c, float elev, bool join } else { - tiles[c.x+c.y*width].nodes[c.i].elevation = elev; + tiles[c.x+c.y*width].set_node_elevation(c.i, elev); signal_tile_changed.emit(c.x, c.y); } } @@ -186,6 +186,12 @@ Terrain::Tile::Tile(): secondary_axis(false) { } +void Terrain::Tile::set_node_elevation(unsigned i, float e) +{ + nodes[i].elevation = e; + secondary_axis = ((nodes[1].elevation+nodes[2].elevation) < (nodes[0].elevation+nodes[3].elevation)); +} + void Terrain::Tile::save(list &st) const { bool flat = true; diff --git a/source/libr2c2/terrain.h b/source/libr2c2/terrain.h index 837119e..fb3328e 100644 --- a/source/libr2c2/terrain.h +++ b/source/libr2c2/terrain.h @@ -69,6 +69,7 @@ public: Tile(); + void set_node_elevation(unsigned, float); void save(std::list &) const; }; -- 2.43.0 From 128f774b5687d3b816e7604876ea6520f54d66bc Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 01:34:38 +0200 Subject: [PATCH 07/16] Support editing multiple terrain tiles at once --- source/designer/terraintool.cpp | 92 +++++++++++++++++++++++++++++---- source/designer/terraintool.h | 1 + 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/source/designer/terraintool.cpp b/source/designer/terraintool.cpp index 5dddb82..4e339bc 100644 --- a/source/designer/terraintool.cpp +++ b/source/designer/terraintool.cpp @@ -12,6 +12,7 @@ TerrainTool::TerrainTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, Terra Tool(d, k, m), terrain(t), marker((GL::VERTEX3, GL::COLOR4_UBYTE)), + edit_size(0), marker_orientation(0), dragging(false), drag_start(0) @@ -32,15 +33,32 @@ void TerrainTool::update_marker() GL::MeshBuilder bld(marker); float ts = terrain.get_type().get_tile_size(); + bld.matrix() *= GL::Matrix::translation(edit_size/2*-ts, edit_size/2*-ts, 0); if(shift_held) { bld.begin(GL::TRIANGLE_STRIP); - bld.vertex(0, ts/2, ts/4); - bld.vertex(0, ts/2, -ts/4); - bld.vertex(0, 0, ts/4); - bld.vertex(0, 0, -ts/4); - bld.vertex(ts/2, 0, ts/4); - bld.vertex(ts/2, 0, -ts/4); + if(edit_size==0) + { + bld.vertex(0, ts/2, ts/4); + bld.vertex(0, ts/2, -ts/4); + bld.vertex(0, 0, ts/4); + bld.vertex(0, 0, -ts/4); + bld.vertex(ts/2, 0, ts/4); + bld.vertex(ts/2, 0, -ts/4); + } + else + { + bld.vertex(0, 0, ts/4); + bld.vertex(0, 0, -ts/4); + bld.vertex(edit_size*ts, 0, ts/4); + bld.vertex(edit_size*ts, 0, -ts/4); + bld.vertex(edit_size*ts, edit_size*ts, ts/4); + bld.vertex(edit_size*ts, edit_size*ts, -ts/4); + bld.vertex(0, edit_size*ts, ts/4); + bld.vertex(0, edit_size*ts, -ts/4); + bld.element(0); + bld.element(1); + } bld.end(); } else @@ -57,15 +75,46 @@ void TerrainTool::update_marker() bld.vertex(0, (edit_size+0.5)*ts, ts/4); bld.vertex(0, (edit_size+0.5)*ts, -ts/4); bld.end(); + if(edit_size>0) + { + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(-ts/2, edit_size*ts, ts/4); + bld.vertex(-ts/2, edit_size*ts, -ts/4); + bld.vertex((edit_size+0.5)*ts, edit_size*ts, ts/4); + bld.vertex((edit_size+0.5)*ts, edit_size*ts, -ts/4); + bld.end(); + bld.begin(GL::TRIANGLE_STRIP); + bld.vertex(edit_size*ts, -ts/2, ts/4); + bld.vertex(edit_size*ts, -ts/2, -ts/4); + bld.vertex(edit_size*ts, (edit_size+0.5)*ts, ts/4); + bld.vertex(edit_size*ts, (edit_size+0.5)*ts, -ts/4); + bld.end(); + } } } void TerrainTool::key_press(unsigned key) { - bool shift_was_held = shift_held; - Tool::key_press(key); - if(shift_held!=shift_was_held) + if(key==Input::KEY_PLUS) + { + ++edit_size; update_marker(); + } + else if(key==Input::KEY_MINUS) + { + if(edit_size>0) + { + --edit_size; + update_marker(); + } + } + else + { + bool shift_was_held = shift_held; + Tool::key_press(key); + if(shift_held!=shift_was_held) + update_marker(); + } } void TerrainTool::key_release(unsigned key) @@ -102,9 +151,30 @@ void TerrainTool::pointer_motion() float elev = terrain.get_node_elevation(highlight_node); float eg = terrain.get_type().get_elevation_granularity(); elev += eg*d; - terrain.set_node_elevation(highlight_node, elev, !shift_held); - marker_position = terrain.get_node_position(highlight_node); + if(edit_size==0) + terrain.set_node_elevation(highlight_node, elev, !shift_held); + else + { + unsigned bx = highlight_node.x-edit_size/2; + unsigned by = highlight_node.y-edit_size/2; + if(edit_size%2==0) + { + bx += highlight_node.i%2; + by += highlight_node.i/2; + } + + // TODO make it possible to adjust the area without flattening it + for(unsigned y=0; y Date: Fri, 22 Nov 2013 01:39:13 +0200 Subject: [PATCH 08/16] Ignore beam gates and terrains in shoppinglist --- source/shoppinglist/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/shoppinglist/main.cpp b/source/shoppinglist/main.cpp index 94976a2..4f410f1 100644 --- a/source/shoppinglist/main.cpp +++ b/source/shoppinglist/main.cpp @@ -129,8 +129,10 @@ ShoppingList::LayoutLoader::LayoutLoader(ShoppingList &s): { add("track", &LayoutLoader::track); add("base"); + add("beamgate"); add("route"); add("signal"); + add("terrain"); add("zone"); } -- 2.43.0 From 3553ca7e70942fe3f5a534a4e27a6ae2dc82e0fe Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 11:39:23 +0200 Subject: [PATCH 09/16] Add property editing for terrain --- source/designer/objectproperties.cpp | 19 +++++++++++++++++++ source/designer/objectproperties.h | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/source/designer/objectproperties.cpp b/source/designer/objectproperties.cpp index af09033..70ddb60 100644 --- a/source/designer/objectproperties.cpp +++ b/source/designer/objectproperties.cpp @@ -63,6 +63,11 @@ ObjectProperties::ObjectProperties(const Selection &selection): lbl_title->set_text("Beam gate properties"); properties = new BeamGateProperties(*this, *gate); } + else if(Terrain *terrain = dynamic_cast(object)) + { + lbl_title->set_text("Terrain properties"); + properties = new TerrainProperties(*this, *terrain); + } } if(!properties) @@ -169,3 +174,17 @@ void ObjectProperties::BeamGateProperties::apply() { gate.set_address(lexical_cast(ent_address->get_text())); } + + +ObjectProperties::TerrainProperties::TerrainProperties(ObjectProperties &p, Terrain &t): + terrain(t), + ent_width(p.add_property("Width", lexical_cast(terrain.get_width()), 4)), + ent_height(p.add_property("Height", lexical_cast(terrain.get_height()), 4)) +{ } + +void ObjectProperties::TerrainProperties::apply() +{ + unsigned width = lexical_cast(ent_width->get_text()); + unsigned height = lexical_cast(ent_height->get_text()); + terrain.set_size(width, height); +} diff --git a/source/designer/objectproperties.h b/source/designer/objectproperties.h index 9180206..8433b68 100644 --- a/source/designer/objectproperties.h +++ b/source/designer/objectproperties.h @@ -5,6 +5,7 @@ #include #include "libr2c2/beamgate.h" #include "libr2c2/signal.h" +#include "libr2c2/terrain.h" #include "libr2c2/track.h" class Selection; @@ -70,6 +71,19 @@ private: virtual void apply(); }; + class TerrainProperties: public Properties + { + private: + R2C2::Terrain &terrain; + Msp::GLtk::Entry *ent_width; + Msp::GLtk::Entry *ent_height; + + public: + TerrainProperties(ObjectProperties &, R2C2::Terrain &); + + virtual void apply(); + }; + Properties *properties; Msp::GLtk::Widget *prev_widget; -- 2.43.0 From ab0e6fa3442459d0a299ef90618ab6886d075057 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 13:05:30 +0200 Subject: [PATCH 10/16] Improve tile axis calculation --- source/libr2c2/terrain.cpp | 8 +++++++- source/libr2c2/terrain.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index 072a6e5..502a8c7 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -189,7 +189,12 @@ Terrain::Tile::Tile(): void Terrain::Tile::set_node_elevation(unsigned i, float e) { nodes[i].elevation = e; - secondary_axis = ((nodes[1].elevation+nodes[2].elevation) < (nodes[0].elevation+nodes[3].elevation)); + update_axis(); +} + +void Terrain::Tile::update_axis() +{ + secondary_axis = (abs(nodes[1].elevation-nodes[2].elevation) < abs(nodes[0].elevation-nodes[3].elevation)); } void Terrain::Tile::save(list &st) const @@ -262,6 +267,7 @@ void Terrain::Loader::tile() Tile &t = obj.tiles[next_tile]; Tile::Loader ldr(obj, t); load_sub_with(ldr); + t.update_axis(); unsigned x = next_tile%obj.width; unsigned y = next_tile/obj.width; ++next_tile; diff --git a/source/libr2c2/terrain.h b/source/libr2c2/terrain.h index fb3328e..01571cc 100644 --- a/source/libr2c2/terrain.h +++ b/source/libr2c2/terrain.h @@ -70,6 +70,7 @@ public: Tile(); void set_node_elevation(unsigned, float); + void update_axis(); void save(std::list &) const; }; -- 2.43.0 From f459a73d543b663afeb5a7b4796b04f76860e383 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 13:05:57 +0200 Subject: [PATCH 11/16] Save terrain position and rotation --- source/libr2c2/terrain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index 502a8c7..7b8f9f5 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -159,6 +159,8 @@ Terrain::NodeCoordinates Terrain::get_closest_node(const Ray &ray) const void Terrain::save(list &st) const { + st.push_back((DataFile::Statement("position"), position.x, position.y, position.z)); + st.push_back((DataFile::Statement("rotation"), rotation.radians())); st.push_back((DataFile::Statement("size"), width, height)); for(vector::const_iterator i=tiles.begin(); i!=tiles.end(); ++i) { -- 2.43.0 From e536be49146f43aae6aaaa4455eb44d8e170a773 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 13:09:16 +0200 Subject: [PATCH 12/16] Produce more compact saves of terrains --- source/libr2c2/terrain.cpp | 44 ++++++++++++++++++++++++-------------- source/libr2c2/terrain.h | 2 ++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index 7b8f9f5..e012bc9 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -201,26 +201,38 @@ void Terrain::Tile::update_axis() void Terrain::Tile::save(list &st) const { - bool flat = true; - for(unsigned i=1; (flat && i<4); ++i) - flat = (nodes[i].elevation==nodes[0].elevation && nodes[i].ground==nodes[0].ground && nodes[i].wall==nodes[0].wall); - if(flat) - { - st.push_back((DataFile::Statement("elevation"), nodes[0].elevation)); - st.push_back((DataFile::Statement("ground"), nodes[0].ground)); - } - else + float elevation_mode = find_mode(&Node::elevation); + unsigned ground_mode = find_mode(&Node::ground); + if(elevation_mode) + st.push_back((DataFile::Statement("elevation"), elevation_mode)); + if(ground_mode) + st.push_back((DataFile::Statement("ground"), ground_mode)); + + for(unsigned i=0; i<4; ++i) { - for(unsigned i=0; i<4; ++i) - { - DataFile::Statement ss("node"); - ss.append(i); - nodes[i].save(ss.sub); - st.push_back(ss); - } + if(nodes[i].elevation==elevation_mode && nodes[i].ground==ground_mode) + continue; + + DataFile::Statement ss("node"); + ss.append(i); + if(nodes[i].elevation!=elevation_mode) + ss.sub.push_back((DataFile::Statement("elevation"), nodes[i].elevation)); + if(nodes[i].ground!=ground_mode) + ss.sub.push_back((DataFile::Statement("ground"), nodes[i].ground)); + st.push_back(ss); } } +template +T Terrain::Tile::find_mode(T Node::*member) const +{ + for(unsigned i=0; i<3; ++i) + for(unsigned j=i+1; j<4; ++j) + if(nodes[i].*member==nodes[j].*member) + return nodes[i].*member; + return T(); +} + Terrain::NodeCoordinates::NodeCoordinates(): x(0), diff --git a/source/libr2c2/terrain.h b/source/libr2c2/terrain.h index 01571cc..5b5a889 100644 --- a/source/libr2c2/terrain.h +++ b/source/libr2c2/terrain.h @@ -72,6 +72,8 @@ public: void set_node_elevation(unsigned, float); void update_axis(); void save(std::list &) const; + template + T find_mode(T Node::*) const; }; struct NodeCoordinates -- 2.43.0 From 1bf9fc295f4cf06d976f02ca214b05da6c7c81f7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 13:09:36 +0200 Subject: [PATCH 13/16] Add a terrain object to the catalogue layout --- terrain.dat | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/terrain.dat b/terrain.dat index df47ef5..e32551d 100644 --- a/terrain.dat +++ b/terrain.dat @@ -7,3 +7,91 @@ terrain \100001 tile_size 0.05; elevation_granularity 0.0125; }; + +layout +{ + terrain \100001 + { + position 0.1519720 0.2448861 0.000000; + rotation 0.000000; + size 3 3; + tile + { + node 3 + { + elevation 0.05000000; + }; + }; + tile + { + node 2 + { + elevation 0.05000000; + }; + node 3 + { + elevation 0.05000000; + }; + }; + tile + { + node 2 + { + elevation 0.05000000; + }; + }; + tile + { + node 1 + { + elevation 0.05000000; + }; + node 3 + { + elevation 0.05000000; + }; + }; + tile + { + elevation 0.05000000; + }; + tile + { + elevation 0.05000000; + node 1 + { + elevation 0.000000; + }; + node 3 + { + elevation 0.000000; + }; + }; + tile + { + node 1 + { + elevation 0.05000000; + }; + }; + tile + { + elevation 0.05000000; + node 2 + { + elevation 0.000000; + }; + node 3 + { + elevation 0.000000; + }; + }; + tile + { + node 0 + { + elevation 0.05000000; + }; + }; + }; +}; -- 2.43.0 From db0146da06b7db507a510eed7b53aa59905b38ac Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 13:21:30 +0200 Subject: [PATCH 14/16] Make BeamGate compile with older GCC versions GCC 4.6 produces ambiguity errors despite the using directive in the class declaration. --- source/libr2c2/beamgate.cpp | 8 ++++---- source/libr2c2/beamgate.h | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/source/libr2c2/beamgate.cpp b/source/libr2c2/beamgate.cpp index 698cb45..463a3a9 100644 --- a/source/libr2c2/beamgate.cpp +++ b/source/libr2c2/beamgate.cpp @@ -13,17 +13,17 @@ BeamGate::BeamGate(Layout &l): { invert = true; - layout.add(*this); + TrackAttachment::layout.add(*this); } BeamGate::~BeamGate() { - layout.remove(*this); + TrackAttachment::layout.remove(*this); } BeamGate *BeamGate::clone(Layout *to_layout) const { - BeamGate *gate = new BeamGate(to_layout ? *to_layout : layout); + BeamGate *gate = new BeamGate(to_layout ? *to_layout : TrackAttachment::layout); gate->set_position(position); gate->set_rotation(rotation); return gate; @@ -50,7 +50,7 @@ void BeamGate::set_rotation(const Angle &r) void BeamGate::update_attachment() { - attach_to_closest(100*layout.get_catalogue().get_gauge()); + attach_to_closest(100*TrackAttachment::layout.get_catalogue().get_gauge()); if(track) { diff --git a/source/libr2c2/beamgate.h b/source/libr2c2/beamgate.h index 8a3afe4..bcb4f4d 100644 --- a/source/libr2c2/beamgate.h +++ b/source/libr2c2/beamgate.h @@ -20,10 +20,6 @@ public: void rotation(float); }; -private: - using TrackAttachment::layout; - -public: BeamGate(Layout &); virtual ~BeamGate(); -- 2.43.0 From d6816c177ee8d5f5191e833dce8e3c4e7e0222bf Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 14:43:24 +0200 Subject: [PATCH 15/16] Properly round negative elevations --- source/libr2c2/terrain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/libr2c2/terrain.cpp b/source/libr2c2/terrain.cpp index e012bc9..c89d0f8 100644 --- a/source/libr2c2/terrain.cpp +++ b/source/libr2c2/terrain.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "layout.h" @@ -83,7 +84,7 @@ void Terrain::set_node_elevation(const NodeCoordinates &c, float elev, bool join throw out_of_range("Terrain::set_node_elevation"); float eg = type.get_elevation_granularity(); - elev = int(elev/eg+0.5)*eg; + elev = floor(elev/eg+0.5)*eg; if(joined) { -- 2.43.0 From d405b9943c888e3945c7ea4e496f9d300b114fe0 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 22 Nov 2013 21:43:36 +0200 Subject: [PATCH 16/16] Move track appearance properties into a separate class MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This will eventually enable tracks with different appearance (such as Märklin C and K track) to coexist in the same catalogue. --- source/3d/catalogue.cpp | 27 +++++++++----- source/3d/catalogue.h | 6 ++-- source/3d/endpoint.cpp | 2 +- source/3d/tracktype.cpp | 7 ++-- source/designer/svgexporter.cpp | 6 ++-- source/libr2c2/catalogue.cpp | 26 ++++---------- source/libr2c2/catalogue.h | 13 ++----- source/libr2c2/trackappearance.cpp | 32 +++++++++++++++++ source/libr2c2/trackappearance.h | 37 ++++++++++++++++++++ source/libr2c2/tracktype.cpp | 3 +- source/libr2c2/tracktype.h | 6 +++- source/libr2c2/vehicle.cpp | 3 +- tracks.dat | 56 ++++++++++++++++-------------- 13 files changed, 147 insertions(+), 77 deletions(-) create mode 100644 source/libr2c2/trackappearance.cpp create mode 100644 source/libr2c2/trackappearance.h diff --git a/source/3d/catalogue.cpp b/source/3d/catalogue.cpp index 9daa7c8..e28237f 100644 --- a/source/3d/catalogue.cpp +++ b/source/3d/catalogue.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -14,8 +15,7 @@ using namespace Msp; namespace R2C2 { Catalogue3D::Catalogue3D(Catalogue &c): - catalogue(c), - endpoint_mesh((GL::NORMAL3, GL::VERTEX3)) + catalogue(c) { add_type().creator(&Catalogue3D::create); add_type().creator(&Catalogue3D::create); @@ -28,8 +28,6 @@ Catalogue3D::Catalogue3D(Catalogue &c): const Catalogue::ObjectMap &objs = catalogue.get_all(); for(Catalogue::ObjectMap::const_iterator i=objs.begin(); i!=objs.end(); ++i) object_added(*i->second); - - build_endpoint_mesh(); } Catalogue3D::~Catalogue3D() @@ -41,7 +39,12 @@ Catalogue3D::~Catalogue3D() void Catalogue3D::object_added(const ObjectType &ot) { if(const TrackType *tt = dynamic_cast(&ot)) + { objects[&ot] = new TrackType3D(*this, *tt); + const TrackAppearance &appearance = tt->get_appearance(); + if(!endpoint_meshes.count(&appearance)) + build_endpoint_mesh(appearance); + } else if(const SignalType *st = dynamic_cast(&ot)) objects[&ot] = new SignalType3D(*this, *st); else if(const VehicleType *vt = dynamic_cast(&ot)) @@ -53,13 +56,13 @@ const ObjectType3D &Catalogue3D::get_3d(const ObjectType &ot) const return *get_item(objects, &ot); } -void Catalogue3D::build_endpoint_mesh() +void Catalogue3D::build_endpoint_mesh(const TrackAppearance &appearance) { - const Profile &ballast_profile = catalogue.get_ballast_profile(); + 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(); - const Profile &rail_profile = catalogue.get_rail_profile(); + 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(); @@ -68,7 +71,8 @@ void Catalogue3D::build_endpoint_mesh() float width = max(max(-ballast_min.x, ballast_max.x)*2, gauge+(rail_max.x-rail_min.x)*2)+0.004; float height = ballast_max.y-ballast_min.y+rail_max.y-rail_min.y+0.01; - GL::MeshBuilder bld(endpoint_mesh); + GL::Mesh *mesh = new GL::Mesh((GL::NORMAL3, GL::VERTEX3)); + GL::MeshBuilder bld(*mesh); bld.normal(1, 0, 0); bld.begin(GL::QUADS); bld.vertex(0, width/2, 0); @@ -76,6 +80,13 @@ void Catalogue3D::build_endpoint_mesh() bld.vertex(0, -width/2, height); bld.vertex(0, -width/2, 0); bld.end(); + + endpoint_meshes[&appearance] = mesh; +} + +const GL::Mesh &Catalogue3D::get_endpoint_mesh(const TrackAppearance &appearance) const +{ + return *get_item(endpoint_meshes, &appearance); } FS::Path Catalogue3D::locate_file(const string &name) diff --git a/source/3d/catalogue.h b/source/3d/catalogue.h index 1cc096a..ea41828 100644 --- a/source/3d/catalogue.h +++ b/source/3d/catalogue.h @@ -17,7 +17,7 @@ class Catalogue3D: public Msp::DataFile::Collection private: Catalogue &catalogue; std::map objects; - Msp::GL::Mesh endpoint_mesh; + std::map endpoint_meshes; public: Catalogue3D(Catalogue &); @@ -34,9 +34,9 @@ public: { return dynamic_cast::Type3D &>(get_3d(static_cast(ot))); } private: - void build_endpoint_mesh(); + void build_endpoint_mesh(const TrackAppearance &); public: - const Msp::GL::Mesh &get_endpoint_mesh() const { return endpoint_mesh; } + const Msp::GL::Mesh &get_endpoint_mesh(const TrackAppearance &) const; private: Msp::FS::Path locate_file(const std::string &); diff --git a/source/3d/endpoint.cpp b/source/3d/endpoint.cpp index 97e05a4..aedd689 100644 --- a/source/3d/endpoint.cpp +++ b/source/3d/endpoint.cpp @@ -13,7 +13,7 @@ namespace R2C2 { Endpoint3D::Endpoint3D(const Track3D &t, unsigned i): track(t), index(i), - mesh(track.get_layout().get_catalogue().get_endpoint_mesh()) + mesh(track.get_layout().get_catalogue().get_endpoint_mesh(track.get_track().get_type().get_appearance())) { track.get_layout().get_endpoint_scene().add(*this); } diff --git a/source/3d/tracktype.cpp b/source/3d/tracktype.cpp index d73387c..d664c39 100644 --- a/source/3d/tracktype.cpp +++ b/source/3d/tracktype.cpp @@ -15,15 +15,16 @@ TrackType3D::TrackType3D(Catalogue3D &c, const TrackType &tt): object(0), own_data(false) { + const TrackAppearance &appearance = tt.get_appearance(); const Catalogue &cat = catalogue.get_catalogue(); const vector &parts = tt.get_parts(); - const Profile &ballast_profile = cat.get_ballast_profile(); + 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 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; @@ -53,7 +54,7 @@ TrackType3D::TrackType3D(Catalogue3D &c, const TrackType &tt): object = new GL::Object; object->set_mesh(mesh); - object->set_technique(&catalogue.get(cat.get_track_technique())); + object->set_technique(&catalogue.get(appearance.get_technique())); own_data = true; } diff --git a/source/designer/svgexporter.cpp b/source/designer/svgexporter.cpp index bb8cf4e..890112f 100644 --- a/source/designer/svgexporter.cpp +++ b/source/designer/svgexporter.cpp @@ -19,10 +19,8 @@ void SvgExporter::save(const string &fn) { gauge = layout.get_catalogue().get_gauge()*1000; - const Profile &rail_profile = layout.get_catalogue().get_rail_profile(); - const Vector &rail_min = rail_profile.get_min_coords(); - const Vector &rail_max = rail_profile.get_max_coords(); - rail_width = (rail_max.x-rail_min.x)*1000; + // XXX This should be retrieved from track appearance + rail_width = 2; xmlpp::Document *doc = new xmlpp::Document; xmlpp::Element *root = doc->create_root_node("svg", "http://www.w3.org/2000/svg"); diff --git a/source/libr2c2/catalogue.cpp b/source/libr2c2/catalogue.cpp index 779e210..2fdc21c 100644 --- a/source/libr2c2/catalogue.cpp +++ b/source/libr2c2/catalogue.cpp @@ -24,11 +24,6 @@ Catalogue::~Catalogue() delete i->second; } -float Catalogue::get_rail_elevation() const -{ - return ballast_profile.get_height()+rail_profile.get_height(); -} - void Catalogue::add(ObjectType &object) { insert_unique(objects, object.get_article_number(), &object); @@ -44,23 +39,16 @@ const ObjectType &Catalogue::get(const ArticleNumber &art_nr) const Catalogue::Loader::Loader(Catalogue &c): DataFile::ObjectLoader(c) { - add("ballast_profile", &Loader::ballast_profile); add("gauge", &Loader::gauge); add("layout", &Loader::layout); - add("rail_profile", &Loader::rail_profile); add("scale", &Loader::scale); add("signal", &Loader::signal); add("terrain", &Loader::terrain); add("track", &Loader::track); - add("track_technique", &Catalogue::track_technique); + add("track_appearance", &Loader::track_appearance); add("vehicle", &Loader::vehicle); } -void Catalogue::Loader::ballast_profile() -{ - load_sub(obj.ballast_profile); -} - void Catalogue::Loader::gauge(float g) { obj.gauge = g/1000; @@ -71,11 +59,6 @@ void Catalogue::Loader::layout() load_sub(obj.layout); } -void Catalogue::Loader::rail_profile() -{ - load_sub(obj.rail_profile); -} - void Catalogue::Loader::scale(float n, float d) { obj.scale = n/d; @@ -106,11 +89,16 @@ void Catalogue::Loader::track(ArticleNumber art_nr) if(obj.objects.count(art_nr)) throw key_error(art_nr); - RefPtr trk = new TrackType(art_nr); + RefPtr trk = new TrackType(art_nr, obj.appearance); load_sub(*trk); obj.add(*trk.release()); } +void Catalogue::Loader::track_appearance() +{ + load_sub(obj.appearance); +} + void Catalogue::Loader::vehicle(ArticleNumber art_nr) { if(obj.objects.count(art_nr)) diff --git a/source/libr2c2/catalogue.h b/source/libr2c2/catalogue.h index 5a91560..21ebd38 100644 --- a/source/libr2c2/catalogue.h +++ b/source/libr2c2/catalogue.h @@ -5,7 +5,7 @@ #include #include "articlenumber.h" #include "layout.h" -#include "profile.h" +#include "trackappearance.h" namespace R2C2 { @@ -19,14 +19,13 @@ public: public: Loader(Catalogue &); private: - void ballast_profile(); void gauge(float); void layout(); - void rail_profile(); void scale(float, float); void signal(ArticleNumber); void terrain(ArticleNumber); void track(ArticleNumber); + void track_appearance(); void vehicle(ArticleNumber); }; @@ -37,9 +36,7 @@ public: private: float scale; float gauge; - Profile rail_profile; - Profile ballast_profile; - std::string track_technique; + TrackAppearance appearance; ObjectMap objects; Layout layout; @@ -49,10 +46,6 @@ public: float get_scale() const { return scale; } float get_gauge() const { return gauge; } - float get_rail_elevation() const; - const Profile &get_rail_profile() const { return rail_profile; } - const Profile &get_ballast_profile() const { return ballast_profile; } - const std::string &get_track_technique() const { return track_technique; } void add(ObjectType &); const ObjectType &get(const ArticleNumber &) const; diff --git a/source/libr2c2/trackappearance.cpp b/source/libr2c2/trackappearance.cpp new file mode 100644 index 0000000..b97d696 --- /dev/null +++ b/source/libr2c2/trackappearance.cpp @@ -0,0 +1,32 @@ +#include "trackappearance.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +float TrackAppearance::get_rail_elevation() const +{ + return ballast_profile.get_height()+rail_profile.get_height(); +} + + +TrackAppearance::Loader::Loader(TrackAppearance &a): + ObjectLoader(a) +{ + add("ballast_profile", &Loader::ballast_profile); + add("rail_profile", &Loader::rail_profile); + add("technique", &TrackAppearance::technique); +} + +void TrackAppearance::Loader::ballast_profile() +{ + load_sub(obj.ballast_profile); +} + +void TrackAppearance::Loader::rail_profile() +{ + load_sub(obj.rail_profile); +} + +} // namespace R2C2 diff --git a/source/libr2c2/trackappearance.h b/source/libr2c2/trackappearance.h new file mode 100644 index 0000000..8a18cd4 --- /dev/null +++ b/source/libr2c2/trackappearance.h @@ -0,0 +1,37 @@ +#ifndef LIBR2C2_TRACKAPPEARANCE_H_ +#define LIBR2C2_TRACKAPPEARANCE_H_ + +#include +#include +#include "profile.h" + +namespace R2C2 { + +class TrackAppearance +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(TrackAppearance &); + + private: + void ballast_profile(); + void rail_profile(); + }; + +private: + Profile rail_profile; + Profile ballast_profile; + std::string technique; + +public: + float get_rail_elevation() const; + const Profile &get_rail_profile() const { return rail_profile; } + const Profile &get_ballast_profile() const { return ballast_profile; } + const std::string &get_technique() const { return technique; } +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/tracktype.cpp b/source/libr2c2/tracktype.cpp index e9136ac..7a1f27a 100644 --- a/source/libr2c2/tracktype.cpp +++ b/source/libr2c2/tracktype.cpp @@ -7,8 +7,9 @@ using namespace Msp; namespace R2C2 { -TrackType::TrackType(const ArticleNumber &an): +TrackType::TrackType(const ArticleNumber &an, const TrackAppearance &ta): ObjectType(an), + appearance(ta), state_bits(0), autofit_preference(1) { } diff --git a/source/libr2c2/tracktype.h b/source/libr2c2/tracktype.h index 181cb21..64efe8c 100644 --- a/source/libr2c2/tracktype.h +++ b/source/libr2c2/tracktype.h @@ -9,6 +9,8 @@ namespace R2C2 { +class TrackAppearance; + class TrackType: public ObjectType { public: @@ -39,6 +41,7 @@ public: }; private: + const TrackAppearance &appearance; std::vector parts; std::vector endpoints; unsigned state_bits; @@ -46,8 +49,9 @@ private: std::string object; public: - TrackType(const ArticleNumber &); + TrackType(const ArticleNumber &, const TrackAppearance &); + const TrackAppearance &get_appearance() const { return appearance; } float get_total_length() const; float get_path_length(int) const; unsigned get_paths() const; diff --git a/source/libr2c2/vehicle.cpp b/source/libr2c2/vehicle.cpp index 099644a..dee1e76 100644 --- a/source/libr2c2/vehicle.cpp +++ b/source/libr2c2/vehicle.cpp @@ -175,7 +175,8 @@ void Vehicle::update_position(int sign) { OrientedPoint p = placement.get_point(); position = p.position; - position.z += layout.get_catalogue().get_rail_elevation(); + // TODO Move the z adjustment to VehiclePlacement + position.z += placement.get_position(VehiclePlacement::FRONT_AXLE)->get_type().get_appearance().get_rail_elevation(); rotation = p.rotation; tilt = p.tilt; diff --git a/tracks.dat b/tracks.dat index 9c6bda8..40cf1ca 100644 --- a/tracks.dat +++ b/tracks.dat @@ -1,31 +1,35 @@ scale 1 87; gauge 16.5; -rail_profile -{ - point 1.5 0.0; - smooth_point 1.5 0.3; - smooth_point 0.8 0.4; - smooth_point 0.8 1.4; - smooth_point 1.0 1.6; - smooth_point 1.0 2.1; - smooth_point 0.8 2.3; - smooth_point 0.2 2.3; - smooth_point 0.0 2.1; - smooth_point 0.0 1.6; - smooth_point 0.2 1.4; - smooth_point 0.2 0.4; - smooth_point -0.5 0.3; - point -0.5 0.0; -}; -ballast_profile -{ - point 20.0 0.0; - point 14.0 8.0; - point -14.0 8.0; - point -20.0 0.0; -}; - -track_technique "track.technique"; + +track_appearance +{ + rail_profile + { + point 1.5 0.0; + smooth_point 1.5 0.3; + smooth_point 0.8 0.4; + smooth_point 0.8 1.4; + smooth_point 1.0 1.6; + smooth_point 1.0 2.1; + smooth_point 0.8 2.3; + smooth_point 0.2 2.3; + smooth_point 0.0 2.1; + smooth_point 0.0 1.6; + smooth_point 0.2 1.4; + smooth_point 0.2 0.4; + smooth_point -0.5 0.3; + point -0.5 0.0; + }; + ballast_profile + { + point 20.0 0.0; + point 14.0 8.0; + point -14.0 8.0; + point -20.0 0.0; + }; + + technique "track.technique"; +}; // Straight -- 2.43.0