]> git.tdb.fi Git - r2c2.git/blob - source/designer/cameracontroller.cpp
Rename the project to R²C²
[r2c2.git] / source / designer / cameracontroller.cpp
1 /* $Id$
2
3 This file is part of R²C²
4 Copyright © 2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <cmath>
9 #include <msp/input/keys.h>
10 #include "cameracontroller.h"
11 #include "designer.h"
12
13 using namespace std;
14 using namespace Msp;
15 using namespace R2C2;
16
17 CameraController::CameraController(Designer &d, Graphics::EventSource &es, GL::Camera &c):
18         designer(d),
19         event_source(es),
20         camera(c),
21         move_x(0),
22         move_y(0),
23         drag_mode(NONE)
24 {
25         event_source.signal_button_press.connect(sigc::mem_fun(this, &CameraController::button_press));
26         event_source.signal_button_release.connect(sigc::mem_fun(this, &CameraController::button_release));
27         event_source.signal_pointer_motion.connect(sigc::mem_fun(this, &CameraController::pointer_motion));
28         event_source.signal_key_press.connect(sigc::mem_fun(this, &CameraController::key_press));
29         event_source.signal_key_release.connect(sigc::mem_fun(this, &CameraController::key_release));
30 }
31
32 void CameraController::top_down()
33 {
34         const GL::Vector3 &look = camera.get_look_direction();
35         float xy_len = sqrt(look.x*look.x+look.y*look.y);
36         set_look_direction(GL::Vector3(look.x*0.01/xy_len, look.y*0.01/xy_len, -0.99995));
37 }
38
39 void CameraController::set_look_direction(const GL::Vector3 &look)
40 {
41         GL::Vector3 focus = get_focus();
42         float dist = get_distance();
43         camera.set_look_direction(look);
44         camera.set_position(GL::Vector3(focus.x-look.x*dist, focus.y-look.y*dist, focus.z-look.z*dist));
45 }
46
47 void CameraController::view_all()
48 {
49         Point minp;
50         Point maxp;
51
52         const Layout3D::TrackMap &tracks = designer.get_layout_3d().get_tracks();
53         for(Layout3D::TrackMap::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
54         {
55                 Point tmin;
56                 Point tmax;
57                 i->second->get_bounds(0, tmin, tmax);
58                 minp.x = min(minp.x, tmin.x);
59                 minp.y = min(minp.y, tmin.y);
60                 maxp.x = max(maxp.x, tmax.x);
61                 maxp.y = max(maxp.y, tmax.y);
62         }
63
64         float t = tan(camera.get_field_of_view()/2)*2;
65         float size = max((maxp.y-minp.y+0.1), (maxp.x-minp.x+0.1)/camera.get_aspect());
66         float dist = size/t+size*0.25;
67         GL::Vector3 center((minp.x+maxp.x)/2, (minp.y+maxp.y)/2, 0);
68         const GL::Vector3 &look = camera.get_look_direction();
69         camera.set_position(GL::Vector3(center.x-look.x*dist, center.y-look.y*dist, center.z-look.z*dist));
70 }
71
72 void CameraController::move(float x, float y)
73 {
74         const GL::Vector3 &pos = camera.get_position();
75         const GL::Vector3 &look = camera.get_look_direction();
76         float xy_len = sqrt(look.x*look.x+look.y*look.y);
77         float dx = (look.x*y+look.y*x)/xy_len;
78         float dy = (look.y*y-look.x*x)/xy_len;
79         camera.set_position(GL::Vector3(pos.x+dx, pos.y+dy, pos.z));
80 }
81
82 void CameraController::adjust_distance(float delta)
83 {
84         const GL::Vector3 &pos = camera.get_position();
85         const GL::Vector3 &look = camera.get_look_direction();
86         float dist = get_distance();
87         float low = designer.get_layout().get_catalogue().get_gauge()*5;
88         if(dist+delta<low)
89                 delta = low-dist;
90         camera.set_position(GL::Vector3(pos.x-look.x*delta, pos.y-look.y*delta, pos.z-look.z*delta));
91         dist += delta;
92         camera.set_depth_clip(dist*0.02, dist*50);
93 }
94
95 void CameraController::rotate(float angle)
96 {
97         GL::Vector3 look = camera.get_look_direction();
98         float c = cos(angle);
99         float s = sin(angle);
100         set_look_direction(GL::Vector3(look.x*c-look.y*s, look.x*s+look.y*c, look.z));
101 }
102
103 void CameraController::pitch(float angle)
104 {
105         GL::Vector3 look = camera.get_look_direction();
106         float xy_len = sqrt(look.x*look.x+look.y*look.y);
107         float c = cos(angle);
108         float s = sin(angle);
109         if(xy_len*c-look.z*s<0.01)
110                 top_down();
111         else if(xy_len*s+look.z*c>-0.01)
112                 set_look_direction(GL::Vector3(look.x*0.99995/xy_len, look.y*0.99995/xy_len, -0.01));
113         else
114         {
115                 float xy_scale = (xy_len*c-look.z*s)/xy_len;
116                 set_look_direction(GL::Vector3(look.x*xy_scale, look.y*xy_scale, xy_len*s+look.z*c));
117         }
118 }
119
120 void CameraController::tick(float dt)
121 {
122         if(move_x || move_y)
123         {
124                 float scale = get_view_scale()*dt;
125                 move(move_x*scale, move_y*scale);
126         }
127 }
128
129 void CameraController::button_press(int x, int y, unsigned btn, unsigned mod)
130 {
131         mod = Input::mod_from_sys(mod);
132         if(btn==2 || btn==3)
133         {
134                 if(mod&Input::MOD_CONTROL)
135                         drag_mode = DISTANCE;
136                 else
137                         drag_mode = ((btn==2)==((mod&Input::MOD_SHIFT)!=0) ? ROTATE : PAN);
138
139                 pointer_x = x;
140                 pointer_y = y;
141         }
142         else if(btn==4)
143         {
144                 adjust_distance(-get_distance()*0.1);
145         }
146         else if(btn==5)
147         {
148                 adjust_distance(get_distance()*0.1);
149         }
150 }
151
152 void CameraController::button_release(int, int, unsigned btn, unsigned)
153 {
154         if(btn==2 || btn==3)
155                 drag_mode = NONE;
156 }
157
158 void CameraController::pointer_motion(int x, int y)
159 {
160         if(drag_mode!=NONE)
161         {
162                 int dx = x-pointer_x;
163                 int dy = y-pointer_y;
164
165                 if(drag_mode==PAN)
166                 {
167                         float scale = get_view_scale()/event_source.get_height();
168                         move(-dx*scale, dy*scale);
169                 }
170                 else if(drag_mode==ROTATE)
171                 {
172                         rotate(-dx*M_PI*2/event_source.get_width());
173                         pitch(-dy*M_PI/event_source.get_height());
174                 }
175                 else if(drag_mode==DISTANCE)
176                         adjust_distance(dy*3*get_distance()/event_source.get_height());
177
178                 pointer_x = x;
179                 pointer_y = y;
180         }
181 }
182
183 void CameraController::key_press(unsigned code, unsigned, wchar_t)
184 {
185         unsigned key = Msp::Input::key_from_sys(code);
186
187         if(key==Msp::Input::KEY_RIGHT)
188                 move_x = 1;
189         else if(key==Msp::Input::KEY_LEFT)
190                 move_x = -1;
191         else if(key==Msp::Input::KEY_UP)
192                 move_y = 1;
193         else if(key==Msp::Input::KEY_DOWN)
194                 move_y = -1;
195         else if(key==Msp::Input::KEY_HOME)
196                 view_all();
197         else if(key==Msp::Input::KEY_INSERT)
198                 top_down();
199 }
200
201 void CameraController::key_release(unsigned code, unsigned)
202 {
203         unsigned key = Msp::Input::key_from_sys(code);
204
205         if(key==Msp::Input::KEY_RIGHT || key==Msp::Input::KEY_LEFT)
206                 move_x = 0;
207         else if(key==Msp::Input::KEY_UP || key==Msp::Input::KEY_DOWN)
208                 move_y = 0;
209 }
210
211 GL::Vector3 CameraController::get_focus() const
212 {
213         const GL::Vector3 &pos = camera.get_position();
214         const GL::Vector3 &look = camera.get_look_direction();
215         float dist = get_distance();
216         return GL::Vector3(pos.x+look.x*dist, pos.y+look.y*dist, pos.z+look.z*dist);
217 }
218
219 float CameraController::get_distance() const
220 {
221         return -camera.get_position().z/camera.get_look_direction().z;
222 }
223
224 float CameraController::get_view_scale() const
225 {
226         float t = tan(camera.get_field_of_view()/2)*2;
227         return get_distance()*t;
228 }