Prepare for `BLI_str_unescape` which doesn't read well without the separator.
		
			
				
	
	
		
			613 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			613 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * - Blender Foundation, 2003-2009
 | 
						|
 * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
 | 
						|
 */
 | 
						|
 | 
						|
/** \file
 | 
						|
 * \ingroup bke
 | 
						|
 */
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "DNA_anim_types.h"
 | 
						|
#include "DNA_scene_types.h"
 | 
						|
#include "DNA_sequence_types.h"
 | 
						|
 | 
						|
#include "BLI_listbase.h"
 | 
						|
#include "BLI_string.h"
 | 
						|
 | 
						|
#include "BKE_animsys.h"
 | 
						|
#include "BKE_fcurve.h"
 | 
						|
#include "BKE_idprop.h"
 | 
						|
#include "BKE_lib_id.h"
 | 
						|
#include "BKE_sound.h"
 | 
						|
 | 
						|
#include "DEG_depsgraph.h"
 | 
						|
 | 
						|
#include "IMB_colormanagement.h"
 | 
						|
#include "IMB_imbuf.h"
 | 
						|
 | 
						|
#include "SEQ_sequencer.h"
 | 
						|
 | 
						|
#include "image_cache.h"
 | 
						|
#include "prefetch.h"
 | 
						|
#include "sequencer.h"
 | 
						|
#include "utils.h"
 | 
						|
 | 
						|
static void seq_free_animdata(Scene *scene, Sequence *seq);
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Allocate / Free Functions
 | 
						|
 * \{ */
 | 
						|
 | 
						|
static Strip *seq_strip_alloc(int type)
 | 
						|
{
 | 
						|
  Strip *strip = MEM_callocN(sizeof(Strip), "strip");
 | 
						|
 | 
						|
  if (ELEM(type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) {
 | 
						|
    strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
 | 
						|
    strip->transform->scale_x = 1;
 | 
						|
    strip->transform->scale_y = 1;
 | 
						|
    strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
 | 
						|
  }
 | 
						|
 | 
						|
  strip->us = 1;
 | 
						|
  return strip;
 | 
						|
}
 | 
						|
 | 
						|
static void seq_free_strip(Strip *strip)
 | 
						|
{
 | 
						|
  strip->us--;
 | 
						|
  if (strip->us > 0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (strip->us < 0) {
 | 
						|
    printf("error: negative users in strip\n");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (strip->stripdata) {
 | 
						|
    MEM_freeN(strip->stripdata);
 | 
						|
  }
 | 
						|
 | 
						|
  if (strip->proxy) {
 | 
						|
    if (strip->proxy->anim) {
 | 
						|
      IMB_free_anim(strip->proxy->anim);
 | 
						|
    }
 | 
						|
 | 
						|
    MEM_freeN(strip->proxy);
 | 
						|
  }
 | 
						|
  if (strip->crop) {
 | 
						|
    MEM_freeN(strip->crop);
 | 
						|
  }
 | 
						|
  if (strip->transform) {
 | 
						|
    MEM_freeN(strip->transform);
 | 
						|
  }
 | 
						|
 | 
						|
  MEM_freeN(strip);
 | 
						|
}
 | 
						|
 | 
						|
Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type)
 | 
						|
{
 | 
						|
  Sequence *seq;
 | 
						|
 | 
						|
  seq = MEM_callocN(sizeof(Sequence), "addseq");
 | 
						|
  BLI_addtail(lb, seq);
 | 
						|
 | 
						|
  *((short *)seq->name) = ID_SEQ;
 | 
						|
  seq->name[2] = 0;
 | 
						|
 | 
						|
  seq->flag = SELECT;
 | 
						|
  seq->start = timeline_frame;
 | 
						|
  seq->machine = machine;
 | 
						|
  seq->sat = 1.0;
 | 
						|
  seq->mul = 1.0;
 | 
						|
  seq->blend_opacity = 100.0;
 | 
						|
  seq->volume = 1.0f;
 | 
						|
  seq->pitch = 1.0f;
 | 
						|
  seq->scene_sound = NULL;
 | 
						|
  seq->type = type;
 | 
						|
 | 
						|
  seq->strip = seq_strip_alloc(type);
 | 
						|
  seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
 | 
						|
  seq->cache_flag = SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE;
 | 
						|
 | 
						|
  BKE_sequence_session_uuid_generate(seq);
 | 
						|
 | 
						|
  return seq;
 | 
						|
}
 | 
						|
 | 
						|
/* only give option to skip cache locally (static func) */
 | 
						|
static void BKE_sequence_free_ex(Scene *scene,
 | 
						|
                                 Sequence *seq,
 | 
						|
                                 const bool do_cache,
 | 
						|
                                 const bool do_id_user,
 | 
						|
                                 const bool do_clean_animdata)
 | 
						|
{
 | 
						|
  if (seq->strip) {
 | 
						|
    seq_free_strip(seq->strip);
 | 
						|
  }
 | 
						|
 | 
						|
  BKE_sequence_free_anim(seq);
 | 
						|
 | 
						|
  if (seq->type & SEQ_TYPE_EFFECT) {
 | 
						|
    struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
 | 
						|
    sh.free(seq, do_id_user);
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->sound && do_id_user) {
 | 
						|
    id_us_min(((ID *)seq->sound));
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->stereo3d_format) {
 | 
						|
    MEM_freeN(seq->stereo3d_format);
 | 
						|
  }
 | 
						|
 | 
						|
  /* clipboard has no scene and will never have a sound handle or be active
 | 
						|
   * same goes to sequences copy for proxy rebuild job
 | 
						|
   */
 | 
						|
  if (scene) {
 | 
						|
    Editing *ed = scene->ed;
 | 
						|
 | 
						|
    if (ed->act_seq == seq) {
 | 
						|
      ed->act_seq = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
 | 
						|
      BKE_sound_remove_scene_sound(scene, seq->scene_sound);
 | 
						|
    }
 | 
						|
 | 
						|
    /* XXX This must not be done in BKE code. */
 | 
						|
    if (do_clean_animdata) {
 | 
						|
      seq_free_animdata(scene, seq);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->prop) {
 | 
						|
    IDP_FreePropertyContent_ex(seq->prop, do_id_user);
 | 
						|
    MEM_freeN(seq->prop);
 | 
						|
  }
 | 
						|
 | 
						|
  /* free modifiers */
 | 
						|
  BKE_sequence_modifier_clear(seq);
 | 
						|
 | 
						|
  /* free cached data used by this strip,
 | 
						|
   * also invalidate cache for all dependent sequences
 | 
						|
   *
 | 
						|
   * be _very_ careful here, invalidating cache loops over the scene sequences and
 | 
						|
   * assumes the listbase is valid for all strips,
 | 
						|
   * this may not be the case if lists are being freed.
 | 
						|
   * this is optional BKE_sequence_invalidate_cache
 | 
						|
   */
 | 
						|
  if (do_cache) {
 | 
						|
    if (scene) {
 | 
						|
      BKE_sequence_invalidate_cache_raw(scene, seq);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MEM_freeN(seq);
 | 
						|
}
 | 
						|
 | 
						|
void BKE_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata)
 | 
						|
{
 | 
						|
  BKE_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
 | 
						|
}
 | 
						|
 | 
						|
/* cache must be freed before calling this function
 | 
						|
 * since it leaves the seqbase in an invalid state */
 | 
						|
void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
 | 
						|
{
 | 
						|
  Sequence *iseq, *iseq_next;
 | 
						|
 | 
						|
  for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) {
 | 
						|
    iseq_next = iseq->next;
 | 
						|
    seq_free_sequence_recurse(scene, iseq, do_id_user);
 | 
						|
  }
 | 
						|
 | 
						|
  BKE_sequence_free_ex(scene, seq, false, do_id_user, true);
 | 
						|
}
 | 
						|
 | 
						|
Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
 | 
						|
{
 | 
						|
  if (alloc) {
 | 
						|
    BKE_sequencer_editing_ensure(scene);
 | 
						|
  }
 | 
						|
  return scene->ed;
 | 
						|
}
 | 
						|
 | 
						|
Editing *BKE_sequencer_editing_ensure(Scene *scene)
 | 
						|
{
 | 
						|
  if (scene->ed == NULL) {
 | 
						|
    Editing *ed;
 | 
						|
 | 
						|
    ed = scene->ed = MEM_callocN(sizeof(Editing), "addseq");
 | 
						|
    ed->seqbasep = &ed->seqbase;
 | 
						|
    ed->cache = NULL;
 | 
						|
    ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT;
 | 
						|
    ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT;
 | 
						|
    ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE;
 | 
						|
    ed->recycle_max_cost = 10.0f;
 | 
						|
  }
 | 
						|
 | 
						|
  return scene->ed;
 | 
						|
}
 | 
						|
 | 
						|
void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
 | 
						|
{
 | 
						|
  Editing *ed = scene->ed;
 | 
						|
  Sequence *seq;
 | 
						|
 | 
						|
  if (ed == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  BKE_sequencer_prefetch_free(scene);
 | 
						|
  BKE_sequencer_cache_destruct(scene);
 | 
						|
 | 
						|
  SEQ_ALL_BEGIN (ed, seq) {
 | 
						|
    /* handle cache freeing above */
 | 
						|
    BKE_sequence_free_ex(scene, seq, false, do_id_user, false);
 | 
						|
  }
 | 
						|
  SEQ_ALL_END;
 | 
						|
 | 
						|
  BLI_freelistN(&ed->metastack);
 | 
						|
  MEM_freeN(ed);
 | 
						|
 | 
						|
  scene->ed = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void seq_new_fix_links_recursive(Sequence *seq)
 | 
						|
{
 | 
						|
  SequenceModifierData *smd;
 | 
						|
 | 
						|
  if (seq->type & SEQ_TYPE_EFFECT) {
 | 
						|
    if (seq->seq1 && seq->seq1->tmp) {
 | 
						|
      seq->seq1 = seq->seq1->tmp;
 | 
						|
    }
 | 
						|
    if (seq->seq2 && seq->seq2->tmp) {
 | 
						|
      seq->seq2 = seq->seq2->tmp;
 | 
						|
    }
 | 
						|
    if (seq->seq3 && seq->seq3->tmp) {
 | 
						|
      seq->seq3 = seq->seq3->tmp;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_META) {
 | 
						|
    Sequence *seqn;
 | 
						|
    for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
 | 
						|
      seq_new_fix_links_recursive(seqn);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (smd = seq->modifiers.first; smd; smd = smd->next) {
 | 
						|
    if (smd->mask_sequence && smd->mask_sequence->tmp) {
 | 
						|
      smd->mask_sequence = smd->mask_sequence->tmp;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Duplicate Functions
 | 
						|
 * \{ */
 | 
						|
static Sequence *seq_dupli(const Scene *scene_src,
 | 
						|
                           Scene *scene_dst,
 | 
						|
                           ListBase *new_seq_list,
 | 
						|
                           Sequence *seq,
 | 
						|
                           int dupe_flag,
 | 
						|
                           const int flag)
 | 
						|
{
 | 
						|
  Sequence *seqn = MEM_dupallocN(seq);
 | 
						|
 | 
						|
  if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
 | 
						|
    BKE_sequence_session_uuid_generate(seq);
 | 
						|
  }
 | 
						|
 | 
						|
  seq->tmp = seqn;
 | 
						|
  seqn->strip = MEM_dupallocN(seq->strip);
 | 
						|
 | 
						|
  seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
 | 
						|
 | 
						|
  /* XXX: add F-Curve duplication stuff? */
 | 
						|
 | 
						|
  if (seq->strip->crop) {
 | 
						|
    seqn->strip->crop = MEM_dupallocN(seq->strip->crop);
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->strip->transform) {
 | 
						|
    seqn->strip->transform = MEM_dupallocN(seq->strip->transform);
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->strip->proxy) {
 | 
						|
    seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
 | 
						|
    seqn->strip->proxy->anim = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->prop) {
 | 
						|
    seqn->prop = IDP_CopyProperty_ex(seq->prop, flag);
 | 
						|
  }
 | 
						|
 | 
						|
  if (seqn->modifiers.first) {
 | 
						|
    BLI_listbase_clear(&seqn->modifiers);
 | 
						|
 | 
						|
    BKE_sequence_modifier_list_copy(seqn, seq);
 | 
						|
  }
 | 
						|
 | 
						|
  if (seq->type == SEQ_TYPE_META) {
 | 
						|
    seqn->strip->stripdata = NULL;
 | 
						|
 | 
						|
    BLI_listbase_clear(&seqn->seqbase);
 | 
						|
    /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */
 | 
						|
    /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_SCENE) {
 | 
						|
    seqn->strip->stripdata = NULL;
 | 
						|
    if (seq->scene_sound) {
 | 
						|
      seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_MOVIECLIP) {
 | 
						|
    /* avoid assert */
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_MASK) {
 | 
						|
    /* avoid assert */
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_MOVIE) {
 | 
						|
    seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
 | 
						|
    BLI_listbase_clear(&seqn->anims);
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_SOUND_RAM) {
 | 
						|
    seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
 | 
						|
    seqn->scene_sound = NULL;
 | 
						|
    if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
 | 
						|
      id_us_plus((ID *)seqn->sound);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if (seq->type == SEQ_TYPE_IMAGE) {
 | 
						|
    seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
 | 
						|
  }
 | 
						|
  else if (seq->type & SEQ_TYPE_EFFECT) {
 | 
						|
    struct SeqEffectHandle sh;
 | 
						|
    sh = BKE_sequence_get_effect(seq);
 | 
						|
    if (sh.copy) {
 | 
						|
      sh.copy(seqn, seq, flag);
 | 
						|
    }
 | 
						|
 | 
						|
    seqn->strip->stripdata = NULL;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* sequence type not handled in duplicate! Expect a crash now... */
 | 
						|
    BLI_assert(0);
 | 
						|
  }
 | 
						|
 | 
						|
  /* When using SEQ_DUPE_UNIQUE_NAME, it is mandatory to add new sequences in relevant container
 | 
						|
   * (scene or meta's one), *before* checking for unique names. Otherwise the meta's list is empty
 | 
						|
   * and hence we miss all seqs in that meta that have already been duplicated (see T55668).
 | 
						|
   * Note that unique name check itself could be done at a later step in calling code, once all
 | 
						|
   * seqs have bee duplicated (that was first, simpler solution), but then handling of animation
 | 
						|
   * data will be broken (see T60194). */
 | 
						|
  if (new_seq_list != NULL) {
 | 
						|
    BLI_addtail(new_seq_list, seqn);
 | 
						|
  }
 | 
						|
 | 
						|
  if (scene_src == scene_dst) {
 | 
						|
    if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
 | 
						|
      BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
 | 
						|
    }
 | 
						|
 | 
						|
    if (dupe_flag & SEQ_DUPE_ANIM) {
 | 
						|
      BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return seqn;
 | 
						|
}
 | 
						|
 | 
						|
static Sequence *sequence_dupli_recursive_do(const Scene *scene_src,
 | 
						|
                                             Scene *scene_dst,
 | 
						|
                                             ListBase *new_seq_list,
 | 
						|
                                             Sequence *seq,
 | 
						|
                                             const int dupe_flag)
 | 
						|
{
 | 
						|
  Sequence *seqn;
 | 
						|
 | 
						|
  seq->tmp = NULL;
 | 
						|
  seqn = seq_dupli(scene_src, scene_dst, new_seq_list, seq, dupe_flag, 0);
 | 
						|
  if (seq->type == SEQ_TYPE_META) {
 | 
						|
    Sequence *s;
 | 
						|
    for (s = seq->seqbase.first; s; s = s->next) {
 | 
						|
      sequence_dupli_recursive_do(scene_src, scene_dst, &seqn->seqbase, s, dupe_flag);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return seqn;
 | 
						|
}
 | 
						|
 | 
						|
Sequence *BKE_sequence_dupli_recursive(
 | 
						|
    const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Sequence *seq, int dupe_flag)
 | 
						|
{
 | 
						|
  Sequence *seqn = sequence_dupli_recursive_do(scene_src, scene_dst, new_seq_list, seq, dupe_flag);
 | 
						|
 | 
						|
  /* This does not need to be in recursive call itself, since it is already recursive... */
 | 
						|
  seq_new_fix_links_recursive(seqn);
 | 
						|
 | 
						|
  return seqn;
 | 
						|
}
 | 
						|
 | 
						|
void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
 | 
						|
                                       Scene *scene_dst,
 | 
						|
                                       ListBase *nseqbase,
 | 
						|
                                       const ListBase *seqbase,
 | 
						|
                                       int dupe_flag,
 | 
						|
                                       const int flag)
 | 
						|
{
 | 
						|
  Sequence *seq;
 | 
						|
  Sequence *seqn = NULL;
 | 
						|
  Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
 | 
						|
  /* always include meta's strips */
 | 
						|
  int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL | SEQ_DUPE_IS_RECURSIVE_CALL;
 | 
						|
 | 
						|
  for (seq = seqbase->first; seq; seq = seq->next) {
 | 
						|
    seq->tmp = NULL;
 | 
						|
    if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) {
 | 
						|
      seqn = seq_dupli(scene_src, scene_dst, nseqbase, seq, dupe_flag, flag);
 | 
						|
      if (seqn) { /*should never fail */
 | 
						|
        if (dupe_flag & SEQ_DUPE_CONTEXT) {
 | 
						|
          seq->flag &= ~SEQ_ALLSEL;
 | 
						|
          seqn->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
 | 
						|
        }
 | 
						|
 | 
						|
        if (seq->type == SEQ_TYPE_META) {
 | 
						|
          BKE_sequence_base_dupli_recursive(
 | 
						|
              scene_src, scene_dst, &seqn->seqbase, &seq->seqbase, dupe_flag_recursive, flag);
 | 
						|
        }
 | 
						|
 | 
						|
        if (dupe_flag & SEQ_DUPE_CONTEXT) {
 | 
						|
          if (seq == last_seq) {
 | 
						|
            BKE_sequencer_active_set(scene_dst, seqn);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Fix modifier links recursively from the top level only, when all sequences have been
 | 
						|
   * copied. */
 | 
						|
  if (dupe_flag & SEQ_DUPE_IS_RECURSIVE_CALL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /* fix modifier linking */
 | 
						|
  for (seq = nseqbase->first; seq; seq = seq->next) {
 | 
						|
    seq_new_fix_links_recursive(seq);
 | 
						|
  }
 | 
						|
}
 | 
						|
/* r_prefix + [" + escaped_name + "] + \0 */
 | 
						|
#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
 | 
						|
 | 
						|
static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
 | 
						|
{
 | 
						|
  char name_esc[SEQ_NAME_MAXSTR * 2];
 | 
						|
 | 
						|
  BLI_str_escape(name_esc, name, sizeof(name_esc));
 | 
						|
  return BLI_snprintf_rlen(
 | 
						|
      str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
 | 
						|
}
 | 
						|
 | 
						|
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
 | 
						|
void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
 | 
						|
{
 | 
						|
  char str[SEQ_RNAPATH_MAXSTR];
 | 
						|
  size_t str_len;
 | 
						|
  FCurve *fcu;
 | 
						|
 | 
						|
  if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  str_len = sequencer_rna_path_prefix(str, seq->name + 2);
 | 
						|
 | 
						|
  for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
 | 
						|
    if (STREQLEN(fcu->rna_path, str, str_len)) {
 | 
						|
      unsigned int i;
 | 
						|
      if (fcu->bezt) {
 | 
						|
        for (i = 0; i < fcu->totvert; i++) {
 | 
						|
          BezTriple *bezt = &fcu->bezt[i];
 | 
						|
          bezt->vec[0][0] += ofs;
 | 
						|
          bezt->vec[1][0] += ofs;
 | 
						|
          bezt->vec[2][0] += ofs;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (fcu->fpt) {
 | 
						|
        for (i = 0; i < fcu->totvert; i++) {
 | 
						|
          FPoint *fpt = &fcu->fpt[i];
 | 
						|
          fpt->vec[0] += ofs;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
 | 
						|
}
 | 
						|
 | 
						|
void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
 | 
						|
{
 | 
						|
  char str_from[SEQ_RNAPATH_MAXSTR];
 | 
						|
  size_t str_from_len;
 | 
						|
  FCurve *fcu;
 | 
						|
  FCurve *fcu_last;
 | 
						|
  FCurve *fcu_cpy;
 | 
						|
  ListBase lb = {NULL, NULL};
 | 
						|
 | 
						|
  if (scene->adt == NULL || scene->adt->action == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  str_from_len = sequencer_rna_path_prefix(str_from, name_src);
 | 
						|
 | 
						|
  fcu_last = scene->adt->action->curves.last;
 | 
						|
 | 
						|
  for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
 | 
						|
    if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
 | 
						|
      fcu_cpy = BKE_fcurve_copy(fcu);
 | 
						|
      BLI_addtail(&lb, fcu_cpy);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* notice validate is 0, keep this because the seq may not be added to the scene yet */
 | 
						|
  BKE_animdata_fix_paths_rename(
 | 
						|
      &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
 | 
						|
 | 
						|
  /* add the original fcurves back */
 | 
						|
  BLI_movelisttolist(&scene->adt->action->curves, &lb);
 | 
						|
}
 | 
						|
 | 
						|
/* XXX - hackish function needed to remove all fcurves belonging to a sequencer strip */
 | 
						|
static void seq_free_animdata(Scene *scene, Sequence *seq)
 | 
						|
{
 | 
						|
  char str[SEQ_RNAPATH_MAXSTR];
 | 
						|
  size_t str_len;
 | 
						|
  FCurve *fcu;
 | 
						|
 | 
						|
  if (scene->adt == NULL || scene->adt->action == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  str_len = sequencer_rna_path_prefix(str, seq->name + 2);
 | 
						|
 | 
						|
  fcu = scene->adt->action->curves.first;
 | 
						|
 | 
						|
  while (fcu) {
 | 
						|
    if (STREQLEN(fcu->rna_path, str, str_len)) {
 | 
						|
      FCurve *next_fcu = fcu->next;
 | 
						|
 | 
						|
      BLI_remlink(&scene->adt->action->curves, fcu);
 | 
						|
      BKE_fcurve_free(fcu);
 | 
						|
 | 
						|
      fcu = next_fcu;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      fcu = fcu->next;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#undef SEQ_RNAPATH_MAXSTR
 | 
						|
/** \} */
 |