Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_bake_api.c
| Show All 40 Lines | |||||
| #include "RNA_enum_types.h" | #include "RNA_enum_types.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_fileops.h" | #include "BLI_fileops.h" | ||||
| #include "BLI_math_geom.h" | #include "BLI_math_geom.h" | ||||
| #include "BLI_path_util.h" | #include "BLI_path_util.h" | ||||
| #include "BKE_anim.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_image.h" | #include "BKE_image.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_node.h" | #include "BKE_node.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| ▲ Show 20 Lines • Show All 486 Lines • ▼ Show 20 Lines | else { | ||||
| BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2); | BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| BKE_image_release_ibuf(bk_image->image, ibuf, lock); | BKE_image_release_ibuf(bk_image->image, ibuf, lock); | ||||
| } | } | ||||
| return tot_size; | return tot_size; | ||||
| } | } | ||||
| static ModifierData *bake_triangulate_modifier(Main *bmain, Scene *scene, Object *ob, ReportList *reports) | |||||
| { | |||||
| ModifierData *tri_mod; | |||||
| TriangulateModifierData *tmd; | |||||
| /* triangulating so BVH returns the primitive_id that will be used for rendering */ | |||||
| tri_mod = ED_object_modifier_add( | |||||
| reports, bmain, scene, ob, | |||||
| "TmpTriangulate", eModifierType_Triangulate); | |||||
| tmd = (TriangulateModifierData *)tri_mod; | |||||
| tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; | |||||
| tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; | |||||
| return tri_mod; | |||||
| } | |||||
campbellbarton: Realize its not directly related to this patch (since the triangulate modifier was used… | |||||
| /* get the lookup mesh id, creates one entry if necessary */ | |||||
| static int bake_mesh_get(Main *bmain, Scene *scene, BakeHighPolyMesh **meshes, Object *ob, ReportList *reports) | |||||
| { | |||||
| BakeHighPolyMesh *mesh; | |||||
| int i = 0; | |||||
| while ((mesh = meshes[i])) { | |||||
| if (mesh->ob == ob) { | |||||
| return i; | |||||
| } | |||||
| i++; | |||||
| } | |||||
| mesh = MEM_callocN(sizeof(BakeHighPolyMesh), "Bake Mesh Lookup Entry"); | |||||
| mesh->ob = ob; | |||||
| mesh->restrict_flag = ob->restrictflag; | |||||
| mesh->tri_mod = bake_triangulate_modifier(bmain, scene, ob, reports); | |||||
| mesh->me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0); | |||||
| BKE_mesh_split_faces(mesh->me); | |||||
| BKE_mesh_tessface_ensure(mesh->me); | |||||
| meshes[i] = mesh; | |||||
| return i; | |||||
| } | |||||
| static void bake_highpoly_setup( | |||||
| Main *bmain, Scene *scene, | |||||
| BakeHighPolyData *highpoly, | |||||
| BakeHighPolyMesh **meshes, | |||||
| Object *ob, float obmat[4][4], | |||||
| const char *name, const bool is_dupli, | |||||
| ReportList *reports) | |||||
| { | |||||
| /* initialize highpoly_data */ | |||||
| highpoly->ob = ob; | |||||
| highpoly->name = name; | |||||
| highpoly->is_dupli_object = is_dupli; | |||||
| if (!is_dupli) { | |||||
| highpoly->ob->restrictflag &= ~OB_RESTRICT_RENDER; | |||||
| } | |||||
| /* lowpoly to highpoly transformation matrix */ | |||||
| copy_m4_m4(highpoly->obmat, obmat); | |||||
| invert_m4_m4(highpoly->imat, highpoly->obmat); | |||||
| highpoly->is_flip_object = is_negative_m4(obmat); | |||||
| highpoly->mesh_lookup_id = bake_mesh_get(bmain, scene, meshes, ob, reports); | |||||
| } | |||||
| static int bake( | static int bake( | ||||
| Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, | Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, | ||||
| const ScenePassType pass_type, const int margin, | const ScenePassType pass_type, const int margin, | ||||
| const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, | 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 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 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 *custom_cage, const char *filepath, const int width, const int height, | ||||
| const char *identifier, ScrArea *sa, const char *uv_layer) | const char *identifier, ScrArea *sa, const char *uv_layer) | ||||
| { | { | ||||
| int op_result = OPERATOR_CANCELLED; | int op_result = OPERATOR_CANCELLED; | ||||
| bool ok = false; | bool ok = false; | ||||
| Object *ob_cage = NULL; | Object *ob_cage = NULL; | ||||
| BakeHighPolyData *highpoly = NULL; | BakeHighPolyData *highpoly = NULL; | ||||
| int tot_highpoly; | int tot_highpoly; | ||||
| int tot_dupli; | |||||
| int tot_mesh_objects; | |||||
| char restrict_flag_low = ob_low->restrictflag; | char restrict_flag_low = ob_low->restrictflag; | ||||
| char restrict_flag_cage = 0; | char restrict_flag_cage = 0; | ||||
| Mesh *me_low = NULL; | Mesh *me_low = NULL; | ||||
| Mesh *me_cage = NULL; | Mesh *me_cage = NULL; | ||||
| float *result = NULL; | float *result = NULL; | ||||
| BakePixel *pixel_array_low = NULL; | BakePixel *pixel_array_low = NULL; | ||||
| BakePixel *pixel_array_high = NULL; | BakePixel *pixel_array_high = NULL; | ||||
| const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); | const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); | ||||
| const bool is_noncolor = is_noncolor_pass(pass_type); | const bool is_noncolor = is_noncolor_pass(pass_type); | ||||
| const int depth = RE_pass_depth(pass_type); | const int depth = RE_pass_depth(pass_type); | ||||
| BakeImages bake_images = {NULL}; | BakeImages bake_images = {NULL}; | ||||
| size_t num_pixels; | size_t num_pixels; | ||||
| int tot_materials; | int tot_materials; | ||||
| int i; | int i; | ||||
| ListBase **dupli_list_arr = NULL; | |||||
| BakeHighPolyMesh **meshes_lookup_arr = NULL; | |||||
| RE_bake_engine_set_engine_parameters(re, bmain, scene); | RE_bake_engine_set_engine_parameters(re, bmain, scene); | ||||
| if (!RE_bake_has_engine(re)) { | if (!RE_bake_has_engine(re)) { | ||||
| BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); | BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| tot_materials = ob_low->totcol; | tot_materials = ob_low->totcol; | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (!is_split_materials) { | ||||
| for (i = 0; i < tot_materials; i++) | for (i = 0; i < tot_materials; i++) | ||||
| bake_images.lookup[i] = 0; | bake_images.lookup[i] = 0; | ||||
| } | } | ||||
| } | } | ||||
| if (is_selected_to_active) { | if (is_selected_to_active) { | ||||
| CollectionPointerLink *link; | CollectionPointerLink *link; | ||||
| tot_highpoly = 0; | tot_highpoly = 0; | ||||
| tot_dupli = 0; | |||||
| for (link = selected_objects->first; link; link = link->next) { | for (link = selected_objects->first; link; link = link->next) { | ||||
| Object *ob_iter = link->ptr.data; | Object *ob_iter = link->ptr.data; | ||||
| if (ob_iter == ob_low) | if (ob_iter == ob_low) | ||||
| continue; | continue; | ||||
| if ((ob_iter->transflag & OB_DUPLI) == 0) | |||||
| tot_highpoly ++; | tot_highpoly ++; | ||||
| else | |||||
| tot_dupli ++; | |||||
| } | } | ||||
| if (is_cage && custom_cage[0] != '\0') { | if (is_cage && custom_cage[0] != '\0') { | ||||
| ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); | ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); | ||||
| if (ob_cage == NULL || ob_cage->type != OB_MESH) { | if (ob_cage == NULL || ob_cage->type != OB_MESH) { | ||||
| BKE_report(reports, RPT_ERROR, "No valid cage object"); | BKE_report(reports, RPT_ERROR, "No valid cage object"); | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| else { | else { | ||||
| restrict_flag_cage = ob_cage->restrictflag; | restrict_flag_cage = ob_cage->restrictflag; | ||||
| ob_cage->restrictflag |= OB_RESTRICT_RENDER; | ob_cage->restrictflag |= OB_RESTRICT_RENDER; | ||||
| } | } | ||||
| } | } | ||||
| if (tot_dupli > 0) { | |||||
| DupliObject *dob; | |||||
| int i = 0; | |||||
| dupli_list_arr = MEM_callocN(sizeof(ListBase *) * tot_dupli, "bake dupli object lists"); | |||||
| for (link = selected_objects->first; link; link = link->next) { | |||||
| Object *ob_iter = link->ptr.data; | |||||
| if (ob_iter == ob_low) | |||||
| continue; | |||||
| if ((ob_iter->transflag & OB_DUPLI) != 0) { | |||||
| dupli_list_arr[i] = object_duplilist(bmain->eval_ctx, scene, ob_iter); | |||||
| for (dob = dupli_list_arr[i]->first; dob; dob = dob->next) { | |||||
| if (dob->ob->type == OB_MESH) { | |||||
| tot_highpoly ++; | |||||
| } | |||||
| } | |||||
| i++; | |||||
| } | |||||
| } | |||||
| } | |||||
| tot_mesh_objects = tot_highpoly; | |||||
| /* we overallocate in case all objects are unique */ | |||||
| meshes_lookup_arr = MEM_callocN(sizeof(BakeHighPolyMesh *) * tot_mesh_objects, "Bake Mesh Lookup All"); | |||||
| } | } | ||||
| pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); | 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"); | pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); | ||||
| result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); | result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); | ||||
| /* get the mesh as it arrives in the renderer */ | /* get the mesh as it arrives in the renderer */ | ||||
| me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); | me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); | ||||
| BKE_mesh_split_faces(me_low); | BKE_mesh_split_faces(me_low); | ||||
| BKE_mesh_tessface_ensure(me_low); | BKE_mesh_tessface_ensure(me_low); | ||||
| /* populate the pixel array with the face data */ | /* populate the pixel array with the face data */ | ||||
| if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) | 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); | 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) */ | /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ | ||||
| if (is_selected_to_active) { | if (is_selected_to_active) { | ||||
| CollectionPointerLink *link; | CollectionPointerLink *link; | ||||
| ModifierData *md, *nmd; | ModifierData *md, *nmd; | ||||
| ListBase modifiers_tmp, modifiers_original; | ListBase modifiers_tmp, modifiers_original; | ||||
| int i = 0; | int i = 0; /* highpoly object index */ | ||||
| int j = 0; /* duplilist index */ | |||||
| /* prepare cage mesh */ | /* prepare cage mesh */ | ||||
| if (ob_cage) { | if (ob_cage) { | ||||
| me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); | me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); | ||||
| BKE_mesh_split_faces(me_cage); | BKE_mesh_split_faces(me_cage); | ||||
| BKE_mesh_tessface_ensure(me_cage); | BKE_mesh_tessface_ensure(me_cage); | ||||
| if (me_low->totface != me_cage->totface) { | if (me_low->totface != me_cage->totface) { | ||||
| BKE_report(reports, RPT_ERROR, | BKE_report(reports, RPT_ERROR, | ||||
| Show All 31 Lines | else if (is_cage) { | ||||
| BKE_mesh_tessface_ensure(me_cage); | BKE_mesh_tessface_ensure(me_cage); | ||||
| RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); | 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"); | highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); | ||||
| /* populate highpoly array */ | /* populate highpoly array */ | ||||
| for (link = selected_objects->first; link; link = link->next) { | for (link = selected_objects->first; link; link = link->next) { | ||||
| TriangulateModifierData *tmd; | |||||
| Object *ob_iter = link->ptr.data; | Object *ob_iter = link->ptr.data; | ||||
| if (ob_iter == ob_low) | if (ob_iter == ob_low) | ||||
| continue; | continue; | ||||
| /* initialize highpoly_data */ | if ((ob_iter->transflag & OB_DUPLI) == 0) { | ||||
| highpoly[i].ob = ob_iter; | bake_highpoly_setup(bmain, scene, &highpoly[i], meshes_lookup_arr, ob_iter, ob_iter->obmat, ob_iter->id.name, false, reports); | ||||
| highpoly[i].restrict_flag = ob_iter->restrictflag; | unit_m4(highpoly[i].mat); | ||||
| i++; | |||||
| /* triangulating so BVH returns the primitive_id that will be used for rendering */ | } | ||||
| highpoly[i].tri_mod = ED_object_modifier_add( | else { | ||||
| reports, bmain, scene, highpoly[i].ob, | DupliObject *dob; | ||||
| "TmpTriangulate", eModifierType_Triangulate); | float imat[4][4]; | ||||
| tmd = (TriangulateModifierData *)highpoly[i].tri_mod; | invert_m4_m4(imat, ob_iter->obmat); | ||||
| tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; | |||||
| tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; | for (dob = dupli_list_arr[j]->first; dob; dob = dob->next) { | ||||
| if (dob->ob->type == OB_MESH) { | |||||
| highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); | /* note: dob->mat is already in world space, no need to multiply by the parent */ | ||||
| highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; | bake_highpoly_setup(bmain, scene, &highpoly[i], meshes_lookup_arr, dob->ob, dob->mat, ob_iter->id.name, true, reports); | ||||
| BKE_mesh_split_faces(highpoly[i].me); | |||||
| BKE_mesh_tessface_ensure(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); | /* calculate the baking matrix (from the original object to the dupli) */ | ||||
| mul_m4_m4m4(highpoly[i].mat, imat, dob->mat); | |||||
| i++; | i++; | ||||
| } | } | ||||
| } | |||||
| free_object_duplilist(dupli_list_arr[j]); | |||||
| j++; | |||||
| } | |||||
| } | |||||
| BLI_assert(i == tot_highpoly); | BLI_assert(i == tot_highpoly); | ||||
| BLI_assert(j == tot_dupli); | |||||
| if (dupli_list_arr) | |||||
| MEM_freeN(dupli_list_arr); | |||||
| /* get real mesh count */ | |||||
| for (i = 0; i < tot_mesh_objects; i++) { | |||||
| if (meshes_lookup_arr[i] == NULL) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| tot_mesh_objects = i; | |||||
| ob_low->restrictflag |= OB_RESTRICT_RENDER; | ob_low->restrictflag |= OB_RESTRICT_RENDER; | ||||
| /* populate the pixel arrays with the corresponding face data for each high poly object */ | /* populate the pixel arrays with the corresponding face data for each high poly object */ | ||||
| if (!RE_bake_pixels_populate_from_objects( | if (!RE_bake_pixels_populate_from_objects( | ||||
| me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, | me_low, pixel_array_low, pixel_array_high, | ||||
| cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) | meshes_lookup_arr, tot_mesh_objects, | ||||
| 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"); | BKE_report(reports, RPT_ERROR, "Error handling selected objects"); | ||||
| goto cage_cleanup; | goto cage_cleanup; | ||||
| } | } | ||||
| /* free some memory before the baking */ | |||||
| if (meshes_lookup_arr) { | |||||
| for (i = 0; i < tot_mesh_objects; i++) { | |||||
| if (meshes_lookup_arr[i]->me) { | |||||
| BKE_libblock_free(bmain, meshes_lookup_arr[i]->me); | |||||
| meshes_lookup_arr[i]->me = NULL; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* the baking itself */ | /* the baking itself */ | ||||
| for (i = 0; i < tot_highpoly; i++) { | for (i = 0; i < tot_highpoly; i++) { | ||||
| ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, | ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, | ||||
| num_pixels, depth, pass_type, result); | num_pixels, depth, pass_type, | ||||
| highpoly[i].is_dupli_object ? (float *)highpoly[i].mat : NULL, | |||||
| result); | |||||
| if (!ok) { | if (!ok) { | ||||
| BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); | BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].name + 2); | ||||
| goto cage_cleanup; | goto cage_cleanup; | ||||
| } | } | ||||
| } | } | ||||
| cage_cleanup: | cage_cleanup: | ||||
| /* reverting data back */ | /* reverting data back */ | ||||
| if ((ob_cage == NULL) && is_cage) { | if ((ob_cage == NULL) && is_cage) { | ||||
| ob_low->modifiers = modifiers_original; | ob_low->modifiers = modifiers_original; | ||||
| while ((md = BLI_pophead(&modifiers_tmp))) { | while ((md = BLI_pophead(&modifiers_tmp))) { | ||||
| modifier_free(md); | modifier_free(md); | ||||
| } | } | ||||
| } | } | ||||
| if (!ok) { | if (!ok) { | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* make sure low poly renders */ | /* make sure low poly renders */ | ||||
| ob_low->restrictflag &= ~OB_RESTRICT_RENDER; | ob_low->restrictflag &= ~OB_RESTRICT_RENDER; | ||||
| if (RE_bake_has_engine(re)) { | if (RE_bake_has_engine(re)) { | ||||
| ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result); | ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, NULL, result); | ||||
| } | } | ||||
Not Done Inline ActionsNo strong opinion. But this could just be a NULL argument. to avoid doing any transformation. (since this is such a common case) campbellbarton: No strong opinion. But this could just be a `NULL` argument. to avoid doing any transformation. | |||||
| else { | else { | ||||
| BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); | BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| } | } | ||||
| /* normal space conversion | /* normal space conversion | ||||
| * the normals are expected to be in world space, +X +Y +Z */ | * the normals are expected to be in world space, +X +Y +Z */ | ||||
| ▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| if (is_save_internal) | if (is_save_internal) | ||||
| refresh_images(&bake_images); | refresh_images(&bake_images); | ||||
| cleanup: | cleanup: | ||||
| if (highpoly) { | if (highpoly) | ||||
| MEM_freeN(highpoly); | |||||
| if (meshes_lookup_arr) { | |||||
| int i; | int i; | ||||
| for (i = 0; i < tot_highpoly; i++) { | for (i = 0; i < tot_mesh_objects; i++) { | ||||
| highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; | if (meshes_lookup_arr[i]) { | ||||
| if (highpoly[i].tri_mod) | meshes_lookup_arr[i]->ob->restrictflag = meshes_lookup_arr[i]->restrict_flag; | ||||
| ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); | |||||
| if (highpoly[i].me) | if (meshes_lookup_arr[i]->tri_mod) { | ||||
| BKE_libblock_free(bmain, highpoly[i].me); | ED_object_modifier_remove(reports, bmain, meshes_lookup_arr[i]->ob, meshes_lookup_arr[i]->tri_mod); | ||||
| } | } | ||||
| MEM_freeN(highpoly); | |||||
| if (meshes_lookup_arr[i]->me) { | |||||
| BKE_libblock_free(bmain, meshes_lookup_arr[i]->me); | |||||
| } | |||||
| MEM_freeN(meshes_lookup_arr[i]); | |||||
| } | |||||
| } | |||||
| MEM_freeN(meshes_lookup_arr); | |||||
| } | } | ||||
| ob_low->restrictflag = restrict_flag_low; | ob_low->restrictflag = restrict_flag_low; | ||||
| if (ob_cage) | if (ob_cage) | ||||
| ob_cage->restrictflag = restrict_flag_cage; | ob_cage->restrictflag = restrict_flag_cage; | ||||
| if (pixel_array_low) | if (pixel_array_low) | ||||
| ▲ Show 20 Lines • Show All 368 Lines • Show Last 20 Lines | |||||
Realize its not directly related to this patch (since the triangulate modifier was used already), but think we could use tessface layout, or have a version of BKE_mesh_recalc_tessellation that outputs MPoly tri's instead of MFace's\
Would avoid going via BMesh conversion.