/* context is allowed to be NULL, do not free wm itself (library.c) */ void wm_close_and_free(bContext *C, wmWindowManager *wm) { wmWindow *win; wmOperator *op; wmKeyConfig *keyconf; if (wm->autosavetimer) wm_autosave_timer_ended(wm); while ((win = BLI_pophead(&wm->windows))) { win->screen = NULL; /* prevent draw clear to use screen */ wm_draw_window_clear(win); wm_window_free(C, wm, win); } while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } while ((keyconf = BLI_pophead(&wm->keyconfigs))) { WM_keyconfig_free(keyconf); } BLI_freelistN(&wm->queue); BLI_freelistN(&wm->paintcursors); BLI_freelistN(&wm->drags); wm_reports_free(wm); if (C && CTX_wm_manager(C) == wm) CTX_wm_manager_set(C, NULL); }
/* frees main in end */ int BKE_copybuffer_save(const char *filename, ReportList *reports) { Main *mainb = MEM_callocN(sizeof(Main), "copybuffer"); ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY]; int a, retval; /* path backup/restore */ void *path_list_backup; const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE); path_list_backup = BKE_bpath_list_backup(G.main, path_list_flag); BLO_main_expander(copybuffer_doit); BLO_expand_main(NULL, G.main); /* move over all tagged blocks */ set_listbasepointers(G.main, fromarray); a = set_listbasepointers(mainb, lbarray); while (a--) { ID *id, *nextid; ListBase *lb1 = lbarray[a], *lb2 = fromarray[a]; for (id = lb2->first; id; id = nextid) { nextid = id->next; if (id->flag & LIB_DOIT) { BLI_remlink(lb2, id); BLI_addtail(lb1, id); } } } /* save the buffer */ retval = BLO_write_file(mainb, filename, G_FILE_RELATIVE_REMAP, reports, NULL); /* move back the main, now sorted again */ set_listbasepointers(G.main, lbarray); a = set_listbasepointers(mainb, fromarray); while (a--) { ID *id; ListBase *lb1 = lbarray[a], *lb2 = fromarray[a]; while ((id = BLI_pophead(lb2))) { BLI_addtail(lb1, id); id_sort_by_name(lb1, id); } } MEM_freeN(mainb); /* set id flag to zero; */ BKE_main_id_flag_all(G.main, LIB_NEED_EXPAND | LIB_DOIT, false); if (path_list_backup) { BKE_bpath_list_restore(G.main, path_list_flag, path_list_backup); BKE_bpath_list_free(path_list_backup); } return retval; }
void WM_drag_free_list(struct ListBase *lb) { wmDrag *drag; while ((drag = BLI_pophead(lb))) { WM_drag_free(drag); } }
/** * \return Success. */ bool BKE_blendfile_write_partial( Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports) { Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer"); ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY]; int a, retval; void *path_list_backup = NULL; const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE); if (write_flags & G_FILE_RELATIVE_REMAP) { path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag); } BLO_main_expander(blendfile_write_partial_cb); BLO_expand_main(NULL, bmain_src); /* move over all tagged blocks */ set_listbasepointers(bmain_src, lbarray_src); a = set_listbasepointers(bmain_dst, lbarray_dst); while (a--) { ID *id, *nextid; ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a]; for (id = lb_src->first; id; id = nextid) { nextid = id->next; if (id->tag & LIB_TAG_DOIT) { BLI_remlink(lb_src, id); BLI_addtail(lb_dst, id); } } } /* save the buffer */ retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL); /* move back the main, now sorted again */ set_listbasepointers(bmain_src, lbarray_dst); a = set_listbasepointers(bmain_dst, lbarray_src); while (a--) { ID *id; ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a]; while ((id = BLI_pophead(lb_src))) { BLI_addtail(lb_dst, id); id_sort_by_name(lb_dst, id); } } MEM_freeN(bmain_dst); if (path_list_backup) { BKE_bpath_list_restore(bmain_src, path_list_flag, path_list_backup); BKE_bpath_list_free(path_list_backup); } return retval; }
void free_sensors(ListBase *lb) { bSensor *sens; while ((sens = BLI_pophead(lb))) { free_sensor(sens); } }
void free_actuators(ListBase *lb) { bActuator *act; while ((act = BLI_pophead(lb))) { free_actuator(act); } }
static void GPU_nodes_free(ListBase *nodes) { GPUNode *node; while ((node = BLI_pophead(nodes))) { GPU_node_free(node); } }
void BKE_displist_free(ListBase *lb) { DispList *dl; while ((dl = BLI_pophead(lb))) { BKE_displist_elem_free(dl); } }
void blf_glyph_cache_clear(FontBLF *font) { GlyphCacheBLF *gc; while ((gc = BLI_pophead(&font->cache))) { blf_glyph_cache_free(gc); } }
void free_controllers(ListBase *lb) { bController *cont; while ((cont = BLI_pophead(lb))) { if (cont->slinks) MEM_freeN(cont->slinks); free_controller(cont); } }
void WM_operator_stack_clear(wmWindowManager *wm) { wmOperator *op; while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } WM_main_add_notifier(NC_WM | ND_HISTORY, NULL); }
/* free all MetaElems from ListBase */ static void freeMetaElemlist(ListBase *lb) { MetaElem *ml; if (lb == NULL) return; while ((ml = BLI_pophead(lb))) { MEM_freeN(ml); } }
/* not memfile itself */ void BLO_memfile_free(MemFile *memfile) { MemFileChunk *chunk; while ((chunk = BLI_pophead(&memfile->chunks))) { if (chunk->ident == 0) MEM_freeN(chunk->buf); MEM_freeN(chunk); } memfile->size = 0; }
/* helper for find_nearest_fcurve_vert() - get the best match to use */ static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches) { tNearestVertInfo *nvi = NULL; short found = 0; /* abort if list is empty */ if (BLI_listbase_is_empty(matches)) return NULL; /* if list only has 1 item, remove it from the list and return */ if (BLI_listbase_is_single(matches)) { /* need to remove from the list, otherwise it gets freed and then we can't return it */ return BLI_pophead(matches); } /* try to find the first selected F-Curve vert, then take the one after it */ for (nvi = matches->first; nvi; nvi = nvi->next) { /* which mode of search are we in: find first selected, or find vert? */ if (found) { /* just take this vert now that we've found the selected one * - we'll need to remove this from the list so that it can be returned to the original caller */ BLI_remlink(matches, nvi); return nvi; } else { /* if vert is selected, we've got what we want... */ if (nvi->sel) found = 1; } } /* if we're still here, this means that we failed to find anything appropriate in the first pass, * so just take the first item now... */ return BLI_pophead(matches); }
void blf_glyph_cache_free(GlyphCacheBLF *gc) { GlyphBLF *g; int i; for (i = 0; i < 257; i++) { while ((g = BLI_pophead(&gc->bucket[i]))) { blf_glyph_free(g); } } if (gc->cur_tex != BLF_CURTEX_UNSET) glDeleteTextures((int)gc->cur_tex + 1, gc->textures); MEM_freeN((void *)gc->textures); MEM_freeN(gc); }
void blf_font_free(FontBLF *font) { GlyphCacheBLF *gc; font->glyph_cache = NULL; while ((gc = BLI_pophead(&font->cache))) { blf_glyph_cache_free(gc); } FT_Done_Face(font->face); if (font->filename) MEM_freeN(font->filename); if (font->name) MEM_freeN(font->name); MEM_freeN(font); }
static int bake( Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const ScenePassType pass_type, const int margin, const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[], const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; float *result = NULL; BakePixel *pixel_array_low = NULL; BakePixel *pixel_array_high = NULL; const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); const bool is_noncolor = is_noncolor_pass(pass_type); const int depth = RE_pass_depth(pass_type); BakeImages bake_images = {NULL}; size_t num_pixels; int tot_materials; RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } tot_materials = ob_low->totcol; if (uv_layer && uv_layer[0] != '\0') { Mesh *me = (Mesh *)ob_low->data; if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { BKE_reportf(reports, RPT_ERROR, "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); goto cleanup; } } if (tot_materials == 0) { if (is_save_internal) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); goto cleanup; } else if (is_split_materials) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake without the Split Materials option"); goto cleanup; } else { /* baking externally without splitting materials */ tot_materials = 1; } } /* we overallocate in case there is more materials than images */ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = (size_t)width * (size_t)height * bake_images.size; for (int i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; bake_images.data[i].height = height; bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); bake_images.data[i].image = NULL; } if (!is_split_materials) { /* saving a single image */ for (int i = 0; i < tot_materials; i++) { bake_images.lookup[i] = 0; } } } if (is_selected_to_active) { CollectionPointerLink *link; tot_highpoly = 0; for (link = selected_objects->first; link; link = link->next) { Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; tot_highpoly ++; } if (is_cage && custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; ob_cage->restrictflag |= OB_RESTRICT_RENDER; } } } pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ if (is_selected_to_active) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; int i = 0; /* prepare cage mesh */ if (ob_cage) { me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " "of faces as the active object"); goto cleanup; } } else if (is_cage) { modifiers_original = ob_low->modifiers; BLI_listbase_clear(&modifiers_tmp); for (md = ob_low->modifiers.first; md; md = md->next) { /* Edge Split cannot be applied in the cage, * the cage is supposed to have interpolated normals * between the faces unless the geometry is physically * split. So we create a copy of the low poly mesh without * the eventual edge split.*/ if (md->type == eModifierType_EdgeSplit) continue; nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); modifier_copyData(md, nmd); BLI_addtail(&modifiers_tmp, nmd); } /* temporarily replace the modifiers */ ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* populate highpoly array */ for (link = selected_objects->first; link; link = link->next) { TriangulateModifierData *tmd; Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; /* initialize highpoly_data */ highpoly[i].ob = ob_iter; highpoly[i].restrict_flag = ob_iter->restrictflag; /* triangulating so BVH returns the primitive_id that will be used for rendering */ highpoly[i].tri_mod = ED_object_modifier_add( reports, bmain, scene, highpoly[i].ob, "TmpTriangulate", eModifierType_Triangulate); tmd = (TriangulateModifierData *)highpoly[i].tri_mod; tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; BKE_mesh_split_faces(highpoly[i].me); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); i++; } BLI_assert(i == tot_highpoly); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cage_cleanup; } /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, num_pixels, depth, pass_type, result); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); goto cage_cleanup; } } cage_cleanup: /* reverting data back */ if ((ob_cage == NULL) && is_cage) { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } if (!ok) { goto cleanup; } } else { /* make sure low poly renders */ ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) { ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result); } else { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (ok && pass_type == SCE_PASS_NORMAL) { switch (normal_space) { case R_BAKE_SPACE_WORLD: { /* Cycles internal format */ if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && (normal_swizzle[2] == R_BAKE_POSZ)) { break; } else { RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); } break; } case R_BAKE_SPACE_OBJECT: { RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle); break; } case R_BAKE_SPACE_TANGENT: { if (is_selected_to_active) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat); } else { /* from multiresolution */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; md = modifiers_findByType(ob_low, eModifierType_Multires); if (md) { mode = md->mode; md->mode &= ~eModifierMode_Render; } me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_nores); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (int i = 0; i < bake_images.size; i++) { BakeImage *bk_image = &bake_images.data[i]; if (is_save_internal) { ok = write_internal_bake_pixels( bk_image->image, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, is_clear, is_noncolor); /* might be read by UI to set active image for display */ bake_update_image(sa, bk_image->image); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { BKE_report(reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it"); op_result = OPERATOR_FINISHED; } } /* save externally */ else { BakeData *bake = &scene->r.bake; char name[FILE_MAX]; BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); BLI_path_suffix(name, FILE_MAX, identifier, "_"); } if (is_split_materials) { if (bk_image->image) { BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); } else { if (ob_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_"); } else if (me_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); } else { /* if everything else fails, use the material index */ char tmp[4]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } } /* save it externally */ ok = write_external_bake_pixels( name, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, &bake->im_format, is_noncolor); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); op_result = OPERATOR_CANCELLED; } else { BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); op_result = OPERATOR_FINISHED; } if (!is_split_materials) { break; } } } } if (is_save_internal) refresh_images(&bake_images); cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].tri_mod) ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); if (highpoly[i].me) BKE_libblock_free(bmain, highpoly[i].me); } MEM_freeN(highpoly); } ob_low->restrictflag = restrict_flag_low; if (ob_cage) ob_cage->restrictflag = restrict_flag_cage; if (pixel_array_low) MEM_freeN(pixel_array_low); if (pixel_array_high) MEM_freeN(pixel_array_high); if (bake_images.data) MEM_freeN(bake_images.data); if (bake_images.lookup) MEM_freeN(bake_images.lookup); if (result) MEM_freeN(result); if (me_low) BKE_libblock_free(bmain, me_low); if (me_cage) BKE_libblock_free(bmain, me_cage); return op_result; }
/** * \return Success. */ bool BKE_blendfile_write_partial( Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports) { Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer"); ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY]; int a, retval; void *path_list_backup = NULL; const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE); /* This is needed to be able to load that file as a real one later * (otherwise main->name will not be set at read time). */ BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name)); BLO_main_expander(blendfile_write_partial_cb); BLO_expand_main(NULL, bmain_src); /* move over all tagged blocks */ set_listbasepointers(bmain_src, lbarray_src); a = set_listbasepointers(bmain_dst, lbarray_dst); while (a--) { ID *id, *nextid; ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a]; for (id = lb_src->first; id; id = nextid) { nextid = id->next; if (id->tag & LIB_TAG_DOIT) { BLI_remlink(lb_src, id); BLI_addtail(lb_dst, id); } } } /* Backup paths because remap relative will overwrite them. * * NOTE: we do this only on the list of datablocks that we are writing * because the restored full list is not guaranteed to be in the same * order as before, as expected by BKE_bpath_list_restore. * * This happens because id_sort_by_name does not take into account * string case or the library name, so the order is not strictly * defined for two linked datablocks with the same name! */ if (write_flags & G_FILE_RELATIVE_REMAP) { path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag); } /* save the buffer */ retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL); if (path_list_backup) { BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup); BKE_bpath_list_free(path_list_backup); } /* move back the main, now sorted again */ set_listbasepointers(bmain_src, lbarray_dst); a = set_listbasepointers(bmain_dst, lbarray_src); while (a--) { ID *id; ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a]; while ((id = BLI_pophead(lb_src))) { BLI_addtail(lb_dst, id); id_sort_by_name(lb_dst, id); } } MEM_freeN(bmain_dst); return retval; }