static void screen_render_scene_layer_set(wmOperator *op, Main *mainp, Scene **scene, SceneRenderLayer **srl) { /* single layer re-render */ if (RNA_struct_property_is_set(op->ptr, "scene")) { Scene *scn; char scene_name[MAX_ID_NAME - 2]; RNA_string_get(op->ptr, "scene", scene_name); scn = (Scene *)BLI_findstring(&mainp->scene, scene_name, offsetof(ID, name) + 2); if (scn) { /* camera switch wont have updated */ scn->r.cfra = (*scene)->r.cfra; BKE_scene_camera_switch_update(scn); *scene = scn; } } if (RNA_struct_property_is_set(op->ptr, "layer")) { SceneRenderLayer *rl; char rl_name[RE_MAXNAME]; RNA_string_get(op->ptr, "layer", rl_name); rl = (SceneRenderLayer *)BLI_findstring(&(*scene)->r.layers, rl_name, offsetof(SceneRenderLayer, name)); if (rl) *srl = rl; } }
static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) { Main *bmain = CTX_data_main(C); const char *app_template = template_v; bool has_startup_items = false; wmOperatorType *ot_append = WM_operatortype_find("WORKSPACE_OT_append_activate", true); WorkspaceConfigFileData *startup_config = workspace_config_file_read(app_template); WorkspaceConfigFileData *builtin_config = workspace_system_file_read(app_template); if (startup_config) { for (WorkSpace *workspace = startup_config->workspaces.first; workspace; workspace = workspace->id.next) { uiLayout *row = uiLayoutRow(layout, false); if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { uiLayoutSetActive(row, false); } workspace_append_button(row, ot_append, workspace, startup_config->main); has_startup_items = true; } } if (builtin_config) { bool has_title = false; for (WorkSpace *workspace = builtin_config->workspaces.first; workspace; workspace = workspace->id.next) { if (startup_config && BLI_findstring(&startup_config->workspaces, workspace->id.name, offsetof(ID, name))) { continue; } if (!has_title) { if (has_startup_items) { uiItemS(layout); } has_title = true; } uiLayout *row = uiLayoutRow(layout, false); if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { uiLayoutSetActive(row, false); } workspace_append_button(row, ot_append, workspace, builtin_config->main); } } if (startup_config) { BKE_blendfile_workspace_config_data_free(startup_config); } if (builtin_config) { BKE_blendfile_workspace_config_data_free(builtin_config); } }
bool RE_RenderResult_is_stereo(RenderResult *res) { if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) return false; if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name))) return false; return true; }
static int workspace_append_activate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); char idname[MAX_ID_NAME - 2], filepath[FILE_MAX]; if (!RNA_struct_property_is_set(op->ptr, "idname") || !RNA_struct_property_is_set(op->ptr, "filepath")) { return OPERATOR_CANCELLED; } RNA_string_get(op->ptr, "idname", idname); RNA_string_get(op->ptr, "filepath", filepath); if (workspace_append(C, filepath, idname) != OPERATOR_CANCELLED) { WorkSpace *appended_workspace = BLI_findstring( &bmain->workspaces, idname, offsetof(ID, name) + 2); BLI_assert(appended_workspace != NULL); if (appended_workspace) { /* Reorder to last position. */ BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); /* Changing workspace changes context. Do delayed! */ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; }
/* (currently used for action constraints and in rebuild_pose) */ bPoseChannel *verify_pose_channel(bPose *pose, const char *name) { bPoseChannel *chan; if (pose == NULL) return NULL; /* See if this channel exists */ chan= BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name)); if(chan) { return chan; } /* If not, create it and add it */ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); BLI_strncpy(chan->name, name, sizeof(chan->name)); /* init vars to prevent math errors */ unit_qt(chan->quat); unit_axis_angle(chan->rotAxis, &chan->rotAngle); chan->size[0] = chan->size[1] = chan->size[2] = 1.0f; chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f; chan->ikrotweight = chan->iklinweight = 0.0f; unit_m4(chan->constinv); chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */ BLI_addtail(&pose->chanbase, chan); free_pose_channels_hash(pose); return chan; }
void wm_file_read_report(bContext *C) { ReportList *reports = NULL; Scene *sce; for (sce = G.main->scene.first; sce; sce = sce->id.next) { if (sce->r.engine[0] && BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) { if (reports == NULL) { reports = CTX_wm_reports(C); } BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' " "(an addon may need to be installed or enabled)", sce->r.engine, sce->id.name + 2); } } if (reports) { if (!G.background) { WM_report_banner_show(); } } }
static int set_engine(int argc, const char **argv, void *data) { bContext *C = data; if (argc >= 2) { if (!strcmp(argv[1], "help")) { RenderEngineType *type = NULL; printf("Blender Engine Listing:\n"); for (type = R_engines.first; type; type = type->next) { printf("\t%s\n", type->idname); } exit(0); } else { Scene *scene = CTX_data_scene(C); if (scene) { RenderData *rd = &scene->r; if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) { BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine)); } } else { printf("\nError: no blend loaded. order the arguments so '-E / --engine ' is after a blend is loaded.\n"); } } return 1; } else { printf("\nEngine not specified, give 'help' for a list of available engines.\n"); return 0; } }
PyObject *bpy_text_import_name(const char *name, int *found) { Text *text; char txtname[MAX_ID_NAME - 2]; int namelen = strlen(name); //XXX Main *maggie = bpy_import_main ? bpy_import_main:G.main; Main *maggie = bpy_import_main; *found = 0; if (!maggie) { printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n"); return NULL; } /* we know this cant be importable, the name is too long for blender! */ if (namelen >= (MAX_ID_NAME - 2) - 3) return NULL; memcpy(txtname, name, namelen); memcpy(&txtname[namelen], ".py", 4); text = BLI_findstring(&maggie->text, txtname, offsetof(ID, name) + 2); if (!text) return NULL; else *found = 1; return bpy_text_import(text); }
static void *ml_addview_cb(void *base, const char *str) { RenderResult *rr = base; RenderView *rv; rv = MEM_callocN(sizeof(RenderView), "new render view"); BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME); /* For stereo drawing we need to ensure: * STEREO_LEFT_NAME == STEREO_LEFT_ID and * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */ if (STREQ(str, STEREO_LEFT_NAME)) { BLI_addhead(&rr->views, rv); } else if (STREQ(str, STEREO_RIGHT_NAME)) { RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)); if (left_rv == NULL) { BLI_addhead(&rr->views, rv); } else { BLI_insertlinkafter(&rr->views, left_rv, rv); } } else { BLI_addtail(&rr->views, rv); } return rv; }
/* Find a group with the given name */ bActionGroup *BKE_action_group_find_name(bAction *act, const char name[]) { /* sanity checks */ if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0)) return NULL; /* do string comparisons */ return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name)); }
/* Find KeyingSet type info given a name */ KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]) { /* sanity checks */ if ((name == NULL) || (name[0] == 0)) return NULL; /* search by comparing names */ return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname)); }
RenderEngineType *RE_engines_find(const char *idname) { RenderEngineType *type; type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname)); if (!type) type = &internal_render_type; return type; }
Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String &name) { Scene *sce; /** * Find the specified scene by name, or NULL if nothing matches. */ if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2))) return sce; for (vector<Main *>::iterator it=m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) { Main *main = *it; if ((sce= (Scene *)BLI_findstring(&main->scene, name.ReadPtr(), offsetof(ID, name) + 2))) return sce; } return NULL; }
/** * Return a pointer to the pose channel of the given name * from this pose. */ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name) { if (ELEM(NULL, pose, name) || (name[0] == '\0')) return NULL; if (pose->chanhash) return BLI_ghash_lookup(pose->chanhash, (const void *)name); return BLI_findstring(&((const bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name)); }
static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) { Scene *scene = CTX_data_scene(C); bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; RulerItem *ruler_item; const char *ruler_name = RULER_ID; bool changed = false; if (scene->gpd == NULL) { scene->gpd = gpencil_data_addnew("GPencil"); } gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); if (gpl == NULL) { gpl = gpencil_layer_addnew(scene->gpd, ruler_name, false); gpl->thickness = 1; gpl->flag |= GP_LAYER_HIDE; } gpf = gpencil_layer_getframe(gpl, CFRA, true); free_gpencil_strokes(gpf); for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { bGPDspoint *pt; int j; /* allocate memory for a new stroke */ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); if (ruler_item->flag & RULERITEM_USE_ANGLE) { gps->totpoints = 3; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); for (j = 0; j < 3; j++) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; pt++; } } else { gps->totpoints = 2; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); for (j = 0; j < 3; j += 2) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; pt++; } } gps->flag = GP_STROKE_3DSPACE; BLI_addtail(&gpf->strokes, gps); changed = true; } return changed; }
PyObject *bpy_text_reimport(PyObject *module, int *found) { Text *text; const char *name; char *filepath; char *buf = NULL; //XXX Main *maggie = bpy_import_main ? bpy_import_main:G.main; Main *maggie = bpy_import_main; if (!maggie) { printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n"); return NULL; } *found = 0; /* get name, filename from the module itself */ if ((name = PyModule_GetName(module)) == NULL) return NULL; if ((filepath = (char *)PyModule_GetFilename(module)) == NULL) return NULL; /* look up the text object */ text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2); /* uh-oh.... didn't find it */ if (!text) return NULL; else *found = 1; /* if previously compiled, free the object */ /* (can't see how could be NULL, but check just in case) */ if (text->compiled) { Py_DECREF((PyObject *)text->compiled); } /* compile the buffer */ buf = txt_to_buf(text); text->compiled = Py_CompileString(buf, text->id.name + 2, Py_file_input); MEM_freeN(buf); /* if compile failed.... return this error */ if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); PySys_SetObject("last_traceback", NULL); free_compiled_text(text); return NULL; } /* make into a module */ return PyImport_ExecCodeModule((char *)name, text->compiled); }
/* XXX: read a style configure */ uiStyle *UI_style_get(void) { #if 0 uiStyle *style = NULL; /* offset is two struct uiStyle pointers */ style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2); return (style != NULL) ? style : U.uistyles.first; #else return U.uistyles.first; #endif }
static wmKeyConfig *WM_keyconfig_active(wmWindowManager *wm) { wmKeyConfig *keyconf; /* first try from preset */ keyconf = BLI_findstring(&wm->keyconfigs, U.keyconfigstr, offsetof(wmKeyConfig, idname)); if (keyconf) return keyconf; /* otherwise use default */ return wm->defaultconf; }
static bActuator *edit_actuator_property_get(bContext *C, wmOperator *op, Object **ob) { char actuator_name[MAX_NAME]; bActuator *act; RNA_string_get(op->ptr, "actuator", actuator_name); *ob = edit_object_property_get(C, op); if (!*ob) return NULL; act = BLI_findstring(&((*ob)->actuators), actuator_name, offsetof(bActuator, name)); return act; }
static bController *edit_controller_property_get(bContext *C, wmOperator *op, Object **ob) { char controller_name[MAX_NAME]; bController *cont; RNA_string_get(op->ptr, "controller", controller_name); *ob = edit_object_property_get(C, op); if (!*ob) return NULL; cont = BLI_findstring(&((*ob)->controllers), controller_name, offsetof(bController, name)); return cont; }
static bSensor *edit_sensor_property_get(bContext *C, wmOperator *op, Object **ob) { char sensor_name[MAX_NAME]; bSensor *sens; RNA_string_get(op->ptr, "sensor", sensor_name); *ob = edit_object_property_get(C, op); if (!*ob) return NULL; sens = BLI_findstring(&((*ob)->sensors), sensor_name, offsetof(bSensor, name)); return sens; }
/* return success (1) */ int 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 0; } 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_flag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* here appending/linking starts */ mainl = BLO_library_link_begin(bmain, &bh, libname); BLO_library_link_all(mainl, bh, flag, scene, v3d); 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_flag_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 1; }
static void data_dir_add(ListBase *lb, const char *member) { LinkData *link; if(strcmp(member, "scene") == 0) /* exception */ return; if(BLI_findstring(lb, member, offsetof(LinkData, data))) return; link= MEM_callocN(sizeof(LinkData), "LinkData"); link->data= (void*)member; BLI_addtail(lb, link); }
void test_idbutton(char *name) { /* called from buttons: when name already exists: call new_id */ ListBase *lb; ID *idtest; lb= which_libbase(G.main, GS(name-2) ); if(lb==NULL) return; /* search for id */ idtest= BLI_findstring(lb, name, offsetof(ID, name) + 2); if(idtest) if( new_id(lb, idtest, name)==0 ) sort_alpha_id(lb, idtest); }
static Object *edit_object_property_get(bContext *C, wmOperator *op) { char ob_name[MAX_NAME]; Object *ob; RNA_string_get(op->ptr, "object", ob_name); /* if ob_name is valid try to find the object with this name * otherwise gets the active object */ if (*ob_name) ob = BLI_findstring(&(CTX_data_main(C)->object), ob_name, offsetof(ID, name) + 2); else ob = ED_object_active_context(C); return ob; }
int unpackImage(ReportList *reports, Image *ima, int how) { int ret_value = RET_ERROR; if (ima != NULL) { while (ima->packedfiles.last) { char localname[FILE_MAX], absname[FILE_MAX]; char *newname; ImagePackedFile *imapf = ima->packedfiles.last; unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname)); newname = unpackFile(reports, absname, localname, imapf->packedfile, how); if (newname != NULL) { ImageView *iv; ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK; freePackedFile(imapf->packedfile); imapf->packedfile = NULL; /* update the new corresponding view filepath */ iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath)); if (iv) { BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath)); } /* keep the new name in the image for non-pack specific reasons */ if (how != PF_REMOVE) { BLI_strncpy(ima->name, newname, sizeof(imapf->filepath)); } MEM_freeN(newname); } else { ret_value = RET_ERROR; } BLI_remlink(&ima->packedfiles, imapf); MEM_freeN(imapf); } } if (ret_value == RET_OK) { BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); } return(ret_value); }
PyObject *bpy_text_reimport(PyObject *module, int *found) { Text *text; const char *name; const char *filepath; //XXX Main *maggie = bpy_import_main ? bpy_import_main:G.main; Main *maggie = bpy_import_main; if (!maggie) { printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n"); return NULL; } *found = 0; /* get name, filename from the module itself */ if ((name = PyModule_GetName(module)) == NULL) return NULL; { PyObject *module_file = PyModule_GetFilenameObject(module); if (module_file == NULL) { return NULL; } filepath = _PyUnicode_AsString(module_file); Py_DECREF(module_file); if (filepath == NULL) { return NULL; } } /* look up the text object */ text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2); /* uh-oh.... didn't find it */ if (!text) return NULL; else *found = 1; if (bpy_text_compile(text) == false) { return NULL; } /* make into a module */ return PyImport_ExecCodeModule(name, text->compiled); }
static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info) { Scene *scene = CTX_data_scene(C); bool changed = false; if (scene->gpd) { bGPDlayer *gpl; const char *ruler_name = RULER_ID; gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); if (gpl) { bGPDframe *gpf; gpf = gpencil_layer_getframe(gpl, CFRA, false); if (gpf) { bGPDstroke *gps; for (gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt = gps->points; int j; if (gps->totpoints == 3) { RulerItem *ruler_item = ruler_item_add(ruler_info); for (j = 0; j < 3; j++) { copy_v3_v3(ruler_item->co[j], &pt->x); pt++; } ruler_item->flag |= RULERITEM_USE_ANGLE; changed = true; } else if (gps->totpoints == 2) { RulerItem *ruler_item = ruler_item_add(ruler_info); for (j = 0; j < 3; j += 2) { copy_v3_v3(ruler_item->co[j], &pt->x); pt++; } changed = true; } } } } } return changed; }
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; }
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; }