From 0f87d2fd05786f7ab128d4a041673f6fb085139f Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sun, 1 Jun 2008 14:56:22 +0000 Subject: moved camera into render:: --- src/render/Makefile.am | 6 +- src/render/camera.cc | 349 +++++++++++++++++++++++++++++++++++++++++++++++++ src/render/camera.h | 87 ++++++++++++ src/render/draw.cc | 30 ++--- src/render/draw.h | 2 +- src/render/render.cc | 12 +- src/render/render.h | 1 + 7 files changed, 461 insertions(+), 26 deletions(-) create mode 100644 src/render/camera.cc create mode 100644 src/render/camera.h (limited to 'src/render') 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::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" -- cgit v1.2.3