]> git.tdb.fi Git - libs/gl.git/blob - source/camera.cpp
Keep track of which components have been set in Transform
[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_ratio(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_look_direction(const Vector3 &l)
72 {
73         look_dir = normalize(l);
74         update_object_matrix();
75 }
76
77 void Camera::look_at(const Vector3 &p)
78 {
79         set_look_direction(p-position);
80 }
81
82 void Camera::set_up_direction(const Vector3 &u)
83 {
84         up_dir = normalize(u);
85         update_object_matrix();
86 }
87
88 void Camera::set_object_matrix(const Matrix &m)
89 {
90         position = m.column(3).slice<3>(0);
91         look_dir = normalize(-m.column(2).slice<3>(0));
92         up_dir = normalize(m.column(1).slice<3>(0));
93         update_object_matrix();
94 }
95
96 Vector3 Camera::project(const Vector4 &p) const
97 {
98         Vector4 r = proj_matrix*(view_matrix*p);
99         return r.slice<3>(0)/r.w;
100 }
101
102 Vector3 Camera::project(const Vector3 &p) const
103 {
104         return project(Vector4(p.x, p.y, p.z, 1.0));
105 }
106
107 Vector4 Camera::unproject(const Vector4 &p) const
108 {
109         Vector4 r = invert(proj_matrix)*Vector4(p.x, p.y, p.z, 1.0f);
110         r = matrix*Vector4(r.x/r.w, r.y/r.w, r.z/r.w, p.w);
111         return r;
112 }
113
114 Vector3 Camera::unproject(const Vector3 &p) const
115 {
116         return unproject(Vector4(p.x, p.y, p.z, 1.0f)).slice<3>(0);
117 }
118
119 void Camera::apply() const
120 {
121         MatrixStack::projection() = proj_matrix;
122         MatrixStack::modelview() = view_matrix;
123 }
124
125 void Camera::update_projection_matrix()
126 {
127         float frustum_h = (fov!=Geometry::Angle<float>::zero() ? tan(fov/2.0f)*clip_near : height/2);
128         float frustum_w = frustum_h*aspect;
129         float left = frustum_w*(frustum_x-1.0f);
130         float right = frustum_w*(frustum_x+1.0f);
131         float bottom = frustum_h*(frustum_y-1.0f);
132         float top = frustum_h*(frustum_y+1.0f);
133         if(fov>Geometry::Angle<float>::zero())
134                 proj_matrix = Matrix::frustum(left, right, bottom, top, clip_near, clip_far);
135         else
136                 proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
137         proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
138 }
139
140 void Camera::update_object_matrix()
141 {
142         Vector3 right_dir = normalize(cross(look_dir, up_dir));
143         Vector4 columns[4];
144         columns[0] = compose(right_dir, 0.0f);
145         columns[1] = compose(cross(right_dir, look_dir), 0.0f);
146         columns[2] = compose(-look_dir, 0.0f);
147         columns[3] = compose(position, 1.0f);
148         matrix = Matrix::from_columns(columns);
149         view_matrix = invert(matrix);
150 }
151
152
153 Camera::Loader::Loader(Camera &c):
154         DataFile::ObjectLoader<Camera>(c)
155 {
156         add("aspect_ratio", &Loader::aspect_ratio);
157         add("depth_clip", &Loader::depth_clip);
158         add("field_of_view", &Loader::field_of_view);
159         add("look_at", &Loader::look_at);
160         add("look_direction", &Loader::look_direction);
161         add("orthographic", &Loader::orthographic);
162         add("position", &Loader::position);
163         add("up_direction", &Loader::up_direction);
164 }
165
166 void Camera::Loader::aspect_ratio(float a)
167 {
168         obj.set_aspect_ratio(a);
169 }
170
171 void Camera::Loader::depth_clip(float n, float f)
172 {
173         obj.set_depth_clip(n, f);
174 }
175
176 void Camera::Loader::field_of_view(float a)
177 {
178         obj.set_field_of_view(Geometry::Angle<float>::from_degrees(a));
179 }
180
181 void Camera::Loader::look_at(float x, float y, float z)
182 {
183         obj.look_at(Vector3(x, y, z));
184 }
185
186 void Camera::Loader::look_direction(float x, float y, float z)
187 {
188         obj.set_look_direction(Vector3(x, y, z));
189 }
190
191 void Camera::Loader::orthographic(float w, float h)
192 {
193         obj.set_orthographic(w, h);
194 }
195
196 void Camera::Loader::position(float x, float y, float z)
197 {
198         obj.set_position(Vector3(x, y, z));
199 }
200
201 void Camera::Loader::up_direction(float x, float y, float z)
202 {
203         obj.set_up_direction(Vector3(x, y, z));
204 }
205
206 } // namespace GL
207 } // namespace Msp