/* executes blocking render */ static int screen_render_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; Render *re; Image *ima; View3D *v3d = CTX_wm_view3d(C); Main *mainp = CTX_data_main(C); unsigned int lay_override; const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; /* custom scene and single layer re-render */ screen_render_scene_layer_set(op, mainp, &scene, &srl); if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return OPERATOR_CANCELLED; } re = RE_NewRender(scene->id.name); lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = false; RE_test_break_cb(re, NULL, render_break); ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(scene, ima); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(); RE_SetReports(re, op->reports); BLI_begin_threaded_malloc(); if (is_animation) RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step); else RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay_override, scene->r.cfra, is_write_still); BLI_end_threaded_malloc(); RE_SetReports(re, NULL); // no redraw needed, we leave state as we entered it ED_update_for_newframe(mainp, scene, 1); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); return OPERATOR_FINISHED; }
static int bake_exec(bContext *C, wmOperator *op) { Render *re; int result = OPERATOR_CANCELLED; BakeAPIRender bkr = {NULL}; bake_init_api_data(op, C, &bkr); re = bkr.render; /* setup new render */ RE_test_break_cb(re, NULL, bake_break); if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { goto finally; } if (bkr.is_clear) { const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT)); bake_images_clear(bkr.main, is_tangent); } RE_SetReports(re, bkr.reports); if (bkr.is_selected_to_active) { result = bake( bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.pass_type, bkr.margin, bkr.save_mode, bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa, bkr.uv_layer); } else { CollectionPointerLink *link; const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects); for (link = bkr.selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; result = bake( bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports, bkr.pass_type, bkr.margin, bkr.save_mode, is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa, bkr.uv_layer); } } RE_SetReports(re, NULL); finally: BLI_freelistN(&bkr.selected_objects); return result; }
static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress) { BakeAPIRender *bkr = (BakeAPIRender *)bkv; /* setup new render */ bkr->do_update = do_update; bkr->progress = progress; RE_SetReports(bkr->render, bkr->reports); if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) { bkr->result = OPERATOR_CANCELLED; return; } if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { bkr->result = OPERATOR_CANCELLED; return; } if (bkr->is_clear) { const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT)); bake_images_clear(bkr->main, is_tangent); } if (bkr->is_selected_to_active) { bkr->result = bake( bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa, bkr->uv_layer); } else { CollectionPointerLink *link; const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects); for (link = bkr->selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; bkr->result = bake( bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports, bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa, bkr->uv_layer); if (bkr->result == OPERATOR_CANCELLED) return; } } RE_SetReports(bkr->render, NULL); }
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress) { RenderJob *rj = rjv; rj->stop = stop; rj->do_update = do_update; rj->progress = progress; RE_SetReports(rj->re, rj->reports); if (rj->anim) RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step); else RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay, rj->scene->r.cfra, rj->write_still); RE_SetReports(rj->re, NULL); }
static int render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data) { bContext *C = data; if (CTX_data_scene(C)) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Render *re= RE_NewRender(scene->id.name); ReportList reports; BKE_reports_init(&reports, RPT_PRINT); RE_SetReports(re, &reports); RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step); RE_SetReports(re, NULL); } else { printf("\nError: no blend loaded. cannot use '-a'.\n"); } return 0; }
/* executes blocking render */ static int screen_render_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Render *re= RE_NewRender(scene->id.name); Image *ima; View3D *v3d= CTX_wm_view3d(C); Main *mainp= CTX_data_main(C); unsigned int lay= (v3d)? v3d->lay: scene->lay; const short is_animation= RNA_boolean_get(op->ptr, "animation"); const short is_write_still= RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) { BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected."); return OPERATOR_CANCELLED; } G.afbreek= 0; RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break); ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(scene, ima); /* cleanup sequencer caches before starting user triggered render. otherwise, invalidated cache entries can make their way into the output rendering. We can't put that into RE_BlenderFrame, since sequence rendering can call that recursively... (peter) */ seq_stripelem_cache_cleanup(); RE_SetReports(re, op->reports); if(is_animation) RE_BlenderAnim(re, mainp, scene, camera_override, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step); else RE_BlenderFrame(re, mainp, scene, NULL, camera_override, lay, scene->r.cfra, is_write_still); RE_SetReports(re, NULL); // no redraw needed, we leave state as we entered it ED_update_for_newframe(mainp, scene, CTX_wm_screen(C), 1); WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); return OPERATOR_FINISHED; }
static int render_frame(int argc, const char **argv, void *data) { bContext *C = data; Scene *scene = CTX_data_scene(C); if (scene) { Main *bmain = CTX_data_main(C); if (argc > 1) { Render *re = RE_NewRender(scene->id.name); int frame; ReportList reports; switch (*argv[1]) { case '+': frame = scene->r.sfra + atoi(argv[1] + 1); break; case '-': frame = (scene->r.efra - atoi(argv[1] + 1)) + 1; break; default: frame = atoi(argv[1]); break; } BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_PRINT); frame = CLAMPIS(frame, MINAFRAME, MAXFRAME); RE_SetReports(re, &reports); RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step); RE_SetReports(re, NULL); BLI_end_threaded_malloc(); return 1; } else { printf("\nError: frame number must follow '-f / --render-frame'.\n"); return 0; } } else { printf("\nError: no blend loaded. cannot use '-f / --render-frame'.\n"); return 0; } }
/* executes blocking blensor */ static int screen_blensor_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); static Render *re=NULL; Image *ima; View3D *v3d= CTX_wm_view3d(C); Main *mainp= CTX_data_main(C); unsigned int lay= (v3d)? v3d->lay: scene->lay; float *rays; float *returns; char ray_ptr_str[17]; char return_ptr_str[17]; /* add modal handler for ESC */ const int raycount= RNA_int_get(op->ptr, "raycount"); const int elements_per_ray= RNA_int_get(op->ptr, "elements_per_ray"); const int keep_render_setup = RNA_boolean_get(op->ptr, "keep_render_setup"); const int shading = RNA_boolean_get(op->ptr, "shading"); const float maximum_distance =RNA_float_get(op->ptr, "maximum_distance"); struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; RNA_string_get(op->ptr, "vector_strptr", ray_ptr_str); RNA_string_get(op->ptr, "return_vector_strptr", return_ptr_str); rays = (float *)convert_str_to_ptr(ray_ptr_str); returns = (float *)convert_str_to_ptr(return_ptr_str); if (raycount > 0) { printf ("Raycount: %d\n",raycount); if(re==NULL) { re = RE_NewRender(scene->id.name); } G.is_break = FALSE; //RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break); ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(scene, ima); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(); RE_SetReports(re, op->reports); RE_BlensorFrame(re, mainp, scene, NULL, camera_override, lay, scene->r.cfra, 0, rays, raycount, elements_per_ray, returns, maximum_distance, keep_render_setup, shading); RE_SetReports(re, NULL); // no redraw needed, we leave state as we entered it ED_update_for_newframe(mainp, scene, 1); WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); if (keep_render_setup == 0) { re = NULL; } } return OPERATOR_FINISHED; }
static int bake( 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 use_selected_to_active, 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) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly; int tot_highpoly; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage; Mesh *me_low = NULL; Render *re; float *result = NULL; BakePixel *pixel_array_low = 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); bool is_highpoly = false; bool is_tangent; BakeImages bake_images = {NULL}; int num_pixels; int tot_materials; int i; re = RE_NewRender(scene->id.name); is_tangent = pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT; tot_materials = ob_low->totcol; 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_callocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_callocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); if (!build_image_lookup(bmain, ob_low, &bake_images, reports)) goto cleanup; if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } if (is_clear) { RE_bake_ibuf_clear(&bake_images, is_tangent); } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = width * height * bake_images.size; for (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 (i = 0; i < tot_materials; i++) bake_images.lookup[i] = 0; } } if (use_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 (tot_highpoly == 0) { BKE_report(reports, RPT_ERROR, "No valid selected objects"); op_result = OPERATOR_CANCELLED; goto cleanup; } else { is_highpoly = true; } } if (custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); /* TODO check if cage object has the same topology (num of triangles and a valid UV) */ if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); op_result = OPERATOR_CANCELLED; goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; } } RE_bake_engine_set_engine_parameters(re, bmain, scene); /* blender_test_break uses this global */ G.is_break = false; RE_test_break_cb(re, NULL, bake_break); pixel_array_low = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); if (is_highpoly) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; float mat_low[4][4]; int i = 0; highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* prepare cage mesh */ if (ob_cage) { me_low = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0); copy_m4_m4(mat_low, ob_cage->obmat); } else { 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_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0); copy_m4_m4(mat_low, ob_low->obmat); } /* 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].me = NULL; highpoly[i].tri_mod = NULL; highpoly[i].restrict_flag = ob_iter->restrictflag; highpoly[i].pixel_array = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); /* 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, 1, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; /* lowpoly to highpoly transformation matrix */ invert_m4_m4(highpoly[i].mat_lowtohigh, highpoly[i].ob->obmat); mul_m4_m4m4(highpoly[i].mat_lowtohigh, highpoly[i].mat_lowtohigh, mat_low); i++; } BLI_assert(i == tot_highpoly); /* populate the pixel array with the face data */ RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, highpoly, tot_highpoly, num_pixels, cage_extrusion); /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { if (RE_bake_has_engine(re)) { ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels, depth, pass_type, result); } else { ok = RE_bake_internal(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels, depth, pass_type, result); } if (!ok) break; } /* reverting data back */ if (ob_cage) { ob_cage->restrictflag |= OB_RESTRICT_RENDER; } else { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } } else { /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0); /* populate the pixel array with the face data */ RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images); /* make sure low poly renders */ ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result); else ok = RE_bake_internal(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result); } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (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_highpoly) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle); } 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, 1, 0); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_report(reports, RPT_ERROR, "Problem baking object map"); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (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); if (!ok) { BKE_report(reports, RPT_ERROR, "Problem saving the bake map internally, " "make sure there is a Texture Image node in the current object material"); 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_makepicstring_from_type(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false); 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; } } } } cleanup: if (is_highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].pixel_array) MEM_freeN(highpoly[i].pixel_array); 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 (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); RE_SetReports(re, NULL); return op_result; }