/* client/camera.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include "math/mathlib.h" #include "math/matrix4f.h" #include "core/core.h" #include "client/client.h" #include "client/camera.h" #include "render/render.h" #include "sys/sys.h" using math::degrees360f; using math::degrees180f; using namespace render; namespace client { namespace camera { // gameworld coordinates of the camera target math::Vector3f target; math::Vector3f eye; math::Axis axis; // current camera mode Mode mode; // private variables // current and target yaw angle in XZ plane, positive is looking left float yaw_current; float yaw_target; // movement direction in free mode float target_direction; // current and target pitch angle in XY, positive is looking up float pitch_current; float pitch_target; // movement direction in free mode float target_pitch; float distance; // default pitch in mode::Track const float pitch_track = -15.0f; const float pitch_overview = -75.0f; void set_mode(Mode newmode); void init() { yaw_current = 0; yaw_target = 0; pitch_current = pitch_track * 2; pitch_target = pitch_track; target_pitch = 0.0f; target_direction = 0.0f; distance = 0.4f; set_mode(Track); } void shutdown() { } void set_mode(Mode newmode) { yaw_target = 0; yaw_current = yaw_target; pitch_target = pitch_track; pitch_current = pitch_target; target_direction = 0.0f; target_pitch = 0.0f; distance = 0.4f; switch(newmode) { case Track: // switch camera to Track mode mode = Track; break; case Free: // switch camera to Free mode mode = Free; pitch_target = 2.0 * pitch_track; pitch_current = pitch_target; break; case Cockpit: mode = Cockpit; break; case Overview: // switch camera to Overview mode mode = Overview; default: break; } } void next_mode() { if (!core::localcontrol()) { set_mode(Overview); return; } switch(mode) { case Free: // switch camera to Track mode set_mode(Track); con_print << "camera mode: track" << std::endl; break; case Track: // switch camera to Cockpit mode set_mode(Cockpit); con_print << "camera mode: cockpit" << std::endl; break; case Cockpit: // switch camera to Free mode set_mode(Free); con_print << "camera mode: free" << std::endl; break; default: break; } } void draw(float seconds) { math::Matrix4f matrix; float d = 0; if (!core::localcontrol()) { if (mode != Overview) { set_mode(Overview); } target.clear(); axis.clear(); pitch_current = pitch_overview; axis.change_pitch(pitch_current); distance = 20.0f; } else { if (mode == Overview) set_mode(Track); target.assign(core::localcontrol()->location()); if (mode == Track) { if (core::localcontrol()->model()) target += core::localcontrol()->model()->maxbbox().x * core::localcontrol()->axis().forward(); // make the camera swing while turning target_direction = core::localcontrol()->target_direction; pitch_target = core::localcontrol()->target_pitch; yaw_target = - 45 * target_direction; pitch_target = pitch_track -45 * target_pitch; } else if (mode == Free) { yaw_target = yaw_current - 90 * target_direction; pitch_target = pitch_current - 90 * target_pitch; } else if (mode == Cockpit) { if (core::localcontrol()->model()) target += core::localcontrol()->model()->maxbbox().x * core::localcontrol()->axis().forward(); } axis.assign(core::localcontrol()->axis()); if (mode != Cockpit) { // adjust direction d = degrees180f(yaw_current - yaw_target); yaw_current = degrees360f( yaw_current - 2* d * seconds); axis.change_direction(yaw_current); // adjust pitch target d = degrees180f(pitch_current - pitch_target); pitch_current = degrees360f(pitch_current - 2* d *seconds); axis.change_pitch(pitch_current); if (core::localcontrol()->model()) distance = 1+core::localcontrol()->model()->radius(); else distance = 1.5f; } } // map world coordinates to opengl coordinates gl::rotate(90.0f, 0, 1.0, 0); gl::rotate(-90.0f, 1.0f , 0, 0); // assign transformation matrix matrix.assign(axis); // apply the transpose of the axis transformation (the axis is orhtonormal) gl::multmatrix(matrix.transpose()); // match the camera with the current target gl::translate(-1.0f * target); if (mode != Cockpit) { // apply camera offset gl::translate((1.0f+distance) * axis.forward()); // calculate eye position eye = target - ((1.0f+distance) * axis.forward()); } else { eye.assign(target); } } void set_direction(float direction) { target_direction = direction; math::clamp(target_direction, -1.0f, 1.0f); } void set_pitch(float pitch) { target_pitch = pitch; math::clamp(target_pitch, -1.0f, 1.0f); } void reset() { set_mode(mode); } } // namespace camera } // namespace client