]> git.tdb.fi Git - libs/gl.git/blob - source/camera.cpp
Use libmspmath to provide vector and matrix operations
[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(M_PI/4),
10         aspect(4.0/3.0),
11         clip_near(0.1),
12         clip_far(10),
13         position(0, 0, 0),
14         look_dir(0, 0, -1),
15         up_dir(0, 1, 0)
16 { }
17
18 void Camera::set_field_of_view(float f)
19 {
20         fov = f;
21 }
22
23 void Camera::set_aspect(float a)
24 {
25         aspect = a;
26 }
27
28 void Camera::set_depth_clip(float n, float f)
29 {
30         clip_near = n;
31         clip_far = f;
32 }
33
34 void Camera::set_position(const Vector3 &p)
35 {
36         position = p;
37         compute_matrix();
38 }
39
40 void Camera::set_up_direction(const Vector3 &u)
41 {
42         up_dir = normalize(u);
43
44         compute_matrix();
45 }
46
47 void Camera::set_look_direction(const Vector3 &l)
48 {
49         look_dir = normalize(l);
50
51         compute_matrix();
52 }
53
54 void Camera::look_at(const Vector3 &p)
55 {
56         set_look_direction(p-position);
57 }
58
59 Vector3 Camera::project(const Vector4 &p) const
60 {
61         float frustum_h = tan(fov/2);
62         float frustum_w = frustum_h*aspect;
63         float z_range = clip_far-clip_near;
64
65         Vector4 eye = matrix*p;
66
67         return Vector3(eye.x/frustum_w/-eye.z, eye.y/frustum_h/-eye.z,
68                 (clip_far+clip_near)/z_range+2*clip_far*clip_near/(eye.z*z_range));
69 }
70
71 Vector3 Camera::project(const Vector3 &p) const
72 {
73         return project(Vector4(p.x, p.y, p.z, 1.0));
74 }
75
76 Vector4 Camera::unproject(const Vector4 &p) const
77 {
78         float frustum_h = tan(fov/2);
79         float frustum_w = frustum_h*aspect;
80         float z_range = clip_far-clip_near;
81
82         float z = (2*clip_far*clip_near)/(p.z*z_range-(clip_far+clip_near))-matrix[14]*p.w;
83         float x = p.x*-z*frustum_w-matrix[12]*p.w;
84         float y = p.y*-z*frustum_h-matrix[13]*p.w;
85
86         return Vector4(matrix[0]*x+matrix[1]*y+matrix[2]*z,
87                 matrix[4]*x+matrix[5]*y+matrix[6]*z,
88                 matrix[8]*x+matrix[9]*y+matrix[10]*z,
89                 p.w);
90 }
91
92 void Camera::apply() const
93 {
94         MatrixStack::projection() = Matrix::perspective(fov, aspect, clip_near, clip_far);
95         MatrixStack::modelview() = matrix;
96 }
97
98 void Camera::compute_matrix()
99 {
100         Vector3 right_dir = normalize(cross(look_dir, up_dir));
101         double mdata[16];
102
103         mdata[0] = right_dir.x;
104         mdata[4] = right_dir.y;
105         mdata[8] = right_dir.z;
106
107         mdata[1] = right_dir.y*look_dir.z-right_dir.z*look_dir.y;
108         mdata[5] = right_dir.z*look_dir.x-right_dir.x*look_dir.z;
109         mdata[9] = right_dir.x*look_dir.y-right_dir.y*look_dir.x;
110
111         mdata[2] = -look_dir.x;
112         mdata[6] = -look_dir.y;
113         mdata[10] = -look_dir.z;
114
115         mdata[12] = -position.x*mdata[0]-position.y*mdata[4]-position.z*mdata[8];
116         mdata[13] = -position.x*mdata[1]-position.y*mdata[5]-position.z*mdata[9];
117         mdata[14] = -position.x*mdata[2]-position.y*mdata[6]-position.z*mdata[10];
118
119         mdata[3] = 0;
120         mdata[7] = 0;
121         mdata[11] = 0;
122         mdata[15] = 1;
123
124         matrix = mdata;
125 }
126
127 } // namespace GL
128 } // namespace Msp