From 2220ba2f11705ea9a4e480603d43ab7ed4cf5a89 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 21 Nov 2013 17:12:12 +0200 Subject: [PATCH] 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