Esempio n. 1
0
// get pointer to material
RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID)
{
	// if object is available
	if (obj != NULL)
	{
		// get pointer to texture image
		KX_GameObject * gameObj = gameObjectType.checkType(obj);
		if (gameObj != NULL && gameObj->GetMeshCount() > 0)
		{
			// get material from mesh
			RAS_MeshObject * mesh = gameObj->GetMesh(0);
			RAS_MeshMaterial *meshMat = mesh->GetMeshMaterial(matID);
			if (meshMat != NULL && meshMat->m_bucket != NULL)
				// return pointer to polygon or blender material
				return meshMat->m_bucket->GetPolyMaterial();
		}
	}
	// otherwise material was not found
	return NULL;
}
/* 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;
}