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')
-rw-r--r--src/render/Makefile.am6
-rw-r--r--src/render/camera.cc349
-rw-r--r--src/render/camera.h87
-rw-r--r--src/render/draw.cc30
-rw-r--r--src/render/draw.h2
-rw-r--r--src/render/render.cc12
-rw-r--r--src/render/render.h1
7 files changed, 461 insertions, 26 deletions
diff --git a/src/render/Makefile.am b/src/render/Makefile.am
index 5747681..389c141 100644
--- a/src/render/Makefile.am
+++ b/src/render/Makefile.am
@@ -3,6 +3,6 @@ METASOURCES = AUTO
noinst_LTLIBRARIES = librender.la
librender_la_LDFLAGS = -avoid-version -no-undefined @GL_LIBS@
librender_la_LIBADD = $(top_builddir)/src/math/libmath.la
-librender_la_SOURCES = draw.cc gl.cc image.cc render.cc text.cc textures.cc \
- tga.cc
-noinst_HEADERS = draw.h gl.h image.h render.h text.h textures.h tga.h
+librender_la_SOURCES = camera.cc draw.cc gl.cc image.cc render.cc text.cc \
+ textures.cc tga.cc
+noinst_HEADERS = camera.h draw.h gl.h image.h render.h text.h textures.h tga.h
diff --git a/src/render/camera.cc b/src/render/camera.cc
new file mode 100644
index 0000000..8da6bc9
--- /dev/null
+++ b/src/render/camera.cc
@@ -0,0 +1,349 @@
+/*
+ render/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 "core/core.h"
+#include "math/mathlib.h"
+#include "math/matrix4f.h"
+#include "render/camera.h"
+#include "render/gl.h"
+#include "sys/sys.h"
+
+using math::degrees360f;
+using math::degrees180f;
+
+namespace render
+{
+
+const float MIN_DELTA = 10e-10;
+
+const float pitch_track = -15.0f;
+const float pitch_overview = -75.0f;
+
+float Camera::camera_aspect = 1.0f;
+math::Vector3f Camera::camera_eye;
+math::Vector3f Camera::camera_target;
+math::Axis Camera::camera_axis;
+Camera::Mode Camera::camera_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;
+
+void Camera::init()
+{
+ camera_aspect = 1.0f;
+
+ 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;
+
+ set_mode(Track);
+
+ camera_axis.clear();
+ camera_eye.clear();
+ camera_target.clear();
+
+}
+
+void Camera::shutdown()
+{
+}
+
+void Camera::set_aspect(float aspect)
+{
+ camera_aspect = aspect;
+}
+
+void Camera::set_mode(Mode newmode) {
+
+ 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_axis.clear();
+
+ switch(newmode) {
+ case Track:
+ // switch camera to Track mode
+ camera_mode = Track;
+ if (core::localcontrol()) {
+ if (core::localcontrol()->state())
+ camera_axis.assign(core::localcontrol()->state()->axis());
+ else
+ camera_axis.assign(core::localcontrol()->axis());
+ }
+ break;
+
+ case Free:
+ // switch camera to Free mode
+ camera_mode = Free;
+ pitch_target = 2.0 * pitch_track;
+ pitch_current = pitch_target;
+ break;
+
+ case Cockpit:
+ camera_mode = Cockpit;
+ break;
+
+ case Overview:
+ // switch camera to Overview mode
+ camera_mode = Overview;
+
+ default:
+ break;
+ }
+
+}
+
+void Camera::next_mode()
+{
+
+ if (!core::localcontrol()) {
+ set_mode(Overview);
+ return;
+ }
+
+ switch(camera_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 Camera::draw(float seconds)
+{
+ math::Matrix4f matrix;
+ math::Axis target_axis;
+ float d = 0;
+
+ if (!core::localcontrol()) {
+
+ if (camera_mode != Overview) {
+ set_mode(Overview);
+ }
+
+ camera_eye.clear();
+ camera_target.clear();
+ camera_axis.clear();
+ pitch_current = pitch_overview;
+ camera_axis.change_pitch(pitch_current);
+
+ distance = 20.0f;
+
+ } else {
+ if (mode() == Overview)
+ set_mode(Track);
+
+ if (core::localcontrol()->state()) {
+ camera_target.assign(core::localcontrol()->state()->location());
+ target_axis.assign(core::localcontrol()->state()->axis());
+ } else {
+ camera_target.assign(core::localcontrol()->location());
+ target_axis.assign(core::localcontrol()->axis());
+ }
+
+ if (core::localcontrol()->model()) {
+ distance = core::localcontrol()->model()->radius();
+ } else {
+ distance = 1.0f;
+ }
+
+ if (mode() == Track) {
+ float cosangle;
+ float angle;
+ float side;
+ float u;
+ const float cam_speed = seconds;
+
+ math::Vector3f n;
+ math::Vector3f p;
+
+ // camera axis: pitch
+
+ // project target_axis.up() into the plane with axis->left() normal
+ n = camera_axis.left();
+ p = target_axis.up();
+ u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]);
+ p = target_axis.up() + u * n;
+
+ side = camera_axis.forward().x * p.x +
+ camera_axis.forward().y * p.y +
+ camera_axis.forward().z * p.z;
+
+ if ((fabs(side) - MIN_DELTA > 0)) {
+
+ cosangle = math::dotproduct(p, camera_axis.up());
+ if (fabs(cosangle) + MIN_DELTA < 1 ) {
+ angle = acos(cosangle) * 180.0f / M_PI;
+ angle = math::sgnf(side) * angle * cam_speed;
+ camera_axis.change_pitch(-angle);
+ }
+ }
+
+ // camera axis: direction
+
+ // project target_axis.forward() into the plane with axis.up() normal
+ n = camera_axis.up();
+ p = target_axis.forward();
+ u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]);
+ p = target_axis.forward() + u * n;
+
+ side = camera_axis.left().x * p.x +
+ camera_axis.left().y * p.y +
+ camera_axis.left().z * p.z;
+
+ if ((fabs(side) - MIN_DELTA > 0)) {
+
+ cosangle = math::dotproduct(p, camera_axis.forward());
+ if (fabs(cosangle) + MIN_DELTA < 1 ) {
+ angle = acos(cosangle) * 180.0f / M_PI;
+ angle = math::sgnf(side) * angle * cam_speed;
+ camera_axis.change_direction(angle);
+ }
+ }
+
+ // camera axis: roll
+
+ // project target_axis.up() into the plane with axis.forward() normal
+ n = camera_axis.forward();
+ p = target_axis.up();
+ u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]);
+ p = target_axis.up() + u * n;
+
+ side = camera_axis.left().x * p.x +
+ camera_axis.left().y * p.y +
+ camera_axis.left().z * p.z;
+
+ if ((fabs(side) - MIN_DELTA > 0)) {
+
+ cosangle = math::dotproduct(p, camera_axis.up());
+ if (fabs(cosangle) + MIN_DELTA < 1 ) {
+ angle = acos(cosangle) * 180.0f / M_PI;
+ angle = math::sgnf(side) * angle * cam_speed;
+ camera_axis.change_roll(angle);
+ }
+ }
+
+ if (core::localcontrol()->model()) {
+ camera_target -= (core::localcontrol()->model()->maxbbox().x + 0.1f) * camera_axis.forward();
+ camera_target += (core::localcontrol()->model()->maxbbox().z + 0.1f ) * camera_axis.up();
+ }
+
+ } else if (mode() == Free) {
+ camera_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_axis.change_direction(direction_current);
+
+ // adjust pitch
+ d = degrees180f(pitch_current - pitch_target);
+ pitch_current = degrees360f(pitch_current - d * seconds);
+ camera_axis.change_pitch(pitch_current);
+
+ } else if (mode() == Cockpit) {
+ camera_axis.assign(target_axis);
+
+ if (core::localcontrol()->state() && core::localcontrol()->model())
+ camera_target += (core::localcontrol()->model()->maxbbox().x+0.05) *
+ core::localcontrol()->state()->axis().forward();
+
+ distance = 0.0f;
+ }
+ }
+
+ // Change to the projection matrix and set our viewing volume.
+ gl::matrixmode(GL_PROJECTION);
+ gl::loadidentity();
+
+ const float frustum_size = 0.5f;
+ const float frustum_front = 1.0f;
+ distance += frustum_front;
+ gl::frustum(-frustum_size*aspect(), frustum_size*aspect(), -frustum_size, frustum_size, frustum_front, 1024.0f);
+
+ // model view
+ gl::matrixmode(GL_MODELVIEW);
+ gl::loadidentity();
+
+ // 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(camera_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 * camera_target);
+
+ // apply camera offset
+ gl::translate(distance * camera_axis.forward());
+
+ // calculate eye position
+ camera_eye = camera_target - (distance * camera_axis.forward());
+}
+
+void Camera::set_direction(float direction)
+{
+ target_direction = direction;
+ math::clamp(target_direction, -1.0f, 1.0f);
+}
+
+void Camera::set_pitch(float pitch)
+{
+ target_pitch = pitch;
+ math::clamp(target_pitch, -1.0f, 1.0f);
+}
+
+void Camera::reset()
+{
+ set_mode(camera_mode);
+}
+
+}
diff --git a/src/render/camera.h b/src/render/camera.h
new file mode 100644
index 0000000..42bd835
--- /dev/null
+++ b/src/render/camera.h
@@ -0,0 +1,87 @@
+/*
+ render/camera.h
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_RENDER_CAMERA_H__
+#define __INCLUDED_RENDER_CAMERA_H__
+
+#include "math/mathlib.h"
+
+namespace render {
+
+/// camera functions
+class Camera
+{
+public:
+
+ /// enum indicating the camera mode
+ enum Mode {Free, Track, Cockpit, Overview};
+
+ /// initialize the camera
+ static void init();
+
+ /// shutdown the camera
+ static void shutdown();
+
+ /// gameworld coordinates of the camera eye
+ static inline const math::Vector3f & eye() { return camera_eye; }
+
+ /// gameworld coordinates of the camera target
+ static inline const math::Vector3f & target() { return camera_target; }
+
+ /// gameworld camera axis
+ static inline const math::Axis & axis() { return camera_axis; }
+
+ /// current camera mode
+ static inline Mode mode() { return camera_mode; }
+
+ /// current aspect ratio
+ static inline float aspect() { return camera_aspect; }
+
+ /// reset the current mode
+ static void reset();
+
+ /// draw the OpenGL camera transformation
+ static void draw(float elapsed);
+
+ /// set target direction
+ static void set_direction(float direction);
+
+ /// set target pitch
+ static void set_pitch(float pitch);
+
+ /// switch to next camera mode
+ static void next_mode();
+
+ /// set specified camera mode
+ static void set_mode(Mode newmode);
+
+ /// set camera aspect ratio
+ static void set_aspect(float aspect);
+
+private:
+ static math::Vector3f camera_eye;
+ static math::Vector3f camera_target;
+ static math::Axis camera_axis;
+ static Mode camera_mode;
+ static float camera_aspect;
+
+ // current and target yaw angle in XZ plane, positive is looking left
+ static float direction_current;
+ static float direction_target;
+ static float target_direction;
+
+ // current and target pitch angle in XY, positive is looking up
+ static float pitch_current;
+ static float pitch_target;
+ static float target_pitch;
+
+ static float distance;
+
+};
+
+} // namespace client
+
+#endif // __INCLUDED_RENDER_CAMERA_H__
diff --git a/src/render/draw.cc b/src/render/draw.cc
index cb16b89..f3df6c0 100644
--- a/src/render/draw.cc
+++ b/src/render/draw.cc
@@ -38,10 +38,6 @@ math::Vector3f v7(-1, -1, -1);
const float drawdistance = 128.0f;
const float drawfxdistance = 32.0f;
-math::Vector3f camera_target;
-math::Vector3f camera_eye;
-math::Axis camera_axis;
-
float angle = 0;
// function to test flags
@@ -266,7 +262,7 @@ void pass_prepare(float seconds)
if (entity->model()) {
entity->state()->state_visible = false;
- float dq = math::distancesquared(camera_eye, entity->location());
+ float dq = math::distancesquared(Camera::eye(), entity->location());
if (dq <= drawfxdistance*drawfxdistance*entity->model()->radius()) {
// entites within drawing distance
@@ -487,13 +483,13 @@ void draw_pass_model_fx()
gl::color(color);
glTexCoord2f(0,1);
- gl::vertex(location + (camera_axis.up() - camera_axis.left()) * light_size);
+ gl::vertex(location + (Camera::axis().up() - Camera::axis().left()) * light_size);
glTexCoord2f(0,0);
- gl::vertex(location + (camera_axis.up() + camera_axis.left()) * light_size);
+ gl::vertex(location + (Camera::axis().up() + Camera::axis().left()) * light_size);
glTexCoord2f(1,0);
- gl::vertex(location + (camera_axis.up() * -1 + camera_axis.left()) * light_size);
+ gl::vertex(location + (Camera::axis().up() * -1 + Camera::axis().left()) * light_size);
glTexCoord2f(1,1);
- gl::vertex(location + (camera_axis.up() * -1 - camera_axis.left()) * light_size);
+ gl::vertex(location + (Camera::axis().up() * -1 - Camera::axis().left()) * light_size);
Stats::quads++;
@@ -531,7 +527,7 @@ void draw_pass_model_fx()
color.assign(flare->color());
}
- float a = dotproduct(flare_axis.forward(), camera_axis.forward());
+ float a = dotproduct(flare_axis.forward(), Camera::axis().forward());
if (a < -0.1f) {
color.a = -a - 0.1f;
gl::color(color);
@@ -621,11 +617,11 @@ void draw_pass_spacegrid()
float s = 1.0f / gridsize;
float z = -4.0f;
- float dx = camera_target.x - floorf(camera_target.x);
- float dy = camera_target.y - floorf(camera_target.y);
+ float dx = Camera::target().x - floorf(Camera::target().x);
+ float dy = Camera::target().y - floorf(Camera::target().y);
gl::push();
- gl::translate(camera_target);
+ gl::translate(Camera::target());
gl::color(0,0, 1.0f);
gl::normal(0, 0, 1.0f);
@@ -653,7 +649,7 @@ void draw_pass_spacegrid()
/* ----- Main draw routine ----------------------------------------- */
-void draw(math::Axis const &axis, math::Vector3f const &eye, math::Vector3f const &target, float seconds)
+void draw(float seconds)
{
Stats::clear();
@@ -662,10 +658,8 @@ void draw(math::Axis const &axis, math::Vector3f const &eye, math::Vector3f cons
if( angle > 360.0f ) {
angle -= 360.0f;
}
-
- camera_target.assign(target);
- camera_eye.assign(eye);
- camera_axis.assign(axis);
+
+ Camera::draw(seconds); // draw the current camera transformation
pass_prepare(seconds);
diff --git a/src/render/draw.h b/src/render/draw.h
index a260f34..ee9db26 100644
--- a/src/render/draw.h
+++ b/src/render/draw.h
@@ -14,7 +14,7 @@ namespace render
{
/// draw the world
-void draw(math::Axis const &axis, math::Vector3f const &eye, math::Vector3f const &target, float seconds);
+void draw(float seconds);
/// draw a sphere
void draw_sphere(math::Color const & color, float radius);
diff --git a/src/render/render.cc b/src/render/render.cc
index 87ff64a..dac0972 100644
--- a/src/render/render.cc
+++ b/src/render/render.cc
@@ -85,6 +85,8 @@ void init()
r_bbox = core::Cvar::get("r_bbox", "0", core::Cvar::Archive);
r_bbox->set_info("[bool] render model bounding box");
+ Camera::init();
+
Textures::init();
Text::init();
@@ -94,10 +96,6 @@ void shutdown()
{
con_print << "^BShutting down renderer..." << std::endl;
- Text::shutdown();
-
- Textures::shutdown();
-
// clear entity models, this will force a reload
for (std::map<unsigned int, core::Entity *>::iterator it=core::Entity::registry.begin(); it != core::Entity::registry.end(); it++) {
core::Entity *entity = (*it).second;
@@ -111,6 +109,12 @@ void shutdown()
// clear vertex array
delete vertexarray;
vertexarray = 0;
+
+ Text::shutdown();
+
+ Textures::shutdown();
+
+ Camera::shutdown();
}
}
diff --git a/src/render/render.h b/src/render/render.h
index 68952f1..ebecf7f 100644
--- a/src/render/render.h
+++ b/src/render/render.h
@@ -10,6 +10,7 @@
#include "core/cvar.h"
#include "model/vertexarray.h"
+#include "render/camera.h"
#include "render/draw.h"
#include "render/gl.h"
#include "render/text.h"