#include <limits>
#include <signal.h>
#include <msp/core/except.h>
-#include <msp/core/getopt.h>
#include <msp/fs/stat.h>
#include <msp/gbase/display.h>
#include <msp/gbase/window.h>
#include <msp/gl/blend.h>
#include <msp/gl/framebuffer.h>
-#include <msp/gl/immediate.h>
#include <msp/gl/matrix.h>
#include <msp/gl/misc.h>
-#include <msp/gl/projection.h>
#include <msp/gl/tests.h>
#include <msp/gl/transform.h>
#include <msp/io/print.h>
#include <msp/strings/formatter.h>
-#include <msp/strings/lexicalcast.h>
-#include <msp/strings/regex.h>
#include <msp/time/units.h>
-#include "libmarklin/except.h"
+#include "libmarklin/driver.h"
#include "libmarklin/tracktype.h"
#include "engineer.h"
#include "mainpanel.h"
using namespace Msp;
Engineer::Engineer(int argc, char **argv):
- layout(catalogue),
+ options(argc, argv),
+ window(options.screen_w, options.screen_h, options.fullscreen),
+ layout(catalogue, (options.driver.empty() ? 0 : Driver::create(options.driver))),
layout_3d(layout),
server(0),
+ pipeline(window.get_width(), window.get_height(), false),
placing_train(0),
placing_block(0),
- placing_entry(0),
- simulate(false)
+ placing_entry(0)
{
- // Parse options
- unsigned screen_w = 1280;
- unsigned screen_h = 960;
- bool fullscreen = false;
- string res;
- bool debug = false;
- string device = "/dev/ttyS0";
- bool network = false;
-
- GetOpt getopt;
- getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG);
- getopt.add_option('f', "fullscreen", fullscreen, GetOpt::NO_ARG);
- getopt.add_option('g', "debug", debug, GetOpt::NO_ARG);
- getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG);
- getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG);
- getopt.add_option('n', "network", network, GetOpt::NO_ARG);
- getopt(argc, argv);
-
- const vector<string> &args = getopt.get_args();
- if(args.empty())
- throw UsageError("No layout given");
-
- if(!res.empty())
- {
- if(RegMatch m=Regex("([1-9][0-9]*)x([1-9][0-9]*)").match(res))
- {
- screen_w = lexical_cast<unsigned>(m[1].str);
- screen_h = lexical_cast<unsigned>(m[2].str);
- }
- else
- throw UsageError("Invalid resolution");
- }
-
// Setup GUI
- window = new Graphics::SimpleGLWindow(screen_w, screen_h, fullscreen);
- window->set_title("Railroad Engineer");
- window->signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0));
+ window.set_title("Railroad Engineer");
+ window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0));
DataFile::load(ui_res, "marklin.res");
- root = new GLtk::Root(ui_res, *window);
+ root = new GLtk::Root(ui_res, window);
root->signal_button_press.connect(sigc::mem_fun(this, &Engineer::button_press));
root->signal_pointer_motion.connect(sigc::mem_fun(this, &Engineer::pointer_motion));
root->set_visible(true);
main_panel = new MainPanel(*this, ui_res);
root->add(*main_panel);
- main_panel->set_position(0, window->get_height()-main_panel->get_geometry().h);
+ main_panel->set_position(0, window.get_height()-main_panel->get_geometry().h);
main_panel->set_visible(true);
// Setup railroad control
DataFile::load(catalogue, "tracks.dat");
DataFile::load(catalogue, "locos.dat");
- DataFile::load(layout, args.front());
-
- if(device!="none")
- control.open(device);
+ DataFile::load(layout, options.layout_fn);
- control.set_debug(debug);
-
- trfc_mgr = new TrafficManager(control, layout);
- layout_3d.set_traffic_manager(*trfc_mgr);
- trfc_mgr->signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added));
- trfc_mgr->signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved));
+ layout.signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added));
+ layout.signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved));
if(FS::exists("engineer.state"))
- DataFile::load(*trfc_mgr, "engineer.state");
+ DataFile::load(layout, "engineer.state");
- if(network)
+ if(options.network)
{
- server = new Server(*trfc_mgr);
+ server = new Server(layout);
server->use_event_dispatcher(event_disp);
}
- const map<unsigned, Sensor *> &sensors = control.get_sensors();
- for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
- i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Engineer::sensor_event), i->second));
+ layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Engineer::sensor_event));
// Setup 3D view
DataFile::load(arrow_mesh, "arrow.mesh");
- overlay = new Overlay3D(*window, camera, ui_res.get_default_font());
+ overlay = new Overlay3D(window, camera, ui_res.get_default_font());
- pipeline = new GL::Pipeline(window->get_width(), window->get_height(), false);
- pipeline->set_camera(&camera);
- pipeline->add_renderable(layout_3d.get_scene());
+ pipeline.set_camera(&camera);
+ pipeline.add_renderable(layout_3d.get_scene());
light.set_position(0, -0.259, 0.966, 0);
lighting.attach(0, light);
- GL::PipelinePass &pass = pipeline->add_pass(0);
+ GL::PipelinePass &pass = pipeline.add_pass(0);
pass.depth_test = &GL::DepthTest::lequal();
pass.lighting = &lighting;
Engineer::~Engineer()
{
- const list<Train *> &trains = trfc_mgr->get_trains();
- for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
- (*i)->set_speed(0);
-
- while(control.get_queue_length())
- control.tick();
+ const map<unsigned, Train *> &trains = layout.get_trains();
+ for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
+ i->second->set_speed(0);
+ layout.get_driver().flush();
- if(!simulate)
- trfc_mgr->save("engineer.state");
+ if(!options.simulate)
+ layout.save_trains("engineer.state");
- delete pipeline;
delete overlay;
delete root;
- delete window;
- delete trfc_mgr;
delete server;
}
int Engineer::main()
{
- window->show();
+ window.show();
return Application::main();
}
void Engineer::tick()
{
- window->get_display().tick();
+ window.get_display().tick();
- control.tick();
- trfc_mgr->tick();
+ layout.tick();
event_disp.tick(Time::zero);
for(list<Train *>::iterator i=new_trains.begin(); i!=new_trains.end(); ++i)
GL::clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
- pipeline->render_all();
+ pipeline.render_all();
{
GL::Bind blend(GL::Blend::alpha());
overlay->render(0);
GL::Texture::unbind();
}
- window->swap_buffers();
+ window.swap_buffers();
}
void Engineer::button_press(int x, int y, unsigned btn, unsigned)
}
else
{
- Track3D *track = pick_track(x, window->get_height()-y-1);
- if(track)
+ Track3D *t3d = pick_track(x, window.get_height()-y-1);
+ if(t3d)
{
- if(unsigned tid=track->get_track().get_turnout_id())
+ Track &track = t3d->get_track();
+ if(track.get_turnout_id())
{
- Turnout &turnout = control.get_turnout(tid);
- try
+ Block &block = layout.get_block_by_track(track);
+ if(block.get_train() && !block.get_train()->free_block(block))
+ main_panel->set_status_text("Turnout busy");
+ else
{
- turnout.set_path((turnout.get_path()+1)%track->get_track().get_type().get_n_paths());
- main_panel->set_status_text(format("Turnout %d switched", turnout.get_address()));
- }
- catch(const TurnoutBusy &e)
- {
- main_panel->set_status_text(e.what());
+ unsigned paths = track.get_type().get_paths();
+ unsigned i = track.get_active_path()+1;
+ while(!(paths&(1<<i)))
+ {
+ if(!(paths>>i))
+ i = 0;
+ else
+ ++i;
+ }
+ track.set_active_path(i);
}
}
- else if(simulate)
+ /*else if(simulate)
{
if(unsigned sid=track->get_track().get_sensor_id())
{
Sensor &sensor = control.get_sensor(sid);
control.signal_sensor_event.emit(sid, !sensor.get_state());
}
- }
+ }*/
}
}
}
{
if(placing_train)
{
- Track3D *track = pick_track(x, window->get_height()-y-1);
+ Track3D *track = pick_track(x, window.get_height()-y-1);
if(track)
{
- Block &block = trfc_mgr->get_block_by_track(track->get_track());
+ Block &block = layout.get_block_by_track(track->get_track());
if(&block!=placing_block)
{
if(placing_block)
{
const list<Track3D *> &tracks = layout_3d.get_tracks();
- float view_aspect = float(window->get_width()-200)/window->get_height();
+ float view_aspect = float(window.get_width()-200)/window.get_height();
float view_height = tan(camera.get_field_of_view()/2)*2;
float best_score = 0;
GL::Vector3 pos;
float size = max(width/view_aspect, height);
float c = cos(angle);
float s = sin(angle);
- float x = (min_x+max_x)/2-size*105/window->get_height();
+ float x = (min_x+max_x)/2-size*105/window.get_height();
float y = (min_y+max_y)/2;
float z = max(size*1.05/view_height, 0.15);
void Engineer::set_block_color(const Block &block, const GL::Color &color)
{
- (void)block;
- (void)color;
+ (void)block; (void)color;
}
void Engineer::reset_block_color(const Block &block)
{
if(unsigned sid=block.get_sensor_id())
{
- Sensor &sensor = control.get_sensor(sid);
- if(sensor.get_state())
+ if(layout.get_driver().get_sensor(sid))
{
set_block_color(block, GL::Color(1, 0.5, 0.3));
return;
set_block_color(block, GL::Color(1, 1, 1));
}
-void Engineer::sensor_event(bool, Sensor *sensor)
+void Engineer::sensor_event(unsigned addr, bool)
{
- const list<Block *> &blocks = trfc_mgr->get_blocks();
- for(list<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
- if((*i)->get_sensor_id()==sensor->get_address())
+ const set<Block *> &blocks = layout.get_blocks();
+ for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ if((*i)->get_sensor_id()==addr)
reset_block_color(**i);
}
Track3D *Engineer::pick_track(int x, int y)
{
float view_height = tan(camera.get_field_of_view()/2)*2;
- float xx = ((float(x)-window->get_width()/2)/window->get_height())*view_height;
- float yy = (float(y)/window->get_height()-0.5)*view_height;
- float size = 4.0/window->get_height()*view_height;
+ float xx = ((float(x)-window.get_width()/2)/window.get_height())*view_height;
+ float yy = (float(y)/window.get_height()-0.5)*view_height;
+ float size = 4.0/window.get_height()*view_height;
camera.apply();
{
signal(sig, SIG_DFL);
IO::print(IO::cerr, "Fatal signal received, terminating\n");
- const map<unsigned, Locomotive *> &locos = control.get_locomotives();
- for(map<unsigned, Locomotive *>::const_iterator i=locos.begin(); i!=locos.end(); ++i)
+ const map<unsigned, Train *> &trains = layout.get_trains();
+ for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
i->second->set_speed(0);
- control.flush();
+ layout.get_driver().flush();
raise(sig);
}
else if(sig==SIGTERM || sig==SIGINT)