diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
69 files changed, 2207 insertions, 1229 deletions
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index ccb077d6b82..db8fe75b6d1 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -298,6 +298,8 @@ IDTypeInfo IDType_ID_AC = { .blend_read_expand = action_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* ***************** Library data level operations on action ************** */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 20956d6eb18..da874539232 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -362,6 +362,20 @@ void BKE_keyingsets_blend_read_expand(BlendExpander *expander, ListBase *list) /* ***************************************** */ /* Evaluation Data-Setting Backend */ +static bool is_fcurve_evaluatable(FCurve *fcu) +{ + if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) { + return false; + } + if (fcu->grp != NULL && (fcu->grp->flag & AGRP_MUTED)) { + return false; + } + if (BKE_fcurve_is_empty(fcu)) { + return false; + } + return true; +} + bool BKE_animsys_store_rna_setting(PointerRNA *ptr, /* typically 'fcu->rna_path', 'fcu->array_index' */ const char *rna_path, @@ -594,18 +608,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, { /* Calculate then execute each curve. */ LISTBASE_FOREACH (FCurve *, fcu, list) { - /* Check if this F-Curve doesn't belong to a muted group. */ - if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { - continue; - } - /* Check if this curve should be skipped. */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { - continue; - } - /* Skip empty curves, as if muted. */ - if (BKE_fcurve_is_empty(fcu)) { + + if (!is_fcurve_evaluatable(fcu)) { continue; } + PathResolvedRNA anim_rna; if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); @@ -979,6 +986,19 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, return nes; } +static NlaEvalStrip *nlastrips_ctime_get_strip_single( + ListBase *dst_list, + NlaStrip *single_strip, + const AnimationEvalContext *anim_eval_context, + const bool flush_to_original) +{ + ListBase single_tracks_list; + single_tracks_list.first = single_tracks_list.last = single_strip; + + return nlastrips_ctime_get_strip( + dst_list, &single_tracks_list, -1, anim_eval_context, flush_to_original); +} + /* ---------------------- */ /* Initialize a valid mask, allocating memory if necessary. */ @@ -1152,7 +1172,7 @@ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot) /* Free memory owned by this evaluation channel. */ static void nlaevalchan_free_data(NlaEvalChannel *nec) { - nlavalidmask_free(&nec->valid); + nlavalidmask_free(&nec->domain); if (nec->blend_snapshot != NULL) { nlaevalchan_snapshot_free(nec->blend_snapshot); @@ -1353,7 +1373,7 @@ static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval, nec->mix_mode = nlaevalchan_detect_mix_mode(key, length); - nlavalidmask_init(&nec->valid, length); + nlavalidmask_init(&nec->domain, length); nec->base_snapshot.channel = nec; nec->base_snapshot.length = length; @@ -1682,14 +1702,6 @@ static bool nlaeval_blend_value(NlaBlendData *blend, return false; } - if (nec->mix_mode == NEC_MIX_QUATERNION) { - /* For quaternion properties, always output all sub-channels. */ - BLI_bitmap_set_all(nec->valid.ptr, true, 4); - } - else { - BLI_BITMAP_ENABLE(nec->valid.ptr, array_index); - } - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); float *p_value = &nec_snapshot->values[array_index]; @@ -1889,16 +1901,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, /* Evaluate all the F-Curves in the action, * saving the relevant pointers to data that will need to be used. */ for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { - float value = 0.0f; - /* check if this curve should be skipped */ - if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) { - continue; - } - if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) { - continue; - } - if (BKE_fcurve_is_empty(fcu)) { + if (!is_fcurve_evaluatable(fcu)) { continue; } @@ -1906,7 +1910,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, * NOTE: we use the modified time here, since strip's F-Curve Modifiers * are applied on top of this. */ - value = evaluate_fcurve(fcu, evaltime); + float value = evaluate_fcurve(fcu, evaltime); /* apply strip's F-Curve Modifiers on this value * NOTE: we apply the strip's original evaluation time not the modified one @@ -2099,12 +2103,21 @@ void nladata_flush_channels(PointerRNA *ptr, /* for each channel with accumulated values, write its value on the property it affects */ LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) { + /** + * The bitmask is set for all channels touched by NLA due to the domain() function. + * Channels touched by current set of evaluated strips will have a snapshot channel directly + * from the evaluation snapshot. + * + * This function falls back to the default value if the snapshot channel doesn't exist. + * Thus channels, touched by NLA but not by the current set of evaluated strips, will be + * reset to default. If channel not touched by NLA then it's value is unchanged. + */ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec); PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1}; for (int i = 0; i < nec_snapshot->length; i++) { - if (BLI_BITMAP_TEST(nec->valid.ptr, i)) { + if (BLI_BITMAP_TEST(nec->domain.ptr, i)) { float value = nec_snapshot->values[i]; if (nec->is_array) { rna.prop_index = i; @@ -2131,13 +2144,7 @@ static void nla_eval_domain_action(PointerRNA *ptr, LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { /* check if this curve should be skipped */ - if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) { - continue; - } - if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) { - continue; - } - if (BKE_fcurve_is_empty(fcu)) { + if (!is_fcurve_evaluatable(fcu)) { continue; } @@ -2146,14 +2153,14 @@ static void nla_eval_domain_action(PointerRNA *ptr, if (nec != NULL) { /* For quaternion properties, enable all sub-channels. */ if (nec->mix_mode == NEC_MIX_QUATERNION) { - BLI_bitmap_set_all(nec->valid.ptr, true, 4); + BLI_bitmap_set_all(nec->domain.ptr, true, 4); continue; } int idx = nlaevalchan_validate_index(nec, fcu->array_index); if (idx >= 0) { - BLI_BITMAP_ENABLE(nec->valid.ptr, idx); + BLI_BITMAP_ENABLE(nec->domain.ptr, idx); } } } @@ -2212,190 +2219,345 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels, /* ---------------------- */ +/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored + * and includes a workaround for when user is not editing in place. */ +static void animsys_create_tweak_strip(const AnimData *adt, + const bool keyframing_to_strip, + NlaStrip *r_tweak_strip) + +{ + /* Copy active strip so we can modify how it evaluates without affecting user data. */ + memcpy(r_tweak_strip, adt->actstrip, sizeof(NlaStrip)); + r_tweak_strip->next = r_tweak_strip->prev = NULL; + + /* If tweaked strip is syncing action length, then evaluate using action length. */ + if (r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) { + BKE_nlastrip_recalculate_bounds_sync_action(r_tweak_strip); + } + + /* Strips with a user-defined time curve don't get properly remapped for editing + * at the moment, so mapping them just for display may be confusing. */ + const bool is_inplace_tweak = !(adt->flag & ADT_NLA_EDIT_NOMAP) && + !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME); + + if (!is_inplace_tweak) { + /* Use Hold due to no proper remapping yet (the note above). */ + r_tweak_strip->extendmode = NLASTRIP_EXTEND_HOLD; + + /* Disable range. */ + r_tweak_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP; + } + + /** Controls whether able to keyframe outside range of tweaked strip. */ + if (keyframing_to_strip) { + r_tweak_strip->extendmode = (is_inplace_tweak && + !(r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ? + NLASTRIP_EXTEND_NOTHING : + NLASTRIP_EXTEND_HOLD; + } +} + +/** Action track and strip are associated with the non-pushed action. */ +static void animsys_create_action_track_strip(const AnimData *adt, + const bool keyframing_to_strip, + NlaStrip *r_action_strip) +{ + memset(r_action_strip, 0, sizeof(NlaStrip)); + + bAction *action = adt->action; + + if ((adt->flag & ADT_NLA_EDIT_ON)) { + action = adt->tmpact; + } + + /* Set settings of dummy NLA strip from AnimData settings. */ + r_action_strip->act = action; + + /* Action range is calculated taking F-Modifiers into account + * (which making new strips doesn't do due to the troublesome nature of that). */ + calc_action_range(r_action_strip->act, &r_action_strip->actstart, &r_action_strip->actend, 1); + r_action_strip->start = r_action_strip->actstart; + r_action_strip->end = (IS_EQF(r_action_strip->actstart, r_action_strip->actend)) ? + (r_action_strip->actstart + 1.0f) : + (r_action_strip->actend); + + r_action_strip->blendmode = adt->act_blendmode; + r_action_strip->extendmode = adt->act_extendmode; + r_action_strip->influence = adt->act_influence; + + /* NOTE: must set this, or else the default setting overrides, + * and this setting doesn't work. */ + r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; + + /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range. + * Extendmode Nothing and Hold will behave as normal. Hold Forward will behave just like Hold. + */ + if (r_action_strip->extendmode != NLASTRIP_EXTEND_NOTHING) { + r_action_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP; + } + + const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0; + const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0; + const bool actionstrip_evaluated = r_action_strip->act && !soloing && !tweaking; + if (!actionstrip_evaluated) { + r_action_strip->flag |= NLASTRIP_FLAG_MUTED; + } + + /** If we're keyframing, then we must allow keyframing outside fcurve bounds. */ + if (keyframing_to_strip) { + r_action_strip->extendmode = NLASTRIP_EXTEND_HOLD; + } +} + +static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt) +{ + /* Skip disabled tracks unless it contains the tweaked strip. */ + const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) && + (nlt->index == adt->act_track->index); + if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) { + return false; + } + + /* Solo and muting are mutually exclusive. */ + if (adt->flag & ADT_NLA_SOLO_TRACK) { + /* Skip if there is a solo track, but this isn't it. */ + if ((nlt->flag & NLATRACK_SOLO) == 0) { + return false; + } + } + else { + /* Skip track if muted. */ + if (nlt->flag & NLATRACK_MUTED) { + return false; + } + } + + return true; +} + +/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no + * strips evaluated) nor NLA interference (ensure NLA not soloing). */ +static bool is_action_track_evaluated_without_nla(const AnimData *adt, + const bool any_strip_evaluated) +{ + if (adt->action == NULL) { + return false; + } + + if (any_strip_evaluated) { + return false; + } + + /** NLA settings interference. */ + if ((adt->flag & (ADT_NLA_SOLO_TRACK | ADT_NLA_EDIT_ON)) == 0) { + return false; + } + + /** Allow action track to evaluate as if there isn't any NLA data. */ + return true; +} + /** - * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels" + * XXX(Wayde Moss): #BKE_nlatrack_find_tweaked() exists within nla.c, but it doesn't appear to + * work as expected. From #animsys_evaluate_nla_for_flush(), it returns NULL in tweak mode. I'm not + * sure why. Preferably, it would be as simple as checking for `(adt->act_Track == nlt)` but that + * doesn't work either, neither does comparing indices. * + * This function is a temporary work around. The first disabled track is always the tweaked track. + */ +static NlaTrack *nlatrack_find_tweaked(const AnimData *adt) +{ + NlaTrack *nlt; + + if (adt == NULL) { + return NULL; + } + + /* Since the track itself gets disabled, we want the first disabled. */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + if (nlt->flag & NLATRACK_DISABLED) { + return nlt; + } + } + + return NULL; +} + +/** + * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels" * \param[out] echannels: Evaluation channels with calculated values - * \param[out] r_context: If not NULL, - * data about the currently edited strip is stored here and excluded from value calculation. - * \return false if NLA evaluation isn't actually applicable. */ -static bool animsys_evaluate_nla(NlaEvalData *echannels, - PointerRNA *ptr, - AnimData *adt, - const AnimationEvalContext *anim_eval_context, - const bool flush_to_original, - NlaKeyframingContext *r_context) +static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels, + PointerRNA *ptr, + const AnimData *adt, + const AnimationEvalContext *anim_eval_context, + const bool flush_to_original) { NlaTrack *nlt; short track_index = 0; bool has_strips = false; - ListBase estrips = {NULL, NULL}; NlaEvalStrip *nes; - NlaStrip dummy_strip_buf; - /* dummy strip for active action */ - NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf; + NlaStrip tweak_strip; - memset(dummy_strip, 0, sizeof(*dummy_strip)); + NlaTrack *tweaked_track = nlatrack_find_tweaked(adt); - /* 1. get the stack of strips to evaluate at current time (influence calculated here) */ + /* Get the stack of strips to evaluate at current time (influence calculated here). */ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) { - /* stop here if tweaking is on and this strip is the tweaking track - * (it will be the first one that's 'disabled')... */ - if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) { - break; + + if (!is_nlatrack_evaluatable(adt, nlt)) { + continue; } - /* solo and muting are mutually exclusive... */ - if (adt->flag & ADT_NLA_SOLO_TRACK) { - /* skip if there is a solo track, but this isn't it */ - if ((nlt->flag & NLATRACK_SOLO) == 0) { - continue; - } - /* else - mute doesn't matter */ + if (nlt->strips.first) { + has_strips = true; + } + + /** Append strip to evaluate for this track. */ + if (nlt == tweaked_track) { + /** Tweaked strip is evaluated differently. */ + animsys_create_tweak_strip(adt, false, &tweak_strip); + nes = nlastrips_ctime_get_strip_single( + &estrips, &tweak_strip, anim_eval_context, flush_to_original); } else { - /* no solo tracks - skip track if muted */ - if (nlt->flag & NLATRACK_MUTED) { - continue; - } + nes = nlastrips_ctime_get_strip( + &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original); + } + if (nes) { + nes->track = nlt; + } + } + + if (is_action_track_evaluated_without_nla(adt, has_strips)) { + BLI_freelistN(&estrips); + return false; + } + + NlaStrip action_strip = {0}; + animsys_create_action_track_strip(adt, false, &action_strip); + nlastrips_ctime_get_strip_single(&estrips, &action_strip, anim_eval_context, flush_to_original); + + /* Per strip, evaluate and accumulate on top of existing channels. */ + for (nes = estrips.first; nes; nes = nes->next) { + nlastrip_evaluate(ptr, + echannels, + NULL, + nes, + &echannels->eval_snapshot, + anim_eval_context, + flush_to_original); + } + + /* Free temporary evaluation data that's not used elsewhere. */ + BLI_freelistN(&estrips); + return true; +} + +/** Lower blended values are calculated and accumulated into r_context->lower_eval_data. */ +static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr, + const AnimData *adt, + const AnimationEvalContext *anim_eval_context, + NlaKeyframingContext *r_context) +{ + if (!r_context) { + return; + } + + /* Early out. If NLA track is soloing and tweaked action isn't it, then don't allow keyframe + * insertion. */ + if (adt->flag & ADT_NLA_SOLO_TRACK) { + if (!(adt->act_track && (adt->act_track->flag & NLATRACK_SOLO))) { + r_context->eval_strip = NULL; + return; + } + } + + NlaTrack *nlt; + short track_index = 0; + bool has_strips = false; + + ListBase lower_estrips = {NULL, NULL}; + NlaEvalStrip *nes; + + NlaTrack *tweaked_track = nlatrack_find_tweaked(adt); + + /* Get the lower stack of strips to evaluate at current time (influence calculated here). */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) { + + if (!is_nlatrack_evaluatable(adt, nlt)) { + continue; + } + + /* Tweaked strip effect should not be stored in any snapshot. */ + if (nlt == tweaked_track) { + break; } - /* if this track has strips (but maybe they won't be suitable), set has_strips - * - used for mainly for still allowing normal action evaluation... - */ if (nlt->strips.first) { has_strips = true; } - /* otherwise, get strip to evaluate for this channel */ + /* Get strip to evaluate for this channel. */ nes = nlastrips_ctime_get_strip( - &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original); + &lower_estrips, &nlt->strips, track_index, anim_eval_context, false); if (nes) { nes->track = nlt; } } - /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack - * - only do this if we're not exclusively evaluating the 'solo' NLA-track - * - however, if the 'solo' track houses the current 'tweaking' strip, - * then we should allow this to play, otherwise nothing happens + /** Note: Although we early out, we can still keyframe to the non-pushed action since the + * keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without + * remapping. */ - if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) { - /* if there are strips, evaluate action as per NLA rules */ - if ((has_strips) || (adt->actstrip)) { - /* make dummy NLA strip, and add that to the stack */ - ListBase dummy_trackslist; - - dummy_trackslist.first = dummy_trackslist.last = dummy_strip; - - /* Strips with a user-defined time curve don't get properly remapped for editing - * at the moment, so mapping them just for display may be confusing. */ - bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) && - !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME); - - if (is_inplace_tweak) { - /* edit active action in-place according to its active strip, so copy the data */ - memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip)); - /* Prevents nla eval from considering active strip's adj strips. - * For user, this means entering tweak mode on a strip ignores evaluating adjacent strips - * in the same track. */ - dummy_strip->next = dummy_strip->prev = NULL; - - /* If tweaked strip is syncing action length, then evaluate using action length. */ - if (dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) { - BKE_nlastrip_recalculate_bounds_sync_action(dummy_strip); - } - } - else { - /* set settings of dummy NLA strip from AnimData settings */ - dummy_strip->act = adt->action; - - /* action range is calculated taking F-Modifiers into account - * (which making new strips doesn't do due to the troublesome nature of that) */ - calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1); - dummy_strip->start = dummy_strip->actstart; - dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ? - (dummy_strip->actstart + 1.0f) : - (dummy_strip->actend); - - /* Always use the blend mode of the strip in tweak mode, even if not in-place. */ - if (nlt && adt->actstrip) { - dummy_strip->blendmode = adt->actstrip->blendmode; - dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD; - } - else { - dummy_strip->blendmode = adt->act_blendmode; - dummy_strip->extendmode = adt->act_extendmode; - } + if (is_action_track_evaluated_without_nla(adt, has_strips)) { + BLI_freelistN(&lower_estrips); + return; + } - /* Unless extend-mode is Nothing (might be useful for flattening NLA evaluation), - * disable range. */ - if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) { - dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP; - } + /* Write r_context->eval_strip. */ + if (adt->flag & ADT_NLA_EDIT_ON) { - dummy_strip->influence = adt->act_influence; + NlaStrip *tweak_strip = &r_context->strip; + animsys_create_tweak_strip(adt, true, tweak_strip); + r_context->eval_strip = nlastrips_ctime_get_strip_single( + NULL, tweak_strip, anim_eval_context, false); + } + else { - /* NOTE: must set this, or else the default setting overrides, - * and this setting doesn't work. */ - dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; - } + NlaStrip *action_strip = &r_context->strip; + animsys_create_action_track_strip(adt, true, action_strip); + r_context->eval_strip = nlastrips_ctime_get_strip_single( + NULL, action_strip, anim_eval_context, false); + } - /* add this to our list of evaluation strips */ - if (r_context == NULL) { - nlastrips_ctime_get_strip( - &estrips, &dummy_trackslist, -1, anim_eval_context, flush_to_original); - } - /* If computing the context for keyframing, store data there instead of the list. */ - else { - /* The extend mode here effectively controls - * whether it is possible to key-frame beyond the ends.*/ - dummy_strip->extendmode = (is_inplace_tweak && - !(dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ? - NLASTRIP_EXTEND_NOTHING : - NLASTRIP_EXTEND_HOLD; - - r_context->eval_strip = nes = nlastrips_ctime_get_strip( - NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original); - - /* These setting combinations require no data from strips below, so exit immediately. */ - if ((nes == NULL) || - (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) { - BLI_freelistN(&estrips); - return true; - } - } - } - else { - /* special case - evaluate as if there isn't any NLA data */ - BLI_freelistN(&estrips); - return false; - } + /* If NULL, then keyframing will fail. No need to do any more processing. */ + if (!r_context->eval_strip) { + BLI_freelistN(&lower_estrips); + return; } - /* only continue if there are strips to evaluate */ - if (BLI_listbase_is_empty(&estrips)) { - return true; + /* If tweak strip is full REPLACE, then lower strips not needed. */ + if (r_context->strip.blendmode == NLASTRIP_MODE_REPLACE && + IS_EQF(r_context->strip.influence, 1.0f)) { + BLI_freelistN(&lower_estrips); + return; } - /* 2. for each strip, evaluate then accumulate on top of existing channels, - * but don't set values yet. */ - for (nes = estrips.first; nes; nes = nes->next) { + /* For each strip, evaluate then accumulate on top of existing channels. */ + for (nes = lower_estrips.first; nes; nes = nes->next) { nlastrip_evaluate(ptr, - echannels, + &r_context->lower_eval_data, NULL, nes, - &echannels->eval_snapshot, + &r_context->lower_eval_data.eval_snapshot, anim_eval_context, - flush_to_original); + false); } - /* 3. free temporary evaluation data that's not used elsewhere */ - BLI_freelistN(&estrips); - return true; + /* Free temporary evaluation data that's not used elsewhere. */ + BLI_freelistN(&lower_estrips); } /* NLA Evaluation function (mostly for use through do_animdata) @@ -2412,7 +2574,7 @@ static void animsys_calculate_nla(PointerRNA *ptr, nlaeval_init(&echannels); /* evaluate the NLA stack, obtaining a set of values to flush */ - if (animsys_evaluate_nla(&echannels, ptr, adt, anim_eval_context, flush_to_original, NULL)) { + if (animsys_evaluate_nla_for_flush(&echannels, ptr, adt, anim_eval_context, flush_to_original)) { /* reset any channels touched by currently inactive actions to default value */ animsys_evaluate_nla_domain(ptr, &echannels, adt); @@ -2448,8 +2610,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( struct ListBase *cache, struct PointerRNA *ptr, struct AnimData *adt, - const AnimationEvalContext *anim_eval_context, - const bool flush_to_original) + const AnimationEvalContext *anim_eval_context) { /* No remapping needed if NLA is off or no action. */ if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || @@ -2472,8 +2633,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( ctx->adt = adt; nlaeval_init(&ctx->lower_eval_data); - animsys_evaluate_nla( - &ctx->lower_eval_data, ptr, adt, anim_eval_context, flush_to_original, ctx); + animsys_evaluate_nla_for_keyframing(ptr, adt, anim_eval_context, ctx); BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); BLI_addtail(cache, ctx); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 4c9fb4b191a..b8a0ed087e0 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -331,6 +331,8 @@ IDTypeInfo IDType_ID_AR = { .blend_read_expand = armature_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /** \} */ diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index e1e8d06b9ec..85dabe4490c 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -526,6 +526,10 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom case CD_PROP_BOOL: return std::make_unique<ArrayReadAttribute<bool>>( domain, Span(static_cast<bool *>(layer.data), size)); + case CD_MLOOPUV: + auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); }; + return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, decltype(get_uv)>>( + domain, Span(static_cast<MLoopUV *>(layer.data), size), get_uv); } } } @@ -570,6 +574,12 @@ static WriteAttributePtr write_attribute_from_custom_data( case CD_PROP_BOOL: return std::make_unique<ArrayWriteAttribute<bool>>( domain, MutableSpan(static_cast<bool *>(layer.data), size)); + case CD_MLOOPUV: + auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); }; + auto set_uv = [](MLoopUV &uv, const float2 value) { copy_v2_v2(uv.uv, value); }; + return std::make_unique< + DerivedArrayWriteAttribute<MLoopUV, float2, decltype(get_uv), decltype(set_uv)>>( + domain, MutableSpan(static_cast<MLoopUV *>(layer.data), size), get_uv, set_uv); } } } @@ -597,8 +607,9 @@ static void get_custom_data_layer_attribute_names(const CustomData &custom_data, Set<std::string> &r_names) { for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) { - if (component.attribute_domain_with_type_supported(domain, - static_cast<CustomDataType>(layer.type))) { + const CustomDataType data_type = static_cast<CustomDataType>(layer.type); + if (component.attribute_domain_with_type_supported(domain, data_type) || + ELEM(data_type, CD_MLOOPUV)) { r_names.add(layer.name); } } @@ -1327,7 +1338,7 @@ Set<std::string> MeshComponent::attribute_names() const for (StringRef name : vertex_group_names_.keys()) { names.add(name); } - get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_CORNER, names); + get_custom_data_layer_attribute_names(mesh_->ldata, *this, ATTR_DOMAIN_CORNER, names); get_custom_data_layer_attribute_names(mesh_->vdata, *this, ATTR_DOMAIN_POINT, names); get_custom_data_layer_attribute_names(mesh_->edata, *this, ATTR_DOMAIN_EDGE, names); get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_POLYGON, names); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 0855db1a943..49475c014cd 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -647,6 +647,10 @@ UserDef *BKE_blendfile_userdef_from_defaults(void) BKE_studiolight_default(userdef->light_param, userdef->light_ambient); BKE_preferences_asset_library_default_add(userdef); + /* Enable asset browser features by default for alpha testing. + * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha + * builds. */ + userdef->experimental.use_asset_browser = true; return userdef; } diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 762ced7dc5f..2ad0ac950d0 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -23,7 +23,7 @@ * - passing output paths to the visitor?, like render out. * - passing sequence strips with many images. * - passing directory paths - visitors don't know which path is a dir or a file. - * */ + */ #include <sys/stat.h> diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 9a954a89cad..28c8ae3e416 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -410,6 +410,8 @@ IDTypeInfo IDType_ID_BR = { .blend_read_expand = brush_blend_read_expand, .blend_read_undo_preserve = brush_undo_preserve, + + .lib_override_apply_post = NULL, }; static RNG *brush_rng; @@ -978,7 +980,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->fill_leak = 3; brush->gpencil_settings->fill_threshold = 0.1f; brush->gpencil_settings->fill_simplylvl = 1; - brush->gpencil_settings->fill_factor = 1; + brush->gpencil_settings->fill_factor = 1.0f; brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->hardeness = 1.0f; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index d6c31809a2e..1e2139522f1 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -142,6 +142,8 @@ IDTypeInfo IDType_ID_CF = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* TODO: make this per cache file to avoid global locks. */ diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 0ca22e34973..b0e3743add1 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -203,6 +203,8 @@ IDTypeInfo IDType_ID_CA = { .blend_read_expand = camera_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /** \} */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index c2d6d5c7594..09bd397cc78 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -285,7 +285,7 @@ static int do_step_cloth( mul_m4_v3(ob->obmat, verts->xconst); } - effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights); + effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights, false); if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) { cloth_update_verts(ob, clmd, result); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 58ce7227398..601ee57fc89 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_GR = { .blend_read_expand = collection_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /** \} */ @@ -1941,9 +1943,6 @@ static void scene_collections_build_array(Collection *collection, void *data) static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot) { - Collection *collection; - Collection **array; - *collections_array = NULL; *tot = 0; @@ -1951,7 +1950,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - collection = scene->master_collection; + Collection *collection = scene->master_collection; BLI_assert(collection != NULL); scene_collection_callback(collection, scene_collections_count, tot); @@ -1959,7 +1958,8 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + Collection **array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + *collections_array = array; scene_collection_callback(collection, scene_collections_build_array, &array); } diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 65accc66084..6bc385ecd31 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -318,7 +318,7 @@ static eContextResult ctx_data_get(bContext *C, const char *member, bContextData * * Values in order of importance * (0, -1, 1) - Where 1 is highest priority - * */ + */ if (done != 1 && recursion < 1 && C->wm.store) { C->data.recursion = 1; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index ebce28c4e23..5632ae28960 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -327,6 +327,8 @@ IDTypeInfo IDType_ID_CU = { .blend_read_expand = curve_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; static int cu_isectLL(const float v1[3], @@ -2373,7 +2375,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl) * 0,1,2,3,4 --> 1,2,3,4,0 * * this is why we compare last with second last - * */ + */ float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3]; BevPoint *bevp_first; diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c index 4725be6d302..63da7c1dd11 100644 --- a/source/blender/blenkernel/intern/curve_deform.c +++ b/source/blender/blenkernel/intern/curve_deform.c @@ -233,7 +233,7 @@ static bool calc_curve_deform( * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell * * note: moved functions into quat_apply_track/vec_apply_track - * */ + */ copy_qt_qt(quat, new_quat); copy_v3_v3(cent, co); diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index b0994fb683a..37e9c810123 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -212,9 +212,9 @@ static void layerFree_mdeformvert(void *data, int count, int size) /* copy just zeros in this case */ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count) { - int i, size = sizeof(void *); + const int size = sizeof(void *); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { void **ptr = POINTER_OFFSET(dest, i * size); *ptr = NULL; } @@ -253,15 +253,14 @@ static void layerInterp_mdeformvert(const void **sources, MDeformVert *dvert = dest; struct MDeformWeight_Link *dest_dwlink = NULL; struct MDeformWeight_Link *node; - int i, j, totweight; /* build a list of unique def_nrs for dest */ - totweight = 0; - for (i = 0; i < count; i++) { + int totweight = 0; + for (int i = 0; i < count; i++) { const MDeformVert *source = sources[i]; float interp_weight = weights[i]; - for (j = 0; j < source->totweight; j++) { + for (int j = 0; j < source->totweight; j++) { MDeformWeight *dw = &source->dw[j]; float weight = dw->weight * interp_weight; @@ -311,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources, if (totweight) { dvert->totweight = totweight; - for (i = 0, node = dest_dwlink; node; node = node->next, i++) { + int i = 0; + for (node = dest_dwlink; node; node = node->next, i++) { if (node->dw.weight > 1.0f) { node->dw.weight = 1.0f; } @@ -416,18 +416,16 @@ static void layerInterp_tface( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { MTFace *tf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const MTFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -446,9 +444,8 @@ static void layerSwap_tface(void *data, const int *corner_indices) { MTFace *tf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { const int source_index = corner_indices[j]; copy_v2_v2(uv[j], tf->uv[source_index]); } @@ -517,18 +514,16 @@ static void layerInterp_origspace_face( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { OrigSpaceFace *osf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const OrigSpaceFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -546,9 +541,8 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices) { OrigSpaceFace *osf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { copy_v2_v2(uv[j], osf->uv[corner_indices[j]]); } memcpy(osf->uv, uv, sizeof(osf->uv)); @@ -567,13 +561,11 @@ static void layerDefault_origspace_face(void *data, int count) static void layerSwap_mdisps(void *data, const int *ci) { MDisps *s = data; - float(*d)[3] = NULL; - int corners, cornersize, S; if (s->disps) { int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */ - corners = multires_mdisp_corners(s); - cornersize = s->totdisp / corners; + int corners = multires_mdisp_corners(s); + int cornersize = s->totdisp / corners; if (corners != nverts) { /* happens when face changed vertex count in edit mode @@ -585,9 +577,9 @@ static void layerSwap_mdisps(void *data, const int *ci) return; } - d = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); + float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); - for (S = 0; S < corners; S++) { + for (int S = 0; S < corners; S++) { memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize); } @@ -1128,9 +1120,8 @@ static void layerSwap_mcol(void *data, const int *corner_indices) { MCol *mcol = data; MCol col[4]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { col[j] = mcol[corner_indices[j]]; } @@ -2064,13 +2055,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void CustomData_update_typemap(CustomData *data) { - int i, lasttype = -1; + int lasttype = -1; - for (i = 0; i < CD_NUMTYPES; i++) { + for (int i = 0; i < CD_NUMTYPES; i++) { data->typemap[i] = -1; } - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { const int type = data->layers[i].type; if (type != lasttype) { data->typemap[type] = i; @@ -2097,18 +2088,16 @@ bool CustomData_merge(const struct CustomData *source, { /*const LayerTypeInfo *typeInfo;*/ CustomDataLayer *layer, *newlayer; - void *data; - int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, - flag = 0; + int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; int number = 0, maxnumber = -1; bool changed = false; - for (i = 0; i < source->totlayer; i++) { + for (int i = 0; i < source->totlayer; i++) { layer = &source->layers[i]; /*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/ - type = layer->type; - flag = layer->flag; + int type = layer->type; + int flag = layer->flag; if (type != lasttype) { number = 0; @@ -2136,6 +2125,7 @@ bool CustomData_merge(const struct CustomData *source, continue; } + void *data; switch (alloctype) { case CD_ASSIGN: case CD_REFERENCE: @@ -2518,8 +2508,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, /* Passing a layer-data to copy from with an alloctype that won't copy is * most likely a bug */ - BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) || - (alloctype == CD_REFERENCE)); + BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; @@ -2616,10 +2605,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void *CustomData_add_layer( CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem) { - CustomDataLayer *layer; const LayerTypeInfo *typeInfo = layerType_getInfo(type); - layer = customData_add_layer__internal( + CustomDataLayer *layer = customData_add_layer__internal( data, type, alloctype, layerdata, totelem, typeInfo->defaultname); CustomData_update_typemap(data); @@ -2638,9 +2626,8 @@ void *CustomData_add_layer_named(CustomData *data, int totelem, const char *name) { - CustomDataLayer *layer; - - layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, alloctype, layerdata, totelem, name); CustomData_update_typemap(data); if (layer) { @@ -2828,12 +2815,10 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type) void CustomData_free_temporary(CustomData *data, int totelem) { - CustomDataLayer *layer; int i, j; bool changed = false; - for (i = 0, j = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; + CustomDataLayer *layer = &data->layers[i]; if (i != j) { data->layers[j] = data->layers[i]; @@ -3681,10 +3666,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) { - const LayerTypeInfo *typeInfo; int offset = data->layers[n].offset; - - typeInfo = layerType_getInfo(data->layers[n].type); + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); if (typeInfo->set_default) { typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); @@ -4050,7 +4033,6 @@ void CustomData_bmesh_interp(CustomData *data, return; } - int i, j; void *source_buf[SOURCE_BUF_SIZE]; const void **sources = (const void **)source_buf; @@ -4071,11 +4053,11 @@ void CustomData_bmesh_interp(CustomData *data, } /* interpolates a layer at a time */ - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->interp) { - for (j = 0; j < count; j++) { + for (int j = 0; j < count; j++) { sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset); } CustomData_bmesh_interp_n( @@ -4453,7 +4435,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons void CustomData_layers__print(CustomData *data) { - printf("{\n"); int i; @@ -4508,10 +4489,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int { CustomDataExternal *external = data->external; CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; char filename[FILE_MAX]; - const LayerTypeInfo *typeInfo; int update = 0; if (!external) { @@ -4520,7 +4498,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4539,7 +4517,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); if (!cdf_read_open(cdf, filename)) { cdf_free(cdf); CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename); @@ -4548,7 +4526,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4557,7 +4535,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int /* pass */ } else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (blay) { if (cdf_read_layer(cdf, blay)) { @@ -4584,10 +4562,6 @@ void CustomData_external_write( CustomData *data, ID *id, CustomDataMask mask, int totelem, int free) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; - const LayerTypeInfo *typeInfo; int update = 0; char filename[FILE_MAX]; @@ -4597,8 +4571,8 @@ void CustomData_external_write( /* test if there is anything to write */ for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4616,11 +4590,11 @@ void CustomData_external_write( CustomData_external_read(data, id, mask, totelem); customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) { if (layer->flag & CD_FLAG_IN_MEMORY) { @@ -4642,11 +4616,11 @@ void CustomData_external_write( int i; for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (cdf_write_layer(cdf, blay)) { if (typeInfo->write(cdf, layer->data, totelem)) { @@ -4670,8 +4644,8 @@ void CustomData_external_write( } for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { if (free) { @@ -4691,15 +4665,13 @@ void CustomData_external_add( CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - int layer_index; - layer_index = CustomData_get_active_layer_index(data, type); + int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return; } - layer = &data->layers[layer_index]; + CustomDataLayer *layer = &data->layers[layer_index]; if (layer->flag & CD_FLAG_EXTERNAL) { return; @@ -4823,8 +4795,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye cd_interp interp_cd = NULL; cd_copy copy_cd = NULL; - void *tmp_dst; - if (!sources) { /* Not supported here, abort. */ return; @@ -4841,7 +4811,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye copy_cd = type_info->copy; } - tmp_dst = MEM_mallocN(data_size, __func__); + void *tmp_dst = MEM_mallocN(data_size, __func__); if (count > 1 && !interp_cd) { if (data_flag) { diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 375792a02c2..58c050493c9 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -488,6 +488,7 @@ void BKE_displist_fill(ListBase *dispbase, while (cont) { int dl_flag_accum = 0; + int dl_rt_accum = 0; cont = 0; totvert = 0; nextcol = 0; @@ -535,6 +536,7 @@ void BKE_displist_fill(ListBase *dispbase, } } dl_flag_accum |= dl->flag; + dl_rt_accum |= dl->rt; } } @@ -544,6 +546,7 @@ void BKE_displist_fill(ListBase *dispbase, dlnew = MEM_callocN(sizeof(DispList), "filldisplist"); dlnew->type = DL_INDEX3; dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE)); + dlnew->rt = (dl_rt_accum & CU_SMOOTH); dlnew->col = colnr; dlnew->nr = totvert; dlnew->parts = tot; @@ -1129,7 +1132,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, * * The right solution would be to COW the Curve data block at the input of the modifier * stack just like what the mesh modifier does. - * */ + */ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 811a27c9f3f..31860bbe0b4 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -5156,7 +5156,8 @@ static int dynamicPaint_prepareEffectStep(struct Depsgraph *depsgraph, /* Init force data if required */ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { - ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights); + ListBase *effectors = BKE_effectors_create( + depsgraph, ob, NULL, surface->effector_weights, false); /* allocate memory for force data (dir vector + strength) */ *force = MEM_mallocN(sizeof(float[4]) * sData->total_points, "PaintEffectForces"); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 13e9bb1bf24..4104b6080c5 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -270,11 +270,71 @@ void BKE_effector_relations_free(ListBase *lb) } } +/* Check that the force field isn't disabled via its flags. */ +static bool is_effector_enabled(PartDeflect *pd, bool use_rotation) +{ + switch (pd->forcefield) { + case PFIELD_BOID: + case PFIELD_GUIDE: + return true; + + case PFIELD_TEXTURE: + return (pd->flag & PFIELD_DO_LOCATION) != 0 && pd->tex != NULL; + + default: + if (use_rotation) { + return (pd->flag & (PFIELD_DO_LOCATION | PFIELD_DO_ROTATION)) != 0; + } + else { + return (pd->flag & PFIELD_DO_LOCATION) != 0; + } + } +} + +/* Check that the force field won't have zero effect due to strength settings. */ +static bool is_effector_nonzero_strength(PartDeflect *pd) +{ + if (pd->f_strength != 0.0f) { + return true; + } + + if (pd->forcefield == PFIELD_TEXTURE) { + return false; + } + + if (pd->f_noise > 0.0f || pd->f_flow != 0.0f) { + return true; + } + + switch (pd->forcefield) { + case PFIELD_BOID: + case PFIELD_GUIDE: + return true; + + case PFIELD_VORTEX: + return pd->shape != PFIELD_SHAPE_POINT; + + case PFIELD_DRAG: + return pd->f_damp != 0.0f; + + default: + return false; + } +} + +/* Check if the force field will affect its user. */ +static bool is_effector_relevant(PartDeflect *pd, EffectorWeights *weights, bool use_rotation) +{ + return (weights->weight[pd->forcefield] != 0.0f) && is_effector_enabled(pd, use_rotation) && + is_effector_nonzero_strength(pd); +} + /* Create effective list of effectors from relations built beforehand. */ ListBase *BKE_effectors_create(Depsgraph *depsgraph, Object *ob_src, ParticleSystem *psys_src, - EffectorWeights *weights) + EffectorWeights *weights, + bool use_rotation) { Scene *scene = DEG_get_evaluated_scene(depsgraph); ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group); @@ -299,7 +359,8 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph, } PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2; - if (weights->weight[pd->forcefield] == 0.0f) { + + if (!is_effector_relevant(pd, weights, use_rotation)) { continue; } @@ -310,7 +371,7 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph, if (ob == ob_src) { continue; } - if (weights->weight[ob->pd->forcefield] == 0.0f) { + if (!is_effector_relevant(ob->pd, weights, use_rotation)) { continue; } if (ob->pd->shape == PFIELD_SHAPE_POINTS && BKE_object_get_evaluated_mesh(ob) == NULL) { @@ -903,7 +964,9 @@ static void do_texture_effector(EffectorCache *eff, madd_v3_v3fl(force, efd->nor, fac); } - add_v3_v3(total_force, force); + if (eff->pd->flag & PFIELD_DO_LOCATION) { + add_v3_v3(total_force, force); + } } static void do_physical_effector(EffectorCache *eff, EffectorData *efd, @@ -918,6 +981,7 @@ static void do_physical_effector(EffectorCache *eff, float strength = pd->f_strength; float damp = pd->f_damp; float noise_factor = pd->f_noise; + float flow_falloff = efd->falloff; if (noise_factor > 0.0f) { strength += wind_func(rng, noise_factor); @@ -1027,6 +1091,7 @@ static void do_physical_effector(EffectorCache *eff, break; case PFIELD_FLUIDFLOW: zero_v3(force); + flow_falloff = 0; #ifdef WITH_FLUID if (pd->f_source) { float density; @@ -1036,8 +1101,7 @@ static void do_physical_effector(EffectorCache *eff, influence *= density; } mul_v3_fl(force, influence); - /* apply flow */ - madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence); + flow_falloff = influence; } } #endif @@ -1047,9 +1111,8 @@ static void do_physical_effector(EffectorCache *eff, if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec); - if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_FLUIDFLOW) == 0 && - pd->f_flow != 0.0f) { - madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); + if (!ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG) && pd->f_flow != 0.0f) { + madd_v3_v3fl(total_force, point->vel, -pd->f_flow * flow_falloff); } } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 59248e5f9f8..7fe009d51ca 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3225,7 +3225,7 @@ static void update_effectors( ListBase *effectors; /* make sure smoke flow influence is 0.0f */ fds->effector_weights->weight[PFIELD_FLUIDFLOW] = 0.0f; - effectors = BKE_effectors_create(depsgraph, ob, NULL, fds->effector_weights); + effectors = BKE_effectors_create(depsgraph, ob, NULL, fds->effector_weights, false); if (effectors) { /* Precalculate wind forces. */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index df1dbaa905f..25a0259abe3 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -176,6 +176,8 @@ IDTypeInfo IDType_ID_VF = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /***************************** VFont *******************************/ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index a47a3dbc872..dae0b757df0 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -19,6 +19,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" #include "BKE_pointcloud.h" +#include "BKE_volume.h" #include "DNA_object_types.h" @@ -52,6 +53,8 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ return new PointCloudComponent(); case GeometryComponentType::Instances: return new InstancesComponent(); + case GeometryComponentType::Volume: + return new VolumeComponent(); } BLI_assert(false); return nullptr; @@ -202,6 +205,13 @@ const PointCloud *GeometrySet::get_pointcloud_for_read() const return (component == nullptr) ? nullptr : component->get_for_read(); } +/* Returns a read-only volume or null. */ +const Volume *GeometrySet::get_volume_for_read() const +{ + const VolumeComponent *component = this->get_component_for_read<VolumeComponent>(); + return (component == nullptr) ? nullptr : component->get_for_read(); +} + /* Returns true when the geometry set has a point cloud component that has a point cloud. */ bool GeometrySet::has_pointcloud() const { @@ -216,6 +226,13 @@ bool GeometrySet::has_instances() const return component != nullptr && component->instances_amount() >= 1; } +/* Returns true when the geometry set has a volume component that has a volume. */ +bool GeometrySet::has_volume() const +{ + const VolumeComponent *component = this->get_component_for_read<VolumeComponent>(); + return component != nullptr && component->has_volume(); +} + /* Create a new geometry set that only contains the given mesh. */ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership) { @@ -263,6 +280,13 @@ PointCloud *GeometrySet::get_pointcloud_for_write() return component.get_for_write(); } +/* Returns a mutable volume or null. No ownership is transferred. */ +Volume *GeometrySet::get_volume_for_write() +{ + VolumeComponent &component = this->get_component_for_write<VolumeComponent>(); + return component.get_for_write(); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -545,6 +569,85 @@ bool InstancesComponent::is_empty() const /** \} */ /* -------------------------------------------------------------------- */ +/** \name Volume Component + * \{ */ + +VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) +{ +} + +VolumeComponent::~VolumeComponent() +{ + this->clear(); +} + +GeometryComponent *VolumeComponent::copy() const +{ + VolumeComponent *new_component = new VolumeComponent(); + if (volume_ != nullptr) { + new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void VolumeComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (volume_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, volume_); + } + volume_ = nullptr; + } +} + +bool VolumeComponent::has_volume() const +{ + return volume_ != nullptr; +} + +/* Clear the component and replace it with the new volume. */ +void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + volume_ = volume; + ownership_ = ownership; +} + +/* Return the volume and clear the component. The caller takes over responsibility for freeing the + * volume (if the component was responsible before). */ +Volume *VolumeComponent::release() +{ + BLI_assert(this->is_mutable()); + Volume *volume = volume_; + volume_ = nullptr; + return volume; +} + +/* Get the volume from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ +const Volume *VolumeComponent::get_for_read() const +{ + return volume_; +} + +/* Get the volume from this component. This method can only be used when the component is mutable, + * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ +Volume *VolumeComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + volume_ = BKE_volume_copy_for_eval(volume_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return volume_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name C API * \{ */ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f68a390db64..0c813c170ad 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -93,7 +93,33 @@ static void greasepencil_copy_data(Main *UNUSED(bmain), /* make a copy of source layer and its data */ /* TODO here too could add unused flags... */ - bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); + bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src, true, true); + + /* Apply local layer transform to all frames. Calc the active frame is not enough + * because onion skin can use more frames. This is more slow but required here. */ + if (gpl_dst->actframe != NULL) { + bool transfomed = ((!is_zero_v3(gpl_dst->location)) || (!is_zero_v3(gpl_dst->rotation)) || + (!is_one_v3(gpl_dst->scale))); + if (transfomed) { + loc_eul_size_to_mat4( + gpl_dst->layer_mat, gpl_dst->location, gpl_dst->rotation, gpl_dst->scale); + bool do_onion = ((gpl_dst->onion_flag & GP_LAYER_ONIONSKIN) != 0); + bGPDframe *init_gpf = (do_onion) ? gpl_dst->frames.first : gpl_dst->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + bGPDspoint *pt; + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(gpl_dst->layer_mat, &pt->x); + } + } + /* if not onion, exit loop. */ + if (!do_onion) { + break; + } + } + } + } BLI_addtail(&gpd_dst->layers, gpl_dst); } @@ -303,6 +329,8 @@ IDTypeInfo IDType_ID_GD = { .blend_read_expand = greasepencil_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* ************************************************** */ @@ -581,7 +609,7 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) } /* Create a copy of the frame */ - new_frame = BKE_gpencil_frame_duplicate(gpl->actframe); + new_frame = BKE_gpencil_frame_duplicate(gpl->actframe, true); /* Find frame to insert it before */ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { @@ -686,6 +714,14 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* Enable always affected by scene lights. */ gpl->flag |= GP_LAYER_USE_LIGHTS; + + /* Init transform. */ + zero_v3(gpl->location); + zero_v3(gpl->rotation); + copy_v3_fl(gpl->scale, 1.0f); + loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); + /* make this one the active one */ if (setactive) { BKE_gpencil_layer_active_set(gpd, gpl); @@ -957,7 +993,7 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, * \param gpf_src: Source grease pencil frame * \return Pointer to new frame */ -bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) +bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes) { bGPDstroke *gps_dst = NULL; bGPDframe *gpf_dst; @@ -971,12 +1007,14 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) gpf_dst = MEM_dupallocN(gpf_src); gpf_dst->prev = gpf_dst->next = NULL; - /* copy strokes */ + /* Copy strokes. */ BLI_listbase_clear(&gpf_dst->strokes); - LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { - /* make copy of source stroke */ - gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); - BLI_addtail(&gpf_dst->strokes, gps_dst); + if (dup_strokes) { + LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { + /* make copy of source stroke */ + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); + BLI_addtail(&gpf_dst->strokes, gps_dst); + } } /* return new frame */ @@ -1010,7 +1048,9 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds * \param gpl_src: Source grease pencil layer * \return Pointer to new layer */ -bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) +bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src, + const bool dup_frames, + const bool dup_strokes) { const bGPDframe *gpf_src; bGPDframe *gpf_dst; @@ -1035,14 +1075,16 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /* copy frames */ BLI_listbase_clear(&gpl_dst->frames); - for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) { - /* make a copy of source frame */ - gpf_dst = BKE_gpencil_frame_duplicate(gpf_src); - BLI_addtail(&gpl_dst->frames, gpf_dst); - - /* if source frame was the current layer's 'active' frame, reassign that too */ - if (gpf_src == gpl_dst->actframe) { - gpl_dst->actframe = gpf_dst; + if (dup_frames) { + for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) { + /* make a copy of source frame */ + gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes); + BLI_addtail(&gpl_dst->frames, gpf_dst); + + /* if source frame was the current layer's 'active' frame, reassign that too */ + if (gpf_src == gpl_dst->actframe) { + gpl_dst->actframe = gpf_dst; + } } } @@ -2519,7 +2561,7 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer, int cfra) { bGPdata *gpd = (bGPdata *)ob->data; - const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool is_multiedit = ((GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) && (!GPENCIL_PLAY_ON(gpd))); const bool is_onion = do_onion && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0); const bool is_drawing = (gpd->runtime.sbuffer_used > 0); @@ -2541,6 +2583,11 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer, continue; } + /* If scale to 0 the layer must be invisible. */ + if (is_zero_v3(gpl->scale)) { + continue; + } + /* Hide the layer if it's defined a view layer filter. This is used to * generate renders, putting only selected GP layers for each View Layer. * This is used only in final render and never in Viewport. */ @@ -2759,10 +2806,10 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev * \param gpl: Grease pencil layer * \param diff_mat: Result parent matrix */ -void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, - Object *obact, - bGPDlayer *gpl, - float diff_mat[4][4]) +void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + float diff_mat[4][4]) { Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact; Object *obparent = gpl->parent; @@ -2771,11 +2818,10 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, /* if not layer parented, try with object parented */ if (obparent_eval == NULL) { - if (ob_eval != NULL) { - if (ob_eval->type == OB_GPENCIL) { - copy_m4_m4(diff_mat, ob_eval->obmat); - return; - } + if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) { + copy_m4_m4(diff_mat, ob_eval->obmat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); + return; } /* not gpencil object */ unit_m4(diff_mat); @@ -2785,6 +2831,7 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } if (gpl->partype == PARBONE) { @@ -2800,6 +2847,7 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); add_v3_v3(diff_mat[3], ob_eval->obmat[3]); } + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } @@ -2807,11 +2855,11 @@ void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, } /** - * Update parent matrix. + * Update parent matrix and local transforms. * \param depsgraph: Depsgraph * \param ob: Grease pencil object */ -void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob) +void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob) { if (ob->type != OB_GPENCIL) { return; @@ -2820,31 +2868,50 @@ void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob) bGPdata *gpd = (bGPdata *)ob->data; float cur_mat[4][4]; + bool changed = false; LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - if ((gpl->parent != NULL) && (gpl->actframe != NULL)) { - Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent); - /* calculate new matrix */ - if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - copy_m4_m4(cur_mat, ob_parent->obmat); - } - else if (gpl->partype == PARBONE) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr); - if (pchan != NULL) { - copy_m4_m4(cur_mat, ob->imat); - mul_m4_m4m4(cur_mat, ob_parent->obmat, pchan->pose_mat); + unit_m4(cur_mat); + if (gpl->actframe != NULL) { + if (gpl->parent != NULL) { + Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent); + /* calculate new matrix */ + if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { + copy_m4_m4(cur_mat, ob_parent->obmat); } - else { - unit_m4(cur_mat); + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr); + if (pchan != NULL) { + copy_m4_m4(cur_mat, ob->imat); + mul_m4_m4m4(cur_mat, ob_parent->obmat, pchan->pose_mat); + } + else { + unit_m4(cur_mat); + } } + changed = !equals_m4m4(gpl->inverse, cur_mat); + } + + /* Calc local layer transform. */ + bool transfomed = ((!is_zero_v3(gpl->location)) || (!is_zero_v3(gpl->rotation)) || + (!is_one_v3(gpl->scale))); + if (transfomed) { + loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale); } + /* only redo if any change */ - if (!equals_m4m4(gpl->inverse, cur_mat)) { + if (changed || transfomed) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { bGPDspoint *pt; int i; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - mul_m4_v3(gpl->inverse, &pt->x); - mul_m4_v3(cur_mat, &pt->x); + if (changed) { + mul_m4_v3(gpl->inverse, &pt->x); + mul_m4_v3(cur_mat, &pt->x); + } + + if (transfomed) { + mul_m4_v3(gpl->layer_mat, &pt->x); + } } } } diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 1be2cba31b5..8b12e1b5fca 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -701,13 +701,18 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o Object *ob_orig = (Object *)DEG_get_original_id(&ob->id); bGPdata *gpd_orig = (bGPdata *)ob_orig->data; - /* Need check if some layer is parented. */ + /* Need check if some layer is parented or transformed. */ bool do_parent = false; + bool do_transform = false; LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { if (gpl->parent != NULL) { do_parent = true; break; } + if ((!is_zero_v3(gpl->location)) || (!is_zero_v3(gpl->rotation)) || (!is_one_v3(gpl->scale))) { + do_transform = true; + break; + } } const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_eval); @@ -715,7 +720,7 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o const bool do_modifiers = (bool)((!is_multiedit) && (!is_curve_edit) && (ob->greasepencil_modifiers.first != NULL) && (!GPENCIL_SIMPLIFY_MODIF(scene))); - if ((!do_modifiers) && (!do_parent)) { + if ((!do_modifiers) && (!do_parent) && (!do_transform)) { return; } DEG_debug_print_eval(depsgraph, __func__, gpd_eval->id.name, gpd_eval); diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index a44b054e366..f76e5a73478 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -197,6 +197,8 @@ IDTypeInfo IDType_ID_HA = { .blend_read_expand = hair_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; static void hair_random(Hair *hair) diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b0991f1d343..6b164e6bc50 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -92,11 +92,9 @@ IDProperty *IDP_NewIDPArray(const char *name) IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) { /* don't use MEM_dupallocN because this may be part of an array */ - IDProperty *narray, *tmp; - BLI_assert(array->type == IDP_IDPARRAY); - narray = MEM_mallocN(sizeof(IDProperty), __func__); + IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__); *narray = *array; narray->data.pointer = MEM_dupallocN(array->data.pointer); @@ -107,7 +105,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) * then free it. this makes for more maintainable * code than simply re-implementing the copy functions * in this loop.*/ - tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); + IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); MEM_freeN(tmp); } @@ -131,15 +129,13 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) /* shallow copies item */ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) { - IDProperty *old; - BLI_assert(prop->type == IDP_IDPARRAY); if (index >= prop->len || index < 0) { return; } - old = GETPROP(prop, index); + IDProperty *old = GETPROP(prop, index); if (item != old) { IDP_FreePropertyContent(old); @@ -164,8 +160,6 @@ void IDP_AppendArray(IDProperty *prop, IDProperty *item) void IDP_ResizeIDPArray(IDProperty *prop, int newlen) { - int newsize; - BLI_assert(prop->type == IDP_IDPARRAY); /* first check if the array buffer size has room */ @@ -200,7 +194,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); prop->len = newlen; @@ -218,9 +212,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /* bigger */ IDProperty **array = newarr; IDPropertyTemplate val; - int a; - for (a = prop->len; a < newlen; a++) { + for (int a = prop->len; a < newlen; a++) { val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group"); } @@ -228,9 +221,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) else { /* smaller */ IDProperty **array = prop->data.pointer; - int a; - for (a = newlen; a < prop->len; a++) { + for (int a = newlen; a < prop->len; a++) { IDP_FreeProperty(array[a]); } } @@ -239,7 +231,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /*this function works for strings too!*/ void IDP_ResizeArray(IDProperty *prop, int newlen) { - int newsize; const bool is_grow = newlen >= prop->len; /* first check if the array buffer size has room */ @@ -257,7 +248,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; if (is_grow == false) { @@ -362,10 +353,8 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_STRING); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); if (prop->data.pointer) { newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -379,10 +368,8 @@ static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) { - int stlen; - BLI_assert(prop->type == IDP_STRING); - stlen = (int)strlen(st); + int stlen = (int)strlen(st); if (maxlen > 0 && maxlen < stlen) { stlen = maxlen; } @@ -400,11 +387,9 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) void IDP_ConcatStringC(IDProperty *prop, const char *st) { - int newlen; - BLI_assert(prop->type == IDP_STRING); - newlen = prop->len + (int)strlen(st); + int newlen = prop->len + (int)strlen(st); /* we have to remember that prop->len includes the null byte for strings. * so there's no need to add +1 to the resize function.*/ IDP_ResizeArray(prop, newlen); @@ -413,13 +398,11 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st) void IDP_ConcatString(IDProperty *str1, IDProperty *append) { - int newlen; - BLI_assert(append->type == IDP_STRING); /* since ->len for strings includes the NULL byte, we have to subtract one or * we'll get an extra null byte after each concatenation operation.*/ - newlen = str1->len + append->len - 1; + int newlen = str1->len + append->len - 1; IDP_ResizeArray(str1, newlen); strcat(str1->data.pointer, append->data.pointer); } @@ -440,10 +423,8 @@ void IDP_FreeString(IDProperty *prop) static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_ID); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->data.pointer = prop->data.pointer; if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -479,14 +460,12 @@ void IDP_AssignID(IDProperty *prop, ID *id, const int flag) */ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) { - IDProperty *newp, *link; - BLI_assert(prop->type == IDP_GROUP); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->len = prop->len; newp->subtype = prop->subtype; - for (link = prop->data.group.first; link; link = link->next) { + LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) { BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); } @@ -497,13 +476,11 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) * When values name and types match, copy the values, else ignore */ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) { - IDProperty *other, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { - other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); if (other && prop->type == other->type) { switch (prop->type) { case IDP_INT: @@ -526,12 +503,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen) { - IDProperty *prop_dst, *prop_dst_next; - const IDProperty *prop_src; - - for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) { - prop_dst_next = prop_dst->next; - if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) { + LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) { + const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name); + if (prop_src != NULL) { /* check of we should replace? */ if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && @@ -554,12 +528,11 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a */ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) { - IDProperty *loop, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *loop; for (loop = dest->data.group.first; loop; loop = loop->next) { if (STREQ(loop->name, prop->name)) { BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); @@ -612,13 +585,11 @@ void IDP_MergeGroup_ex(IDProperty *dest, const bool do_overwrite, const int flag) { - IDProperty *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); if (do_overwrite) { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { if (prop->type == IDP_GROUP) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); @@ -633,7 +604,7 @@ void IDP_MergeGroup_ex(IDProperty *dest, } } else { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); if (prop_exist != NULL) { if (prop->type == IDP_GROUP) { @@ -741,10 +712,9 @@ IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *nam * direct data. */ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) { - IDProperty *loop; - BLI_assert(prop->type == IDP_GROUP); - for (loop = prop->data.group.first; loop; loop = loop->next) { + + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_FreePropertyContent_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); @@ -863,14 +833,12 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is } return false; case IDP_GROUP: { - IDProperty *link1, *link2; - if (is_strict && prop1->len != prop2->len) { return false; } - for (link1 = prop1->data.group.first; link1; link1 = link1->next) { - link2 = IDP_GetPropertyFromGroup(prop2, link1->name); + LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) { + IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name); if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) { return false; @@ -1158,11 +1126,10 @@ static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { const IDProperty *array = prop->data.pointer; - int a; BLO_write_struct_array(writer, IDProperty, prop->len, array); - for (a = 0; a < prop->len; a++) { + for (int a = 0; a < prop->len; a++) { IDP_WriteProperty_OnlyData(&array[a], writer); } } @@ -1176,9 +1143,7 @@ static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) { - IDProperty *loop; - - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_BlendWrite(writer, loop); } } @@ -1212,13 +1177,11 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty *array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; BLO_read_data_address(reader, &prop->data.pointer); - array = (IDProperty *)prop->data.pointer; + IDProperty *array = (IDProperty *)prop->data.pointer; /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared * there's not really anything we can do to correct this, at least don't crash */ @@ -1234,14 +1197,12 @@ static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty **array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; if (prop->subtype == IDP_GROUP) { BLO_read_pointer_array(reader, &prop->data.pointer); - array = prop->data.pointer; + IDProperty **array = prop->data.pointer; for (int i = 0; i < prop->len; i++) { IDP_DirectLinkProperty(array[i], reader); @@ -1266,12 +1227,11 @@ static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader) { ListBase *lb = &prop->data.group; - IDProperty *loop; BLO_read_list(reader, lb); /*Link child id properties now*/ - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_DirectLinkProperty(loop, reader); } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ab57d14d2cf..10f15519ea4 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -338,6 +338,8 @@ IDTypeInfo IDType_ID_IM = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* prototypes */ diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 1ab6e61e20e..d43a0cb3813 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -200,6 +200,8 @@ IDTypeInfo IDType_ID_IP = { .blend_read_expand = ipo_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* *************************************************** */ diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 433d64a5927..540337b84b3 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -223,6 +223,8 @@ IDTypeInfo IDType_ID_KE = { .blend_read_expand = shapekey_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; #define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 74f78106be5..3d3ade1a529 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -205,6 +205,8 @@ IDTypeInfo IDType_ID_LT = { .blend_read_expand = lattice_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w) diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 13f76b46570..54c2f5f5565 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -112,6 +112,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* GS reads the memory pointed at in a specific ordering. @@ -1793,32 +1795,31 @@ static void library_make_local_copying_check(ID *id, return; /* Already checked, nothing else to do. */ } - MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id); + MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->relations_from_pointers, id); BLI_gset_insert(loop_tags, id); - for (; entry != NULL; entry = entry->next) { - - /* Used_to_user stores ID pointer, not pointer to ID pointer. */ - ID *par_id = (ID *)entry->id_pointer; - + for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL; + from_id_entry = from_id_entry->next) { /* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual * relation we want to check is in the other way around. */ - if (entry->usage_flag & IDWALK_CB_LOOPBACK) { + if (from_id_entry->usage_flag & IDWALK_CB_LOOPBACK) { continue; } + ID *from_id = from_id_entry->id_pointer.from; + /* Shape-keys are considered 'private' to their owner ID here, and never tagged * (since they cannot be linked), so we have to switch effective parent to their owner. */ - if (GS(par_id->name) == ID_KE) { - par_id = ((Key *)par_id)->from; + if (GS(from_id->name) == ID_KE) { + from_id = ((Key *)from_id)->from; } - if (par_id->lib == NULL) { + if (from_id->lib == NULL) { /* Local user, early out to avoid some gset querying... */ continue; } - if (!BLI_gset_haskey(done_ids, par_id)) { - if (BLI_gset_haskey(loop_tags, par_id)) { + if (!BLI_gset_haskey(done_ids, from_id)) { + if (BLI_gset_haskey(loop_tags, from_id)) { /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it. * Note that this is the situation that can lead to archipelagoes of linked data-blocks * (since all of them have non-local users, they would all be duplicated, @@ -1827,10 +1828,10 @@ static void library_make_local_copying_check(ID *id, continue; } /* Else, recursively check that user ID. */ - library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids); + library_make_local_copying_check(from_id, loop_tags, id_relations, done_ids); } - if (par_id->tag & LIB_TAG_DOIT) { + if (from_id->tag & LIB_TAG_DOIT) { /* This user will be fully local in future, so far so good, * nothing to do here but check next user. */ } diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index e4094c48368..9e8e515e1a3 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -368,118 +368,154 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) return success; } -static bool lib_override_hierarchy_recursive_tag(Main *bmain, - ID *id, - const uint tag, - const uint missing_tag, - Library *override_group_lib_reference) +/* Tag all IDs in dependency relationships within an override hierarchy/group. + * + * Note: this is typically called to complete `lib_override_linked_group_tag()`. + * Note: BMain's relations mapping won't be valid anymore after that call. + */ +static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain, + ID *id, + const uint tag, + const uint missing_tag) { - void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id); - if (entry_vp == NULL) { - /* Already processed. */ - return (id->tag & tag) != 0; - } + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); + BLI_assert(entry != NULL); - /* Note: in case some reference ID is missing from linked data (and therefore its override uses - * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */ - if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && - id->override_library->reference->lib == override_group_lib_reference) { - if (id->override_library->reference->tag & LIB_TAG_MISSING) { - id->tag |= missing_tag; - } - else { - id->tag |= tag; - } + if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { + /* This ID has already been processed. */ + return (*(uint *)&id->tag & tag) != 0; } - /* This way we won't process again that ID, should we encounter it again through another - * relationship hierarchy. - * Note that this does not free any memory from relations, so we can still use the entries. - */ - BKE_main_relations_ID_remove(bmain, id); + * relationship hierarchy. */ + entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntry *entry = *entry_vp; entry != NULL; entry = entry->next) { - if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + to_id_entry = to_id_entry->next) { + if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as * actual dependencies. */ continue; } /* We only consider IDs from the same library. */ - if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) { - if (lib_override_hierarchy_recursive_tag( - bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) && - override_group_lib_reference == NULL) { + ID *to_id = *to_id_entry->id_pointer.to; + if (to_id != NULL && to_id->lib == id->lib) { + if (lib_override_hierarchy_dependencies_recursive_tag(bmain, to_id, tag, missing_tag)) { id->tag |= tag; } } } - return (id->tag & tag) != 0; + return (*(uint *)&id->tag & tag) != 0; } -/** - * Tag all IDs in given \a bmain that are being used by given \a id_root ID or its dependencies, - * recursively. - * It detects and tag only chains of dependencies marked at both ends by given tag. - * - * This will include all local IDs, and all IDs from the same library as the \a id_root. - * - * \param id_root: The root of the hierarchy of dependencies to be tagged. - * \param do_create_main_relashionships: Whether main relations needs to be created or already - * exist (in any case, they will be freed by this function). - */ -void BKE_lib_override_library_dependencies_tag(Main *bmain, - ID *id_root, - const uint tag, - const bool do_create_main_relashionships) +typedef struct LibOverrideGroupTagData { + ID *id_root; + uint tag; + uint missing_tag; +} LibOverrideGroupTagData; + +static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data) { - if (do_create_main_relashionships) { - BKE_main_relations_create(bmain, 0); + if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) { + return IDWALK_RET_STOP_RECURSION; } - /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key - * has a driver using an armature object's bone, we need to override the shape-key/obdata, - * the objects using them, etc.) */ - lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL); + LibOverrideGroupTagData *data = cb_data->user_data; + const uint tag = data->tag; + const uint missing_tag = data->missing_tag; - BKE_main_relations_free(bmain); + ID *id_root = data->id_root; + Library *library_root = id_root->lib; + ID *id = *cb_data->id_pointer; + ID *id_owner = cb_data->id_owner; + + BLI_assert(id_owner == cb_data->id_self); + + if (ELEM(id, NULL, id_owner)) { + return IDWALK_RET_NOP; + } + + BLI_assert(id_owner->lib == library_root); + + if (*(uint *)&id->tag & (tag | missing_tag)) { + /* Already processed and tagged, nothing else to do here. */ + return IDWALK_RET_STOP_RECURSION; + } + + if (id->lib != library_root) { + /* We do not override data-blocks from other libraries, nor do we process them. */ + return IDWALK_RET_STOP_RECURSION; + } + + /* We tag all collections and objects for override. And we also tag all other data-blocks which + * would use one of those. + * Note: missing IDs (aka placeholders) are never overridden. */ + if (ELEM(GS(id->name), ID_OB, ID_GR)) { + if ((id->tag & LIB_TAG_MISSING)) { + id->tag |= missing_tag; + } + else { + id->tag |= tag; + } + } + + return IDWALK_RET_NOP; } -/** - * Tag all IDs in given \a bmain that are part of the same \a id_root liboverride ID group. - * That is, all other liboverride IDs (in)directly used by \a is_root one, and sharing the same - * library for their reference IDs. +/* This will tag at least all 'boundary' linked IDs for a potential override group. * - * \param id_root: The root of the hierarchy of liboverride dependencies to be tagged. - * \param do_create_main_relashionships: Whether main relations needs to be created or already - * exist (in any case, they will be freed by this function). + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. + * + * We currently only consider Collections and Objects (that are not used as bone shapes) as valid + * boundary IDs to define an override group. */ -void BKE_lib_override_library_override_group_tag(Main *bmain, - ID *id_root, - const uint tag, - const uint missing_tag, - const bool do_create_main_relashionships) +static void lib_override_linked_group_tag( + Main *bmain, ID *id, const uint tag, const uint missing_tag, const bool create_bmain_relations) { - if (do_create_main_relashionships) { + if (create_bmain_relations) { BKE_main_relations_create(bmain, 0); } - /* We tag all liboverride data-blocks from the same library as reference one, - * being used by the root ID. */ - lib_override_hierarchy_recursive_tag( - bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib); + if (ELEM(GS(id->name), ID_OB, ID_GR)) { + LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag}; + /* Tag all collections and objects. */ + BKE_library_foreach_ID_link( + bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE); - BKE_main_relations_free(bmain); + /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly + * override those. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & tag)) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + if (pchan->custom != NULL) { + pchan->custom->id.tag &= ~(tag | missing_tag); + } + } + } + } + } + + lib_override_hierarchy_dependencies_recursive_tag(bmain, id, tag, missing_tag); + + if (create_bmain_relations) { + BKE_main_relations_free(bmain); + } } -static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_data) +static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data) { - if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) { + if (cb_data->cb_flag & + (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { return IDWALK_RET_STOP_RECURSION; } - ID *id_root = cb_data->user_data; - Library *library_root = id_root->lib; + LibOverrideGroupTagData *data = cb_data->user_data; + const uint tag = data->tag; + const uint missing_tag = data->missing_tag; + + ID *id_root = data->id_root; + Library *library_reference_root = id_root->override_library->reference->lib; ID *id = *cb_data->id_pointer; ID *id_owner = cb_data->id_owner; @@ -489,62 +525,69 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da return IDWALK_RET_NOP; } - BLI_assert(id->lib != NULL); - BLI_assert(id_owner->lib == library_root); - - if (id->tag & LIB_TAG_DOIT) { + if (*(uint *)&id->tag & (tag | missing_tag)) { /* Already processed and tagged, nothing else to do here. */ return IDWALK_RET_STOP_RECURSION; } - if (id->lib != library_root) { + if (!ID_IS_OVERRIDE_LIBRARY(id) || ID_IS_LINKED(id)) { + /* Fully local, or linked ID, those are never part of a local override group. */ + return IDWALK_RET_STOP_RECURSION; + } + + /* NOTE: Since we rejected embedded data too at the beginning of this function, id should only be + * a real override now. + * + * However, our usual trouble maker, Key, is not considered as an embedded ID currently, yet it + * is never a real override either. Enjoy. */ + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + return IDWALK_RET_NOP; + } + + if (id->override_library->reference->lib != library_reference_root) { /* We do not override data-blocks from other libraries, nor do we process them. */ return IDWALK_RET_STOP_RECURSION; } - /* We tag all collections and objects for override. And we also tag all other data-blocks which - * would use one of those. - * Note: missing IDs (aka placeholders) are never overridden. */ - if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) { - id->tag |= LIB_TAG_DOIT; + if (id->override_library->reference->tag & LIB_TAG_MISSING) { + id->tag |= missing_tag; + } + else { + id->tag |= tag; } return IDWALK_RET_NOP; } +/* This will tag at least all 'boundary' linked IDs for a potential override group. + * + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. + * + * We currently only consider Collections and Objects (that are not used as bone shapes) as valid + * boundary IDs to define an override group. + */ +static void lib_override_local_group_tag(Main *bmain, + ID *id, + const uint tag, + const uint missing_tag) +{ + LibOverrideGroupTagData data = {.id_root = id, .tag = tag, .missing_tag = missing_tag}; + /* Tag all local overrides in id_root's group. */ + BKE_library_foreach_ID_link( + bmain, id, lib_override_local_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE); +} + static bool lib_override_library_create_do(Main *bmain, ID *id_root) { id_root->tag |= LIB_TAG_DOIT; BKE_main_relations_create(bmain, 0); - if (ELEM(GS(id_root->name), ID_OB, ID_GR)) { - /* Tag all collections and objects. */ - BKE_library_foreach_ID_link(bmain, - id_root, - lib_override_library_make_tag_ids_cb, - id_root, - IDWALK_READONLY | IDWALK_RECURSE); - - /* Then, we remove (untag) bone shape objects, you shall never want to override those - * (hopefully). */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & LIB_TAG_DOIT)) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL) { - pchan->custom->id.tag &= ~LIB_TAG_DOIT; - } - } - } - } - } + lib_override_linked_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, false); + lib_override_hierarchy_dependencies_recursive_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING); - /* Now tag all non-object/collection IDs 'in-between' two tagged ones, as those are part of an - * override chain and therefore also need to be overridden. - * One very common cases are e.g. drivers on geometry or materials of an overridden object, that - * are using another overridden object as parameter. */ - /* Note that this call will also free the main relations data we created above. */ - BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, false); + BKE_main_relations_free(bmain); return BKE_lib_override_library_create_from_tag(bmain); } @@ -737,14 +780,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ { BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); - /* Tag all collections and objects, as well as other IDs using them. */ id_root->tag |= LIB_TAG_DOIT; ID *id_root_reference = id_root->override_library->reference; - /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag - * linked reference ones to be overridden again. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true); + lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING); + + lib_override_linked_group_tag(bmain, id_root_reference, LIB_TAG_DOIT, LIB_TAG_MISSING, true); + /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides. */ GHash *linkedref_to_old_override = BLI_ghash_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); ID *id; @@ -755,7 +798,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ * same linked ID in a same hierarchy. */ if (!BLI_ghash_haskey(linkedref_to_old_override, id->override_library->reference)) { BLI_ghash_insert(linkedref_to_old_override, id->override_library->reference, id); - id->override_library->reference->tag |= LIB_TAG_DOIT; + BLI_assert(id->override_library->reference->tag & LIB_TAG_DOIT); } } } @@ -765,7 +808,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ /* Note that this call also remaps all pointers of tagged IDs from old override IDs to new * override IDs (including within the old overrides themselves, since those are tagged too * above). */ - const bool success = lib_override_library_create_do(bmain, id_root_reference); + const bool success = BKE_lib_override_library_create_from_tag(bmain); if (!success) { return success; @@ -828,6 +871,23 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ RNA_id_pointer_create(id_override_old, &rnaptr_src); RNA_id_pointer_create(id_override_new, &rnaptr_dst); + /* We remove any operation tagged with `IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE`, + * that way the potentially new pointer will be properly kept, when old one is still valid + * too (typical case: assigning new ID to some usage, while old one remains used elsewhere + * in the override hierarchy). */ + LISTBASE_FOREACH_MUTABLE ( + IDOverrideLibraryProperty *, op, &id_override_new->override_library->properties) { + LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) { + lib_override_library_property_operation_clear(opop); + BLI_freelinkN(&op->operations, opop); + } + } + if (BLI_listbase_is_empty(&op->operations)) { + BKE_lib_override_library_property_delete(id_override_new->override_library, op); + } + } + RNA_struct_override_apply( bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library); } @@ -900,7 +960,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) id_root->tag |= LIB_TAG_DOIT; /* Tag all library overrides in the chains of dependencies from the given root one. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true); + lib_override_local_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT); ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { @@ -1619,31 +1679,37 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i return; } - void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root); - if (entry_pp == NULL) { - /* Already processed. */ + void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root); + if (entry_vp == NULL) { + /* This ID is not used by nor using any other ID. */ + lib_override_library_id_reset_do(bmain, id_root); + return; + } + + MainIDRelationsEntry *entry = *entry_vp; + if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { + /* This ID has already been processed. */ return; } lib_override_library_id_reset_do(bmain, id_root); /* This way we won't process again that ID, should we encounter it again through another - * relationship hierarchy. - * Note that this does not free any memory from relations, so we can still use the entries. - */ - BKE_main_relations_ID_remove(bmain, id_root); + * relationship hierarchy. */ + entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) { - if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + to_id_entry = to_id_entry->next) { + if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) { /* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as * actual dependencies. */ continue; } /* We only consider IDs from the same library. */ - if (entry->id_pointer != NULL) { - ID *id_entry = *entry->id_pointer; - if (id_entry->override_library != NULL) { - lib_override_library_id_hierarchy_recursive_reset(bmain, id_entry); + if (*to_id_entry->id_pointer.to != NULL) { + ID *to_id = *to_id_entry->id_pointer.to; + if (to_id->override_library != NULL) { + lib_override_library_id_hierarchy_recursive_reset(bmain, to_id); } } } @@ -1922,7 +1988,9 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, ID *local) { if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) { - /* This is actually purely local data with an override template, nothing to do here! */ + /* This is actually purely local data with an override template, or one of those embedded IDs + * (root node trees, master collections or shapekeys) that cannot have their own override. + * Nothing to do here! */ return NULL; } diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index e687e94073d..8be26fc8547 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -237,9 +237,12 @@ static void library_foreach_ID_link(Main *bmain, * but we might as well use it (Main->relations is always assumed valid, * it's responsibility of code creating it to free it, * especially if/when it starts modifying Main database). */ - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id); - for (; entry != NULL; entry = entry->next) { - BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag); + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, + id); + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + to_id_entry = to_id_entry->next) { + BKE_lib_query_foreachid_process( + &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag); } continue; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 6a560d51362..d2f1196d804 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -84,6 +84,8 @@ IDTypeInfo IDType_ID_LI = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index a47a0c043ff..4a2afb7f5e6 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -209,6 +209,8 @@ IDTypeInfo IDType_ID_LA = { .blend_read_expand = light_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; Light *BKE_light_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 0553c070fdf..4ef3b8c3237 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -107,6 +107,8 @@ IDTypeInfo IDType_ID_LP = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type) diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 8542959d4b0..283e2a94732 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -767,6 +767,8 @@ IDTypeInfo IDType_ID_LS = { .blend_read_expand = linestyle_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; static const char *modifier_name[LS_MODIFIER_NUM] = { diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index 4b577ccec2c..d5cbcb62af2 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -211,35 +211,51 @@ void BKE_main_unlock(struct Main *bmain) static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data) { - MainIDRelations *rel = cb_data->user_data; + MainIDRelations *bmain_relations = cb_data->user_data; ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; const int cb_flag = cb_data->cb_flag; if (*id_pointer) { - MainIDRelationsEntry *entry, **entry_p; - - entry = BLI_mempool_alloc(rel->entry_pool); - if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) { - entry->next = *entry_p; - } - else { - entry->next = NULL; + MainIDRelationsEntry **entry_p; + + /* Add `id_pointer` as child of `id_self`. */ + { + if (!BLI_ghash_ensure_p( + bmain_relations->relations_from_pointers, id_self, (void ***)&entry_p)) { + *entry_p = MEM_callocN(sizeof(**entry_p), __func__); + (*entry_p)->session_uuid = id_self->session_uuid; + } + else { + BLI_assert((*entry_p)->session_uuid == id_self->session_uuid); + } + MainIDRelationsEntryItem *to_id_entry = BLI_mempool_alloc(bmain_relations->entry_items_pool); + to_id_entry->next = (*entry_p)->to_ids; + to_id_entry->id_pointer.to = id_pointer; + to_id_entry->session_uuid = (*id_pointer != NULL) ? (*id_pointer)->session_uuid : + MAIN_ID_SESSION_UUID_UNSET; + to_id_entry->usage_flag = cb_flag; + (*entry_p)->to_ids = to_id_entry; } - entry->id_pointer = id_pointer; - entry->usage_flag = cb_flag; - *entry_p = entry; - entry = BLI_mempool_alloc(rel->entry_pool); - if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) { - entry->next = *entry_p; - } - else { - entry->next = NULL; + /* Add `id_self` as parent of `id_pointer`. */ + if (*id_pointer != NULL) { + if (!BLI_ghash_ensure_p( + bmain_relations->relations_from_pointers, *id_pointer, (void ***)&entry_p)) { + *entry_p = MEM_callocN(sizeof(**entry_p), __func__); + (*entry_p)->session_uuid = (*id_pointer)->session_uuid; + } + else { + BLI_assert((*entry_p)->session_uuid == (*id_pointer)->session_uuid); + } + MainIDRelationsEntryItem *from_id_entry = BLI_mempool_alloc( + bmain_relations->entry_items_pool); + from_id_entry->next = (*entry_p)->from_ids; + from_id_entry->id_pointer.from = id_self; + from_id_entry->session_uuid = id_self->session_uuid; + from_id_entry->usage_flag = cb_flag; + (*entry_p)->from_ids = from_id_entry; } - entry->id_pointer = (ID **)id_self; - entry->usage_flag = cb_flag; - *entry_p = entry; } return IDWALK_RET_NOP; @@ -253,59 +269,63 @@ void BKE_main_relations_create(Main *bmain, const short flag) } bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__); - bmain->relations->id_used_to_user = BLI_ghash_new( - BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - bmain->relations->id_user_to_used = BLI_ghash_new( + bmain->relations->relations_from_pointers = BLI_ghash_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - bmain->relations->entry_pool = BLI_mempool_create( - sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP); + bmain->relations->entry_items_pool = BLI_mempool_create( + sizeof(MainIDRelationsEntryItem), 128, 128, BLI_MEMPOOL_NOP); + + bmain->relations->flag = flag; ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { const int idwalk_flag = IDWALK_READONLY | ((flag & MAINIDRELATIONS_INCLUDE_UI) != 0 ? IDWALK_INCLUDE_UI : 0); + + /* Ensure all IDs do have an entry, even if they are not connected to any other. */ + MainIDRelationsEntry **entry_p; + if (!BLI_ghash_ensure_p(bmain->relations->relations_from_pointers, id, (void ***)&entry_p)) { + *entry_p = MEM_callocN(sizeof(**entry_p), __func__); + (*entry_p)->session_uuid = id->session_uuid; + } + else { + BLI_assert((*entry_p)->session_uuid == id->session_uuid); + } + BKE_library_foreach_ID_link( NULL, id, main_relations_create_idlink_cb, bmain->relations, idwalk_flag); } FOREACH_MAIN_ID_END; - - bmain->relations->flag = flag; } void BKE_main_relations_free(Main *bmain) { - if (bmain->relations) { - if (bmain->relations->id_used_to_user) { - BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL); - } - if (bmain->relations->id_user_to_used) { - BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL); + if (bmain->relations != NULL) { + if (bmain->relations->relations_from_pointers != NULL) { + BLI_ghash_free(bmain->relations->relations_from_pointers, NULL, MEM_freeN); } - BLI_mempool_destroy(bmain->relations->entry_pool); + BLI_mempool_destroy(bmain->relations->entry_items_pool); MEM_freeN(bmain->relations); bmain->relations = NULL; } } -/** - * Remove an ID from the relations (the two entries for that ID, not the ID from entries in other - * IDs' relationships). - * - * Does not free any allocated memory. - * Allows to use those relations as a way to mark an ID as already processed, without requiring any - * additional tagging or GSet. - * Obviously, relations should be freed after use then, since this will make them fully invalid. - */ -void BKE_main_relations_ID_remove(Main *bmain, ID *id) +/** Set or clear given `tag` in all relation entries of given `bmain`. */ +void BKE_main_relations_tag_set(struct Main *bmain, + const MainIDRelationsEntryTags tag, + const bool value) { - if (bmain->relations) { - /* Note: we do not free the entries from the mempool, those will be dealt with when finally - * freeing the whole relations. */ - if (bmain->relations->id_used_to_user) { - BLI_ghash_remove(bmain->relations->id_used_to_user, id, NULL, NULL); + if (bmain->relations == NULL) { + return; + } + for (GHashIterator *gh_iter = BLI_ghashIterator_new(bmain->relations->relations_from_pointers); + !BLI_ghashIterator_done(gh_iter); + BLI_ghashIterator_step(gh_iter)) { + MainIDRelationsEntry *entry = BLI_ghashIterator_getValue(gh_iter); + if (value) { + entry->tags |= tag; } - if (bmain->relations->id_user_to_used) { - BLI_ghash_remove(bmain->relations->id_user_to_used, id, NULL, NULL); + else { + entry->tags &= ~tag; } } } diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 04fec1e57c4..83d9449934c 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -270,6 +270,8 @@ IDTypeInfo IDType_ID_MSK = { .blend_read_expand = mask_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; static struct { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index e892a3f4d53..70906065347 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -274,6 +274,8 @@ IDTypeInfo IDType_ID_MA = { .blend_read_expand = material_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; void BKE_gpencil_material_attr_init(Material *ma) diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 65ec91c57cf..849c7ef57fb 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -204,6 +204,8 @@ IDTypeInfo IDType_ID_MB = { .blend_read_expand = metaball_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* Functions */ diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 051c7e56ef9..1550401cc9c 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -263,7 +263,7 @@ static void build_bvh_spatial(PROCESS *process, * BASED AT CODE (but mostly rewritten) : * C code from the article * "An Implicit Surface Polygonizer" - * by Jules Bloomenthal, jbloom@beauty.gmu.edu + * by Jules Bloomenthal <jbloom@beauty.gmu.edu> * in "Graphics Gems IV", Academic Press, 1994 * * Authored by Jules Bloomenthal, Xerox PARC. diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 950885d2114..622f6d7a7b8 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -364,6 +364,8 @@ IDTypeInfo IDType_ID_ME = { .blend_read_expand = mesh_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; enum { @@ -939,7 +941,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); - me_dst->mselect = MEM_dupallocN(me_dst->mselect); + me_dst->mselect = MEM_dupallocN(me_src->mselect); me_dst->totvert = verts_len; me_dst->totedge = edges_len; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index b872c91cc29..175caf85b49 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_MC = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /*********************** movieclip buffer loaders *************************/ diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 441da8b134a..45ac20ef154 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -781,7 +781,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene, smd.levels = smd.renderLevels = lvl; smd.quality = 3; if (!is_plain_uv) { - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; } else { smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.cc index 76885eadaae..2dbfa85b8e1 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.cc @@ -25,10 +25,10 @@ #include "MEM_guardedalloc.h" -#include <limits.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> +#include <climits> +#include <cstddef> +#include <cstdlib> +#include <cstring> /* Allow using deprecated functionality for .blend file I/O. */ #define DNA_DEPRECATED_ALLOW @@ -109,7 +109,7 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), static void ntree_init_data(ID *id) { bNodeTree *ntree = (bNodeTree *)id; - ntree_set_typeinfo(ntree, NULL); + ntree_set_typeinfo(ntree, nullptr); } static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) @@ -121,7 +121,7 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; /* in case a running nodetree is copied */ - ntree_dst->execdata = NULL; + ntree_dst->execdata = nullptr; BLI_listbase_clear(&ntree_dst->nodes); BLI_listbase_clear(&ntree_dst->links); @@ -133,17 +133,17 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true); BLI_ghash_insert(new_pointers, (void *)node_src, new_node); /* Store mapping to inputs. */ - bNodeSocket *new_input_sock = new_node->inputs.first; - const bNodeSocket *input_sock_src = node_src->inputs.first; - while (new_input_sock != NULL) { + bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; + const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first; + while (new_input_sock != nullptr) { BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock); new_input_sock = new_input_sock->next; input_sock_src = input_sock_src->next; } /* Store mapping to outputs. */ - bNodeSocket *new_output_sock = new_node->outputs.first; - const bNodeSocket *output_sock_src = node_src->outputs.first; - while (new_output_sock != NULL) { + bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; + const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first; + while (new_output_sock != nullptr) { BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock); new_output_sock = new_output_sock->next; output_sock_src = output_sock_src->next; @@ -153,10 +153,13 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c /* copy links */ BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) { - link_dst->fromnode = BLI_ghash_lookup_default(new_pointers, link_dst->fromnode, NULL); - link_dst->fromsock = BLI_ghash_lookup_default(new_pointers, link_dst->fromsock, NULL); - link_dst->tonode = BLI_ghash_lookup_default(new_pointers, link_dst->tonode, NULL); - link_dst->tosock = BLI_ghash_lookup_default(new_pointers, link_dst->tosock, NULL); + link_dst->fromnode = (bNode *)BLI_ghash_lookup_default( + new_pointers, link_dst->fromnode, nullptr); + link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default( + new_pointers, link_dst->fromsock, nullptr); + link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr); + link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default( + new_pointers, link_dst->tosock, nullptr); /* update the link socket's pointer */ if (link_dst->tosock) { link_dst->tosock->link = link_dst; @@ -166,14 +169,18 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c /* copy interface sockets */ BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); bNodeSocket *sock_dst, *sock_src; - for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; sock_dst != NULL; - sock_dst = sock_dst->next, sock_src = sock_src->next) { + for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first, + sock_src = (bNodeSocket *)ntree_src->inputs.first; + sock_dst != nullptr; + sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { node_socket_copy(sock_dst, sock_src, flag_subdata); } BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); - for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; sock_dst != NULL; - sock_dst = sock_dst->next, sock_src = sock_src->next) { + for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first, + sock_src = (bNodeSocket *)ntree_src->outputs.first; + sock_dst != nullptr; + sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { node_socket_copy(sock_dst, sock_src, flag_subdata); } @@ -185,26 +192,29 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c NODE_INSTANCE_HASH_ITER (iter, ntree_src->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); + bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); } } else { - ntree_dst->previews = NULL; + ntree_dst->previews = nullptr; } /* update node->parent pointers */ - for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; - node_dst = node_dst->next, node_src = node_src->next) { + for (bNode *node_dst = (bNode *)ntree_dst->nodes.first, + *node_src = (bNode *)ntree_src->nodes.first; + node_dst; + node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) { if (node_dst->parent) { - node_dst->parent = BLI_ghash_lookup_default(new_pointers, node_dst->parent, NULL); + node_dst->parent = (bNode *)BLI_ghash_lookup_default( + new_pointers, node_dst->parent, nullptr); } } - BLI_ghash_free(new_pointers, NULL, NULL); + BLI_ghash_free(new_pointers, nullptr, nullptr); /* node tree will generate its own interface type */ - ntree_dst->interface_type = NULL; + ntree_dst->interface_type = nullptr; } static void ntree_free_data(ID *id) @@ -223,7 +233,7 @@ static void ntree_free_data(ID *id) break; case NTREE_TEXTURE: ntreeTexEndExecTree(ntree->execdata); - ntree->execdata = NULL; + ntree->execdata = nullptr; break; } } @@ -267,17 +277,18 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { - bNodeSocketValueObject *default_value = sock->default_value; + bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_COLLECTION: { - bNodeSocketValueCollection *default_value = sock->default_value; + bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) + sock->default_value; BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); break; } @@ -327,11 +338,10 @@ static void node_foreach_cache(ID *id, void *user_data) { bNodeTree *nodetree = (bNodeTree *)id; - IDCacheKey key = { - .id_session_uuid = id->session_uuid, - .offset_in_ID = offsetof(bNodeTree, previews), - .cache_v = nodetree->previews, - }; + IDCacheKey key = {0}; + key.id_session_uuid = id->session_uuid; + key.offset_in_ID = offsetof(bNodeTree, previews); + key.cache_v = nodetree->previews; /* TODO, see also `direct_link_nodetree()` in readfile.c. */ #if 0 @@ -351,7 +361,7 @@ static void node_foreach_cache(ID *id, static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) { - if (sock->default_value == NULL) { + if (sock->default_value == nullptr) { return; } @@ -448,7 +458,7 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) /* could be handlerized at some point, now only 1 exception still */ if ((ntree->type == NTREE_SHADER) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { - BKE_curvemapping_blend_write(writer, node->storage); + BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { NodeShaderScript *nss = (NodeShaderScript *)node->storage; @@ -462,11 +472,11 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) { - BKE_curvemapping_blend_write(writer, node->storage); + BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if ((ntree->type == NTREE_TEXTURE) && (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) { - BKE_curvemapping_blend_write(writer, node->storage); + BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { /* pass */ @@ -474,7 +484,7 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { /* Simple forward compatibility for fix for T50736. * Not ideal (there is no ideal solution here), but should do for now. */ - NodeGlare *ndg = node->storage; + NodeGlare *ndg = (NodeGlare *)node->storage; /* Not in undo case. */ if (!BLO_write_is_undo(writer)) { switch (ndg->type) { @@ -543,10 +553,10 @@ static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_addres /* Clean up, important in undo case to reduce false detection of changed datablocks. */ ntree->init = 0; /* to set callbacks and force setting types */ ntree->is_updating = false; - ntree->typeinfo = NULL; - ntree->interface_type = NULL; - ntree->progress = NULL; - ntree->execdata = NULL; + ntree->typeinfo = nullptr; + ntree->interface_type = nullptr; + ntree->progress = nullptr; + ntree->execdata = nullptr; BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); @@ -560,10 +570,10 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) IDP_BlendDataRead(reader, &sock->prop); BLO_read_data_address(reader, &sock->link); - sock->typeinfo = NULL; + sock->typeinfo = nullptr; BLO_read_data_address(reader, &sock->storage); BLO_read_data_address(reader, &sock->default_value); - sock->cache = NULL; + sock->cache = nullptr; } /* ntree itself has been read! */ @@ -572,18 +582,18 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) /* note: writing and reading goes in sync, for speed */ ntree->init = 0; /* to set callbacks and force setting types */ ntree->is_updating = false; - ntree->typeinfo = NULL; - ntree->interface_type = NULL; + ntree->typeinfo = nullptr; + ntree->interface_type = nullptr; - ntree->progress = NULL; - ntree->execdata = NULL; + ntree->progress = nullptr; + ntree->execdata = nullptr; BLO_read_data_address(reader, &ntree->adt); BKE_animdata_blend_read_data(reader, ntree->adt); BLO_read_list(reader, &ntree->nodes); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - node->typeinfo = NULL; + node->typeinfo = nullptr; BLO_read_list(reader, &node->inputs); BLO_read_list(reader, &node->outputs); @@ -618,7 +628,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) case CMP_NODE_HUECORRECT: case TEX_NODE_CURVE_RGB: case TEX_NODE_CURVE_TIME: { - BKE_curvemapping_blend_read(reader, node->storage); + BKE_curvemapping_blend_read(reader, (CurveMapping *)node->storage); break; } case SH_NODE_SCRIPT: { @@ -634,22 +644,22 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) case SH_NODE_TEX_IMAGE: { NodeTexImage *tex = (NodeTexImage *)node->storage; tex->iuser.ok = 1; - tex->iuser.scene = NULL; + tex->iuser.scene = nullptr; break; } case SH_NODE_TEX_ENVIRONMENT: { NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage; tex->iuser.ok = 1; - tex->iuser.scene = NULL; + tex->iuser.scene = nullptr; break; } case CMP_NODE_IMAGE: case CMP_NODE_R_LAYERS: case CMP_NODE_VIEWER: case CMP_NODE_SPLITVIEWER: { - ImageUser *iuser = node->storage; + ImageUser *iuser = (ImageUser *)node->storage; iuser->ok = 1; - iuser->scene = NULL; + iuser->scene = nullptr; break; } case CMP_NODE_CRYPTOMATTE: { @@ -659,9 +669,9 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) break; } case TEX_NODE_IMAGE: { - ImageUser *iuser = node->storage; + ImageUser *iuser = (ImageUser *)node->storage; iuser->ok = 1; - iuser->scene = NULL; + iuser->scene = nullptr; break; } default: @@ -701,7 +711,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) } /* TODO, should be dealt by new generic cache handling of IDs... */ - ntree->previews = NULL; + ntree->previews = nullptr; /* type verification is in lib-link */ } @@ -718,17 +728,18 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { - bNodeSocketValueObject *default_value = sock->default_value; + bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_COLLECTION: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) + sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } @@ -777,7 +788,7 @@ void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree) * first versioning that can change types still without functions that * update the typeinfo pointers. Versioning after lib linking needs * these top be valid. */ - ntreeSetTypes(NULL, ntree); + ntreeSetTypes(nullptr, ntree); /* For nodes with static socket layout, add/remove sockets as needed * to match the static layout. */ @@ -798,21 +809,22 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) { IDP_BlendReadExpand(expander, sock->prop); - if (sock->default_value != NULL) { + if (sock->default_value != nullptr) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { - bNodeSocketValueObject *default_value = sock->default_value; + bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_COLLECTION: { - bNodeSocketValueCollection *default_value = sock->default_value; + bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) + sock->default_value; BLO_expand(expander, default_value->value); break; } @@ -866,28 +878,30 @@ static void ntree_blend_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_NT = { - .id_code = ID_NT, - .id_filter = FILTER_ID_NT, - .main_listbase_index = INDEX_ID_NT, - .struct_size = sizeof(bNodeTree), - .name = "NodeTree", - .name_plural = "node_groups", - .translation_context = BLT_I18NCONTEXT_ID_NODETREE, - .flags = 0, - - .init_data = ntree_init_data, - .copy_data = ntree_copy_data, - .free_data = ntree_free_data, - .make_local = NULL, - .foreach_id = node_foreach_id, - .foreach_cache = node_foreach_cache, - - .blend_write = ntree_blend_write, - .blend_read_data = ntree_blend_read_data, - .blend_read_lib = ntree_blend_read_lib, - .blend_read_expand = ntree_blend_read_expand, - - .blend_read_undo_preserve = NULL, + /* id_code */ ID_NT, + /* id_filter */ FILTER_ID_NT, + /* main_listbase_index */ INDEX_ID_NT, + /* struct_size */ sizeof(bNodeTree), + /* name */ "NodeTree", + /* name_plural */ "node_groups", + /* translation_context */ BLT_I18NCONTEXT_ID_NODETREE, + /* flags */ 0, + + /* init_data */ ntree_init_data, + /* copy_data */ ntree_copy_data, + /* free_data */ ntree_free_data, + /* make_local */ nullptr, + /* foreach_id */ node_foreach_id, + /* foreach_cache */ node_foreach_cache, + + /* blend_write */ ntree_blend_write, + /* blend_read_data */ ntree_blend_read_data, + /* blend_read_lib */ ntree_blend_read_lib, + /* blend_read_expand */ ntree_blend_read_expand, + + /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) @@ -947,11 +961,11 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) node_add_sockets_from_type(ntree, node, ntype); - if (ntype->initfunc != NULL) { + if (ntype->initfunc != nullptr) { ntype->initfunc(ntree, node); } - if (ntree->typeinfo->node_add_init != NULL) { + if (ntree->typeinfo->node_add_init != nullptr) { ntree->typeinfo->node_add_init(ntree, node); } @@ -964,10 +978,10 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) PointerRNA ptr; RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); - /* XXX Warning: context can be NULL in case nodes are added in do_versions. + /* XXX Warning: context can be nullptr in case nodes are added in do_versions. * Delayed init is not supported for nodes with context-based initfunc_api atm. */ - BLI_assert(C != NULL); + BLI_assert(C != nullptr); ntype->initfunc_api(C, &ptr); } @@ -997,7 +1011,7 @@ static void node_set_typeinfo(const struct bContext *C, /* for nodes saved in older versions storage can get lost, make undefined then */ if (node->flag & NODE_INIT) { if (typeinfo && typeinfo->storagename[0] && !node->storage) { - typeinfo = NULL; + typeinfo = nullptr; } } @@ -1027,7 +1041,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, /* deprecated integer type */ sock->type = typeinfo->type; - if (sock->default_value == NULL) { + if (sock->default_value == nullptr) { /* initialize the default_value pointer used by standard socket types */ node_socket_init_default_value(sock); } @@ -1055,24 +1069,24 @@ static void update_typeinfo(Main *bmain, ntree->init |= NTREE_TYPE_INIT; if (treetype && STREQ(ntree->idname, treetype->idname)) { - ntree_set_typeinfo(ntree, unregister ? NULL : treetype); + ntree_set_typeinfo(ntree, unregister ? nullptr : treetype); } /* initialize nodes */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (nodetype && STREQ(node->idname, nodetype->idname)) { - node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype); + node_set_typeinfo(C, ntree, node, unregister ? nullptr : nodetype); } /* initialize node sockets */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { - node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { - node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } } @@ -1080,12 +1094,12 @@ static void update_typeinfo(Main *bmain, /* initialize tree sockets */ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { - node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { - node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } } @@ -1123,22 +1137,20 @@ void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) } } -static GHash *nodetreetypes_hash = NULL; -static GHash *nodetypes_hash = NULL; -static GHash *nodesockettypes_hash = NULL; +static GHash *nodetreetypes_hash = nullptr; +static GHash *nodetypes_hash = nullptr; +static GHash *nodesockettypes_hash = nullptr; bNodeTreeType *ntreeTypeFind(const char *idname) { - bNodeTreeType *nt; - if (idname[0]) { - nt = BLI_ghash_lookup(nodetreetypes_hash, idname); + bNodeTreeType *nt = (bNodeTreeType *)BLI_ghash_lookup(nodetreetypes_hash, idname); if (nt) { return nt; } } - return NULL; + return nullptr; } void ntreeTypeAdd(bNodeTreeType *nt) @@ -1147,23 +1159,23 @@ void ntreeTypeAdd(bNodeTreeType *nt) /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, nt, NULL, NULL, false); + update_typeinfo(G_MAIN, nullptr, nt, nullptr, nullptr, false); } /* callback for hash value free function */ static void ntree_free_type(void *treetype_v) { - bNodeTreeType *treetype = treetype_v; + bNodeTreeType *treetype = (bNodeTreeType *)treetype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, treetype, NULL, NULL, true); + update_typeinfo(G_MAIN, nullptr, treetype, nullptr, nullptr, true); MEM_freeN(treetype); } void ntreeTypeFreeLink(const bNodeTreeType *nt) { - BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type); + BLI_ghash_remove(nodetreetypes_hash, nt->idname, nullptr, ntree_free_type); } bool ntreeIsRegistered(bNodeTree *ntree) @@ -1179,13 +1191,13 @@ GHashIterator *ntreeTypeGetIterator(void) bNodeType *nodeTypeFind(const char *idname) { if (idname[0]) { - bNodeType *nt = BLI_ghash_lookup(nodetypes_hash, idname); + bNodeType *nt = (bNodeType *)BLI_ghash_lookup(nodetypes_hash, idname); if (nt) { return nt; } } - return NULL; + return nullptr; } static void free_dynamic_typeinfo(bNodeType *ntype) @@ -1203,18 +1215,18 @@ static void free_dynamic_typeinfo(bNodeType *ntype) /* callback for hash value free function */ static void node_free_type(void *nodetype_v) { - bNodeType *nodetype = nodetype_v; + bNodeType *nodetype = (bNodeType *)nodetype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, NULL, nodetype, NULL, true); + update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true); /* XXX deprecated */ if (nodetype->type == NODE_DYNAMIC) { free_dynamic_typeinfo(nodetype); } - /* Can be NULL when the type is not dynamically allocated. */ + /* Can be null when the type is not dynamically allocated. */ if (nodetype->free_self) { nodetype->free_self(nodetype); } @@ -1224,18 +1236,18 @@ void nodeRegisterType(bNodeType *nt) { /* debug only: basic verification of registered types */ BLI_assert(nt->idname[0] != '\0'); - BLI_assert(nt->poll != NULL); + BLI_assert(nt->poll != nullptr); BLI_ghash_insert(nodetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, NULL, nt, NULL, false); + update_typeinfo(G_MAIN, nullptr, nullptr, nt, nullptr, false); } void nodeUnregisterType(bNodeType *nt) { - BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type); + BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type); } bool nodeTypeUndefined(bNode *node) @@ -1253,23 +1265,23 @@ GHashIterator *nodeTypeGetIterator(void) bNodeSocketType *nodeSocketTypeFind(const char *idname) { if (idname[0]) { - bNodeSocketType *st = BLI_ghash_lookup(nodesockettypes_hash, idname); + bNodeSocketType *st = (bNodeSocketType *)BLI_ghash_lookup(nodesockettypes_hash, idname); if (st) { return st; } } - return NULL; + return nullptr; } /* callback for hash value free function */ static void node_free_socket_type(void *socktype_v) { - bNodeSocketType *socktype = socktype_v; + bNodeSocketType *socktype = (bNodeSocketType *)socktype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, NULL, NULL, socktype, true); + update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, socktype, true); socktype->free_self(socktype); } @@ -1280,12 +1292,12 @@ void nodeRegisterSocketType(bNodeSocketType *st) /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ - update_typeinfo(G_MAIN, NULL, NULL, NULL, st, false); + update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, st, false); } void nodeUnregisterSocketType(bNodeSocketType *st) { - BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type); + BLI_ghash_remove(nodesockettypes_hash, st->idname, nullptr, node_free_socket_type); } bool nodeSocketIsRegistered(bNodeSocket *sock) @@ -1306,13 +1318,13 @@ struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *id return sock; } } - return NULL; + return nullptr; } /* find unique socket identifier */ static bool unique_identifier_check(void *arg, const char *identifier) { - struct ListBase *lb = arg; + const ListBase *lb = (const ListBase *)arg; LISTBASE_FOREACH (bNodeSocket *, sock, lb) { if (STREQ(sock->identifier, identifier)) { return true; @@ -1343,14 +1355,14 @@ static bNodeSocket *make_socket(bNodeTree *ntree, BLI_uniquename_cb( unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); - bNodeSocket *sock = MEM_callocN(sizeof(bNodeSocket), "sock"); + bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); sock->in_out = in_out; BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); BLI_strncpy(sock->name, name, NODE_MAXSTR); - sock->storage = NULL; + sock->storage = nullptr; sock->flag |= SOCK_COLLAPSED; sock->type = SOCK_CUSTOM; /* int type undefined by default */ @@ -1364,17 +1376,18 @@ static void socket_id_user_increment(bNodeSocket *sock) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { - bNodeSocketValueObject *default_value = sock->default_value; + bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_COLLECTION: { - bNodeSocketValueCollection *default_value = sock->default_value; + bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) + sock->default_value; id_us_plus((ID *)default_value->value); break; } @@ -1396,17 +1409,18 @@ static void socket_id_user_decrement(bNodeSocket *sock) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { - bNodeSocketValueObject *default_value = sock->default_value; + bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; id_us_min(&default_value->value->id); break; } case SOCK_IMAGE: { - bNodeSocketValueImage *default_value = sock->default_value; + bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; id_us_min(&default_value->value->id); break; } case SOCK_COLLECTION: { - bNodeSocketValueCollection *default_value = sock->default_value; + bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) + sock->default_value; id_us_min(&default_value->value->id); break; } @@ -1437,7 +1451,7 @@ void nodeModifySocketType( if (sock->default_value) { socket_id_user_decrement(sock); MEM_freeN(sock->default_value); - sock->default_value = NULL; + sock->default_value = nullptr; } sock->type = type; @@ -1552,7 +1566,7 @@ const char *nodeStaticSocketType(int type, int subtype) case SOCK_COLLECTION: return "NodeSocketCollection"; } - return NULL; + return nullptr; } const char *nodeStaticSocketInterfaceType(int type, int subtype) @@ -1621,7 +1635,7 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype) case SOCK_COLLECTION: return "NodeSocketInterfaceCollection"; } - return NULL; + return nullptr; } bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, @@ -1636,7 +1650,7 @@ bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, if (!idname) { CLOG_ERROR(&LOG, "static node socket type %d undefined", type); - return NULL; + return nullptr; } bNodeSocket *sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name); @@ -1657,7 +1671,7 @@ bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, if (!idname) { CLOG_ERROR(&LOG, "static node socket type %d undefined", type); - return NULL; + return nullptr; } bNodeSocket *sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name); @@ -1727,23 +1741,23 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) /* finds a node based on its name */ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) { - return BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); + return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); } /* Finds a node based on given socket and returns true on success. */ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { - *r_node = NULL; + *r_node = nullptr; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; int index = 0; LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { if (sock == tsock) { - if (r_node != NULL) { + if (r_node != nullptr) { *r_node = node; } - if (r_sockindex != NULL) { + if (r_sockindex != nullptr) { *r_sockindex = index; } return true; @@ -1762,7 +1776,7 @@ bNode *nodeFindRootParent(bNode *node) if (node->parent) { return nodeFindRootParent(node->parent); } - return node->type == NODE_FRAME ? node : NULL; + return node->type == NODE_FRAME ? node : nullptr; } /** @@ -1821,7 +1835,7 @@ static void iter_backwards_ex(const bNodeTree *ntree, { LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { bNodeLink *link = sock->link; - if (link == NULL) { + if (link == nullptr) { continue; } if ((link->flag & NODE_LINK_VALID) == 0) { @@ -1901,7 +1915,7 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node) bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) { - bNode *node = MEM_callocN(sizeof(bNode), "new node"); + bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node"); BLI_addtail(&ntree->nodes, node); BLI_strncpy(node->idname, idname, sizeof(node->idname)); @@ -1914,7 +1928,7 @@ bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idnam bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) { - const char *idname = NULL; + const char *idname = nullptr; NODE_TYPES_BEGIN (ntype) { /* do an extra poll here, because some int types are used @@ -1928,7 +1942,7 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) NODE_TYPES_END; if (!idname) { CLOG_ERROR(&LOG, "static node type %d undefined", type); - return NULL; + return nullptr; } return nodeAddNode(C, ntree, idname); } @@ -1951,7 +1965,7 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, /* XXX some compositor node (e.g. image, render layers) still store * some persistent buffer data here, need to clear this to avoid dangling pointers. */ - sock_dst->cache = NULL; + sock_dst->cache = nullptr; } /* keep socket listorder identical, for copying links */ @@ -1962,7 +1976,7 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, const int flag, const bool unique_name) { - bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); + bNode *node_dst = (bNode *)MEM_callocN(sizeof(bNode), "dupli node"); bNodeSocket *sock_dst, *sock_src; bNodeLink *link_dst, *link_src; @@ -1977,14 +1991,18 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, } BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); - for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; sock_dst != NULL; - sock_dst = sock_dst->next, sock_src = sock_src->next) { + for (sock_dst = (bNodeSocket *)node_dst->inputs.first, + sock_src = (bNodeSocket *)node_src->inputs.first; + sock_dst != nullptr; + sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { node_socket_copy(sock_dst, sock_src, flag); } BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); - for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; sock_dst != NULL; - sock_dst = sock_dst->next, sock_src = sock_src->next) { + for (sock_dst = (bNodeSocket *)node_dst->outputs.first, + sock_src = (bNodeSocket *)node_src->outputs.first; + sock_dst != nullptr; + sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { node_socket_copy(sock_dst, sock_src, flag); } @@ -1993,9 +2011,10 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, } BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); - for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; - link_dst != NULL; - link_dst = link_dst->next, link_src = link_src->next) { + for (link_dst = (bNodeLink *)node_dst->internal_links.first, + link_src = (bNodeLink *)node_src->internal_links.first; + link_dst != nullptr; + link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) { /* This is a bit annoying to do index lookups in a list, but is likely to be faster than * trying to create a hash-map. At least for usual nodes, which only have so much sockets * and internal links. */ @@ -2005,8 +2024,8 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, BLI_assert(to_sock_index != -1); link_dst->fromnode = node_dst; link_dst->tonode = node_dst; - link_dst->fromsock = BLI_findlink(&node_dst->inputs, from_sock_index); - link_dst->tosock = BLI_findlink(&node_dst->outputs, to_sock_index); + link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index); + link_dst->tosock = (bNodeSocket *)BLI_findlink(&node_dst->outputs, to_sock_index); } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -2017,7 +2036,7 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, node_src->typeinfo->copyfunc(ntree, node_dst, node_src); } - node_dst->new_node = NULL; + node_dst->new_node = nullptr; /* Only call copy function when a copy is made for the main database, not * for cases like the dependency graph and localization. */ @@ -2040,17 +2059,17 @@ static void node_set_new_pointers(bNode *node_src, bNode *new_node) /* Store mapping to the node itself. */ node_src->new_node = new_node; /* Store mapping to inputs. */ - bNodeSocket *new_input_sock = new_node->inputs.first; - bNodeSocket *input_sock_src = node_src->inputs.first; - while (new_input_sock != NULL) { + bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; + bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first; + while (new_input_sock != nullptr) { input_sock_src->new_sock = new_input_sock; new_input_sock = new_input_sock->next; input_sock_src = input_sock_src->next; } /* Store mapping to outputs. */ - bNodeSocket *new_output_sock = new_node->outputs.first; - bNodeSocket *output_sock_src = node_src->outputs.first; - while (new_output_sock != NULL) { + bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; + bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first; + while (new_output_sock != nullptr) { output_sock_src->new_sock = new_output_sock; new_output_sock = new_output_sock->next; output_sock_src = output_sock_src->next; @@ -2069,9 +2088,9 @@ bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree, const bool do_id_user) { bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user); - bNode *new_node = new_ntree->nodes.first; - bNode *node_src = ntree->nodes.first; - while (new_node != NULL) { + bNode *new_node = (bNode *)new_ntree->nodes.first; + bNode *node_src = (bNode *)ntree->nodes.first; + while (new_node != nullptr) { node_set_new_pointers(node_src, new_node); new_node = new_node->next; node_src = node_src->next; @@ -2083,14 +2102,14 @@ bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree, bNodeLink *nodeAddLink( bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) { - bNodeLink *link = NULL; + bNodeLink *link = nullptr; /* test valid input */ BLI_assert(fromnode); BLI_assert(tonode); if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { - link = MEM_callocN(sizeof(bNodeLink), "link"); + link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); if (ntree) { BLI_addtail(&ntree->links, link); } @@ -2101,7 +2120,7 @@ bNodeLink *nodeAddLink( } else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { /* OK but flip */ - link = MEM_callocN(sizeof(bNodeLink), "link"); + link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); if (ntree) { BLI_addtail(&ntree->links, link); } @@ -2126,7 +2145,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link) } if (link->tosock) { - link->tosock->link = NULL; + link->tosock->link = nullptr; } MEM_freeN(link); @@ -2137,10 +2156,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link) void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) { - bNodeLink *link, *next; - - for (link = ntree->links.first; link; link = next) { - next = link->next; + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->fromsock == sock || link->tosock == sock) { nodeRemLink(ntree, link); } @@ -2149,7 +2165,7 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) ntree->update |= NTREE_UPDATE_LINKS; } -bool nodeLinkIsHidden(bNodeLink *link) +bool nodeLinkIsHidden(const bNodeLink *link) { return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock); } @@ -2200,7 +2216,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node) } } -void nodeToView(bNode *node, float x, float y, float *rx, float *ry) +void nodeToView(const bNode *node, float x, float y, float *rx, float *ry) { if (node->parent) { nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry); @@ -2211,7 +2227,7 @@ void nodeToView(bNode *node, float x, float y, float *rx, float *ry) } } -void nodeFromView(bNode *node, float x, float y, float *rx, float *ry) +void nodeFromView(const bNode *node, float x, float y, float *rx, float *ry) { if (node->parent) { nodeFromView(node->parent, x, y, rx, ry); @@ -2224,10 +2240,10 @@ void nodeFromView(bNode *node, float x, float y, float *rx, float *ry) } } -bool nodeAttachNodeCheck(bNode *node, bNode *parent) +bool nodeAttachNodeCheck(const bNode *node, const bNode *parent) { - for (bNode *parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) { - if (parent_recurse == parent) { + for (const bNode *parent_iter = node; parent_iter; parent_iter = parent_iter->parent) { + if (parent_iter == parent) { return true; } } @@ -2258,7 +2274,7 @@ void nodeDetachNode(struct bNode *node) nodeToView(node, 0.0f, 0.0f, &locx, &locy); node->locx = locx; node->locy = locy; - node->parent = NULL; + node->parent = nullptr; } } @@ -2307,7 +2323,7 @@ void nodePositionRelative(bNode *from_node, void nodePositionPropagate(bNode *node) { LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { - if (nsock->link != NULL) { + if (nsock->link != nullptr) { bNodeLink *link = nsock->link; nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock); nodePositionPropagate(link->fromnode); @@ -2317,17 +2333,15 @@ void nodePositionPropagate(bNode *node) bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) { - bNodeTree *ntree; - /* trees are created as local trees for compositor, material or texture nodes, * node groups and other tree types are created as library data. */ - const bool is_embedded = (bmain == NULL); + const bool is_embedded = (bmain == nullptr); int flag = 0; if (is_embedded) { flag |= LIB_ID_CREATE_NO_MAIN; } - ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag); + bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag); if (is_embedded) { ntree->id.flag |= LIB_EMBEDDED_DATA; } @@ -2347,7 +2361,7 @@ bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_i { const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN; - bNodeTree *ntree_copy = (bNodeTree *)BKE_id_copy_ex(bmain, (ID *)ntree, NULL, flag); + bNodeTree *ntree_copy = (bNodeTree *)BKE_id_copy_ex(bmain, (ID *)ntree, nullptr, flag); return ntree_copy; } bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) @@ -2362,7 +2376,7 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) * using BKE_node_preview_init_tree to set up previews for a whole node tree in advance. * This should be left more to the individual node tree implementations. */ -int BKE_node_preview_used(bNode *node) +bool BKE_node_preview_used(const bNode *node) { /* XXX check for closed nodes? */ return (node->typeinfo->flag & NODE_PREVIEW) != 0; @@ -2371,14 +2385,14 @@ int BKE_node_preview_used(bNode *node) bNodePreview *BKE_node_preview_verify( bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create) { - bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); + bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); if (!preview) { if (create) { - preview = MEM_callocN(sizeof(bNodePreview), "node preview"); + preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview"); BKE_node_instance_hash_insert(previews, key, preview); } else { - return NULL; + return nullptr; } } @@ -2391,12 +2405,13 @@ bNodePreview *BKE_node_preview_verify( if (preview->rect) { if (preview->xsize != xsize || preview->ysize != ysize) { MEM_freeN(preview->rect); - preview->rect = NULL; + preview->rect = nullptr; } } - if (preview->rect == NULL) { - preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), "node preview rect"); + if (preview->rect == nullptr) { + preview->rect = (unsigned char *)MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), + "node preview rect"); preview->xsize = xsize; preview->ysize = ysize; } @@ -2407,9 +2422,9 @@ bNodePreview *BKE_node_preview_verify( bNodePreview *BKE_node_preview_copy(bNodePreview *preview) { - bNodePreview *new_preview = MEM_dupallocN(preview); + bNodePreview *new_preview = (bNodePreview *)MEM_dupallocN(preview); if (preview->rect) { - new_preview->rect = MEM_dupallocN(preview->rect); + new_preview->rect = (unsigned char *)MEM_dupallocN(preview->rect); } return new_preview; } @@ -2498,7 +2513,7 @@ void BKE_node_preview_free_tree(bNodeTree *ntree) if (ntree->previews) { BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); - ntree->previews = NULL; + ntree->previews = nullptr; } } @@ -2517,7 +2532,7 @@ void BKE_node_preview_clear_tree(bNodeTree *ntree) bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, ntree->previews) { - bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); + bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); BKE_node_preview_clear(preview); } } @@ -2547,8 +2562,8 @@ void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree) bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, from_previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter); - bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key); + bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); + bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key); if (from && to) { node_preview_sync(to, from); @@ -2566,7 +2581,7 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo /* transfer previews */ to_ntree->previews = from_ntree->previews; - from_ntree->previews = NULL; + from_ntree->previews = nullptr; /* clean up, in case any to_ntree nodes have been removed */ BKE_node_preview_remove_unused(to_ntree); @@ -2576,7 +2591,7 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, from_ntree->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); + bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); /* replace existing previews */ BKE_node_instance_hash_remove( @@ -2584,10 +2599,10 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo BKE_node_instance_hash_insert(to_ntree->previews, key, preview); } - /* Note: NULL free function here, + /* Note: null free function here, * because pointers have already been moved over to to_ntree->previews! */ - BKE_node_instance_hash_free(from_ntree->previews, NULL); - from_ntree->previews = NULL; + BKE_node_instance_hash_free(from_ntree->previews, nullptr); + from_ntree->previews = nullptr; } } } @@ -2633,7 +2648,7 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node) lb = &node->inputs; } else { - lb = NULL; + lb = nullptr; } if (lb) { @@ -2677,7 +2692,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node) /* texture node has bad habit of keeping exec data around */ if (ntree->type == NTREE_TEXTURE && ntree->execdata) { ntreeTexEndExecTree(ntree->execdata); - ntree->execdata = NULL; + ntree->execdata = nullptr; } } @@ -2754,7 +2769,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) { - if (bmain != NULL) { + if (bmain != nullptr) { DEG_relations_tag_update(bmain); } } @@ -2826,7 +2841,7 @@ void ntreeFreeLocalTree(bNodeTree *ntree) void ntreeFreeCache(bNodeTree *ntree) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } @@ -2925,7 +2940,7 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id) case ID_SIM: return &((Simulation *)id)->nodetree; default: - return NULL; + return nullptr; } } @@ -2933,10 +2948,10 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id) bNodeTree *ntreeFromID(ID *id) { bNodeTree **nodetree = BKE_ntree_ptr_from_id(id); - return (nodetree != NULL) ? *nodetree : NULL; + return (nodetree != nullptr) ? *nodetree : nullptr; } -/* Finds and returns the datablock that privately owns the given tree, or NULL. */ +/* Finds and returns the datablock that privately owns the given tree, or null. */ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree) { ListBase *lists[] = {&bmain->materials, @@ -2946,9 +2961,9 @@ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree) &bmain->scenes, &bmain->linestyles, &bmain->simulations, - NULL}; + nullptr}; - for (int i = 0; lists[i] != NULL; i++) { + for (int i = 0; lists[i] != nullptr; i++) { LISTBASE_FOREACH (ID *, id, lists[i]) { if (ntreeFromID(id) == ntree) { return id; @@ -2956,12 +2971,12 @@ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree) } } - return NULL; + return nullptr; } -bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode) +bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) { if (node == testnode) { return true; } @@ -2969,9 +2984,9 @@ bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode) return false; } -bool ntreeOutputExists(bNode *node, bNodeSocket *testsock) +bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock) { - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { + LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) { if (sock == testsock) { return true; } @@ -2999,7 +3014,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) * Note: previews are not copied here. */ bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex( - NULL, &ntree->id, NULL, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA)); + nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA)); ltree->id.tag |= LIB_TAG_LOCALIZED; @@ -3012,9 +3027,9 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) /* ensures only a single output node is enabled */ ntreeSetOutput(ntree); - bNode *node_src = ntree->nodes.first; - bNode *node_local = ltree->nodes.first; - while (node_src != NULL) { + bNode *node_src = (bNode *)ntree->nodes.first; + bNode *node_local = (bNode *)ltree->nodes.first; + while (node_src != nullptr) { node_local->original = node_src; node_src = node_src->next; node_local = node_local->next; @@ -3027,7 +3042,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) return ltree; } - return NULL; + return nullptr; } /* sync local composite with real tree */ @@ -3066,11 +3081,11 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree, bNodeSocketType *stype = nodeSocketTypeFind(idname); int own_index = ntree->cur_index++; - if (stype == NULL) { - return NULL; + if (stype == nullptr) { + return nullptr; } - bNodeSocket *sock = MEM_callocN(sizeof(bNodeSocket), "socket template"); + bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template"); BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); node_socket_set_typeinfo(ntree, sock, stype); sock->in_out = in_out; @@ -3089,7 +3104,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree, sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); BLI_strncpy(sock->name, name, NODE_MAXSTR); - sock->storage = NULL; + sock->storage = nullptr; sock->flag |= SOCK_COLLAPSED; return sock; @@ -3103,7 +3118,7 @@ bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char * return iosock; } } - return NULL; + return nullptr; } bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, @@ -3190,7 +3205,7 @@ static void ntree_interface_identifier_base(bNodeTree *ntree, char *base) /* check if the identifier is already in use */ static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) { - return (RNA_struct_find(identifier) != NULL); + return (RNA_struct_find(identifier) != nullptr); } /* generates the actual unique identifier and ui name and description */ @@ -3206,7 +3221,8 @@ static void ntree_interface_identifier(bNodeTree *ntree, * On top of the sanitized id string add a number suffix if necessary to avoid duplicates. */ identifier[0] = '\0'; - BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen); + BLI_uniquename_cb( + ntree_interface_unique_identifier_check, nullptr, base, '_', identifier, maxlen); sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); @@ -3246,7 +3262,7 @@ static void ntree_interface_type_create(bNodeTree *ntree) } } -StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) +StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create) { if (ntree->interface_type) { /* strings are generated from base string + ID name, sizes are sufficient */ @@ -3284,7 +3300,7 @@ void ntreeInterfaceTypeFree(bNodeTree *ntree) { if (ntree->interface_type) { RNA_struct_free(&BLENDER_RNA, ntree->interface_type); - ntree->interface_type = NULL; + ntree->interface_type = nullptr; } } @@ -3310,12 +3326,12 @@ bNode *ntreeFindType(const bNodeTree *ntree, int type) } } } - return NULL; + return nullptr; } bool ntreeHasType(const bNodeTree *ntree, int type) { - return ntreeFindType(ntree, type) != NULL; + return ntreeFindType(ntree, type) != nullptr; } bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) @@ -3333,7 +3349,7 @@ bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) return false; } -bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to) +bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to) { LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if (link->fromsock == from && link->tosock == to) { @@ -3343,13 +3359,13 @@ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to) return link; } } - return NULL; + return nullptr; } -int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock) +int nodeCountSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock) { int tot = 0; - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) { if (link->fromsock == sock || link->tosock == sock) { tot++; } @@ -3359,8 +3375,8 @@ int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock) bNode *nodeGetActive(bNodeTree *ntree) { - if (ntree == NULL) { - return NULL; + if (ntree == nullptr) { + return nullptr; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -3368,7 +3384,7 @@ bNode *nodeGetActive(bNodeTree *ntree) return node; } } - return NULL; + return nullptr; } static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, @@ -3400,7 +3416,7 @@ static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, } } } - return NULL; + return nullptr; } /* two active flags, ID nodes have special flag for buttons display */ @@ -3410,14 +3426,14 @@ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) return node_get_active_id_recursive( ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype); } - return NULL; + return nullptr; } bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) { bool ok = false; - if (ntree == NULL) { + if (ntree == nullptr) { return ok; } @@ -3435,11 +3451,11 @@ bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) /* update all groups linked from here * if active ID node has been found already, - * just pass NULL so other matching nodes are deactivated. + * just pass null so other matching nodes are deactivated. */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == NODE_GROUP) { - ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : NULL)); + ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : nullptr)); } } @@ -3449,7 +3465,7 @@ bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) /* two active flags, ID nodes have special flag for buttons display */ void nodeClearActiveID(bNodeTree *ntree, short idtype) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } @@ -3480,7 +3496,7 @@ void nodeSetSelected(bNode *node, bool select) void nodeClearActive(bNodeTree *ntree) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } @@ -3515,7 +3531,7 @@ void nodeSetActive(bNodeTree *ntree, bNode *node) } } -int nodeSocketIsHidden(bNodeSocket *sock) +int nodeSocketIsHidden(const bNodeSocket *sock) { return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } @@ -3530,10 +3546,13 @@ void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) } } -int nodeSocketLinkLimit(struct bNodeSocket *sock) +int nodeSocketLinkLimit(const bNodeSocket *sock) { bNodeSocketType *stype = sock->typeinfo; - if (stype != NULL && stype->use_link_limits_of_type) { + if (sock->flag & SOCK_MULTI_INPUT) { + return 4095; + } + if (stype != nullptr && stype->use_link_limits_of_type) { int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit; return limit; } @@ -3553,15 +3572,15 @@ int nodeSocketLinkLimit(struct bNodeSocket *sock) * Currently its only used for ID's, but nodes may one day * reference other pointers which need validation. */ -typedef struct bNodeClipboardExtraInfo { +struct bNodeClipboardExtraInfo { struct bNodeClipboardExtraInfo *next, *prev; ID *id; char id_name[MAX_ID_NAME]; char library_name[FILE_MAX]; -} bNodeClipboardExtraInfo; +}; #endif /* USE_NODE_CB_VALIDATE */ -typedef struct bNodeClipboard { +struct bNodeClipboard { ListBase nodes; #ifdef USE_NODE_CB_VALIDATE @@ -3570,11 +3589,11 @@ typedef struct bNodeClipboard { ListBase links; int type; -} bNodeClipboard; +}; -static bNodeClipboard node_clipboard = {{NULL}}; +static bNodeClipboard node_clipboard = {{nullptr}}; -void BKE_node_clipboard_init(struct bNodeTree *ntree) +void BKE_node_clipboard_init(const struct bNodeTree *ntree) { node_clipboard.type = ntree->type; } @@ -3582,12 +3601,12 @@ void BKE_node_clipboard_init(struct bNodeTree *ntree) void BKE_node_clipboard_clear(void) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) { - nodeRemLink(NULL, link); + nodeRemLink(nullptr, link); } BLI_listbase_clear(&node_clipboard.links); LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_clipboard.nodes) { - node_free_node(NULL, node); + node_free_node(nullptr, node); } BLI_listbase_clear(&node_clipboard.nodes); @@ -3609,8 +3628,10 @@ bool BKE_node_clipboard_validate(void) BLI_assert(BLI_listbase_count(&node_clipboard.nodes) == BLI_listbase_count(&node_clipboard.nodes_extra_info)); - for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first; node; - node = node->next, node_info = node_info->next) { + for (node = (bNode *)node_clipboard.nodes.first, + node_info = (bNodeClipboardExtraInfo *)node_clipboard.nodes_extra_info.first; + node; + node = (bNode *)node->next, node_info = (bNodeClipboardExtraInfo *)node_info->next) { /* validate the node against the stored node info */ /* re-assign each loop since we may clear, @@ -3621,13 +3642,13 @@ bool BKE_node_clipboard_validate(void) if (node->id) { /* We want to search into current blend file, so using G_MAIN is valid here too. */ ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name)); - BLI_assert(lb != NULL); + BLI_assert(lb != nullptr); if (BLI_findindex(lb, node_info->id) == -1) { - /* may assign NULL */ - node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); + /* May assign null. */ + node->id = (ID *)BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); - if (node->id == NULL) { + if (node->id == nullptr) { ok = false; } } @@ -3642,8 +3663,8 @@ void BKE_node_clipboard_add_node(bNode *node) { #ifdef USE_NODE_CB_VALIDATE /* add extra info */ - bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo), - "bNodeClipboardExtraInfo"); + bNodeClipboardExtraInfo *node_info = (bNodeClipboardExtraInfo *)MEM_mallocN( + sizeof(bNodeClipboardExtraInfo), __func__); node_info->id = node->id; if (node->id) { @@ -3718,11 +3739,11 @@ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str return hash; } -bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node) +bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, + const bNodeTree *ntree, + const bNode *node) { - bNodeInstanceKey key; - - key = node_hash_int_str(parent_key, ntree->id.name + 2); + bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2); if (node) { key = node_hash_int_str(key, node->name); @@ -3746,7 +3767,7 @@ static bool node_instance_hash_key_cmp(const void *a, const void *b) bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) { - bNodeInstanceHash *hash = MEM_mallocN(sizeof(bNodeInstanceHash), info); + bNodeInstanceHash *hash = (bNodeInstanceHash *)MEM_mallocN(sizeof(bNodeInstanceHash), info); hash->ghash = BLI_ghash_new( node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash"); return hash; @@ -3754,13 +3775,13 @@ bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) { - BLI_ghash_free(hash->ghash, NULL, (GHashValFreeFP)valfreefp); + BLI_ghash_free(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); MEM_freeN(hash); } void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value) { - bNodeInstanceHashEntry *entry = value; + bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; entry->key = key; entry->tag = 0; BLI_ghash_insert(hash->ghash, &entry->key, value); @@ -3775,17 +3796,17 @@ int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp) { - return BLI_ghash_remove(hash->ghash, &key, NULL, (GHashValFreeFP)valfreefp); + return BLI_ghash_remove(hash->ghash, &key, nullptr, (GHashValFreeFP)valfreefp); } void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) { - BLI_ghash_clear(hash->ghash, NULL, (GHashValFreeFP)valfreefp); + BLI_ghash_clear(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); } void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) { - return BLI_ghash_popkey(hash->ghash, &key, NULL); + return BLI_ghash_popkey(hash->ghash, &key, nullptr); } int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) @@ -3803,7 +3824,8 @@ void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, hash) { - bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); + bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) + BKE_node_instance_hash_iterator_get_value(&iter); value->tag = 0; } @@ -3811,13 +3833,14 @@ void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) { - bNodeInstanceHashEntry *entry = value; + bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; entry->tag = 1; } bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key) { - bNodeInstanceHashEntry *entry = BKE_node_instance_hash_lookup(hash, key); + bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)BKE_node_instance_hash_lookup(hash, + key); if (entry) { entry->tag = 1; @@ -3833,13 +3856,14 @@ void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, /* NOTE: Hash must not be mutated during iterating! * Store tagged entries in a separate list and remove items afterward. */ - bNodeInstanceKey *untagged = MEM_mallocN(sizeof(bNodeInstanceKey) * - BKE_node_instance_hash_size(hash), - "temporary node instance key list"); + bNodeInstanceKey *untagged = (bNodeInstanceKey *)MEM_mallocN( + sizeof(bNodeInstanceKey) * BKE_node_instance_hash_size(hash), + "temporary node instance key list"); bNodeInstanceHashIterator iter; int num_untagged = 0; NODE_INSTANCE_HASH_ITER (iter, hash) { - bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); + bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) + BKE_node_instance_hash_iterator_get_value(&iter); if (!value->tag) { untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter); @@ -3903,12 +3927,12 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, in (*totnodes)++; } if (*totnodes == 0) { - *deplist = NULL; + *deplist = nullptr; return; } bNode **nsort; - nsort = *deplist = MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array"); + nsort = *deplist = (bNode **)MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array"); /* recursive check */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -3929,7 +3953,7 @@ static void ntree_update_node_level(bNodeTree *ntree) /* recursive check */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->done == 0) { - node->level = node_get_deplist_recurs(ntree, node, NULL); + node->level = node_get_deplist_recurs(ntree, node, nullptr); } } } @@ -3957,7 +3981,7 @@ static void ntree_update_link_pointers(bNodeTree *ntree) /* first clear data */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - sock->link = NULL; + sock->link = nullptr; } } @@ -3996,7 +4020,7 @@ void ntreeUpdateAllNew(Main *main) } } - ntreeUpdateTree(NULL, ntree); + ntreeUpdateTree(nullptr, ntree); } } FOREACH_NODETREE_END; @@ -4004,7 +4028,7 @@ void ntreeUpdateAllNew(Main *main) void ntreeUpdateAllUsers(Main *main, ID *id) { - if (id == NULL) { + if (id == nullptr) { return; } @@ -4023,7 +4047,7 @@ void ntreeUpdateAllUsers(Main *main, ID *id) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + ntreeUpdateTree(nullptr, ntree); } } FOREACH_NODETREE_END; @@ -4133,7 +4157,7 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id) { bool changed = false; - if (ELEM(NULL, id, ntree)) { + if (ELEM(nullptr, id, ntree)) { return changed; } @@ -4237,7 +4261,7 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, case ID: \ BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \ ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \ - BLI_assert(ntype->rna_ext.srna != NULL); \ + BLI_assert(ntype->rna_ext.srna != nullptr); \ RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \ break; @@ -4271,15 +4295,16 @@ void node_type_base_custom( node_type_base_defaults(ntype); } +struct SocketTemplateIdentifierCallbackData { + bNodeSocketTemplate *list; + bNodeSocketTemplate *ntemp; +}; + static bool unique_socket_template_identifier_check(void *arg, const char *name) { - bNodeSocketTemplate *ntemp; - struct { - bNodeSocketTemplate *list; - bNodeSocketTemplate *ntemp; - } *data = arg; + SocketTemplateIdentifierCallbackData *data = (SocketTemplateIdentifierCallbackData *)arg; - for (ntemp = data->list; ntemp->type >= 0; ntemp++) { + for (bNodeSocketTemplate *ntemp = data->list; ntemp->type >= 0; ntemp++) { if (ntemp != data->ntemp) { if (STREQ(ntemp->identifier, name)) { return true; @@ -4295,10 +4320,7 @@ static void unique_socket_template_identifier(bNodeSocketTemplate *list, const char defname[], char delim) { - struct { - bNodeSocketTemplate *list; - bNodeSocketTemplate *ntemp; - } data; + SocketTemplateIdentifierCallbackData data; data.list = list; data.ntemp = ntemp; @@ -4448,7 +4470,7 @@ static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(node } /* register fallback types used for undefined tree, nodes, sockets */ -static void register_undefined_types(void) +static void register_undefined_types() { /* Note: these types are not registered in the type hashes, * they are just used as placeholders in case the actual types are not registered. @@ -4473,7 +4495,7 @@ static void register_undefined_types(void) NodeSocketTypeUndefined.output_link_limit = 0xFFF; } -static void registerCompositNodes(void) +static void registerCompositNodes() { register_node_type_cmp_group(); @@ -4577,7 +4599,7 @@ static void registerCompositNodes(void) register_node_type_cmp_cornerpin(); } -static void registerShaderNodes(void) +static void registerShaderNodes() { register_node_type_sh_group(); @@ -4674,7 +4696,7 @@ static void registerShaderNodes(void) register_node_type_sh_tex_white_noise(); } -static void registerTextureNodes(void) +static void registerTextureNodes() { register_node_type_tex_group(); @@ -4724,7 +4746,7 @@ static void registerTextureNodes(void) register_node_type_tex_proc_distnoise(); } -static void registerGeometryNodes(void) +static void registerGeometryNodes() { register_node_type_geo_group(); @@ -4749,9 +4771,12 @@ static void registerGeometryNodes(void) register_node_type_geo_attribute_color_ramp(); register_node_type_geo_point_rotate(); register_node_type_geo_align_rotation_to_vector(); + register_node_type_geo_sample_texture(); + register_node_type_geo_points_to_volume(); + register_node_type_geo_collection_info(); } -static void registerFunctionNodes(void) +static void registerFunctionNodes() { register_node_type_fn_boolean_math(); register_node_type_fn_float_compare(); @@ -4800,8 +4825,8 @@ void BKE_node_system_exit(void) } NODE_TYPES_END; - BLI_ghash_free(nodetypes_hash, NULL, node_free_type); - nodetypes_hash = NULL; + BLI_ghash_free(nodetypes_hash, nullptr, node_free_type); + nodetypes_hash = nullptr; } if (nodesockettypes_hash) { @@ -4815,8 +4840,8 @@ void BKE_node_system_exit(void) } NODE_SOCKET_TYPES_END; - BLI_ghash_free(nodesockettypes_hash, NULL, node_free_socket_type); - nodesockettypes_hash = NULL; + BLI_ghash_free(nodesockettypes_hash, nullptr, node_free_socket_type); + nodesockettypes_hash = nullptr; } if (nodetreetypes_hash) { @@ -4827,8 +4852,8 @@ void BKE_node_system_exit(void) } NODE_TREE_TYPES_END; - BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type); - nodetreetypes_hash = NULL; + BLI_ghash_free(nodetreetypes_hash, nullptr, ntree_free_type); + nodetreetypes_hash = nullptr; } } @@ -4837,58 +4862,58 @@ void BKE_node_system_exit(void) void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain) { - ntreeiter->ngroup = bmain->nodetrees.first; - ntreeiter->scene = bmain->scenes.first; - ntreeiter->mat = bmain->materials.first; - ntreeiter->tex = bmain->textures.first; - ntreeiter->light = bmain->lights.first; - ntreeiter->world = bmain->worlds.first; - ntreeiter->linestyle = bmain->linestyles.first; - ntreeiter->simulation = bmain->simulations.first; + ntreeiter->ngroup = (bNodeTree *)bmain->nodetrees.first; + ntreeiter->scene = (Scene *)bmain->scenes.first; + ntreeiter->mat = (Material *)bmain->materials.first; + ntreeiter->tex = (Tex *)bmain->textures.first; + ntreeiter->light = (Light *)bmain->lights.first; + ntreeiter->world = (World *)bmain->worlds.first; + ntreeiter->linestyle = (FreestyleLineStyle *)bmain->linestyles.first; + ntreeiter->simulation = (Simulation *)bmain->simulations.first; } bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, struct ID **r_id) { if (ntreeiter->ngroup) { - *r_nodetree = ntreeiter->ngroup; + *r_nodetree = (bNodeTree *)ntreeiter->ngroup; *r_id = (ID *)ntreeiter->ngroup; - ntreeiter->ngroup = ntreeiter->ngroup->id.next; + ntreeiter->ngroup = (bNodeTree *)ntreeiter->ngroup->id.next; } else if (ntreeiter->scene) { - *r_nodetree = ntreeiter->scene->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->scene->nodetree; *r_id = (ID *)ntreeiter->scene; - ntreeiter->scene = ntreeiter->scene->id.next; + ntreeiter->scene = (Scene *)ntreeiter->scene->id.next; } else if (ntreeiter->mat) { - *r_nodetree = ntreeiter->mat->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->mat->nodetree; *r_id = (ID *)ntreeiter->mat; - ntreeiter->mat = ntreeiter->mat->id.next; + ntreeiter->mat = (Material *)ntreeiter->mat->id.next; } else if (ntreeiter->tex) { - *r_nodetree = ntreeiter->tex->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->tex->nodetree; *r_id = (ID *)ntreeiter->tex; - ntreeiter->tex = ntreeiter->tex->id.next; + ntreeiter->tex = (Tex *)ntreeiter->tex->id.next; } else if (ntreeiter->light) { - *r_nodetree = ntreeiter->light->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->light->nodetree; *r_id = (ID *)ntreeiter->light; - ntreeiter->light = ntreeiter->light->id.next; + ntreeiter->light = (Light *)ntreeiter->light->id.next; } else if (ntreeiter->world) { - *r_nodetree = ntreeiter->world->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->world->nodetree; *r_id = (ID *)ntreeiter->world; - ntreeiter->world = ntreeiter->world->id.next; + ntreeiter->world = (World *)ntreeiter->world->id.next; } else if (ntreeiter->linestyle) { - *r_nodetree = ntreeiter->linestyle->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->linestyle->nodetree; *r_id = (ID *)ntreeiter->linestyle; - ntreeiter->linestyle = ntreeiter->linestyle->id.next; + ntreeiter->linestyle = (FreestyleLineStyle *)ntreeiter->linestyle->id.next; } else if (ntreeiter->simulation) { - *r_nodetree = ntreeiter->simulation->nodetree; + *r_nodetree = (bNodeTree *)ntreeiter->simulation->nodetree; *r_id = (ID *)ntreeiter->simulation; - ntreeiter->simulation = ntreeiter->simulation->id.next; + ntreeiter->simulation = (Simulation *)ntreeiter->simulation->id.next; } else { return false; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 155508e9caa..381823754e9 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1118,6 +1118,20 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id) } } +static void object_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src)) +{ + Object *object = (Object *)id_dst; + + ListBase pidlist; + BKE_ptcache_ids_from_object(&pidlist, object, NULL, 0); + LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) { + LISTBASE_FOREACH (PointCache *, point_cache, pid->ptcaches) { + point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY; + } + } + BLI_freelistN(&pidlist); +} + IDTypeInfo IDType_ID_OB = { .id_code = ID_OB, .id_filter = FILTER_ID_OB, @@ -1141,6 +1155,8 @@ IDTypeInfo IDType_ID_OB = { .blend_read_expand = object_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = object_lib_override_apply_post, }; void BKE_object_workob_clear(Object *workob) @@ -1506,11 +1522,11 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData /** * Copy the whole stack of modifiers from one object into another. * - * \warning **Does not** clear modifier stack and related data (particle systems, softbody, + * \warning **Does not** clear modifier stack and related data (particle systems, soft-body, * etc.) in `ob_dst`, if needed calling code must do it. * - * @param do_copy_all If true, even modifiers that should not suport copying (like Hook one) will - * be duplicated. + * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one) + * will be duplicated. */ bool BKE_object_modifier_stack_copy(Object *ob_dst, const Object *ob_src, @@ -3527,9 +3543,6 @@ static void solve_parenting( } } -/** - * \note scene is the active scene while actual_scene is the scene the object resides in. - */ static void object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 1d79f871fa2..69442b7646c 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -225,7 +225,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o case OB_GPENCIL: { BKE_gpencil_prepare_eval_data(depsgraph, scene, ob); BKE_gpencil_modifiers_calc(depsgraph, scene, ob); - BKE_gpencil_update_layer_parent(depsgraph, ob); + BKE_gpencil_update_layer_transforms(depsgraph, ob); break; } case OB_HAIR: diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 1d62a1cce2a..d2f4d0702ed 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -140,7 +140,7 @@ static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, fl * instead of Complex.h * in fftw.h "fftw_complex" typedefed as double[2] * below you can see functions are needed to work with such complex numbers. - * */ + */ static void init_complex(fftw_complex cmpl, float real, float image) { cmpl[0] = real; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 7c65f118cf4..13f4304f923 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -158,6 +158,8 @@ IDTypeInfo IDType_ID_PAL = { .blend_read_expand = NULL, .blend_read_undo_preserve = palette_undo_preserve, + + .lib_override_apply_post = NULL, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -221,6 +223,8 @@ IDTypeInfo IDType_ID_PC = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 335913c9b8e..ec3b6198d7c 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -511,6 +511,8 @@ IDTypeInfo IDType_ID_PA = { .blend_read_expand = particle_settings_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT]; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 55d4043f96c..c727a144c87 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -1400,8 +1400,9 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra) static void psys_update_effectors(ParticleSimulationData *sim) { BKE_effectors_free(sim->psys->effectors); + bool use_rotation = (sim->psys->part->flag & PART_ROT_DYN) != 0; sim->psys->effectors = BKE_effectors_create( - sim->depsgraph, sim->ob, sim->psys, sim->psys->part->effector_weights); + sim->depsgraph, sim->ob, sim->psys, sim->psys->part->effector_weights, use_rotation); precalc_guides(sim, sim->psys->effectors); } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 7bd14e80333..b9ff2a1179d 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -190,6 +190,8 @@ IDTypeInfo IDType_ID_PT = { /* blend_read_expand */ pointcloud_blend_read_expand, /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; static void pointcloud_random(PointCloud *pointcloud) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 586aeb274a5..19078446009 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1720,7 +1720,7 @@ static void rigidbody_update_sim_ob( ListBase *effectors; /* get effectors present in the group specified by effector_weights */ - effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights); + effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_vel[3]; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index b19b0e684b2..0ce5240b17d 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1689,6 +1689,19 @@ static void scene_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old) } } +static void scene_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src)) +{ + Scene *scene = (Scene *)id_dst; + + if (scene->rigidbody_world != NULL) { + PTCacheID pid; + BKE_ptcache_id_from_rigidbody(&pid, NULL, scene->rigidbody_world); + LISTBASE_FOREACH (PointCache *, point_cache, pid.ptcaches) { + point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY; + } + } +} + IDTypeInfo IDType_ID_SCE = { .id_code = ID_SCE, .id_filter = FILTER_ID_SCE, @@ -1714,6 +1727,8 @@ IDTypeInfo IDType_ID_SCE = { .blend_read_expand = scene_blend_read_expand, .blend_read_undo_preserve = scene_undo_preserve, + + .lib_override_apply_post = scene_lib_override_apply_post, }; const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 52c41c9fd05..80a83aecea8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -315,6 +315,8 @@ IDTypeInfo IDType_ID_SCR = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* ************ Spacetype/regiontype handling ************** */ @@ -1599,8 +1601,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) BLO_read_list(reader, &snode->treepath); snode->edittree = NULL; - snode->iofsd = NULL; - BLI_listbase_clear(&snode->linkdrag); + snode->runtime = NULL; } else if (sl->spacetype == SPACE_TEXT) { SpaceText *st = (SpaceText *)sl; diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 14e6ce63023..4e0a08455e6 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -173,6 +173,8 @@ IDTypeInfo IDType_ID_SIM = { /* blend_read_expand */ simulation_blend_read_expand, /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; void *BKE_simulation_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 736acd76dfd..de88e8a941c 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1539,7 +1539,8 @@ static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, * or even be UI option sb->spawn_cf_threads_nopts */ int lowsprings = 100; - ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights); + ListBase *effectors = BKE_effectors_create( + depsgraph, ob, NULL, ob->soft->effector_weights, false); /* figure the number of threads while preventing pretty pointless threading overhead */ totthread = BKE_scene_num_threads(scene); @@ -2300,7 +2301,7 @@ static void softbody_calc_forces( } /* after spring scan because it uses Effoctors too */ - ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights, false); if (do_deflector) { float defforce[3]; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 78729fb9261..0c917434bd1 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -221,6 +221,8 @@ IDTypeInfo IDType_ID_SO = { .blend_read_expand = sound_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; #ifdef WITH_AUDASPACE diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index fabf0bb8971..9caeaf05e6a 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -114,6 +114,8 @@ IDTypeInfo IDType_ID_SPK = { .blend_read_expand = speaker_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; void *BKE_speaker_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 9ef2e818293..9bf215515f7 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -258,6 +258,8 @@ IDTypeInfo IDType_ID_TXT = { .blend_read_expand = NULL, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /** \} */ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 4c2e4a82acb..ce84bfcd95a 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -226,6 +226,8 @@ IDTypeInfo IDType_ID_TE = { .blend_read_expand = texture_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* Utils for all IDs using those texture slots. */ diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index e5f9d59270e..d124922acd1 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -587,15 +587,15 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, { const MovieTrackingSettings *settings = &tracking->settings; + MovieTrackingTrack *track = BKE_tracking_track_add_empty(tracking, tracksbase); + MovieTrackingMarker marker; + const float half_pattern_px = settings->default_pattern_size / 2.0f; const float half_search_px = settings->default_search_size / 2.0f; const float pattern_size[2] = {half_pattern_px / width, half_pattern_px / height}; const float search_size[2] = {half_search_px / width, half_search_px / height}; - MovieTrackingTrack *track = BKE_tracking_track_add_empty(tracking, tracksbase); - - MovieTrackingMarker marker; memset(&marker, 0, sizeof(marker)); marker.pos[0] = x; marker.pos[1] = y; @@ -665,6 +665,86 @@ void BKE_tracking_track_free(MovieTrackingTrack *track) } } +/* Get frame numbers of the very first and last markers. + * There is no check on whether the marker is enabled or not. */ +void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track, + int *r_first_frame, + int *r_last_frame) +{ + BLI_assert(track->markersnr > 0); + const int last_marker_index = track->markersnr - 1; + *r_first_frame = track->markers[0].framenr; + *r_last_frame = track->markers[last_marker_index].framenr; +} + +/* Find the minimum starting frame and maximum ending frame within given set of + * tracks. + */ +void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ MovieTrackingTrack **tracks, + const int num_tracks, + int *r_first_frame, + int *r_last_frame) +{ + *r_first_frame = INT_MAX; + *r_last_frame = INT_MIN; + for (int i = 0; i < num_tracks; ++i) { + const struct MovieTrackingTrack *track = tracks[i]; + int track_first_frame, track_last_frame; + BKE_tracking_track_first_last_frame_get(track, &track_first_frame, &track_last_frame); + *r_first_frame = min_ii(*r_first_frame, track_first_frame); + *r_last_frame = max_ii(*r_last_frame, track_last_frame); + } +} + +int BKE_tracking_count_selected_tracks_in_list(const ListBase *tracks_list) +{ + int num_selected_tracks = 0; + LISTBASE_FOREACH (const MovieTrackingTrack *, track, tracks_list) { + if (TRACK_SELECTED(track)) { + ++num_selected_tracks; + } + } + return num_selected_tracks; +} + +int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ MovieTracking *tracking) +{ + ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking); + return BKE_tracking_count_selected_tracks_in_list(tracks_list); +} + +MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(MovieTracking *tracking, + int *r_num_tracks) +{ + *r_num_tracks = 0; + + ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking); + if (tracks_list == NULL) { + return NULL; + } + + /* Initialize input. */ + const int num_selected_tracks = BKE_tracking_count_selected_tracks_in_active_object(tracking); + if (num_selected_tracks == 0) { + return NULL; + } + + MovieTrackingTrack **source_tracks = MEM_malloc_arrayN( + num_selected_tracks, sizeof(MovieTrackingTrack *), "selected tracks array"); + int source_track_index = 0; + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_list) { + if (!TRACK_SELECTED(track)) { + continue; + } + source_tracks[source_track_index] = track; + ++source_track_index; + } + + *r_num_tracks = num_selected_tracks; + + return source_tracks; +} + /* Set flag for all specified track's areas. * * area - which part of marker should be selected. see TRACK_AREA_* constants. @@ -918,6 +998,124 @@ void BKE_tracking_tracks_join(MovieTracking *tracking, BKE_tracking_dopesheet_tag_update(tracking); } +static void accumulate_marker(MovieTrackingMarker *dst_marker, + const MovieTrackingMarker *src_marker) +{ + BLI_assert(dst_marker->framenr == src_marker->framenr); + + if (src_marker->flag & MARKER_DISABLED) { + return; + } + + add_v2_v2(dst_marker->pos, src_marker->pos); + for (int corner = 0; corner < 4; ++corner) { + add_v2_v2(dst_marker->pattern_corners[corner], src_marker->pattern_corners[corner]); + } + add_v2_v2(dst_marker->search_min, src_marker->search_min); + add_v2_v2(dst_marker->search_max, src_marker->search_max); + + BLI_assert(is_finite_v2(src_marker->search_min)); + BLI_assert(is_finite_v2(src_marker->search_max)); + + dst_marker->flag &= ~MARKER_DISABLED; + if ((src_marker->flag & MARKER_TRACKED) == 0) { + dst_marker->flag &= ~MARKER_TRACKED; + } +} + +static void multiply_marker(MovieTrackingMarker *marker, const float multiplier) +{ + mul_v2_fl(marker->pos, multiplier); + for (int corner = 0; corner < 4; ++corner) { + mul_v2_fl(marker->pattern_corners[corner], multiplier); + } + mul_v2_fl(marker->search_min, multiplier); + mul_v2_fl(marker->search_max, multiplier); +} + +/* Helper function for BKE_tracking_tracks_average which takes care of averaging fields of + * markers (position, patterns, ...). */ +static void tracking_average_markers(MovieTrackingTrack *dst_track, + /*const*/ MovieTrackingTrack **src_tracks, + const int num_src_tracks) +{ + /* Get global range of frames within which averaging would happen. */ + int first_frame, last_frame; + BKE_tracking_tracks_first_last_frame_minmax( + src_tracks, num_src_tracks, &first_frame, &last_frame); + if (last_frame < first_frame) { + return; + } + const int num_frames = last_frame - first_frame + 1; + + /* Allocate temporary array where averaging will happen into. */ + MovieTrackingMarker *accumulator = MEM_calloc_arrayN( + num_frames, sizeof(MovieTrackingMarker), "tracks average accumulator"); + int *counters = MEM_calloc_arrayN(num_frames, sizeof(int), "tracks accumulator counters"); + for (int frame = first_frame; frame <= last_frame; ++frame) { + const int frame_index = frame - first_frame; + accumulator[frame_index].framenr = frame; + accumulator[frame_index].flag |= (MARKER_DISABLED | MARKER_TRACKED); + } + + /* Accumulate track markers. */ + for (int track_index = 0; track_index < num_src_tracks; ++track_index) { + /*const*/ MovieTrackingTrack *track = src_tracks[track_index]; + for (int frame = first_frame; frame <= last_frame; ++frame) { + MovieTrackingMarker interpolated_marker; + if (!BKE_tracking_marker_get_interpolated(track, frame, &interpolated_marker)) { + continue; + } + const int frame_index = frame - first_frame; + accumulate_marker(&accumulator[frame_index], &interpolated_marker); + ++counters[frame_index]; + } + } + + /* Average and store the result. */ + for (int frame = first_frame; frame <= last_frame; ++frame) { + /* Average. */ + const int frame_index = frame - first_frame; + if (!counters[frame_index]) { + continue; + } + const float multiplier = 1.0f / (float)counters[frame_index]; + multiply_marker(&accumulator[frame_index], multiplier); + /* Store the result. */ + BKE_tracking_marker_insert(dst_track, &accumulator[frame_index]); + } + + /* Free memory. */ + MEM_freeN(accumulator); + MEM_freeN(counters); +} + +/* Helper function for BKE_tracking_tracks_average which takes care of averaging fields of + * tracks (track for example, offset). */ +static void tracking_average_tracks(MovieTrackingTrack *dst_track, + /*const*/ MovieTrackingTrack **src_tracks, + const int num_src_tracks) +{ + /* TODO(sergey): Consider averaging weight, stabilization weight, maybe even bundle position. */ + zero_v2(dst_track->offset); + for (int track_index = 0; track_index < num_src_tracks; track_index++) { + add_v2_v2(dst_track->offset, src_tracks[track_index]->offset); + } + mul_v2_fl(dst_track->offset, 1.0f / num_src_tracks); +} + +void BKE_tracking_tracks_average(MovieTrackingTrack *dst_track, + /*const*/ MovieTrackingTrack **src_tracks, + const int num_src_tracks) +{ + if (num_src_tracks == 0) { + return; + } + + tracking_average_markers(dst_track, src_tracks, num_src_tracks); + tracking_average_tracks(dst_track, src_tracks, num_src_tracks); +} + MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieTrackingObject *object, const char *name) @@ -1224,8 +1422,6 @@ MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track, /* put new marker */ track->markers[a + 1] = *marker; - track->last_marker = a + 1; - return &track->markers[a + 1]; } @@ -1314,51 +1510,47 @@ void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event) } } +/** + * Get marker closest to the given frame number. + * + * If there is maker with exact frame number it returned. + * Otherwise, marker with highest frame number but lower than the requested + * frame is returned if such marker exists. Otherwise, the marker with lowest + * frame number greater than the requested frame number is returned. + * + * This function has complexity of `O(log number_of_markers)`. + */ MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr) { - int a = track->markersnr - 1; + const int num_markers = track->markersnr; - if (!track->markersnr) { + if (num_markers == 0) { + BLI_assert(!"Detected degenerated track, should never happen."); return NULL; } - /* approximate pre-first framenr marker with first marker */ - if (framenr < track->markers[0].framenr) { - return &track->markers[0]; - } + int left_boundary = 0; + int right_boundary = num_markers; + while (left_boundary < right_boundary) { + const int median_index = (left_boundary + right_boundary) / 2; + MovieTrackingMarker *marker = &track->markers[median_index]; - if (track->last_marker < track->markersnr) { - a = track->last_marker; - } - - if (track->markers[a].framenr <= framenr) { - while (a < track->markersnr && track->markers[a].framenr <= framenr) { - if (track->markers[a].framenr == framenr) { - track->last_marker = a; - - return &track->markers[a]; - } - a++; + if (marker->framenr == framenr) { + return marker; } - /* if there's no marker for exact position, use nearest marker from left side */ - return &track->markers[a - 1]; - } - - while (a >= 0 && track->markers[a].framenr >= framenr) { - if (track->markers[a].framenr == framenr) { - track->last_marker = a; - - return &track->markers[a]; + if (marker->framenr < framenr) { + left_boundary = median_index + 1; + } + else { + BLI_assert(marker->framenr > framenr); + right_boundary = median_index - 1; } - - a--; } - /* if there's no marker for exact position, use nearest marker from left side */ - return &track->markers[a]; + const int closest_index = clamp_i(right_boundary, 0, num_markers - 1); - return NULL; + return &track->markers[closest_index]; } MovieTrackingMarker *BKE_tracking_marker_get_exact(MovieTrackingTrack *track, int framenr) @@ -1389,6 +1581,84 @@ MovieTrackingMarker *BKE_tracking_marker_ensure(MovieTrackingTrack *track, int f return marker; } +static const MovieTrackingMarker *get_usable_marker_for_interpolation( + struct MovieTrackingTrack *track, + const MovieTrackingMarker *anchor_marker, + const int direction) +{ + BLI_assert(direction == -1 || direction == 1); + + const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1; + const MovieTrackingMarker *current_marker = anchor_marker; + + while (current_marker >= track->markers && current_marker <= last_marker) { + if ((current_marker->flag & MARKER_DISABLED) == 0) { + return current_marker; + } + current_marker += direction; + } + + return NULL; +} + +bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track, + const int framenr, + struct MovieTrackingMarker *r_marker) +{ + const MovieTrackingMarker *closest_marker = BKE_tracking_marker_get(track, framenr); + if (closest_marker == NULL) { + return false; + } + if (closest_marker->framenr == framenr && (closest_marker->flag & MARKER_DISABLED) == 0) { + *r_marker = *closest_marker; + return true; + } + + const MovieTrackingMarker *left_marker = get_usable_marker_for_interpolation( + track, closest_marker, -1); + if (left_marker == NULL) { + return false; + } + + const MovieTrackingMarker *right_marker = get_usable_marker_for_interpolation( + track, closest_marker + 1, 1); + if (right_marker == NULL) { + return false; + } + + if (left_marker == right_marker) { + *r_marker = *left_marker; + return true; + } + + const float factor = (float)(framenr - left_marker->framenr) / + (right_marker->framenr - left_marker->framenr); + + interp_v2_v2v2(r_marker->pos, left_marker->pos, right_marker->pos, factor); + + for (int i = 0; i < 4; i++) { + interp_v2_v2v2(r_marker->pattern_corners[i], + left_marker->pattern_corners[i], + right_marker->pattern_corners[i], + factor); + } + + interp_v2_v2v2(r_marker->search_min, left_marker->search_min, right_marker->search_min, factor); + interp_v2_v2v2(r_marker->search_max, left_marker->search_max, right_marker->search_max, factor); + + r_marker->framenr = framenr; + r_marker->flag = 0; + + if (framenr == left_marker->framenr) { + r_marker->flag = left_marker->flag; + } + else if (framenr == right_marker->framenr) { + r_marker->flag = right_marker->flag; + } + + return true; +} + void BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker *marker, float min[2], float max[2]) @@ -1683,7 +1953,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTra /* Put new marker to an array. */ plane_track->markers[a + 1] = *plane_marker; - plane_track->last_marker = a + 1; return &plane_track->markers[a + 1]; } diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 6f58416924f..46589a578a8 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -311,11 +311,7 @@ static void retrieve_next_lower_usable_frame( * translation stabilization, which has an enabled tracking marker at this very * frame. We search both for the next lower and next higher position, to allow * the caller to interpolate gaps and to extrapolate at the ends of the - * definition range. - * - * NOTE: Regarding performance note that the individual tracks will cache the - * last search position. - */ + * definition range. */ static void find_next_working_frames(StabContext *ctx, int framenr, int *next_lower, diff --git a/source/blender/blenkernel/intern/tracking_test.cc b/source/blender/blenkernel/intern/tracking_test.cc index 6afcf6872eb..2877d8db358 100644 --- a/source/blender/blenkernel/intern/tracking_test.cc +++ b/source/blender/blenkernel/intern/tracking_test.cc @@ -5,15 +5,23 @@ #include "DNA_tracking_types.h" #include "BKE_tracking.h" +#include "BLI_float2.hh" + +namespace blender { namespace { class TrackingTest : public ::testing::Test { protected: - MovieTrackingMarker *addMarkerToTrack(MovieTrackingTrack *track, int frame_number) + MovieTrackingMarker *addMarkerToTrack(MovieTrackingTrack *track, + int frame_number, + const float2 &position = float2(0.0f, 0.0f), + int flag = 0) { MovieTrackingMarker marker = {{0.0f}}; + copy_v2_v2(marker.pos, position); marker.framenr = frame_number; + marker.flag = flag; return BKE_tracking_marker_insert(track, &marker); } }; @@ -22,24 +30,58 @@ class TrackingTest : public ::testing::Test { TEST_F(TrackingTest, BKE_tracking_marker_get) { - MovieTrackingTrack track = {nullptr}; + { + MovieTrackingTrack track = {nullptr}; - addMarkerToTrack(&track, 1); - addMarkerToTrack(&track, 10); + addMarkerToTrack(&track, 10); - { - const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 1); - EXPECT_NE(marker, nullptr); - EXPECT_EQ(marker->framenr, 1); + EXPECT_EQ(BKE_tracking_marker_get(&track, 0), &track.markers[0]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 10), &track.markers[0]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 20), &track.markers[0]); + + BKE_tracking_track_free(&track); } { - const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 5); - EXPECT_NE(marker, nullptr); - EXPECT_EQ(marker->framenr, 1); + MovieTrackingTrack track = {nullptr}; + + addMarkerToTrack(&track, 1); + addMarkerToTrack(&track, 10); + + { + const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 1); + EXPECT_NE(marker, nullptr); + EXPECT_EQ(marker->framenr, 1); + } + + { + const MovieTrackingMarker *marker = BKE_tracking_marker_get(&track, 5); + EXPECT_NE(marker, nullptr); + EXPECT_EQ(marker->framenr, 1); + } + + BKE_tracking_track_free(&track); } - BKE_tracking_track_free(&track); + { + { + MovieTrackingTrack track = {nullptr}; + + addMarkerToTrack(&track, 1); + addMarkerToTrack(&track, 2); + addMarkerToTrack(&track, 10); + + EXPECT_EQ(BKE_tracking_marker_get(&track, 0), &track.markers[0]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 1), &track.markers[0]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 2), &track.markers[1]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 3), &track.markers[1]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 9), &track.markers[1]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 10), &track.markers[2]); + EXPECT_EQ(BKE_tracking_marker_get(&track, 11), &track.markers[2]); + + BKE_tracking_track_free(&track); + } + } } TEST_F(TrackingTest, BKE_tracking_marker_get_exact) @@ -62,3 +104,107 @@ TEST_F(TrackingTest, BKE_tracking_marker_get_exact) BKE_tracking_track_free(&track); } + +TEST_F(TrackingTest, BKE_tracking_marker_get_interpolated) +{ + /* Simple case, no disabled markers in a way. */ + { + MovieTrackingTrack track = {nullptr}; + + addMarkerToTrack(&track, 1, float2(1.0f, 5.0f)); + addMarkerToTrack(&track, 10, float2(2.0f, 1.0f)); + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 1); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.0f, 5.0f), 1e-6f); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 10); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(2.0f, 1.0f), 1e-6f); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 4); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.3333333f, 3.6666666f), 1e-6f); + } + + BKE_tracking_track_free(&track); + } + + /* More comprehensive test, which resembles real life trackign scenario better. */ + { + MovieTrackingTrack track = {nullptr}; + + addMarkerToTrack(&track, 1, float2(1.0f, 5.0f)); + addMarkerToTrack(&track, 2, float2(0.0f, 0.0f), MARKER_DISABLED); + addMarkerToTrack(&track, 9, float2(0.0f, 0.0f), MARKER_DISABLED); + addMarkerToTrack(&track, 10, float2(2.0f, 1.0f)); + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 1); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.0f, 5.0f), 1e-6f); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 10); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(2.0f, 1.0f), 1e-6f); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 4); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.3333333f, 3.6666666f), 1e-6f); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 9, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.framenr, 9); + EXPECT_V2_NEAR(interpolated_marker.pos, float2(1.888888f, 1.4444444f), 1e-6f); + } + + BKE_tracking_track_free(&track); + } + + /* Tracked/keyframed flag check. */ + { + MovieTrackingTrack track = {nullptr}; + + addMarkerToTrack(&track, 1, float2(1.0f, 5.0f), MARKER_TRACKED); + addMarkerToTrack(&track, 10, float2(2.0f, 1.0f), MARKER_TRACKED); + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 1, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.flag, MARKER_TRACKED); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 10, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.flag, MARKER_TRACKED); + } + + { + MovieTrackingMarker interpolated_marker; + EXPECT_TRUE(BKE_tracking_marker_get_interpolated(&track, 4, &interpolated_marker)); + EXPECT_EQ(interpolated_marker.flag, 0); + } + + BKE_tracking_track_free(&track); + } +} + +} // namespace blender diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index e78576206de..643510cf652 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -251,42 +251,10 @@ static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty) BLI_assert(!BLI_listbase_is_empty(&ustack->steps)); } } - -/* Return whether `us_item` is before (-1), after (1) or same as (0) `us_anchor` step. */ -static int undosys_stack_order(const UndoStack *ustack, - const UndoStep *us_anchor, - const UndoStep *us_item) -{ - const int index_anchor = BLI_findindex(&ustack->steps, us_anchor); - const int index_item = BLI_findindex(&ustack->steps, us_item); - BLI_assert(index_anchor >= 0); - BLI_assert(index_item >= 0); - - return (index_item == index_anchor) ? 0 : (index_item < index_anchor) ? -1 : 1; -} - -# define ASSERT_VALID_UNDO_STEP(_ustack, _us_undo) \ - { \ - const UndoStep *_us_anchor = (_ustack)->step_active; \ - BLI_assert(_us_anchor == NULL || \ - (undosys_stack_order((_ustack), _us_anchor, (_us_undo)) <= 0)); \ - } \ - (void)0 - -# define ASSERT_VALID_REDO_STEP(_ustack, _us_redo) \ - { \ - const UndoStep *_us_anchor = (_ustack)->step_active; \ - BLI_assert(_us_anchor == NULL || \ - (undosys_stack_order((_ustack), _us_anchor, (_us_redo)) >= 0)); \ - } \ - (void)0 - #else static void undosys_stack_validate(UndoStack *UNUSED(ustack), bool UNUSED(expect_non_empty)) { } -# define ASSERT_VALID_UNDO_STEP(_ustack, _us_undo) -# define ASSERT_VALID_REDO_STEP(_ustack, _us_redo) #endif UndoStack *BKE_undosys_stack_create(void) @@ -586,7 +554,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack, BLI_strncpy(us->name, name, sizeof(us->name)); } us->type = ut; - /* True by default, code needs to explicitely set it to false if necessary. */ + /* True by default, code needs to explicitly set it to false if necessary. */ us->use_old_bmain_data = true; /* Initialized, not added yet. */ @@ -701,37 +669,91 @@ UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut) return NULL; } -bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, - bContext *C, - UndoStep *us, - bool use_skip) +/** + * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and + * `us_target`. + * + * \note If `us_reference` and `us_target` are the same, we consider this is an undo. + * + * \return -1 for undo, 1 for redo, 0 in case of error. + */ +int BKE_undosys_step_calc_direction(const UndoStack *ustack, + const UndoStep *us_target, + const UndoStep *us_reference) +{ + if (us_reference == NULL) { + us_reference = ustack->step_active; + } + + BLI_assert(us_reference != NULL); + + /* Note that we use heuristics to make this lookup as fast as possible in most common cases, + * assuming that: + * - Most cases are just undo or redo of one step from active one. + * - Otherwise, it is typically faster to check future steps since active one is usually close + * to the end of the list, rather than its start. */ + /* NOTE: in case target step is the active one, we assume we are in an undo case... */ + if (ELEM(us_target, us_reference, us_reference->prev)) { + return -1; + } + if (us_target == us_reference->next) { + return 1; + } + + /* Search forward, and then backward. */ + for (UndoStep *us_iter = us_reference->next; us_iter != NULL; us_iter = us_iter->next) { + if (us_iter == us_target) { + return 1; + } + } + for (UndoStep *us_iter = us_reference->prev; us_iter != NULL; us_iter = us_iter->prev) { + if (us_iter == us_target) { + return -1; + } + } + + BLI_assert(!"Target undo step not found, this should not happen and may indicate an undo stack corruption"); + return 0; +} + +/** + * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one. + * + * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the + * active step. + * + * \note In case `use_skip` is true, the final target will always be **beyond** the given one (if + * the given one has to be skipped). + * + * \param us_reference If NULL, will be set to current active step in the undo stack. Otherwise, it + * is assumed to match the current state, and will be used as basis for the + * undo/redo process (i.e. all steps in-between `us_reference` and `us_target` + * will be processed). + */ +bool BKE_undosys_step_load_data_ex(UndoStack *ustack, + bContext *C, + UndoStep *us_target, + UndoStep *us_reference, + const bool use_skip) { UNDO_NESTED_ASSERT(false); - if (us == NULL) { - CLOG_ERROR(&LOG, "called with a NULL step"); + if (us_target == NULL) { + CLOG_ERROR(&LOG, "called with a NULL target step"); return false; } undosys_stack_validate(ustack, true); - /* We expect to get next-from-actual-target step here (i.e. active step in case we only undo - * once)? - * FIXME: this is very confusing now that we may have to undo several steps anyway, this function - * should just get the target final step, not assume that it is getting the active one by default - * (or the step after the target one when undoing more than one step). */ - UndoStep *us_target = us->prev; - if (us_target == NULL) { - CLOG_ERROR(&LOG, "could not find a valid target step"); + if (us_reference == NULL) { + us_reference = ustack->step_active; + } + if (us_reference == NULL) { + CLOG_ERROR(&LOG, "could not find a valid initial active target step as reference"); return false; } - ASSERT_VALID_UNDO_STEP(ustack, us_target); - /* This will be active once complete. */ - UndoStep *us_active = us_target; - if (use_skip) { - while (us_active && us_active->skip) { - us_active = us_active->prev; - } - } + /* This considers we are in undo case if both `us_target` and `us_reference` are the same. */ + const int undo_dir = BKE_undosys_step_calc_direction(ustack, us_target, us_reference); + BLI_assert(undo_dir != 0); /* This will be the active step once the undo process is complete. * @@ -740,7 +762,7 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, UndoStep *us_target_active = us_target; if (use_skip) { while (us_target_active != NULL && us_target_active->skip) { - us_target_active = us_target_active->prev; + us_target_active = (undo_dir == -1) ? us_target_active->prev : us_target_active->next; } } if (us_target_active == NULL) { @@ -748,42 +770,47 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, return false; } - CLOG_INFO( - &LOG, 1, "addr=%p, name='%s', type='%s'", us_target, us_target->name, us_target->type->name); + CLOG_INFO(&LOG, + 1, + "addr=%p, name='%s', type='%s', undo_dir=%d", + us_target, + us_target->name, + us_target->type->name, + undo_dir); - /* Undo steps until we reach original given target, if we do have a current active step. + /* Undo/Redo steps until we reach given target step (or beyond if it has to be skipped), from + * given reference step. * * NOTE: Unlike with redo case, where we can expect current active step to fully reflect current * data status, in undo case we also do reload the active step. * FIXME: this feels weak, and should probably not be actually needed? Or should also be done in * redo case? */ - if (ustack->step_active != NULL) { - for (UndoStep *us_iter = ustack->step_active; us_iter != us_target; us_iter = us_iter->prev) { - BLI_assert(us_iter != NULL); - undosys_step_decode(C, G_MAIN, ustack, us_iter, -1, false); - ustack->step_active = us_iter; - } - } + bool is_processing_extra_skipped_steps = false; + for (UndoStep *us_iter = (undo_dir == -1) ? us_reference : us_reference->next; us_iter != NULL; + us_iter = (undo_dir == -1) ? us_iter->prev : us_iter->next) { + BLI_assert(us_iter != NULL); - /* Undo target step, and all potential extra ones if some steps have to be 'skipped'. */ - for (UndoStep *us_iter = us_target; us_iter != NULL; us_iter = us_iter->prev) { const bool is_final = (us_iter == us_target_active); - if (!is_final) { + if (!is_final && is_processing_extra_skipped_steps) { BLI_assert(us_iter->skip == true); CLOG_INFO(&LOG, 2, - "undo continue with skip addr=%p, name='%s', type='%s'", + "undo/redo continue with skip addr=%p, name='%s', type='%s'", us_iter, us_iter->name, us_iter->type->name); } - undosys_step_decode(C, G_MAIN, ustack, us_iter, -1, is_final); + undosys_step_decode(C, G_MAIN, ustack, us_iter, undo_dir, is_final); ustack->step_active = us_iter; + if (us_iter == us_target) { + is_processing_extra_skipped_steps = true; + } + if (is_final) { - /* Undo process is finished and successful. */ + /* Undo/Redo process is finished and successful. */ return true; } } @@ -793,139 +820,117 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, return false; } -bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) -{ - return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true); -} - -bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C) +/** + * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one. + */ +bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target) { - return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); + /* Note that here we do not skip 'skipped' steps by default. */ + return BKE_undosys_step_load_data_ex(ustack, C, us_target, NULL, false); } -void BKE_undosys_step_undo_from_index(UndoStack *ustack, bContext *C, int index) +/** + * Undo/Redo until the step matching given `index` in the undo stack becomes the active (currently + * loaded) one. + */ +void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int index) { - UndoStep *us = BLI_findlink(&ustack->steps, index); - BLI_assert(us->skip == false); - BKE_undosys_step_load_data(ustack, C, us); + UndoStep *us_target = BLI_findlink(&ustack->steps, index); + BLI_assert(us_target->skip == false); + BKE_undosys_step_load_data(ustack, C, us_target); } -bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, +/** + * Undo until `us_target` step becomes the active (currently loaded) one. + * + * \warning This function assumes that the given target step is _before_ current active one. + * + * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the + * active step. + * + * \note In case `use_skip` is true, the final target will always be **before** the given one (if + * the given one has to be skipped). + */ +bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, bContext *C, - UndoStep *us, + UndoStep *us_target, bool use_skip) { - UNDO_NESTED_ASSERT(false); - if (us == NULL) { - CLOG_ERROR(&LOG, "called with a NULL step"); - return false; - } - undosys_stack_validate(ustack, true); + /* In case there is no active step, we consider we just load given step, so reference must be + * itself (due to weird 'load current active step in undo case' thing, see comments in + * #BKE_undosys_step_load_data_ex). */ + UndoStep *us_reference = ustack->step_active != NULL ? ustack->step_active : us_target; - /* We expect to get previous-from-actual-target step here (i.e. active step in case we only redo - * once)? - * FIXME: this is very confusing now that we may have to redo several steps anyway, this function - * should just get the target final step, not assume that it is getting the active one by default - * (or the step before the target one when redoing more than one step). */ - UndoStep *us_target = us->next; - if (us_target == NULL) { - CLOG_ERROR(&LOG, "could not find a valid target step"); - return false; - } - ASSERT_VALID_REDO_STEP(ustack, us_target); + BLI_assert(BKE_undosys_step_calc_direction(ustack, us_target, us_reference) == -1); - /* This will be the active step once the redo process is complete. - * - * In case we do skip 'skipped' steps, the final active step may be several steps forward the one - * passed as parameter. */ - UndoStep *us_target_active = us_target; - if (use_skip) { - while (us_target_active != NULL && us_target_active->skip) { - us_target_active = us_target_active->next; - } - } - if (us_target_active == NULL) { - CLOG_ERROR(&LOG, "could not find a valid final active target step"); - return false; - } + return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip); +} - CLOG_INFO( - &LOG, 1, "addr=%p, name='%s', type='%s'", us_target, us_target->name, us_target->type->name); +/** + * Undo until `us_target` step becomes the active (currently loaded) one. + * + * \note See #BKE_undosys_step_undo_with_data_ex for details. + */ +bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target) +{ + return BKE_undosys_step_undo_with_data_ex(ustack, C, us_target, true); +} - /* Redo steps until we reach original given target, if we do have a current active step. */ +/** + * Undo one step from current active (currently loaded) one. + */ +bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C) +{ if (ustack->step_active != NULL) { - for (UndoStep *us_iter = ustack->step_active->next; us_iter != us_target; - us_iter = us_iter->next) { - BLI_assert(us_iter != NULL); - undosys_step_decode(C, G_MAIN, ustack, us_iter, 1, false); - ustack->step_active = us_iter; - } + return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active->prev); } - - /* Redo target step, and all potential extra ones if some steps have to be 'skipped'. */ - for (UndoStep *us_iter = us_target; us_iter != NULL; us_iter = us_iter->next) { - const bool is_final = (us_iter == us_target_active); - - if (!is_final) { - BLI_assert(us_iter->skip == true); - CLOG_INFO(&LOG, - 2, - "redo continue with skip addr=%p, name='%s', type='%s'", - us_iter, - us_iter->name, - us_iter->type->name); - } - - undosys_step_decode(C, G_MAIN, ustack, us_iter, 1, is_final); - ustack->step_active = us_iter; - - if (is_final) { - /* Redo process is finished and successful. */ - return true; - } - } - - BLI_assert( - !"This should never be reached, either undo stack is corrupted, or code above is buggy"); return false; } -bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) +/** + * Redo until `us_target` step becomes the active (currently loaded) one. + * + * \warning This function assumes that the given target step is _after_ current active one. + * + * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the + * active step. + * + * \note In case `use_skip` is true, the final target will always be **after** the given one (if + * the given one has to be skipped). + */ +bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, + bContext *C, + UndoStep *us_target, + bool use_skip) { - return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true); + /* In case there is no active step, we consider we just load given step, so reference must be + * the previous one. */ + UndoStep *us_reference = ustack->step_active != NULL ? ustack->step_active : us_target->prev; + + BLI_assert(BKE_undosys_step_calc_direction(ustack, us_target, us_reference) == 1); + + return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip); } -bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C) +/** + * Redo until `us_target` step becomes the active (currently loaded) one. + * + * \note See #BKE_undosys_step_redo_with_data_ex for details. + */ +bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target) { - return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active); + return BKE_undosys_step_redo_with_data_ex(ustack, C, us_target, true); } -bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us) +/** + * Redo one step from current active one. + */ +bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C) { - UNDO_NESTED_ASSERT(false); - const int index_active = BLI_findindex(&ustack->steps, ustack->step_active); - const int index_target = BLI_findindex(&ustack->steps, us); - BLI_assert(!ELEM(-1, index_active, index_target)); - bool ok = true; - - if (index_target < index_active) { - uint i = index_active - index_target; - while (i-- && ok) { - ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false); - } - } - else if (index_target > index_active) { - uint i = index_target - index_active; - while (i-- && ok) { - ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false); - } - } - - if (ok) { - BLI_assert(ustack->step_active == us); + if (ustack->step_active != NULL) { + return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active->next); } - - return ok; + return false; } /** diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index b55f80c6473..e98fae9d92a 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -1167,8 +1167,7 @@ bool BKE_unit_replace_string( /* Replace # with add sign when there is no operator between it and the next number. * * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3" - * - * */ + */ { char *str_found = str; const char *ch = str; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 9e7a3736141..77cfb3ffea5 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -128,7 +128,7 @@ static struct VolumeFileCache { std::lock_guard<std::mutex> lock(mutex); return simplified_grids.lookup_or_add_cb(simplify_level, [&]() { const float resolution_factor = 1.0f / (1 << simplify_level); - const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid); + const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid); return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor); }); } @@ -523,6 +523,8 @@ static void volume_copy_data(Main *UNUSED(bmain), volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src); } #endif + + volume_dst->batch_cache = nullptr; } static void volume_free_data(ID *id) @@ -642,6 +644,8 @@ IDTypeInfo IDType_ID_VO = { /* blend_read_expand */ volume_blend_read_expand, /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; void BKE_volume_init_grids(Volume *volume) @@ -1233,39 +1237,39 @@ const char *BKE_volume_grid_name(const VolumeGrid *volume_grid) } #ifdef WITH_OPENVDB -VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid) +VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid) { - if (grid->isType<openvdb::FloatGrid>()) { + if (grid.isType<openvdb::FloatGrid>()) { return VOLUME_GRID_FLOAT; } - if (grid->isType<openvdb::Vec3fGrid>()) { + if (grid.isType<openvdb::Vec3fGrid>()) { return VOLUME_GRID_VECTOR_FLOAT; } - if (grid->isType<openvdb::BoolGrid>()) { + if (grid.isType<openvdb::BoolGrid>()) { return VOLUME_GRID_BOOLEAN; } - if (grid->isType<openvdb::DoubleGrid>()) { + if (grid.isType<openvdb::DoubleGrid>()) { return VOLUME_GRID_DOUBLE; } - if (grid->isType<openvdb::Int32Grid>()) { + if (grid.isType<openvdb::Int32Grid>()) { return VOLUME_GRID_INT; } - if (grid->isType<openvdb::Int64Grid>()) { + if (grid.isType<openvdb::Int64Grid>()) { return VOLUME_GRID_INT64; } - if (grid->isType<openvdb::Vec3IGrid>()) { + if (grid.isType<openvdb::Vec3IGrid>()) { return VOLUME_GRID_VECTOR_INT; } - if (grid->isType<openvdb::Vec3dGrid>()) { + if (grid.isType<openvdb::Vec3dGrid>()) { return VOLUME_GRID_VECTOR_DOUBLE; } - if (grid->isType<openvdb::StringGrid>()) { + if (grid.isType<openvdb::StringGrid>()) { return VOLUME_GRID_STRING; } - if (grid->isType<openvdb::MaskGrid>()) { + if (grid.isType<openvdb::MaskGrid>()) { return VOLUME_GRID_MASK; } - if (grid->isType<openvdb::points::PointDataGrid>()) { + if (grid.isType<openvdb::points::PointDataGrid>()) { return VOLUME_GRID_POINTS; } return VOLUME_GRID_UNKNOWN; @@ -1276,7 +1280,7 @@ VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid) { #ifdef WITH_OPENVDB const openvdb::GridBase::Ptr grid = volume_grid->grid(); - return BKE_volume_grid_type_openvdb(grid); + return BKE_volume_grid_type_openvdb(*grid); #else UNUSED_VARS(volume_grid); #endif diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 291116556c3..5a101cf009b 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -192,6 +192,8 @@ IDTypeInfo IDType_ID_WS = { .blend_read_expand = workspace_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 8fe7653fc25..a2ce37a5d90 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -206,6 +206,8 @@ IDTypeInfo IDType_ID_WO = { .blend_read_expand = world_blend_read_expand, .blend_read_undo_preserve = NULL, + + .lib_override_apply_post = NULL, }; World *BKE_world_add(Main *bmain, const char *name) |