/* 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); if (core::localcontrol()->state()) { target.assign(core::localcontrol()->state()->location()); axis.assign(core::localcontrol()->state()->axis()); } else { target.assign(core::localcontrol()->location()); axis.assign(core::localcontrol()->axis()); } if (mode == Track) { if (core::localcontrol()->state() && core::localcontrol()->model()) { target -= (core::localcontrol()->model()->maxbbox().x + 0.15f) * core::localcontrol()->state()->axis().forward(); target += (core::localcontrol()->model()->maxbbox().z + 0.3f ) * core::localcontrol()->state()->axis().up(); } // make the camera swing while turning target_direction = core::localcontrol()->target_direction; target_pitch = core::localcontrol()->target_pitch; yaw_target = - 30 * target_direction; pitch_target = - 30 * target_pitch; //pitch_target = pitch_track - 30 * target_pitch; distance = 0.0f; } else if (mode == Free) { yaw_target = yaw_current - 90 * target_direction; pitch_target = pitch_current - 90 * target_pitch; if (core::localcontrol()->model()) { distance = core::localcontrol()->model()->radius(); } else { distance = 1.0f; } } else if (mode == Cockpit) { if (core::localcontrol()->state() && core::localcontrol()->model()) target += (core::localcontrol()->model()->maxbbox().x+0.05) * core::localcontrol()->state()->axis().forward(); distance = 0.0f; } if (mode != Cockpit) { // adjust direction d = degrees180f(yaw_current - yaw_target); yaw_current = degrees360f( yaw_current - d * seconds); axis.change_direction(yaw_current); // adjust pitch target d = degrees180f(pitch_current - pitch_target); pitch_current = degrees360f(pitch_current - d *seconds); axis.change_pitch(pitch_current); } } // 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); // apply camera offset gl::translate((1.0 + distance) * axis.forward()); // calculate eye position eye = target - ((1.0f+distance) * axis.forward()); 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