GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
gk2.c
Go to the documentation of this file.
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
25static int _add_key(Keylist *, int, float);
26static void _remove_key(Keylist *);
27
28static Keylist *Keys = NULL;
29static Keylist *Keytail = NULL;
30static Viewnode *Views = NULL;
31static float Keystartpos = 0.0;
32static float Keyendpos = 1.0;
33static float Tension = 0.8;
34static int Viewsteps = 0;
35static int Numkeys = 0;
36static int Interpmode = KF_SPLINE;
37static int Fmode = 0;
38
39/* next & prior already initialized to NULL */
40static 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
110static 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 */
140int 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 */
155void 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) {
162 GS_set_draw(GSD_BACK);
166
167 gk_draw_path(Views, Viewsteps, Keys);
168
169 GS_done_draw();
170 }
171
172 return;
173}
174
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 */
188{
189 return;
190}
191
192/*!
193 \brief Update tension
194 */
196{
197 if (Views) {
199 }
200
201 return;
202}
203
204/*!
205 \brief Print keyframe info
206
207 \param name filename
208 */
209void 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 */
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
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 */
297void GK_set_numsteps(int newsteps)
298{
299 Viewsteps = newsteps;
301
302 return;
303}
304
305/*!
306 \brief Deletes all keyframes, resets field masks.
307
308 Doesn't change number of frames requested.
309 */
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 */
336int 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);
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 */
367int 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
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 */
429int 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)) {
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 */
486void 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 */
502void GK_show_path(int flag)
503{
504 if (flag) {
505 Fmode |= FM_PATH;
506
507 if (Views) {
508 GS_set_draw(GSD_FRONT);
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 */
529void GK_show_vect(int flag)
530{
531 if (flag) {
532 Fmode |= FM_VECT;
533 if (Views) {
534
535 GS_set_draw(GSD_FRONT);
537
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 */
555void GK_show_site(int flag)
556{
557 if (flag) {
558 Fmode |= FM_SITE;
559
560 if (Views) {
561
562 GS_set_draw(GSD_FRONT);
564
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 */
583void GK_show_vol(int flag)
584{
585 if (flag) {
586 Fmode |= FM_VOL;
587
588 if (Views) {
589
590 GS_set_draw(GSD_FRONT);
592
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 */
611void GK_show_list(int flag)
612{
613 if (flag) {
614 Fmode |= FM_LABEL;
615
616 if (Views) {
618 }
619 }
620 else {
621 Fmode &= ~FM_LABEL;
622 }
623
624 return;
625}
#define NULL
Definition: ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
void GK_set_tension(float tens)
Set value for tension when interpmode is KF_SPLINE.
Definition: gk2.c:155
int GK_set_interpmode(int mode)
Set interpolation mode.
Definition: gk2.c:140
void GK_show_vol(int flag)
Show volumes.
Definition: gk2.c:583
void GK_do_framestep(int step, int render)
Moves the animation to frame number "step".
Definition: gk2.c:486
void GK_show_vect(int flag)
Show vector sets.
Definition: gk2.c:529
void GK_update_tension(void)
Update tension.
Definition: gk2.c:195
void GK_showtension_stop(void)
Show tension stop ?
Definition: gk2.c:187
void GK_showtension_start(void)
Definition: gk2.c:175
void GK_show_path(int flag)
Draw the current path.
Definition: gk2.c:502
void GK_show_list(int flag)
Show list.
Definition: gk2.c:611
void GK_print_keys(const char *name)
Print keyframe info.
Definition: gk2.c:209
void GK_show_site(int flag)
Show point sets.
Definition: gk2.c:555
int GK_delete_key(float pos, float precis, int justone)
Definition: gk2.c:367
void GK_set_numsteps(int newsteps)
Set the number of frames to be interpolated from keyframes.
Definition: gk2.c:297
void GK_update_frames(void)
Recalculate path using the current number of frames requested.
Definition: gk2.c:243
int GK_move_key(float oldpos, float precis, float newpos)
Move keyframe.
Definition: gk2.c:336
int GK_add_key(float pos, unsigned long fmask, int force_replace, float precis)
Add keyframe.
Definition: gk2.c:429
void GK_clear_keys(void)
Deletes all keyframes, resets field masks.
Definition: gk2.c:310
void gk_free_key(Keylist *ok)
Free keyframe list.
Definition: gk.c:271
int gk_draw_path(Viewnode *views, int steps, Keylist *keys)
Draw path.
Definition: gk.c:738
Viewnode * gk_make_framesfromkeys(Keylist *keys, int keysteps, int newsteps, int loop, float t)
Generate viewnode from keyframes.
Definition: gk.c:301
Viewnode * gk_make_linear_framesfromkeys(Keylist *keys, int keysteps, int newsteps, int loop)
Generate viewnode from keyframe list (linear interpolation)
Definition: gk.c:604
void gk_follow_frames(Viewnode *view, int numsteps, Keylist *keys, int step, int onestep, int render, unsigned long mode)
Checks key masks.
Definition: gk.c:141
void GP_alldraw_site(void)
Draw all available point sets.
Definition: gp2.c:607
int GS_get_twist(void)
Get twist value.
Definition: gs2.c:2865
void GS_draw_all_list(void)
Draw all glLists.
Definition: gs2.c:879
void GS_get_from(float *fr)
Get viewpoint 'from' position.
Definition: gs2.c:2725
void GS_get_viewdir(float *dir)
Get viewdir.
Definition: gs2.c:2809
void GS_alldraw_wire(void)
Draw all wires.
Definition: gs2.c:1919
void GS_clear(int col)
Clear view.
Definition: gs2.c:3418
int GS_get_fov(void)
Get fied of view.
Definition: gs2.c:2855
void GS_ready_draw(void)
Definition: gs2.c:2488
unsigned int GS_background_color(void)
Get background color.
Definition: gs2.c:2452
void GS_set_draw(int where)
Sets which buffer to draw to.
Definition: gs2.c:2462
void GS_done_draw(void)
Draw done, swap buffers.
Definition: gs2.c:2501
void GV_alldraw_vect(void)
Draw all loaded vector sets.
Definition: gv2.c:506
void GVL_alldraw_vol(void)
Draw all volume sets.
Definition: gvl2.c:441
const char * name
Definition: named_colr.c:7
#define X(j)
#define Y(j)