/** * \return if succeeded. */ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm) { if (BLI_listbase_is_single(&bmain->workspaces)) { return false; } ListBase ordered; BKE_id_ordered_list(&ordered, &bmain->workspaces); WorkSpace *prev = NULL, *next = NULL; for (LinkData *link = ordered.first; link; link = link->next) { if (link->data == workspace) { prev = link->prev ? link->prev->data : NULL; next = link->next ? link->next->data : NULL; break; } } BLI_freelistN(&ordered); BLI_assert((prev != NULL) || (next != NULL)); for (wmWindow *win = wm->windows.first; win; win = win->next) { WorkSpace *workspace_active = WM_window_get_active_workspace(win); if (workspace_active == workspace) { ED_workspace_change((prev != NULL) ? prev : next, C, wm, win); } } BKE_id_free(bmain, &workspace->id); return true; }
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); }
/* Add a new F-Curve Modifier to the given F-Curve of a certain type */ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu) { const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); FModifier *fcm; /* sanity checks */ if (ELEM(NULL, modifiers, fmi)) { return NULL; } /* special checks for whether modifier can be added */ if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) { /* cycles modifier must be first in stack, so for now, don't add if it can't be */ /* TODO: perhaps there is some better way, but for now, */ CLOG_STR_ERROR(&LOG, "Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be " "first in stack."); return NULL; } /* add modifier itself */ fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); fcm->type = type; fcm->flag = FMODIFIER_FLAG_EXPANDED; fcm->curve = owner_fcu; fcm->influence = 1.0f; BLI_addtail(modifiers, fcm); /* tag modifier as "active" if no other modifiers exist in the stack yet */ if (BLI_listbase_is_single(modifiers)) { fcm->flag |= FMODIFIER_FLAG_ACTIVE; } /* add modifier's data */ fcm->data = MEM_callocN(fmi->size, fmi->structName); /* init custom settings if necessary */ if (fmi->new_data) { fmi->new_data(fcm->data); } /* update the fcurve if the Cycles modifier is added */ if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES)) { calchandles_fcurve(owner_fcu); } /* return modifier for further editing */ return fcm; }
/* 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); }
/** * This function pastes data from the keyframes copy/paste buffer * * \return Status code is whether the method FAILED to do anything */ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) { bAnimListElem *ale; const Scene *scene = (ac->scene); const bool from_single = BLI_listbase_is_single(&animcopybuf); const bool to_simple = BLI_listbase_is_single(anim_data); float offset = 0.0f; int pass; /* check if buffer is empty */ if (BLI_listbase_is_empty(&animcopybuf)) { BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste"); return -1; } if (BLI_listbase_is_empty(anim_data)) { BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into"); return -1; } /* methods of offset */ switch (offset_mode) { case KEYFRAME_PASTE_OFFSET_CFRA_START: offset = (float)(CFRA - animcopy_firstframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_END: offset = (float)(CFRA - animcopy_lastframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: offset = (float)(CFRA - animcopy_cfra); break; case KEYFRAME_PASTE_OFFSET_NONE: offset = 0.0f; break; } if (from_single && to_simple) { /* 1:1 match, no tricky checking, just paste */ FCurve *fcu; tAnimCopybufItem *aci; ale = anim_data->first; fcu = (FCurve *)ale->data; /* destination F-Curve */ aci = animcopybuf.first; paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false); ale->update |= ANIM_UPDATE_DEFAULT; } else { /* from selected channels * This "passes" system aims to try to find "matching" channels to paste keyframes * into with increasingly loose matching heuristics. The process finishes when at least * one F-Curve has been pasted into. */ for (pass = 0; pass < 3; pass++) { unsigned int totmatch = 0; for (ale = anim_data->first; ale; ale = ale->next) { /* find buffer item to paste from * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group * - if names do matter, only check if id-type is ok for now (group check is not that important) * - most importantly, rna-paths should match (array indices are unimportant for now) */ AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ tAnimCopybufItem *aci = NULL; switch (pass) { case 0: /* most strict, must be exact path match data_path & index */ aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip); break; case 1: /* less strict, just compare property names */ aci = pastebuf_match_path_property(fcu, from_single, to_simple); break; case 2: /* Comparing properties gave no results, so just do index comparisons */ aci = pastebuf_match_index_only(fcu, from_single, to_simple); break; } /* copy the relevant data from the matching buffer curve */ if (aci) { totmatch++; if (adt) { ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); } else { paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); } } ale->update |= ANIM_UPDATE_DEFAULT; } /* don't continue if some fcurves were pasted */ if (totmatch) break; } } ANIM_animdata_update(ac, anim_data); return 0; }
/* Does not fix anything, but checks that all linked data-blocks are still valid (i.e. pointing to the right library). */ bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports) { ListBase mainlist; bool is_valid = true; BKE_main_lock(bmain); blo_split_main(&mainlist, bmain); ListBase *lbarray[MAX_LIBARRAY]; int i = set_listbasepointers(bmain, lbarray); while (i--) { for (ID *id = lbarray[i]->first; id != NULL; id = id->next) { if (id->lib != NULL) { is_valid = false; BKE_reportf(reports, RPT_ERROR, "ID %s is in local database while being linked from library %s!\n", id->name, id->lib->name); } } } for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) { Library *curlib = curmain->curlib; if (curlib == NULL) { BKE_reportf(reports, RPT_ERROR, "Library database with NULL library datablock!\n"); continue; } BKE_library_filepath_set(bmain, curlib, curlib->name); BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports); if (bh == NULL) { BKE_reportf(reports, RPT_ERROR, "Library ID %s not found at expected path %s!\n", curlib->id.name, curlib->filepath); continue; } i = set_listbasepointers(curmain, lbarray); while (i--) { ID *id = lbarray[i]->first; if (id == NULL) { continue; } if (GS(id->name) == ID_LI) { is_valid = false; BKE_reportf(reports, RPT_ERROR, "Library ID %s in library %s, this should not happen!\n", id->name, curlib->name); continue; } int totnames = 0; LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames); for (; id != NULL; id = id->next) { if (id->lib == NULL) { is_valid = false; BKE_reportf(reports, RPT_ERROR, "ID %s has NULL lib pointer while being in library %s!\n", id->name, curlib->name); continue; } if (id->lib != curlib) { is_valid = false; BKE_reportf(reports, RPT_ERROR, "ID %s has mismatched lib pointer!\n", id->name); continue; } LinkNode *name = names; for (; name; name = name->next) { char *str_name = (char *)name->link; if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) { break; } } if (name == NULL) { is_valid = false; BKE_reportf(reports, RPT_ERROR, "ID %s not found in library %s anymore!\n", id->name, id->lib->name); continue; } } BLI_linklist_free(names, free); } BLO_blendhandle_close(bh); } blo_join_main(&mainlist); BLI_assert(BLI_listbase_is_single(&mainlist)); BLI_assert(mainlist.first == (void *)bmain); BKE_main_unlock(bmain); return is_valid; }
static bool scanfill_preprocess_self_isect( ScanFillContext *sf_ctx, PolyInfo *poly_info, const unsigned short poly_nr, ListBase *filledgebase) { PolyInfo *pi = &poly_info[poly_nr]; GHash *isect_hash = NULL; ListBase isect_lb = {NULL}; /* warning, O(n2) check here, should use spatial lookup */ { ScanFillEdge *eed; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { ScanFillEdge *eed_other; for (eed_other = eed->next; eed_other; eed_other = (eed_other == pi->edge_last) ? NULL : eed_other->next) { if (!ELEM(eed->v1, eed_other->v1, eed_other->v2) && !ELEM(eed->v2, eed_other->v1, eed_other->v2) && (eed != eed_other)) { /* check isect */ float pt[2]; BLI_assert(eed != eed_other); if (isect_seg_seg_v2_point(eed->v1->co, eed->v2->co, eed_other->v1->co, eed_other->v2->co, pt) == 1) { ScanFillIsect *isect; if (UNLIKELY(isect_hash == NULL)) { isect_hash = BLI_ghash_ptr_new(__func__); } isect = MEM_mallocN(sizeof(ScanFillIsect), __func__); BLI_addtail(&isect_lb, isect); copy_v2_v2(isect->co, pt); isect->co[2] = eed->v1->co[2]; isect->v = BLI_scanfill_vert_add(sf_ctx, isect->co); isect->v->poly_nr = eed->v1->poly_nr; /* NOTE: vert may belong to 2 polys now */ VFLAG_SET(isect->v, V_ISISECT); edge_isect_ls_add(isect_hash, eed, isect); edge_isect_ls_add(isect_hash, eed_other, isect); } } } } } if (isect_hash == NULL) { return false; } /* now subdiv the edges */ { ScanFillEdge *eed; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { if (eed->user_flag & E_ISISECT) { ListBase *e_ls = BLI_ghash_lookup(isect_hash, eed); LinkData *isect_link; /* maintain coorect terminating edge */ if (pi->edge_last == eed) { pi->edge_last = NULL; } if (BLI_listbase_is_single(e_ls) == false) { BLI_sortlist_r(e_ls, eed->v2->co, edge_isect_ls_sort_cb); } /* move original edge to filledgebase and add replacement * (which gets subdivided next) */ { ScanFillEdge *eed_tmp; eed_tmp = BLI_scanfill_edge_add(sf_ctx, eed->v1, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed_tmp); BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_tmp); BLI_remlink(&sf_ctx->filledgebase, eed); BLI_addtail(filledgebase, eed); if (pi->edge_first == eed) { pi->edge_first = eed_tmp; } eed = eed_tmp; } for (isect_link = e_ls->first; isect_link; isect_link = isect_link->next) { ScanFillIsect *isect = isect_link->data; ScanFillEdge *eed_subd; eed_subd = BLI_scanfill_edge_add(sf_ctx, isect->v, eed->v2); eed_subd->poly_nr = poly_nr; eed->v2 = isect->v; BLI_remlink(&sf_ctx->filledgebase, eed_subd); BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_subd); /* step to the next edge and continue dividing */ eed = eed_subd; } BLI_freelistN(e_ls); MEM_freeN(e_ls); if (pi->edge_last == NULL) { pi->edge_last = eed; } } } } BLI_freelistN(&isect_lb); BLI_ghash_free(isect_hash, NULL, NULL); { ScanFillEdge *e_init; ScanFillEdge *e_curr; ScanFillEdge *e_next; ScanFillVert *v_prev; ScanFillVert *v_curr; int inside = false; /* first vert */ #if 0 e_init = pi->edge_last; e_curr = e_init; e_next = pi->edge_first; v_prev = e_curr->v1; v_curr = e_curr->v2; #else /* find outside vertex */ { ScanFillEdge *eed; ScanFillEdge *eed_prev; float min_x = FLT_MAX; e_curr = pi->edge_last; e_next = pi->edge_first; eed_prev = pi->edge_last; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { if (eed->v2->co[0] < min_x) { min_x = eed->v2->co[0]; e_curr = eed_prev; e_next = eed; } eed_prev = eed; } e_init = e_curr; v_prev = e_curr->v1; v_curr = e_curr->v2; } #endif BLI_assert(e_curr->poly_nr == poly_nr); BLI_assert(pi->edge_last->poly_nr == poly_nr); do { ScanFillVert *v_next; v_next = (e_next->v1 == v_curr) ? e_next->v2 : e_next->v1; BLI_assert(ELEM(v_curr, e_next->v1, e_next->v2)); /* track intersections */ if (inside) { EFLAG_SET(e_next, E_ISDELETE); } if (v_next->user_flag & V_ISISECT) { inside = !inside; } /* now step... */ v_prev = v_curr; v_curr = v_next; e_curr = e_next; e_next = edge_step(poly_info, poly_nr, v_prev, v_curr, e_curr); } while (e_curr != e_init); } return true; }