]> git.tdb.fi Git - r2c2.git/blob - source/designer/terraintool.cpp
Don't crash if a train has no router
[r2c2.git] / source / designer / terraintool.cpp
1 #include <cmath>
2 #include <msp/gl/meshbuilder.h>
3 #include <msp/input/keys.h>
4 #include "designer.h"
5 #include "terraintool.h"
6
7 using namespace std;
8 using namespace Msp;
9 using namespace R2C2;
10
11 TerrainTool::TerrainTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, Terrain &t):
12         Tool(d, k, m),
13         terrain(t),
14         marker((GL::VERTEX3, GL::COLOR4_UBYTE)),
15         edit_size(0),
16         marker_orientation(0),
17         dragging(false),
18         drag_start(0)
19 {
20         designer.get_layout_3d().get_scene().add(*this);
21
22         update_marker();
23 }
24
25 TerrainTool::~TerrainTool()
26 {
27         designer.get_layout_3d().get_scene().remove(*this);
28 }
29
30 void TerrainTool::update_marker()
31 {
32         marker.clear();
33         GL::MeshBuilder bld(marker);
34
35         float ts = terrain.get_type().get_tile_size();
36         bld.matrix() *= GL::Matrix::translation(edit_size/2*-ts, edit_size/2*-ts, 0);
37         if(shift_held)
38         {
39                 bld.begin(GL::TRIANGLE_STRIP);
40                 if(edit_size==0)
41                 {
42                         bld.vertex(0, ts/2, ts/4);
43                         bld.vertex(0, ts/2, -ts/4);
44                         bld.vertex(0, 0, ts/4);
45                         bld.vertex(0, 0, -ts/4);
46                         bld.vertex(ts/2, 0, ts/4);
47                         bld.vertex(ts/2, 0, -ts/4);
48                 }
49                 else
50                 {
51                         bld.vertex(0, 0, ts/4);
52                         bld.vertex(0, 0, -ts/4);
53                         bld.vertex(edit_size*ts, 0, ts/4);
54                         bld.vertex(edit_size*ts, 0, -ts/4);
55                         bld.vertex(edit_size*ts, edit_size*ts, ts/4);
56                         bld.vertex(edit_size*ts, edit_size*ts, -ts/4);
57                         bld.vertex(0, edit_size*ts, ts/4);
58                         bld.vertex(0, edit_size*ts, -ts/4);
59                         bld.element(0);
60                         bld.element(1);
61                 }
62                 bld.end();
63         }
64         else
65         {
66                 bld.begin(GL::TRIANGLE_STRIP);
67                 bld.vertex(-ts/2, 0, ts/4);
68                 bld.vertex(-ts/2, 0, -ts/4);
69                 bld.vertex((edit_size+0.5)*ts, 0, ts/4);
70                 bld.vertex((edit_size+0.5)*ts, 0, -ts/4);
71                 bld.end();
72                 bld.begin(GL::TRIANGLE_STRIP);
73                 bld.vertex(0, -ts/2, ts/4);
74                 bld.vertex(0, -ts/2, -ts/4);
75                 bld.vertex(0, (edit_size+0.5)*ts, ts/4);
76                 bld.vertex(0, (edit_size+0.5)*ts, -ts/4);
77                 bld.end();
78                 if(edit_size>0)
79                 {
80                         bld.begin(GL::TRIANGLE_STRIP);
81                         bld.vertex(-ts/2, edit_size*ts, ts/4);
82                         bld.vertex(-ts/2, edit_size*ts, -ts/4);
83                         bld.vertex((edit_size+0.5)*ts, edit_size*ts, ts/4);
84                         bld.vertex((edit_size+0.5)*ts, edit_size*ts, -ts/4);
85                         bld.end();
86                         bld.begin(GL::TRIANGLE_STRIP);
87                         bld.vertex(edit_size*ts, -ts/2, ts/4);
88                         bld.vertex(edit_size*ts, -ts/2, -ts/4);
89                         bld.vertex(edit_size*ts, (edit_size+0.5)*ts, ts/4);
90                         bld.vertex(edit_size*ts, (edit_size+0.5)*ts, -ts/4);
91                         bld.end();
92                 }
93         }
94 }
95
96 void TerrainTool::key_press(unsigned key)
97 {
98         if(key==Input::KEY_PLUS)
99         {
100                 ++edit_size;
101                 update_marker();
102         }
103         else if(key==Input::KEY_MINUS)
104         {
105                 if(edit_size>0)
106                 {
107                         --edit_size;
108                         update_marker();
109                 }
110         }
111         else
112         {
113                 bool shift_was_held = shift_held;
114                 Tool::key_press(key);
115                 if(shift_held!=shift_was_held)
116                         update_marker();
117         }
118 }
119
120 void TerrainTool::key_release(unsigned key)
121 {
122         bool shift_was_held = shift_held;
123         Tool::key_release(key);
124         if(shift_held!=shift_was_held)
125                 update_marker();
126 }
127
128 void TerrainTool::button_press(unsigned btn)
129 {
130         if(btn==1)
131         {
132                 dragging = true;
133                 drag_start = pointer.y;
134         }
135 }
136
137 void TerrainTool::button_release(unsigned btn)
138 {
139         if(btn==1)
140                 dragging = false;
141 }
142
143 void TerrainTool::pointer_motion()
144 {
145         if(dragging)
146         {
147                 float d = (pointer.y-drag_start)*20;
148
149                 if(abs(d)>1)
150                 {
151                         float elev = terrain.get_node_elevation(highlight_node);
152                         float eg = terrain.get_type().get_elevation_granularity();
153                         elev += eg*d;
154                         if(edit_size==0)
155                                 terrain.set_node_elevation(highlight_node, elev, !shift_held);
156                         else
157                         {
158                                 unsigned bx = highlight_node.x-edit_size/2;
159                                 unsigned by = highlight_node.y-edit_size/2;
160                                 if(edit_size%2==0)
161                                 {
162                                         bx += highlight_node.i%2;
163                                         by += highlight_node.i/2;
164                                 }
165
166                                 // TODO make it possible to adjust the area without flattening it
167                                 for(unsigned y=0; y<edit_size; ++y)
168                                         for(unsigned x=0; x<edit_size; ++x)
169                                                 for(unsigned i=0; i<4; ++i)
170                                                 {
171                                                         Terrain::NodeCoordinates c(bx+x, by+y, i);
172                                                         if(c.x<terrain.get_width() && c.y<terrain.get_height())
173                                                                 terrain.set_node_elevation(c, elev, !shift_held);
174                                                 }
175                         }
176
177                         marker_position = terrain.get_node_position(highlight_node);
178                         drag_start = pointer.y;
179                 }
180         }
181         else
182         {
183                 Ray ray = designer.get_view().create_ray(pointer.x, pointer.y);
184                 highlight_node = terrain.get_closest_node(ray);
185                 marker_position = terrain.get_node_position(highlight_node);
186                 marker_orientation = highlight_node.i^(highlight_node.i>>1);
187         }
188 }
189
190 void TerrainTool::render(GL::Renderer &renderer, const GL::Tag &tag) const
191 {
192         if(tag.id)
193                 return;
194
195         GL::Renderer::Push push(renderer);
196
197         renderer.matrix_stack() *= GL::Matrix::translation(marker_position);
198         renderer.matrix_stack() *= GL::Matrix::rotation(Angle::from_turns(marker_orientation*0.25), 0, 0, 1);
199         marker.draw(renderer);
200 }