]> git.tdb.fi Git - r2c2.git/blob - source/3d/layout.cpp
Fix a segfault in removing vehicles when creating a new train
[r2c2.git] / source / 3d / layout.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <algorithm>
9 #include <limits>
10 #include <msp/gl/clip.h>
11 #include <msp/gl/matrix.h>
12 #include <msp/gl/rendermode.h>
13 #include <msp/gl/select.h>
14 #include <msp/gl/texture.h>
15 #include <msp/datafile/parser.h>
16 #include "layout.h"
17 #include "track.h"
18 #include "vehicle.h"
19
20 using namespace std;
21 using namespace Msp;
22
23 namespace Marklin {
24
25 Layout3D::Layout3D(Layout &l):
26         layout(l),
27         catalogue(layout.get_catalogue())
28 {
29         layout.signal_track_added.connect(sigc::mem_fun(this, &Layout3D::track_added));
30         layout.signal_track_removed.connect(sigc::mem_fun(this, &Layout3D::track_removed));
31         layout.signal_vehicle_added.connect(sigc::mem_fun(this, &Layout3D::vehicle_added));
32         layout.signal_vehicle_removed.connect(sigc::mem_fun(this, &Layout3D::vehicle_removed));
33
34         const set<Track *> &ltracks = layout.get_tracks();
35         for(set<Track *>::iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
36                 track_added(**i);
37 }
38
39 Layout3D::~Layout3D()
40 {
41         while(!tracks.empty())
42                 delete tracks.begin()->second;
43         while(!vehicles.empty())
44                 delete vehicles.begin()->second;
45 }
46
47 void Layout3D::add_track(Track3D &t)
48 {
49         if(tracks.count(&t.get_track()))
50                 throw KeyError("Duplicate track");
51
52         tracks[&t.get_track()] = &t;
53 }
54
55 void Layout3D::remove_track(Track3D &t)
56 {
57         tracks.erase(&t.get_track());
58 }
59
60 Track3D &Layout3D::get_track(Track &t) const
61 {
62         TrackMap::const_iterator i = tracks.find(&t);
63         if(i==tracks.end())
64                 throw KeyError("Unknown track");
65
66         return *i->second;
67 }
68
69 Track3D *Layout3D::pick_track(float x, float y, float size) const
70 {
71         vector<GL::SelectRecord> select_buf;
72         GL::select_buffer(select_buf);
73         GL::render_mode(GL::SELECT);
74
75         {
76                 GL::PushMatrix push_mat;
77                 GL::load_identity();
78
79                 GL::ClipPlane(1, 0, x-size, 0).apply_to(0);
80                 GL::ClipPlane(-1, 0, -x-size, 0).apply_to(1);
81                 GL::ClipPlane(0, 1, y-size, 0).apply_to(2);
82                 GL::ClipPlane(0, -1, -y-size, 0).apply_to(3);
83         }
84
85         scene.render(0);
86
87         GL::ClipPlane::disable(0);
88         GL::ClipPlane::disable(1);
89         GL::ClipPlane::disable(2);
90         GL::ClipPlane::disable(3);
91
92         GL::render_mode(GL::RENDER);
93         Track3D *track = 0;
94         unsigned track_depth = numeric_limits<unsigned>::max();
95         for(vector<GL::SelectRecord>::iterator i=select_buf.begin(); i!=select_buf.end(); ++i)
96                 if(i->min_depth<track_depth && !i->names.empty())
97                 {
98                         track = reinterpret_cast<Track3D *>(i->names.back());
99                         track_depth = i->min_depth;
100                 }
101
102         return track;
103 }
104
105 void Layout3D::add_vehicle(Vehicle3D &v)
106 {
107         if(vehicles.count(&v.get_vehicle()))
108                 throw KeyError("Duplicate vehicle");
109
110         vehicles[&v.get_vehicle()] = &v;
111 }
112
113 void Layout3D::remove_vehicle(Vehicle3D &v)
114 {
115         vehicles.erase(&v.get_vehicle());
116 }
117
118 Vehicle3D &Layout3D::get_vehicle(Vehicle &v) const
119 {
120         VehicleMap::const_iterator i = vehicles.find(&v);
121         if(i==vehicles.end())
122                 throw KeyError("Unknown vehicle");
123
124         return *i->second;
125 }
126
127 void Layout3D::track_added(Track &t)
128 {
129         new Track3D(*this, t);
130 }
131
132 void Layout3D::track_removed(Track &t)
133 {
134         TrackMap::iterator i = tracks.find(&t);
135         if(i!=tracks.end())
136                 delete i->second;
137 }
138
139 void Layout3D::vehicle_added(Vehicle &v)
140 {
141         new Vehicle3D(*this, v);
142 }
143
144 void Layout3D::vehicle_removed(Vehicle &v)
145 {
146         VehicleMap::iterator i = vehicles.find(&v);
147         if(i!=vehicles.end())
148                 delete i->second;
149 }
150
151 } // namespace Marklin