Blender V4.3
DocumentImporter.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* TODO:
10 * * name imported objects
11 * * import object rotation as euler */
12
13#include <algorithm> /* sort() */
14#include <map>
15#include <string>
16
17#include "COLLADAFWArrayPrimitiveType.h"
18#include "COLLADAFWCamera.h"
19#include "COLLADAFWColorOrTexture.h"
20#include "COLLADAFWIndexList.h"
21#include "COLLADAFWLibraryNodes.h"
22#include "COLLADAFWLight.h"
23#include "COLLADAFWMeshPrimitiveWithFaceVertexCount.h"
24#include "COLLADAFWPolygons.h"
25#include "COLLADAFWRoot.h"
26#include "COLLADAFWSampler.h"
27#include "COLLADAFWStableHeaders.h"
28#include "COLLADAFWTypes.h"
29#include "COLLADAFWVisualScene.h"
30
31#include "COLLADASaxFWLIExtraDataCallbackHandler.h"
32#include "COLLADASaxFWLLoader.h"
33
34#include "MEM_guardedalloc.h"
35
36#include "BLI_fileops.h"
37#include "BLI_listbase.h"
38#include "BLI_math_matrix.h"
39#include "BLI_string.h"
40#include "BLI_utildefines.h"
41
42#include "BKE_camera.h"
43#include "BKE_collection.hh"
44#include "BKE_fcurve.hh"
45#include "BKE_global.hh"
46#include "BKE_image.hh"
47#include "BKE_layer.hh"
48#include "BKE_lib_id.hh"
49#include "BKE_light.h"
50#include "BKE_material.h"
51#include "BKE_scene.hh"
52
53#include "BLI_path_utils.hh"
54
55#include "DNA_camera_types.h"
56#include "DNA_light_types.h"
57
58#include "RNA_access.hh"
59
60#include "WM_api.hh"
61#include "WM_types.hh"
62
63#include "DEG_depsgraph.hh"
65
66#include "DocumentImporter.h"
67#include "ErrorHandler.h"
68#include "ExtraHandler.h"
69#include "TransformReader.h"
70
71#include "Materials.h"
72#include "collada_internal.h"
73#include "collada_utils.h"
74
75/*
76 * COLLADA Importer limitations:
77 * - no multiple scene import, all objects are added to active scene
78 */
79
81 : import_settings(import_settings),
82 mImportStage(Fetching_Scene_data),
83 mContext(C),
84 view_layer(CTX_data_view_layer(mContext)),
85 armature_importer(&unit_converter,
86 &mesh_importer,
89 view_layer,
90 import_settings),
91 mesh_importer(&unit_converter,
92 import_settings->custom_normals,
93 &armature_importer,
96 view_layer),
97 anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C))
98{
99}
100
102{
103 TagsMap::iterator etit;
104 etit = uid_tags_map.begin();
105 while (etit != uid_tags_map.end()) {
106 delete etit->second;
107 etit++;
108 }
109}
110
112{
113 ErrorHandler errorHandler;
114 COLLADASaxFWL::Loader loader(&errorHandler);
115 COLLADAFW::Root root(&loader, this);
116 ExtraHandler *ehandler = new ExtraHandler(this, &(this->anim_importer));
117
118 loader.registerExtraDataCallbackHandler(ehandler);
119
120 /* deselect all to select new objects */
122
123 std::string mFilename = std::string(this->import_settings->filepath);
124 const std::string encodedFilename = bc_url_encode(mFilename);
125 if (!root.loadDocument(encodedFilename)) {
126 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 1st pass\n");
127 delete ehandler;
128 return false;
129 }
130
131 if (errorHandler.hasError()) {
132 delete ehandler;
133 return false;
134 }
135
137 mImportStage = Fetching_Controller_data;
138 COLLADASaxFWL::Loader loader2;
139 COLLADAFW::Root root2(&loader2, this);
140
141 if (!root2.loadDocument(encodedFilename)) {
142 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n");
143 delete ehandler;
144 return false;
145 }
146
147 delete ehandler;
148
149 return true;
150}
151
152void DocumentImporter::cancel(const COLLADAFW::String &errorMessage)
153{
154 /* TODO: if possible show error info
155 *
156 * Should we get rid of invisible Meshes that were created so far
157 * or maybe create objects at coordinate space origin?
158 *
159 * The latter sounds better. */
160}
161
163
165{
166 if (mImportStage == Fetching_Controller_data) {
167 return;
168 }
169
170 Main *bmain = CTX_data_main(mContext);
171 /* TODO: create a new scene except the selected <visual_scene> -
172 * use current blender scene for it */
173 Scene *sce = CTX_data_scene(mContext);
174 unit_converter.calculate_scale(*sce);
175
176 std::vector<Object *> *objects_to_scale = new std::vector<Object *>();
177
179 std::vector<const COLLADAFW::VisualScene *>::iterator sit;
180 for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
181 PointerRNA unit_settings;
182 PropertyRNA *system, *scale;
183
184 /* for scene unit settings: system, scale_length */
185
186 PointerRNA sceneptr = RNA_id_pointer_create(&sce->id);
187 unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
188 system = RNA_struct_find_property(&unit_settings, "system");
189 scale = RNA_struct_find_property(&unit_settings, "scale_length");
190
191 if (this->import_settings->import_units) {
192
193 switch (unit_converter.isMetricSystem()) {
195 RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
196 break;
198 RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL);
199 break;
200 default:
201 RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE);
202 break;
203 }
204 float unit_factor = unit_converter.getLinearMeter();
205 RNA_property_float_set(&unit_settings, scale, unit_factor);
206 fprintf(stdout, "Collada: Adjusting Blender units to Importset units: %f.\n", unit_factor);
207 }
208
209 /* Write nodes to scene */
210 fprintf(stderr, "+-- Import Scene --------\n");
211 const COLLADAFW::NodePointerArray &roots = (*sit)->getRootNodes();
212 for (uint i = 0; i < roots.getCount(); i++) {
213 std::vector<Object *> *objects_done = write_node(roots[i], nullptr, sce, nullptr, false);
214 objects_to_scale->insert(
215 objects_to_scale->end(), objects_done->begin(), objects_done->end());
216 delete objects_done;
217 }
218 }
219
220 mesh_importer.optimize_material_assignements();
221
222 armature_importer.set_tags_map(this->uid_tags_map);
223 armature_importer.make_armatures(mContext, *objects_to_scale);
224 armature_importer.make_shape_keys(mContext);
225
226#if 0
227 armature_importer.fix_animation();
228#endif
229
230 for (const COLLADAFW::VisualScene *vscene : vscenes) {
231 const COLLADAFW::NodePointerArray &roots = vscene->getRootNodes();
232
233 for (uint i = 0; i < roots.getCount(); i++) {
234 translate_anim_recursive(roots[i], nullptr, nullptr);
235 }
236 }
237
238 if (!libnode_ob.empty()) {
239
240 fprintf(stderr, "| Cleanup: free %d library nodes\n", int(libnode_ob.size()));
241 /* free all library_nodes */
242 std::vector<Object *>::iterator it;
243 for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
244 Object *ob = *it;
245 BKE_scene_collections_object_remove(bmain, sce, ob, true);
246 }
247 libnode_ob.clear();
248 }
249
250 bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
251
252 delete objects_to_scale;
253
254 /* update scene */
257 WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, nullptr);
258}
259
261 COLLADAFW::Node *par = nullptr,
262 Object *parob = nullptr)
263{
264 /* The split in #29246, root_map must point at actual root when
265 * calculating bones in apply_curves_as_matrix. - actual root is the root node.
266 * This has to do with inverse bind poses being world space
267 * (the sources for skinned bones' rest-poses) and the way
268 * non-skinning nodes have their "rest-pose" recursively calculated.
269 * XXX TODO: design issue, how to support unrelated joints taking
270 * part in skinning. */
271 if (par) { // && par->getType() == COLLADAFW::Node::JOINT) {
272 /* If par is root if there's no corresponding key in root_map. */
273 if (root_map.find(par->getUniqueId()) == root_map.end()) {
274 root_map[node->getUniqueId()] = node;
275 }
276 else {
277 root_map[node->getUniqueId()] = root_map[par->getUniqueId()];
278 }
279 }
280
281#if 0
282 COLLADAFW::Transformation::TransformationType types[] = {
283 COLLADAFW::Transformation::ROTATE,
284 COLLADAFW::Transformation::SCALE,
285 COLLADAFW::Transformation::TRANSLATE,
286 COLLADAFW::Transformation::MATRIX,
287 };
288
289 Object *ob;
290#endif
291 uint i;
292
293 if (node->getType() == COLLADAFW::Node::JOINT && par == nullptr) {
294 /* For Skeletons without root node we have to simulate the
295 * root node here and recursively enter the same function
296 * XXX: maybe this can be made more elegant. */
297 translate_anim_recursive(node, node, parob);
298 }
299 else {
300 anim_importer.translate_Animations(
301 node, root_map, object_map, FW_object_map, uid_material_map);
302 COLLADAFW::NodePointerArray &children = node->getChildNodes();
303 for (i = 0; i < children.getCount(); i++) {
304 translate_anim_recursive(children[i], node, nullptr);
305 }
306 }
307}
308
309std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
310{
311 const char AUTORING_TOOL[] = "authoring_tool";
312 const std::string BLENDER("Blender ");
313 const COLLADAFW::FileInfo::ValuePairPointerArray &valuePairs = asset->getValuePairArray();
314 for (size_t i = 0, count = valuePairs.getCount(); i < count; i++) {
315 const COLLADAFW::FileInfo::ValuePair *valuePair = valuePairs[i];
316 const COLLADAFW::String &key = valuePair->first;
317 const COLLADAFW::String &value = valuePair->second;
318 if (key == AUTORING_TOOL) {
319 if (value.compare(0, BLENDER.length(), BLENDER) == 0) {
320 /* Was made with Blender, now get version string */
321 std::string v = value.substr(BLENDER.length());
322 std::string::size_type n = v.find(" ");
323 if (n > 0) {
324 return v.substr(0, n);
325 }
326 }
327 }
328 }
329 return "";
330}
331
332bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
333{
334 unit_converter.read_asset(asset);
335 import_from_version = get_import_version(asset);
336 anim_importer.set_import_from_version(import_from_version);
337 return true;
338}
339
340bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
341{
342 /* XXX could store the scene id, but do nothing for now */
343 return true;
344}
345Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera, Scene *sce)
346{
347 const COLLADAFW::UniqueId &cam_uid = camera->getInstanciatedObjectId();
348 if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {
349 // fprintf(stderr, "Couldn't find camera by UID.\n");
350 return nullptr;
351 }
352
353 Main *bmain = CTX_data_main(mContext);
354 Object *ob = bc_add_object(bmain, sce, view_layer, OB_CAMERA, nullptr);
355 Camera *cam = uid_camera_map[cam_uid];
356 Camera *old_cam = (Camera *)ob->data;
357 ob->data = cam;
358 BKE_id_free_us(bmain, old_cam);
359 return ob;
360}
361
363{
364 const COLLADAFW::UniqueId &lamp_uid = lamp->getInstanciatedObjectId();
365 if (uid_light_map.find(lamp_uid) == uid_light_map.end()) {
366 fprintf(stderr, "Couldn't find light by UID.\n");
367 return nullptr;
368 }
369
370 Main *bmain = CTX_data_main(mContext);
371 Object *ob = bc_add_object(bmain, sce, view_layer, OB_LAMP, nullptr);
372 Light *la = uid_light_map[lamp_uid];
373 Light *old_light = (Light *)ob->data;
374 ob->data = la;
375 BKE_id_free_us(bmain, old_light);
376 return ob;
377}
378
380 COLLADAFW::Node *source_node,
381 COLLADAFW::Node *instance_node,
382 Scene *sce,
383 bool is_library_node)
384{
385 // fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ?
386 // instance_node->getOriginalId().c_str() : nullptr, source_node ?
387 // source_node->getOriginalId().c_str() : nullptr);
388
389 Main *bmain = CTX_data_main(mContext);
390 Object *obn = (Object *)BKE_id_copy(bmain, &source_ob->id);
391 id_us_min(&obn->id);
393 BKE_collection_object_add_from(bmain, sce, source_ob, obn);
394
395 if (instance_node) {
396 anim_importer.read_node_transform(instance_node, obn);
397 /* if we also have a source_node (always ;), take its
398 * transformation matrix and apply it to the newly instantiated
399 * object to account for node hierarchy transforms in `.dae`. */
400 if (source_node) {
401 COLLADABU::Math::Matrix4 mat4 = source_node->getTransformationMatrix();
402 COLLADABU::Math::Matrix4 bmat4 =
403 mat4.transpose(); /* transpose to get blender row-major order */
404 float mat[4][4];
405 for (int i = 0; i < 4; i++) {
406 for (int j = 0; j < 4; j++) {
407 mat[i][j] = bmat4[i][j];
408 }
409 }
410 /* calc new matrix and apply */
411 mul_m4_m4m4(obn->runtime->object_to_world.ptr(), obn->object_to_world().ptr(), mat);
412 BKE_object_apply_mat4(obn, obn->object_to_world().ptr(), false, false);
413 }
414 }
415 else {
416 anim_importer.read_node_transform(source_node, obn);
417 }
418
419 /*DAG_relations_tag_update(CTX_data_main(mContext));*/
420
421 COLLADAFW::NodePointerArray &children = source_node->getChildNodes();
422 if (children.getCount()) {
423 for (uint i = 0; i < children.getCount(); i++) {
424 COLLADAFW::Node *child_node = children[i];
425 const COLLADAFW::UniqueId &child_id = child_node->getUniqueId();
426 if (object_map.find(child_id) == object_map.end()) {
427 continue;
428 }
429 COLLADAFW::InstanceNodePointerArray &inodes = child_node->getInstanceNodes();
430 Object *new_child = nullptr;
431 if (inodes.getCount()) { /* \todo loop through instance nodes */
432 const COLLADAFW::UniqueId &id = inodes[0]->getInstanciatedObjectId();
433 fprintf(stderr, "Doing %d child nodes\n", int(node_map.count(id)));
434 new_child = create_instance_node(
435 object_map.find(id)->second, node_map[id], child_node, sce, is_library_node);
436 }
437 else {
438 new_child = create_instance_node(
439 object_map.find(child_id)->second, child_node, nullptr, sce, is_library_node);
440 }
441 bc_set_parent(new_child, obn, mContext, true);
442
443 if (is_library_node) {
444 libnode_ob.push_back(new_child);
445 }
446 }
447 }
448
449 return obn;
450}
451
453{
454 if (et && et->isProfile("blender")) {
455 short type = 0;
456 et->setData("type", &type);
457 BKE_constraint_add_for_object(ob, "Test_con", type);
458 }
459}
460
461void DocumentImporter::report_unknown_reference(const COLLADAFW::Node &node,
462 const std::string object_type)
463{
464 std::string id = node.getOriginalId();
465 std::string name = node.getName();
466 fprintf(stderr,
467 "error: node id=\"%s\", name=\"%s\" refers to an undefined %s.\n",
468 id.c_str(),
469 name.c_str(),
470 object_type.c_str());
471}
472
473std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
474 COLLADAFW::Node *parent_node,
475 Scene *sce,
476 Object *par,
477 bool is_library_node)
478{
479 Main *bmain = CTX_data_main(mContext);
480 Object *ob = nullptr;
481 bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
482 bool read_transform = true;
483 std::string id = node->getOriginalId();
484 std::string name = node->getName();
485
486 /* if node has child nodes write them */
487 COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
488
489 std::vector<Object *> *objects_done = new std::vector<Object *>();
490 std::vector<Object *> *root_objects = new std::vector<Object *>();
491
492 fprintf(
493 stderr, "| %s id='%s', name='%s'\n", is_joint ? "JOINT" : "NODE ", id.c_str(), name.c_str());
494
495 if (is_joint) {
496 if (parent_node == nullptr && !is_library_node) {
497 /* A Joint on root level is a skeleton without root node.
498 * Here we add the armature "on the fly": */
499 par = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, std::string("Armature").c_str());
500 objects_done->push_back(par);
501 root_objects->push_back(par);
502 object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par));
503 node_map[node->getUniqueId()] = node;
504 }
505 if (parent_node == nullptr || parent_node->getType() != COLLADAFW::Node::JOINT) {
506 armature_importer.add_root_joint(node, par);
507 }
508
509 if (parent_node == nullptr) {
510 /* for skeletons without root node all has been done above.
511 * Skeletons with root node are handled further down. */
512 goto finally;
513 }
514 }
515 else {
516 COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
517 COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
518 COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
519 COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
520 COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
521 size_t geom_done = 0;
522 size_t camera_done = 0;
523 size_t lamp_done = 0;
524 size_t controller_done = 0;
525 size_t inst_done = 0;
526
527 /* XXX linking object with the first <instance_geometry>, though a node may have more of
528 * them... maybe join multiple <instance_...> meshes into 1, and link object with it? not
529 * sure... <instance_geometry> */
530 while (geom_done < geom.getCount()) {
531 ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map);
532 if (ob == nullptr) {
533 report_unknown_reference(*node, "instance_mesh");
534 }
535 else {
536 objects_done->push_back(ob);
537 if (parent_node == nullptr) {
538 root_objects->push_back(ob);
539 }
540 }
541 geom_done++;
542 }
543 while (camera_done < camera.getCount()) {
544 ob = create_camera_object(camera[camera_done], sce);
545 if (ob == nullptr) {
546 report_unknown_reference(*node, "instance_camera");
547 }
548 else {
549 objects_done->push_back(ob);
550 if (parent_node == nullptr) {
551 root_objects->push_back(ob);
552 }
553 }
554 camera_done++;
555 }
556 while (lamp_done < lamp.getCount()) {
557 ob = create_light_object(lamp[lamp_done], sce);
558 if (ob == nullptr) {
559 report_unknown_reference(*node, "instance_light");
560 }
561 else {
562 objects_done->push_back(ob);
563 if (parent_node == nullptr) {
564 root_objects->push_back(ob);
565 }
566 }
567 lamp_done++;
568 }
569 while (controller_done < controller.getCount()) {
570 COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)
571 controller[controller_done];
572 ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map);
573 if (ob == nullptr) {
574 report_unknown_reference(*node, "instance_controller");
575 }
576 else {
577 objects_done->push_back(ob);
578 if (parent_node == nullptr) {
579 root_objects->push_back(ob);
580 }
581 }
582 controller_done++;
583 }
584 /* XXX instance_node is not supported yet */
585 while (inst_done < inst_node.getCount()) {
586 const COLLADAFW::UniqueId &node_id = inst_node[inst_done]->getInstanciatedObjectId();
587 if (object_map.find(node_id) == object_map.end()) {
588 fprintf(stderr,
589 "Cannot find object for node referenced by <instance_node name=\"%s\">.\n",
590 inst_node[inst_done]->getName().c_str());
591 ob = nullptr;
592 }
593 else {
594 std::pair<std::multimap<COLLADAFW::UniqueId, Object *>::iterator,
595 std::multimap<COLLADAFW::UniqueId, Object *>::iterator>
596 pair_iter = object_map.equal_range(node_id);
597 for (std::multimap<COLLADAFW::UniqueId, Object *>::iterator it2 = pair_iter.first;
598 it2 != pair_iter.second;
599 it2++)
600 {
601 Object *source_ob = (Object *)it2->second;
602 COLLADAFW::Node *source_node = node_map[node_id];
603 ob = create_instance_node(source_ob, source_node, node, sce, is_library_node);
604 objects_done->push_back(ob);
605 if (parent_node == nullptr) {
606 root_objects->push_back(ob);
607 }
608 }
609 }
610 inst_done++;
611
612 read_transform = false;
613 }
614
615 /* if node is empty - create empty object
616 * XXX empty node may not mean it is empty object, not sure about this */
617 if ((geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
618 /* Check if Object is armature, by checking if immediate child is a JOINT node. */
619 if (is_armature(node)) {
620 ExtraTags *et = getExtraTags(node->getUniqueId());
621 ob = bc_add_armature(node, et, bmain, sce, view_layer, OB_ARMATURE, name.c_str());
622 }
623 else {
624 ob = bc_add_object(bmain, sce, view_layer, OB_EMPTY, nullptr);
625 }
626 objects_done->push_back(ob);
627 if (parent_node == nullptr) {
628 root_objects->push_back(ob);
629 }
630 }
631
632 /* XXX: if there are multiple instances, only one is stored. */
633
634 if (!ob) {
635 goto finally;
636 }
637
638 for (Object *ob : *objects_done) {
639 std::string nodename = node->getName().empty() ? node->getOriginalId() : node->getName();
640 BKE_libblock_rename(*bmain, ob->id, (char *)nodename.c_str());
641 object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), ob));
642 node_map[node->getUniqueId()] = node;
643
644 if (is_library_node) {
645 libnode_ob.push_back(ob);
646 }
647 }
648
649 // create_constraints(et, ob);
650 }
651
652 for (Object *ob : *objects_done) {
653 if (read_transform) {
654 anim_importer.read_node_transform(node, ob); /* overwrites location set earlier */
655 }
656
657 if (!is_joint) {
658 if (par && ob) {
659 ob->parent = par;
660 ob->partype = PAROBJECT;
661 ob->parsubstr[0] = 0;
662
663 // bc_set_parent(ob, par, mContext, false);
664 }
665 }
666 }
667
668 if (objects_done->empty()) {
669 ob = nullptr;
670 }
671 else {
672 ob = *objects_done->begin();
673 }
674
675 for (uint i = 0; i < child_nodes.getCount(); i++) {
676 std::vector<Object *> *child_objects;
677 child_objects = write_node(child_nodes[i], node, sce, ob, is_library_node);
678 delete child_objects;
679 }
680
681finally:
682 delete objects_done;
683
684 return root_objects;
685}
686
687bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
688{
689 if (mImportStage == Fetching_Controller_data) {
690 return true;
691 }
692
693 /* This method called on post process after writeGeometry, writeMaterial, etc. */
694
695 /* For each <node> in <visual_scene>:
696 * create an Object
697 * if Mesh (previously created in writeGeometry) to which <node> corresponds exists,
698 * link Object with that mesh.
699 *
700 * Update: since we cannot link a Mesh with Object in
701 * writeGeometry because <geometry> does not reference <node>,
702 * we link Objects with Meshes here.
703 */
704 vscenes.push_back(visualScene);
705
706 return true;
707}
708
709bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
710{
711 if (mImportStage == Fetching_Controller_data) {
712 return true;
713 }
714
715 Scene *sce = CTX_data_scene(mContext);
716
717 const COLLADAFW::NodePointerArray &nodes = libraryNodes->getNodes();
718
719 fprintf(stderr, "+-- Read Library nodes ----------\n");
720 for (uint i = 0; i < nodes.getCount(); i++) {
721 std::vector<Object *> *child_objects;
722 child_objects = write_node(nodes[i], nullptr, sce, nullptr, true);
723 delete child_objects;
724 }
725 return true;
726}
727
728bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
729{
730 if (mImportStage == Fetching_Controller_data) {
731 return true;
732 }
733
734 return mesh_importer.write_geometry(geom);
735}
736
737bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
738{
739 if (mImportStage == Fetching_Controller_data) {
740 return true;
741 }
742
743 Main *bmain = CTX_data_main(mContext);
744 const std::string &str_mat_id = cmat->getName().empty() ? cmat->getOriginalId() :
745 cmat->getName();
746 Material *ma = BKE_material_add(bmain, (char *)str_mat_id.c_str());
747 id_us_min(&ma->id);
748
749 this->uid_effect_map[cmat->getInstantiatedEffect()] = ma;
750 this->uid_material_map[cmat->getUniqueId()] = ma;
751
752 return true;
753}
754
755void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
756{
757 MaterialNode matNode = MaterialNode(mContext, ef, ma, uid_image_map);
758
759 /* Direct mapping to principled BSDF Shader */
760 matNode.set_diffuse(ef->getDiffuse());
761 matNode.set_emission(ef->getEmission());
762 matNode.set_ior(ef->getIndexOfRefraction());
763 matNode.set_alpha(ef->getOpaqueMode(), ef->getTransparent(), ef->getTransparency());
764
765 /* following mapping still needs to be verified */
766#if 0
767 /* needs rework to be done for 2.81 */
768 matNode.set_shininess(ef->getShininess());
769#endif
770 matNode.set_reflectivity(ef->getReflectivity());
771
772 /* not supported by principled BSDF */
773 matNode.set_ambient(ef->getAmbient());
774 matNode.set_specular(ef->getSpecular());
775 matNode.set_reflective(ef->getReflective());
776
777 matNode.update_material_nodetree();
778}
779
780bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
781{
782 if (mImportStage == Fetching_Controller_data) {
783 return true;
784 }
785
786 const COLLADAFW::UniqueId &uid = effect->getUniqueId();
787
788 if (uid_effect_map.find(uid) == uid_effect_map.end()) {
789 fprintf(stderr, "Couldn't find a material by UID.\n");
790 return true;
791 }
792
793 Material *ma = uid_effect_map[uid];
794 std::map<COLLADAFW::UniqueId, Material *>::iterator iter;
795 for (iter = uid_material_map.begin(); iter != uid_material_map.end(); iter++) {
796 if (iter->second == ma) {
797 this->FW_object_map[iter->first] = effect;
798 break;
799 }
800 }
801 COLLADAFW::CommonEffectPointerArray common_efs = effect->getCommonEffects();
802 if (common_efs.getCount() < 1) {
803 fprintf(stderr, "Couldn't find <profile_COMMON>.\n");
804 return true;
805 }
806 /* XXX TODO: Take all <profile_common>s
807 * Currently only first <profile_common> is supported */
808 COLLADAFW::EffectCommon *ef = common_efs[0];
809 write_profile_COMMON(ef, ma);
810 this->FW_object_map[effect->getUniqueId()] = effect;
811
812 return true;
813}
814
815bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
816{
817 if (mImportStage == Fetching_Controller_data) {
818 return true;
819 }
820
821 Main *bmain = CTX_data_main(mContext);
822 Camera *cam = nullptr;
823 std::string cam_id, cam_name;
824
825 ExtraTags *et = getExtraTags(camera->getUniqueId());
826 cam_id = camera->getOriginalId();
827 cam_name = camera->getName();
828 if (cam_name.empty()) {
829 cam = (Camera *)BKE_camera_add(bmain, (char *)cam_id.c_str());
830 }
831 else {
832 cam = (Camera *)BKE_camera_add(bmain, (char *)cam_name.c_str());
833 }
834
835 if (!cam) {
836 fprintf(stderr, "Cannot create camera.\n");
837 return true;
838 }
839
840 if (et && et->isProfile("blender")) {
841 et->setData("shiftx", &(cam->shiftx));
842 et->setData("shifty", &(cam->shifty));
843 et->setData("dof_distance", &(cam->dof.focus_distance));
844 }
845 cam->clip_start = camera->getNearClippingPlane().getValue();
846 cam->clip_end = camera->getFarClippingPlane().getValue();
847
848 COLLADAFW::Camera::CameraType type = camera->getCameraType();
849 switch (type) {
850 case COLLADAFW::Camera::ORTHOGRAPHIC: {
851 cam->type = CAM_ORTHO;
852 break;
853 }
854 case COLLADAFW::Camera::PERSPECTIVE: {
855 cam->type = CAM_PERSP;
856 break;
857 }
858 case COLLADAFW::Camera::UNDEFINED_CAMERATYPE: {
859 fprintf(stderr, "Current camera type is not supported.\n");
860 cam->type = CAM_PERSP;
861 break;
862 }
863 }
864
865 switch (camera->getDescriptionType()) {
866 case COLLADAFW::Camera::ASPECTRATIO_AND_Y: {
867 switch (cam->type) {
868 case CAM_ORTHO: {
869 double ymag = 2 * camera->getYMag().getValue();
870 double aspect = camera->getAspectRatio().getValue();
871 double xmag = aspect * ymag;
872 cam->ortho_scale = float(xmag);
873 break;
874 }
875 case CAM_PERSP:
876 default: {
877 double yfov = camera->getYFov().getValue();
878 double aspect = camera->getAspectRatio().getValue();
879
880 /* NOTE: Needs more testing (As we currently have no official test data for this) */
881
882 double xfov = 2.0f * atanf(aspect * tanf(DEG2RADF(yfov) * 0.5f));
883 cam->lens = fov_to_focallength(xfov, cam->sensor_x);
884 break;
885 }
886 }
887 break;
888 }
889 /* XXX correct way to do following four is probably to get also render
890 * size and determine proper settings from that somehow */
891 case COLLADAFW::Camera::ASPECTRATIO_AND_X:
892 case COLLADAFW::Camera::SINGLE_X:
893 case COLLADAFW::Camera::X_AND_Y: {
894 switch (cam->type) {
895 case CAM_ORTHO:
896 cam->ortho_scale = float(camera->getXMag().getValue()) * 2;
897 break;
898 case CAM_PERSP:
899 default: {
900 double x = camera->getXFov().getValue();
901 /* X is in degrees, cam->lens is in millimeters. */
902 cam->lens = fov_to_focallength(DEG2RADF(x), cam->sensor_x);
903 break;
904 }
905 }
906 break;
907 }
908 case COLLADAFW::Camera::SINGLE_Y: {
909 switch (cam->type) {
910 case CAM_ORTHO:
911 cam->ortho_scale = float(camera->getYMag().getValue());
912 break;
913 case CAM_PERSP:
914 default: {
915 double yfov = camera->getYFov().getValue();
916 /* yfov is in degrees, cam->lens is in millimeters. */
917 cam->lens = fov_to_focallength(DEG2RADF(yfov), cam->sensor_x);
918 break;
919 }
920 }
921 break;
922 }
923 case COLLADAFW::Camera::UNDEFINED:
924 /* read nothing, use blender defaults. */
925 break;
926 }
927
928 this->uid_camera_map[camera->getUniqueId()] = cam;
929 this->FW_object_map[camera->getUniqueId()] = camera;
930 /* XXX import camera options */
931 return true;
932}
933
934bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
935{
936 if (mImportStage == Fetching_Controller_data) {
937 return true;
938 }
939
940 const std::string &imagepath = image->getImageURI().toNativePath();
941
942 char dir[FILE_MAX];
943 char absolute_path[FILE_MAX];
944 const char *workpath;
945
946 BLI_path_split_dir_part(this->import_settings->filepath, dir, sizeof(dir));
947 BLI_path_join(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
948 if (BLI_exists(absolute_path)) {
949 workpath = absolute_path;
950 }
951 else {
952 /* Maybe imagepath was already absolute ? */
953 if (!BLI_exists(imagepath.c_str())) {
954 fprintf(stderr, "|! Image not found: %s\n", imagepath.c_str());
955 return true;
956 }
957 workpath = imagepath.c_str();
958 }
959
960 Image *ima = BKE_image_load_exists(CTX_data_main(mContext), workpath);
961 if (!ima) {
962 fprintf(stderr, "|! Cannot create image: %s\n", workpath);
963 return true;
964 }
965 this->uid_image_map[image->getUniqueId()] = ima;
966 fprintf(stderr, "| import Image: %s\n", workpath);
967 return true;
968}
969
970bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
971{
972 if (mImportStage == Fetching_Controller_data) {
973 return true;
974 }
975
976 Main *bmain = CTX_data_main(mContext);
977 Light *lamp = nullptr;
978 std::string la_id, la_name;
979
980 ExtraTags *et = getExtraTags(light->getUniqueId());
981#if 0
982 TagsMap::iterator etit;
983 ExtraTags *et = 0;
984 etit = uid_tags_map.find(light->getUniqueId().toAscii());
985 if (etit != uid_tags_map.end()) {
986 et = etit->second;
987 }
988#endif
989
990 la_id = light->getOriginalId();
991 la_name = light->getName();
992 if (la_name.empty()) {
993 lamp = (Light *)BKE_light_add(bmain, (char *)la_id.c_str());
994 }
995 else {
996 lamp = (Light *)BKE_light_add(bmain, (char *)la_name.c_str());
997 }
998
999 if (!lamp) {
1000 fprintf(stderr, "Cannot create light.\n");
1001 return true;
1002 }
1003
1004 /* if we find an ExtraTags for this, use that instead. */
1005 if (et && et->isProfile("blender")) {
1006 et->setData("type", &(lamp->type));
1007 et->setData("flag", &(lamp->flag));
1008 et->setData("mode", &(lamp->mode));
1009 et->setData("red", &(lamp->r));
1010 et->setData("green", &(lamp->g));
1011 et->setData("blue", &(lamp->b));
1012 et->setData("energy", &(lamp->energy));
1013 et->setData("spotsize", &(lamp->spotsize));
1015 et->setData("spotblend", &(lamp->spotblend));
1016 et->setData("clipsta", &(lamp->clipsta));
1017 et->setData("clipend", &(lamp->att_dist));
1018 et->setData("radius", &(lamp->radius));
1019 et->setData("area_shape", &(lamp->area_shape));
1020 et->setData("area_size", &(lamp->area_size));
1021 et->setData("area_sizey", &(lamp->area_sizey));
1022 et->setData("area_sizez", &(lamp->area_sizez));
1023 }
1024 else {
1025 // float d = 25.0f; /* UNUSED. */
1026 float e = 1.0f;
1027
1028 if (light->getColor().isValid()) {
1029 COLLADAFW::Color col = light->getColor();
1030 lamp->r = col.getRed();
1031 lamp->g = col.getGreen();
1032 lamp->b = col.getBlue();
1033 }
1034
1035 lamp->energy = e;
1036
1037 switch (light->getLightType()) {
1038 case COLLADAFW::Light::AMBIENT_LIGHT: {
1039 lamp->type = LA_SUN; /* TODO: needs more thoughts. */
1040 break;
1041 }
1042 case COLLADAFW::Light::SPOT_LIGHT: {
1043 lamp->type = LA_SPOT;
1044 lamp->spotsize = DEG2RADF(light->getFallOffAngle().getValue());
1045 lamp->spotblend = light->getFallOffExponent().getValue();
1046 break;
1047 }
1048 case COLLADAFW::Light::DIRECTIONAL_LIGHT: {
1049 /* our sun is very strong, so pick a smaller energy level */
1050 lamp->type = LA_SUN;
1051 break;
1052 }
1053 case COLLADAFW::Light::POINT_LIGHT: {
1054 lamp->type = LA_LOCAL;
1055 break;
1056 }
1057 case COLLADAFW::Light::UNDEFINED: {
1058 fprintf(stderr, "Current light type is not supported.\n");
1059 lamp->type = LA_LOCAL;
1060 break;
1061 }
1062 }
1063 }
1064
1065 this->uid_light_map[light->getUniqueId()] = lamp;
1066 this->FW_object_map[light->getUniqueId()] = light;
1067 return true;
1068}
1069
1070bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
1071{
1072 if (mImportStage == Fetching_Controller_data) {
1073 return true;
1074 }
1075
1076 return anim_importer.write_animation(anim);
1077}
1078
1079bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
1080{
1081 if (mImportStage == Fetching_Controller_data) {
1082 return true;
1083 }
1084
1085 // return true;
1086 return anim_importer.write_animation_list(animationList);
1087}
1088
1089#if WITH_OPENCOLLADA_ANIMATION_CLIP
1090bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip)
1091{
1092 /* Since opencollada 1.6.68: called on post-process stage after writeVisualScenes. */
1093
1094 if (mImportStage == Fetching_Controller_data) {
1095 return true;
1096 }
1097
1098 return true;
1099 /* TODO: implement import of AnimationClips */
1100 // return animation_clip_importer.write_animation_clip(animationClip);
1101}
1102#endif
1103
1104bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
1105{
1106 return armature_importer.write_skin_controller_data(skin);
1107}
1108
1109bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
1110{
1111 if (mImportStage == Fetching_Controller_data) {
1112 return true;
1113 }
1114
1115 return armature_importer.write_controller(controller);
1116}
1117
1118bool DocumentImporter::writeFormulas(const COLLADAFW::Formulas *formulas)
1119{
1120 return true;
1121}
1122
1123bool DocumentImporter::writeKinematicsScene(const COLLADAFW::KinematicsScene *kinematicsScene)
1124{
1125 return true;
1126}
1127
1128ExtraTags *DocumentImporter::getExtraTags(const COLLADAFW::UniqueId &uid)
1129{
1130 if (uid_tags_map.find(uid.toAscii()) == uid_tags_map.end()) {
1131 return nullptr;
1132 }
1133 return uid_tags_map[uid.toAscii()];
1134}
1135
1136bool DocumentImporter::addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags)
1137{
1138 uid_tags_map[uid.toAscii()] = extra_tags;
1139 return true;
1140}
1141
1142bool DocumentImporter::is_armature(COLLADAFW::Node *node)
1143{
1144 COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
1145 for (uint i = 0; i < child_nodes.getCount(); i++) {
1146 if (child_nodes[i]->getType() == COLLADAFW::Node::JOINT) {
1147 return true;
1148 }
1149 }
1150
1151 /* no child is JOINT */
1152 return false;
1153}
Camera data-block and utility functions.
void * BKE_camera_add(struct Main *bmain, const char *name)
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, bool free_us)
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
struct bConstraint * BKE_constraint_add_for_object(struct Object *ob, const char *name, short type)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Image * BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists=nullptr)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
IDNewNameResult BKE_libblock_rename(Main &bmain, ID &id, blender::StringRefNull name, const IDNewNameMode mode=IDNewNameMode::RenameExistingNever)
Definition lib_id.cc:2316
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:765
void id_us_min(ID *id)
Definition lib_id.cc:359
General operations, lookup, etc. for blender lights.
struct Light * BKE_light_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT
General operations, lookup, etc. for materials.
struct Material * BKE_material_add(struct Main *bmain, const char *name)
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
#define DEG2RADF(_deg)
float fov_to_focallength(float hfov, float sensor)
#define FILE_MAX
#define BLI_path_join(...)
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
unsigned int uint
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ CAM_PERSP
@ CAM_ORTHO
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ PAROBJECT
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ USER_UNIT_IMPERIAL
@ USER_UNIT_METRIC
@ USER_UNIT_NONE
static Controller * controller
Read Guarded memory(de)allocation.
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
#define ND_TRANSFORM
Definition WM_types.hh:423
#define NC_OBJECT
Definition WM_types.hh:346
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
virtual const char * getName() const
void read_node_transform(COLLADAFW::Node *node, Object *ob)
bool write_animation_list(const COLLADAFW::AnimationList *animlist)
void translate_Animations(COLLADAFW::Node *Node, std::map< COLLADAFW::UniqueId, COLLADAFW::Node * > &root_map, std::multimap< COLLADAFW::UniqueId, Object * > &object_map, std::map< COLLADAFW::UniqueId, const COLLADAFW::Object * > FW_object_map, std::map< COLLADAFW::UniqueId, Material * > uid_material_map)
bool write_animation(const COLLADAFW::Animation *anim)
void set_import_from_version(std::string import_from_version)
void make_shape_keys(bContext *C)
void make_armatures(bContext *C, std::vector< Object * > &objects_to_scale)
bool write_skin_controller_data(const COLLADAFW::SkinControllerData *data)
bool write_controller(const COLLADAFW::Controller *controller)
void set_tags_map(TagsMap &tags_map)
void add_root_joint(COLLADAFW::Node *node, Object *parent)
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *)
std::vector< Object * > * write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool)
std::string get_import_version(const COLLADAFW::FileInfo *asset)
bool addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags)
Object * create_light_object(COLLADAFW::InstanceLight *, Scene *)
bool writeGeometry(const COLLADAFW::Geometry *)
bool writeKinematicsScene(const COLLADAFW::KinematicsScene *)
void cancel(const COLLADAFW::String &errorMessage)
bool writeEffect(const COLLADAFW::Effect *)
bool writeLibraryNodes(const COLLADAFW::LibraryNodes *)
bool writeFormulas(const COLLADAFW::Formulas *)
void translate_anim_recursive(COLLADAFW::Node *, COLLADAFW::Node *, Object *)
bool writeVisualScene(const COLLADAFW::VisualScene *)
bool writeScene(const COLLADAFW::Scene *)
Object * create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool)
bool writeAnimationList(const COLLADAFW::AnimationList *)
bool writeAnimation(const COLLADAFW::Animation *)
bool writeController(const COLLADAFW::Controller *)
void create_constraints(ExtraTags *et, Object *ob)
DocumentImporter(bContext *C, const ImportSettings *import_settings)
bool writeImage(const COLLADAFW::Image *)
bool writeSkinControllerData(const COLLADAFW::SkinControllerData *)
bool writeCamera(const COLLADAFW::Camera *)
ExtraTags * getExtraTags(const COLLADAFW::UniqueId &uid)
bool writeLight(const COLLADAFW::Light *)
bool writeMaterial(const COLLADAFW::Material *)
Object * create_camera_object(COLLADAFW::InstanceCamera *, Scene *)
bool writeGlobalAsset(const COLLADAFW::FileInfo *)
bool is_armature(COLLADAFW::Node *node)
Handler class for parser errors.
bool hasError()
Handler class for <extra> data, through which different profiles can be handled.
Class for saving <extra> tags for a specific UniqueId.
Definition ExtraTags.h:17
bool isProfile(std::string profile)
Definition ExtraTags.cpp:26
bool setData(std::string tag, short *data)
Definition ExtraTags.cpp:68
void set_reflectivity(COLLADAFW::FloatOrParam &val)
void set_shininess(COLLADAFW::FloatOrParam &val)
void set_specular(COLLADAFW::ColorOrTexture &cot)
void update_material_nodetree()
void set_ior(COLLADAFW::FloatOrParam &val)
void set_reflective(COLLADAFW::ColorOrTexture &cot)
void set_emission(COLLADAFW::ColorOrTexture &cot)
void set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, COLLADAFW::ColorOrTexture &cot, COLLADAFW::FloatOrParam &val)
void set_diffuse(COLLADAFW::ColorOrTexture &cot)
void set_ambient(COLLADAFW::ColorOrTexture &cot)
void optimize_material_assignements()
bool write_geometry(const COLLADAFW::Geometry *geom)
Object * create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, bool isController, std::map< COLLADAFW::UniqueId, Material * > &uid_material_map)
void read_asset(const COLLADAFW::FileInfo *asset)
void calculate_scale(Scene &sce)
UnitConverter::UnitSystem isMetricSystem(void)
float getLinearMeter(void)
Object * bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
Object * bc_add_armature(COLLADAFW::Node *node, ExtraTags *node_extra_tags, Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
std::string bc_url_encode(std::string data)
OperationNode * node
#define tanf(x)
#define atanf(x)
draw_view in_light_buf[] float
uint col
int count
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PointerRNA RNA_id_pointer_create(ID *id)
float clip_end
float sensor_x
float clip_start
struct CameraDOFSettings dof
float ortho_scale
float energy
float att_dist
float area_sizez
float area_sizey
short area_shape
float clipsta
float spotblend
float spotsize
float radius
float area_size
short type
short flag
ObjectRuntimeHandle * runtime
struct Object * parent
char parsubstr[64]
void WM_event_add_notifier(const bContext *C, uint type, void *reference)