X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fdesigner%2Fcameracontroller.cpp;h=7b7e5f1339672d0dac127d8a5931a76d6f54ef57;hb=5929b101ee38b5668b328e7b1eac4bf49c912412;hp=fb16bb862911f00988c0c88809fd99b481f103db;hpb=e07c0d862a4d43b2585c93e79d25380d00675309;p=r2c2.git diff --git a/source/designer/cameracontroller.cpp b/source/designer/cameracontroller.cpp index fb16bb8..7b7e5f1 100644 --- a/source/designer/cameracontroller.cpp +++ b/source/designer/cameracontroller.cpp @@ -1,99 +1,197 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - #include #include +#include "3d/layout.h" #include "cameracontroller.h" using namespace std; using namespace Msp; +using namespace R2C2; -CameraController::CameraController(Graphics::Window &w, GL::Camera &c): - window(w), - camera(c), +CameraController::CameraController(View3D &v, Input::Keyboard &k, Input::Mouse &m): + view(v), + keyboard(k), + mouse(m), + camera(view.get_camera()), move_x(0), move_y(0), - zoom(0), - rotate(0), - pitch(0) + shift_pressed(false), + ctrl_pressed(false), + 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)); + mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &CameraController::button_press), false)); + mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &CameraController::button_release), false)); + mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &CameraController::axis_motion), false)); + keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &CameraController::key_press), false)); + keyboard.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &CameraController::key_release), false)); } -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(focus-look*dist); +} + +void CameraController::view_all() +{ + view.view_all(); +} + +void CameraController::move(float x, float y) +{ + const GL::Vector3 &pos = camera.get_position(); + const GL::Vector3 &look = camera.get_look_direction(); + GL::Vector3 fwd_dir = normalize(GL::Vector3(look.x, look.y, 0)); + GL::Vector3 right_dir = cross(fwd_dir, GL::Vector3(0, 0, 1)); + camera.set_position(pos+fwd_dir*y+right_dir*x); +} + +void CameraController::adjust_distance(float delta) +{ + const GL::Vector3 &pos = camera.get_position(); + const GL::Vector3 &look = camera.get_look_direction(); + float dist = get_distance(); + // XXX This should probably depend on the layout contents in some way + float low = 0.1; + if(dist+delta-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)); + } +} - if(rotate || pitch) +void CameraController::tick(float dt) +{ + if(move_x || move_y) { - 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); + float scale = get_view_scale()*dt; + move(move_x*scale, move_y*scale); } +} - if(move_x || move_y || zoom) +void CameraController::button_press(unsigned btn) +{ + if(btn==2 || btn==3) + { + if(ctrl_pressed) + drag_mode = DISTANCE; + else + drag_mode = ((btn==2)==shift_pressed ? ROTATE : PAN); + } + else if(btn==4) + { + adjust_distance(-get_distance()*0.1); + } + else if(btn==5) { - 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); + adjust_distance(get_distance()*0.1); } } -void CameraController::key_press(unsigned code, unsigned, wchar_t) +void CameraController::button_release(unsigned btn) { - unsigned key = Msp::Input::key_from_sys(code); + if(btn==2 || btn==3) + drag_mode = NONE; +} +void CameraController::axis_motion(unsigned axis, float, float change) +{ + if(drag_mode==PAN) + { + float dx = (axis==0 ? change : 0); + float dy = (axis==1 ? change : 0); + float scale = get_view_scale(); + move(-dx*scale, -dy*scale); + } + else if(drag_mode==ROTATE) + { + if(axis==0) + rotate(Angle::from_turns(-change/2)); + else if(axis==1) + pitch(Angle::from_turns(change/4)); + } + else if(drag_mode==DISTANCE && axis==1) + adjust_distance(-change*3*get_distance()); +} + +void CameraController::key_press(unsigned key) +{ 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(); + else if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R) + shift_pressed = true; + else if(key==Msp::Input::KEY_CTRL_L || key==Msp::Input::KEY_CTRL_R) + ctrl_pressed = true; } -void CameraController::key_release(unsigned code, unsigned) +void CameraController::key_release(unsigned key) { - 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; + else if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R) + shift_pressed = false; + else if(key==Msp::Input::KEY_CTRL_L || key==Msp::Input::KEY_CTRL_R) + ctrl_pressed = false; +} + +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.0f)*2.0f; + return get_distance()*t; }