]> git.tdb.fi Git - libs/gl.git/blob - source/camera.cpp
Add another constructor to RenderTarget to resolve an ambiguity
[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::update_projection_matrix()
120 {
121         float frustum_h = (fov!=Geometry::Angle<float>::zero() ? tan(fov/2.0f)*clip_near : height/2);
122         float frustum_w = frustum_h*aspect;
123         float left = frustum_w*(frustum_x-1.0f);
124         float right = frustum_w*(frustum_x+1.0f);
125         float bottom = frustum_h*(frustum_y-1.0f);
126         float top = frustum_h*(frustum_y+1.0f);
127         if(fov>Geometry::Angle<float>::zero())
128                 proj_matrix = Matrix::frustum(left, right, bottom, top, clip_near, clip_far);
129         else
130                 proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
131         proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
132 }
133
134 void Camera::update_object_matrix()
135 {
136         Vector3 right_dir = normalize(cross(look_dir, up_dir));
137         Vector4 columns[4];
138         columns[0] = compose(right_dir, 0.0f);
139         columns[1] = compose(cross(right_dir, look_dir), 0.0f);
140         columns[2] = compose(-look_dir, 0.0f);
141         columns[3] = compose(position, 1.0f);
142         matrix = Matrix::from_columns(columns);
143         view_matrix = invert(matrix);
144 }
145
146
147 Camera::Loader::Loader(Camera &c):
148         DataFile::ObjectLoader<Camera>(c)
149 {
150         add("aspect_ratio", &Loader::aspect_ratio);
151         add("depth_clip", &Loader::depth_clip);
152         add("field_of_view", &Loader::field_of_view);
153         add("look_at", &Loader::look_at);
154         add("look_direction", &Loader::look_direction);
155         add("orthographic", &Loader::orthographic);
156         add("position", &Loader::position);
157         add("up_direction", &Loader::up_direction);
158 }
159
160 void Camera::Loader::aspect_ratio(float a)
161 {
162         obj.set_aspect_ratio(a);
163 }
164
165 void Camera::Loader::depth_clip(float n, float f)
166 {
167         obj.set_depth_clip(n, f);
168 }
169
170 void Camera::Loader::field_of_view(float a)
171 {
172         obj.set_field_of_view(Geometry::Angle<float>::from_degrees(a));
173 }
174
175 void Camera::Loader::look_at(float x, float y, float z)
176 {
177         obj.look_at(Vector3(x, y, z));
178 }
179
180 void Camera::Loader::look_direction(float x, float y, float z)
181 {
182         obj.set_look_direction(Vector3(x, y, z));
183 }
184
185 void Camera::Loader::orthographic(float w, float h)
186 {
187         obj.set_orthographic(w, h);
188 }
189
190 void Camera::Loader::position(float x, float y, float z)
191 {
192         obj.set_position(Vector3(x, y, z));
193 }
194
195 void Camera::Loader::up_direction(float x, float y, float z)
196 {
197         obj.set_up_direction(Vector3(x, y, z));
198 }
199
200 } // namespace GL
201 } // namespace Msp