--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include <msp/input/keys.h>
+#include "cameracontroller.h"
+
+using namespace std;
+using namespace Msp;
+
+CameraController::CameraController(Graphics::Window &w, GL::Camera &c):
+ window(w),
+ camera(c),
+ move_x(0),
+ move_y(0),
+ zoom(0),
+ rotate(0),
+ pitch(0)
+{
+ window.signal_key_press.connect(sigc::mem_fun(this, &CameraController::key_press));
+ window.signal_key_release.connect(sigc::mem_fun(this, &CameraController::key_release));
+}
+
+void CameraController::tick(float dt)
+{
+ if(!move_x && !move_y && !zoom && !rotate && !pitch)
+ return;
+
+ GL::Vector3 pos = camera.get_position();
+ 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);
+
+ if(rotate || pitch)
+ {
+ 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);
+ }
+
+ if(move_x || move_y || zoom)
+ {
+ 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);
+ }
+}
+
+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;
+ else if(key==Msp::Input::KEY_LEFT)
+ rotate = 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;
+}
+
+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;
+ 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;
+}
#include <cmath>
#include <GL/gl.h>
#include <msp/gl/blend.h>
+#include <msp/gl/framebuffer.h>
#include <msp/gl/matrix.h>
#include <msp/gl/misc.h>
#include <msp/gl/projection.h>
manipulator(*this, selection),
measure(*this),
input(0),
- cam_yaw(M_PI/2),
- cam_pitch(-M_PI/4),
- cam_pos(0, -0.5, 0.5),
- shift(false),
- move_x(0),
- move_y(0),
- zoom(0),
- rotate(0),
- pitch(0)
+ camera_ctl(window, camera),
+ shift(false)
{
window.set_title("Railway Designer");
window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Designer::exit), 0));
GL::enable(GL_CULL_FACE);
pipeline = new GL::Pipeline(window.get_width(), window.get_height(), false);
+ pipeline->set_camera(&camera);
pipeline->add_renderable(layout_3d->get_scene());
if(base_object)
pipeline->add_renderable(*base_object);
GL::PipelinePass *pass = &pipeline->add_pass(GL::Tag());
pass->lighting = &lighting;
+ camera.set_up_direction(GL::Vector3(0, 0, 1));
+ view_all();
+
// Setup UI
DataFile::load(ui_res, "marklin.res");
root = new GLtk::Root(ui_res, window);
}
}
-void Designer::map_pointer_coords(int x, int y, float &gx, float &gy)
+Point Designer::map_pointer_coords(int x, int y)
{
- float cos_pitch = cos(cam_pitch);
- float sin_pitch = sin(cam_pitch);
- float cos_yaw = cos(cam_yaw);
- float sin_yaw = sin(cam_yaw);
-
- float rx = sin_yaw*0.55228;
- float ry = -cos_yaw*0.55228;
-
- float ux = cos_yaw*-sin_pitch*0.41421;
- float uy = sin_yaw*-sin_pitch*0.41421;
- float uz = cos_pitch*0.41421;
-
- float xf = static_cast<float>(x)*2/window.get_width()-1;
- float yf = static_cast<float>(y)*2/window.get_height()-1;
+ float xf = x*2.0/window.get_width()-1.0;
+ float yf = y*2.0/window.get_height()-1.0;
+ GL::Vector4 vec = camera.unproject(GL::Vector4(xf, yf, 0, 0));
+ const GL::Vector3 &pos = camera.get_position();
- float vx = cos_yaw*cos_pitch + xf*rx + yf*ux;
- float vy = sin_yaw*cos_pitch + xf*ry + yf*uy;
- float vz = sin_pitch + yf*uz;
-
- gx = cam_pos.x-vx*cam_pos.z/vz;
- gy = cam_pos.y-vy*cam_pos.z/vz;
+ return Point(pos.x-vec.x*pos.z/vec.z, pos.y-vec.y*pos.z/vec.z);
}
void Designer::tick()
last_tick = t;
window.get_display().tick();
-
- if(move_y)
- {
- cam_pos.x += cos(cam_yaw)*dt*move_y;
- cam_pos.y += sin(cam_yaw)*dt*move_y;
- }
- if(move_x)
- {
- cam_pos.x += sin(cam_yaw)*dt*move_x;
- cam_pos.y += -cos(cam_yaw)*dt*move_x;
- }
- if(zoom)
- {
- cam_pos.x += cos(cam_yaw)*cos(cam_pitch)*dt*zoom;
- cam_pos.y += sin(cam_yaw)*cos(cam_pitch)*dt*zoom;
- cam_pos.z += sin(cam_pitch)*dt*zoom;
- }
- if(rotate)
- {
- float vx = cos(cam_yaw)*cos(cam_pitch);
- float vy = sin(cam_yaw)*cos(cam_pitch);
- float vz = sin(cam_pitch);
-
- float gx = cam_pos.x-vx*cam_pos.z/vz;
- float gy = cam_pos.y-vy*cam_pos.z/vz;
- float d = sqrt(vx*vx+vy*vy)*cam_pos.z/vz;
-
- cam_yaw += M_PI*dt*rotate;
- if(cam_yaw>M_PI*2)
- cam_yaw -= M_PI*2;
- else if(cam_yaw<0)
- cam_yaw += M_PI*2;
-
- cam_pos.x = gx+cos(cam_yaw)*d;
- cam_pos.y = gy+sin(cam_yaw)*d;
- }
- if(pitch)
- {
- cam_pitch += M_PI/2*dt*pitch;
- if(cam_pitch>M_PI/12)
- cam_pitch = M_PI/12;
- else if(cam_pitch<-M_PI/2)
- cam_pitch = -M_PI/2;
- }
+ camera_ctl.tick(dt);
if(tooltip_timeout && t>tooltip_timeout)
{
}
else if(key==Msp::Input::KEY_A)
add_selection_to_route();
- else if(key==Msp::Input::KEY_RIGHT)
- rotate = -1;
- else if(key==Msp::Input::KEY_LEFT)
- rotate = 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;
}
void Designer::key_release(unsigned code, unsigned)
if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R)
shift = false;
- else if(key==Msp::Input::KEY_RIGHT || key==Msp::Input::KEY_LEFT)
- rotate = 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;
}
void Designer::button_press(int x, int y, unsigned btn, unsigned)
{
y = window.get_height()-y-1;
- float gx, gy;
- map_pointer_coords(x, y, gx, gy);
+ Point ground = map_pointer_coords(x, y);
if(mode==CATALOGUE)
{
if(ctrack)
{
Track *track = ctrack->get_track().copy();
- track->set_position(Point(gx, gy, 0));
+ track->set_position(ground);
layout->add_track(*track);
selection.clear();
}
}
else if(mode==MANIPULATE)
- manipulator.button_press(x, y, gx, gy, btn);
+ manipulator.button_press(x, y, ground.x, ground.y, btn);
else if(mode==MEASURE)
- measure.button_press(x, y, gx, gy, btn);
+ measure.button_press(x, y, ground.x, ground.y, btn);
}
void Designer::pointer_motion(int x, int y)
if(mode!=INPUT)
{
- float gx, gy;
- map_pointer_coords(x, y, gx, gy);
- manipulator.pointer_motion(x, y, gx, gy);
- measure.pointer_motion(x, y, gx, gy);
+ Point ground = map_pointer_coords(x, y);
+ manipulator.pointer_motion(x, y, ground.x, ground.y);
+ measure.pointer_motion(x, y, ground.x, ground.y);
}
}
-void Designer::project_3d()
-{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustum(-0.055228, 0.055228, -0.041421, 0.041421, 0.1, 10);
- glMatrixMode(GL_MODELVIEW);
-}
-
void Designer::apply_camera()
{
- glLoadIdentity();
if(mode==CATALOGUE)
- glTranslatef(0, 0, -1);
- else
{
- glRotatef(-cam_pitch*180/M_PI-90, 1, 0, 0);
- glRotatef(90-cam_yaw*180/M_PI, 0, 0, 1);
- glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
+ GL::matrix_mode(GL::PROJECTION);
+ GL::load_identity();
+ GL::frustum_centered(0.11046, 0.082843, 0.1, 10);
+ GL::matrix_mode(GL::MODELVIEW);
+ GL::load_identity();
+ GL::translate(0, 0, -1);
}
+ else
+ camera.apply();
}
void Designer::render()
{
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ GL::clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
GL::enable(GL::DEPTH_TEST);
GL::Texture::unbind();
- project_3d();
- apply_camera();
if(mode==CATALOGUE)
+ {
+ apply_camera();
cat_layout_3d->get_scene().render();
+ }
else
{
pipeline->render_all();
float yy = (float(y)/window.get_height()-0.5)*0.82843;
float size = 4.0/window.get_height()*0.82843;
- project_3d();
apply_camera();
return l->pick_track(xx, yy, size);
input = 0;
mode = SELECT;
}
+
+void Designer::view_all()
+{
+ Point minp;
+ Point maxp;
+
+ const list<Track3D *> &tracks = layout_3d->get_tracks();
+ for(list<Track3D *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ {
+ Point tmin;
+ Point tmax;
+ (*i)->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));
+}