From: Mikko Rasa Date: Fri, 29 Oct 2010 10:43:00 +0000 (+0000) Subject: Rewrite CameraController to make use of mouse X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=61da962442ae528bba9c66fa0c09427b53a4cbe0;p=r2c2.git Rewrite CameraController to make use of mouse --- 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; } diff --git a/source/designer/cameracontroller.h b/source/designer/cameracontroller.h index 63ba2c1..b39b3d5 100644 --- a/source/designer/cameracontroller.h +++ b/source/designer/cameracontroller.h @@ -11,24 +11,70 @@ Distributed under the GPL #include #include +class Designer; + +/** +Moves the camera based on keyboard and mouse events. Controls are as follows: + +Arrow keys - pan +Home - view all +Insert - view from top down +Wheel - adjust viewing distance +RMB - rotate +MMB - pan +Shift + RMB - pan +Shift + MMB - rotate +Ctrl + RMB - adjust viewing distance +Ctrl + MMB - adjust viewing distance +*/ class CameraController { private: - Msp::Graphics::Window &window; + enum DragMode + { + NONE, + PAN, + ROTATE, + DISTANCE + }; + + Designer &designer; + Msp::Graphics::EventSource &event_source; Msp::GL::Camera &camera; int move_x; int move_y; - int zoom; - int rotate; - int pitch; + int pointer_x; + int pointer_y; + DragMode drag_mode; public: - CameraController(Msp::Graphics::Window &, Msp::GL::Camera &); + CameraController(Designer &, Msp::Graphics::EventSource &, Msp::GL::Camera &); + + void top_down(); + void set_look_direction(const Msp::GL::Vector3 &); + void view_all(); + + void move(float, float); + void adjust_distance(float); + void rotate(float); + void pitch(float); void tick(float); private: + void button_press(int, int, unsigned, unsigned); + void button_release(int, int, unsigned, unsigned); + void pointer_motion(int, int); void key_press(unsigned, unsigned, wchar_t); void key_release(unsigned, unsigned); + + /** Return the focus point, i.e. where the look ray intersects with ground. */ + Msp::GL::Vector3 get_focus() const; + + /** Return distance from the focus point. */ + float get_distance() const; + + /** Return the viewport height at focus distance. */ + float get_view_scale() const; }; #endif diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 92c2f25..a31d244 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -48,7 +48,6 @@ Designer::Designer(int argc, char **argv): mode(SELECT), manipulator(*this, selection), measure(*this), - camera_ctl(window, camera), track_wrap(*this, selection) { window.set_title("Railway Designer"); @@ -111,7 +110,7 @@ Designer::Designer(int argc, char **argv): pass->blend = &GL::Blend::alpha(); camera.set_up_direction(GL::Vector3(0, 0, 1)); - view_all(); + camera.set_look_direction(GL::Vector3(0, 0.5, -0.866)); // Setup UI DataFile::load(ui_res, "marklin.res"); @@ -137,6 +136,9 @@ Designer::Designer(int argc, char **argv): overlay = new Overlay3D(window, camera, ui_res.get_default_font()); + camera_ctl = new CameraController(*this, *root, camera); + camera_ctl->view_all(); + const Layout3D::TrackMap &tracks = layout_3d->get_tracks(); for(Layout3D::TrackMap::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) update_track_icon(*i->second); @@ -144,6 +146,7 @@ Designer::Designer(int argc, char **argv): Designer::~Designer() { + delete camera_ctl; delete overlay; delete root; delete pipeline; @@ -263,7 +266,7 @@ void Designer::tick() window.get_display().tick(); root->tick(); - camera_ctl.tick(dt); + camera_ctl->tick(dt); for(list::iterator i=new_tracks.begin(); i!=new_tracks.end(); ++i) layout_3d->get_track(**i).get_path().set_mask(0); @@ -584,31 +587,6 @@ void Designer::route_name_accept(const string &text) cur_route->set_name(text); } -void Designer::view_all() -{ - Point minp; - Point maxp; - - const Layout3D::TrackMap &tracks = 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 cam_dist = size/t+size*0.25; - Point center((minp.x+maxp.x)/2, (minp.y+maxp.y)/2); - camera.set_position(GL::Vector3(center.x, center.y-cam_dist*0.5, cam_dist*0.866)); - camera.set_look_direction(GL::Vector3(0, 0.5, -0.866)); -} - string Designer::tooltip(int x, int y) { if(Track3D *t3d = pick_track(x, y)) diff --git a/source/designer/designer.h b/source/designer/designer.h index 63d2591..3aeb08c 100644 --- a/source/designer/designer.h +++ b/source/designer/designer.h @@ -70,7 +70,7 @@ private: Selection selection; Manipulator manipulator; Measure measure; - CameraController camera_ctl; + CameraController *camera_ctl; TrackWrap track_wrap; Msp::Time::TimeStamp last_tick; @@ -120,7 +120,6 @@ private: void turnout_id_accept(const std::string &); void sensor_id_accept(const std::string &); void route_name_accept(const std::string &); - void view_all(); std::string tooltip(int, int); void show_route(const Marklin::Route *); };