~ubuntu-branches/ubuntu/intrepid/gpac/intrepid-proposed

« back to all changes in this revision

Viewing changes to src/scenegraph/smil_anim.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2007-01-24 23:34:57 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070124233457-zzlls8afkt0nyakj
Tags: 0.4.2~rc2-0ubuntu1
* New upstream release
  * Most notably MP4 tagging support via MP4Box -itags
* debian/patches/01_64bits.dpatch: dropped; included upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *                      GPAC - Multimedia Framework C SDK
 
3
 *
 
4
 *                      Authors: Cyril Concolato - Jean Le Feuvre
 
5
 *    Copyright (c)2004-200X ENST - All rights reserved
 
6
 *
 
7
 *  This file is part of GPAC / SVG Scene Graph sub-project
 
8
 *
 
9
 *  GPAC is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU Lesser General Public License as published by
 
11
 *  the Free Software Foundation; either version 2, or (at your option)
 
12
 *  any later version.
 
13
 *
 
14
 *  GPAC is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU Lesser General Public License for more details. 
 
18
 *
 
19
 *  You should have received a copy of the GNU Lesser General Public
 
20
 *  License along with this library; see the file COPYING.  If not, write to
 
21
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
22
 *
 
23
 */
 
24
 
 
25
#include <gpac/scenegraph_svg.h>
 
26
#include <gpac/internal/scenegraph_dev.h>
 
27
#include <gpac/nodes_svg.h>
 
28
 
 
29
static void gf_smil_anim_animate_using_values(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
 
30
{
 
31
        SMILAnimationAttributes *anim = rai->anim_elt->anim;
 
32
        GF_List *values = anim->values.values;
 
33
 
 
34
        GF_FieldInfo value_info, value_info_next;
 
35
        u32 keyValueIndex;
 
36
        u32 nbValues;
 
37
 
 
38
        Fixed interval_duration;
 
39
        Fixed interpolation_coefficient;
 
40
 
 
41
        memset(&value_info, 0, sizeof(GF_FieldInfo));
 
42
        value_info.fieldType = anim->values.type;
 
43
        value_info.eventType = anim->values.transform_type;
 
44
        value_info_next = value_info;
 
45
 
 
46
        nbValues = gf_list_count(values);
 
47
        if (nbValues == 1) {
 
48
                if (rai->previous_key_index != 0) {
 
49
                        value_info.far_ptr = gf_list_get(values, 0);
 
50
                        gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
51
                        gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
 
52
                        rai->previous_key_index = 0;
 
53
                        rai->target_value_changed = 1;
 
54
                }
 
55
                return;
 
56
        }
 
57
 
 
58
        if (gf_list_count(anim->keyTimes)) {
 
59
                u32 keyTimeIndex;
 
60
                Fixed keyTimeBefore = 0, keyTimeAfter=0; 
 
61
                u32 keyTimesCount = gf_list_count(anim->keyTimes);
 
62
                for (keyTimeIndex = rai->previous_keytime_index; keyTimeIndex<keyTimesCount; keyTimeIndex++) {
 
63
                        Fixed *tm1, *t = gf_list_get(anim->keyTimes, keyTimeIndex);
 
64
                        if (normalized_simple_time < *t) {
 
65
                                rai->previous_keytime_index = keyTimeIndex;
 
66
                                tm1 = (Fixed *) gf_list_get(anim->keyTimes, keyTimeIndex-1);
 
67
                                if (tm1) keyTimeBefore = *tm1; 
 
68
                                else keyTimeBefore = 0;
 
69
                                keyTimeAfter = *t;
 
70
                                break;
 
71
                        }
 
72
                }
 
73
                keyTimeIndex--;
 
74
                keyValueIndex = keyTimeIndex;
 
75
                interval_duration = keyTimeAfter - keyTimeBefore;
 
76
                if (interval_duration) interpolation_coefficient = gf_divfix(normalized_simple_time - keyTimeBefore, interval_duration);
 
77
                else interpolation_coefficient = 1;
 
78
//              fprintf(stdout, "Using Key Times: index %d, interval duration %.2f, coeff: %.2f\n", keyTimeIndex, interval_duration, interpolation_coefficient);
 
79
        } else {
 
80
                if (anim->calcMode == SMIL_CALCMODE_DISCRETE) {
 
81
                        Fixed tmp = normalized_simple_time*nbValues;
 
82
                        keyValueIndex = FIX2INT(gf_floor(tmp));
 
83
                        interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
 
84
                } else {
 
85
                        Fixed tmp = normalized_simple_time*(nbValues-1);
 
86
                        keyValueIndex = FIX2INT(gf_floor(tmp));
 
87
                        interpolation_coefficient = tmp - INT2FIX(keyValueIndex);
 
88
                }
 
89
                //fprintf(stdout, "No KeyTimes: key index %d, coeff: %.2f\n", keyValueIndex, FIX2FLT(interpolation_coefficient));
 
90
        }
 
91
 
 
92
        if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_animateMotion) {
 
93
                SVGanimateMotionElement *am = (SVGanimateMotionElement *)rai->anim_elt;
 
94
                if (gf_list_count(am->keyPoints)) {
 
95
                        interpolation_coefficient = *(Fixed *)gf_list_get(am->keyPoints, keyValueIndex);
 
96
                        keyValueIndex = 0;
 
97
//                      fprintf(stdout, "Using Key Points: key Value Index %d, coeff: %.2f\n", keyValueIndex, interpolation_coefficient);
 
98
                }
 
99
        }
 
100
 
 
101
        if (rai->previous_key_index == (s32)keyValueIndex &&
 
102
                rai->previous_coef == interpolation_coefficient) return;
 
103
 
 
104
        rai->previous_key_index = keyValueIndex;
 
105
        rai->previous_coef = interpolation_coefficient;
 
106
        rai->target_value_changed = 1;
 
107
 
 
108
        switch (anim->calcMode) {
 
109
        case SMIL_CALCMODE_DISCRETE:
 
110
                value_info.far_ptr = gf_list_get(values, keyValueIndex);
 
111
                gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
112
                gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
 
113
                break;
 
114
        case SMIL_CALCMODE_PACED:
 
115
                /* TODO: at the moment assume it is linear */
 
116
        case SMIL_CALCMODE_SPLINE:
 
117
                /* TODO: at the moment assume it is linear */
 
118
        case SMIL_CALCMODE_LINEAR:
 
119
                if (keyValueIndex == nbValues - 1) {
 
120
                        value_info.far_ptr = gf_list_get(values, nbValues - 1);
 
121
                        gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
122
                        gf_svg_attributes_copy(&rai->interpolated_value, &value_info, 0);
 
123
                } else {
 
124
                        value_info.far_ptr = gf_list_get(values, keyValueIndex);
 
125
                        gf_svg_attributes_pointer_update(&value_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
126
                        value_info_next.far_ptr = gf_list_get(values, keyValueIndex+1);
 
127
                        gf_svg_attributes_pointer_update(&value_info_next, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
128
                        gf_svg_attributes_interpolate(&value_info, &value_info_next, &rai->interpolated_value, interpolation_coefficient, 1);
 
129
                }
 
130
                break;
 
131
        }
 
132
}
 
133
 
 
134
static void gf_smil_anim_set(SMIL_Anim_RTI *rai)
 
135
{
 
136
        GF_FieldInfo to_info;
 
137
        if (!rai->anim_elt->anim->to.type) return;
 
138
        to_info.fieldType = rai->anim_elt->anim->to.type;
 
139
        to_info.eventType = rai->anim_elt->anim->to.transform_type;
 
140
        to_info.far_ptr   = rai->anim_elt->anim->to.value;
 
141
        gf_svg_attributes_pointer_update(&to_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
142
 
 
143
        gf_svg_attributes_copy(&rai->interpolated_value, &to_info, 0);
 
144
        rai->target_value_changed = 1;
 
145
}
 
146
 
 
147
static void gf_smil_anim_animate_from_to(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
 
148
{
 
149
        SMILAnimationAttributes *anim = rai->anim_elt->anim;
 
150
 
 
151
        GF_FieldInfo from_info, to_info;
 
152
        
 
153
        if (rai->previous_coef == normalized_simple_time) return;
 
154
 
 
155
        rai->previous_coef = normalized_simple_time;
 
156
 
 
157
        from_info.fieldType = anim->from.type;
 
158
        from_info.eventType = anim->from.transform_type;
 
159
        from_info.far_ptr = anim->from.value;
 
160
        gf_svg_attributes_pointer_update(&from_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
161
 
 
162
        to_info.fieldType = anim->to.type;
 
163
        to_info.eventType = anim->to.transform_type;
 
164
        to_info.far_ptr = anim->to.value;
 
165
        gf_svg_attributes_pointer_update(&to_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
166
 
 
167
        switch (anim->calcMode) {
 
168
        case SMIL_CALCMODE_DISCRETE:
 
169
                {
 
170
                        /* before half of the duration stay at 'from' and then switch to 'to' */
 
171
                        s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
 
172
                        if (useFrom == rai->previous_key_index) return;
 
173
                        gf_svg_attributes_copy(&rai->interpolated_value, (useFrom?&from_info:&to_info), 0);
 
174
                        rai->previous_key_index = useFrom;
 
175
                }
 
176
                break;
 
177
        case SMIL_CALCMODE_SPLINE:
 
178
        case SMIL_CALCMODE_PACED:
 
179
        case SMIL_CALCMODE_LINEAR:
 
180
        default:
 
181
                gf_svg_attributes_interpolate(&from_info, &to_info, &rai->interpolated_value, normalized_simple_time, 1);
 
182
                break;
 
183
        }
 
184
        rai->target_value_changed = 1;
 
185
}
 
186
 
 
187
static void gf_smil_anim_animate_from_by(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
 
188
{
 
189
        SMILAnimationAttributes *anim = rai->anim_elt->anim;
 
190
        GF_FieldInfo from_info, by_info;
 
191
        
 
192
        if (rai->previous_coef == normalized_simple_time) return;
 
193
 
 
194
        rai->previous_coef = normalized_simple_time;
 
195
 
 
196
        from_info.fieldType = anim->from.type;
 
197
        from_info.eventType = anim->from.transform_type;
 
198
        from_info.far_ptr = anim->from.value;
 
199
        gf_svg_attributes_pointer_update(&from_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
200
 
 
201
        by_info.fieldType = anim->by.type;
 
202
        by_info.eventType = anim->by.transform_type;
 
203
        by_info.far_ptr = anim->by.value;
 
204
        gf_svg_attributes_pointer_update(&by_info, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
205
 
 
206
        switch (anim->calcMode) {
 
207
        case SMIL_CALCMODE_DISCRETE:
 
208
                {
 
209
                        /* before half of the duration stay at 'from' and then switch to 'to' */
 
210
                        s32 useFrom = (normalized_simple_time<=FIX_ONE/2);
 
211
                        if (useFrom == rai->previous_key_index) return;
 
212
                        if (useFrom) {
 
213
                                gf_svg_attributes_copy(&rai->interpolated_value, &from_info, 0);
 
214
                        } else {
 
215
                                gf_svg_attributes_muladd(FIX_ONE, &from_info, FIX_ONE, &by_info, &rai->interpolated_value, 0);
 
216
                        }
 
217
                        rai->previous_key_index = useFrom;
 
218
                }
 
219
                break;
 
220
        case SMIL_CALCMODE_SPLINE:
 
221
        case SMIL_CALCMODE_PACED:
 
222
        case SMIL_CALCMODE_LINEAR:
 
223
        default:
 
224
                gf_svg_attributes_muladd(FIX_ONE, &from_info, normalized_simple_time, &by_info, &rai->interpolated_value, 0);
 
225
                break;
 
226
        }
 
227
        rai->target_value_changed = 1;
 
228
}
 
229
 
 
230
static Bool gf_svg_compute_path_anim(SMIL_Anim_RTI *rai, GF_Matrix2D *m, Fixed normalized_simple_time) 
 
231
{
 
232
        Bool res = 0;
 
233
        Fixed offset;
 
234
        offset = gf_mulfix(normalized_simple_time, rai->length);
 
235
        gf_mx2d_init(*m);
 
236
        res = gf_path_iterator_get_transform(rai->path_iterator, offset, 1, m, 1, 0);
 
237
//      fprintf(stdout, "Time: %f - Offset: %f, Position: %f, %f\n", normalized_simple_time, offset, ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[2], ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[5]);
 
238
        switch (rai->rotate) {
 
239
        case SVG_NUMBER_AUTO:
 
240
                break;
 
241
        case SVG_NUMBER_AUTO_REVERSE:
 
242
                gf_mx2d_add_rotation(m, m->m[2], m->m[5], GF_PI);
 
243
                break;
 
244
        default:
 
245
                ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[0] = 1;
 
246
                ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[1] = 0;
 
247
                ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[3] = 0;
 
248
                ((GF_Matrix2D *)rai->interpolated_value.far_ptr)->m[4] = 1;
 
249
        }
 
250
        return res;
 
251
}
 
252
 
 
253
static void gf_smil_anim_animate_using_path(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
 
254
{
 
255
        Bool res = 0;
 
256
        gf_svg_compute_path_anim(rai, rai->interpolated_value.far_ptr, normalized_simple_time);
 
257
        if (res) rai->target_value_changed = 1;
 
258
}
 
259
 
 
260
static void gf_smil_anim_discard(SMIL_Timing_RTI *rti, Fixed normalized_scene_time)
 
261
{
 
262
        GF_Node *targetNode = (GF_Node *)rti->timed_elt->xlink->href.target;
 
263
        if (!targetNode) return;
 
264
        /* deletes the node and replace all references to that node to NULL */
 
265
        gf_node_replace(targetNode, NULL, 0);
 
266
        /* sets the node to NULL in case of future calls to discard */
 
267
        rti->timed_elt->xlink->href.target = NULL;
 
268
        /* TODO: The animation (discard) does not need to run again */
 
269
        /* TODO: Invalidate the scene ?*/
 
270
}
 
271
 
 
272
static void gf_smil_anim_get_last_specified_value(SMIL_Anim_RTI *rai)
 
273
{
 
274
        SVGElement *e = rai->anim_elt;
 
275
 
 
276
        if (rai->path) {
 
277
                /*TODO CHECK WITH CYRIL !! */
 
278
//              if (!rai->last_specified_value.far_ptr) rai->last_specified_value.far_ptr = malloc(sizeof(GF_Matrix2D));
 
279
//              gf_svg_compute_path_anim(rai, rai->last_specified_value.far_ptr, FIX_ONE);
 
280
        } else if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_set) {          
 
281
                rai->last_specified_value.fieldType = e->anim->to.type;
 
282
                rai->last_specified_value.eventType = e->anim->to.transform_type;
 
283
                rai->last_specified_value.far_ptr   = e->anim->to.value;
 
284
                return;
 
285
        }
 
286
 
 
287
        if (gf_list_count(e->anim->values.values)) {
 
288
                /* Ignore from/to/by*/
 
289
                rai->last_specified_value.fieldType = e->anim->values.type;
 
290
                rai->last_specified_value.eventType = e->anim->values.transform_type;
 
291
                rai->last_specified_value.far_ptr = gf_list_last(e->anim->values.values);
 
292
        } else if (e->anim->by.type && (e->anim->to.type == 0)) {
 
293
                rai->last_specified_value.fieldType = e->anim->by.type;
 
294
                rai->last_specified_value.eventType = e->anim->by.transform_type;
 
295
                rai->last_specified_value.far_ptr   = e->anim->by.value;
 
296
        } else { 
 
297
                rai->last_specified_value.fieldType = e->anim->to.type;
 
298
                rai->last_specified_value.eventType = e->anim->to.transform_type;
 
299
                rai->last_specified_value.far_ptr   = e->anim->to.value;
 
300
        }
 
301
        if (gf_svg_is_inherit(&rai->last_specified_value)) {
 
302
                rai->last_specified_value.fieldType = rai->owner->presentation_value.fieldType;
 
303
                rai->last_specified_value.eventType = rai->owner->presentation_value.eventType;
 
304
                rai->last_specified_value.far_ptr = rai->owner->presentation_value.far_ptr;
 
305
        }
 
306
        gf_svg_attributes_pointer_update(&rai->last_specified_value, &rai->owner->presentation_value, &rai->owner->current_color_value);
 
307
}
 
308
 
 
309
#if 0
 
310
/* TODO: fix this ... */
 
311
static void gf_smil_anim_get_last_nb_iterations(SMIL_Anim_RTI *rai, u32 *nb_iterations)
 
312
{
 
313
        if (rai->anim_elt->timing->repeatCount.type) {
 
314
                *nb_iterations = (u32)rai->anim_elt->timing->repeatCount.count;
 
315
        } else {
 
316
                *nb_iterations = (u32)rai->anim_elt->timing->repeatDur.clock_value;
 
317
        }
 
318
}
 
319
#endif
 
320
 
 
321
static void gf_smil_anim_apply_accumulate(SMIL_Anim_RTI *rai)
 
322
{
 
323
        u32 nb_iterations = rai->anim_elt->timing->runtime->current_interval->nb_iterations;
 
324
        if (rai->anim_elt->anim->accumulate == SMIL_ACCUMULATE_SUM && nb_iterations > 0) {
 
325
                gf_svg_attributes_muladd(INT2FIX(nb_iterations), &rai->last_specified_value, FIX_ONE, &rai->interpolated_value, &rai->interpolated_value, 1);
 
326
        } 
 
327
}
 
328
 
 
329
static SMIL_Anim_RTI *gf_smil_anim_get_anim_runtime_from_timing(SMIL_Timing_RTI *rti)
 
330
{
 
331
        SVGElement *e = rti->timed_elt;
 
332
        u32 i, j;
 
333
        if (!e->xlink->href.target) return NULL;
 
334
        for (i = 0; i < gf_node_animation_count((GF_Node *)e->xlink->href.target); i++) {
 
335
                SMIL_Anim_RTI *rai_tmp;
 
336
                SMIL_AttributeAnimations *aa = gf_node_animation_get((GF_Node *)e->xlink->href.target, i);
 
337
                j=0;
 
338
                while ((rai_tmp = gf_list_enum(aa->anims, &j))) {
 
339
                        if (rai_tmp->anim_elt->timing->runtime == rti) {                                                
 
340
                                return rai_tmp;
 
341
                        }
 
342
                }
 
343
        }
 
344
        return NULL;
 
345
}
 
346
 
 
347
/* Compute the Animation Value (AV), possibly based on the Underlying Value (read-only) in the case 
 
348
of from-less/to-less/inherit values animations */
 
349
static void gf_smil_anim_compute_interpolation_value(SMIL_Anim_RTI *rai, Fixed normalized_simple_time)
 
350
{
 
351
        SVGElement *e = rai->anim_elt;
 
352
 
 
353
        if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_discard) {
 
354
                /* TODO */
 
355
                return;
 
356
        } else if (rai->path) {
 
357
                gf_smil_anim_animate_using_path(rai, normalized_simple_time);
 
358
                return;
 
359
        } else if (gf_node_get_tag((GF_Node *)rai->anim_elt) == TAG_SVG_set) {          
 
360
                gf_smil_anim_set(rai);
 
361
                return;
 
362
        }
 
363
 
 
364
        if (gf_list_count(e->anim->values.values)) {
 
365
                /* Ignore from/to/by*/
 
366
                gf_smil_anim_animate_using_values(rai, normalized_simple_time);
 
367
        } else if (e->anim->by.type && (e->anim->to.type == 0)) {
 
368
                /* no to but a by, this is a by or a from-by animation */
 
369
                gf_smil_anim_animate_from_by(rai, normalized_simple_time);
 
370
        } else { 
 
371
                gf_smil_anim_animate_from_to(rai, normalized_simple_time);
 
372
        }
 
373
}
 
374
 
 
375
static void gf_smil_anim_animate(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
 
376
{
 
377
        SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
 
378
 
 
379
        if (!rai) return;
 
380
 
 
381
//      fprintf(stdout, "Animation: %x @ time : %f\n", rti, normalized_simple_time);
 
382
 
 
383
        rai->target_value_changed = 0;
 
384
        gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
 
385
        if (rai->target_value_changed) gf_smil_anim_apply_accumulate(rai);
 
386
        /* Apply additive behavior if required
 
387
                PV = (additive == sum ? PV + anim->IV : anim->IV); */
 
388
        if (rai->anim_elt->anim->additive == SMIL_ADDITIVE_SUM) {
 
389
                gf_svg_attributes_add(&rai->owner->presentation_value, &rai->interpolated_value, &rai->owner->presentation_value, 1);
 
390
        } else {
 
391
                gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->interpolated_value, 1);
 
392
        }
 
393
}
 
394
 
 
395
static void gf_smil_anim_freeze(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
 
396
{
 
397
        SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
 
398
        if (!rai) return;
 
399
 
 
400
//      fprintf(stdout, "Freeze: %x @ time : %f\n", rti, normalized_simple_time);
 
401
 
 
402
        /* we do the accumulation only once and store the result in interpolated value */
 
403
        if (rti->cycle_number == rti->first_frozen) {
 
404
                rai->target_value_changed = 0;
 
405
                gf_smil_anim_compute_interpolation_value(rai, normalized_simple_time);
 
406
                if (rai->target_value_changed) gf_smil_anim_apply_accumulate(rai);
 
407
        } 
 
408
        if (rai->anim_elt->anim->additive == SMIL_ADDITIVE_SUM) {
 
409
                gf_svg_attributes_add(&rai->owner->presentation_value, &rai->interpolated_value, &rai->owner->presentation_value, 1);
 
410
        } else {
 
411
                gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->interpolated_value, 1);
 
412
        }
 
413
}
 
414
 
 
415
static void gf_smil_anim_restore(SMIL_Timing_RTI *rti, Fixed normalized_simple_time)
 
416
{
 
417
        SMIL_Anim_RTI *rai = gf_smil_anim_get_anim_runtime_from_timing(rti);
 
418
        if (!rai) return;
 
419
 
 
420
//      fprintf(stdout, "Restore: %x @ time : %f\n", rti, normalized_simple_time);
 
421
 
 
422
        gf_svg_attributes_copy(&rai->owner->presentation_value, &rai->owner->saved_specified_value, 0);
 
423
        //gf_list_del_item(rai->owner->anims, rai);
 
424
}
 
425
 
 
426
void gf_smil_anim_init_runtime_info(SVGElement *e)
 
427
{
 
428
        u32 i;
 
429
        GF_FieldInfo target_attribute;
 
430
        SMIL_AttributeAnimations *aa = NULL;
 
431
        SMIL_Anim_RTI *rai;
 
432
 
 
433
        if (e->anim->attributeName.name) {
 
434
                gf_node_get_field_by_name((GF_Node *)e->xlink->href.target, e->anim->attributeName.name, &target_attribute);
 
435
        } else {
 
436
                /* if attributeName is not specified it is a transform attribute */
 
437
                gf_node_get_field_by_name((GF_Node *)e->xlink->href.target, "transform", &target_attribute);
 
438
        }
 
439
 
 
440
        GF_SAFEALLOC(rai, sizeof(SMIL_Anim_RTI))
 
441
        rai->anim_elt = e;      
 
442
        rai->interpolated_value = target_attribute;
 
443
        rai->interpolated_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType, 0);
 
444
        rai->previous_key_index = -1;
 
445
        rai->previous_coef = -1;
 
446
 
 
447
        if (gf_node_get_tag((GF_Node *)e) == TAG_SVG_animateMotion) {
 
448
                SVGanimateMotionElement *am = (SVGanimateMotionElement *)e;
 
449
                rai->rotate = am->rotate.type;
 
450
                if (e->anim->to.type == 0 && e->anim->by.type == 0 && e->anim->values.type == 0) {
 
451
                        rai->path = gf_path_new();
 
452
                        if (gf_list_count(am->path.points)) {
 
453
                                gf_svg_path_build(rai->path, am->path.commands, am->path.points);
 
454
                                rai->path_iterator = gf_path_iterator_new(rai->path);
 
455
                                rai->length = gf_path_iterator_get_length(rai->path_iterator);
 
456
                        } else {
 
457
                                u32 count;
 
458
                                count = gf_list_count(((SVGElement *)e)->children);
 
459
                                for (i = 0; i < count; i++) {
 
460
                                        GF_Node *child = gf_list_get(((SVGElement *)e)->children, i);
 
461
                                        if (gf_node_get_tag((GF_Node *)child) == TAG_SVG_mpath) {
 
462
                                                SVGmpathElement *mpath = (SVGmpathElement *)child;
 
463
                                                GF_Node *used_path = NULL;
 
464
                                                if (mpath->xlink && mpath->xlink->href.target) used_path = (GF_Node *)mpath->xlink->href.target;
 
465
                                                else if (mpath->xlink->href.iri) used_path= gf_sg_find_node_by_name(gf_node_get_graph((GF_Node *)mpath), mpath->xlink->href.iri);
 
466
                                                if (used_path && gf_node_get_tag(used_path) == TAG_SVG_path) {
 
467
                                                        SVGpathElement *used_path_elt = (SVGpathElement *)used_path;
 
468
                                                        gf_svg_path_build(rai->path, used_path_elt->d.commands, used_path_elt->d.points);
 
469
                                                        rai->path_iterator = gf_path_iterator_new(rai->path);
 
470
                                                        rai->length = gf_path_iterator_get_length(rai->path_iterator);
 
471
                                                }
 
472
                                                break;
 
473
                                        }
 
474
                                }
 
475
                        }
 
476
                }
 
477
        }
 
478
 
 
479
        /* for all animations, check if there is already one animation on this attribute,
 
480
           if yes, get the list and append the new animation
 
481
           if no, create a list and add the new animation. */
 
482
        for (i = 0; i < gf_node_animation_count((GF_Node *)e->xlink->href.target); i++) {
 
483
                aa = gf_node_animation_get((GF_Node *)e->xlink->href.target, i);
 
484
                if (aa->presentation_value.fieldIndex == target_attribute.fieldIndex) {
 
485
                        gf_list_add(aa->anims, rai);
 
486
                        break;
 
487
                }
 
488
                aa = NULL;
 
489
        }
 
490
        if (!aa) {
 
491
                GF_SAFEALLOC(aa, sizeof(SMIL_AttributeAnimations))
 
492
 
 
493
                /* Save the DOM value before any animation starts */
 
494
                aa->saved_specified_value = target_attribute;
 
495
                aa->orig_dom_ptr = target_attribute.far_ptr;
 
496
                aa->saved_specified_value.far_ptr = gf_svg_create_attribute_value(target_attribute.fieldType, 0);
 
497
                gf_svg_attributes_copy(&aa->saved_specified_value, &target_attribute, 0);
 
498
 
 
499
                /* Stores the pointer to the presentation value */
 
500
                aa->presentation_value = target_attribute;
 
501
 
 
502
                aa->anims = gf_list_new();
 
503
                gf_list_add(aa->anims, rai);
 
504
                gf_node_animation_add((GF_Node *)e->xlink->href.target, aa);
 
505
        }
 
506
        rai->owner = aa;
 
507
 
 
508
        e->timing->runtime->activation = gf_smil_anim_animate;
 
509
        e->timing->runtime->freeze = gf_smil_anim_freeze;
 
510
        e->timing->runtime->restore = gf_smil_anim_restore;
 
511
        gf_smil_anim_get_last_specified_value(rai);
 
512
}
 
513
 
 
514
void gf_smil_anim_delete_runtime_info(SMIL_Anim_RTI *rai)
 
515
{
 
516
        gf_svg_delete_attribute_value(rai->interpolated_value.fieldType, rai->interpolated_value.far_ptr, rai->anim_elt->sgprivate->scenegraph);
 
517
        if (rai->path) gf_path_del(rai->path);
 
518
        if (rai->path_iterator) gf_path_iterator_del(rai->path_iterator);
 
519
        free(rai);
 
520
}
 
521
 
 
522
void gf_smil_anim_delete_animations(SVGElement *e)
 
523
{
 
524
        u32 i, j;
 
525
        for (i = 0; i < gf_node_animation_count((GF_Node *)e); i ++) {
 
526
                SMIL_Anim_RTI *rai;
 
527
                SMIL_AttributeAnimations *aa = gf_node_animation_get((GF_Node *)e, i);
 
528
                gf_svg_delete_attribute_value(aa->saved_specified_value.fieldType, aa->saved_specified_value.far_ptr, e->sgprivate->scenegraph);
 
529
                j=0;
 
530
                while ((rai = gf_list_enum(aa->anims, &j))) {
 
531
                        gf_smil_anim_delete_runtime_info(rai);
 
532
                }
 
533
                gf_list_del(aa->anims);
 
534
                free(aa);
 
535
        }
 
536
        gf_node_animation_del((GF_Node *)e);
 
537
}
 
538
 
 
539
void gf_smil_anim_init_node(GF_Node *node)
 
540
{
 
541
        SVGElement *anim_elt = (SVGElement *)node;
 
542
        
 
543
        if (!anim_elt->xlink) return;
 
544
        if (anim_elt->xlink->href.type == SVG_IRI_IRI) {
 
545
                if (!anim_elt->xlink->href.iri) { 
 
546
                        fprintf(stderr, "Error: IRI not initialized\n");
 
547
                        return;
 
548
                } else {
 
549
                        GF_Node *n;
 
550
                        
 
551
                        n = gf_sg_find_node_by_name(gf_node_get_graph(node), anim_elt->xlink->href.iri);
 
552
                        if (n) {
 
553
                                anim_elt->xlink->href.type = SVG_IRI_ELEMENTID;
 
554
                                anim_elt->xlink->href.target = (SVGElement *)n;
 
555
                                gf_svg_register_iri(node->sgprivate->scenegraph, &anim_elt->xlink->href);
 
556
                        } else {
 
557
                                return;
 
558
                        }
 
559
                }
 
560
        } 
 
561
 
 
562
        if (!anim_elt->xlink->href.target) return;
 
563
 
 
564
        gf_smil_timing_init_runtime_info(anim_elt);
 
565
        if (anim_elt->anim) gf_smil_anim_init_runtime_info(anim_elt);
 
566
        /*THIS IS A DISCARD OR THIS CRASHES.*/
 
567
        else {
 
568
                anim_elt->timing->runtime->activation = gf_smil_anim_discard;
 
569
        }
 
570
 
 
571
}
 
572
 
 
573
/* TODO: update for elliptical arcs */          
 
574
void gf_svg_path_build(GF_Path *path, GF_List *commands, GF_List *points)
 
575
{
 
576
        u32 i, j, command_count, points_count;
 
577
        SVG_Point orig, ct_orig, ct_end, end, *tmp;
 
578
        command_count = gf_list_count(commands);
 
579
        points_count = gf_list_count(points);
 
580
        orig.x = orig.y = ct_orig.x = ct_orig.y = 0;
 
581
 
 
582
        for (i=0, j=0; i<command_count; i++) {
 
583
                u8 *command = gf_list_get(commands, i);
 
584
                switch (*command) {
 
585
                case SVG_PATHCOMMAND_M: /* Move To */
 
586
                        tmp = gf_list_get(points, j);
 
587
                        orig = *tmp;
 
588
                        gf_path_add_move_to(path, orig.x, orig.y);
 
589
                        j++;
 
590
                        /*provision for nextCurveTo when no curve is specified:
 
591
                                "If there is no previous command or if the previous command was not an C, c, S or s, 
 
592
                                assume the first control point is coincident with the current point.
 
593
                        */
 
594
                        ct_orig = orig;
 
595
                        break;
 
596
                case SVG_PATHCOMMAND_L: /* Line To */
 
597
                        tmp = gf_list_get(points, j);
 
598
                        end = *tmp;
 
599
 
 
600
                        gf_path_add_line_to(path, end.x, end.y);
 
601
                        j++;
 
602
                        orig = end;
 
603
                        /*cf above*/
 
604
                        ct_orig = orig;
 
605
                        break;
 
606
                case SVG_PATHCOMMAND_C: /* Curve To */
 
607
                        tmp = gf_list_get(points, j);
 
608
                        ct_orig = *tmp;
 
609
                        tmp = gf_list_get(points, j+1);
 
610
                        ct_end = *tmp;
 
611
                        tmp = gf_list_get(points, j+2);
 
612
                        end = *tmp;
 
613
                        gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
 
614
                        ct_orig = ct_end;
 
615
                        orig = end;
 
616
                        j+=3;
 
617
                        break;
 
618
                case SVG_PATHCOMMAND_S: /* Next Curve To */
 
619
                        ct_orig.x = 2*orig.x - ct_orig.x;
 
620
                        ct_orig.y = 2*orig.y - ct_orig.y;
 
621
                        tmp = gf_list_get(points, j);
 
622
                        ct_end = *tmp;
 
623
                        tmp = gf_list_get(points, j+1);
 
624
                        end = *tmp;
 
625
                        gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
 
626
                        ct_orig = ct_end;
 
627
                        orig = end;
 
628
                        j+=2;
 
629
                        break;
 
630
                case SVG_PATHCOMMAND_Q: /* Quadratic Curve To */
 
631
                        tmp = gf_list_get(points, j);
 
632
                        ct_orig = *tmp;
 
633
                        tmp = gf_list_get(points, j+1);
 
634
                        end = *tmp;
 
635
                        gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);                     
 
636
                        orig = end;
 
637
                        j+=2;
 
638
                        break;
 
639
                case SVG_PATHCOMMAND_T: /* Next Quadratic Curve To */
 
640
                        ct_orig.x = 2*orig.x - ct_orig.x;
 
641
                        ct_orig.y = 2*orig.y - ct_orig.y;
 
642
                        tmp = gf_list_get(points, j);
 
643
                        end = *tmp;
 
644
                        gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
 
645
                        orig = end;
 
646
                        j++;
 
647
                        break;
 
648
                case SVG_PATHCOMMAND_Z: /* Close */
 
649
                        gf_path_close(path);
 
650
                        break;
 
651
                }
 
652
        }       
 
653
}
 
654