GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
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} "
225 "{DirZ %f} {FOV %f} {TWIST %f} {cplane-0 {{pos_x 0.000000} "
226 "{pos_y 0.000000} {pos_z 0.000000} {blend_type OFF} {rot "
227 "0.000000} {tilt 0.000000}}}} keyanimtag%d 0} ",
228 k->pos, k->fields[KF_FROMX], k->fields[KF_FROMY],
229 k->fields[KF_FROMZ], k->fields[KF_DIRX], k->fields[KF_DIRY],
230 k->fields[KF_DIRZ], k->fields[KF_FOV] / 10.,
231 k->fields[KF_TWIST], cnt);
232 cnt++;
233 }
234
235 fclose(fp);
236 return;
237}
238
239/*!
240 \brief Recalculate path using the current number of frames requested.
241
242 Call after changing number of frames or when
243 Keyframes change.
244 */
246{
247 Keylist *k;
248 int loop = 0;
249
250 if (Keys) {
251 if (Numkeys > 1) {
252 k = Keytail;
253 Keyendpos = k->pos;
254
255 if (k->fields[KF_FROMX] == Keys->fields[KF_FROMX] &&
256 k->fields[KF_FROMY] == Keys->fields[KF_FROMY] &&
257 k->fields[KF_FROMZ] == Keys->fields[KF_FROMZ]) {
258 loop = 1;
259 }
260 }
261
262 Keystartpos = Keys->pos;
263 }
264
265 if (Interpmode == KF_LINEAR && Numkeys > 1) {
266 if (Views) {
267 free(Views);
268 Views = NULL;
269 }
270
271 Views = gk_make_linear_framesfromkeys(Keys, Numkeys, Viewsteps, loop);
272
273 if (!Views) {
274 G_warning(_("Check no. of frames requested and keyframes marked"));
275 }
276 }
277 else if (Numkeys > 2) {
278 if (Views) {
279 free(Views);
280 Views = NULL;
281 }
282
283 Views = gk_make_framesfromkeys(Keys, Numkeys, Viewsteps, loop,
284 1.0 - Tension);
285
286 if (!Views) {
287 G_warning(_("Check no. of frames requested and keyframes marked"));
288 }
289 }
290
291 return;
292}
293
294/*!
295 \brief Set the number of frames to be interpolated from keyframes
296
297 \param newsteps number of frames
298 */
299void GK_set_numsteps(int newsteps)
300{
301 Viewsteps = newsteps;
303
304 return;
305}
306
307/*!
308 \brief Deletes all keyframes, resets field masks.
309
310 Doesn't change number of frames requested.
311 */
313{
314 gk_free_key(Keys);
315 Keys = NULL;
316 Numkeys = 0;
317 free(Views);
318 Views = NULL;
319
320 Keystartpos = 0.0;
321 Keyendpos = 1.0;
322
323 return;
324}
325
326/*!
327 \brief Move keyframe
328
329 Precis works as in other functions - to identify keyframe to move.
330 Only the first keyframe in the precis range will be moved.
331
332 \param oldpos old position
333 \param precis precision value
334 \param newpos new position
335
336 \return number of keys moved (1 or 0)
337 */
338int GK_move_key(float oldpos, float precis, float newpos)
339{
340 Keylist *k;
341
342 for (k = Keys; k; k = k->next) {
343 if (k->pos >= oldpos - precis && k->pos <= oldpos + precis) {
344 _remove_key(k);
345 k->pos = newpos;
346 _add_key(k, 1, precis);
348 return (1);
349 }
350 }
351
352 return (0);
353}
354
355/*!
356 Delete keyframe
357
358 The values pos and precis are used to determine which keyframes to
359 delete. Any keyframes with their position within precis of pos will
360 be deleted if justone is zero. If justone is non-zero, only the first
361 (lowest pos) keyframe in the range will be deleted.
362
363 \param pos position
364 \param precis precision
365 \param justone delete only one keyframe
366
367 \return number of keys deleted.
368 */
369int GK_delete_key(float pos, float precis, int justone)
370{
371 Keylist *k, *next;
372 int cnt;
373
374 for (cnt = 0, k = Keys; k;) {
375 next = k->next;
376
377 if (k->pos >= pos - precis && k->pos <= pos + precis) {
378 cnt++;
379 _remove_key(k);
380 free(k);
381 if (justone) {
382 break;
383 }
384 }
385
386 k = next;
387 }
388
390 return (cnt);
391}
392
393/*!
394 \brief Add keyframe
395
396 The pos value is the relative position in the animation for this
397 particular keyframe - used to compare relative distance to neighboring
398 keyframes, it can be any floating point value.
399
400 The fmask value can be any of the following or'd together:
401 - KF_FROMX_MASK
402 - KF_FROMY_MASK
403 - KF_FROMZ_MASK
404 - KF_FROM_MASK (KF_FROMX_MASK | KF_FROMY_MASK | KF_FROMZ_MASK)
405
406 - KF_DIRX_MASK
407 - KF_DIRY_MASK
408 - KF_DIRZ_MASK
409 - KF_DIR_MASK (KF_DIRX_MASK | KF_DIRY_MASK | KF_DIRZ_MASK)
410
411 - KF_FOV_MASK
412 - KF_TWIST_MASK
413
414 - KF_ALL_MASK (KF_FROM_MASK | KF_DIR_MASK | KF_FOV_MASK | KF_TWIST_MASK)
415
416 Other fields will be added later.
417
418 The value precis and the boolean force_replace are used to determine
419 if a keyframe should be considered to be at the same position as a
420 pre-existing keyframe. e.g., if anykey.pos - newkey.pos &lt;= precis,
421 GK_add_key() will fail unless force_replace is TRUE.
422
423 \param pos position
424 \param fmaks
425 \param force_replace
426 \param precis precision value
427
428 \return 1 if key is added
429 \return -1 key not added
430 */
431int GK_add_key(float pos, unsigned long fmask, int force_replace, float precis)
432{
433 Keylist *newk;
434 float tmp[3];
435
436 if (NULL == (newk = (Keylist *)malloc(sizeof(Keylist)))) {
437 fprintf(stderr, "Out of memory\n");
438 return (-1);
439 }
440
441 /* All fields set, don't use mask until making Views */
442
443 GS_get_from(tmp);
444 newk->fields[KF_FROMX] = tmp[X];
445 newk->fields[KF_FROMY] = tmp[Y];
446 newk->fields[KF_FROMZ] = tmp[Z];
447
448 G_debug(3, "KEY FROM: %f %f %f", tmp[X], tmp[Y], tmp[Z]);
449
450 /* Instead of View Dir try get_focus (view center) */
451 /* View Dir is implied from eye and center position */
452 /* GS_get_viewdir(tmp); */
453
454 /* ACS 1 line: was GS_get_focus(tmp);
455 with this kanimator works also for flythrough navigation
456 also changed in gk.c
457 */
458 GS_get_viewdir(tmp);
459 newk->fields[KF_DIRX] = tmp[X];
460 newk->fields[KF_DIRY] = tmp[Y];
461 newk->fields[KF_DIRZ] = tmp[Z];
462
463 newk->fields[KF_FOV] = GS_get_fov();
464 newk->fields[KF_TWIST] = GS_get_twist();
465 newk->pos = pos;
466 newk->fieldmask = fmask;
467 newk->next = NULL;
468 newk->prior = NULL;
469
470 if (0 < _add_key(newk, force_replace, precis)) {
472 return (1);
473 }
474
475 return (-1);
476}
477
478/*!
479 \brief Moves the animation to frame number "step".
480
481 Step should be a value between 1 and the number of frames. If
482 render is non-zero, calls draw_all.
483
484 \param step step value
485 \param render
486 */
487void GK_do_framestep(int step, int render)
488{
489 if (Views) {
490 if (step > 0 && step <= Viewsteps) {
491 gk_follow_frames(Views, Viewsteps, Keys, step, 1, render, Fmode);
492 }
493 }
494
495 return;
496}
497
498/*!
499 \brief Draw the current path
500
501 \param flag
502 */
503void GK_show_path(int flag)
504{
505 if (flag) {
506 Fmode |= FM_PATH;
507
508 if (Views) {
509 GS_set_draw(GSD_FRONT);
511
512 gk_draw_path(Views, Viewsteps, Keys);
513
514 GS_done_draw();
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 else {
571 Fmode &= ~FM_SITE;
572 }
573
574 return;
575}
576
577/*!
578 \brief Show volumes
579
580 \param flag
581 */
582void GK_show_vol(int flag)
583{
584 if (flag) {
585 Fmode |= FM_VOL;
586
587 if (Views) {
588
589 GS_set_draw(GSD_FRONT);
591
593
594 GS_done_draw();
595 }
596 }
597 else {
598 Fmode &= ~FM_VOL;
599 }
600
601 return;
602}
603
604/*!
605 \brief Show list
606
607 \param flag
608 */
609void GK_show_list(int flag)
610{
611 if (flag) {
612 Fmode |= FM_LABEL;
613
614 if (Views) {
616 }
617 }
618 else {
619 Fmode &= ~FM_LABEL;
620 }
621
622 return;
623}
#define NULL
Definition ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition gis/error.c:159
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition gis/error.c:203
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:582
void GK_do_framestep(int step, int render)
Moves the animation to frame number "step".
Definition gk2.c:487
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:503
void GK_show_list(int flag)
Show list.
Definition gk2.c:609
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:369
void GK_set_numsteps(int newsteps)
Set the number of frames to be interpolated from keyframes.
Definition gk2.c:299
void GK_update_frames(void)
Recalculate path using the current number of frames requested.
Definition gk2.c:245
int GK_move_key(float oldpos, float precis, float newpos)
Move keyframe.
Definition gk2.c:338
int GK_add_key(float pos, unsigned long fmask, int force_replace, float precis)
Add keyframe.
Definition gk2.c:431
void GK_clear_keys(void)
Deletes all keyframes, resets field masks.
Definition gk2.c:312
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:749
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:611
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:611
int GS_get_twist(void)
Get twist value.
Definition gs2.c:2860
void GS_draw_all_list(void)
Draw all glLists.
Definition gs2.c:872
void GS_get_from(float *fr)
Get viewpoint 'from' position.
Definition gs2.c:2721
void GS_get_viewdir(float *dir)
Get viewdir.
Definition gs2.c:2804
void GS_alldraw_wire(void)
Draw all wires.
Definition gs2.c:1917
void GS_clear(int col)
Clear view.
Definition gs2.c:3414
int GS_get_fov(void)
Get field of view.
Definition gs2.c:2850
void GS_ready_draw(void)
Definition gs2.c:2485
unsigned int GS_background_color(void)
Get background color.
Definition gs2.c:2449
void GS_set_draw(int where)
Sets which buffer to draw to.
Definition gs2.c:2459
void GS_done_draw(void)
Draw done, swap buffers.
Definition gs2.c:2498
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:6
#define X(j)
#define Y(j)