5 #include <msp/core/except.h>
6 #include <msp/core/getopt.h>
7 #include <msp/gl/matrix.h>
8 #include <msp/gl/transform.h>
9 #include <msp/strings/formatter.h>
10 #include <msp/strings/lexicalcast.h>
11 #include <msp/strings/regex.h>
13 #include "mainpanel.h"
14 #include "trainpanel.h"
15 #include "trainproperties.h"
18 using namespace Marklin;
23 Engineer::Engineer(int argc, char **argv):
35 train_prop_stale(false)
39 string device="/dev/ttyS0";
43 getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG);
44 getopt.add_option('f', "fullscreen", fullscreen, GetOpt::NO_ARG);
45 getopt.add_option('g', "debug", debug, GetOpt::NO_ARG);
46 getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG);
47 getopt.add_option('q', "quality", quality, GetOpt::REQUIRED_ARG);
48 getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG);
49 getopt.add_option( "no-lighting", no_lighting, GetOpt::NO_ARG);
54 if(RegMatch m=Regex("([1-9][0-9]*)x([1-9][0-9]*)").match(res))
56 screen_w=lexical_cast<unsigned>(m[1].str);
57 screen_h=lexical_cast<unsigned>(m[2].str);
60 throw UsageError("Invalid resolution");
66 control.set_debug(debug);
68 layout_3d.set_quality(quality);
70 catalogue.load("tracks.dat");
72 const vector<string> &args=getopt.get_args();
74 throw UsageError("No layout given");
75 layout.load(args.front());
77 trfc_mgr=new TrafficManager(control, layout);
78 trfc_mgr->signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved));
80 const map<unsigned, Sensor *> &sensors=control.get_sensors();
81 for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
82 i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Engineer::sensor_event), i->second));
92 Train *Engineer::add_train(unsigned addr)
94 /*if(control.get_locomotive(addr))
99 train_prop=new TrainProperties(*this, ui_res, 0);
100 train_prop->signal_ok.connect(sigc::mem_fun(this, &Engineer::dismiss_train_prop));
101 train_prop_stale=false;
107 Locomotive *loco=new Locomotive(control, addr);
108 Train *train=new Train(*trfc_mgr, *loco);
109 train->set_name(format("Train %d", trfc_mgr->get_trains().size()));
111 //train_prop=new TrainProperties(ui_res, *train);
113 TrainPanel *tpanel=new TrainPanel(*this, ui_res, *train);
114 int y=main_panel->get_geometry().y;
115 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
116 y-=(*i)->get_geometry().h;
117 tpanel->set_position(0, y-tpanel->get_geometry().h);
118 train_panels.push_back(tpanel);
122 status_text="Select train location";
130 SDL_Init(SDL_INIT_VIDEO);
131 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
132 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
133 SDL_Surface *screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
136 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
137 screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
141 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
142 screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
145 throw Exception("Couldn't create window");
147 SDL_EnableUNICODE(1);
149 glEnableClientState(GL_VERTEX_ARRAY);
150 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
151 glEnable(GL_COLOR_MATERIAL);
152 glDepthFunc(GL_LEQUAL);
154 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156 DataFile::load(ui_res, "engineer.res");
157 main_panel=new MainPanel(*this, ui_res);
158 main_panel->set_position(0, screen_h-main_panel->get_geometry().h);
163 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
171 void Engineer::tick()
176 while(SDL_PollEvent(&event))
180 case SDL_MOUSEBUTTONDOWN:
181 button_press(event.button.x, screen_h-1-event.button.y, event.button.button);
183 case SDL_MOUSEBUTTONUP:
184 button_release(event.button.x, screen_h-1-event.button.y, event.button.button);
186 case SDL_MOUSEMOTION:
187 pointer_motion(event.motion.x, screen_h-1-event.motion.y);
190 key_press(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode);
200 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
204 glRotatef(-cam_rot*180/M_PI, 0, 0, 1);
205 glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
209 glEnable(GL_LIGHTING);
216 glLightfv(GL_LIGHT0, GL_POSITION, params);
219 //glEnable(GL_DEPTH_TEST);
220 glEnable(GL_MULTISAMPLE);
224 glDisable(GL_LIGHTING);
225 glColor4f(1, 1, 1, 1);
226 const Track3DSeq <racks=layout_3d.get_tracks();
227 for(Track3DSeq::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
229 Track &track=(*i)->get_track();
230 if(track.get_turnout_id())
232 Turnout &trnt=control.get_turnout(track.get_turnout_id());
233 (*i)->render_route(trnt.get_route());
236 (*i)->render_route(-1);
239 if(placing_train && placing_block)
241 const Marklin::Block::Endpoint &bep=placing_block->get_endpoints()[placing_entry];
242 float rot=bep.track->get_endpoint_direction(bep.track_ep);
243 Point pos=bep.track->get_endpoint_position(bep.track_ep);
245 GL::translate(pos.x, pos.y, pos.z+0.03);
246 GL::rotate(rot*180/M_PI+180, 0, 0, 1);
247 GL::Texture::unbind();
248 glColor4f(1, 1, 1, 1);
249 glBegin(GL_TRIANGLE_FAN);
251 glVertex2f(0.05, 0.03);
252 glVertex2f(0.05, 0.01);
254 glVertex2f(0, -0.01);
255 glVertex2f(0.05, -0.01);
256 glVertex2f(0.05, -0.03);
261 glMatrixMode(GL_PROJECTION);
263 glOrtho(0, screen_w, 0, screen_h, 0, 1);
264 glMatrixMode(GL_MODELVIEW);
267 glDisable(GL_DEPTH_TEST);
268 glDisable(GL_LIGHTING);
269 glDisable(GL_MULTISAMPLE);
271 main_panel->render();
272 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
275 train_prop->render();
283 const GL::Font &font=ui_res.get_default_font();
285 GL::translate(340, 10, 0);
286 GL::scale_uniform(font.get_default_size());
287 glColor4f(1, 1, 1, 1);
288 font.draw_string(status_text);
290 SDL_GL_SwapBuffers();
293 void Engineer::key_press(unsigned key, unsigned mod, wchar_t ch)
296 train_prop->key_press(key, mod, ch);
299 void Engineer::button_press(int x, int y, unsigned btn)
301 if(main_panel->get_geometry().is_inside(x, y))
303 main_panel->button_press(x, y-main_panel->get_geometry().y, btn);
306 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
307 if((*i)->get_geometry().is_inside(x, y))
309 (*i)->button_press(x, y, btn);
312 if(train_prop && train_prop->get_geometry().is_inside(x, y))
314 train_prop->button_press(x, y, btn);
320 if(btn==1 && placing_block)
322 set_block_color(*placing_block, Color(1, 1, 1));
324 placing_train->place(placing_block, placing_entry);
329 const vector<Block::Endpoint> &endpoints=placing_block->get_endpoints();
330 placing_entry=(placing_entry+1)%endpoints.size();
335 Track3D *track=pick_track(x, y);
338 if(unsigned tid=track->get_track().get_turnout_id())
340 Turnout &turnout=control.get_turnout(tid);
341 turnout.set_route(1-turnout.get_route());
345 if(unsigned sid=track->get_track().get_sensor_id())
347 Sensor &sensor=control.get_sensor(sid);
348 control.signal_sensor_event.emit(sid, !sensor.get_state());
355 void Engineer::button_release(int x, int y, unsigned btn)
357 if(main_panel->get_geometry().is_inside(x, y))
359 main_panel->button_release(x, y-main_panel->get_geometry().y, btn);
362 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
363 if((*i)->get_geometry().is_inside(x, y))
365 (*i)->button_release(x, y, btn);
368 if(train_prop && train_prop->get_geometry().is_inside(x, y))
370 train_prop->button_release(x, y, btn);
375 void Engineer::pointer_motion(int x, int y)
377 if(main_panel->get_geometry().is_inside(x, y))
379 main_panel->pointer_motion(x, y);
382 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
383 if((*i)->get_geometry().is_inside(x, y))
385 (*i)->pointer_motion(x, y);
388 if(train_prop && train_prop->get_geometry().is_inside(x, y))
390 train_prop->pointer_motion(x, y);
394 Track3D *track=pick_track(x, y);
395 if(track && placing_train)
397 Block *block=trfc_mgr->get_block_by_track(&track->get_track());
398 if(block!=placing_block)
401 set_block_color(*placing_block, Color(1, 1, 1));
404 set_block_color(*placing_block, Color(0.5, 1, 0.7));
407 else if(track && track->get_track().get_turnout_id())
410 ss<<"Turnout "<<track->get_track().get_turnout_id();
411 status_text=ss.str();
413 else if(!placing_train)
417 void Engineer::view_all()
419 const Track3DSeq &tracks=layout_3d.get_tracks();
422 float best_height=-1;
425 for(float angle=0; angle<M_PI; angle+=0.01)
431 for(Track3DSeq::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
434 (*i)->get_bounds(angle, minp, maxp);
435 min_x=min(min_x, minp.x);
436 max_x=max(max_x, maxp.x);
437 min_y=min(min_y, minp.y);
438 max_y=max(max_y, maxp.y);
441 float width=max_x-min_x;
442 float height=max_y-min_y;
443 height=max(height, width);
445 if(height<best_height || best_height<0)
449 mid_x=(min_x+max_x)/2;
450 mid_y=(min_y+max_y)/2;
454 float c=cos(cam_rot);
455 float s=sin(cam_rot);
456 cam_pos.x=c*mid_x-s*mid_y;
457 cam_pos.y=s*mid_x+c*mid_y;
458 cam_pos.z=max(best_height*1.05/0.82843, 0.15);
461 void Engineer::set_block_color(const Block &block, const Color &color)
463 const set<Track *> &tracks=block.get_tracks();
464 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
465 layout_3d.get_track(*i)->set_color(color);
468 void Engineer::sensor_event(bool state, Sensor *sensor)
470 const list<Track3D *> <racks=layout_3d.get_tracks();
471 for(list<Track3D *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
472 if((*i)->get_track().get_sensor_id()==sensor->get_address())
475 (*i)->set_color(Color(1, 0.5, 0.3));
477 (*i)->set_color(Color(1, 1, 1));
481 void Engineer::block_reserved(const Block &block, const Train *train)
483 if(unsigned sid=block.get_sensor_id())
485 Sensor &sensor=control.get_sensor(sid);
486 cout<<block.get_sensor_id()<<' '<<&sensor<<' '<<sensor.get_state()<<'\n';
487 if(sensor.get_state())
492 set_block_color(block, Color(1, 1, 0.3));
494 set_block_color(block, Color(1, 1, 1));
497 void Engineer::project_3d()
499 glMatrixMode(GL_PROJECTION);
501 //glFrustum(-0.055228, 0.055228, -0.041421, 0.041421, 0.1, 10);
502 glFrustum(-0.069036, 0.041421, -0.041421, 0.041421, 0.1, 10);
503 glMatrixMode(GL_MODELVIEW);
506 Track3D *Engineer::pick_track(int x, int y)
508 float xx=((float)(x-(int)screen_w*5/8)/screen_h)*0.82843;
509 //float xx=((float)(x-(int)screen_w/2)/screen_h)*0.82843;
510 float yy=((float)y/screen_h-0.5)*0.82843;
511 float size=(float)4/screen_h*0.82843;
515 glRotatef(-cam_rot*180/M_PI, 0, 0, 1);
516 glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
518 return layout_3d.pick_track(xx, yy, size);
521 void Engineer::dismiss_train_prop()
523 train_prop_stale=true;
526 Application::RegApp<Engineer> Engineer::reg;