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 &lt;= 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