5 #include <msp/core/error.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"
17 using namespace Marklin;
22 Engineer::Engineer(int argc, char **argv):
36 string device="/dev/ttyS0";
40 getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG);
41 getopt.add_option('f', "fullscreen", fullscreen, GetOpt::NO_ARG);
42 getopt.add_option('g', "debug", debug, GetOpt::NO_ARG);
43 getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG);
44 getopt.add_option('q', "quality", quality, GetOpt::REQUIRED_ARG);
45 getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG);
46 getopt.add_option( "no-lighting", no_lighting, GetOpt::NO_ARG);
51 if(RegMatch m=Regex("([1-9][0-9]*)x([1-9][0-9]*)").match(res))
53 screen_w=lexical_cast<unsigned>(m[1].str);
54 screen_h=lexical_cast<unsigned>(m[2].str);
57 throw UsageError("Invalid resolution");
63 control.set_debug(debug);
65 layout_3d.set_quality(quality);
67 catalogue.load("tracks.dat");
69 const list<string> &args=getopt.get_args();
71 throw UsageError("No layout given");
72 layout.load(args.front());
74 control.signal_sensor_event.connect(sigc::mem_fun(this, &Engineer::sensor_event));
76 trfc_mgr=new TrafficManager(control, layout);
77 trfc_mgr->signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved));
87 void Engineer::add_train(unsigned addr)
89 if(control.get_locomotive(addr))
92 Locomotive *loco=new Locomotive(control, addr);
93 Train *train=new Train(*trfc_mgr, *loco);
94 train->set_name(format("Train %d", trfc_mgr->get_trains().size()));
96 TrainPanel *tpanel=new TrainPanel(*this, ui_res, *train);
97 int y=main_panel->get_geometry().y;
98 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
99 y-=(*i)->get_geometry().h;
100 tpanel->set_position(0, y-tpanel->get_geometry().h);
101 train_panels.push_back(tpanel);
105 status_text="Select train location";
110 SDL_Init(SDL_INIT_VIDEO);
111 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
112 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
113 SDL_Surface *screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
116 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
117 screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
121 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
122 screen=SDL_SetVideoMode(screen_w, screen_h, 32, SDL_OPENGL|(fullscreen?SDL_FULLSCREEN:0));
125 throw Exception("Couldn't create window");
127 glEnableClientState(GL_VERTEX_ARRAY);
128 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
129 glEnable(GL_COLOR_MATERIAL);
130 glDepthFunc(GL_LEQUAL);
132 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
134 Parser::load(ui_res, "engineer.res");
135 main_panel=new MainPanel(*this, ui_res);
136 main_panel->set_position(0, screen_h-main_panel->get_geometry().h);
141 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
149 void Engineer::tick()
154 while(SDL_PollEvent(&event))
158 case SDL_MOUSEBUTTONDOWN:
159 button_press(event.button.x, screen_h-1-event.button.y, event.button.button);
161 case SDL_MOUSEBUTTONUP:
162 button_release(event.button.x, screen_h-1-event.button.y, event.button.button);
164 case SDL_MOUSEMOTION:
165 pointer_motion(event.motion.x, screen_h-1-event.motion.y);
168 key_press(event.key.keysym.sym, event.key.keysym.mod);
178 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
182 glRotatef(-cam_rot*180/M_PI, 0, 0, 1);
183 glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
187 glEnable(GL_LIGHTING);
194 glLightfv(GL_LIGHT0, GL_POSITION, params);
197 //glEnable(GL_DEPTH_TEST);
198 glEnable(GL_MULTISAMPLE);
202 glDisable(GL_LIGHTING);
203 glColor4f(1, 1, 1, 1);
204 const Track3DSeq <racks=layout_3d.get_tracks();
205 for(Track3DSeq::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
207 Track &track=(*i)->get_track();
208 if(track.get_turnout_id())
210 Turnout *trnt=control.get_turnout(track.get_turnout_id());
212 (*i)->render_route(trnt->get_route());
214 (*i)->render_route(-1);
217 (*i)->render_route(-1);
220 if(placing_train && placing_block)
222 float rot=placing_entry->track->get_rotation()+placing_entry->track_ep->rot;
223 Point pos=placing_entry->track->get_endpoint_position(*placing_entry->track_ep);
225 GL::translate(pos.x, pos.y, pos.z+0.03);
226 GL::rotate(rot*180/M_PI+180, 0, 0, 1);
227 GL::Texture::unbind();
228 glColor4f(1, 1, 1, 1);
229 glBegin(GL_TRIANGLE_FAN);
231 glVertex2f(0.05, 0.03);
232 glVertex2f(0.05, 0.01);
234 glVertex2f(0, -0.01);
235 glVertex2f(0.05, -0.01);
236 glVertex2f(0.05, -0.03);
241 glMatrixMode(GL_PROJECTION);
243 glOrtho(0, screen_w, 0, screen_h, 0, 1);
244 glMatrixMode(GL_MODELVIEW);
247 glDisable(GL_DEPTH_TEST);
248 glDisable(GL_LIGHTING);
249 glDisable(GL_MULTISAMPLE);
251 main_panel->render();
252 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
255 const GL::Font &font=ui_res.get_font("dejavu-12");
257 GL::translate(340, 10, 0);
258 GL::scale_uniform(font.get_default_size());
259 glColor4f(1, 1, 1, 1);
260 font.draw_string(status_text);
262 SDL_GL_SwapBuffers();
265 void Engineer::key_press(unsigned, unsigned)
269 void Engineer::button_press(int x, int y, unsigned btn)
271 if(main_panel->get_geometry().is_inside(x, y))
273 main_panel->button_press(x, y, btn);
276 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
277 if((*i)->get_geometry().is_inside(x, y))
279 (*i)->button_press(x, y, btn);
285 if(btn==1 && placing_block)
287 set_block_color(*placing_block, Color(1, 1, 1));
289 placing_train->place(placing_block, placing_entry);
294 const Block::EndpointSeq &endpoints=placing_block->get_endpoints();
295 Block::EndpointSeq::const_iterator i;
296 for(i=endpoints.begin(); i!=endpoints.end(); ++i)
297 if(&*i==placing_entry)
300 if(i==endpoints.end())
307 Track3D *track=pick_track(x, y);
310 Turnout *turnout=control.get_turnout(track->get_track().get_turnout_id());
312 turnout->set_route(1-turnout->get_route());
315 Sensor *sensor=control.get_sensor(track->get_track().get_sensor_id());
317 control.signal_sensor_event.emit(track->get_track().get_sensor_id(), !sensor->get_state());
323 void Engineer::button_release(int x, int y, unsigned btn)
325 if(main_panel->get_geometry().is_inside(x, y))
327 main_panel->button_release(x, y, btn);
330 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
331 if((*i)->get_geometry().is_inside(x, y))
333 (*i)->button_release(x, y, btn);
338 void Engineer::pointer_motion(int x, int y)
340 if(main_panel->get_geometry().is_inside(x, y))
342 main_panel->pointer_motion(x, y);
345 for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
346 if((*i)->get_geometry().is_inside(x, y))
348 (*i)->pointer_motion(x, y);
352 Track3D *track=pick_track(x, y);
353 if(track && placing_train)
355 Block *block=trfc_mgr->get_block_by_track(&track->get_track());
356 if(block!=placing_block)
359 set_block_color(*placing_block, Color(1, 1, 1));
361 placing_entry=&block->get_endpoints().front();
362 set_block_color(*placing_block, Color(0.5, 1, 0.7));
365 else if(track && track->get_track().get_turnout_id())
368 ss<<"Turnout "<<track->get_track().get_turnout_id();
369 status_text=ss.str();
371 else if(!placing_train)
375 void Engineer::view_all()
377 const Track3DSeq &tracks=layout_3d.get_tracks();
380 float best_height=-1;
383 for(float angle=0; angle<M_PI; angle+=0.01)
389 for(Track3DSeq::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
392 (*i)->get_bounds(angle, minp, maxp);
393 min_x=min(min_x, minp.x);
394 max_x=max(max_x, maxp.x);
395 min_y=min(min_y, minp.y);
396 max_y=max(max_y, maxp.y);
399 float width=max_x-min_x;
400 float height=max_y-min_y;
401 height=max(height, width);
403 if(height<best_height || best_height<0)
407 mid_x=(min_x+max_x)/2;
408 mid_y=(min_y+max_y)/2;
412 float c=cos(cam_rot);
413 float s=sin(cam_rot);
414 cam_pos.x=c*mid_x-s*mid_y;
415 cam_pos.y=s*mid_x+c*mid_y;
416 cam_pos.z=max(best_height*1.05/0.82843, 0.15);
419 void Engineer::set_block_color(const Block &block, const Color &color)
421 const TrackSet &tracks=block.get_tracks();
422 for(TrackSet::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
423 layout_3d.get_track(*i)->set_color(color);
426 void Engineer::sensor_event(unsigned addr, bool state)
428 cout<<"sensor_event "<<state<<" @ "<<addr<<'\n';
429 const Track3DSeq <racks=layout_3d.get_tracks();
430 for(Track3DSeq::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
431 if((*i)->get_track().get_sensor_id()==addr)
434 (*i)->set_color(Color(1, 0.5, 0.3));
436 (*i)->set_color(Color(1, 1, 1));
440 void Engineer::block_reserved(const Block &block, const Train *train)
442 if(Sensor *sensor=control.get_sensor(block.get_sensor_id()))
443 if(sensor->get_state())
447 set_block_color(block, Color(1, 1, 0.3));
449 set_block_color(block, Color(1, 1, 1));
452 void Engineer::project_3d()
454 glMatrixMode(GL_PROJECTION);
456 //glFrustum(-0.055228, 0.055228, -0.041421, 0.041421, 0.1, 10);
457 glFrustum(-0.069036, 0.041421, -0.041421, 0.041421, 0.1, 10);
458 glMatrixMode(GL_MODELVIEW);
461 Track3D *Engineer::pick_track(int x, int y)
463 float xx=((float)(x-(int)screen_w*5/8)/screen_h)*0.82843;
464 //float xx=((float)(x-(int)screen_w/2)/screen_h)*0.82843;
465 float yy=((float)y/screen_h-0.5)*0.82843;
466 float size=(float)4/screen_h*0.82843;
470 glRotatef(-cam_rot*180/M_PI, 0, 0, 1);
471 glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
473 return layout_3d.pick_track(xx, yy, size);
476 Application::RegApp<Engineer> Engineer::reg;