]> git.tdb.fi Git - libs/gl.git/blob - source/camera.cpp
Support rotating the camera frustum
[libs/gl.git] / source / camera.cpp
1 #include <cmath>
2 #include "camera.h"
3 #include "matrix.h"
4
5 namespace Msp {
6 namespace GL {
7
8 Camera::Camera():
9         fov(Geometry::Angle<float>::from_turns(0.125)),
10         height(0),
11         aspect(4.0/3.0),
12         clip_near(0.1),
13         clip_far(10),
14         frustum_x(0),
15         frustum_y(0),
16         position(0, 0, 0),
17         look_dir(0, 0, -1),
18         up_dir(0, 1, 0)
19 {
20         update_projection_matrix();
21         update_object_matrix();
22 }
23
24 void Camera::set_field_of_view(const Geometry::Angle<float> &f)
25 {
26         fov = f;
27         update_projection_matrix();
28 }
29
30 void Camera::set_orthographic(float w, float h)
31 {
32         fov = Geometry::Angle<float>::zero();
33         height = h;
34         if(w)
35                 aspect = w/h;
36         update_projection_matrix();
37 }
38
39 void Camera::set_aspect(float a)
40 {
41         aspect = a;
42         update_projection_matrix();
43 }
44
45 void Camera::set_depth_clip(float n, float f)
46 {
47         clip_near = n;
48         clip_far = f;
49         update_projection_matrix();
50 }
51
52 void Camera::set_frustum_axis(float x, float y)
53 {
54         frustum_x = x;
55         frustum_y = y;
56         update_projection_matrix();
57 }
58
59 void Camera::set_frustum_rotation(const Geometry::Angle<float> &r)
60 {
61         rotate = r;
62         update_projection_matrix();
63 }
64
65 void Camera::set_position(const Vector3 &p)
66 {
67         position = p;
68         update_object_matrix();
69 }
70
71 void Camera::set_up_direction(const Vector3 &u)
72 {
73         up_dir = normalize(u);
74         update_object_matrix();
75 }
76
77 void Camera::set_look_direction(const Vector3 &l)
78 {
79         look_dir = normalize(l);
80         update_object_matrix();
81 }
82
83 void Camera::look_at(const Vector3 &p)
84 {
85         set_look_direction(p-position);
86 }
87
88 Vector3 Camera::project(const Vector4 &p) const
89 {
90         Vector4 r = proj_matrix*(view_matrix*p);
91         return r.slice<3>(0)/r.w;
92 }
93
94 Vector3 Camera::project(const Vector3 &p) const
95 {
96         return project(Vector4(p.x, p.y, p.z, 1.0));
97 }
98
99 Vector4 Camera::unproject(const Vector4 &p) const
100 {
101         Vector4 r = invert(proj_matrix)*Vector4(p.x, p.y, p.z, 1.0f);
102         r = object_matrix*Vector4(r.x, r.y, r.z, p.w);
103         return r;
104 }
105
106 void Camera::apply() const
107 {
108         MatrixStack::projection() = proj_matrix;
109         MatrixStack::modelview() = view_matrix;
110 }
111
112 void Camera::update_projection_matrix()
113 {
114         float frustum_h = (fov!=Geometry::Angle<float>::zero() ? tan(fov/2.0f)*clip_near : height/2);
115         float frustum_w = frustum_h*aspect;
116         float left = frustum_w*(frustum_x-1.0f);
117         float right = frustum_w*(frustum_x+1.0f);
118         float bottom = frustum_h*(frustum_y-1.0f);
119         float top = frustum_h*(frustum_y+1.0f);
120         if(fov>Geometry::Angle<float>::zero())
121                 proj_matrix = Matrix::frustum(left, right, bottom, top, clip_near, clip_far);
122         else
123                 proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
124         proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
125 }
126
127 void Camera::update_object_matrix()
128 {
129         Vector3 right_dir = normalize(cross(look_dir, up_dir));
130         Vector4 columns[4];
131         columns[0] = compose(right_dir, 0.0f);
132         columns[1] = compose(cross(right_dir, look_dir), 0.0f);
133         columns[2] = compose(-look_dir, 0.0f);
134         columns[3] = compose(position, 1.0f);
135         object_matrix = Matrix::from_columns(columns);
136         view_matrix = invert(object_matrix);
137 }
138
139 } // namespace GL
140 } // namespace Msp