/* 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" 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; // target yaw, angle in XZ plane, positive is looking left float yaw_target; // target pitch, angle in XZ plane, positive is looking left float pitch_target; // distance from the camera to the target float distance; // current camera mode Mode mode; // private variables // current yaw, angle in XZ plane, positive is looking left float yaw_current; // current pitch, angle in XY, positive is looking up float pitch_current; // default pitch in mode::Overview float pitch_overview; // default pitch in mode::Track const float pitch_track = 15.0f; // default rotate offset increase/decrease float rotate_offset_inc; // default translate offset increase/decrease const float translate_offset_inc = 0.1; void init() { rotate_offset_inc = 5.0f; yaw_current = 0; yaw_target = 0; pitch_current = pitch_track * 2; pitch_target = pitch_track; distance = 0.4f; mode = Track; } void shutdown() { } void set_mode(Mode newmode) { switch(newmode) { case Track: // switch camera to Track mode mode = Track; yaw_target = 0; yaw_current = yaw_target; pitch_target = pitch_track; pitch_current = pitch_target; distance = 0.4f; break; case Free: // switch camera to Free mode mode = Free; yaw_target = 0; yaw_current = yaw_target; pitch_target = pitch_track; pitch_current = pitch_target; distance = 0.4f; 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); break; case Track: // switch camera to Free mode set_mode(Free); break; default: break; } } void draw(float elapsed) { math::Matrix4f matrix; math::Axis axis; float d = 0; if (!core::localcontrol()) { if (mode != Overview) { set_mode(Overview); } target.clear(); axis.clear(); pitch_current = -75.0f; axis.change_pitch(pitch_current); distance = 20.0f; } else { if (mode == Overview) set_mode(Track); target.assign(core::localcontrol()->location()); axis.assign(core::localcontrol()->axis()); // adjust direction d = degrees180f(yaw_current - yaw_target); yaw_current = degrees360f( yaw_current - d * elapsed); axis.change_direction(yaw_current); // adjust pitch target d = degrees180f(pitch_current - pitch_target); pitch_current = degrees360f(pitch_current - d *elapsed); 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); // apply camera offset gl::translate((1.0f+distance) * axis.forward()); // calculate eye position eye = target - ((1.0f+distance) * axis.forward()); } void key_right() { if (mode == Free) { yaw_target = degrees360f( yaw_target + rotate_offset_inc); } } void key_left() { if (mode == Free) { yaw_target = degrees360f( yaw_target - rotate_offset_inc); } } void key_down() { if (mode == Free) { pitch_target = pitch_target + rotate_offset_inc; if (pitch_target > 90.0f) pitch_target = 90.0f; } } void key_up() { if (mode == Free) { pitch_target = pitch_target - rotate_offset_inc; if (pitch_target < -90.0f) pitch_target = -90.0f; } } } // namespace camera } // namespace client