]> git.tdb.fi Git - r2c2.git/blob - source/designer/cameracontroller.cpp
Add View3D class to bundle Layout3D with a camera and a pipeline
[r2c2.git] / source / designer / cameracontroller.cpp
1 /* $Id$
2
3 This file is part of R²C²
4 Copyright © 2010-2011 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <cmath>
9 #include <msp/input/keys.h>
10 #include "3d/layout.h"
11 #include "cameracontroller.h"
12
13 using namespace std;
14 using namespace Msp;
15 using namespace R2C2;
16
17 CameraController::CameraController(View3D &v, Graphics::EventSource &es):
18         view(v),
19         event_source(es),
20         camera(view.get_camera()),
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         view.view_all();
50 }
51
52 void CameraController::move(float x, float y)
53 {
54         const GL::Vector3 &pos = camera.get_position();
55         const GL::Vector3 &look = camera.get_look_direction();
56         float xy_len = sqrt(look.x*look.x+look.y*look.y);
57         float dx = (look.x*y+look.y*x)/xy_len;
58         float dy = (look.y*y-look.x*x)/xy_len;
59         camera.set_position(GL::Vector3(pos.x+dx, pos.y+dy, pos.z));
60 }
61
62 void CameraController::adjust_distance(float delta)
63 {
64         const GL::Vector3 &pos = camera.get_position();
65         const GL::Vector3 &look = camera.get_look_direction();
66         float dist = get_distance();
67         float low = view.get_layout().get_layout().get_catalogue().get_gauge()*5;
68         if(dist+delta<low)
69                 delta = low-dist;
70         camera.set_position(GL::Vector3(pos.x-look.x*delta, pos.y-look.y*delta, pos.z-look.z*delta));
71         dist += delta;
72         camera.set_depth_clip(dist*0.02, dist*50);
73 }
74
75 void CameraController::rotate(float angle)
76 {
77         GL::Vector3 look = camera.get_look_direction();
78         float c = cos(angle);
79         float s = sin(angle);
80         set_look_direction(GL::Vector3(look.x*c-look.y*s, look.x*s+look.y*c, look.z));
81 }
82
83 void CameraController::pitch(float angle)
84 {
85         GL::Vector3 look = camera.get_look_direction();
86         float xy_len = sqrt(look.x*look.x+look.y*look.y);
87         float c = cos(angle);
88         float s = sin(angle);
89         if(xy_len*c-look.z*s<0.01)
90                 top_down();
91         else if(xy_len*s+look.z*c>-0.01)
92                 set_look_direction(GL::Vector3(look.x*0.99995/xy_len, look.y*0.99995/xy_len, -0.01));
93         else
94         {
95                 float xy_scale = (xy_len*c-look.z*s)/xy_len;
96                 set_look_direction(GL::Vector3(look.x*xy_scale, look.y*xy_scale, xy_len*s+look.z*c));
97         }
98 }
99
100 void CameraController::tick(float dt)
101 {
102         if(move_x || move_y)
103         {
104                 float scale = get_view_scale()*dt;
105                 move(move_x*scale, move_y*scale);
106         }
107 }
108
109 void CameraController::button_press(int x, int y, unsigned btn, unsigned mod)
110 {
111         mod = Input::mod_from_sys(mod);
112         if(btn==2 || btn==3)
113         {
114                 if(mod&Input::MOD_CONTROL)
115                         drag_mode = DISTANCE;
116                 else
117                         drag_mode = ((btn==2)==((mod&Input::MOD_SHIFT)!=0) ? ROTATE : PAN);
118
119                 pointer_x = x;
120                 pointer_y = y;
121         }
122         else if(btn==4)
123         {
124                 adjust_distance(-get_distance()*0.1);
125         }
126         else if(btn==5)
127         {
128                 adjust_distance(get_distance()*0.1);
129         }
130 }
131
132 void CameraController::button_release(int, int, unsigned btn, unsigned)
133 {
134         if(btn==2 || btn==3)
135                 drag_mode = NONE;
136 }
137
138 void CameraController::pointer_motion(int x, int y)
139 {
140         if(drag_mode!=NONE)
141         {
142                 int dx = x-pointer_x;
143                 int dy = y-pointer_y;
144
145                 if(drag_mode==PAN)
146                 {
147                         float scale = get_view_scale()/event_source.get_height();
148                         move(-dx*scale, dy*scale);
149                 }
150                 else if(drag_mode==ROTATE)
151                 {
152                         rotate(-dx*M_PI*2/event_source.get_width());
153                         pitch(-dy*M_PI/event_source.get_height());
154                 }
155                 else if(drag_mode==DISTANCE)
156                         adjust_distance(dy*3*get_distance()/event_source.get_height());
157
158                 pointer_x = x;
159                 pointer_y = y;
160         }
161 }
162
163 void CameraController::key_press(unsigned code, unsigned, wchar_t)
164 {
165         unsigned key = Msp::Input::key_from_sys(code);
166
167         if(key==Msp::Input::KEY_RIGHT)
168                 move_x = 1;
169         else if(key==Msp::Input::KEY_LEFT)
170                 move_x = -1;
171         else if(key==Msp::Input::KEY_UP)
172                 move_y = 1;
173         else if(key==Msp::Input::KEY_DOWN)
174                 move_y = -1;
175         else if(key==Msp::Input::KEY_HOME)
176                 view_all();
177         else if(key==Msp::Input::KEY_INSERT)
178                 top_down();
179 }
180
181 void CameraController::key_release(unsigned code, unsigned)
182 {
183         unsigned key = Msp::Input::key_from_sys(code);
184
185         if(key==Msp::Input::KEY_RIGHT || key==Msp::Input::KEY_LEFT)
186                 move_x = 0;
187         else if(key==Msp::Input::KEY_UP || key==Msp::Input::KEY_DOWN)
188                 move_y = 0;
189 }
190
191 GL::Vector3 CameraController::get_focus() const
192 {
193         const GL::Vector3 &pos = camera.get_position();
194         const GL::Vector3 &look = camera.get_look_direction();
195         float dist = get_distance();
196         return GL::Vector3(pos.x+look.x*dist, pos.y+look.y*dist, pos.z+look.z*dist);
197 }
198
199 float CameraController::get_distance() const
200 {
201         return -camera.get_position().z/camera.get_look_direction().z;
202 }
203
204 float CameraController::get_view_scale() const
205 {
206         float t = tan(camera.get_field_of_view()/2)*2;
207         return get_distance()*t;
208 }