Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/camera.cc')
-rw-r--r--src/render/camera.cc512
1 files changed, 211 insertions, 301 deletions
diff --git a/src/render/camera.cc b/src/render/camera.cc
index d6cf562..70684d7 100644
--- a/src/render/camera.cc
+++ b/src/render/camera.cc
@@ -6,17 +6,14 @@
#include <cmath>
-#include "core/application.h"
-#include "core/gameinterface.h"
-#include "math/mathlib.h"
-#include "math/matrix4f.h"
#include "render/camera.h"
#include "render/gl.h"
#include "render/state.h"
+#include "core/entity.h"
+#include "core/range.h"
+#include "math/functions.h"
#include "sys/sys.h"
-using math::degrees360f;
-using math::degrees180f;
namespace render
{
@@ -24,134 +21,72 @@ namespace render
const float MIN_DELTA = 10e-10;
const float COS_PI_4 = sqrt(2.0f) * 0.5f;
-const float pitch_free = -30.0f;
-const float pitch_track = -5.0f;
-const float pitch_overview = -5.0f;
-math::Vector3f Camera::camera_eye;
-math::Vector3f Camera::camera_target;
-math::Axis Camera::camera_axis;
-math::Axis Camera::camera_scene_axis;
-Camera::Mode Camera::camera_mode;
-Camera::Mode Camera::camera_previous_mode;
-
-// current and target yaw angle in XZ plane, positive is looking left
-float Camera::direction_current;
-float Camera::direction_target;
-float Camera::target_direction;
-
-// current and target pitch angle in XY, positive is looking up
-float Camera::pitch_current;
-float Camera::pitch_target;
-float Camera::target_pitch;
-
-float Camera::distance;
-float Camera::camera_zoom;
-
-void Camera::init()
+Camera::Camera(const Mode mode)
{
- direction_current = 0;
- direction_target = 0;
-
- pitch_current = pitch_track * 2;
- pitch_target = pitch_track;
-
- target_pitch = 0.0f;
- target_direction = 0.0f;
-
- distance = 0.4f;
- camera_zoom = 2.0f;
-
- camera_mode = Overview;
- camera_previous_mode = Track;
- set_mode(Track);
-
- camera_axis.clear();
- camera_scene_axis.clear();
- camera_eye.clear();
- camera_target.clear();
-
+ _mode = mode;
+ _distance = 1.0f;
+ _multiplier = 1.0f;
+ _target_entity = 0;
+
+ _freelook_direction = 0.0f;
+ _freelook_pitch = 0.0f;
+
+ _movement_direction = 0.0f;
+ _movement_pitch = 0.0f;
}
-void Camera::shutdown()
+Camera::~Camera()
{
}
-void Camera::set_mode(Mode newmode)
+void Camera::set_mode(const Mode mode)
{
+ _mode = mode;
+ reset();
+}
- direction_target = 0;
- direction_current = direction_target;
- pitch_target = pitch_track;
- pitch_current = pitch_target;
-
- target_direction = 0.0f;
- target_pitch = 0.0f;
- distance = 0.4f;
-
- camera_scene_axis.clear();
-
- if (camera_mode != Overview)
- camera_previous_mode = camera_mode;
-
- switch (newmode) {
- case Track:
- // switch camera to Track mode
- camera_mode = Track;
- if (core::localcontrol()) {
- camera_scene_axis.assign(core::localcontrol()->axis());
- }
- break;
-
- case Free:
- // switch camera to Free mode
- camera_mode = Free;
- pitch_target = pitch_free;
- pitch_current = pitch_target;
- break;
-
- case Cockpit:
- camera_mode = Cockpit;
- break;
-
- case Overview:
- // switch camera to Overview mode
- camera_mode = Overview;
+void Camera::set_multiplier(const float multiplier)
+{
+ _multiplier = multiplier;
+}
- default:
- break;
- }
+void Camera::set_freelook_direction(const float angle)
+{
+ _freelook_direction = angle;
+}
+void Camera::set_freelook_pitch(const float angle)
+{
+ _freelook_pitch = angle;
}
-void Camera::view_next()
+void Camera::set_movement_direction(const float speed)
+{
+ _movement_direction = speed;
+ math::clamp(_movement_direction, -1.0f, 1.0f);
+}
+
+void Camera::set_movement_pitch(const float speed)
{
+ _movement_pitch = speed;
+ math::clamp(_movement_pitch, -1.0f, 1.0f);
+}
- if (!core::localcontrol()) {
- set_mode(Overview);
- return;
- }
+void Camera::cycle_mode_next()
+{
- switch (camera_mode) {
+ switch (mode()) {
case Free:
- // switch camera to Track mode
set_mode(Track);
- //con_print << "view: track" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: track"));
break;
case Track:
- // switch camera to Cockpit mode
set_mode(Cockpit);
- //con_print << "view: cockpit" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: cockpit"));
break;
case Cockpit:
- // switch camera to Free mode
set_mode(Free);
- //con_print << "view: free" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: free"));
break;
default:
@@ -159,34 +94,19 @@ void Camera::view_next()
}
}
-void Camera::view_previous()
+void Camera::cycle_mode_previous()
{
-
- if (!core::localcontrol()) {
- set_mode(Overview);
- return;
- }
-
- switch (camera_mode) {
+ switch (mode()) {
case Cockpit:
- // switch camera to Track mode
set_mode(Track);
- //con_print << "view: track" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: track"));
break;
case Free:
- // switch camera to Cockpit mode
set_mode(Cockpit);
- //con_print << "view: cockpit" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: cockpit"));
break;
case Track:
- // switch camera to Free mode
set_mode(Free);
- //con_print << "view: free" << std::endl;
- //core::application()->notify_message(core::Message::Info, std::string("view: free"));
break;
default:
@@ -194,180 +114,182 @@ void Camera::view_previous()
}
}
-void Camera::set_zoom(float zoom)
+void Camera::reset()
{
- camera_zoom += zoom;
- math::clamp(camera_zoom, 1.0f, 10.0f);
-}
+ if (target())
+ {
+ _target_location.assign(target()->location());
+ _target_axis.assign(target()->axis());
+ _distance = 0.0f;
+ }
+ else
+ {
+ _location.clear();
+ _target_axis.clear();
+ _distance = 0.0f;
+ }
+ _axis.assign(_target_axis);
+ if (mode() == Free)
+ {
+ _target_axis.clear();
+ }
+
+ _freelook_direction = 0.0f;
+ _freelook_pitch = 0.0f;
-void Camera::frame(float seconds)
+ _movement_direction = 0.0f;
+ _movement_pitch = 0.0f;
+}
+void Camera::set_target(const core::Entity *entity)
{
- math::Axis target_axis;
- float d = 0;
-
- if (core::localplayer()->view()) {
- if (camera_mode != Overview) {
- set_mode(Overview);
- }
- } else if (core::localcontrol()) {
- if (camera_mode == Overview) {
- set_mode(camera_previous_mode);
- }
- } else {
- if (camera_mode != Overview) {
- set_mode(Overview);
- }
- }
+ _target_entity = entity;
+}
- if (mode() == Overview) {
- camera_eye.clear();
-
- if (core::localplayer()->view()) {
- // player view entity
-
- camera_scene_axis.assign(core::localplayer()->view()->axis());
- if (core::localplayer()->view() == core::localcontrol()) {
- camera_scene_axis.change_pitch(pitch_free);
- camera_target.assign(core::localplayer()->view()->location());
- distance = math::max(core::localplayer()->view()->radius(), 1.0f) * 2.0f;
- } else {
- distance = math::max(core::localplayer()->view()->radius(), 1.0f) * 3.0f;
- camera_scene_axis.change_direction(180.0f);
- camera_target.assign(core::localplayer()->view()->location() - core::localplayer()->view()->axis().left()*(math::max(core::localplayer()->view()->radius(), 1.0f)*0.5f));
+void Camera::frame(const float elapsed)
+{
+ const float ROTATESPEED = 25.0f * elapsed;
+ switch(mode())
+ {
+ case Track:
+ {
+ math::Axis desired_axis;
+
+ // 3rd person view
+ if (target())
+ {
+ _target_location.assign(target()->location());
+
+ if (target()->model())
+ {
+ const float modelscale = target()->radius() / target()->model()->radius();
+ _target_location += target()->axis().up() * target()->model()->box().max().z() * modelscale;
+ }
+ else
+ {
+ _target_location += target()->axis().up() * target()->radius();
+ }
+ desired_axis.assign(target()->axis());
+ _distance = target()->radius() * _multiplier * 2.0f;
}
-
- /*
- } else if (core::localplayer()->zone()->default_view()) {
- // default zone view entity
- camera_target.assign(core::localplayer()->zone()->default_view()->location());
- camera_scene_axis.assign(core::localplayer()->zone()->default_view()->axis());
- camera_scene_axis.change_direction(180.0f);
- distance = math::max(core::localplayer()->zone()->default_view()->radius(), 1.0f) * 2.0f;
- */
- } else {
- // default location (0,0,0)
- camera_target.clear();
- camera_scene_axis.clear();
- pitch_current = pitch_overview;
- camera_scene_axis.change_pitch(pitch_current);
- distance = 8.0f;
- }
- } else {
-
- camera_target.assign(core::localcontrol()->location());
- target_axis.assign(core::localcontrol()->axis());
- distance = core::localcontrol()->radius();
-
- if (mode() == Track) {
-
- float cosangle; // cosine of an angle
- float angle; // angle in radians
- math::Vector3f n; // normal of a plane
+ else
+ {
+ _target_location.assign(0.0f, 0.0f, 1.0f);
+ _distance = _multiplier * 2.0f;
+ }
+ // FIXME Bad solution below
- // freelook target
- target_axis.change_direction(90 * target_direction);
- target_axis.change_pitch(90 * target_pitch);
-
- // rotate scene axis towards target axis
- n.assign(math::crossproduct(camera_scene_axis.forward(), target_axis.forward()));
- if (!(n.length() < MIN_DELTA)) {
+ math::Vector3f n (math::crossproduct(_target_axis.forward(), desired_axis.forward()));
+ float l = n.length();
+ float d = math::dotproduct(_target_axis.forward(), desired_axis.forward());
+ float a = (d > 0.0f ? 1.0f - d : 1.0f);
+ if ((a > MIN_DELTA) && (l > MIN_DELTA))
+ {
n.normalize();
- cosangle = math::dotproduct(camera_scene_axis.forward(), target_axis.forward());
- angle = acos(cosangle) * seconds; // * 180.0f / M_PI;
- if (angle > MIN_DELTA)
- camera_scene_axis.rotate(n, -angle);
+ _target_axis.rotate(n, -ROTATESPEED * a);
+
}
-
- n.assign(math::crossproduct(camera_scene_axis.left(), target_axis.left()));
- if (!(n.length() < MIN_DELTA)) {
+
+ n.assign (math::crossproduct(_target_axis.up(), desired_axis.up()));
+ l = n.length();
+ d = math::dotproduct(_target_axis.up(), desired_axis.up());
+ a = (d > 0.0f ? 1.0f - d : 1.0f);
+ if ((a > MIN_DELTA) && (l > MIN_DELTA))
+ {
n.normalize();
- cosangle = math::dotproduct(camera_scene_axis.left(), target_axis.left());
- angle = acos(cosangle) * seconds; // * 180.0f / M_PI;
- if (angle > MIN_DELTA)
- camera_scene_axis.rotate(n, -angle);
+ _target_axis.rotate(n, -ROTATESPEED * a);
+
}
- n.assign(math::crossproduct(camera_scene_axis.up(), target_axis.up()));
- if (!(n.length() < MIN_DELTA)) {
- n.normalize();
- cosangle = math::dotproduct(camera_scene_axis.up(), target_axis.up());
- angle = acos(cosangle) * seconds; // * 180.0f / M_PI;
- if (angle > MIN_DELTA)
- camera_scene_axis.rotate(n, -angle);
+ _axis.assign(_target_axis);
+ _axis.change_direction(_freelook_direction);
+ _axis.change_pitch(_freelook_pitch);
+ break;
+ }
+
+ case Cockpit:
+ {
+ // 1st person view
+ if (target())
+ {
+ _target_location.assign(target()->location());
+ _target_axis.assign(target()->axis());
+ _distance = 0.0f;
}
-
- if (core::localcontrol()->model() && core::localcontrol()->model()->radius()) {
- const float modelscale = core::localcontrol()->radius() / core::localcontrol()->model()->radius();
+ else
+ {
+ _target_location.clear();
+ _target_axis.clear();
+ _distance = 0.0f;
+ }
+
+ _axis.assign(_target_axis);
+ _axis.change_direction(_freelook_direction);
+ _axis.change_pitch(_freelook_pitch);
+ break;
+ }
+ case Free:
+ {
+ // look at self
+ if (target())
+ {
+ _target_location.assign(target()->location());
+ _axis.assign(target()->axis());
- camera_target -= camera_scene_axis.forward() * math::max(FRUSTUMFRONT / WORLDSCALE, core::localcontrol()->model()->box().max().x() * modelscale);
- camera_target += camera_scene_axis.up() * math::max(FRUSTUMFRONT / WORLDSCALE, core::localcontrol()->model()->box().max().z() * modelscale);
- } else {
- camera_target -= camera_scene_axis.forward() * math::max(FRUSTUMFRONT / WORLDSCALE, FRUSTUMFRONT / WORLDSCALE + core::localcontrol()->radius());
- camera_target += camera_scene_axis.up() * math::max(FRUSTUMFRONT / WORLDSCALE, FRUSTUMFRONT / WORLDSCALE + core::localcontrol()->radius());
+ _distance = target()->radius() * _multiplier * 2.0f;
+ }
+ else
+ {
+ _target_location.clear();
+ _axis.clear();
+
+ _distance = _multiplier * 2.0f;
}
- distance = math::max(FRUSTUMFRONT / WORLDSCALE, FRUSTUMFRONT / WORLDSCALE + camera_zoom * core::localcontrol()->radius()) + 0.001f;
-
- } else if (mode() == Free) {
-
- camera_scene_axis.assign(target_axis);
-
- direction_target = direction_current - 90 * target_direction;
- pitch_target = pitch_current - 90 * target_pitch;
-
- // adjust direction
- d = degrees180f(direction_current - direction_target);
- direction_current = degrees360f(direction_current - d * seconds);
- camera_scene_axis.change_direction(direction_current);
-
- // adjust pitch
- d = degrees180f(pitch_current - pitch_target);
- pitch_current = degrees360f(pitch_current - d * seconds);
- camera_scene_axis.change_pitch(pitch_current);
-
- distance = math::max(FRUSTUMFRONT / WORLDSCALE, FRUSTUMFRONT / WORLDSCALE + camera_zoom * core::localcontrol()->radius()) + 0.001f;
-
- } else if (mode() == Cockpit) {
+ _target_axis.rotate(math::Vector3f(0.0f, 0.0f, 1.0f), -M_PI * _movement_direction * elapsed);
+ _target_axis.change_pitch(180.0f * _movement_pitch * elapsed);
- camera_scene_axis.assign(target_axis);
-
- direction_target = + 90 * target_direction;
- pitch_target = + 90 * target_pitch;
-
- // adjust direction
- d = degrees180f(direction_current - direction_target);
- direction_current = degrees360f(direction_current - d * seconds);
- camera_scene_axis.change_direction(direction_current);
-
- // adjust pitch
- d = degrees180f(pitch_current - pitch_target);
- pitch_current = degrees360f(pitch_current - d * seconds);
- camera_scene_axis.change_pitch(pitch_current);
-
- if (core::localcontrol()->model()) {
- const float modelscale = core::localcontrol()->radius() / core::localcontrol()->model()->radius();
- camera_target += (core::localcontrol()->model()->box().max().x() * modelscale) *
- core::localcontrol()->axis().forward();
- } else {
- camera_target += (core::localcontrol()->radius()) *
- core::localcontrol()->axis().forward();
+ _axis.assign(_axis * _target_axis);
+ _axis.change_direction(_freelook_direction);
+ _axis.change_pitch(_freelook_pitch);
+ break;
+ }
+ case Overview:
+ {
+ if (target())
+ {
+ _target_location.assign(target()->location());
+ _target_axis.assign(target()->axis());
+ _distance = 2.0f * target()->radius() * _multiplier;
+
+ _target_axis.change_direction(180.0f);
+
+ // default pitch angle
+ _target_axis.change_pitch(-5.0f);
+ }
+ else
+ {
+ _target_location.clear();
+ _target_axis.clear();
+
+ _distance = 2.0f * _multiplier;
}
- distance = (FRUSTUMFRONT / WORLDSCALE) - 0.001f;
+
+ _axis.assign(_target_axis);
+ break;
}
}
-
- // calculate eye position
- camera_eye = camera_target - (distance * camera_scene_axis.forward());
- camera_axis.assign(camera_scene_axis);
+
+ _distance += FRUSTUMFRONT / WORLDSCALE;
+ _location.assign(_target_location - _axis.forward() * _distance);
}
-void Camera::frustum()
+void Camera::draw()
{
// Change to the projection matrix and set our viewing volume large enough for the skysphere
gl::matrixmode(GL_PROJECTION);
gl::loadidentity();
- gl::frustum(-FRUSTUMSIZE, FRUSTUMSIZE, -FRUSTUMSIZE / State::aspect(), FRUSTUMSIZE / State::aspect(), FRUSTUMFRONT, core::range::maxdistance * WORLDSCALE);
+ gl::frustum(-FRUSTUMSIZE, FRUSTUMSIZE, -FRUSTUMSIZE / State::aspect(), FRUSTUMSIZE / State::aspect(), FRUSTUMFRONT, FARPLANE);
gl::matrixmode(GL_MODELVIEW);
gl::loadidentity();
@@ -376,25 +298,25 @@ void Camera::frustum()
gl::rotate(-90.0f, 1.0f , 0.0f, 0.0f);
// apply the transpose of the axis transformation (the axis is orhtonormal)
- math::Matrix4f matrix;
- matrix.assign(camera_scene_axis);
+ math::Matrix4f matrix(_axis);
gl::multmatrix(matrix.transpose());
- gl::scale(4.0f, 4.0f, 4.0f);
-
- gl::translate(-1.0f * camera_eye);
+ // apply world scale
+ gl::scale(WORLDSCALE, WORLDSCALE, WORLDSCALE);
+ // apply camera eye translation
+ gl::translate(-1.0f * _location);
}
-void Camera::frustum_default(float distance, float cx, float cy)
+void Camera::draw(const float center_x, const float center_y)
{
// Change to the projection matrix and set our viewing volume large enough for the skysphere
gl::matrixmode(GL_PROJECTION);
gl::loadidentity();
- // move eye to (cx, cy)
+ // move projection center to (cx, cy)
// note: the factor 2.0f probably has to be 1.0f/frustum_size
- gl::translate(2.0f*(-State::width() * 0.5f + cx) / State::width() , 2.0f*(State::height() * 0.5f - cy) / State::height(), 0.0f);
+ gl::translate(2.0f*(-State::width() * 0.5f + center_x) / State::width() , 2.0f * (State::height() * 0.5f - center_y) / State::height(), 0.0f);
gl::frustum(-FRUSTUMSIZE, FRUSTUMSIZE, -FRUSTUMSIZE / State::aspect(), FRUSTUMSIZE / State::aspect(), FRUSTUMFRONT, 1023.0f);
@@ -404,10 +326,13 @@ void Camera::frustum_default(float distance, float cx, float cy)
// map world coordinates to opengl coordinates
gl::rotate(90.0f, 0.0f, 1.0f, 0.0f);
gl::rotate(-90.0f, 1.0f , 0.0f, 0.0f);
+
+ // apply the transpose of the axis transformation (the axis is orhtonormal)
+ math::Matrix4f matrix(_axis);
+ gl::multmatrix(matrix.transpose());
- gl::translate(distance + 1.0f, 0.0f, 0.0f);
- camera_eye.assign(-distance - 1.0f, 0.0f, 0.0f);
- camera_axis.clear();
+ // apply camera eye translation
+ gl::translate(-1.0f * _location);
}
void Camera::ortho()
@@ -420,22 +345,7 @@ void Camera::ortho()
gl::matrixmode(GL_MODELVIEW);
gl::loadidentity();
}
+
-void Camera::set_direction(float direction)
-{
- target_direction = direction;
- math::clamp(target_direction, -1.0f, 1.0f);
-}
+} // namespace render
-void Camera::set_pitch(float pitch)
-{
- target_pitch = pitch;
- math::clamp(target_pitch, -1.0f, 1.0f);
-}
-
-void Camera::reset()
-{
- set_mode(camera_mode);
-}
-
-}