Cleanup: manually remove header text not handled by automation
[blender.git] / source / blender / collada / BCAnimationCurve.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include "BCAnimationCurve.h"
21
22 BCAnimationCurve::BCAnimationCurve()
23 {
24         this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT);
25         this->fcurve = NULL;
26         this->curve_is_local_copy = false;
27 }
28
29 BCAnimationCurve::BCAnimationCurve(const BCAnimationCurve &other)
30 {
31         this->min = other.min;
32         this->max = other.max;
33         this->fcurve = other.fcurve;
34         this->curve_key = other.curve_key;
35         this->curve_is_local_copy = false;
36         this->id_ptr = other.id_ptr;
37
38         /* The fcurve of the new instance is a copy and can be modified */
39
40         get_edit_fcurve();
41 }
42
43 BCAnimationCurve::BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu)
44 {
45         this->min = 0;
46         this->max = 0;
47         this->curve_key = key;
48         this->fcurve = fcu;
49         this->curve_is_local_copy = false;
50         init_pointer_rna(ob);
51 }
52
53 BCAnimationCurve::BCAnimationCurve(const BCCurveKey &key, Object *ob)
54 {
55         this->curve_key = key;
56         this->fcurve = NULL;
57         this->curve_is_local_copy = false;
58         init_pointer_rna(ob);
59 }
60
61 void BCAnimationCurve::init_pointer_rna(Object *ob)
62 {
63         switch (this->curve_key.get_animation_type()) {
64         case BC_ANIMATION_TYPE_BONE:
65         {
66                 bArmature *arm = (bArmature *)ob->data;
67                 RNA_id_pointer_create(&arm->id, &id_ptr);
68         }
69         break;
70         case BC_ANIMATION_TYPE_OBJECT:
71         {
72                 RNA_id_pointer_create(&ob->id, &id_ptr);
73         }
74         break;
75         case BC_ANIMATION_TYPE_MATERIAL:
76         {
77                 Material *ma = give_current_material(ob, curve_key.get_subindex() + 1);
78                 RNA_id_pointer_create(&ma->id, &id_ptr);
79         }
80         break;
81         case BC_ANIMATION_TYPE_CAMERA:
82         {
83                 Camera *camera = (Camera *)ob->data;
84                 RNA_id_pointer_create(&camera->id, &id_ptr);
85         }
86         break;
87         case BC_ANIMATION_TYPE_LIGHT:
88         {
89                 Lamp *lamp = (Lamp *)ob->data;
90                 RNA_id_pointer_create(&lamp->id, &id_ptr);
91         }
92         break;
93         default:
94                 fprintf(stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
95                 break;
96         }
97 }
98
99 void BCAnimationCurve::delete_fcurve(FCurve *fcu)
100 {
101         free_fcurve(fcu);
102 }
103
104 FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
105 {
106         FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
107         fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
108         fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
109         fcu->array_index = array_index;
110         return fcu;
111 }
112
113 void BCAnimationCurve::create_bezt(float frame, float output)
114 {
115         FCurve *fcu = get_edit_fcurve();
116         BezTriple bez;
117         memset(&bez, 0, sizeof(BezTriple));
118         bez.vec[1][0] = frame;
119         bez.vec[1][1] = output;
120         bez.ipo = U.ipo_new; /* use default interpolation mode here... */
121         bez.f1 = bez.f2 = bez.f3 = SELECT;
122         bez.h1 = bez.h2 = HD_AUTO;
123         insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
124         calchandles_fcurve(fcu);
125 }
126
127 BCAnimationCurve::~BCAnimationCurve()
128 {
129         if (curve_is_local_copy && fcurve) {
130                 //fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
131                 delete_fcurve(fcurve);
132                 this->fcurve = NULL;
133         }
134 }
135
136 const bool BCAnimationCurve::is_of_animation_type(BC_animation_type type) const
137 {
138         return curve_key.get_animation_type() == type;
139 }
140
141 const std::string BCAnimationCurve::get_channel_target() const
142 {
143         const std::string path = curve_key.get_path();
144         return bc_string_after(path, '.');
145 }
146
147 const std::string BCAnimationCurve::get_animation_name(Object *ob) const
148 {
149         std::string name;
150
151         switch (curve_key.get_animation_type()) {
152                 case BC_ANIMATION_TYPE_OBJECT:
153                 {
154                         name = id_name(ob);
155                 }
156                 break;
157
158                 case BC_ANIMATION_TYPE_BONE:
159                 {
160                         if (fcurve == NULL || fcurve->rna_path == NULL)
161                                 name = "";
162                         else {
163                                 const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones[");
164                                 name = (boneName) ? std::string(boneName) : "";
165                         }
166                 }
167                 break;
168
169                 case BC_ANIMATION_TYPE_CAMERA:
170                 {
171                         Camera *camera = (Camera *)ob->data;
172                         name = id_name(ob) + "-" + id_name(camera) + "-camera";
173                 }
174                 break;
175
176                 case BC_ANIMATION_TYPE_LIGHT:
177                 {
178                         Lamp *lamp = (Lamp *)ob->data;
179                         name = id_name(ob) + "-" + id_name(lamp) + "-light";
180                 }
181                 break;
182
183                 case BC_ANIMATION_TYPE_MATERIAL:
184                 {
185                         Material *ma = give_current_material(ob, this->curve_key.get_subindex() + 1);
186                         name = id_name(ob) + "-" + id_name(ma) + "-material";
187                 }
188                 break;
189
190                 default:
191                 {
192                         name = "";
193                 }
194         }
195
196         return name;
197 }
198
199 const int BCAnimationCurve::get_channel_index() const
200 {
201         return curve_key.get_array_index();
202 }
203
204 const int BCAnimationCurve::get_subindex() const
205 {
206         return curve_key.get_subindex();
207 }
208
209 const std::string BCAnimationCurve::get_rna_path() const
210 {
211         return curve_key.get_path();
212 }
213
214 const int BCAnimationCurve::sample_count() const
215 {
216         if (fcurve == NULL)
217                 return 0;
218         return fcurve->totvert;
219 }
220
221 const int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
222 {
223         if (fcurve == NULL)
224                 return -1;
225
226         const int cframe = fcurve->bezt[start_at].vec[1][0]; // inacurate!
227
228         if (fabs(cframe - sample_frame) < 0.00001)
229                 return start_at;
230         return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
231 }
232
233 const int BCAnimationCurve::closest_index_below(const float sample_frame) const
234 {
235         if (fcurve == NULL)
236                 return -1;
237
238         float lower_frame = sample_frame;
239         float upper_frame = sample_frame;
240         int lower_index = 0;
241         int upper_index = 0;
242
243         for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) {
244                 upper_index = fcu_index;
245
246                 const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate!
247                 if (cframe <= sample_frame) {
248                         lower_frame = cframe;
249                         lower_index = fcu_index;
250                 }
251                 if (cframe >= sample_frame) {
252                         upper_frame = cframe;
253                         break;
254                 }
255         }
256
257         if (lower_index == upper_index)
258                 return lower_index;
259
260         const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
261         return (fraction < 0.5) ? lower_index : upper_index;
262 }
263
264 const int BCAnimationCurve::get_interpolation_type(float sample_frame) const
265 {
266         const int index = closest_index_below(sample_frame);
267         if (index < 0)
268                 return BEZT_IPO_BEZ;
269         return fcurve->bezt[index].ipo;
270 }
271
272 const FCurve *BCAnimationCurve::get_fcurve() const
273 {
274         return fcurve;
275 }
276
277 FCurve *BCAnimationCurve::get_edit_fcurve()
278 {
279         if (!curve_is_local_copy) {
280                 const int index = curve_key.get_array_index();
281                 const std::string &path = curve_key.get_path();
282                 fcurve = create_fcurve(index, path.c_str());
283
284                 /* Caution here:
285                 Replacing the pointer here is OK only because the original value
286                 of FCurve was a const pointer into Blender territory. We do not
287                 touch that! We use the local copy to prepare data for export.
288                 */
289
290                 curve_is_local_copy = true;
291         }
292         return fcurve;
293 }
294
295 void BCAnimationCurve::clean_handles()
296 {
297         if (fcurve == NULL)
298                 fcurve = get_edit_fcurve();
299
300         /* Keep old bezt data for copy)*/
301         BezTriple *old_bezts = fcurve->bezt;
302         int totvert = fcurve->totvert;
303         fcurve->bezt = NULL;
304         fcurve->totvert = 0;
305
306         for (int i = 0; i < totvert; i++) {
307                 BezTriple *bezt = &old_bezts[i];
308                 float x = bezt->vec[1][0];
309                 float y = bezt->vec[1][1];
310                 insert_vert_fcurve(fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS);
311                 BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
312                 lastb->f1 = lastb->f2 = lastb->f3 = 0;
313         }
314
315         /* now free the memory used by the old BezTriples */
316         if (old_bezts)
317                 MEM_freeN(old_bezts);
318 }
319
320 const bool BCAnimationCurve::is_transform_curve() const
321 {
322         std::string channel_target = this->get_channel_target();
323         return (
324                 is_rotation_curve() ||
325                 channel_target == "scale" ||
326                 channel_target == "location"
327                 );
328 }
329
330 const bool BCAnimationCurve::is_rotation_curve() const
331 {
332         std::string channel_target = this->get_channel_target();
333         return (
334                 channel_target == "rotation" ||
335                 channel_target == "rotation_euler" ||
336                 channel_target == "rotation_quaternion"
337                 );
338 }
339
340 const float BCAnimationCurve::get_value(const float frame)
341 {
342         if (fcurve) {
343                 return evaluate_fcurve(fcurve, frame);
344         }
345         return 0; // TODO: handle case where neither sample nor fcu exist
346 }
347
348 void BCAnimationCurve::update_range(float val)
349 {
350         if (val < min) {
351                         min = val;
352         }
353         if (val > max) {
354                 max = val;
355         }
356 }
357
358 void BCAnimationCurve::init_range(float val)
359 {
360         min = max = val;
361 }
362
363 void BCAnimationCurve::adjust_range(const int frame_index)
364 {
365         if (fcurve && fcurve->totvert > 1) {
366                 const float eval = evaluate_fcurve(fcurve, frame_index);
367
368                 int first_frame = fcurve->bezt[0].vec[1][0];
369                 if (first_frame == frame_index) {
370                         init_range(eval);
371                 }
372                 else {
373                         update_range(eval);
374                 }
375         }
376 }
377
378 void BCAnimationCurve::add_value(const float val, const int frame_index)
379 {
380         FCurve *fcu = get_edit_fcurve();
381         fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
382         insert_vert_fcurve(
383                 fcu,
384                 frame_index, val,
385                 BEZT_KEYTYPE_KEYFRAME,
386                 INSERTKEY_NOFLAGS);
387
388         if (fcu->totvert == 1) {
389                 init_range(val);
390         }
391         else {
392                 update_range(val);
393         }
394 }
395
396 bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
397 {
398         int array_index = curve_key.get_array_index();
399
400         /* transformation curves are feeded directly from the transformation matrix
401         * to resolve parent inverse matrix issues with object hierarchies.
402         * Maybe this can be unified with the
403         */
404         const std::string channel_target = get_channel_target();
405         float val = 0;
406         /* Pick the value from the sample according to the definition of the FCurve */
407         bool good = sample.get_value(channel_target, array_index, &val);
408         if (good) {
409                 add_value(val, frame_index);
410         }
411         return good;
412 }
413
414 bool BCAnimationCurve::add_value_from_rna(const int frame_index)
415 {
416         PointerRNA ptr;
417         PropertyRNA *prop;
418         float value = 0.0f;
419         int array_index = curve_key.get_array_index();
420         const std::string full_path = curve_key.get_full_path();
421
422         /* get property to read from, and get value as appropriate */
423         bool path_resolved = RNA_path_resolve_full(&id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
424         if (!path_resolved && array_index == 0) {
425                 const std::string rna_path = curve_key.get_path();
426                 path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
427         }
428
429         if (path_resolved) {
430                 bool is_array = RNA_property_array_check(prop);
431                 if (is_array) {
432                         /* array */
433                         if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
434                                 switch (RNA_property_type(prop)) {
435                                 case PROP_BOOLEAN:
436                                         value = (float)RNA_property_boolean_get_index(&ptr, prop, array_index);
437                                         break;
438                                 case PROP_INT:
439                                         value = (float)RNA_property_int_get_index(&ptr, prop, array_index);
440                                         break;
441                                 case PROP_FLOAT:
442                                         value = RNA_property_float_get_index(&ptr, prop, array_index);
443                                         break;
444                                 default:
445                                         break;
446                                 }
447                         }
448                         else {
449                                 fprintf(stderr, "Out of Bounds while reading data for Curve %s\n", curve_key.get_full_path().c_str());
450                                 return false;
451                         }
452                 }
453                 else {
454                         /* not an array */
455                         switch (RNA_property_type(prop)) {
456                         case PROP_BOOLEAN:
457                                 value = (float)RNA_property_boolean_get(&ptr, prop);
458                                 break;
459                         case PROP_INT:
460                                 value = (float)RNA_property_int_get(&ptr, prop);
461                                 break;
462                         case PROP_FLOAT:
463                                 value = RNA_property_float_get(&ptr, prop);
464                                 break;
465                         case PROP_ENUM:
466                                 value = (float)RNA_property_enum_get(&ptr, prop);
467                                 break;
468                         default:
469                                 fprintf(stderr, "property type %d not supported for Curve %s\n", RNA_property_type(prop), curve_key.get_full_path().c_str());
470                                 return false;
471                                 break;
472                         }
473                 }
474         }
475         else {
476                 /* path couldn't be resolved */
477                 fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
478                 return false;
479         }
480
481         add_value(value, frame_index);
482         return true;
483 }
484
485 void BCAnimationCurve::get_value_map(BCValueMap &value_map)
486 {
487         value_map.clear();
488         if (fcurve == NULL) {
489                 return;
490         }
491
492         for (int i = 0; i < fcurve->totvert; i++) {
493                 const float frame = fcurve->bezt[i].vec[1][0];
494                 const float val = fcurve->bezt[i].vec[1][1];
495                 value_map[frame] = val;
496         }
497 }
498
499 void BCAnimationCurve::get_frames(BCFrames &frames) const
500 {
501         frames.clear();
502         if (fcurve) {
503                 for (int i = 0; i < fcurve->totvert; i++) {
504                         const float val = fcurve->bezt[i].vec[1][0];
505                         frames.push_back(val);
506                 }
507         }
508 }
509
510 void BCAnimationCurve::get_values(BCValues &values) const
511 {
512         values.clear();
513         if (fcurve) {
514                 for (int i = 0; i < fcurve->totvert; i++) {
515                         const float val = fcurve->bezt[i].vec[1][1];
516                         values.push_back(val);
517                 }
518         }
519 }
520
521 bool BCAnimationCurve::is_animated()
522 {
523         static float MIN_DISTANCE = 0.00001;
524         return fabs(max - min) > MIN_DISTANCE;
525 }
526
527
528 bool BCAnimationCurve::is_keyframe(int frame) {
529         if (this->fcurve == NULL)
530                 return false;
531
532         for (int i = 0; i < fcurve->totvert; ++i) {
533                 const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
534                 if (cframe == frame)
535                         return true;
536                 if (cframe > frame)
537                         break;
538         }
539         return false;
540 }
541
542 /* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
543 inline bool operator< (const BCAnimationCurve& lhs, const BCAnimationCurve& rhs) {
544         std::string lhtgt = lhs.get_channel_target();
545         std::string rhtgt = rhs.get_channel_target();
546         if (lhtgt == rhtgt)
547         {
548                 const int lha = lhs.get_channel_index();
549                 const int rha = rhs.get_channel_index();
550                 return lha < rha;
551         }
552         else
553                 return lhtgt < rhtgt;
554 }
555
556 BCCurveKey::BCCurveKey()
557 {
558         this->key_type = BC_ANIMATION_TYPE_OBJECT;
559         this->rna_path = "";
560         this->curve_array_index = 0;
561         this->curve_subindex = -1;
562 }
563
564 BCCurveKey::BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex)
565 {
566         this->key_type = type;
567         this->rna_path = path;
568         this->curve_array_index = array_index;
569         this->curve_subindex = subindex;
570 }
571
572 void BCCurveKey::operator=(const BCCurveKey &other)
573 {
574         this->key_type = other.key_type;
575         this->rna_path = other.rna_path;
576         this->curve_array_index = other.curve_array_index;
577         this->curve_subindex = other.curve_subindex;
578 }
579
580 const std::string BCCurveKey::get_full_path() const
581 {
582         return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
583 }
584
585 const std::string BCCurveKey::get_path() const
586 {
587         return this->rna_path;
588 }
589
590 const int BCCurveKey::get_array_index() const
591 {
592         return this->curve_array_index;
593 }
594
595 const int BCCurveKey::get_subindex() const
596 {
597         return this->curve_subindex;
598 }
599
600 void BCCurveKey::set_object_type(BC_animation_type object_type)
601 {
602         this->key_type = object_type;
603 }
604
605 const BC_animation_type BCCurveKey::get_animation_type() const
606 {
607         return this->key_type;
608 }
609
610 const bool BCCurveKey::operator<(const BCCurveKey &other) const
611 {
612         /* needed for using this class as key in maps and sets */
613         if (this->key_type != other.key_type)
614                 return this->key_type < other.key_type;
615
616         if (this->curve_subindex != other.curve_subindex)
617                 return this->curve_subindex < other.curve_subindex;
618
619         if (this->rna_path != other.rna_path)
620                 return this->rna_path < other.rna_path;
621
622         return this->curve_array_index < other.curve_array_index;
623 }
624
625 BCBezTriple::BCBezTriple(BezTriple &bezt) :
626         bezt(bezt) {}
627
628 const float BCBezTriple::get_frame() const
629 {
630         return bezt.vec[1][0];
631 }
632
633 const float BCBezTriple::get_time(Scene *scene) const
634 {
635         return FRA2TIME(bezt.vec[1][0]);
636 }
637
638 const float BCBezTriple::get_value() const
639 {
640         return bezt.vec[1][1];
641 }
642
643 const float BCBezTriple::get_angle() const
644 {
645         return RAD2DEGF(get_value());
646 }
647
648 void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
649 {
650         get_tangent(scene, point, as_angle, 0);
651 }
652
653 void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
654 {
655         get_tangent(scene, point, as_angle, 2);
656 }
657
658 void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
659 {
660         point[0] = FRA2TIME(bezt.vec[index][0]);
661         if (bezt.ipo != BEZT_IPO_BEZ) {
662                 /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data */
663                 point[0] = 0;
664                 point[1] = 0;
665         }
666         else if (as_angle) {
667                 point[1] = RAD2DEGF(bezt.vec[index][1]);
668         }
669         else {
670                 point[1] = bezt.vec[index][1];
671         }
672 }