Blender V4.3
BCAnimationCurve.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "RNA_path.hh"
6
7#include "BCAnimationCurve.h"
8
10{
11 this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT);
12 this->fcurve = nullptr;
13 this->curve_is_local_copy = false;
14}
15
17{
18 this->min = other.min;
19 this->max = other.max;
20 this->fcurve = other.fcurve;
21 this->curve_key = other.curve_key;
22 this->curve_is_local_copy = false;
23 this->id_ptr = other.id_ptr;
24
25 /* The fcurve of the new instance is a copy and can be modified */
26
28}
29
31{
32 this->min = 0;
33 this->max = 0;
34 this->curve_key = key;
35 this->fcurve = fcu;
36 this->curve_is_local_copy = false;
37 init_pointer_rna(ob);
38}
39
41{
42 this->curve_key = key;
43 this->fcurve = nullptr;
44 this->curve_is_local_copy = false;
45 init_pointer_rna(ob);
46}
47
48void BCAnimationCurve::init_pointer_rna(Object *ob)
49{
50 switch (this->curve_key.get_animation_type()) {
52 bArmature *arm = (bArmature *)ob->data;
53 id_ptr = RNA_id_pointer_create(&arm->id);
54 break;
55 }
57 id_ptr = RNA_id_pointer_create(&ob->id);
58 break;
59 }
61 Material *ma = BKE_object_material_get(ob, curve_key.get_subindex() + 1);
62 id_ptr = RNA_id_pointer_create(&ma->id);
63 break;
64 }
66 Camera *camera = (Camera *)ob->data;
67 id_ptr = RNA_id_pointer_create(&camera->id);
68 break;
69 }
71 Light *lamp = (Light *)ob->data;
72 id_ptr = RNA_id_pointer_create(&lamp->id);
73 break;
74 }
75 default:
76 fprintf(
77 stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
78 break;
79 }
80}
81
82void BCAnimationCurve::delete_fcurve(FCurve *fcu)
83{
84 BKE_fcurve_free(fcu);
85}
86
87FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
88{
91 fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
92 fcu->array_index = array_index;
93 return fcu;
94}
95
96void BCAnimationCurve::create_bezt(float frame, float output)
97{
98 FCurve *fcu = get_edit_fcurve();
99 BezTriple bez;
100 memset(&bez, 0, sizeof(BezTriple));
101 bez.vec[1][0] = frame;
102 bez.vec[1][1] = output;
103 bez.ipo = U.ipo_new; /* use default interpolation mode here... */
104 bez.f1 = bez.f2 = bez.f3 = SELECT;
105 bez.h1 = bez.h2 = HD_AUTO;
108}
109
111{
112 if (curve_is_local_copy && fcurve) {
113 // fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
114 delete_fcurve(fcurve);
115 this->fcurve = nullptr;
116 }
117}
118
120{
121 return curve_key.get_animation_type() == type;
122}
123
125{
126 const std::string path = curve_key.get_path();
127
128 if (bc_startswith(path, "pose.bones")) {
129 return bc_string_after(path, "pose.bones");
130 }
131 return bc_string_after(path, ".");
132}
133
135{
136 const std::string channel = get_channel_target();
137 return bc_string_after(channel, ".");
138}
139
141{
142 const std::string channel = get_channel_target();
143 std::string pose_bone_name = bc_string_before(channel, ".");
144 if (pose_bone_name == channel) {
145 pose_bone_name = "";
146 }
147 else {
148 pose_bone_name = bc_string_after(pose_bone_name, "\"[");
149 pose_bone_name = bc_string_before(pose_bone_name, "]\"");
150 }
151 return pose_bone_name;
152}
153
155{
156 std::string name;
157
158 switch (curve_key.get_animation_type()) {
160 name = id_name(ob);
161 break;
162 }
164 if (fcurve == nullptr || fcurve->rna_path == nullptr) {
165 name = "";
166 }
167 else {
168 char boneName[MAXBONENAME];
169 if (BLI_str_quoted_substr(fcurve->rna_path, "pose.bones[", boneName, sizeof(boneName))) {
170 name = id_name(ob) + "_" + std::string(boneName);
171 }
172 else {
173 name = "";
174 }
175 }
176 break;
177 }
179 Camera *camera = (Camera *)ob->data;
180 name = id_name(ob) + "-" + id_name(camera) + "-camera";
181 break;
182 }
184 Light *lamp = (Light *)ob->data;
185 name = id_name(ob) + "-" + id_name(lamp) + "-light";
186 break;
187 }
189 Material *ma = BKE_object_material_get(ob, this->curve_key.get_subindex() + 1);
190 name = id_name(ob) + "-" + id_name(ma) + "-material";
191 break;
192 }
193 default: {
194 name = "";
195 }
196 }
197
198 return name;
199}
200
202{
203 return curve_key.get_array_index();
204}
205
207{
208 return curve_key.get_subindex();
209}
210
212{
213 return curve_key.get_path();
214}
215
217{
218 if (fcurve == nullptr) {
219 return 0;
220 }
221 return fcurve->totvert;
222}
223
224int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
225{
226 if (fcurve == nullptr) {
227 return -1;
228 }
229
230 const int cframe = fcurve->bezt[start_at].vec[1][0]; /* inaccurate! */
231
232 if (fabs(cframe - sample_frame) < 0.00001) {
233 return start_at;
234 }
235 return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
236}
237
238int BCAnimationCurve::closest_index_below(const float sample_frame) const
239{
240 if (fcurve == nullptr) {
241 return -1;
242 }
243
244 float lower_frame = sample_frame;
245 float upper_frame = sample_frame;
246 int lower_index = 0;
247 int upper_index = 0;
248
249 for (int fcu_index = 0; fcu_index < fcurve->totvert; fcu_index++) {
250 upper_index = fcu_index;
251
252 const int cframe = fcurve->bezt[fcu_index].vec[1][0]; /* inaccurate! */
253 if (cframe <= sample_frame) {
254 lower_frame = cframe;
255 lower_index = fcu_index;
256 }
257 if (cframe >= sample_frame) {
258 upper_frame = cframe;
259 break;
260 }
261 }
262
263 if (lower_index == upper_index) {
264 return lower_index;
265 }
266
267 const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
268 return (fraction < 0.5) ? lower_index : upper_index;
269}
270
271int BCAnimationCurve::get_interpolation_type(float sample_frame) const
272{
273 const int index = closest_index_below(sample_frame);
274 if (index < 0) {
275 return BEZT_IPO_BEZ;
276 }
277 return fcurve->bezt[index].ipo;
278}
279
281{
282 return fcurve;
283}
284
286{
287 if (!curve_is_local_copy) {
288 const int index = curve_key.get_array_index();
289 const std::string &path = curve_key.get_path();
290 fcurve = create_fcurve(index, path.c_str());
291
292 /* Caution here:
293 * Replacing the pointer here is OK only because the original value
294 * of FCurve was a const pointer into Blender territory. We do not
295 * touch that! We use the local copy to prepare data for export. */
296
297 curve_is_local_copy = true;
298 }
299 return fcurve;
300}
301
303{
304 using namespace blender::animrig;
305 if (fcurve == nullptr) {
306 fcurve = get_edit_fcurve();
307 }
308
309 const KeyframeSettings settings = get_keyframe_settings(true);
310
311 /* Keep old bezt data for copy). */
312 BezTriple *old_bezts = fcurve->bezt;
313 int totvert = fcurve->totvert;
314 fcurve->bezt = nullptr;
315 fcurve->totvert = 0;
316
317 for (int i = 0; i < totvert; i++) {
318 BezTriple *bezt = &old_bezts[i];
319 float x = bezt->vec[1][0];
320 float y = bezt->vec[1][1];
321 insert_vert_fcurve(fcurve, {x, y}, settings, INSERTKEY_NOFLAGS);
322 BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
323 lastb->f1 = lastb->f2 = lastb->f3 = 0;
324 }
325
326 /* now free the memory used by the old BezTriples */
327 if (old_bezts) {
328 MEM_freeN(old_bezts);
329 }
330}
331
333{
334 std::string channel_type = this->get_channel_type();
335 return (is_rotation_curve() || channel_type == "scale" || channel_type == "location");
336}
337
339{
340 std::string channel_type = this->get_channel_type();
341 return ELEM(channel_type, "rotation", "rotation_euler", "rotation_quaternion");
342}
343
344float BCAnimationCurve::get_value(const float frame)
345{
346 if (fcurve) {
347 return evaluate_fcurve(fcurve, frame);
348 }
349 return 0; /* TODO: handle case where neither sample nor fcu exist */
350}
351
352void BCAnimationCurve::update_range(float val)
353{
354 if (val < min) {
355 min = val;
356 }
357 if (val > max) {
358 max = val;
359 }
360}
361
362void BCAnimationCurve::init_range(float val)
363{
364 min = max = val;
365}
366
367void BCAnimationCurve::adjust_range(const int frame_index)
368{
369 if (fcurve && fcurve->totvert > 1) {
370 const float eval = evaluate_fcurve(fcurve, frame_index);
371
372 int first_frame = fcurve->bezt[0].vec[1][0];
373 if (first_frame == frame_index) {
374 init_range(eval);
375 }
376 else {
377 update_range(eval);
378 }
379 }
380}
381
382void BCAnimationCurve::add_value(const float val, const int frame_index)
383{
384 using namespace blender::animrig;
385 const KeyframeSettings settings = get_keyframe_settings(true);
386 FCurve *fcu = get_edit_fcurve();
387 fcu->auto_smoothing = U.auto_smoothing_new;
388 insert_vert_fcurve(fcu, {float(frame_index), val}, settings, INSERTKEY_NOFLAGS);
389
390 if (fcu->totvert == 1) {
391 init_range(val);
392 }
393 else {
394 update_range(val);
395 }
396}
397
398bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
399{
400 int array_index = curve_key.get_array_index();
401
402 /* transformation curves are fed directly from the transformation matrix
403 * to resolve parent inverse matrix issues with object hierarchies.
404 * Maybe this can be unified with the
405 */
406 const std::string channel_target = get_channel_target();
407 float val = 0;
408 /* Pick the value from the sample according to the definition of the FCurve */
409 bool good = sample.get_value(channel_target, array_index, &val);
410 if (good) {
411 add_value(val, frame_index);
412 }
413 return good;
414}
415
416bool BCAnimationCurve::add_value_from_rna(const int frame_index)
417{
419 PropertyRNA *prop;
420 float value = 0.0f;
421 int array_index = curve_key.get_array_index();
422 const std::string full_path = curve_key.get_full_path();
423
424 /* get property to read from, and get value as appropriate */
425 bool path_resolved = RNA_path_resolve_full(
426 &id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
427 if (!path_resolved && array_index == 0) {
428 const std::string rna_path = curve_key.get_path();
429 path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
430 }
431
432 if (path_resolved) {
433 bool is_array = RNA_property_array_check(prop);
434 if (is_array) {
435 /* array */
436 if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
437 switch (RNA_property_type(prop)) {
438 case PROP_BOOLEAN:
439 value = float(RNA_property_boolean_get_index(&ptr, prop, array_index));
440 break;
441 case PROP_INT:
442 value = float(RNA_property_int_get_index(&ptr, prop, array_index));
443 break;
444 case PROP_FLOAT:
445 value = RNA_property_float_get_index(&ptr, prop, array_index);
446 break;
447 default:
448 break;
449 }
450 }
451 else {
452 fprintf(stderr,
453 "Out of Bounds while reading data for Curve %s\n",
454 curve_key.get_full_path().c_str());
455 return false;
456 }
457 }
458 else {
459 /* not an array */
460 switch (RNA_property_type(prop)) {
461 case PROP_BOOLEAN:
462 value = float(RNA_property_boolean_get(&ptr, prop));
463 break;
464 case PROP_INT:
465 value = float(RNA_property_int_get(&ptr, prop));
466 break;
467 case PROP_FLOAT:
468 value = RNA_property_float_get(&ptr, prop);
469 break;
470 case PROP_ENUM:
471 value = float(RNA_property_enum_get(&ptr, prop));
472 break;
473 default:
474 fprintf(stderr,
475 "property type %d not supported for Curve %s\n",
476 RNA_property_type(prop),
477 curve_key.get_full_path().c_str());
478 return false;
479 break;
480 }
481 }
482 }
483 else {
484 /* path couldn't be resolved */
485 fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
486 return false;
487 }
488
489 add_value(value, frame_index);
490 return true;
491}
492
494{
495 value_map.clear();
496 if (fcurve == nullptr) {
497 return;
498 }
499
500 for (int i = 0; i < fcurve->totvert; i++) {
501 const float frame = fcurve->bezt[i].vec[1][0];
502 const float val = fcurve->bezt[i].vec[1][1];
503 value_map[frame] = val;
504 }
505}
506
508{
509 frames.clear();
510 if (fcurve) {
511 for (int i = 0; i < fcurve->totvert; i++) {
512 const float val = fcurve->bezt[i].vec[1][0];
513 frames.push_back(val);
514 }
515 }
516}
517
519{
520 values.clear();
521 if (fcurve) {
522 for (int i = 0; i < fcurve->totvert; i++) {
523 const float val = fcurve->bezt[i].vec[1][1];
524 values.push_back(val);
525 }
526 }
527}
528
530{
531 static float MIN_DISTANCE = 0.00001;
532 return fabs(max - min) > MIN_DISTANCE;
533}
534
536{
537 if (this->fcurve == nullptr) {
538 return false;
539 }
540
541 for (int i = 0; i < fcurve->totvert; i++) {
542 const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
543 if (cframe == frame) {
544 return true;
545 }
546 if (cframe > frame) {
547 break;
548 }
549 }
550 return false;
551}
552
553/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
554inline bool operator<(const BCAnimationCurve &lhs, const BCAnimationCurve &rhs)
555{
556 std::string lhtgt = lhs.get_channel_target();
557 std::string rhtgt = rhs.get_channel_target();
558 if (lhtgt == rhtgt) {
559 const int lha = lhs.get_channel_index();
560 const int rha = rhs.get_channel_index();
561 return lha < rha;
562 }
563
564 return lhtgt < rhtgt;
565}
566
568{
569 this->key_type = BC_ANIMATION_TYPE_OBJECT;
570 this->rna_path = "";
571 this->curve_array_index = 0;
572 this->curve_subindex = -1;
573}
574
576 const std::string path,
577 const int array_index,
578 const int subindex)
579{
580 this->key_type = type;
581 this->rna_path = path;
582 this->curve_array_index = array_index;
583 this->curve_subindex = subindex;
584}
585
587{
588 this->key_type = other.key_type;
589 this->rna_path = other.rna_path;
590 this->curve_array_index = other.curve_array_index;
591 this->curve_subindex = other.curve_subindex;
592}
593
594std::string BCCurveKey::get_full_path() const
595{
596 return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
597}
598
599std::string BCCurveKey::get_path() const
600{
601 return this->rna_path;
602}
603
605{
606 return this->curve_array_index;
607}
608
610{
611 return this->curve_subindex;
612}
613
615{
616 this->key_type = object_type;
617}
618
620{
621 return this->key_type;
622}
623
624bool BCCurveKey::operator<(const BCCurveKey &other) const
625{
626 /* needed for using this class as key in maps and sets */
627 if (this->key_type != other.key_type) {
628 return this->key_type < other.key_type;
629 }
630
631 if (this->curve_subindex != other.curve_subindex) {
632 return this->curve_subindex < other.curve_subindex;
633 }
634
635 if (this->rna_path != other.rna_path) {
636 return this->rna_path < other.rna_path;
637 }
638
639 return this->curve_array_index < other.curve_array_index;
640}
641
643
645{
646 return bezt.vec[1][0];
647}
648
649float BCBezTriple::get_time(Scene *scene) const
650{
651 return FRA2TIME(bezt.vec[1][0]);
652}
653
655{
656 return bezt.vec[1][1];
657}
658
660{
661 return RAD2DEGF(get_value());
662}
663
664void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
665{
666 get_tangent(scene, point, as_angle, 0);
667}
668
669void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
670{
671 get_tangent(scene, point, as_angle, 2);
672}
673
674void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
675{
676 point[0] = FRA2TIME(bezt.vec[index][0]);
677 if (bezt.ipo != BEZT_IPO_BEZ) {
678 /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain
679 * unused data */
680 point[0] = 0;
681 point[1] = 0;
682 }
683 else if (as_angle) {
684 point[1] = RAD2DEGF(bezt.vec[index][1]);
685 }
686 else {
687 point[1] = bezt.vec[index][1];
688 }
689}
bool operator<(const BCAnimationCurve &lhs, const BCAnimationCurve &rhs)
std::vector< float > BCValues
std::map< int, float > BCValueMap
BC_animation_type
@ BC_ANIMATION_TYPE_MATERIAL
@ BC_ANIMATION_TYPE_LIGHT
@ BC_ANIMATION_TYPE_OBJECT
@ BC_ANIMATION_TYPE_BONE
@ BC_ANIMATION_TYPE_CAMERA
std::vector< float > BCFrames
void BKE_fcurve_handles_recalc(FCurve *fcu)
FCurve * BKE_fcurve_create(void)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_free(FCurve *fcu)
struct Material * BKE_object_material_get(struct Object *ob, short act)
#define RAD2DEGF(_rad)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.c:517
#define ELEM(...)
struct FCurve FCurve
@ INSERTKEY_NOFLAGS
@ FCURVE_SELECTED
@ FCURVE_VISIBLE
#define MAXBONENAME
struct Camera Camera
@ HD_AUTO
struct BezTriple BezTriple
@ BEZT_IPO_BEZ
struct Light Light
struct Material Material
#define FRA2TIME(a)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_INT
Definition RNA_types.hh:66
#define U
#define output
std::string get_rna_path() const
FCurve * get_fcurve() const
float get_value(float frame)
void get_values(BCValues &values) const
void add_value(float val, int frame)
bool add_value_from_matrix(const BCSample &sample, int frame)
std::string get_channel_type() const
void adjust_range(int frame)
bool is_rotation_curve() const
void get_value_map(BCValueMap &value_map)
bool is_keyframe(int frame)
int get_interpolation_type(float sample_frame) const
bool is_of_animation_type(BC_animation_type type) const
int closest_index_below(float sample_frame) const
void get_frames(BCFrames &frames) const
int closest_index_above(float sample_frame, int start_at) const
bool is_transform_curve() const
std::string get_channel_posebone() const
bool add_value_from_rna(int frame)
std::string get_channel_target() const
int get_channel_index() const
std::string get_animation_name(Object *ob) const
void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
float get_frame() const
BezTriple & bezt
BCBezTriple(BezTriple &bezt)
float get_time(Scene *scene) const
void get_out_tangent(Scene *scene, float point[2], bool as_angle) const
void get_in_tangent(Scene *scene, float point[2], bool as_angle) const
float get_value() const
float get_angle() const
std::string get_path() const
int get_subindex() const
std::string get_full_path() const
void set_object_type(BC_animation_type object_type)
int get_array_index() const
void operator=(const BCCurveKey &other)
BC_animation_type get_animation_type() const
bool operator<(const BCCurveKey &other) const
std::string id_name(void *id)
std::string bc_string_after(const std::string &s, const std::string probe)
std::string bc_string_before(const std::string &s, const std::string probe)
bool bc_startswith(std::string const &value, std::string const &starting)
local_group_size(16, 16) .push_constant(Type rhs
#define SELECT
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 fabs(const float2 a)
KeyframeSettings get_keyframe_settings(bool from_userprefs)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
Lesser Key-framing API call.
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PropertyType RNA_property_type(PropertyRNA *prop)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:537
#define min(a, b)
Definition sort.c:32
float vec[3][3]
char * rna_path
int array_index
unsigned int totvert
char auto_smoothing
PointerRNA * ptr
Definition wm_files.cc:4126