]> git.tdb.fi Git - r2c2.git/commitdiff
Add TrainView for viewing the layout from the train's perspective
authorMikko Rasa <tdb@tdb.fi>
Sun, 10 Oct 2010 10:18:00 +0000 (10:18 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 10 Oct 2010 10:18:00 +0000 (10:18 +0000)
Make TrainPanel collapsible to save space
Add button for taking train off the track

marklin.res
source/engineer/engineer.cpp
source/engineer/engineer.h
source/engineer/trainpanel.cpp
source/engineer/trainpanel.h
source/engineer/trainview.cpp [new file with mode: 0644]
source/engineer/trainview.h [new file with mode: 0644]

index 8efa84edd184bc65f5265ba7f128ab6a4ecc9cda..e44ac9d031fc733797c2c8ecada73f75f942f0d4 100644 (file)
@@ -13,6 +13,14 @@ style "label"
        special "text";
 };
 
+style "image"
+{
+       special "image"
+       {
+               fill 1.0 1.0;
+       };
+};
+
 graphic "tooltip"
 {
        texture "gui.png";
@@ -85,6 +93,34 @@ graphic "red_button_pressed"
        shadow { top 0; right 1; bottom 2; left 0; };
 };
 
+graphic "up_arrow_button"
+{
+       texture "gui.png";
+       slice 2 18 13 13;
+       shadow { top 0; right 1; bottom 2; left 0; };
+};
+
+graphic "up_arrow_button_pressed"
+{
+       texture "gui.png";
+       slice 17 18 13 13;
+       shadow { top 0; right 1; bottom 2; left 0; };
+};
+
+graphic "down_arrow_button"
+{
+       texture "gui.png";
+       slice 2 4 13 13;
+       shadow { top 0; right 1; bottom 2; left 0; };
+};
+
+graphic "down_arrow_button_pressed"
+{
+       texture "gui.png";
+       slice 17 4 13 13;
+       shadow { top 0; right 1; bottom 2; left 0; };
+};
+
 style "button"
 {
        font_color 0 0 0;
@@ -142,6 +178,28 @@ style "button-red"
        };
 };
 
+style "button-arrow_up"
+{
+       part
+       {
+               graphic NORMAL "up_arrow_button";
+               graphic ACTIVE "up_arrow_button_pressed";
+               align 0.5 0.5;
+               fill 0.0 0.0;
+       };
+};
+
+style "button-arrow_down"
+{
+       part
+       {
+               graphic NORMAL "down_arrow_button";
+               graphic ACTIVE "down_arrow_button_pressed";
+               align 0.5 0.5;
+               fill 0.0 0.0;
+       };
+};
+
 graphic "yellow_lamp"
 {
        texture "gui.png";
@@ -227,6 +285,11 @@ style "panel"
        special "children";
 };
 
+style "panel-group"
+{
+       special "children";
+};
+
 graphic "sunken_black_bg"
 {
        texture "gui.png";
@@ -358,34 +421,6 @@ style "list"
        };
 };
 
-graphic "up_arrow_button"
-{
-       texture "gui.png";
-       slice 2 18 13 13;
-       shadow { top 0; right 1; bottom 2; left 0; };
-};
-
-graphic "up_arrow_button_pressed"
-{
-       texture "gui.png";
-       slice 17 18 13 13;
-       shadow { top 0; right 1; bottom 2; left 0; };
-};
-
-graphic "down_arrow_button"
-{
-       texture "gui.png";
-       slice 2 4 13 13;
-       shadow { top 0; right 1; bottom 2; left 0; };
-};
-
-graphic "down_arrow_button_pressed"
-{
-       texture "gui.png";
-       slice 17 4 13 13;
-       shadow { top 0; right 1; bottom 2; left 0; };
-};
-
 style "dropdown"
 {
        font_color 0.0 0.0 0.0;
index b6651342f2137bd24a58b94b5de0e0da21c913b2..59aaeeca9f9e3aef5677ccc5196c7a0d6b57a1a1 100644 (file)
@@ -5,6 +5,7 @@ Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
 Distributed under the GPL
 */
 
+#include <algorithm>
 #include <cmath>
 #include <cstdlib>
 #include <limits>
@@ -33,6 +34,7 @@ Distributed under the GPL
 #include "mainpanel.h"
 #include "trainpanel.h"
 #include "trainproperties.h"
+#include "trainview.h"
 
 using namespace std;
 using namespace Marklin;
@@ -137,6 +139,26 @@ void Engineer::set_status(const string &text)
        status_timeout = Time::now()+10*Time::sec;
 }
 
+void Engineer::rearrange_panels()
+{
+       int y = main_panel->get_geometry().y;
+       for(list<TrainPanel *>::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
+       {
+               y -= (*i)->get_geometry().h;
+               (*i)->set_position(0, y);
+       }
+}
+
+void Engineer::add_train_view(TrainView &tv)
+{
+       train_views.push_back(&tv);
+}
+
+void Engineer::remove_train_view(TrainView &tv)
+{
+       train_views.erase(remove(train_views.begin(), train_views.end(), &tv), train_views.end());
+}
+
 void Engineer::pick(bool with_ep)
 {
        picking = true;
@@ -158,6 +180,9 @@ void Engineer::tick()
        layout.tick();
        event_disp.tick(Time::zero);
 
+       for(list<TrainView *>::iterator i=train_views.begin(); i!=train_views.end(); ++i)
+               (*i)->prepare();
+
        if(status_timeout && Time::now()>status_timeout)
        {
                main_panel->set_status_text(string());
@@ -403,12 +428,8 @@ void Engineer::train_added(Train &train)
 {
        TrainPanel *tpanel = new TrainPanel(*this, ui_res, train);
        root->add(*tpanel);
-       int y = main_panel->get_geometry().y;
-       for(list<TrainPanel *>::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
-               y -= (*i)->get_geometry().h;
-       tpanel->set_position(0, y-tpanel->get_geometry().h);
        train_panels.push_back(tpanel);
-       tpanel->set_visible(true);
+       rearrange_panels();
 
        Vehicle3D &loco3d = layout_3d.get_vehicle(train.get_vehicle(0));
        overlay->set_label(loco3d, train.get_name());
index dc7a7a02dddf64ca6712bc2986236961972aa70a..61a2f59e37730c53e88a87bccbfd26bda1ea6abc 100644 (file)
@@ -26,7 +26,7 @@ Distributed under the GPL
 
 class MainPanel;
 class TrainPanel;
-class TrainProperties;
+class TrainView;
 
 class Engineer: public Msp::Application
 {
@@ -56,6 +56,7 @@ private:
 
        MainPanel *main_panel;
        std::list<TrainPanel *> train_panels;
+       std::list<TrainView *> train_views;
        Msp::Time::TimeStamp status_timeout;
        bool picking;
        Marklin::Track *picking_track;
@@ -73,7 +74,12 @@ public:
        Msp::GLtk::Root &get_root() const { return *root; }
        const Marklin::Catalogue &get_catalogue() const { return catalogue; }
        Marklin::Layout &get_layout() { return layout; }
+       Marklin::Layout3D &get_layout_3d() { return layout_3d; }
+       const Msp::GL::Lighting &get_lighting() const { return lighting; }
        void set_status(const std::string &);
+       void rearrange_panels();
+       void add_train_view(TrainView &);
+       void remove_train_view(TrainView &);
        void pick(bool);
        int main();
        void quit() { exit(0); }
index 75024dcac300f1a7abc65e65ff7e8e0562c4104a..922e3741e272183abad52382f4255ce08c6fbfe3 100644 (file)
@@ -6,7 +6,6 @@ Distributed under the GPL
 */
 
 #include <cmath>
-#include <msp/gltk/button.h>
 #include <msp/strings/formatter.h>
 #include "libmarklin/timetable.h"
 #include "libmarklin/vehicletype.h"
@@ -15,6 +14,7 @@ Distributed under the GPL
 #include "timetabledialog.h"
 #include "trainpanel.h"
 #include "trainproperties.h"
+#include "trainview.h"
 
 using namespace std;
 using namespace Msp;
@@ -24,46 +24,61 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t):
        Widget(r),
        Panel(r),
        engineer(e),
-       train(t)
+       train(t),
+       expanded(false)
 {
-       set_size(200, 175);
+       set_size(200, 65);
 
        train.signal_control_changed.connect(sigc::mem_fun(this, &TrainPanel::train_control_changed));
 
-       add(*(lbl_addr=new GLtk::Label(res, format("%2d", train.get_address()))));
+       add(*(pnl_basic = new GLtk::Panel(res)));
+       pnl_basic->set_style("group");
+       pnl_basic->set_geometry(GLtk::Geometry(0, geom.h-58, geom.w, 45));
+
+       pnl_basic->add(*(lbl_addr = new GLtk::Label(res, format("%2d", train.get_address()))));
        lbl_addr->set_style("digital");
-       lbl_addr->set_geometry(GLtk::Geometry(10, geom.h-30, 35, 20));
+       lbl_addr->set_geometry(GLtk::Geometry(10, 28, 35, 20));
 
-       add(*(lbl_name=new GLtk::Label(res, train.get_name())));
+       pnl_basic->add(*(lbl_name = new GLtk::Label(res, train.get_name())));
        lbl_name->set_style("digital");
-       lbl_name->set_geometry(GLtk::Geometry(50, geom.h-30, geom.w-55, 20));
+       lbl_name->set_geometry(GLtk::Geometry(50, 28, geom.w-77, 20));
        train.signal_name_changed.connect(sigc::mem_fun(lbl_name, &GLtk::Label::set_text));
 
-       add(*(lbl_speed=new GLtk::Label(res, "  0")));
+       pnl_basic->add(*(lbl_speed = new GLtk::Label(res, "  0")));
        lbl_speed->set_style("digital");
-       lbl_speed->set_geometry(GLtk::Geometry(10, geom.h-55, 35, 20));
+       lbl_speed->set_geometry(GLtk::Geometry(10, 3, 35, 20));
 
-       add(*(sld_speed=new GLtk::HSlider(res)));
-       sld_speed->set_geometry(GLtk::Geometry(50, geom.h-50, geom.w-80, 10));
+       pnl_basic->add(*(sld_speed = new GLtk::HSlider(res)));
+       sld_speed->set_geometry(GLtk::Geometry(50, 8, geom.w-80, 10));
        sld_speed->set_range(0, 200);
        sld_speed->set_step(5);
        sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_slider_changed));
 
-       add(*(tgl_forward=new GLtk::Toggle(res)));
+       pnl_basic->add(*(tgl_forward = new GLtk::Toggle(res)));
        tgl_forward->set_text("Fwd");
-       tgl_forward->set_geometry(GLtk::Geometry(geom.w-30, geom.h-58, 20, 27));
+       tgl_forward->set_geometry(GLtk::Geometry(geom.w-30, 0, 20, 27));
        tgl_forward->set_value(true);
        tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainPanel::forward_toggled));
 
+       pnl_basic->add(*(btn_expand = new GLtk::Button(res)));
+       btn_expand->set_style("arrow_down");
+       btn_expand->set_geometry(GLtk::Geometry(geom.w-22, 28, 12, 20));
+       btn_expand->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::expand_clicked));
+
+       add(*(pnl_extra = new GLtk::Panel(res)));
+       pnl_extra->set_style("group");
+       pnl_extra->set_geometry(GLtk::Geometry(0, 10, geom.w, 135));
+       pnl_extra->set_visible(false);
+
        const Route *route = train.get_route();
-       add(*(lbl_route=new GLtk::Label(res, (route ? route->get_name() : "Free run"))));
+       pnl_extra->add(*(lbl_route = new GLtk::Label(res, (route ? route->get_name() : "Free run"))));
        lbl_route->set_style("digital");
-       lbl_route->set_geometry(GLtk::Geometry(10, 65, geom.w-20, 20));
+       lbl_route->set_geometry(GLtk::Geometry(10, 85, geom.w-20, 20));
        train.signal_route_changed.connect(sigc::mem_fun(this, &TrainPanel::train_route_changed));
 
-       add(*(lbl_status=new GLtk::Label(res, train.get_status())));
+       pnl_extra->add(*(lbl_status = new GLtk::Label(res, train.get_status())));
        lbl_status->set_style("digital");
-       lbl_status->set_geometry(GLtk::Geometry(10, 40, geom.w-20, 20));
+       lbl_status->set_geometry(GLtk::Geometry(10, 60, geom.w-20, 20));
        train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::train_status_changed));
 
        const map<unsigned, string> &funcs = train.get_locomotive_type().get_functions();
@@ -73,9 +88,9 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t):
                string fname = i->second;
                fname[0] = toupper(fname[0]);
                GLtk::Toggle *tgl;
-               add(*(tgl=new GLtk::Toggle(res)));
+               pnl_extra->add(*(tgl = new GLtk::Toggle(res)));
                tgl->set_text(fname);
-               tgl->set_geometry(GLtk::Geometry(x, geom.h-87, 36, 27));
+               tgl->set_geometry(GLtk::Geometry(x, 108, 36, 27));
                tgl->set_value(train.get_function(i->first));
                tgl->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainPanel::func_toggled), i->first));
 
@@ -85,25 +100,51 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t):
 
        GLtk::Button *btn;
 
-       add(*(btn=new GLtk::Button(res, "Edit")));
-       btn->set_geometry(GLtk::Geometry(geom.w-46, 10, 36, 25));
+       pnl_extra->add(*(btn = new GLtk::Button(res, "Edit")));
+       btn->set_geometry(GLtk::Geometry(10, 30, 36, 25));
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::edit_clicked));
 
-       add(*(btn=new GLtk::Button(res, "Place")));
-       btn->set_geometry(GLtk::Geometry(geom.w-82, 10, 36, 25));
+       pnl_extra->add(*(btn = new GLtk::Button(res, "Place")));
+       btn->set_geometry(GLtk::Geometry(10, 0, 36, 25));
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::place_clicked));
 
-       add(*(btn=new GLtk::Button(res, "GoTo")));
-       btn->set_geometry(GLtk::Geometry(geom.w-118, 10, 36, 25));
+       pnl_extra->add(*(btn = new GLtk::Button(res, "Take")));
+       btn->set_geometry(GLtk::Geometry(46, 0, 36, 25));
+       btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::take_clicked));
+
+       pnl_extra->add(*(btn = new GLtk::Button(res, "GoTo")));
+       btn->set_geometry(GLtk::Geometry(100, 0, 36, 25));
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::goto_clicked));
 
-       add(*(btn=new GLtk::Button(res, "Route")));
-       btn->set_geometry(GLtk::Geometry(geom.w-154, 10, 36, 25));
+       pnl_extra->add(*(btn = new GLtk::Button(res, "Route")));
+       btn->set_geometry(GLtk::Geometry(100, 30, 36, 25));
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::route_clicked));
 
-       add(*(btn=new GLtk::Button(res, "TTbl")));
-       btn->set_geometry(GLtk::Geometry(geom.w-190, 10, 36, 25));
+       pnl_extra->add(*(btn = new GLtk::Button(res, "TTbl")));
+       btn->set_geometry(GLtk::Geometry(46, 30, 36, 25));
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::timetable_clicked));
+
+       pnl_extra->add(*(btn = new GLtk::Button(res, "View")));
+       btn->set_geometry(GLtk::Geometry(geom.w-46, 30, 36, 25));
+       btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::view_clicked));
+}
+
+void TrainPanel::expand(bool e)
+{
+       expanded = e;
+       pnl_extra->set_visible(expanded);
+       if(expanded)
+       {
+               set_size(geom.w, 205);
+               btn_expand->set_style("arrow_up");
+       }
+       else
+       {
+               set_size(geom.w, 65);
+               btn_expand->set_style("arrow_down");
+       }
+       pnl_basic->set_geometry(GLtk::Geometry(0, geom.h-58, geom.w, 45));
+       engineer.rearrange_panels();
 }
 
 void TrainPanel::train_control_changed(const string &control, float value)
@@ -144,12 +185,16 @@ void TrainPanel::place_clicked()
        pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &TrainPanel::place));
 }
 
+void TrainPanel::take_clicked()
+{
+       train.unplace();
+}
+
 void TrainPanel::edit_clicked()
 {
        TrainProperties *dialog = new TrainProperties(engineer, res, &train);
        engineer.get_root().add(*dialog);
        dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
-       dialog->set_visible(true);
 }
 
 void TrainPanel::route_clicked()
@@ -157,7 +202,6 @@ void TrainPanel::route_clicked()
        RouteSelect *dialog = new RouteSelect(engineer, res, train);
        engineer.get_root().add(*dialog);
        dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
-       dialog->set_visible(true);
 }
 
 void TrainPanel::goto_clicked()
@@ -180,6 +224,18 @@ void TrainPanel::timetable_clicked()
        dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
 }
 
+void TrainPanel::view_clicked()
+{
+       TrainView *dialog = new TrainView(engineer, train);
+       engineer.get_root().add(*dialog);
+       dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
+}
+
+void TrainPanel::expand_clicked()
+{
+       expand(!expanded);
+}
+
 void TrainPanel::speed_slider_changed(double value)
 {
        float speed = value/3.6*engineer.get_layout().get_catalogue().get_scale();
index 9b2a54414618264e2e693ce26912a205da6cb4bf..d15462ec61d8855d367dd899d289d58a89363eef 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the GPL
 #define TRAINPANEL_H_
 
 #include <sigc++/trackable.h>
+#include <msp/gltk/button.h>
 #include <msp/gltk/hslider.h>
 #include <msp/gltk/label.h>
 #include <msp/gltk/panel.h>
@@ -23,6 +24,9 @@ class TrainPanel: public Msp::GLtk::Panel, public sigc::trackable
 private:
        Engineer &engineer;
        Marklin::Train &train;
+       Msp::GLtk::Panel *pnl_basic;
+       Msp::GLtk::Panel *pnl_extra;
+       Msp::GLtk::Button *btn_expand;
        Msp::GLtk::Label *lbl_addr;
        Msp::GLtk::Label *lbl_name;
        Msp::GLtk::HSlider *sld_speed;
@@ -32,19 +36,25 @@ private:
        Msp::GLtk::Toggle *tgl_forward;
        std::map<unsigned, Msp::GLtk::Toggle *> tgl_funcs;
        sigc::connection pick_conn;
+       bool expanded;
 
 public:
        TrainPanel(Engineer &, const Msp::GLtk::Resources &, Marklin::Train &);
+       void expand(bool = true);
+
 private:
        void train_control_changed(const std::string &, float);
        void train_function_changed(unsigned, bool);
        void train_route_changed(const Marklin::Route *);
        void train_status_changed(const std::string &);
        void place_clicked();
+       void take_clicked();
        void edit_clicked();
        void route_clicked();
        void goto_clicked();
        void timetable_clicked();
+       void view_clicked();
+       void expand_clicked();
        void speed_slider_changed(double);
        void forward_toggled(bool);
        void func_toggled(bool, unsigned);
diff --git a/source/engineer/trainview.cpp b/source/engineer/trainview.cpp
new file mode 100644 (file)
index 0000000..b27136c
--- /dev/null
@@ -0,0 +1,123 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/gl/tests.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/image.h>
+#include "libmarklin/vehicle.h"
+#include "libmarklin/vehicletype.h"
+#include "engineer.h"
+#include "trainview.h"
+
+using namespace Msp;
+using namespace Marklin;
+
+TrainView::TrainView(Engineer &e, const Train &t):
+       GLtk::Widget(e.get_ui_resources()),
+       GLtk::Panel(e.get_ui_resources()),
+       engineer(e),
+       train(t),
+       mode(SIDE),
+       pipeline(280, 280, false),
+       stale(false)
+{
+       set_size(300, 330);
+
+       tex.set_min_filter(GL::LINEAR);
+       tex.storage(GL::RGB, 280, 280, 0);
+       tex.image(0, GL::RGB, GL::UNSIGNED_BYTE, 0);
+       fbo.attach(GL::COLOR_ATTACHMENT0, tex, 0);
+       depth.storage(GL::DEPTH_COMPONENT, 280, 280);
+       fbo.attach(GL::DEPTH_ATTACHMENT, depth);
+
+       camera.set_up_direction(GL::Vector3(0, 0, 1));
+       camera.set_depth_clip(0.01, 10);
+       camera.set_aspect(1);
+       pipeline.set_camera(&camera);
+
+       pipeline.add_renderable(engineer.get_layout_3d().get_scene());
+
+       GL::PipelinePass *pass = &pipeline.add_pass(0);
+       pass->depth_test = &GL::DepthTest::lequal();
+       pass->lighting = &engineer.get_lighting();
+
+       GLtk::Image *image;
+       add(*(image = new GLtk::Image(res, &tex)));
+       image->set_geometry(GLtk::Geometry(10, 40, geom.w-20, geom.h-50));
+
+       GLtk::Button *btn;
+
+       add(*(btn = new GLtk::Button(res, "Roof")));
+       btn->set_geometry(GLtk::Geometry(10, 10, 36, 25));
+       btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), ROOF));
+
+       add(*(btn = new GLtk::Button(res, "Side")));
+       btn->set_geometry(GLtk::Geometry(46, 10, 36, 25));
+       btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), SIDE));
+
+       add(*(btn = new GLtk::Button(res, "Head")));
+       btn->set_geometry(GLtk::Geometry(82, 10, 36, 25));
+       btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), HEAD));
+
+       add(*(btn = new GLtk::Button(res, "Close")));
+       btn->set_geometry(GLtk::Geometry(geom.w-46, 10, 36, 25));
+       btn->signal_clicked.connect(sigc::mem_fun(this, &TrainView::close_clicked));
+
+       engineer.add_train_view(*this);
+}
+
+TrainView::~TrainView()
+{
+       engineer.remove_train_view(*this);
+}
+
+void TrainView::set_mode(Mode m)
+{
+       mode = m;
+}
+
+void TrainView::prepare()
+{
+       const Vehicle &veh = train.get_vehicle(0);
+       const Point &pos = veh.get_position();
+       float angle = veh.get_direction();
+       float c = cos(angle);
+       float s = sin(angle);
+       float l = veh.get_type().get_length();
+
+       switch(mode)
+       {
+       case ROOF:
+               camera.set_position(GL::Vector3(pos.x-l*c, pos.y-l*s, pos.z+0.07));
+               camera.set_look_direction(GL::Vector3(c, s, -0.2));
+               break;
+       case SIDE:
+               camera.set_position(GL::Vector3(pos.x-l*0.8*c+0.05*s, pos.y-l*0.8*s-0.05*c, pos.z+0.03));
+               camera.set_look_direction(GL::Vector3(c-0.2*s, s+0.2*c, 0));
+               break;
+       case HEAD:
+               camera.set_position(GL::Vector3(pos.x+l*0.55*c, pos.y+l*0.55*s, pos.z+0.03));
+               camera.set_look_direction(GL::Vector3(c, s, 0));
+               break;
+       }
+
+       GL::Bind _bind_fbo(fbo);
+       fbo.clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
+       pipeline.render_all();
+}
+
+void TrainView::button_release(int x, int y, unsigned btn)
+{
+       GLtk::Panel::button_release(x, y, btn);
+       if(stale)
+               delete this;
+}
+
+void TrainView::close_clicked()
+{
+       stale = true;
+}
diff --git a/source/engineer/trainview.h b/source/engineer/trainview.h
new file mode 100644 (file)
index 0000000..16a1ef9
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef TRAINVIEW_H_
+#define TRAINVIEW_H_
+
+#include <msp/gl/renderbuffer.h>
+#include <msp/gl/framebuffer.h>
+#include <msp/gl/texture2d.h>
+#include <msp/gltk/panel.h>
+#include "libmarklin/train.h"
+
+class Engineer;
+
+class TrainView: public Msp::GLtk::Panel
+{
+public:
+       enum Mode
+       {
+               ROOF,
+               SIDE,
+               HEAD
+       };
+
+private:
+       Engineer &engineer;
+       const Marklin::Train &train;
+       Mode mode;
+       Msp::GL::Framebuffer fbo;
+       Msp::GL::Texture2D tex;
+       Msp::GL::Renderbuffer depth;
+       Msp::GL::Camera camera;
+       Msp::GL::Pipeline pipeline;
+       bool stale;
+
+public:
+       TrainView(Engineer &, const Marklin::Train &);
+       ~TrainView();
+
+       void set_mode(Mode);
+       void prepare();
+private:
+       virtual void button_release(int, int, unsigned);
+       void close_clicked();
+};
+
+#endif