1 /*!
2 \file lib/ogsf/gk2.c
3
4 \brief OGSF library - setting and manipulating keyframes animation
5
6 GRASS OpenGL gsurf OGSF Library
7
8 (C) 1999-2008 by the GRASS Development Team
9
10 This program is free software under the
11 GNU General Public License (>=v2).
12 Read the file COPYING that comes with GRASS
13 for details.
14
15 \author Bill Brown USACERL, GMSL/University of Illinois
16 \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
17 */
18
19 #include <stdlib.h>
20
21 #include <grass/gis.h>
22 #include <grass/glocale.h>
23 #include <grass/ogsf.h>
24
25 static int _add_key(Keylist *, int, float);
26 static void _remove_key(Keylist *);
27
28 static Keylist *Keys = NULL;
29 static Keylist *Keytail = NULL;
30 static Viewnode *Views = NULL;
31 static float Keystartpos = 0.0;
32 static float Keyendpos = 1.0;
33 static float Tension = 0.8;
34 static int Viewsteps = 0;
35 static int Numkeys = 0;
36 static int Interpmode = KF_SPLINE;
37 static int Fmode = 0;
38
39 /* next & prior already initialized to NULL */
_add_key(Keylist * newk,int force_replace,float precis)40 static int _add_key(Keylist * newk, int force_replace, float precis)
41 {
42 Keylist *k, *tempk, *prev;
43 int found;
44
45 found = 0;
46 prev = NULL;
47
48 /* if(Viewsteps) precis = 0.5/Viewsteps; */
49 for (k = Keys; k; k = k->next) {
50 if (k->pos >= newk->pos - precis && k->pos <= newk->pos + precis) {
51 if (force_replace) {
52
53 if (k->prior) {
54 k->prior->next = newk;
55 newk->prior = prev;
56 }
57 else {
58 Keys = newk;
59 }
60
61 newk->next = k->next;
62 newk->prior = k->prior;
63 tempk = k;
64 k = newk;
65 free(tempk);
66 }
67 else {
68 free(newk);
69 }
70
71 return (-1);
72 }
73 }
74
75 if (Keys) {
76 if (newk->pos < Keys->pos) {
77 /* new will be first */
78 newk->next = Keys;
79 Keys->prior = newk;
80 Keys = newk;
81 }
82 else {
83 prev = k = Keys;
84 while (k && !found) {
85 if (k->pos > newk->pos) {
86 prev->next = newk;
87 newk->next = k;
88 newk->prior = prev;
89 k->prior = newk;
90 found = 1;
91 }
92
93 prev = k;
94 k = k->next;
95 }
96 if (!found) {
97 Keytail = prev->next = newk;
98 newk->prior = prev;
99 }
100 }
101 }
102 else {
103 Keys = Keytail = newk;
104 }
105
106 ++Numkeys;
107 return (1);
108 }
109
_remove_key(Keylist * k)110 static void _remove_key(Keylist * k)
111 {
112 if (k->prior) {
113 k->prior->next = k->next;
114 if (k->next) {
115 k->next->prior = k->prior;
116 }
117 else {
118 Keytail = k->prior;
119 }
120 }
121 else {
122 Keys = k->next;
123 if (k->next) {
124 k->next->prior = NULL;
125 }
126 }
127 k->next = k->prior = NULL;
128
129 return;
130 }
131
132 /*!
133 \brief Set interpolation mode
134
135 \param mode interpolation mode (KF_LINEAR or KF_SPLINE)
136
137 \return 1 on success
138 \return -1 on error (invalid interpolation mode)
139 */
GK_set_interpmode(int mode)140 int GK_set_interpmode(int mode)
141 {
142 if (KF_LEGAL_MODE(mode)) {
143 Interpmode = mode;
144 return (1);
145 }
146
147 return (-1);
148 }
149
150 /*!
151 \brief Set value for tension when interpmode is KF_SPLINE.
152
153 \param tens value tens should be between 0.0; 1.0.
154 */
GK_set_tension(float tens)155 void GK_set_tension(float tens)
156 {
157 Tension = tens > 1.0 ? 1.0 : (tens < 0.0 ? 0.0 : tens);
158
159 /* for now */
160 if (Views) {
161 GK_update_frames();
162 GS_set_draw(GSD_BACK);
163 GS_ready_draw();
164 GS_clear(GS_background_color());
165 GS_alldraw_wire();
166
167 gk_draw_path(Views, Viewsteps, Keys);
168
169 GS_done_draw();
170 }
171
172 return;
173 }
174
GK_showtension_start(void)175 void GK_showtension_start(void)
176 {
177 return;
178 }
179
180 /*!
181 \brief Show tension stop ?
182
183 Use GK_showtension_start/GK_update_tension/GK_showtension_stop to
184 initialize and stop multi-view display of path when changing
185 tension.
186 */
GK_showtension_stop(void)187 void GK_showtension_stop(void)
188 {
189 return;
190 }
191
192 /*!
193 \brief Update tension
194 */
GK_update_tension(void)195 void GK_update_tension(void)
196 {
197 if (Views) {
198 GK_update_frames();
199 }
200
201 return;
202 }
203
204 /*!
205 \brief Print keyframe info
206
207 \param name filename
208 */
GK_print_keys(const char * name)209 void GK_print_keys(const char *name)
210 {
211 Keylist *k;
212 FILE *fp;
213 int cnt = 1;
214
215 if (NULL == (fp = fopen(name, "w"))) {
216 G_fatal_error(_("Unable to open file <%s> for writing"), name);
217 }
218 /* write a default frame rate of 30 at top of file */
219 fprintf(fp, "30 \n");
220
221 for (k = Keys; k; k = k->next) {
222
223 fprintf(fp,
224 "{%f {{FromX %f} {FromY %f} {FromZ %f} {DirX %f} {DirY %f} {DirZ %f} {FOV %f} {TWIST %f} {cplane-0 {{pos_x 0.000000} {pos_y 0.000000} {pos_z 0.000000} {blend_type OFF} {rot 0.000000} {tilt 0.000000}}}} keyanimtag%d 0} ",
225 k->pos, k->fields[KF_FROMX], k->fields[KF_FROMY],
226 k->fields[KF_FROMZ], k->fields[KF_DIRX], k->fields[KF_DIRY],
227 k->fields[KF_DIRZ], k->fields[KF_FOV] / 10.,
228 k->fields[KF_TWIST], cnt);
229 cnt++;
230 }
231
232 fclose(fp);
233 return;
234
235 }
236
237 /*!
238 \brief Recalculate path using the current number of frames requested.
239
240 Call after changing number of frames or when
241 Keyframes change.
242 */
GK_update_frames(void)243 void GK_update_frames(void)
244 {
245 Keylist *k;
246 int loop = 0;
247
248 if (Keys) {
249 if (Numkeys > 1) {
250 k = Keytail;
251 Keyendpos = k->pos;
252
253 if (k->fields[KF_FROMX] == Keys->fields[KF_FROMX] &&
254 k->fields[KF_FROMY] == Keys->fields[KF_FROMY] &&
255 k->fields[KF_FROMZ] == Keys->fields[KF_FROMZ]) {
256 loop = 1;
257 }
258 }
259
260 Keystartpos = Keys->pos;
261 }
262
263 if (Interpmode == KF_LINEAR && Numkeys > 1) {
264 if (Views) {
265 free(Views);
266 Views = NULL;
267 }
268
269 Views = gk_make_linear_framesfromkeys(Keys, Numkeys, Viewsteps, loop);
270
271 if (!Views) {
272 G_warning(_("Check no. of frames requested and keyframes marked"));
273 }
274 }
275 else if (Numkeys > 2) {
276 if (Views) {
277 free(Views);
278 Views = NULL;
279 }
280
281 Views = gk_make_framesfromkeys
282 (Keys, Numkeys, Viewsteps, loop, 1.0 - Tension);
283
284 if (!Views) {
285 G_warning(_("Check no. of frames requested and keyframes marked"));
286 }
287 }
288
289 return;
290 }
291
292 /*!
293 \brief Set the number of frames to be interpolated from keyframes
294
295 \param newsteps number of frames
296 */
GK_set_numsteps(int newsteps)297 void GK_set_numsteps(int newsteps)
298 {
299 Viewsteps = newsteps;
300 GK_update_frames();
301
302 return;
303 }
304
305 /*!
306 \brief Deletes all keyframes, resets field masks.
307
308 Doesn't change number of frames requested.
309 */
GK_clear_keys(void)310 void GK_clear_keys(void)
311 {
312 gk_free_key(Keys);
313 Keys = NULL;
314 Numkeys = 0;
315 free(Views);
316 Views = NULL;
317
318 Keystartpos = 0.0;
319 Keyendpos = 1.0;
320
321 return;
322 }
323
324 /*!
325 \brief Move keyframe
326
327 Precis works as in other functions - to identify keyframe to move.
328 Only the first keyframe in the precis range will be moved.
329
330 \param oldpos old position
331 \param precis precision value
332 \param newpos new position
333
334 \return number of keys moved (1 or 0)
335 */
GK_move_key(float oldpos,float precis,float newpos)336 int GK_move_key(float oldpos, float precis, float newpos)
337 {
338 Keylist *k;
339
340 for (k = Keys; k; k = k->next) {
341 if (k->pos >= oldpos - precis && k->pos <= oldpos + precis) {
342 _remove_key(k);
343 k->pos = newpos;
344 _add_key(k, 1, precis);
345 GK_update_frames();
346 return (1);
347 }
348 }
349
350 return (0);
351 }
352
353 /*!
354 Delete keyframe
355
356 The values pos and precis are used to determine which keyframes to
357 delete. Any keyframes with their position within precis of pos will
358 be deleted if justone is zero. If justone is non-zero, only the first
359 (lowest pos) keyframe in the range will be deleted.
360
361 \param pos position
362 \param precis precision
363 \param justone delete only one keyframe
364
365 \return number of keys deleted.
366 */
GK_delete_key(float pos,float precis,int justone)367 int GK_delete_key(float pos, float precis, int justone)
368 {
369 Keylist *k, *next;
370 int cnt;
371
372 for (cnt = 0, k = Keys; k;) {
373 next = k->next;
374
375 if (k->pos >= pos - precis && k->pos <= pos + precis) {
376 cnt++;
377 _remove_key(k);
378 free(k);
379 if (justone) {
380 break;
381 }
382 }
383
384 k = next;
385 }
386
387 GK_update_frames();
388 return (cnt);
389 }
390
391 /*!
392 \brief Add keyframe
393
394 The pos value is the relative position in the animation for this
395 particular keyframe - used to compare relative distance to neighboring
396 keyframes, it can be any floating point value.
397
398 The fmask value can be any of the following or'd together:
399 - KF_FROMX_MASK
400 - KF_FROMY_MASK
401 - KF_FROMZ_MASK
402 - KF_FROM_MASK (KF_FROMX_MASK | KF_FROMY_MASK | KF_FROMZ_MASK)
403
404 - KF_DIRX_MASK
405 - KF_DIRY_MASK
406 - KF_DIRZ_MASK
407 - KF_DIR_MASK (KF_DIRX_MASK | KF_DIRY_MASK | KF_DIRZ_MASK)
408
409 - KF_FOV_MASK
410 - KF_TWIST_MASK
411
412 - KF_ALL_MASK (KF_FROM_MASK | KF_DIR_MASK | KF_FOV_MASK | KF_TWIST_MASK)
413
414 Other fields will be added later.
415
416 The value precis and the boolean force_replace are used to determine
417 if a keyframe should be considered to be at the same position as a
418 pre-existing keyframe. e.g., if anykey.pos - newkey.pos <= precis,
419 GK_add_key() will fail unless force_replace is TRUE.
420
421 \param pos position
422 \param fmaks
423 \param force_replace
424 \param precis precision value
425
426 \return 1 if key is added
427 \return -1 key not added
428 */
GK_add_key(float pos,unsigned long fmask,int force_replace,float precis)429 int GK_add_key(float pos, unsigned long fmask, int force_replace,
430 float precis)
431 {
432 Keylist *newk;
433 float tmp[3];
434
435 if (NULL == (newk = (Keylist *) malloc(sizeof(Keylist)))) {
436 fprintf(stderr, "Out of memory\n");
437 return (-1);
438 }
439
440 /* All fields set, don't use mask until making Views */
441
442 GS_get_from(tmp);
443 newk->fields[KF_FROMX] = tmp[X];
444 newk->fields[KF_FROMY] = tmp[Y];
445 newk->fields[KF_FROMZ] = tmp[Z];
446
447 G_debug(3, "KEY FROM: %f %f %f", tmp[X], tmp[Y], tmp[Z]);
448
449 /* Instead of View Dir try get_focus (view center) */
450 /* View Dir is implied from eye and center position */
451 /* GS_get_viewdir(tmp); */
452
453 /* ACS 1 line: was GS_get_focus(tmp);
454 with this kanimator works also for flythrough navigation
455 also changed in gk.c
456 */
457 GS_get_viewdir(tmp);
458 newk->fields[KF_DIRX] = tmp[X];
459 newk->fields[KF_DIRY] = tmp[Y];
460 newk->fields[KF_DIRZ] = tmp[Z];
461
462 newk->fields[KF_FOV] = GS_get_fov();
463 newk->fields[KF_TWIST] = GS_get_twist();
464 newk->pos = pos;
465 newk->fieldmask = fmask;
466 newk->next = NULL;
467 newk->prior = NULL;
468
469 if (0 < _add_key(newk, force_replace, precis)) {
470 GK_update_frames();
471 return (1);
472 }
473
474 return (-1);
475 }
476
477 /*!
478 \brief Moves the animation to frame number "step".
479
480 Step should be a value between 1 and the number of frames. If
481 render is non-zero, calls draw_all.
482
483 \param step step value
484 \param render
485 */
GK_do_framestep(int step,int render)486 void GK_do_framestep(int step, int render)
487 {
488 if (Views) {
489 if (step > 0 && step <= Viewsteps) {
490 gk_follow_frames(Views, Viewsteps, Keys, step, 1, render, Fmode);
491 }
492 }
493
494 return;
495 }
496
497 /*!
498 \brief Draw the current path
499
500 \param flag
501 */
GK_show_path(int flag)502 void GK_show_path(int flag)
503 {
504 if (flag) {
505 Fmode |= FM_PATH;
506
507 if (Views) {
508 GS_set_draw(GSD_FRONT);
509 GS_ready_draw();
510
511 gk_draw_path(Views, Viewsteps, Keys);
512
513 GS_done_draw();
514
515 }
516 }
517 else {
518 Fmode &= ~FM_PATH;
519 }
520
521 return;
522 }
523
524 /*!
525 \brief Show vector sets
526
527 \param flag
528 */
GK_show_vect(int flag)529 void GK_show_vect(int flag)
530 {
531 if (flag) {
532 Fmode |= FM_VECT;
533 if (Views) {
534
535 GS_set_draw(GSD_FRONT);
536 GS_ready_draw();
537
538 GV_alldraw_vect();
539
540 GS_done_draw();
541 }
542 }
543 else {
544 Fmode &= ~FM_VECT;
545 }
546
547 return;
548 }
549
550 /*!
551 \brief Show point sets
552
553 \param flag
554 */
GK_show_site(int flag)555 void GK_show_site(int flag)
556 {
557 if (flag) {
558 Fmode |= FM_SITE;
559
560 if (Views) {
561
562 GS_set_draw(GSD_FRONT);
563 GS_ready_draw();
564
565 GP_alldraw_site();
566
567 GS_done_draw();
568
569 }
570 }
571 else {
572 Fmode &= ~FM_SITE;
573 }
574
575 return;
576 }
577
578 /*!
579 \brief Show volumes
580
581 \param flag
582 */
GK_show_vol(int flag)583 void GK_show_vol(int flag)
584 {
585 if (flag) {
586 Fmode |= FM_VOL;
587
588 if (Views) {
589
590 GS_set_draw(GSD_FRONT);
591 GS_ready_draw();
592
593 GVL_alldraw_vol();
594
595 GS_done_draw();
596
597 }
598 }
599 else {
600 Fmode &= ~FM_VOL;
601 }
602
603 return;
604 }
605
606 /*!
607 \brief Show list
608
609 \param flag
610 */
GK_show_list(int flag)611 void GK_show_list(int flag)
612 {
613 if (flag) {
614 Fmode |= FM_LABEL;
615
616 if (Views) {
617 GS_draw_all_list();
618 }
619 }
620 else {
621 Fmode &= ~FM_LABEL;
622 }
623
624 return;
625 }
626