예제 #1
0
/**
 * Make either a shallow copy, or deeper duplicate of given collection.
 *
 * If \a do_hierarchy and \a do_deep_copy are false, this is a regular (shallow) ID copy.
 *
 * \warning If any 'deep copy' behavior is enabled,
 * this functions will clear all \a bmain id.idnew pointers.
 *
 * \param do_hierarchy If true, it will recursively make shallow copies of children collections.
 * \param do_objects If true, it will also make duplicates of objects.
 *                   This one does nothing if \a do_hierarchy is not set.
 * \param do_obdata If true, it will also make deep duplicates of objects,
 * using behavior defined in user settings (U.dupflag).
 * This one does nothing if \a do_hierarchy and \a do_objects are not set.
 */
Collection *BKE_collection_duplicate(Main *bmain,
                                     Collection *parent,
                                     Collection *collection,
                                     const bool do_hierarchy,
                                     const bool do_objects,
                                     const bool do_obdata)
{
  /* It's not allowed to copy the master collection. */
  if (collection->flag & COLLECTION_IS_MASTER) {
    BLI_assert("!Master collection can't be duplicated");
    return NULL;
  }

  if (do_hierarchy) {
    BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
    BKE_main_id_clear_newpoins(bmain);
  }

  Collection *collection_new = collection_duplicate_recursive(
      bmain, parent, collection, do_hierarchy, do_objects, do_obdata);

  /* This code will follows into all ID links using an ID tagged with LIB_TAG_NEW.*/
  BKE_libblock_relink_to_newid(&collection_new->id);

  if (do_hierarchy) {
    /* Cleanup. */
    BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
    BKE_main_id_clear_newpoins(bmain);
  }

  BKE_main_collection_sync(bmain);

  return collection_new;
}
예제 #2
0
/**
 * \return Success.
 */
bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, ReportList *reports)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	View3D *v3d = CTX_wm_view3d(C);
	Main *mainl = NULL;
	Library *lib;
	BlendHandle *bh;
		
	bh = BLO_blendhandle_from_file(libname, reports);
	
	if (bh == NULL) {
		/* error reports will have been made by BLO_blendhandle_from_file() */
		return false;
	}

	BKE_scene_base_deselect_all(scene);
	
	/* tag everything, all untagged data can be made local
	 * its also generally useful to know what is new
	 *
	 * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
	BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
	
	/* here appending/linking starts */
	mainl = BLO_library_link_begin(bmain, &bh, libname);
	
	BLO_library_link_copypaste(mainl, bh);

	BLO_library_link_end(mainl, &bh, flag, scene, v3d);
	
	/* mark all library linked objects to be updated */
	BKE_main_lib_objects_recalc_all(bmain);
	IMB_colormanagement_check_file_config(bmain);
	
	/* append, rather than linking */
	lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
	BKE_library_make_local(bmain, lib, true, false);
	
	/* important we unset, otherwise these object wont
	 * link into other scenes from this blend file */
	BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
	
	/* recreate dependency graph to include new objects */
	DAG_relations_tag_update(bmain);
	
	BLO_blendhandle_close(bh);
	/* remove library... */
	
	return true;
}
예제 #3
0
void BKE_libblock_delete(Main *bmain, void *idv)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int base_count, i;

	base_count = set_listbasepointers(bmain, lbarray);
	BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);

	/* First tag all datablocks directly from target lib.
	 * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
	 * Avoids to have to loop twice. */
	for (i = 0; i < base_count; i++) {
		ListBase *lb = lbarray[i];
		ID *id;

		for (id = lb->first; id; id = id->next) {
			/* Note: in case we delete a library, we also delete all its datablocks! */
			if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) {
				id->tag |= LIB_TAG_DOIT;
				/* Will tag 'never NULL' users of this ID too.
				 * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
				 * links, this can lead to nasty crashing here in second, actual deleting loop.
				 * Also, this will also flag users of deleted data that cannot be unlinked
				 * (object using deleted obdata, etc.), so that they also get deleted. */
				BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
			}
		}
	}

	/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
	 * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
	 * over meshes when we come to freeing obdata). */
	for (i = base_count; i--; ) {
		ListBase *lb = lbarray[i];
		ID *id, *id_next;

		for (id = lb->first; id; id = id_next) {
			id_next = id->next;
			if (id->tag & LIB_TAG_DOIT) {
				if (id->us != 0) {
#ifdef DEBUG_PRINT
					printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
#endif
					BLI_assert(id->us == 0);
				}
				BKE_libblock_free(bmain, id);
			}
		}
	}
}
KX_BlenderSceneConverter::KX_BlenderSceneConverter(
							Main *maggie,
							KX_KetsjiEngine *engine)
							:m_maggie(maggie),
							m_ketsjiEngine(engine),
							m_alwaysUseExpandFraming(false),
							m_usemat(false),
							m_useglslmat(false),
							m_use_mat_cache(true)
{
	BKE_main_id_tag_all(maggie, false);  /* avoid re-tagging later on */
	m_newfilename = "";
	m_threadinfo = new ThreadInfo();
	pthread_mutex_init(&m_threadinfo->merge_lock, NULL);
}
예제 #5
0
KX_BlenderSceneConverter::KX_BlenderSceneConverter(
							Main *maggie,
							KX_KetsjiEngine *engine)
							:m_maggie(maggie),
							m_ketsjiEngine(engine),
							m_alwaysUseExpandFraming(false),
							m_usemat(false),
							m_useglslmat(false),
							m_use_mat_cache(true)
{
	BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false);  /* avoid re-tagging later on */
	m_newfilename = "";
	m_threadinfo = new ThreadInfo();
	m_threadinfo->m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), NULL);
	BLI_mutex_init(&m_threadinfo->m_mutex);
}
예제 #6
0
bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports)
{
	BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
	if (bh == NULL) {
		/* Error reports will have been made by BLO_blendhandle_from_file(). */
		return false;
	}
	/* Here appending/linking starts. */
	Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
	BLO_library_link_copypaste(mainl, bh);
	BLO_library_link_end(mainl, &bh, 0, NULL, NULL);
	/* Mark all library linked objects to be updated. */
	BKE_main_lib_objects_recalc_all(bmain_dst);
	IMB_colormanagement_check_file_config(bmain_dst);
	/* Append, rather than linking. */
	Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath));
	BKE_library_make_local(bmain_dst, lib, true, false);
	/* Important we unset, otherwise these object wont
	 * link into other scenes from this blend file.
	 */
	BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
	BLO_blendhandle_close(bh);
	return true;
}
예제 #7
0
void BKE_blendfile_write_partial_end(Main *bmain_src)
{
	BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
}
예제 #8
0
/* Note m_map_*** are all ok and don't need to be freed
 * most are temp and NewRemoveObject frees m_map_gameobject_to_blender */
bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
{
	int maggie_index = -1;
	int i = 0;

	if (maggie == NULL)
		return false;

	// If the given library is currently in loading, we do nothing.
	if (m_status_map.count(maggie->name)) {
		BLI_mutex_lock(&m_threadinfo->m_mutex);
		const bool finished = m_status_map[maggie->name]->IsFinished();
		BLI_mutex_unlock(&m_threadinfo->m_mutex);

		if (!finished) {
			printf("Library (%s) is currently being loaded asynchronously, and cannot be freed until this process is done\n", maggie->name);
			return false;
		}
	}

	/* tag all false except the one we remove */
	for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
		Main *main = *it;
		if (main != maggie) {
			BKE_main_id_tag_all(main, LIB_TAG_DOIT, false);
		}
		else {
			maggie_index = i;
		}
		i++;
	}

	/* should never happen but just to be safe */
	if (maggie_index == -1)
		return false;

	m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index);
	BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, true);

	/* free all tagged objects */
	KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
	int numScenes = scenes->size();

	for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
		KX_Scene *scene = scenes->at(scene_idx);
		if (IS_TAGGED(scene->GetBlenderScene())) {
			m_ketsjiEngine->RemoveScene(scene->GetName());
			m_mat_cache.erase(scene);
			m_polymat_cache.erase(scene);
			scene_idx--;
			numScenes--;
		}
		else {
			/* in case the mesh might be refered to later */
			{
				CTR_Map<STR_HashedString, void *> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
				
				for (int i = 0; i < mapStringToMeshes.size(); i++) {
					RAS_MeshObject *meshobj = (RAS_MeshObject *) *mapStringToMeshes.at(i);
					if (meshobj && IS_TAGGED(meshobj->GetMesh())) {
						STR_HashedString mn = meshobj->GetName();
						mapStringToMeshes.remove(mn);
						m_map_mesh_to_gamemesh.remove(CHashedPtr(meshobj->GetMesh()));
						i--;
					}
				}
			}

			/* Now unregister actions */
			{
				CTR_Map<STR_HashedString, void *> &mapStringToActions = scene->GetLogicManager()->GetActionMap();

				for (int i = 0; i < mapStringToActions.size(); i++) {
					ID *action = (ID*) *mapStringToActions.at(i);

					if (IS_TAGGED(action)) {
						STR_HashedString an = action->name + 2;
						mapStringToActions.remove(an);
						m_map_blender_to_gameAdtList.remove(CHashedPtr(action));
						i--;
					}
				}
			}
			
			//scene->FreeTagged(); /* removed tagged objects and meshes*/
			CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL};

			for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) {
				CListValue *obs = obj_lists[ob_ls_idx];
				RAS_MeshObject *mesh;

				for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) {
					KX_GameObject *gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
					if (IS_TAGGED(gameobj->GetBlenderObject())) {
						int size_before = obs->GetCount();

						/* Eventually calls RemoveNodeDestructObject
						 * frees m_map_gameobject_to_blender from UnregisterGameObject */
						scene->RemoveObject(gameobj);

						if (size_before != obs->GetCount())
							ob_idx--;
						else {
							printf("ERROR COULD NOT REMOVE \"%s\"\n", gameobj->GetName().ReadPtr());
						}
					}
					else {
						gameobj->RemoveTaggedActions();
						/* free the mesh, we could be referecing a linked one! */
						int mesh_index = gameobj->GetMeshCount();
						while (mesh_index--) {
							mesh = gameobj->GetMesh(mesh_index);
							if (IS_TAGGED(mesh->GetMesh())) {
								gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */
								break;
							}
							else {
								/* also free the mesh if it's using a tagged material */
								int mat_index = mesh->NumMaterials();
								while (mat_index--) {
									if (IS_TAGGED(mesh->GetMeshMaterial(mat_index)->m_bucket->GetPolyMaterial()->GetBlenderMaterial())) {
										gameobj->RemoveMeshes(); /* XXX - slack, same as above */
										break;
									}
								}
							}
						}

						/* make sure action actuators are not referencing tagged actions */
						for (unsigned int act_idx = 0; act_idx < gameobj->GetActuators().size(); act_idx++) {
							if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) {
								BL_ActionActuator *act = (BL_ActionActuator *)gameobj->GetActuators()[act_idx];
								if (IS_TAGGED(act->GetAction()))
									act->SetAction(NULL);
							}
						}
					}
				}
			}
		}
	}

	int size;

	// delete the entities of this scene
	/* TODO - */
#if 0
	vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
	size = m_worldinfos.size();
	for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
		if ((*worldit).second) {
			delete (*worldit).second;
			*worldit = m_worldinfos.back();
			m_worldinfos.pop_back();
			size--;
		} else {
			i++;
			worldit++;
		}
	}
#endif


	/* Worlds don't reference original blender data so we need to make a set from them */
	typedef std::set<KX_WorldInfo *> KX_WorldInfoSet;
	KX_WorldInfoSet worldset;
	for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
		KX_Scene *scene = scenes->at(scene_idx);
		if (scene->GetWorldInfo())
			worldset.insert(scene->GetWorldInfo());
	}

	vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
	size = m_worldinfos.size();
	for (i = 0, worldit = m_worldinfos.begin(); i < size;) {
		if (worldit->second && (worldset.count(worldit->second)) == 0) {
			delete worldit->second;
			*worldit = m_worldinfos.back();
			m_worldinfos.pop_back();
			size--;
		} 
		else {
			i++;
			worldit++;
		}
	}
	worldset.clear();
	/* done freeing the worlds */

	vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
	size = m_polymaterials.size();

	for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
		RAS_IPolyMaterial *mat = polymit->second;
		Material *bmat = NULL;

		KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial *>(mat);
		bmat = bl_mat->GetBlenderMaterial();

		if (IS_TAGGED(bmat)) {
			/* only remove from bucket */
			polymit->first->GetBucketManager()->RemoveMaterial(mat);
		}

		i++;
		polymit++;
	}

	for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
		RAS_IPolyMaterial *mat = polymit->second;
		Material *bmat = NULL;

		KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
		bmat = bl_mat->GetBlenderMaterial();

		if (IS_TAGGED(bmat)) {
			// Remove the poly material coresponding to this Blender Material.
			m_polymat_cache[polymit->first].erase(bmat);
			delete polymit->second;
			*polymit = m_polymaterials.back();
			m_polymaterials.pop_back();
			size--;
		} else {
			i++;
			polymit++;
		}
	}

	vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
	size = m_materials.size();
	for (i = 0, matit = m_materials.begin(); i < size; ) {
		BL_Material *mat = matit->second;
		if (IS_TAGGED(mat->material)) {
			// Remove the bl material coresponding to this Blender Material.
			m_mat_cache[matit->first].erase(mat->material);
			delete matit->second;
			*matit = m_materials.back();
			m_materials.pop_back();
			size--;
		} 
		else {
			i++;
			matit++;
		}
	}

	vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
	RAS_BucketManager::BucketList::iterator bit;
	list<RAS_MeshSlot>::iterator msit;
	RAS_BucketManager::BucketList buckets;

	size = m_meshobjects.size();
	for (i = 0, meshit = m_meshobjects.begin(); i < size;) {
		RAS_MeshObject *me = meshit->second;
		if (IS_TAGGED(me->GetMesh())) {
			// Before deleting the mesh object, make sure the rasterizer is
			// no longer referencing it.
			buckets = meshit->first->GetBucketManager()->GetSolidBuckets();
			for (bit = buckets.begin(); bit != buckets.end(); bit++) {
				msit = (*bit)->msBegin();

				while (msit != (*bit)->msEnd()) {
					if (msit->m_mesh == meshit->second)
						(*bit)->RemoveMesh(&(*msit++));
					else
						msit++;
				}
			}

			// And now the alpha buckets
			buckets = meshit->first->GetBucketManager()->GetAlphaBuckets();
			for (bit = buckets.begin(); bit != buckets.end(); bit++) {
				msit = (*bit)->msBegin();

				while (msit != (*bit)->msEnd()) {
					if (msit->m_mesh == meshit->second)
						(*bit)->RemoveMesh(&(*msit++));
					else
						msit++;
				}
			}

			// Now it should be safe to delete
			delete meshit->second;
			*meshit = m_meshobjects.back();
			m_meshobjects.pop_back();
			size--;
		} 
		else {
			i++;
			meshit++;
		}
	}

#ifdef WITH_PYTHON
	/* make sure this maggie is removed from the import list if it's there
	 * (this operation is safe if it isn't in the list) */
	removeImportMain(maggie);
#endif

	delete m_status_map[maggie->name];
	m_status_map.erase(maggie->name);

	BKE_main_free(maggie);

	return true;
}
예제 #9
0
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
	Main *bmain = CTX_data_main(BPy_GetContext());
	Main *mainl = NULL;
	int err = 0;

	BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);

	/* here appending/linking starts */
	mainl = BLO_library_link_begin(bmain, &(self->blo_handle), self->relpath);

	{
		int idcode_step = 0, idcode;
		while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
			if (BKE_idcode_is_linkable(idcode)) {
				const char *name_plural = BKE_idcode_to_name_plural(idcode);
				PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
				// printf("lib: %s\n", name_plural);
				if (ls && PyList_Check(ls)) {
					/* loop */
					Py_ssize_t size = PyList_GET_SIZE(ls);
					Py_ssize_t i;

					for (i = 0; i < size; i++) {
						PyObject *item_src = PyList_GET_ITEM(ls, i);
						PyObject *item_dst;  /* must be set below */
						const char *item_idname = _PyUnicode_AsString(item_src);

						// printf("  %s\n", item_idname);

						if (item_idname) {
							ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_idname);
							if (id) {
#ifdef USE_RNA_DATABLOCKS
								/* swap name for pointer to the id */
								item_dst = PyCapsule_New((void *)id, NULL, NULL);
#else
								/* leave as is */
								continue;
#endif
							}
							else {
								bpy_lib_exit_warn_idname(self, name_plural, item_idname);
								/* just warn for now */
								/* err = -1; */
								item_dst = Py_INCREF_RET(Py_None);
							}

							/* ID or None */
						}
						else {
							/* XXX, could complain about this */
							bpy_lib_exit_warn_type(self, item_src);
							PyErr_Clear();
							item_dst = Py_INCREF_RET(Py_None);
						}

						/* item_dst must be new or already incref'd */
						Py_DECREF(item_src);
						PyList_SET_ITEM(ls, i, item_dst);
					}
				}
			}
		}
	}

	if (err == -1) {
		/* exception raised above, XXX, this leaks some memory */
		BLO_blendhandle_close(self->blo_handle);
		self->blo_handle = NULL;
		BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
		return NULL;
	}
	else {
		Library *lib = mainl->curlib; /* newly added lib, assign before append end */
		BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL);
		BLO_blendhandle_close(self->blo_handle);
		self->blo_handle = NULL;

		GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);

		/* copied from wm_operator.c */
		{
			/* mark all library linked objects to be updated */
			BKE_main_lib_objects_recalc_all(bmain);

			/* append, rather than linking */
			if ((self->flag & FILE_LINK) == 0) {
				BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
			}
		}

		BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);

		/* finally swap the capsules for real bpy objects
		 * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
#ifdef USE_RNA_DATABLOCKS
		{
			int idcode_step = 0, idcode;
			while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
				if (BKE_idcode_is_linkable(idcode)) {
					const char *name_plural = BKE_idcode_to_name_plural(idcode);
					PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
					if (ls && PyList_Check(ls)) {
						Py_ssize_t size = PyList_GET_SIZE(ls);
						Py_ssize_t i;
						PyObject *item;

						for (i = 0; i < size; i++) {
							item = PyList_GET_ITEM(ls, i);
							if (PyCapsule_CheckExact(item)) {
								PointerRNA id_ptr;
								ID *id;

								id = PyCapsule_GetPointer(item, NULL);
								id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
								Py_DECREF(item);

								RNA_id_pointer_create(id, &id_ptr);
								item = pyrna_struct_CreatePyObject(&id_ptr);
								PyList_SET_ITEM(ls, i, item);
							}
						}
					}
				}
			}
		}
#endif  /* USE_RNA_DATABLOCKS */

		BLI_ghash_free(old_to_new_ids, NULL, NULL);
		Py_RETURN_NONE;
	}
}