Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/camera.h>
27 :
28 : #include <gpac/options.h>
29 : #include "visual_manager.h"
30 :
31 : #define FORCE_CAMERA_3D
32 :
33 684 : void camera_invalidate(GF_Camera *cam)
34 : {
35 : /*forces recompute of default viewpoint*/
36 684 : cam->had_viewpoint = 2;
37 684 : cam->had_nav_info = GF_TRUE;
38 684 : cam->flags = CAM_IS_DIRTY;
39 : // cam->navigate_mode = GF_NAVIGATE_NONE;
40 684 : }
41 :
42 2477 : static void camera_frustum_from_matrix(GF_Camera *cam, GF_Matrix *mx)
43 : {
44 : u32 i;
45 :
46 2477 : cam->planes[FRUS_LEFT_PLANE].normal.x = mx->m[3] + mx->m[0];
47 2477 : cam->planes[FRUS_LEFT_PLANE].normal.y = mx->m[7] + mx->m[4];
48 2477 : cam->planes[FRUS_LEFT_PLANE].normal.z = mx->m[11] + mx->m[8];
49 2477 : cam->planes[FRUS_LEFT_PLANE].d = mx->m[15] + mx->m[12];
50 :
51 2477 : cam->planes[FRUS_RIGHT_PLANE].normal.x = mx->m[3] - mx->m[0];
52 2477 : cam->planes[FRUS_RIGHT_PLANE].normal.y = mx->m[7] - mx->m[4];
53 2477 : cam->planes[FRUS_RIGHT_PLANE].normal.z = mx->m[11] - mx->m[8];
54 2477 : cam->planes[FRUS_RIGHT_PLANE].d = mx->m[15] - mx->m[12];
55 :
56 2477 : cam->planes[FRUS_BOTTOM_PLANE].normal.x = mx->m[3] + mx->m[1];
57 2477 : cam->planes[FRUS_BOTTOM_PLANE].normal.y = mx->m[7] + mx->m[5];
58 2477 : cam->planes[FRUS_BOTTOM_PLANE].normal.z = mx->m[11] + mx->m[9];
59 2477 : cam->planes[FRUS_BOTTOM_PLANE].d = mx->m[15] + mx->m[13];
60 :
61 2477 : cam->planes[FRUS_TOP_PLANE].normal.x = mx->m[3] - mx->m[1];
62 2477 : cam->planes[FRUS_TOP_PLANE].normal.y = mx->m[7] - mx->m[5];
63 2477 : cam->planes[FRUS_TOP_PLANE].normal.z = mx->m[11] - mx->m[9];
64 2477 : cam->planes[FRUS_TOP_PLANE].d = mx->m[15] - mx->m[13];
65 :
66 2477 : cam->planes[FRUS_FAR_PLANE].normal.x = mx->m[3] - mx->m[2];
67 2477 : cam->planes[FRUS_FAR_PLANE].normal.y = mx->m[7] - mx->m[6];
68 2477 : cam->planes[FRUS_FAR_PLANE].normal.z = mx->m[11] - mx->m[10];
69 2477 : cam->planes[FRUS_FAR_PLANE].d = mx->m[15] - mx->m[14];
70 :
71 2477 : cam->planes[FRUS_NEAR_PLANE].normal.x = mx->m[3] + mx->m[2];
72 2477 : cam->planes[FRUS_NEAR_PLANE].normal.y = mx->m[7] + mx->m[6];
73 2477 : cam->planes[FRUS_NEAR_PLANE].normal.z = mx->m[11] + mx->m[10];
74 2477 : cam->planes[FRUS_NEAR_PLANE].d = mx->m[15] + mx->m[14];
75 :
76 17339 : for (i=0; i<6; ++i) {
77 : #ifdef GPAC_FIXED_POINT
78 : /*after some testing, it's just safer to move back to float here, the smallest drift will
79 : result in completely wrong culling...*/
80 : Float vx, vy, vz, nor;
81 : vx = FIX2FLT(cam->planes[i].normal.x);
82 : vy = FIX2FLT(cam->planes[i].normal.y);
83 : vz = FIX2FLT(cam->planes[i].normal.z);
84 : nor = (Float) sqrt(vx*vx + vy*vy + vz*vz);
85 : vx /= nor;
86 : vy /= nor;
87 : vz /= nor;
88 : cam->planes[i].d = FLT2FIX (FIX2FLT(cam->planes[i].d) / nor);
89 : cam->planes[i].normal.x = FLT2FIX(vx);
90 : cam->planes[i].normal.y = FLT2FIX(vy);
91 : cam->planes[i].normal.z = FLT2FIX(vz);
92 : #else
93 14862 : Float len = (Float)(1.0f / gf_vec_len(cam->planes[i].normal));
94 14862 : cam->planes[i].normal = gf_vec_scale(cam->planes[i].normal, len);
95 14862 : cam->planes[i].d *= len;
96 : #endif
97 :
98 : /*compute p-vertex idx*/
99 14862 : cam->p_idx[i] = gf_plane_get_p_vertex_idx(&cam->planes[i]);
100 : }
101 2477 : }
102 :
103 : /*based on Copyright (C) 1995 Stephen Chenney (schenney@cs.berkeley.edu)*/
104 158 : SFRotation camera_get_orientation(SFVec3f pos, SFVec3f target, SFVec3f up)
105 : {
106 : SFVec3f dir, tmp, v, axis, new_y;
107 : SFVec4f norm, inv_norm, y_quat, ny_quat, rot_y, rot;
108 :
109 158 : gf_vec_diff(dir, target, pos);
110 158 : gf_vec_norm(&dir);
111 158 : tmp = gf_vec_scale(dir, gf_vec_dot(up, dir));
112 158 : gf_vec_diff(v, up, tmp);
113 158 : gf_vec_norm(&v);
114 158 : axis.x = dir.y;
115 158 : axis.y = -dir.x;
116 158 : axis.z = 0;
117 :
118 158 : if (gf_vec_dot(axis, axis) < FIX_EPSILON) {
119 107 : if (dir.z> 0) {
120 1 : norm.x = 0;
121 1 : norm.y = FIX_ONE;
122 1 : norm.z = 0;
123 1 : norm.q = 0;
124 : } else {
125 106 : norm.x = 0;
126 106 : norm.y = 0;
127 106 : norm.z = 0;
128 106 : norm.q = FIX_ONE;
129 : }
130 : } else {
131 51 : gf_vec_norm(&axis);
132 51 : norm = gf_quat_from_axis_cos(axis, -dir.z);
133 : }
134 : /* Find the inverse rotation. */
135 158 : inv_norm.x = -norm.x;
136 158 : inv_norm.y = -norm.y;
137 158 : inv_norm.z = -norm.z;
138 158 : inv_norm.q = norm.q;
139 : /* Rotate the y. */
140 158 : y_quat.x = y_quat.z = y_quat.q = 0;
141 158 : y_quat.y = FIX_ONE;
142 158 : ny_quat = gf_quat_multiply(&norm, &y_quat);
143 158 : ny_quat = gf_quat_multiply(&ny_quat, &inv_norm);
144 :
145 158 : new_y.x = ny_quat.x;
146 158 : new_y.y = ny_quat.y;
147 158 : new_y.z = ny_quat.z;
148 :
149 158 : tmp = gf_vec_cross(new_y, v);
150 :
151 158 : if (gf_vec_dot(tmp, tmp) < FIX_EPSILON) {
152 : /* The old and new may be pointing in the same or opposite. Need
153 : ** to generate a vector perpendicular to the old or new y.
154 : */
155 142 : tmp.x = 0;
156 142 : tmp.y = -v.z;
157 142 : tmp.z = v.y;
158 142 : if (gf_vec_dot(tmp, tmp) < FIX_EPSILON) {
159 0 : tmp.x = v.z;
160 0 : tmp.y = 0;
161 0 : tmp.z = -v.x;
162 : }
163 : }
164 158 : gf_vec_norm(&tmp);
165 :
166 158 : rot_y = gf_quat_from_axis_cos(tmp, gf_vec_dot(new_y, v));
167 :
168 : /* rot_y holds the rotation about the initial camera direction needed
169 : ** to align the up vectors in the final position.
170 : */
171 :
172 : /* Put the 2 rotations together. */
173 158 : rot = gf_quat_multiply(&rot_y, &norm);
174 158 : return gf_quat_to_rotation(&rot);
175 : }
176 :
177 : #define FAR_PLANE_2D -10000
178 : #define NEAR_PLANE_2D 1000
179 :
180 587 : void camera_set_2d(GF_Camera *cam)
181 : {
182 587 : cam->is_3D = GF_FALSE;
183 : #ifdef FORCE_CAMERA_3D
184 587 : cam->position.x = cam->position.y = 0;
185 587 : cam->position.z = INT2FIX(NEAR_PLANE_2D);
186 587 : cam->up.x = cam->up.z = 0;
187 587 : cam->up.y = FIX_ONE;
188 587 : cam->target.x = cam->target.y = cam->target.z = 0;
189 587 : cam->vp_position = cam->position;
190 587 : cam->vp_orientation.x = cam->vp_orientation.y = 0;
191 587 : cam->vp_orientation.q = 0;
192 587 : cam->vp_orientation.y = FIX_ONE;
193 587 : cam->vp_fov = cam->fieldOfView = FLT2FIX(0.785398);
194 587 : cam->vp_dist = INT2FIX(NEAR_PLANE_2D);
195 587 : cam->end_zoom = FIX_ONE;
196 : #endif
197 587 : }
198 :
199 10367 : void camera_update_stereo(GF_Camera *cam, GF_Matrix2D *user_transform, Bool center_coords, Fixed horizontal_shift, Fixed nominal_view_distance, Fixed view_distance_offset, u32 camlay)
200 : {
201 : Fixed vlen, h, w, ar;
202 : SFVec3f corner, center;
203 : GF_Matrix post_model_view;
204 :
205 18257 : if (! (cam->flags & CAM_IS_DIRTY)) return;
206 :
207 2477 : ar = gf_divfix(cam->width, cam->height);
208 2477 : gf_mx_init(post_model_view);
209 :
210 2477 : if (cam->is_3D) {
211 1277 : if (!cam->z_far) {
212 0 : cam->z_near = FIX_ONE / 100;
213 0 : cam->z_far = FIX_ONE * 100;
214 : }
215 : /*setup perspective*/
216 1277 : if (camlay==GF_3D_CAMERA_OFFAXIS) {
217 : Fixed left, right, top, bottom, shift, wd2, ndfl, viewing_distance;
218 : SFVec3f eye, pos, tar, disp;
219 :
220 : viewing_distance = nominal_view_distance;
221 :
222 830 : wd2 = gf_mulfix(cam->z_near, gf_tan(cam->fieldOfView/2));
223 830 : ndfl = gf_divfix(cam->z_near, viewing_distance);
224 : /*compute h displacement*/
225 830 : shift = gf_mulfix(horizontal_shift, ndfl);
226 :
227 : top = wd2;
228 : bottom = -top;
229 830 : left = -gf_mulfix(ar, wd2) - shift;
230 830 : right = gf_mulfix(ar, wd2) - shift;
231 :
232 830 : gf_mx_init(cam->projection);
233 830 : cam->projection.m[0] = gf_divfix(2*cam->z_near, (right-left));
234 830 : cam->projection.m[5] = gf_divfix(2*cam->z_near, (top-bottom));
235 830 : cam->projection.m[8] = gf_divfix(right+left, right-left);
236 830 : cam->projection.m[9] = gf_divfix(top+bottom, top-bottom);
237 830 : cam->projection.m[10] = gf_divfix(cam->z_far+cam->z_near, cam->z_near-cam->z_far);
238 830 : cam->projection.m[11] = -FIX_ONE;
239 830 : cam->projection.m[14] = 2*gf_muldiv(cam->z_near, cam->z_far, cam->z_near-cam->z_far);
240 830 : cam->projection.m[15] = 0;
241 :
242 830 : gf_vec_diff(eye, cam->target, cam->position);
243 830 : gf_vec_norm(&eye);
244 830 : disp = gf_vec_cross(eye, cam->up);
245 830 : gf_vec_norm(&disp);
246 :
247 830 : gf_vec_diff(center, cam->world_bbox.center, cam->position);
248 830 : vlen = gf_vec_len(center);
249 830 : shift = gf_mulfix(horizontal_shift, gf_divfix(vlen, viewing_distance));
250 :
251 830 : pos = gf_vec_scale(disp, shift);
252 830 : gf_vec_add(pos, pos, cam->position);
253 830 : gf_vec_add(tar, pos, eye);
254 :
255 : /*setup modelview*/
256 830 : gf_mx_lookat(&cam->modelview, pos, tar, cam->up);
257 : } else {
258 447 : gf_mx_perspective(&cam->projection, cam->fieldOfView, ar, cam->z_near, cam->z_far);
259 :
260 : /*setup modelview*/
261 447 : gf_mx_lookat(&cam->modelview, cam->position, cam->target, cam->up);
262 : }
263 :
264 1277 : if (!center_coords) {
265 0 : gf_mx_add_scale(&post_model_view, FIX_ONE, -FIX_ONE, FIX_ONE);
266 0 : gf_mx_add_translation(&post_model_view, -cam->width / 2, -cam->height / 2, 0);
267 : }
268 :
269 : /*compute center and radius - CHECK ME!*/
270 1277 : vlen = cam->z_far - cam->z_near;
271 1277 : h = gf_mulfix(vlen , gf_tan(cam->fieldOfView / 2));
272 1277 : w = gf_mulfix(h, ar);
273 : center.x = 0;
274 : center.y = 0;
275 1277 : center.z = cam->z_near + vlen / 2;
276 : corner.x = w;
277 : corner.y = h;
278 : corner.z = vlen;
279 1277 : gf_vec_diff(corner, corner, center);
280 1277 : cam->radius = gf_vec_len(corner);
281 1277 : gf_vec_diff(cam->center, cam->target, cam->position);
282 1277 : gf_vec_norm(&cam->center);
283 1277 : cam->center = gf_vec_scale(cam->center, cam->z_near + vlen/2);
284 1277 : gf_vec_add(cam->center, cam->center, cam->position);
285 : } else {
286 : GF_BBox b;
287 : Fixed hw, hh;
288 1200 : hw = cam->width / 2;
289 1200 : hh = cam->height / 2;
290 1200 : cam->z_near = INT2FIX(NEAR_PLANE_2D);
291 1200 : cam->z_far = INT2FIX(FAR_PLANE_2D);
292 :
293 : /*setup ortho*/
294 1200 : gf_mx_ortho(&cam->projection, -hw, hw, -hh, hh, cam->z_near, cam->z_far);
295 :
296 : /*setup modelview*/
297 2400 : gf_mx_init(cam->modelview);
298 : #ifdef FORCE_CAMERA_3D
299 1200 : if (! (cam->flags & CAM_NO_LOOKAT))
300 1200 : gf_mx_lookat(&cam->modelview, cam->position, cam->target, cam->up);
301 : #endif
302 :
303 1200 : if (!center_coords) {
304 1 : gf_mx_add_scale(&post_model_view, FIX_ONE, -FIX_ONE, FIX_ONE);
305 1 : gf_mx_add_translation(&post_model_view, -hw, -hh, 0);
306 : }
307 1200 : if (user_transform) {
308 : #ifdef FORCE_CAMERA_3D
309 138 : if (! (cam->flags & CAM_NO_LOOKAT)) {
310 : GF_Matrix mx;
311 138 : gf_mx_from_mx2d(&mx, user_transform);
312 138 : mx.m[10] = mx.m[0];
313 138 : gf_mx_add_matrix(&post_model_view, &mx);
314 : } else
315 : #endif
316 0 : gf_mx_add_matrix_2d(&post_model_view, user_transform);
317 : }
318 1200 : if (cam->end_zoom != FIX_ONE) gf_mx_add_scale(&post_model_view, cam->end_zoom, cam->end_zoom, cam->end_zoom);
319 1200 : if (cam->flags & CAM_HAS_VIEWPORT) gf_mx_add_matrix(&post_model_view, &cam->viewport);
320 :
321 : /*compute center & radius*/
322 1200 : b.max_edge.x = hw;
323 1200 : b.max_edge.y = hh;
324 1200 : b.min_edge.x = -hw;
325 1200 : b.min_edge.y = -hh;
326 1200 : b.min_edge.z = b.max_edge.z = (cam->z_near+cam->z_far) / 2;
327 1200 : gf_bbox_refresh(&b);
328 1200 : cam->center = b.center;
329 1200 : cam->radius = b.radius;
330 :
331 1200 : if (camlay==GF_3D_CAMERA_OFFAXIS)
332 : camlay=GF_3D_CAMERA_LINEAR;
333 : }
334 :
335 2477 : if (camlay == GF_3D_CAMERA_CIRCULAR) {
336 : GF_Matrix mx;
337 : Fixed viewing_distance = nominal_view_distance;
338 : SFVec3f pos, target;
339 : Fixed angle;
340 :
341 0 : gf_vec_diff(center, cam->world_bbox.center, cam->position);
342 0 : vlen = gf_vec_len(center);
343 0 : vlen += gf_mulfix(view_distance_offset, gf_divfix(vlen, nominal_view_distance));
344 :
345 0 : gf_vec_diff(pos, cam->target, cam->position);
346 0 : gf_vec_norm(&pos);
347 0 : pos = gf_vec_scale(pos, vlen);
348 0 : gf_vec_add(target, pos, cam->position);
349 :
350 0 : gf_mx_init(mx);
351 0 : gf_mx_add_translation(&mx, target.x, target.y, target.z);
352 0 : angle = gf_atan2(horizontal_shift, viewing_distance);
353 0 : gf_mx_add_rotation(&mx, angle, cam->up.x, cam->up.y, cam->up.z);
354 0 : gf_mx_add_translation(&mx, -target.x, -target.y, -target.z);
355 :
356 0 : pos = cam->position;
357 0 : gf_mx_apply_vec(&mx, &pos);
358 :
359 0 : gf_mx_lookat(&cam->modelview, pos, target, cam->up);
360 2477 : } else if (camlay == GF_3D_CAMERA_LINEAR) {
361 0 : Fixed viewing_distance = nominal_view_distance + view_distance_offset;
362 : GF_Vec eye, disp, pos, tar;
363 :
364 0 : gf_vec_diff(center, cam->world_bbox.center, cam->position);
365 0 : vlen = gf_vec_len(center);
366 0 : vlen += gf_mulfix(view_distance_offset, gf_divfix(vlen, nominal_view_distance));
367 :
368 0 : gf_vec_diff(eye, cam->target, cam->position);
369 0 : gf_vec_norm(&eye);
370 0 : tar = gf_vec_scale(eye, vlen);
371 0 : gf_vec_add(tar, tar, cam->position);
372 :
373 0 : disp = gf_vec_cross(eye, cam->up);
374 0 : gf_vec_norm(&disp);
375 :
376 0 : disp= gf_vec_scale(disp, gf_divfix(gf_mulfix(vlen, horizontal_shift), viewing_distance));
377 0 : gf_vec_add(pos, cam->position, disp);
378 :
379 0 : gf_mx_lookat(&cam->modelview, pos, tar, cam->up);
380 : }
381 2477 : gf_mx_add_matrix(&cam->modelview, &post_model_view);
382 :
383 : /*compute frustum planes*/
384 2477 : gf_mx_copy(cam->unprojection, cam->projection);
385 2477 : gf_mx_add_matrix_4x4(&cam->unprojection, &cam->modelview);
386 2477 : camera_frustum_from_matrix(cam, &cam->unprojection);
387 : /*also compute reverse PM for unprojections*/
388 2477 : gf_mx_inverse_4x4(&cam->unprojection);
389 2477 : cam->flags &= ~CAM_IS_DIRTY;
390 : }
391 :
392 9537 : void camera_update(GF_Camera *cam, GF_Matrix2D *user_transform, Bool center_coords)
393 : {
394 9537 : camera_update_stereo(cam, user_transform, center_coords, 0, 0, 0, GF_3D_CAMERA_STRAIGHT);
395 9537 : }
396 878 : void camera_set_vectors(GF_Camera *cam, SFVec3f pos, SFRotation ori, Fixed fov)
397 : {
398 : Fixed sin_a, cos_a, icos_a, tmp;
399 :
400 878 : cam->fieldOfView = fov;
401 878 : cam->last_pos = cam->position;
402 878 : cam->position = pos;
403 : /*compute up & target vectors in local system*/
404 878 : sin_a = gf_sin(ori.q);
405 878 : cos_a = gf_cos(ori.q);
406 878 : icos_a = FIX_ONE - cos_a;
407 878 : tmp = gf_mulfix(icos_a, ori.z);
408 878 : cam->target.x = gf_mulfix(ori.x, tmp) + gf_mulfix(sin_a, ori.y);
409 878 : cam->target.y = gf_mulfix(ori.y, tmp) - gf_mulfix(sin_a, ori.x);
410 878 : cam->target.z = gf_mulfix(ori.z, tmp) + cos_a;
411 878 : gf_vec_norm(&cam->target);
412 878 : cam->target = gf_vec_scale(cam->target, -cam->vp_dist);
413 878 : gf_vec_add(cam->target, cam->target, pos);
414 878 : tmp = gf_mulfix(icos_a, ori.y);
415 878 : cam->up.x = gf_mulfix(ori.x, tmp) - gf_mulfix(sin_a, ori.z);
416 878 : cam->up.y = gf_mulfix(ori.y, tmp) + cos_a;
417 878 : cam->up.z = gf_mulfix(ori.z, tmp) + gf_mulfix(sin_a, ori.x);
418 878 : gf_vec_norm(&cam->up);
419 878 : cam->flags |= CAM_IS_DIRTY;
420 878 : }
421 :
422 627 : void camera_reset_viewpoint(GF_Camera *cam, Bool animate)
423 : {
424 627 : if (!animate || (cam->had_viewpoint==2) ) {
425 623 : camera_set_vectors(cam, cam->vp_position, cam->vp_orientation, cam->vp_fov);
426 623 : cam->last_pos = cam->vp_position;
427 623 : cam->anim_len = 0;
428 623 : return;
429 : }
430 : #ifndef FORCE_CAMERA_3D
431 : if (cam->is_3D)
432 : #endif
433 : {
434 4 : cam->start_pos = cam->position;
435 4 : cam->start_ori = camera_get_orientation(cam->position, cam->target, cam->up);
436 4 : cam->start_fov = cam->fieldOfView;
437 4 : cam->end_pos = cam->vp_position;
438 4 : cam->end_ori = cam->vp_orientation;
439 4 : cam->end_fov = cam->vp_fov;
440 :
441 4 : cam->flags |= CAM_IS_DIRTY;
442 4 : cam->anim_start = 0;
443 4 : cam->anim_len = 1000;
444 : }
445 : #ifndef FORCE_CAMERA_3D
446 : else {
447 : cam->start_zoom = FIX_ONE;
448 : cam->start_trans.x = cam->start_trans.y = 0;
449 : cam->start_rot.x = cam->start_rot.y = 0;
450 : cam->flags |= CAM_IS_DIRTY;
451 : /*no animation on 3D viewports*/
452 : cam->anim_start = cam->anim_len = 0;
453 : }
454 : #endif
455 : }
456 :
457 76 : void camera_move_to(GF_Camera *cam, SFVec3f pos, SFVec3f target, SFVec3f up)
458 : {
459 76 : if (!cam->anim_len) {
460 76 : cam->start_pos = cam->position;
461 76 : cam->start_ori = camera_get_orientation(cam->position, cam->target, cam->up);
462 76 : cam->start_fov = cam->fieldOfView;
463 : }
464 76 : cam->end_pos = pos;
465 76 : cam->end_ori = camera_get_orientation(pos, target, up);
466 76 : cam->end_fov = cam->fieldOfView;
467 :
468 76 : cam->flags |= CAM_IS_DIRTY;
469 76 : cam->anim_start = 0;
470 76 : cam->anim_len = 100;
471 76 : }
472 :
473 285 : void camera_stop_anim(GF_Camera *cam)
474 : {
475 285 : cam->anim_len = 0;
476 285 : }
477 :
478 1 : void camera_jump(GF_Camera *cam)
479 : {
480 : /*no "double-jump" :)*/
481 1 : if (cam->jumping) return;
482 1 : cam->anim_start = 0;
483 1 : cam->anim_len = 1000;
484 1 : cam->jumping = GF_TRUE;
485 1 : cam->flags |= CAM_IS_DIRTY;
486 : }
487 :
488 :
489 8742 : Bool camera_animate(GF_Camera *cam, void *_compositor)
490 : {
491 : u32 now;
492 : Fixed frac;
493 : GF_Compositor *compositor = (GF_Compositor *) _compositor;
494 8742 : if (!cam->anim_len) return GF_FALSE;
495 :
496 106 : now = gf_sc_get_clock(compositor);
497 :
498 106 : if (cam->jumping) {
499 0 : if (!cam->anim_start) {
500 0 : cam->anim_start = now;
501 0 : cam->dheight = 0;
502 0 : return GF_TRUE;
503 : }
504 0 : cam->position.y -= cam->dheight;
505 0 : cam->target.y -= cam->dheight;
506 :
507 0 : now -= cam->anim_start;
508 0 : if (now > cam->anim_len) {
509 0 : cam->anim_len = 0;
510 0 : cam->jumping = GF_FALSE;
511 0 : cam->flags |= CAM_IS_DIRTY;
512 0 : return GF_TRUE;
513 : }
514 0 : frac = FLT2FIX ( ((Float) now) / cam->anim_len);
515 0 : if (frac>FIX_ONE / 2) frac = FIX_ONE - frac;
516 0 : cam->dheight = gf_mulfix(cam->avatar_size.y, frac);
517 0 : cam->position.y += cam->dheight;
518 0 : cam->target.y += cam->dheight;
519 0 : cam->flags |= CAM_IS_DIRTY;
520 0 : return GF_TRUE;
521 : }
522 :
523 106 : if (!cam->anim_start) {
524 7 : cam->anim_start = now;
525 : frac = 0;
526 : } else {
527 99 : now -= cam->anim_start;
528 99 : if (now > cam->anim_len) {
529 4 : cam->anim_len = 0;
530 : #ifndef FORCE_CAMERA_3D
531 : if (cam->is_3D)
532 : #endif
533 : {
534 4 : camera_set_vectors(cam, cam->end_pos, cam->end_ori, cam->end_fov);
535 4 : cam->end_zoom = FIX_ONE;
536 : }
537 : #ifndef FORCE_CAMERA_3D
538 : else {
539 : cam->flags |= CAM_IS_DIRTY;
540 : }
541 : #endif
542 :
543 4 : if (cam->flags & CF_STORE_VP) {
544 2 : cam->flags &= ~CF_STORE_VP;
545 2 : cam->vp_position = cam->position;
546 2 : cam->vp_fov = cam->fieldOfView;
547 2 : cam->vp_orientation = camera_get_orientation(cam->position, cam->target, cam->up);
548 : }
549 : return GF_TRUE;
550 : } else {
551 95 : frac = FLT2FIX( ((Float) now) / cam->anim_len);
552 : }
553 : }
554 :
555 : #ifndef FORCE_CAMERA_3D
556 : if (cam->is_3D)
557 : #endif
558 : {
559 : SFVec3f pos, dif;
560 : SFRotation rot;
561 : Fixed fov;
562 102 : rot = gf_sg_sfrotation_interpolate(cam->start_ori, cam->end_ori, frac);
563 102 : gf_vec_diff(dif, cam->end_pos, cam->start_pos);
564 102 : dif = gf_vec_scale(dif, frac);
565 102 : gf_vec_add(pos, cam->start_pos, dif);
566 102 : fov = gf_mulfix(cam->end_fov - cam->start_fov, frac) + cam->start_fov;
567 102 : cam->end_zoom = frac + gf_mulfix((FIX_ONE-frac), cam->start_zoom);
568 102 : camera_set_vectors(cam, pos, rot, fov);
569 : }
570 102 : return GF_TRUE;
571 : }
572 :
573 :
574 4045 : SFVec3f camera_get_pos_dir(GF_Camera *cam)
575 : {
576 : SFVec3f v;
577 4045 : gf_vec_diff(v, cam->position, cam->target);
578 4045 : gf_vec_norm(&v);
579 4045 : return v;
580 : }
581 4035 : SFVec3f camera_get_target_dir(GF_Camera *cam)
582 : {
583 : SFVec3f v;
584 4035 : gf_vec_diff(v, cam->target, cam->position);
585 4035 : gf_vec_norm(&v);
586 4035 : return v;
587 : }
588 3953 : SFVec3f camera_get_right_dir(GF_Camera *cam)
589 : {
590 : SFVec3f v, pos;
591 3953 : pos = camera_get_pos_dir(cam);
592 3953 : v = gf_vec_cross(cam->up, pos );
593 3953 : gf_vec_norm(&v);
594 3953 : return v;
595 : }
596 :
597 :
|