X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;ds=sidebyside;f=source%2Fdesigner%2Fcameracontroller.cpp;fp=source%2Fdesigner%2Fcameracontroller.cpp;h=bd7edbb530d540e73ac32296b80c6c57a3106180;hb=61da962442ae528bba9c66fa0c09427b53a4cbe0;hp=fb16bb862911f00988c0c88809fd99b481f103db;hpb=b3a73308d67de22a2d65cc56b14edeab25537eba;p=r2c2.git diff --git a/source/designer/cameracontroller.cpp b/source/designer/cameracontroller.cpp index fb16bb8..bd7edbb 100644 --- a/source/designer/cameracontroller.cpp +++ b/source/designer/cameracontroller.cpp @@ -8,51 +8,169 @@ Distributed under the GPL #include #include #include "cameracontroller.h" +#include "designer.h" using namespace std; using namespace Msp; +using namespace Marklin; -CameraController::CameraController(Graphics::Window &w, GL::Camera &c): - window(w), +CameraController::CameraController(Designer &d, Graphics::EventSource &es, GL::Camera &c): + designer(d), + event_source(es), camera(c), move_x(0), move_y(0), - zoom(0), - rotate(0), - pitch(0) + drag_mode(NONE) { - window.signal_key_press.connect(sigc::mem_fun(this, &CameraController::key_press)); - window.signal_key_release.connect(sigc::mem_fun(this, &CameraController::key_release)); + event_source.signal_button_press.connect(sigc::mem_fun(this, &CameraController::button_press)); + event_source.signal_button_release.connect(sigc::mem_fun(this, &CameraController::button_release)); + event_source.signal_pointer_motion.connect(sigc::mem_fun(this, &CameraController::pointer_motion)); + event_source.signal_key_press.connect(sigc::mem_fun(this, &CameraController::key_press)); + event_source.signal_key_release.connect(sigc::mem_fun(this, &CameraController::key_release)); } -void CameraController::tick(float dt) +void CameraController::top_down() +{ + const GL::Vector3 &look = camera.get_look_direction(); + float xy_len = sqrt(look.x*look.x+look.y*look.y); + set_look_direction(GL::Vector3(look.x*0.01/xy_len, look.y*0.01/xy_len, -0.99995)); +} + +void CameraController::set_look_direction(const GL::Vector3 &look) +{ + GL::Vector3 focus = get_focus(); + float dist = get_distance(); + camera.set_look_direction(look); + camera.set_position(GL::Vector3(focus.x-look.x*dist, focus.y-look.y*dist, focus.z-look.z*dist)); +} + +void CameraController::view_all() +{ + Point minp; + Point maxp; + + const Layout3D::TrackMap &tracks = designer.get_layout_3d().get_tracks(); + for(Layout3D::TrackMap::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + { + Point tmin; + Point tmax; + i->second->get_bounds(0, tmin, tmax); + minp.x = min(minp.x, tmin.x); + minp.y = min(minp.y, tmin.y); + maxp.x = max(maxp.x, tmax.x); + maxp.y = max(maxp.y, tmax.y); + } + + float t = tan(camera.get_field_of_view()/2)*2; + float size = max((maxp.y-minp.y+0.1), (maxp.x-minp.x+0.1)/camera.get_aspect()); + float dist = size/t+size*0.25; + GL::Vector3 center((minp.x+maxp.x)/2, (minp.y+maxp.y)/2, 0); + const GL::Vector3 &look = camera.get_look_direction(); + camera.set_position(GL::Vector3(center.x-look.x*dist, center.y-look.y*dist, center.z-look.z*dist)); +} + +void CameraController::move(float x, float y) +{ + const GL::Vector3 &pos = camera.get_position(); + const GL::Vector3 &look = camera.get_look_direction(); + float xy_len = sqrt(look.x*look.x+look.y*look.y); + float dx = (look.x*y+look.y*x)/xy_len; + float dy = (look.y*y-look.x*x)/xy_len; + camera.set_position(GL::Vector3(pos.x+dx, pos.y+dy, pos.z)); +} + +void CameraController::adjust_distance(float delta) +{ + const GL::Vector3 &pos = camera.get_position(); + const GL::Vector3 &look = camera.get_look_direction(); + camera.set_position(GL::Vector3(pos.x-look.x*delta, pos.y-look.y*delta, pos.z-look.z*delta)); +} + +void CameraController::rotate(float angle) { - if(!move_x && !move_y && !zoom && !rotate && !pitch) - return; + GL::Vector3 look = camera.get_look_direction(); + float c = cos(angle); + float s = sin(angle); + set_look_direction(GL::Vector3(look.x*c-look.y*s, look.x*s+look.y*c, look.z)); +} - GL::Vector3 pos = camera.get_position(); +void CameraController::pitch(float angle) +{ GL::Vector3 look = camera.get_look_direction(); float xy_len = sqrt(look.x*look.x+look.y*look.y); - GL::Vector3 look_xy(look.x/xy_len, look.y/xy_len, 0); - GL::Vector3 ground(pos.x-look.x*pos.z/look.z, pos.y-look.y*pos.z/look.z, 0); + float c = cos(angle); + float s = sin(angle); + if(xy_len*c-look.z*s<0.01) + top_down(); + else if(xy_len*s+look.z*c>-0.01) + set_look_direction(GL::Vector3(look.x*0.99995/xy_len, look.y*0.99995/xy_len, -0.01)); + else + { + float xy_scale = (xy_len*c-look.z*s)/xy_len; + set_look_direction(GL::Vector3(look.x*xy_scale, look.y*xy_scale, xy_len*s+look.z*c)); + } +} + +void CameraController::tick(float dt) +{ + if(move_x || move_y) + { + float scale = get_view_scale()*dt; + move(move_x*scale, move_y*scale); + } +} + +void CameraController::button_press(int x, int y, unsigned btn, unsigned mod) +{ + mod = Input::mod_from_sys(mod); + if(btn==2 || btn==3) + { + if(mod&Input::MOD_CONTROL) + drag_mode = DISTANCE; + else + drag_mode = ((btn==2)==((mod&Input::MOD_SHIFT)!=0) ? ROTATE : PAN); - if(rotate || pitch) + pointer_x = x; + pointer_y = y; + } + else if(btn==4) + { + adjust_distance(-get_distance()*0.1); + } + else if(btn==5) { - float speed = -3*dt*xy_len*pos.z/look.z; - pos.x += (look_xy.y*rotate - look_xy.x*look.z*pitch)*speed; - pos.y += (-look_xy.x*rotate - look_xy.y*look.z*pitch)*speed; - pos.z += xy_len*pitch*speed; - camera.set_position(pos); - camera.look_at(ground); + adjust_distance(get_distance()*0.1); } +} + +void CameraController::button_release(int, int, unsigned btn, unsigned) +{ + if(btn==2 || btn==3) + drag_mode = NONE; +} - if(move_x || move_y || zoom) +void CameraController::pointer_motion(int x, int y) +{ + if(drag_mode!=NONE) { - float zoom_speed = -zoom*pos.z/look.z; - pos.x += (look_xy.x*move_y + look_xy.y*move_x + look.x*zoom_speed)*dt; - pos.y += (look_xy.y*move_y - look_xy.x*move_x + look.y*zoom_speed)*dt; - pos.z += look.z*dt*zoom_speed; - camera.set_position(pos); + int dx = x-pointer_x; + int dy = y-pointer_y; + + if(drag_mode==PAN) + { + float scale = get_view_scale()/event_source.get_height(); + move(-dx*scale, dy*scale); + } + else if(drag_mode==ROTATE) + { + rotate(-dx*M_PI*2/event_source.get_width()); + pitch(-dy*M_PI/event_source.get_height()); + } + else if(drag_mode==DISTANCE) + adjust_distance(dy*3*get_distance()/event_source.get_height()); + + pointer_x = x; + pointer_y = y; } } @@ -61,25 +179,17 @@ void CameraController::key_press(unsigned code, unsigned, wchar_t) unsigned key = Msp::Input::key_from_sys(code); if(key==Msp::Input::KEY_RIGHT) - rotate = -1; + move_x = 1; else if(key==Msp::Input::KEY_LEFT) - rotate = 1; + move_x = -1; else if(key==Msp::Input::KEY_UP) move_y = 1; else if(key==Msp::Input::KEY_DOWN) move_y = -1; - else if(key==Msp::Input::KEY_INSERT) - zoom = -1; - else if(key==Msp::Input::KEY_PGUP) - zoom = 1; else if(key==Msp::Input::KEY_HOME) - pitch = 1; - else if(key==Msp::Input::KEY_END) - pitch = -1; - else if(key==Msp::Input::KEY_DELETE) - move_x = -1; - else if(key==Msp::Input::KEY_PGDN) - move_x = 1; + view_all(); + else if(key==Msp::Input::KEY_INSERT) + top_down(); } void CameraController::key_release(unsigned code, unsigned) @@ -87,13 +197,26 @@ void CameraController::key_release(unsigned code, unsigned) unsigned key = Msp::Input::key_from_sys(code); if(key==Msp::Input::KEY_RIGHT || key==Msp::Input::KEY_LEFT) - rotate = 0; + move_x = 0; else if(key==Msp::Input::KEY_UP || key==Msp::Input::KEY_DOWN) move_y = 0; - else if(key==Msp::Input::KEY_INSERT || key==Msp::Input::KEY_PGUP) - zoom = 0; - else if(key==Msp::Input::KEY_HOME || key==Msp::Input::KEY_END) - pitch = 0; - else if(key==Msp::Input::KEY_DELETE || key==Msp::Input::KEY_PGDN) - move_x = 0; +} + +GL::Vector3 CameraController::get_focus() const +{ + const GL::Vector3 &pos = camera.get_position(); + const GL::Vector3 &look = camera.get_look_direction(); + float dist = get_distance(); + return GL::Vector3(pos.x+look.x*dist, pos.y+look.y*dist, pos.z+look.z*dist); +} + +float CameraController::get_distance() const +{ + return -camera.get_position().z/camera.get_look_direction().z; +} + +float CameraController::get_view_scale() const +{ + float t = tan(camera.get_field_of_view()/2)*2; + return get_distance()*t; }